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