Various polishing: man page tweaks, --version now does something,
[sgt/agedu] / alloc.c
1 /*
2 * alloc.c: implementation of alloc.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 "agedu.h"
13 #include "alloc.h"
14
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;
71 int datalen = 0, stuffcr = 0, htmlesc = 0;
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);
95 } else if (*p == 'h') {
96 htmlesc = 1;
97 data = va_arg(ap, const char *);
98 datalen = strlen(data);
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) {
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--;
120 }
121 } else {
122 while (datalen > 0) {
123 if (htmlesc && (*data < 32 || *data >= 127))
124 *rp++ = '?'; /* *shrug* */
125 else if (htmlesc && *data == '<')
126 rp += sprintf(rp, "&lt;");
127 else if (htmlesc && *data == '>')
128 rp += sprintf(rp, "&gt;");
129 else if (htmlesc && *data == '&')
130 rp += sprintf(rp, "&amp;");
131 else if (stuffcr && *data == '\n')
132 *rp++ = '\r', *rp++ = '\n';
133 else
134 *rp++ = *data;
135 data++, datalen--;
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 }