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