1 /*  Missing time implementations for Windows
2     Code taken largely from rtmpserver (www.rtmpd.com)
3 
4     Copyright (C) 2011-2018 Ruven Pillay
5                   2010 Gavriloaie Eugen-Andrei
6                   1997, 1998 Kungliga Tekniska Hogskolan
7 		             (Royal Institute of Technology, Stockholm, Sweden)
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 3 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software Foundation,
21     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23 
24 #ifdef WIN32
25 
26 #include <ctype.h>
27 #include <cmath>
28 #include <ctime>
29 #include <cstdlib>
30 #include <cstring>
31 #include <Windows.h>
32 
33 
34 int
strncasecmp(const char * s1,const char * s2,size_t n)35 strncasecmp(const char *s1, const char *s2, size_t n)
36 {
37   while(n > 0
38 	&& toupper((unsigned char)*s1) == toupper((unsigned char)*s2))
39     {
40       if(*s1 == '\0')
41 	return 0;
42       s1++;
43       s2++;
44       n--;
45     }
46   if(n == 0)
47     return 0;
48   return toupper((unsigned char)*s1) - toupper((unsigned char)*s2);
49 }
50 
51 int
gettimeofday(struct timeval * tv,struct timezone * tz)52 gettimeofday(struct timeval *tv, struct timezone* tz) {
53   FILETIME ft;
54   GetSystemTimeAsFileTime(&ft);
55   __int64 value = ((__int64) ft.dwHighDateTime << 32) | ft.dwLowDateTime;
56   tv->tv_usec = (long) ((value / 10LL) % 1000000LL);
57   tv->tv_sec = (long) ((value - 116444736000000000LL) / 10000000LL);
58   return (0);
59 }
60 
61 static int
is_leap(unsigned y)62 is_leap(unsigned y)
63 {
64   y += 1900;
65   return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
66 }
67 
68 time_t
timegm(struct tm * tm)69 timegm (struct tm *tm)
70 {
71   static const unsigned ndays[2][12] ={
72     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
73     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
74   time_t res = 0;
75   int i;
76 
77   for (i = 70; i < tm->tm_year; ++i)
78     res += is_leap(i) ? 366 : 365;
79 
80   for (i = 0; i < tm->tm_mon; ++i)
81     res += ndays[is_leap(tm->tm_year)][i];
82   res += tm->tm_mday - 1;
83   res *= 24;
84   res += tm->tm_hour;
85   res *= 60;
86   res += tm->tm_min;
87   res *= 60;
88   res += tm->tm_sec;
89   return res;
90 }
91 
92 static const char *abb_weekdays[] = {
93   "Sun",
94   "Mon",
95   "Tue",
96   "Wed",
97   "Thu",
98   "Fri",
99   "Sat",
100   NULL
101 };
102 
103 static const char *full_weekdays[] = {
104   "Sunday",
105   "Monday",
106   "Tuesday",
107   "Wednesday",
108   "Thursday",
109   "Friday",
110   "Saturday",
111   NULL
112 };
113 
114 static const char *abb_month[] = {
115   "Jan",
116   "Feb",
117   "Mar",
118   "Apr",
119   "May",
120   "Jun",
121   "Jul",
122   "Aug",
123   "Sep",
124   "Oct",
125   "Nov",
126   "Dec",
127   NULL
128 };
129 
130 static const char *full_month[] = {
131   "January",
132   "February",
133   "Mars",
134   "April",
135   "May",
136   "June",
137   "July",
138   "August",
139   "September",
140   "October",
141   "November",
142   "December",
143   NULL,
144 };
145 
146 static const char *ampm[] = {
147   "am",
148   "pm",
149   NULL
150 };
151 
152 /*
153  * Try to match `*buf' to one of the strings in `strs'.  Return the
154  * index of the matching string (or -1 if none).  Also advance buf.
155  */
156 
157 static int
match_string(const char ** buf,const char ** strs)158 match_string (const char **buf, const char **strs)
159 {
160   int i = 0;
161 
162   for (i = 0; strs[i] != NULL; ++i) {
163     int len = strlen (strs[i]);
164 
165     if (strncasecmp (*buf, strs[i], len) == 0) {
166       *buf += len;
167       return i;
168     }
169   }
170   return -1;
171 }
172 
173 /*
174  * tm_year is relative this year */
175 
176 const int tm_year_base = 1900;
177 
178 /*
179  * Return TRUE iff `year' was a leap year.
180  */
181 
182 static int
is_leap_year(int year)183 is_leap_year (int year)
184 {
185   return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
186 }
187 
188 /*
189  * Return the weekday [0,6] (0 = Sunday) of the first day of `year'
190  */
191 
192 static int
first_day(int year)193 first_day (int year)
194 {
195   int ret = 4;
196 
197   for (; year > 1970; --year)
198     ret = (ret + 365 + is_leap_year (year) ? 1 : 0) % 7;
199   return ret;
200 }
201 
202 /*
203  * Set `timeptr' given `wnum' (week number [0, 53])
204  */
205 
206 static void
set_week_number_sun(struct tm * timeptr,int wnum)207 set_week_number_sun (struct tm *timeptr, int wnum)
208 {
209   int fday = first_day (timeptr->tm_year + tm_year_base);
210 
211   timeptr->tm_yday = wnum * 7 + timeptr->tm_wday - fday;
212   if (timeptr->tm_yday < 0) {
213     timeptr->tm_wday = fday;
214     timeptr->tm_yday = 0;
215   }
216 }
217 
218 /*
219  * Set `timeptr' given `wnum' (week number [0, 53])
220  */
221 
222 static void
set_week_number_mon(struct tm * timeptr,int wnum)223 set_week_number_mon (struct tm *timeptr, int wnum)
224 {
225   int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
226 
227   timeptr->tm_yday = wnum * 7 + (timeptr->tm_wday + 6) % 7 - fday;
228   if (timeptr->tm_yday < 0) {
229     timeptr->tm_wday = (fday + 1) % 7;
230     timeptr->tm_yday = 0;
231   }
232 }
233 
234 /*
235  * Set `timeptr' given `wnum' (week number [0, 53])
236  */
237 
238 static void
set_week_number_mon4(struct tm * timeptr,int wnum)239 set_week_number_mon4 (struct tm *timeptr, int wnum)
240 {
241   int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
242   int offset = 0;
243 
244   if (fday < 4)
245     offset += 7;
246 
247   timeptr->tm_yday = offset + (wnum - 1) * 7 + timeptr->tm_wday - fday;
248   if (timeptr->tm_yday < 0) {
249     timeptr->tm_wday = fday;
250     timeptr->tm_yday = 0;
251   }
252 }
253 
254 /*
255  *
256  */
257 
258 char *
strptime(const char * buf,const char * fmt,struct tm * timeptr)259 strptime (const char *buf, const char *fmt, struct tm *timeptr)
260 {
261   char c;
262 
263   for (; (c = *fmt) != '\0'; ++fmt) {
264     char *s;
265     int ret;
266 
267     if (isspace (c)) {
268       while (isspace (*buf))
269 	++buf;
270     } else if (c == '%' && fmt[1] != '\0') {
271       c = *++fmt;
272       if (c == 'E' || c == 'O')
273 	c = *++fmt;
274       switch (c) {
275       case 'A' :
276 	ret = match_string (&buf, full_weekdays);
277 	if (ret < 0)
278 	  return NULL;
279 	timeptr->tm_wday = ret;
280 	break;
281       case 'a' :
282 	ret = match_string (&buf, abb_weekdays);
283 	if (ret < 0)
284 	  return NULL;
285 	timeptr->tm_wday = ret;
286 	break;
287       case 'B' :
288 	ret = match_string (&buf, full_month);
289 	if (ret < 0)
290 	  return NULL;
291 	timeptr->tm_mon = ret;
292 	break;
293       case 'b' :
294       case 'h' :
295 	ret = match_string (&buf, abb_month);
296 	if (ret < 0)
297 	  return NULL;
298 	timeptr->tm_mon = ret;
299 	break;
300       case 'C' :
301 	ret = strtol (buf, &s, 10);
302 	if (s == buf)
303 	  return NULL;
304 	timeptr->tm_year = (ret * 100) - tm_year_base;
305 	buf = s;
306 	break;
307       case 'c' :
308 	abort ();
309       case 'D' :		/* %m/%d/%y */
310 	s = strptime (buf, "%m/%d/%y", timeptr);
311 	if (s == NULL)
312 	  return NULL;
313 	buf = s;
314 	break;
315       case 'd' :
316       case 'e' :
317 	ret = strtol (buf, &s, 10);
318 	if (s == buf)
319 	  return NULL;
320 	timeptr->tm_mday = ret;
321 	buf = s;
322 	break;
323       case 'H' :
324       case 'k' :
325 	ret = strtol (buf, &s, 10);
326 	if (s == buf)
327 	  return NULL;
328 	timeptr->tm_hour = ret;
329 	buf = s;
330 	break;
331       case 'I' :
332       case 'l' :
333 	ret = strtol (buf, &s, 10);
334 	if (s == buf)
335 	  return NULL;
336 	if (ret == 12)
337 	  timeptr->tm_hour = 0;
338 	else
339 	  timeptr->tm_hour = ret;
340 	buf = s;
341 	break;
342       case 'j' :
343 	ret = strtol (buf, &s, 10);
344 	if (s == buf)
345 	  return NULL;
346 	timeptr->tm_yday = ret - 1;
347 	buf = s;
348 	break;
349       case 'm' :
350 	ret = strtol (buf, &s, 10);
351 	if (s == buf)
352 	  return NULL;
353 	timeptr->tm_mon = ret - 1;
354 	buf = s;
355 	break;
356       case 'M' :
357 	ret = strtol (buf, &s, 10);
358 	if (s == buf)
359 	  return NULL;
360 	timeptr->tm_min = ret;
361 	buf = s;
362 	break;
363       case 'n' :
364 	if (*buf == '\n')
365 	  ++buf;
366 	else
367 	  return NULL;
368 	break;
369       case 'p' :
370 	ret = match_string (&buf, ampm);
371 	if (ret < 0)
372 	  return NULL;
373 	if (timeptr->tm_hour == 0) {
374 	  if (ret == 1)
375 	    timeptr->tm_hour = 12;
376 	} else
377 	  timeptr->tm_hour += 12;
378 	break;
379       case 'r' :		/* %I:%M:%S %p */
380 	s = strptime (buf, "%I:%M:%S %p", timeptr);
381 	if (s == NULL)
382 	  return NULL;
383 	buf = s;
384 	break;
385       case 'R' :		/* %H:%M */
386 	s = strptime (buf, "%H:%M", timeptr);
387 	if (s == NULL)
388 	  return NULL;
389 	buf = s;
390 	break;
391       case 'S' :
392 	ret = strtol (buf, &s, 10);
393 	if (s == buf)
394 	  return NULL;
395 	timeptr->tm_sec = ret;
396 	buf = s;
397 	break;
398       case 't' :
399 	if (*buf == '\t')
400 	  ++buf;
401 	else
402 	  return NULL;
403 	break;
404       case 'T' :		/* %H:%M:%S */
405       case 'X' :
406 	s = strptime (buf, "%H:%M:%S", timeptr);
407 	if (s == NULL)
408 	  return NULL;
409 	buf = s;
410 	break;
411       case 'u' :
412 	ret = strtol (buf, &s, 10);
413 	if (s == buf)
414 	  return NULL;
415 	timeptr->tm_wday = ret - 1;
416 	buf = s;
417 	break;
418       case 'w' :
419 	ret = strtol (buf, &s, 10);
420 	if (s == buf)
421 	  return NULL;
422 	timeptr->tm_wday = ret;
423 	buf = s;
424 	break;
425       case 'U' :
426 	ret = strtol (buf, &s, 10);
427 	if (s == buf)
428 	  return NULL;
429 	set_week_number_sun (timeptr, ret);
430 	buf = s;
431 	break;
432       case 'V' :
433 	ret = strtol (buf, &s, 10);
434 	if (s == buf)
435 	  return NULL;
436 	set_week_number_mon4 (timeptr, ret);
437 	buf = s;
438 	break;
439       case 'W' :
440 	ret = strtol (buf, &s, 10);
441 	if (s == buf)
442 	  return NULL;
443 	set_week_number_mon (timeptr, ret);
444 	buf = s;
445 	break;
446       case 'x' :
447 	s = strptime (buf, "%Y:%m:%d", timeptr);
448 	if (s == NULL)
449 	  return NULL;
450 	buf = s;
451 	break;
452       case 'y' :
453 	ret = strtol (buf, &s, 10);
454 	if (s == buf)
455 	  return NULL;
456 	if (ret < 70)
457 	  timeptr->tm_year = 100 + ret;
458 	else
459 	  timeptr->tm_year = ret;
460 	buf = s;
461 	break;
462       case 'Y' :
463 	ret = strtol (buf, &s, 10);
464 	if (s == buf)
465 	  return NULL;
466 	timeptr->tm_year = ret - tm_year_base;
467 	buf = s;
468 	break;
469       case 'Z' :
470 	abort ();
471       case '\0' :
472 	--fmt;
473 	/* FALLTHROUGH */
474       case '%' :
475 	if (*buf == '%')
476 	  ++buf;
477 	else
478 	  return NULL;
479 	break;
480       default :
481 	if (*buf == '%' || *++buf == c)
482 	  ++buf;
483 	else
484 	  return NULL;
485 	break;
486       }
487     } else {
488       if (*buf == c)
489 	++buf;
490       else
491 	return NULL;
492     }
493   }
494   return (char *)buf;
495 }
496 
497 
498 #endif /* WIN32 */
499