1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <time.h>
8 #include "utils_cgi.h"
10 struct parameter_s
11 {
12 char *key;
13 char *value;
14 };
15 typedef struct parameter_s parameter_t;
17 static parameter_t *parameters = NULL;
18 static size_t parameters_num = 0;
19 static _Bool parameters_init = 0;
21 static int parameter_add (const char *key, const char *value) /* {{{ */
22 {
23 parameter_t *ptr;
25 if (value == NULL)
26 return (EINVAL);
28 ptr = realloc (parameters, sizeof (*parameters) * (parameters_num + 1));
29 if (ptr == NULL)
30 return (ENOMEM);
31 parameters = ptr;
33 ptr = parameters + parameters_num;
34 if (key == NULL)
35 {
36 ptr->key = NULL;
37 }
38 else
39 {
40 ptr->key = strdup (key);
41 if (ptr->key == NULL)
42 return (ENOMEM);
43 }
45 ptr->value = strdup (value);
46 if (ptr->value == NULL)
47 {
48 free (ptr->key);
49 return (ENOMEM);
50 }
52 parameters_num++;
53 return (0);
54 } /* }}} int parameter_add */
56 static char *parameter_lookup (const char *key) /* {{{ */
57 {
58 size_t i;
60 for (i = 0; i < parameters_num; i++)
61 {
62 if ((key == NULL) && (parameters[i].key == NULL))
63 return (parameters[i].value);
64 else if ((key != NULL) && (parameters[i].key != NULL)
65 && (strcmp (key, parameters[i].key) == 0))
66 return (parameters[i].value);
67 }
69 return (NULL);
70 } /* }}} char *parameter_lookup */
72 static char *uri_unescape (char *string) /* {{{ */
73 {
74 char *in;
75 char *out;
77 if (string == NULL)
78 return (NULL);
80 in = string;
81 out = string;
83 while (*in != 0)
84 {
85 if (*in == '+')
86 {
87 *out = ' ';
88 }
89 else if ((in[0] == '%')
90 && isxdigit ((int) in[1]) && isxdigit ((int) in[2]))
91 {
92 char tmpstr[3];
93 char *endptr;
94 long value;
96 tmpstr[0] = in[1];
97 tmpstr[1] = in[2];
98 tmpstr[2] = 0;
100 errno = 0;
101 endptr = NULL;
102 value = strtol (tmpstr, &endptr, /* base = */ 16);
103 if ((endptr == tmpstr) || (errno != 0))
104 {
105 *out = '?';
106 }
107 else
108 {
109 *out = (char) value;
110 }
112 in += 2;
113 }
114 else
115 {
116 *out = *in;
117 }
119 in++;
120 out++;
121 } /* while (*in != 0) */
123 *out = 0;
124 return (string);
125 } /* }}} char *uri_unescape */
127 static int parse_keyval (char *keyval) /* {{{ */
128 {
129 char *key;
130 char *val;
132 val = strchr (keyval, '=');
133 if (val == NULL)
134 {
135 key = NULL;
136 val = keyval;
137 }
138 else
139 {
140 key = keyval;
141 *val = 0;
142 val++;
143 }
145 parameter_add (uri_unescape (key), uri_unescape (val));
147 return (0);
148 } /* }}} int parse_keyval */
150 static int parse_query_string (char *query_string) /* {{{ */
151 {
152 char *dummy;
153 char *keyval;
155 if (query_string == NULL)
156 return (EINVAL);
158 dummy = query_string;
159 while ((keyval = strtok (dummy, ";&")) != NULL)
160 {
161 dummy = NULL;
162 parse_keyval (keyval);
163 }
165 return (0);
166 } /* }}} int parse_query_string */
168 int param_init (void) /* {{{ */
169 {
170 const char *query_string;
171 char *copy;
172 int status;
174 if (parameters_init)
175 return (0);
177 query_string = getenv ("QUERY_STRING");
178 if (query_string == NULL)
179 return (ENOENT);
181 copy = strdup (query_string);
182 if (copy == NULL)
183 return (ENOMEM);
185 status = parse_query_string (copy);
186 free (copy);
188 parameters_init = 1;
190 return (status);
191 } /* }}} int param_init */
193 void param_finish (void) /* {{{ */
194 {
195 size_t i;
197 if (!parameters_init)
198 return;
200 for (i = 0; i < parameters_num; i++)
201 {
202 free (parameters[i].key);
203 free (parameters[i].value);
204 }
205 free (parameters);
207 parameters = NULL;
208 parameters_num = 0;
209 parameters_init = 0;
210 } /* }}} void param_finish */
212 const char *param (const char *key) /* {{{ */
213 {
214 param_init ();
216 return (parameter_lookup (key));
217 } /* }}} const char *param */
219 int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
220 {
221 size_t in;
222 size_t out;
224 in = 0;
225 out = 0;
226 while (42)
227 {
228 if (src[in] == 0)
229 {
230 dst[out] = 0;
231 return (0);
232 }
233 else if ((src[in] < 32)
234 || (src[in] == '&')
235 || (src[in] == ';')
236 || (((unsigned char) src[in]) >= 128))
237 {
238 char esc[4];
240 if ((size - out) < 4)
241 break;
243 snprintf (esc, sizeof (esc), "%%%02x", (unsigned int) src[in]);
244 dst[out] = esc[0];
245 dst[out+1] = esc[1];
246 dst[out+2] = esc[2];
248 out += 3;
249 in++;
250 }
251 else
252 {
253 dst[out] = src[in];
254 out++;
255 in++;
256 }
257 } /* while (42) */
259 return (0);
260 } /* }}} int uri_escape */
262 const char *script_name (void) /* {{{ */
263 {
264 char *ret;
266 ret = getenv ("SCRIPT_NAME");
267 if (ret == NULL)
268 ret = "collection4.fcgi";
270 return (ret);
271 } /* }}} char *script_name */
273 int time_to_rfc1123 (time_t t, char *buffer, size_t buffer_size) /* {{{ */
274 {
275 struct tm tm_tmp;
276 size_t status;
278 /* RFC 1123 *requires* the time to be GMT and the "GMT" timezone string.
279 * Apache will ignore the timezone if "localtime_r" and "%z" is used,
280 * resulting in weird behavior. */
281 if (gmtime_r (&t, &tm_tmp) == NULL)
282 return (errno);
284 status = strftime (buffer, buffer_size, "%a, %d %b %Y %T GMT", &tm_tmp);
285 if (status == 0)
286 return (errno);
288 return (0);
289 } /* }}} int time_to_rfc1123 */
291 #define COPY_ENTITY(e) do { \
292 size_t len = strlen (e); \
293 if (dest_size < (len + 1)) \
294 break; \
295 strcpy (dest_ptr, (e)); \
296 dest_ptr += len; \
297 dest_size -= len; \
298 } while (0)
300 char *html_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
301 {
302 char *dest_ptr;
303 size_t dest_size;
304 size_t pos;
306 dest[0] = 0;
307 dest_ptr = dest;
308 dest_size = n;
309 for (pos = 0; src[pos] != 0; pos++)
310 {
311 if (src[pos] == '"')
312 COPY_ENTITY (""");
313 else if (src[pos] == '<')
314 COPY_ENTITY ("<");
315 else if (src[pos] == '>')
316 COPY_ENTITY (">");
317 else if (src[pos] == '&')
318 COPY_ENTITY ("&");
319 else
320 {
321 *dest_ptr = src[pos];
322 dest_ptr++;
323 dest_size--;
324 *dest_ptr = 0;
325 }
327 if (dest_size <= 1)
328 break;
329 }
331 return (dest);
332 } /* }}} char *html_escape_copy */
334 #undef COPY_ENTITY
336 char *html_escape_buffer (char *buffer, size_t buffer_size) /* {{{ */
337 {
338 char tmp[buffer_size];
340 html_escape_copy (tmp, buffer, sizeof (tmp));
341 memcpy (buffer, tmp, buffer_size);
343 return (buffer);
344 } /* }}} char *html_escape_buffer */
346 char *html_escape (const char *string) /* {{{ */
347 {
348 char buffer[4096];
350 if (string == NULL)
351 return (NULL);
353 html_escape_copy (buffer, string, sizeof (buffer));
355 return (strdup (buffer));
356 } /* }}} char *html_escape */
358 /* vim: set sw=2 sts=2 et fdm=marker : */