70322ae3 |
1 | /* |
2 | * malloc.c: implementation of malloc.h |
3 | */ |
4 | |
5 | #include <stdlib.h> |
6 | #include <string.h> |
7 | #include <stdarg.h> |
8 | #include <time.h> |
9 | #include <assert.h> |
10 | #include <stdio.h> |
11 | |
12 | #include "malloc.h" |
13 | |
14 | #define lenof(x) (sizeof((x))/sizeof(*(x))) |
15 | |
16 | extern void fatal(const char *, ...); |
17 | |
18 | void *smalloc(size_t size) { |
19 | void *p; |
20 | p = malloc(size); |
21 | if (!p) { |
22 | fatal("out of memory"); |
23 | } |
24 | return p; |
25 | } |
26 | |
27 | void sfree(void *p) { |
28 | if (p) { |
29 | free(p); |
30 | } |
31 | } |
32 | |
33 | void *srealloc(void *p, size_t size) { |
34 | void *q; |
35 | if (p) { |
36 | q = realloc(p, size); |
37 | } else { |
38 | q = malloc(size); |
39 | } |
40 | if (!q) |
41 | fatal("out of memory"); |
42 | return q; |
43 | } |
44 | |
45 | char *dupstr(const char *s) { |
46 | char *r = smalloc(1+strlen(s)); |
47 | strcpy(r,s); |
48 | return r; |
49 | } |
50 | |
51 | char *dupfmt(const char *fmt, ...) |
52 | { |
53 | int pass; |
54 | int totallen; |
55 | char *ret = NULL, *rp = NULL; |
56 | char datebuf[80]; |
57 | va_list ap; |
58 | time_t t; |
59 | struct tm tm; |
60 | int got_time = 0; |
61 | |
62 | datebuf[0] = '\0'; |
63 | totallen = 0; |
64 | |
65 | for (pass = 0; pass < 2; pass++) { |
66 | const char *p = fmt; |
67 | |
68 | va_start(ap, fmt); |
69 | |
70 | while (*p) { |
71 | const char *data = NULL; |
25b3befe |
72 | int datalen = 0, stuffcr = 0, htmlesc = 0; |
70322ae3 |
73 | |
74 | if (*p == '%') { |
75 | p++; |
76 | if (*p == 'D') { |
77 | if (!datebuf[0]) { |
78 | if (!got_time) { |
79 | t = time(NULL); |
80 | tm = *gmtime(&t); |
81 | got_time = 1; |
82 | } |
83 | strftime(datebuf, lenof(datebuf), |
84 | "%a, %d %b %Y %H:%M:%S GMT", &tm); |
85 | } |
86 | data = datebuf; |
87 | datalen = strlen(data); |
88 | } else if (*p == 'd') { |
89 | int i = va_arg(ap, int); |
90 | sprintf(datebuf, "%d", i); |
91 | data = datebuf; |
92 | datalen = strlen(data); |
93 | } else if (*p == 's') { |
94 | data = va_arg(ap, const char *); |
95 | datalen = strlen(data); |
25b3befe |
96 | } else if (*p == 'h') { |
97 | htmlesc = 1; |
98 | data = va_arg(ap, const char *); |
99 | datalen = strlen(data); |
70322ae3 |
100 | } else if (assert(*p == 'S'), 1) { |
101 | stuffcr = va_arg(ap, int); |
102 | data = va_arg(ap, const char *); |
103 | datalen = strlen(data); |
104 | } |
105 | p++; |
106 | } else { |
107 | data = p; |
108 | while (*p && *p != '%') p++; |
109 | datalen = p - data; |
110 | } |
111 | |
112 | if (pass == 0) { |
25b3befe |
113 | while (datalen > 0) { |
114 | totallen++; |
115 | if (stuffcr && *data == '\n') |
116 | totallen++; |
117 | if (htmlesc && |
118 | (*data == '<' || *data == '>' || *data == '&')) |
119 | totallen += 4; /* max(len("gt;"),len("amp;")) */ |
120 | data++, datalen--; |
70322ae3 |
121 | } |
122 | } else { |
123 | while (datalen > 0) { |
25b3befe |
124 | if (htmlesc && (*data < 32 || *data >= 127)) |
125 | *rp++ = '?'; /* *shrug* */ |
126 | else if (htmlesc && *data == '<') |
127 | rp += sprintf(rp, "<"); |
128 | else if (htmlesc && *data == '>') |
129 | rp += sprintf(rp, ">"); |
130 | else if (htmlesc && *data == '&') |
131 | rp += sprintf(rp, "&"); |
132 | else if (stuffcr && *data == '\n') |
133 | *rp++ = '\r', *rp++ = '\n'; |
134 | else |
135 | *rp++ = *data; |
136 | data++, datalen--; |
70322ae3 |
137 | } |
138 | } |
139 | } |
140 | |
141 | va_end(ap); |
142 | |
143 | if (pass == 0) { |
144 | rp = ret = snewn(totallen+1, char); |
145 | } else { |
146 | assert(rp - ret == totallen); |
147 | *rp = '\0'; |
148 | } |
149 | } |
150 | |
151 | return ret; |
152 | } |