source: Main/trunk/Server/strptime.c@ 214

Last change on this file since 214 was 212, checked in by Nishi, on Oct 3, 2024 at 2:44:55 AM

compiles on vc6

  • Property svn:keywords set to Id
File size: 24.7 KB
Line 
1/* $NetBSD: strptime.c,v 1.62 2017/08/24 01:01:09 ginsbach Exp $ */
2/* http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/lib/libc/time/strptime.c?only_with_tag=HEAD
3 * NetBSD implementation strptime().
4 * Format description: https://netbsd.gw.com/cgi-bin/man-cgi?strptime+3+NetBSD-current
5*/
6/*-
7 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
8 * All rights reserved.
9 *
10 * This code was contributed to The NetBSD Foundation by Klaus Klein.
11 * Heavily optimised by David Laight
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35//#include <sys/cdefs.h>
36//__RCSID("$NetBSD: strptime.c,v 1.62 2017/08/24 01:01:09 ginsbach Exp $");
37
38#if defined(__MINGW32__) || defined(_MSC_VER)
39
40#include <ctype.h>
41#include <string.h>
42#include <time.h>
43#include <stdint.h>
44
45static const unsigned char *conv_num(const unsigned char *, int *, unsigned int, unsigned int);
46static const unsigned char *find_string(const unsigned char *, int *, const char * const *, const char * const *, int);
47
48/*
49 * We do not implement alternate representations. However, we always
50 * check whether a given modifier is allowed for a certain conversion.
51 */
52#define ALT_E 0x01
53#define ALT_O 0x02
54#define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; }
55
56#define TM_YEAR_BASE 1900
57
58#define TM_SUNDAY 0
59#define TM_MONDAY 1
60#define TM_TUESDAY 2
61#define TM_WEDNESDAY 3
62#define TM_THURSDAY 4
63#define TM_FRIDAY 5
64#define TM_SATURDAY 6
65
66#define S_YEAR (1 << 0)
67#define S_MON (1 << 1)
68#define S_YDAY (1 << 2)
69#define S_MDAY (1 << 3)
70#define S_WDAY (1 << 4)
71#define S_HOUR (1 << 5)
72
73#define HAVE_MDAY(s) (s & S_MDAY)
74#define HAVE_MON(s) (s & S_MON)
75#define HAVE_WDAY(s) (s & S_WDAY)
76#define HAVE_YDAY(s) (s & S_YDAY)
77#define HAVE_YEAR(s) (s & S_YEAR)
78#define HAVE_HOUR(s) (s & S_HOUR)
79
80#define SECSPERMIN 60
81#define MINSPERHOUR 60
82#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
83#define HOURSPERDAY 24
84
85#define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
86#define HERE_D_FMT "%y/%m/%d"
87#define HERE_T_FMT_AMPM "%I:%M:%S %p"
88#define HERE_T_FMT "%H:%M:%S"
89
90#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
91
92/*
93** Since everything in isleap is modulo 400 (or a factor of 400), we know that
94** isleap(y) == isleap(y % 400)
95** and so
96** isleap(a + b) == isleap((a + b) % 400)
97** or
98** isleap(a + b) == isleap(a % 400 + b % 400)
99** This is true even if % means modulo rather than Fortran remainder
100** (which is allowed by C89 but not by C99 or later).
101** We use this to avoid addition overflow problems.
102*/
103
104#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
105
106#ifdef _MSC_VER
107#define tzname _tzname
108#define strncasecmp _strnicmp
109#endif
110
111#ifdef TM_ZONE
112static char* utc = "UTC";
113#endif
114/* RFC-822/RFC-2822 */
115static const char* const nast[] = {
116 "EST", "CST", "MST", "PST", "\0\0\0"
117};
118static const char* const nadt[] = {
119 "EDT", "CDT", "MDT", "PDT", "\0\0\0"
120};
121static const char* weekday_name[] =
122{
123 "Sunday", "Monday", "Tuesday", "Wednesday",
124 "Thursday", "Friday", "Saturday"
125};
126static const char* ab_weekday_name[] =
127{
128 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
129};
130static const char* month_name[] =
131{
132 "January", "February", "March", "April", "May", "June",
133 "July", "August", "September", "October", "November", "December"
134};
135static const char* ab_month_name[] =
136{
137 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
138 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
139};
140static const char* am_pm[] = {"AM", "PM"};
141
142
143/*
144 * Table to determine the ordinal date for the start of a month.
145 * Ref: http://en.wikipedia.org/wiki/ISO_week_date
146 */
147static const int start_of_month[2][13] = {
148 /* non-leap year */
149 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
150 /* leap year */
151 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
152};
153
154/*
155 * Calculate the week day of the first day of a year. Valid for
156 * the Gregorian calendar, which began Sept 14, 1752 in the UK
157 * and its colonies. Ref:
158 * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
159 */
160
161static int
162first_wday_of(int yr)
163{
164 return ((2 * (3 - (yr / 100) % 4)) + (yr % 100) + ((yr % 100) / 4) +
165 (isleap(yr) ? 6 : 0) + 1) % 7;
166}
167
168#define delim(p) ((p) == '\0' || isspace((unsigned char)(p)))
169
170static int
171fromzone(const unsigned char **bp, struct tm *tm, int mandatory)
172{
173// timezone_t tz;
174 char buf[512], *p;
175 const unsigned char *rp;
176
177 for (p = buf, rp = *bp; !delim(*rp) && p < &buf[sizeof(buf) - 1]; rp++)
178 *p++ = *rp;
179 *p = '\0';
180
181 if (mandatory)
182 *bp = rp;
183 if (!isalnum((unsigned char)*buf))
184 return 0;
185// tz = tzalloc(buf);
186// if (tz == NULL)
187// return 0;
188
189 *bp = rp;
190 tm->tm_isdst = 0; /* XXX */
191#ifdef TM_GMTOFF
192 tm->TM_GMTOFF = tzgetgmtoff(tz, tm->tm_isdst);
193#endif
194#ifdef TM_ZONE
195 // Can't use tzgetname() here because we are going to free()
196 tm->TM_ZONE = NULL; /* XXX */
197#endif
198// tzfree(tz);
199 return 1;
200}
201
202char* strptime(const char *buf, const char *fmt, struct tm *tm)
203{
204 unsigned char c;
205 const unsigned char *bp, *ep, *zname;
206 int alt_format, i, split_year = 0, neg = 0, state = 0,
207 day_offset = -1, week_offset = 0, offs, mandatory;
208 const char *new_fmt;
209
210 bp = (const unsigned char *)buf;
211
212 while (bp != NULL && (c = *fmt++) != '\0') {
213 /* Clear `alternate' modifier prior to new conversion. */
214 alt_format = 0;
215 i = 0;
216
217 /* Eat up white-space. */
218 if (isspace(c)) {
219 while (isspace(*bp))
220 bp++;
221 continue;
222 }
223
224 if (c != '%')
225 goto literal;
226
227
228again: switch (c = *fmt++) {
229 case '%': /* "%%" is converted to "%". */
230literal:
231 if (c != *bp++)
232 return NULL;
233 LEGAL_ALT(0);
234 continue;
235
236 /*
237 * "Alternative" modifiers. Just set the appropriate flag
238 * and start over again.
239 */
240 case 'E': /* "%E?" alternative conversion modifier. */
241 LEGAL_ALT(0);
242 alt_format |= ALT_E;
243 goto again;
244
245 case 'O': /* "%O?" alternative conversion modifier. */
246 LEGAL_ALT(0);
247 alt_format |= ALT_O;
248 goto again;
249
250 /*
251 * "Complex" conversion rules, implemented through recursion.
252 */
253 case 'c': /* Date and time, using the locale's format. */
254// new_fmt = _TIME_LOCALE(loc)->d_t_fmt;
255 new_fmt = HERE_D_T_FMT;
256 state |= S_WDAY | S_MON | S_MDAY | S_YEAR;
257 goto recurse;
258
259 case 'F': /* The date as "%Y-%m-%d". */
260 new_fmt = "%Y-%m-%d";
261 LEGAL_ALT(0);
262 state |= S_MON | S_MDAY | S_YEAR;
263 goto recurse;
264
265 case 'R': /* The time as "%H:%M". */
266 new_fmt = "%H:%M";
267 LEGAL_ALT(0);
268 goto recurse;
269
270 case 'r': /* The time in 12-hour clock representation. */
271// new_fmt = _TIME_LOCALE(loc)->t_fmt_ampm;
272 new_fmt = HERE_T_FMT_AMPM;
273 LEGAL_ALT(0);
274 goto recurse;
275
276 case 'X': /* The time, using the locale's format. */
277 /* fall through */
278
279 case 'T': /* The time as "%H:%M:%S". */
280 new_fmt = HERE_T_FMT;
281 LEGAL_ALT(0);
282
283recurse:
284 bp = (const unsigned char *)strptime((const char *)bp,
285 new_fmt, tm);
286 LEGAL_ALT(ALT_E);
287 continue;
288
289 case 'x': /* The date, using the locale's format. */
290 /* fall throug */
291
292 case 'D': /* The date as "%y/%m/%d". */
293 {
294 int year;
295 new_fmt = HERE_D_FMT;
296 LEGAL_ALT(0);
297 state |= S_MON | S_MDAY | S_YEAR;
298 year = split_year ? tm->tm_year : 0;
299
300 bp = (const unsigned char *)strptime((const char *)bp,
301 new_fmt, tm);
302 LEGAL_ALT(ALT_E);
303 tm->tm_year += year;
304 if (split_year && tm->tm_year % (2000 - TM_YEAR_BASE) <= 68)
305 tm->tm_year -= 2000 - TM_YEAR_BASE;
306 split_year = 1;
307 continue;
308 }
309 /*
310 * "Elementary" conversion rules.
311 */
312 case 'A': /* The day of week, using the locale's form. */
313 case 'a':
314 bp = find_string(bp, &tm->tm_wday, weekday_name, ab_weekday_name, 7);
315 LEGAL_ALT(0);
316 state |= S_WDAY;
317 continue;
318
319 case 'B': /* The month, using the locale's form. */
320 case 'b':
321 case 'h':
322 bp = find_string(bp, &tm->tm_mon, month_name, ab_month_name, 12);
323 LEGAL_ALT(0);
324 state |= S_MON;
325 continue;
326
327 case 'C': /* The century number. */
328 i = 20;
329 bp = conv_num(bp, &i, 0, 99);
330
331 i = i * 100 - TM_YEAR_BASE;
332 if (split_year)
333 i += tm->tm_year % 100;
334 split_year = 1;
335 tm->tm_year = i;
336 LEGAL_ALT(ALT_E);
337 state |= S_YEAR;
338 continue;
339
340 case 'd': /* The day of month. */
341 case 'e':
342 bp = conv_num(bp, &tm->tm_mday, 1, 31);
343 LEGAL_ALT(ALT_O);
344 state |= S_MDAY;
345 continue;
346
347 case 'k': /* The hour (24-hour clock representation). */
348 LEGAL_ALT(0);
349 /* FALLTHROUGH */
350 case 'H':
351 bp = conv_num(bp, &tm->tm_hour, 0, 23);
352 LEGAL_ALT(ALT_O);
353 state |= S_HOUR;
354 continue;
355
356 case 'l': /* The hour (12-hour clock representation). */
357 LEGAL_ALT(0);
358 /* FALLTHROUGH */
359 case 'I':
360 bp = conv_num(bp, &tm->tm_hour, 1, 12);
361 if (tm->tm_hour == 12)
362 tm->tm_hour = 0;
363 LEGAL_ALT(ALT_O);
364 state |= S_HOUR;
365 continue;
366
367 case 'j': /* The day of year. */
368 i = 1;
369 bp = conv_num(bp, &i, 1, 366);
370 tm->tm_yday = i - 1;
371 LEGAL_ALT(0);
372 state |= S_YDAY;
373 continue;
374
375 case 'M': /* The minute. */
376 bp = conv_num(bp, &tm->tm_min, 0, 59);
377 LEGAL_ALT(ALT_O);
378 continue;
379
380 case 'm': /* The month. */
381 i = 1;
382 bp = conv_num(bp, &i, 1, 12);
383 tm->tm_mon = i - 1;
384 LEGAL_ALT(ALT_O);
385 state |= S_MON;
386 continue;
387
388 case 'p': /* The locale's equivalent of AM/PM. */
389 bp = find_string(bp, &i, am_pm, NULL, 2);
390 if (HAVE_HOUR(state) && tm->tm_hour > 11)
391 return NULL;
392 tm->tm_hour += i * 12;
393 LEGAL_ALT(0);
394 continue;
395
396 case 'S': /* The seconds. */
397 bp = conv_num(bp, &tm->tm_sec, 0, 61);
398 LEGAL_ALT(ALT_O);
399 continue;
400
401#ifndef TIME_MAX
402#ifdef _MSC_VER
403#define TIME_MAX INT32_MAX
404#else
405#define TIME_MAX INT64_MAX
406#endif
407#endif
408 case 's': /* seconds since the epoch */
409 {
410 time_t sse = 0;
411#ifdef _MSC_VER
412 uint32_t rulim = TIME_MAX;
413#else
414 uint64_t rulim = TIME_MAX;
415#endif
416
417 if (*bp < '0' || *bp > '9') {
418 bp = NULL;
419 continue;
420 }
421
422 do {
423 sse *= 10;
424 sse += *bp++ - '0';
425 rulim /= 10;
426 } while ((sse * 10 <= TIME_MAX) &&
427 rulim && *bp >= '0' && *bp <= '9');
428#ifdef _MSC_VER
429 if (sse < 0 || (uint32_t)sse > TIME_MAX) {
430#else
431 if (sse < 0 || (uint64_t)sse > TIME_MAX) {
432#endif
433 bp = NULL;
434 continue;
435 }
436#ifdef _WIN32
437#ifdef _MSC_VER
438 if (1)
439#else
440 if (localtime_s(tm, &sse) == 0)
441#endif
442#else
443 if (localtime_r(&sse, tm))
444#endif
445 state |= S_YDAY | S_WDAY | S_MON | S_MDAY | S_YEAR;
446 else
447 bp = NULL;
448 }
449 continue;
450
451 case 'U': /* The week of year, beginning on sunday. */
452 case 'W': /* The week of year, beginning on monday. */
453 /*
454 * This is bogus, as we can not assume any valid
455 * information present in the tm structure at this
456 * point to calculate a real value, so save the
457 * week for now in case it can be used later.
458 */
459 bp = conv_num(bp, &i, 0, 53);
460 LEGAL_ALT(ALT_O);
461 if (c == 'U')
462 day_offset = TM_SUNDAY;
463 else
464 day_offset = TM_MONDAY;
465 week_offset = i;
466 continue;
467
468 case 'w': /* The day of week, beginning on sunday. */
469 bp = conv_num(bp, &tm->tm_wday, 0, 6);
470 LEGAL_ALT(ALT_O);
471 state |= S_WDAY;
472 continue;
473
474 case 'u': /* The day of week, monday = 1. */
475 bp = conv_num(bp, &i, 1, 7);
476 tm->tm_wday = i % 7;
477 LEGAL_ALT(ALT_O);
478 state |= S_WDAY;
479 continue;
480
481 case 'g': /* The year corresponding to the ISO week
482 * number but without the century.
483 */
484 bp = conv_num(bp, &i, 0, 99);
485 continue;
486
487 case 'G': /* The year corresponding to the ISO week
488 * number with century.
489 */
490 do
491 bp++;
492 while (isdigit(*bp));
493 continue;
494
495 case 'V': /* The ISO 8601:1988 week number as decimal */
496 bp = conv_num(bp, &i, 0, 53);
497 continue;
498
499 case 'Y': /* The year. */
500 i = TM_YEAR_BASE; /* just for data sanity... */
501 bp = conv_num(bp, &i, 0, 9999);
502 tm->tm_year = i - TM_YEAR_BASE;
503 LEGAL_ALT(ALT_E);
504 state |= S_YEAR;
505 continue;
506
507 case 'y': /* The year within 100 years of the epoch. */
508 /* LEGAL_ALT(ALT_E | ALT_O); */
509 bp = conv_num(bp, &i, 0, 99);
510
511 if (split_year)
512 /* preserve century */
513 i += (tm->tm_year / 100) * 100;
514 else {
515 split_year = 1;
516 if (i <= 68)
517 i = i + 2000 - TM_YEAR_BASE;
518 }
519 tm->tm_year = i;
520 state |= S_YEAR;
521 continue;
522
523 case 'Z': // time zone name
524 case 'z': //
525#ifdef _WIN32
526 _tzset();
527#else
528 tzset();
529#endif
530 mandatory = c == 'z';
531 /*
532 * We recognize all ISO 8601 formats:
533 * Z = Zulu time/UTC
534 * [+-]hhmm
535 * [+-]hh:mm
536 * [+-]hh
537 * We recognize all RFC-822/RFC-2822 formats:
538 * UT|GMT
539 * North American : UTC offsets
540 * E[DS]T = Eastern : -4 | -5
541 * C[DS]T = Central : -5 | -6
542 * M[DS]T = Mountain: -6 | -7
543 * P[DS]T = Pacific : -7 | -8
544 * Nautical/Military
545 * [A-IL-M] = -1 ... -9 (J not used)
546 * [N-Y] = +1 ... +12
547 * Note: J maybe used to denote non-nautical
548 * local time
549 */
550 if (mandatory)
551 while (isspace(*bp))
552 bp++;
553
554 zname = bp;
555 switch (*bp++) {
556 case 'G':
557 if (*bp++ != 'M')
558 goto namedzone;
559 /*FALLTHROUGH*/
560 case 'U':
561 if (*bp++ != 'T')
562 goto namedzone;
563 else if (!delim(*bp) && *bp++ != 'C')
564 goto namedzone;
565 /*FALLTHROUGH*/
566 case 'Z':
567 if (!delim(*bp))
568 goto namedzone;
569 tm->tm_isdst = 0;
570#ifdef TM_GMTOFF
571 tm->TM_GMTOFF = 0;
572#endif
573#ifdef TM_ZONE
574 tm->TM_ZONE = utc;
575#endif
576 continue;
577 case '+':
578 neg = 0;
579 break;
580 case '-':
581 neg = 1;
582 break;
583 default:
584namedzone:
585 bp = zname;
586
587 /* Nautical / Military style */
588 if (delim(bp[1]) &&
589 ((*bp >= 'A' && *bp <= 'I') ||
590 (*bp >= 'L' && *bp <= 'Y'))) {
591#ifdef TM_GMTOFF
592 /* Argh! No 'J'! */
593 if (*bp >= 'A' && *bp <= 'I')
594 tm->TM_GMTOFF =
595 (int)*bp - ('A' - 1);
596 else if (*bp >= 'L' && *bp <= 'M')
597 tm->TM_GMTOFF = (int)*bp - 'A';
598 else if (*bp >= 'N' && *bp <= 'Y')
599 tm->TM_GMTOFF = 'M' - (int)*bp;
600 tm->TM_GMTOFF *= SECSPERHOUR;
601#endif
602#ifdef TM_ZONE
603 tm->TM_ZONE = NULL; /* XXX */
604#endif
605 bp++;
606 continue;
607 }
608 /* 'J' is local time */
609 if (delim(bp[1]) && *bp == 'J') {
610#ifdef TM_GMTOFF
611 tm->TM_GMTOFF = -timezone;
612#endif
613#ifdef TM_ZONE
614 tm->TM_ZONE = NULL; /* XXX */
615#endif
616 bp++;
617 continue;
618 }
619
620 /*
621 * From our 3 letter hard-coded table
622 * XXX: Can be removed, handled by tzload()
623 */
624 if (delim(bp[0]) || delim(bp[1]) ||
625 delim(bp[2]) || !delim(bp[3]))
626 goto loadzone;
627 ep = find_string(bp, &i, nast, NULL, 4);
628 if (ep != NULL) {
629#ifdef TM_GMTOFF
630 tm->TM_GMTOFF = (-5 - i) * SECSPERHOUR;
631#endif
632#ifdef TM_ZONE
633 tm->TM_ZONE = __UNCONST(nast[i]);
634#endif
635 bp = ep;
636 continue;
637 }
638 ep = find_string(bp, &i, nadt, NULL, 4);
639 if (ep != NULL) {
640 tm->tm_isdst = 1;
641#ifdef TM_GMTOFF
642 tm->TM_GMTOFF = (-4 - i) * SECSPERHOUR;
643#endif
644#ifdef TM_ZONE
645 tm->TM_ZONE = __UNCONST(nadt[i]);
646#endif
647 bp = ep;
648 continue;
649 }
650 /*
651 * Our current timezone
652 */
653 ep = find_string(bp, &i,
654 (const char * const *)NULL,
655 NULL, 2);
656 if (ep != NULL) {
657 tm->tm_isdst = i;
658#ifdef TM_GMTOFF
659 tm->TM_GMTOFF = -timezone;
660#endif
661#ifdef TM_ZONE
662 tm->TM_ZONE = tzname[i];
663#endif
664 bp = ep;
665 continue;
666 }
667loadzone:
668 /*
669 * The hard way, load the zone!
670 */
671 if (fromzone(&bp, tm, mandatory))
672 continue;
673 goto out;
674 }
675 offs = 0;
676 for (i = 0; i < 4; ) {
677 if (isdigit(*bp)) {
678 offs = offs * 10 + (*bp++ - '0');
679 i++;
680 continue;
681 }
682 if (i == 2 && *bp == ':') {
683 bp++;
684 continue;
685 }
686 break;
687 }
688 if (isdigit(*bp))
689 goto out;
690 switch (i) {
691 case 2:
692 offs *= SECSPERHOUR;
693 break;
694 case 4:
695 i = offs % 100;
696 offs /= 100;
697 if (i >= SECSPERMIN)
698 goto out;
699 /* Convert minutes into decimal */
700 offs = offs * SECSPERHOUR + i * SECSPERMIN;
701 break;
702 default:
703out:
704 if (mandatory)
705 return NULL;
706 bp = zname;
707 continue;
708 }
709 /* ISO 8601 & RFC 3339 limit to 23:59 max */
710 if (offs >= (HOURSPERDAY * SECSPERHOUR))
711 goto out;
712 if (neg)
713 offs = -offs;
714 tm->tm_isdst = 0; /* XXX */
715#ifdef TM_GMTOFF
716 tm->TM_GMTOFF = offs;
717#endif
718#ifdef TM_ZONE
719 tm->TM_ZONE = NULL; /* XXX */
720#endif
721 continue;
722
723 /*
724 * Miscellaneous conversions.
725 */
726 case 'n': /* Any kind of white-space. */
727 case 't':
728 while (isspace(*bp))
729 bp++;
730 LEGAL_ALT(0);
731 continue;
732
733
734 default: /* Unknown/unsupported conversion. */
735 return NULL;
736 }
737 }
738
739 if (!HAVE_YDAY(state) && HAVE_YEAR(state)) {
740 if (HAVE_MON(state) && HAVE_MDAY(state)) {
741 /* calculate day of year (ordinal date) */
742 tm->tm_yday = start_of_month[isleap_sum(tm->tm_year,
743 TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1);
744 state |= S_YDAY;
745 } else if (day_offset != -1) {
746 /*
747 * Set the date to the first Sunday (or Monday)
748 * of the specified week of the year.
749 */
750 if (!HAVE_WDAY(state)) {
751 tm->tm_wday = day_offset;
752 state |= S_WDAY;
753 }
754 tm->tm_yday = (7 -
755 first_wday_of(tm->tm_year + TM_YEAR_BASE) +
756 day_offset) % 7 + (week_offset - 1) * 7 +
757 tm->tm_wday - day_offset;
758 state |= S_YDAY;
759 }
760 }
761
762 if (HAVE_YDAY(state) && HAVE_YEAR(state)) {
763 int isleap;
764
765 if (!HAVE_MON(state)) {
766 /* calculate month of day of year */
767 i = 0;
768 isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE);
769 while (tm->tm_yday >= start_of_month[isleap][i])
770 i++;
771 if (i > 12) {
772 i = 1;
773 tm->tm_yday -= start_of_month[isleap][12];
774 tm->tm_year++;
775 }
776 tm->tm_mon = i - 1;
777 state |= S_MON;
778 }
779
780 if (!HAVE_MDAY(state)) {
781 /* calculate day of month */
782 isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE);
783 tm->tm_mday = tm->tm_yday -
784 start_of_month[isleap][tm->tm_mon] + 1;
785 state |= S_MDAY;
786 }
787
788 if (!HAVE_WDAY(state)) {
789 /* calculate day of week */
790 i = 0;
791 week_offset = first_wday_of(tm->tm_year);
792 while (i++ <= tm->tm_yday) {
793 if (week_offset++ >= 6)
794 week_offset = 0;
795 }
796 tm->tm_wday = week_offset;
797 state |= S_WDAY;
798 }
799 }
800
801 return (char*)bp;
802}
803
804
805static const unsigned char *
806conv_num(const unsigned char *buf, int *dest, unsigned int llim, unsigned int ulim)
807{
808 unsigned int result = 0;
809 unsigned char ch;
810
811 /* The limit also determines the number of valid digits. */
812 unsigned int rulim = ulim;
813
814 ch = *buf;
815 if (ch < '0' || ch > '9')
816 return NULL;
817
818 do {
819 result *= 10;
820 result += ch - '0';
821 rulim /= 10;
822 ch = *++buf;
823 } while ((result <= ulim) && rulim && ch >= '0' && ch <= '9');
824
825 if (result < llim || result > ulim)
826 return NULL;
827
828 *dest = result;
829 return buf;
830}
831
832static const unsigned char *
833find_string(const unsigned char *bp, int *tgt, const char * const *n1,
834 const char * const *n2, int c)
835{
836 int i;
837 size_t len;
838
839 /* check full name - then abbreviated ones */
840 for (; n1 != NULL; n1 = n2, n2 = NULL) {
841 for (i = 0; i < c; i++, n1++) {
842 len = strlen(*n1);
843 if (strncasecmp(*n1, (const char *)bp, len) == 0) {
844 *tgt = i;
845 return bp + len;
846 }
847 }
848 }
849
850 /* Nothing matched */
851 return NULL;
852}
853
854#endif
Note: See TracBrowser for help on using the repository browser.