1 /*
2  * alloc.c: implementation of alloc.h
3  */
4 
5 #include "agedu.h"
6 #include "alloc.h"
7 
8 extern void fatal(const char *, ...);
9 
smalloc(size_t size)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 
sfree(void * p)19 void sfree(void *p) {
20     if (p) {
21 	free(p);
22     }
23 }
24 
srealloc(void * p,size_t size)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 
dupstr(const char * s)37 char *dupstr(const char *s) {
38     char *r = smalloc(1+strlen(s));
39     strcpy(r,s);
40     return r;
41 }
42 
dupfmt(const char * fmt,...)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     bool got_time = false;
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;
64 	    int datalen = 0, stuffcr = 0, htmlesc = 0;
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 = true;
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);
88 		} else if (*p == 'h') {
89 		    htmlesc = 1;
90 		    data = va_arg(ap, const char *);
91 		    datalen = strlen(data);
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) {
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--;
113 		}
114 	    } else {
115 		while (datalen > 0) {
116 		    if (htmlesc && (*data < 32 || *data >= 127))
117 			*rp++ = '?';   /* *shrug* */
118 		    else if (htmlesc && *data == '<')
119 			rp += sprintf(rp, "&lt;");
120 		    else if (htmlesc && *data == '>')
121 			rp += sprintf(rp, "&gt;");
122 		    else if (htmlesc && *data == '&')
123 			rp += sprintf(rp, "&amp;");
124 		    else if (stuffcr && *data == '\n')
125 			*rp++ = '\r', *rp++ = '\n';
126 		    else
127 			*rp++ = *data;
128 		    data++, datalen--;
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 }
145