1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif /* HAVE_CONFIG_H */
4
5 #include <strings.h>
6 #include <inttypes.h>
7 #include <ctype.h>
8 #include <time.h>
9
10 #include "evil_private.h"
11
12 /*
13 * gettimeofday
14 * based on https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-crt/misc/gettimeofday.c
15 * public domain
16 */
17
18 #define FILETIME_1970 116444736000000000ull /* seconds between 1/1/1601 and 1/1/1970 */
19
evil_gettimeofday(struct timeval * tv,struct timezone * tz)20 int evil_gettimeofday(struct timeval *tv, struct timezone *tz)
21 {
22 int res = 0;
23 union
24 {
25 unsigned long long ns100; /* time since 1 Jan 1601 in 100ns units */
26 FILETIME ft;
27 } _now;
28 TIME_ZONE_INFORMATION time_zone_information;
29 DWORD tzi;
30
31 if (tz != NULL)
32 {
33 tzi = GetTimeZoneInformation(&time_zone_information);
34 if (tzi != TIME_ZONE_ID_INVALID)
35 {
36 tz->tz_minuteswest = time_zone_information.Bias;
37 if (tzi == TIME_ZONE_ID_DAYLIGHT)
38 tz->tz_dsttime = 1;
39 else
40 tz->tz_dsttime = 0;
41 }
42 else
43 {
44 tz->tz_minuteswest = 0;
45 tz->tz_dsttime = 0;
46 }
47 }
48
49 if (tv != NULL)
50 {
51 #if _WIN32_WINNT < 0x0602
52 GetSystemTimeAsFileTime(&_now.ft);
53 #else
54 GetSystemTimePreciseAsFileTime(&_now.ft);
55 #endif
56 _now.ns100 -= FILETIME_1970; /* 100 nano-seconds since 1-1-1970 */
57 tv->tv_sec = _now.ns100 / 10000000ull; /* seconds since 1-1-1970 */
58 tv->tv_usec = (long) (_now.ns100 % 10000000ull) /10; /* nanoseconds */
59 }
60
61 return res;
62 }
63
64 /*
65 * strptime
66 * based on http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/time/strptime.c?rev=HEAD
67 * BSD licence
68 */
69
70 #define TM_YEAR_BASE 1900
71
72 /*
73 * We do not implement alternate representations. However, we always
74 * check whether a given modifier is allowed for a certain conversion.
75 */
76 #define ALT_E 0x01
77 #define ALT_O 0x02
78 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; }
79
80
81 static const char *day[7] =
82 {
83 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
84 };
85
86 static const char *abday[7] =
87 {
88 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
89 };
90
91 static const char *mon[12] =
92 {
93 "January", "February", "March", "April", "May", "June", "July",
94 "August", "September", "October", "November", "December"
95 };
96
97 static const char *abmon[12] =
98 {
99 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
100 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
101 };
102
103 static const char *am_pm[2] =
104 {
105 "AM", "PM"
106 };
107
108 static char gmt[] = { "GMT" };
109
110 #ifdef TM_ZONE
111 static char utc[] = { "UTC" };
112 #endif
113
114 /* RFC-822/RFC-2822 */
115 static const char * const nast[5] = {
116 "EST", "CST", "MST", "PST", "\0\0\0"
117 };
118
119 static const char * const nadt[5] = {
120 "EDT", "CDT", "MDT", "PDT", "\0\0\0"
121 };
122
123 static const unsigned char *
find_string(const unsigned char * bp,int * tgt,const char * const * n1,const char * const * n2,int c)124 find_string(const unsigned char *bp, int *tgt,
125 const char *const *n1, const char *const *n2,
126 int c)
127 {
128 size_t len;
129 int i;
130
131 /* check full name - then abbreviated ones */
132 for (; n1 != NULL; n1 = n2, n2 = NULL)
133 {
134 for (i = 0; i < c; i++, n1++)
135 {
136 len = strlen(*n1);
137 if (strncasecmp(*n1, (const char *)bp, len) == 0)
138 {
139 *tgt = i;
140 return bp + len;
141 }
142 }
143 }
144
145 /* Nothing matched */
146 return NULL;
147 }
148
149 static const unsigned char *
conv_num(const unsigned char * buf,int * dest,unsigned int llim,unsigned int ulim)150 conv_num(const unsigned char *buf, int *dest, unsigned int llim, unsigned int ulim)
151 {
152 unsigned int result = 0;
153 unsigned char ch;
154
155 /* The limit also determines the number of valid digits. */
156 unsigned int rulim = ulim;
157
158 ch = *buf;
159 if (ch < '0' || ch > '9')
160 return NULL;
161
162 do {
163 result *= 10;
164 result += ch - '0';
165 rulim /= 10;
166 ch = *++buf;
167 } while ((result * 10 <= ulim) && rulim && (ch >= '0') && (ch <= '9'));
168
169 if ((result < llim) || (result > ulim))
170 return NULL;
171
172 *dest = result;
173 return buf;
174 }
175
176 char *
strptime(const char * buf,const char * fmt,struct tm * tm)177 strptime(const char *buf, const char *fmt, struct tm *tm)
178 {
179 unsigned char c;
180 const unsigned char *bp, *ep;
181 int alt_format, i, split_year = 0, neg = 0, offs;
182 const char *new_fmt;
183
184 bp = (const unsigned char *)buf;
185
186 while (bp != NULL && (c = *fmt++) != '\0')
187 {
188 /* Clear `alternate' modifier prior to new conversion. */
189 alt_format = 0;
190 i = 0;
191
192 /* Eat up white-space. */
193 if (isspace(c))
194 {
195 while (isspace(*bp))
196 bp++;
197 continue;
198 }
199
200 if (c != '%')
201 goto literal;
202
203 again:
204 switch (c = *fmt++)
205 {
206 case '%': /* "%%" is converted to "%". */
207 literal:
208 if (c != *bp++)
209 return NULL;
210 LEGAL_ALT(0);
211 continue;
212
213 /*
214 * "Alternative" modifiers. Just set the appropriate flag
215 * and start over again.
216 */
217 case 'E': /* "%E?" alternative conversion modifier. */
218 LEGAL_ALT(0);
219 alt_format |= ALT_E;
220 goto again;
221
222 case 'O': /* "%O?" alternative conversion modifier. */
223 LEGAL_ALT(0);
224 alt_format |= ALT_O;
225 goto again;
226
227 /*
228 * "Complex" conversion rules, implemented through recursion.
229 */
230 /* case 'c': /\* Date and time, using the locale's format. *\/ */
231 /* new_fmt = _TIME_LOCALE(loc)->d_t_fmt; */
232 /* goto recurse; */
233
234 case 'D': /* The date as "%m/%d/%y". */
235 new_fmt = "%m/%d/%y";
236 LEGAL_ALT(0);
237 goto recurse;
238
239 case 'F': /* The date as "%Y-%m-%d". */
240 new_fmt = "%Y-%m-%d";
241 LEGAL_ALT(0);
242 goto recurse;
243
244 case 'R': /* The time as "%H:%M". */
245 new_fmt = "%H:%M";
246 LEGAL_ALT(0);
247 goto recurse;
248
249 /* case 'r': /\* The time in 12-hour clock representation. *\/ */
250 /* new_fmt = _TIME_LOCALE(loc)->t_fmt_ampm; */
251 /* LEGAL_ALT(0); */
252 /* goto recurse; */
253
254 case 'T': /* The time as "%H:%M:%S". */
255 new_fmt = "%H:%M:%S";
256 LEGAL_ALT(0);
257 goto recurse;
258
259 /* case 'X': /\* The time, using the locale's format. *\/ */
260 /* new_fmt = _TIME_LOCALE(loc)->t_fmt; */
261 /* goto recurse; */
262
263 /* case 'x': /\* The date, using the locale's format. *\/ */
264 /* new_fmt = _TIME_LOCALE(loc)->d_fmt; */
265 recurse:
266 bp = (const unsigned char *)strptime((const char *)bp,
267 new_fmt, tm);
268 LEGAL_ALT(ALT_E);
269 continue;
270
271 /*
272 * "Elementary" conversion rules.
273 */
274 case 'A': /* The day of week, using the locale's form. */
275 case 'a':
276 bp = find_string(bp, &tm->tm_wday, day, abday, 7);
277 LEGAL_ALT(0);
278 continue;
279
280 case 'B': /* The month, using the locale's form. */
281 case 'b':
282 case 'h':
283 bp = find_string(bp, &tm->tm_mon, mon, abmon, 12);
284 LEGAL_ALT(0);
285 continue;
286
287 case 'C': /* The century number. */
288 i = 20;
289 bp = conv_num(bp, &i, 0, 99);
290
291 i = i * 100 - TM_YEAR_BASE;
292 if (split_year)
293 i += tm->tm_year % 100;
294 split_year = 1;
295 tm->tm_year = i;
296 LEGAL_ALT(ALT_E);
297 continue;
298
299 case 'd': /* The day of month. */
300 case 'e':
301 bp = conv_num(bp, &tm->tm_mday, 1, 31);
302 LEGAL_ALT(ALT_O);
303 continue;
304
305 case 'k': /* The hour (24-hour clock representation). */
306 LEGAL_ALT(0);
307 /* FALLTHROUGH */
308 case 'H':
309 bp = conv_num(bp, &tm->tm_hour, 0, 23);
310 LEGAL_ALT(ALT_O);
311 continue;
312
313 case 'l': /* The hour (12-hour clock representation). */
314 LEGAL_ALT(0);
315 /* FALLTHROUGH */
316 case 'I':
317 bp = conv_num(bp, &tm->tm_hour, 1, 12);
318 if (tm->tm_hour == 12)
319 tm->tm_hour = 0;
320 LEGAL_ALT(ALT_O);
321 continue;
322
323 case 'j': /* The day of year. */
324 i = 1;
325 bp = conv_num(bp, &i, 1, 366);
326 tm->tm_yday = i - 1;
327 LEGAL_ALT(0);
328 continue;
329
330 case 'M': /* The minute. */
331 bp = conv_num(bp, &tm->tm_min, 0, 59);
332 LEGAL_ALT(ALT_O);
333 continue;
334
335 case 'm': /* The month. */
336 i = 1;
337 bp = conv_num(bp, &i, 1, 12);
338 tm->tm_mon = i - 1;
339 LEGAL_ALT(ALT_O);
340 continue;
341
342 case 'p': /* The locale's equivalent of AM/PM. */
343 bp = find_string(bp, &i, am_pm, NULL, 2);
344 if (tm->tm_hour > 11)
345 return NULL;
346 tm->tm_hour += i * 12;
347 LEGAL_ALT(0);
348 continue;
349
350 case 'S': /* The seconds. */
351 bp = conv_num(bp, &tm->tm_sec, 0, 61);
352 LEGAL_ALT(ALT_O);
353 continue;
354
355 #ifndef TIME_MAX
356 # ifdef _WIN64
357 # define TIME_MAX INT64_MAX
358 # else
359 # define TIME_MAX INT32_MAX
360 # endif
361 #endif
362 case 's': /* seconds since the epoch */
363 {
364 time_t sse = 0;
365 __int64 rulim = TIME_MAX;
366
367 if (*bp < '0' || *bp > '9')
368 {
369 bp = NULL;
370 continue;
371 }
372
373 do
374 {
375 sse *= 10;
376 sse += *bp++ - '0';
377 rulim /= 10;
378 } while ((sse * 10 <= TIME_MAX) &&
379 rulim && *bp >= '0' && *bp <= '9');
380
381 if (sse < 0 || sse > TIME_MAX)
382 {
383 bp = NULL;
384 continue;
385 }
386
387 if (localtime_r(&sse, tm) == NULL)
388 bp = NULL;
389 }
390 continue;
391
392 case 'U': /* The week of year, beginning on sunday. */
393 case 'W': /* The week of year, beginning on monday. */
394 /*
395 * XXX This is bogus, as we can not assume any valid
396 * information present in the tm structure at this
397 * point to calculate a real value, so just check the
398 * range for now.
399 */
400 bp = conv_num(bp, &i, 0, 53);
401 LEGAL_ALT(ALT_O);
402 continue;
403
404 case 'w': /* The day of week, beginning on sunday. */
405 bp = conv_num(bp, &tm->tm_wday, 0, 6);
406 LEGAL_ALT(ALT_O);
407 continue;
408
409 case 'u': /* The day of week, monday = 1. */
410 bp = conv_num(bp, &i, 1, 7);
411 tm->tm_wday = i % 7;
412 LEGAL_ALT(ALT_O);
413 continue;
414
415 case 'g': /* The year corresponding to the ISO week
416 * number but without the century.
417 */
418 bp = conv_num(bp, &i, 0, 99);
419 continue;
420
421 case 'G': /* The year corresponding to the ISO week
422 * number with century.
423 */
424 do
425 bp++;
426 while (isdigit(*bp));
427 continue;
428
429 case 'V': /* The ISO 8601:1988 week number as decimal */
430 bp = conv_num(bp, &i, 0, 53);
431 continue;
432
433 case 'Y': /* The year. */
434 i = TM_YEAR_BASE; /* just for data sanity... */
435 bp = conv_num(bp, &i, 0, 9999);
436 tm->tm_year = i - TM_YEAR_BASE;
437 LEGAL_ALT(ALT_E);
438 continue;
439
440 case 'y': /* The year within 100 years of the epoch. */
441 /* LEGAL_ALT(ALT_E | ALT_O); */
442 bp = conv_num(bp, &i, 0, 99);
443
444 if (split_year)
445 /* preserve century */
446 i += (tm->tm_year / 100) * 100;
447 else {
448 split_year = 1;
449 if (i <= 68)
450 i = i + 2000 - TM_YEAR_BASE;
451 else
452 i = i + 1900 - TM_YEAR_BASE;
453 }
454 tm->tm_year = i;
455 continue;
456
457 case 'Z':
458 tzset();
459 if (strncmp((const char *)bp, gmt, 3) == 0) {
460 tm->tm_isdst = 0;
461 #ifdef TM_GMTOFF
462 tm->TM_GMTOFF = 0;
463 #endif
464 #ifdef TM_ZONE
465 tm->TM_ZONE = gmt;
466 #endif
467 bp += 3;
468 }
469 else
470 {
471 ep = find_string(bp, &i,
472 (const char * const *)tzname,
473 NULL, 2);
474 if (ep != NULL)
475 {
476 tm->tm_isdst = i;
477 #ifdef TM_GMTOFF
478 tm->TM_GMTOFF = -(timezone);
479 #endif
480 #ifdef TM_ZONE
481 tm->TM_ZONE = tzname[i];
482 #endif
483 }
484 bp = ep;
485 }
486 continue;
487
488 case 'z':
489 /*
490 * We recognize all ISO 8601 formats:
491 * Z = Zulu time/UTC
492 * [+-]hhmm
493 * [+-]hh:mm
494 * [+-]hh
495 * We recognize all RFC-822/RFC-2822 formats:
496 * UT|GMT
497 * North American : UTC offsets
498 * E[DS]T = Eastern : -4 | -5
499 * C[DS]T = Central : -5 | -6
500 * M[DS]T = Mountain: -6 | -7
501 * P[DS]T = Pacific : -7 | -8
502 * Military
503 * [A-IL-M] = -1 ... -9 (J not used)
504 * [N-Y] = +1 ... +12
505 */
506 while (isspace(*bp))
507 bp++;
508
509 switch (*bp++)
510 {
511 case 'G':
512 if (*bp++ != 'M')
513 return NULL;
514 /*FALLTHROUGH*/
515 case 'U':
516 if (*bp++ != 'T')
517 return NULL;
518 /*FALLTHROUGH*/
519 case 'Z':
520 tm->tm_isdst = 0;
521 #ifdef TM_GMTOFF
522 tm->TM_GMTOFF = 0;
523 #endif
524 #ifdef TM_ZONE
525 tm->TM_ZONE = utc;
526 #endif
527 continue;
528 case '+':
529 neg = 0;
530 break;
531 case '-':
532 neg = 1;
533 break;
534 default:
535 --bp;
536 ep = find_string(bp, &i, nast, NULL, 4);
537 if (ep != NULL) {
538 #ifdef TM_GMTOFF
539 tm->TM_GMTOFF = -5 - i;
540 #endif
541 #ifdef TM_ZONE
542 tm->TM_ZONE = __UNCONST(nast[i]);
543 #endif
544 bp = ep;
545 continue;
546 }
547 ep = find_string(bp, &i, nadt, NULL, 4);
548 if (ep != NULL)
549 {
550 tm->tm_isdst = 1;
551 #ifdef TM_GMTOFF
552 tm->TM_GMTOFF = -4 - i;
553 #endif
554 #ifdef TM_ZONE
555 tm->TM_ZONE = __UNCONST(nadt[i]);
556 #endif
557 bp = ep;
558 continue;
559 }
560
561 if ((*bp >= 'A' && *bp <= 'I') ||
562 (*bp >= 'L' && *bp <= 'Y'))
563 {
564 #ifdef TM_GMTOFF
565 /* Argh! No 'J'! */
566 if (*bp >= 'A' && *bp <= 'I')
567 tm->TM_GMTOFF =
568 ('A' - 1) - (int)*bp;
569 else if (*bp >= 'L' && *bp <= 'M')
570 tm->TM_GMTOFF = 'A' - (int)*bp;
571 else if (*bp >= 'N' && *bp <= 'Y')
572 tm->TM_GMTOFF = (int)*bp - 'M';
573 #endif
574 #ifdef TM_ZONE
575 tm->TM_ZONE = NULL; /* XXX */
576 #endif
577 bp++;
578 continue;
579 }
580 return NULL;
581 }
582 offs = 0;
583 for (i = 0; i < 4; )
584 {
585 if (isdigit(*bp))
586 {
587 offs = offs * 10 + (*bp++ - '0');
588 i++;
589 continue;
590 }
591 if (i == 2 && *bp == ':')
592 {
593 bp++;
594 continue;
595 }
596 break;
597 }
598 switch (i)
599 {
600 case 2:
601 offs *= 100;
602 break;
603 case 4:
604 i = offs % 100;
605 if (i >= 60)
606 return NULL;
607 /* Convert minutes into decimal */
608 offs = (offs / 100) * 100 + (i * 50) / 30;
609 break;
610 default:
611 return NULL;
612 }
613 if (neg)
614 offs = -offs;
615 tm->tm_isdst = 0; /* XXX */
616 #ifdef TM_GMTOFF
617 tm->TM_GMTOFF = offs;
618 #endif
619 #ifdef TM_ZONE
620 tm->TM_ZONE = NULL; /* XXX */
621 #endif
622 continue;
623
624 /*
625 * Miscellaneous conversions.
626 */
627 case 'n': /* Any kind of white-space. */
628 case 't':
629 while (isspace(*bp))
630 bp++;
631 LEGAL_ALT(0);
632 continue;
633
634 default: /* Unknown/unsupported conversion. */
635 return NULL;
636 }
637 }
638
639 return (char *)bp;
640 }
641