1 #include "../include/config.h"
2 #include "../include/common.h"
3
4 /*
5 * This file holds random utility functions shared by cgi's and
6 * core.
7 */
8 extern int date_format;
9
10 /* fix the problem with strtok() skipping empty options between tokens */
my_strtok(char * buffer,char * tokens)11 char *my_strtok(char *buffer, char *tokens) {
12 char *token_position = NULL;
13 char *sequence_head = NULL;
14 static char *my_strtok_buffer = NULL;
15 static char *original_my_strtok_buffer = NULL;
16
17 if(buffer != NULL) {
18 my_free(original_my_strtok_buffer);
19 if((my_strtok_buffer = (char *)strdup(buffer)) == NULL)
20 return NULL;
21 original_my_strtok_buffer = my_strtok_buffer;
22 }
23
24 sequence_head = my_strtok_buffer;
25
26 if(sequence_head[0] == '\x0')
27 return NULL;
28
29 token_position = strchr(my_strtok_buffer, tokens[0]);
30
31 if(token_position == NULL) {
32 my_strtok_buffer = strchr(my_strtok_buffer, '\x0');
33 return sequence_head;
34 }
35
36 token_position[0] = '\x0';
37 my_strtok_buffer = token_position + 1;
38
39 return sequence_head;
40 }
41
42 /* fixes compiler problems under Solaris, since strsep() isn't included */
43 /* this code is taken from the glibc source */
my_strsep(char ** stringp,const char * delim)44 char *my_strsep(char **stringp, const char *delim) {
45 char *begin, *end;
46
47 begin = *stringp;
48 if(begin == NULL)
49 return NULL;
50
51 /* A frequent case is when the delimiter string contains only one
52 * character. Here we don't need to call the expensive `strpbrk'
53 * function and instead work using `strchr'. */
54 if(delim[0] == '\0' || delim[1] == '\0') {
55 char ch = delim[0];
56
57 if(ch == '\0' || begin[0] == '\0')
58 end = NULL;
59 else {
60 if(*begin == ch)
61 end = begin;
62 else
63 end = strchr(begin + 1, ch);
64 }
65 }
66 else {
67 /* find the end of the token. */
68 end = strpbrk(begin, delim);
69 }
70
71 if(end) {
72 /* terminate the token and set *STRINGP past NUL character. */
73 *end++ = '\0';
74 *stringp = end;
75 }
76 else
77 /* no more delimiters; this is the last token. */
78 *stringp = NULL;
79
80 return begin;
81 }
82
83 /* open a file read-only via mmap() */
mmap_fopen(char * filename)84 mmapfile *mmap_fopen(char *filename) {
85 mmapfile *new_mmapfile = NULL;
86 int fd = 0;
87 void *mmap_buf = NULL;
88 struct stat statbuf;
89 int mode = O_RDONLY;
90 unsigned long file_size = 0L;
91
92 if(filename == NULL)
93 return NULL;
94
95 /* allocate memory */
96 if((new_mmapfile = (mmapfile *) malloc(sizeof(mmapfile))) == NULL)
97 return NULL;
98
99 /* open the file */
100 if((fd = open(filename, mode)) == -1) {
101 my_free(new_mmapfile);
102 return NULL;
103 }
104
105 /* get file info */
106 if((fstat(fd, &statbuf)) == -1) {
107 close(fd);
108 my_free(new_mmapfile);
109 return NULL;
110 }
111
112 /* get file size */
113 file_size = (unsigned long)statbuf.st_size;
114
115 /* only mmap() if we have a file greater than 0 bytes */
116 if(file_size > 0) {
117
118 /* mmap() the file - allocate one extra byte for processing zero-byte files */
119 if((mmap_buf =
120 (void *)mmap(0, file_size, PROT_READ, MAP_PRIVATE, fd,
121 0)) == MAP_FAILED) {
122 close(fd);
123 my_free(new_mmapfile);
124 return NULL;
125 }
126 }
127 else
128 mmap_buf = NULL;
129
130 /* populate struct info for later use */
131 new_mmapfile->path = (char *)strdup(filename);
132 new_mmapfile->fd = fd;
133 new_mmapfile->file_size = (unsigned long)file_size;
134 new_mmapfile->current_position = 0L;
135 new_mmapfile->current_line = 0L;
136 new_mmapfile->mmap_buf = mmap_buf;
137
138 return new_mmapfile;
139 }
140
141 /* close a file originally opened via mmap() */
mmap_fclose(mmapfile * temp_mmapfile)142 int mmap_fclose(mmapfile * temp_mmapfile) {
143
144 if(temp_mmapfile == NULL)
145 return ERROR;
146
147 /* un-mmap() the file */
148 if(temp_mmapfile->file_size > 0L)
149 munmap(temp_mmapfile->mmap_buf, temp_mmapfile->file_size);
150
151 /* close the file */
152 close(temp_mmapfile->fd);
153
154 /* free memory */
155 my_free(temp_mmapfile->path);
156 my_free(temp_mmapfile);
157
158 return OK;
159 }
160
161 /* gets one line of input from an mmap()'ed file */
mmap_fgets(mmapfile * temp_mmapfile)162 char *mmap_fgets(mmapfile * temp_mmapfile) {
163 char *buf = NULL;
164 unsigned long x = 0L;
165 int len = 0;
166
167 if(temp_mmapfile == NULL)
168 return NULL;
169
170 /* size of file is 0 bytes */
171 if(temp_mmapfile->file_size == 0L)
172 return NULL;
173
174 /* we've reached the end of the file */
175 if(temp_mmapfile->current_position >= temp_mmapfile->file_size)
176 return NULL;
177
178 /* find the end of the string (or buffer) */
179 for(x = temp_mmapfile->current_position; x < temp_mmapfile->file_size;
180 x++) {
181 if(*((char *)(temp_mmapfile->mmap_buf) + x) == '\n') {
182 x++;
183 break;
184 }
185 }
186
187 /* calculate length of line we just read */
188 len = (int)(x - temp_mmapfile->current_position);
189
190 /* allocate memory for the new line */
191 if((buf = (char *)malloc(len + 1)) == NULL)
192 return NULL;
193
194 /* copy string to newly allocated memory and terminate the string */
195 memcpy(buf,
196 ((char *)(temp_mmapfile->mmap_buf) +
197 temp_mmapfile->current_position), len);
198 buf[len] = '\x0';
199
200 /* update the current position */
201 temp_mmapfile->current_position = x;
202
203 /* increment the current line */
204 temp_mmapfile->current_line++;
205
206 return buf;
207 }
208
209 /* gets one line of input from an mmap()'ed file (may be contained on more than one line in the source file) */
mmap_fgets_multiline(mmapfile * temp_mmapfile)210 char *mmap_fgets_multiline(mmapfile * temp_mmapfile) {
211 char *buf = NULL;
212 char *tempbuf = NULL;
213 char *stripped = NULL;
214 int len = 0;
215 int len2 = 0;
216 int end = 0;
217
218 if(temp_mmapfile == NULL)
219 return NULL;
220
221 while(1) {
222
223 my_free(tempbuf);
224
225 if((tempbuf = mmap_fgets(temp_mmapfile)) == NULL)
226 break;
227
228 if(buf == NULL) {
229 len = strlen(tempbuf);
230 if((buf = (char *)malloc(len + 1)) == NULL)
231 break;
232 memcpy(buf, tempbuf, len);
233 buf[len] = '\x0';
234 }
235 else {
236 /* strip leading white space from continuation lines */
237 stripped = tempbuf;
238 while(*stripped == ' ' || *stripped == '\t')
239 stripped++;
240 len = strlen(stripped);
241 len2 = strlen(buf);
242 if((buf =
243 (char *)realloc(buf, len + len2 + 1)) == NULL)
244 break;
245 strcat(buf, stripped);
246 len += len2;
247 buf[len] = '\x0';
248 }
249
250 if(len == 0)
251 break;
252
253 /* handle Windows/DOS CR/LF */
254 if(len >= 2 && buf[len - 2] == '\r')
255 end = len - 3;
256 /* normal Unix LF */
257 else if(len >= 1 && buf[len - 1] == '\n')
258 end = len - 2;
259 else
260 end = len - 1;
261
262 /* two backslashes found. unescape first backslash first and break */
263 if(end >= 1 && buf[end - 1] == '\\' && buf[end] == '\\') {
264 buf[end] = '\n';
265 buf[end + 1] = '\x0';
266 break;
267 }
268
269 /* one backslash found. continue reading the next line */
270 else if(end > 0 && buf[end] == '\\')
271 buf[end] = '\x0';
272
273 /* no continuation marker was found, so break */
274 else
275 break;
276 }
277
278 my_free(tempbuf);
279
280 return buf;
281 }
282
283 /* strip newline, carriage return, and tab characters from beginning and end of a string */
strip(char * buffer)284 void strip(char *buffer) {
285 register int x, z;
286 int len;
287
288 if(buffer == NULL || buffer[0] == '\x0')
289 return;
290
291 /* strip end of string */
292 len = (int)strlen(buffer);
293 for(x = len - 1; x >= 0; x--) {
294 switch(buffer[x]) {
295 case ' ':
296 case '\n':
297 case '\r':
298 case '\t':
299 buffer[x] = '\x0';
300 continue;
301 }
302 break;
303 }
304
305 /* if we stripped all of it, just return */
306 if(!x)
307 return;
308
309 /* save last position for later... */
310 z = x;
311
312 /* strip beginning of string (by shifting) */
313 /* NOTE: this is very expensive to do, so avoid it whenever possible */
314 for(x = 0;; x++) {
315 switch(buffer[x]) {
316 case ' ':
317 case '\n':
318 case '\r':
319 case '\t':
320 continue;
321 }
322 break;
323 }
324
325 if(x > 0 && z > 0) {
326 /* new length of the string after we stripped the end */
327 len = z + 1;
328
329 /* shift chars towards beginning of string to remove leading whitespace */
330 for(z = x; z < len; z++)
331 buffer[z - x] = buffer[z];
332 buffer[len - x] = '\x0';
333 }
334 }
335
336 /**************************************************
337 *************** HASH FUNCTIONS *******************
338 **************************************************/
339 /* dual hash function */
hashfunc(const char * name1,const char * name2,int hashslots)340 int hashfunc(const char *name1, const char *name2, int hashslots) {
341 unsigned int i, result;
342
343 result = 0;
344
345 if(name1)
346 for(i = 0; i < strlen(name1); i++)
347 result += name1[i];
348
349 if(name2)
350 for(i = 0; i < strlen(name2); i++)
351 result += name2[i];
352
353 result = result % hashslots;
354
355 return result;
356 }
357
358 /* dual hash data comparison */
compare_hashdata(const char * val1a,const char * val1b,const char * val2a,const char * val2b)359 int compare_hashdata(const char *val1a, const char *val1b, const char *val2a,
360 const char *val2b) {
361 int result = 0;
362
363 /* NOTE: If hash calculation changes, update the compare_strings() function! */
364
365 /* check first name */
366 if(val1a == NULL && val2a == NULL)
367 result = 0;
368 else if(val1a == NULL)
369 result = 1;
370 else if(val2a == NULL)
371 result = -1;
372 else
373 result = strcmp(val1a, val2a);
374
375 /* check second name if necessary */
376 if(result == 0) {
377 if(val1b == NULL && val2b == NULL)
378 result = 0;
379 else if(val1b == NULL)
380 result = 1;
381 else if(val2b == NULL)
382 result = -1;
383 else
384 result = strcmp(val1b, val2b);
385 }
386
387 return result;
388 }
389 /*
390 * given a date/time in time_t format, produce a corresponding
391 * date/time string, including timezone
392 */
get_datetime_string(time_t * raw_time,char * buffer,int buffer_length,int type)393 void get_datetime_string(time_t * raw_time, char *buffer, int buffer_length,
394 int type) {
395 time_t t;
396 struct tm *tm_ptr, tm_s;
397 int hour;
398 int minute;
399 int second;
400 int month;
401 int day;
402 int year;
403 char *weekdays[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
404 char *months[12] = {
405 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept",
406 "Oct", "Nov", "Dec"
407 };
408 char *tzone = "";
409
410 if(raw_time == NULL)
411 time(&t);
412 else
413 t = *raw_time;
414
415 if(type == HTTP_DATE_TIME)
416 tm_ptr = gmtime_r(&t, &tm_s);
417 else
418 tm_ptr = localtime_r(&t, &tm_s);
419
420 hour = tm_ptr->tm_hour;
421 minute = tm_ptr->tm_min;
422 second = tm_ptr->tm_sec;
423 month = tm_ptr->tm_mon + 1;
424 day = tm_ptr->tm_mday;
425 year = tm_ptr->tm_year + 1900;
426
427 #ifdef HAVE_TM_ZONE
428 tzone = (char *)(tm_ptr->tm_zone);
429 #else
430 tzone = (tm_ptr->tm_isdst) ? tzname[1] : tzname[0];
431 #endif
432
433 /* ctime() style date/time */
434 if(type == LONG_DATE_TIME)
435 snprintf(buffer, buffer_length, "%s %s %d %02d:%02d:%02d %s %d",
436 weekdays[tm_ptr->tm_wday], months[tm_ptr->tm_mon], day,
437 hour, minute, second, tzone, year);
438
439 /* short date/time */
440 else if(type == SHORT_DATE_TIME) {
441 if(date_format == DATE_FORMAT_EURO)
442 snprintf(buffer, buffer_length,
443 "%02d-%02d-%04d %02d:%02d:%02d", day, month,
444 year, hour, minute, second);
445 else if(date_format == DATE_FORMAT_ISO8601
446 || date_format == DATE_FORMAT_STRICT_ISO8601)
447 snprintf(buffer, buffer_length,
448 "%04d-%02d-%02d%c%02d:%02d:%02d", year, month,
449 day,
450 (date_format ==
451 DATE_FORMAT_STRICT_ISO8601) ? 'T' : ' ', hour,
452 minute, second);
453 else
454 snprintf(buffer, buffer_length,
455 "%02d-%02d-%04d %02d:%02d:%02d", month, day,
456 year, hour, minute, second);
457 }
458
459 /* short date */
460 else if(type == SHORT_DATE) {
461 if(date_format == DATE_FORMAT_EURO)
462 snprintf(buffer, buffer_length, "%02d-%02d-%04d", day,
463 month, year);
464 else if(date_format == DATE_FORMAT_ISO8601
465 || date_format == DATE_FORMAT_STRICT_ISO8601)
466 snprintf(buffer, buffer_length, "%04d-%02d-%02d", year,
467 month, day);
468 else
469 snprintf(buffer, buffer_length, "%02d-%02d-%04d", month,
470 day, year);
471 }
472
473 /* expiration date/time for HTTP headers */
474 else if(type == HTTP_DATE_TIME)
475 snprintf(buffer, buffer_length,
476 "%s, %02d %s %d %02d:%02d:%02d GMT",
477 weekdays[tm_ptr->tm_wday], day, months[tm_ptr->tm_mon],
478 year, hour, minute, second);
479
480 /* short time */
481 else
482 snprintf(buffer, buffer_length, "%02d:%02d:%02d", hour, minute,
483 second);
484
485 buffer[buffer_length - 1] = '\x0';
486 }
487
488 /* get days, hours, minutes, and seconds from a raw time_t format or total seconds */
get_time_breakdown(unsigned long raw_time,int * days,int * hours,int * minutes,int * seconds)489 void get_time_breakdown(unsigned long raw_time, int *days, int *hours,
490 int *minutes, int *seconds) {
491 unsigned long temp_time;
492 int temp_days;
493 int temp_hours;
494 int temp_minutes;
495 int temp_seconds;
496
497 temp_time = raw_time;
498
499 temp_days = temp_time / 86400;
500 temp_time -= (temp_days * 86400);
501 temp_hours = temp_time / 3600;
502 temp_time -= (temp_hours * 3600);
503 temp_minutes = temp_time / 60;
504 temp_time -= (temp_minutes * 60);
505 temp_seconds = (int)temp_time;
506
507 *days = temp_days;
508 *hours = temp_hours;
509 *minutes = temp_minutes;
510 *seconds = temp_seconds;
511 }
512