Merge branch 'search'
[collection4.git] / src / utils_params.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <time.h>
7
8 #include "utils_params.h"
9
10 struct parameter_s
11 {
12   char *key;
13   char *value;
14 };
15 typedef struct parameter_s parameter_t;
16
17 static parameter_t *parameters = NULL;
18 static size_t parameters_num = 0;
19 static _Bool parameters_init = 0;
20
21 static int parameter_add (const char *key, const char *value) /* {{{ */
22 {
23   parameter_t *ptr;
24
25   if (value == NULL)
26     return (EINVAL);
27
28   ptr = realloc (parameters, sizeof (*parameters) * (parameters_num + 1));
29   if (ptr == NULL)
30     return (ENOMEM);
31   parameters = ptr;
32
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   }
44
45   ptr->value = strdup (value);
46   if (ptr->value == NULL)
47   {
48     free (ptr->key);
49     return (ENOMEM);
50   }
51
52   parameters_num++;
53   return (0);
54 } /* }}} int parameter_add */
55
56 static char *parameter_lookup (const char *key) /* {{{ */
57 {
58   size_t i;
59
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   }
68
69   return (NULL);
70 } /* }}} char *parameter_lookup */
71
72 static char *uri_unescape (char *string) /* {{{ */
73 {
74   char *in;
75   char *out;
76
77   if (string == NULL)
78     return (NULL);
79
80   in = string;
81   out = string;
82
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;
95
96       tmpstr[0] = in[1];
97       tmpstr[1] = in[2];
98       tmpstr[2] = 0;
99
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       }
111
112       in += 2;
113     }
114     else
115     {
116       *out = *in;
117     }
118
119     in++;
120     out++;
121   } /* while (*in != 0) */
122
123   *out = 0;
124   return (string);
125 } /* }}} char *uri_unescape */
126
127 static int parse_keyval (char *keyval) /* {{{ */
128 {
129   char *key;
130   char *val;
131
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   }
144
145   parameter_add (uri_unescape (key), uri_unescape (val));
146
147   return (0);
148 } /* }}} int parse_keyval */
149
150 static int parse_query_string (char *query_string) /* {{{ */
151 {
152   char *dummy;
153   char *keyval;
154
155   if (query_string == NULL)
156     return (EINVAL);
157
158   dummy = query_string;
159   while ((keyval = strtok (dummy, ";&")) != NULL)
160   {
161     dummy = NULL;
162     parse_keyval (keyval);
163   }
164
165   return (0);
166 } /* }}} int parse_query_string */
167
168 int param_init (void) /* {{{ */
169 {
170   const char *query_string;
171   char *copy;
172   int status;
173
174   if (parameters_init)
175     return (0);
176
177   query_string = getenv ("QUERY_STRING");
178   if (query_string == NULL)
179     return (ENOENT);
180
181   copy = strdup (query_string);
182   if (copy == NULL)
183     return (ENOMEM);
184
185   status = parse_query_string (copy);
186   free (copy);
187
188   parameters_init = 1;
189
190   return (status);
191 } /* }}} int param_init */
192
193 void param_finish (void) /* {{{ */
194 {
195   size_t i;
196
197   if (!parameters_init)
198     return;
199
200   for (i = 0; i < parameters_num; i++)
201   {
202     free (parameters[i].key);
203     free (parameters[i].value);
204   }
205   free (parameters);
206
207   parameters = NULL;
208   parameters_num = 0;
209   parameters_init = 0;
210 } /* }}} void param_finish */
211
212 const char *param (const char *key) /* {{{ */
213 {
214   param_init ();
215
216   return (parameter_lookup (key));
217 } /* }}} const char *param */
218
219 int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
220 {
221   size_t in;
222   size_t out;
223
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];
239
240       if ((size - out) < 4)
241         break;
242       
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];
247
248       out += 3;
249       in++;
250     }
251     else
252     {
253       dst[out] = src[in];
254       out++;
255       in++;
256     }
257   } /* while (42) */
258
259   return (0);
260 } /* }}} int uri_escape */
261
262 const char *script_name (void) /* {{{ */
263 {
264   char *ret;
265
266   ret = getenv ("SCRIPT_NAME");
267   if (ret == NULL)
268     ret = "collection4.fcgi";
269
270   return (ret);
271 } /* }}} char *script_name */
272
273 int time_to_rfc1123 (time_t t, char *buffer, size_t buffer_size) /* {{{ */
274 {
275   struct tm tm_tmp;
276   size_t status;
277
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);
283
284   status = strftime (buffer, buffer_size, "%a, %d %b %Y %T GMT", &tm_tmp);
285   if (status == 0)
286     return (errno);
287
288   return (0);
289 } /* }}} int time_to_rfc1123 */
290
291 /* vim: set sw=2 sts=2 et fdm=marker : */