Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / libc / strptime.cc
blobdc6771fe5e23577a2863df5a3c5d9b231bd466aa
1 /* $NetBSD: strptime.c,v 1.28 2008/04/28 20:23:01 martin Exp $ */
3 /*-
4 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code was contributed to The NetBSD Foundation by Klaus Klein.
8 * Heavily optimised by David Laight
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #ifdef __CYGWIN__
33 #include "winsup.h"
34 #endif
36 #include <sys/cdefs.h>
37 #if defined(LIBC_SCCS) && !defined(lint)
38 __RCSID("$NetBSD: strptime.c,v 1.28 2008/04/28 20:23:01 martin Exp $");
39 #endif
41 #ifdef __CYGWIN__
42 #include "../locale/setlocale.h"
43 #else
44 #include "namespace.h"
45 #include <sys/localedef.h>
46 #endif
47 #include <ctype.h>
48 #include <stdlib.h>
49 #include <locale.h>
50 #include <string.h>
51 #include <time.h>
52 #include <tzfile.h>
54 #ifdef __TM_GMTOFF
55 # define TM_GMTOFF __TM_GMTOFF
56 #endif
57 #ifdef __TM_ZONE
58 # define TM_ZONE __TM_ZONE
59 #endif
61 #ifdef __weak_alias
62 __weak_alias(strptime,_strptime)
63 #endif
65 #define _ctloc(x) (_CurrentTimeLocale->x)
67 #define ALT_E 0x01
68 #define ALT_O 0x02
69 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; }
71 static const int _DAYS_BEFORE_MONTH[12] =
72 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
74 #define SET_MDAY 1
75 #define SET_MON 2
76 #define SET_YEAR 4
77 #define SET_WDAY 8
78 #define SET_YDAY 16
79 #define SET_YMD (SET_YEAR | SET_MON | SET_MDAY)
81 static const char gmt[4] = { "GMT" };
83 typedef struct _era_info_t {
84 size_t num; /* Only in first entry: Number of entries,
85 1 otherwise. */
86 int dir; /* Direction */
87 long offset; /* Number of year closest to start_date in the era. */
88 struct tm start; /* Start date of era */
89 struct tm end; /* End date of era */
90 CHAR *era_C; /* Era string */
91 CHAR *era_Y; /* Replacement for %EY */
92 } era_info_t;
94 static void
95 free_era_info (era_info_t *era_info)
97 size_t num = era_info->num;
99 for (size_t i = 0; i < num; ++i)
101 free (era_info[i].era_C);
102 free (era_info[i].era_Y);
104 free (era_info);
107 static era_info_t *
108 get_era_info (const char *era, locale_t locale)
110 char *c;
111 era_info_t *ei = NULL;
112 size_t num = 0, cur = 0, len;
114 while (*era)
116 ++num;
117 era_info_t *tmp = (era_info_t *) realloc (ei, num * sizeof (era_info_t));
118 if (!tmp)
120 ei->num = cur;
121 free_era_info (ei);
122 return NULL;
124 ei = tmp;
125 ei[cur].num = 1;
126 ei[cur].dir = (*era == '+') ? 1 : -1;
127 era += 2;
128 ei[cur].offset = strtol_l (era, &c, 10, locale);
129 era = c + 1;
130 ei[cur].start.tm_year = strtol_l (era, &c, 10, locale);
131 /* Adjust offset for negative gregorian dates. */
132 if (ei[cur].start.tm_year < 0)
133 ++ei[cur].start.tm_year;
134 ei[cur].start.tm_mon = strtol_l (c + 1, &c, 10, locale);
135 ei[cur].start.tm_mday = strtol_l (c + 1, &c, 10, locale);
136 ei[cur].start.tm_hour = ei[cur].start.tm_min = ei[cur].start.tm_sec = 0;
137 era = c + 1;
138 if (era[0] == '-' && era[1] == '*')
140 ei[cur].end = ei[cur].start;
141 ei[cur].start.tm_year = INT_MIN;
142 ei[cur].start.tm_mon = ei[cur].start.tm_mday = ei[cur].start.tm_hour
143 = ei[cur].start.tm_min = ei[cur].start.tm_sec = 0;
144 era += 3;
146 else if (era[0] == '+' && era[1] == '*')
148 ei[cur].end.tm_year = INT_MAX;
149 ei[cur].end.tm_mon = 12;
150 ei[cur].end.tm_mday = 31;
151 ei[cur].end.tm_hour = 23;
152 ei[cur].end.tm_min = ei[cur].end.tm_sec = 59;
153 era += 3;
155 else
157 ei[cur].end.tm_year = strtol_l (era, &c, 10, locale);
158 /* Adjust offset for negative gregorian dates. */
159 if (ei[cur].end.tm_year < 0)
160 ++ei[cur].end.tm_year;
161 ei[cur].end.tm_mon = strtol_l (c + 1, &c, 10, locale);
162 ei[cur].end.tm_mday = strtol_l (c + 1, &c, 10, locale);
163 ei[cur].end.tm_mday = 31;
164 ei[cur].end.tm_hour = 23;
165 ei[cur].end.tm_min = ei[cur].end.tm_sec = 59;
166 era = c + 1;
168 /* era_C */
169 c = strchr (era, ':');
170 len = c - era;
171 ei[cur].era_C = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
172 if (!ei[cur].era_C)
174 ei->num = cur;
175 free_era_info (ei);
176 return NULL;
178 strncpy (ei[cur].era_C, era, len);
179 era += len;
180 ei[cur].era_C[len] = '\0';
181 /* era_Y */
182 ++era;
183 c = strchr (era, ';');
184 if (!c)
185 c = strchr (era, '\0');
186 len = c - era;
187 ei[cur].era_Y = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
188 if (!ei[cur].era_Y)
190 free (ei[cur].era_C);
191 ei->num = cur;
192 free_era_info (ei);
193 return NULL;
195 strncpy (ei[cur].era_Y, era, len);
196 era += len;
197 ei[cur].era_Y[len] = '\0';
198 ++cur;
199 if (*c)
200 era = c + 1;
202 ei->num = num;
203 return ei;
206 typedef struct _alt_digits_t {
207 size_t num;
208 char **digit;
209 char *buffer;
210 } alt_digits_t;
212 static alt_digits_t *
213 get_alt_digits (const char *alt_digits)
215 alt_digits_t *adi;
216 const char *a, *e;
217 char *aa, *ae;
218 size_t len;
220 adi = (alt_digits_t *) calloc (1, sizeof (alt_digits_t));
221 if (!adi)
222 return NULL;
224 /* Compute number of alt_digits. */
225 adi->num = 1;
226 for (a = alt_digits; (e = strchr (a, ';')) != NULL; a = e + 1)
227 ++adi->num;
228 /* Allocate the `digit' array, which is an array of `num' pointers into
229 `buffer'. */
230 adi->digit = (CHAR **) calloc (adi->num, sizeof (CHAR **));
231 if (!adi->digit)
233 free (adi);
234 return NULL;
236 /* Compute memory required for `buffer'. */
237 len = strlen (alt_digits);
238 /* Allocate it. */
239 adi->buffer = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
240 if (!adi->buffer)
242 free (adi->digit);
243 free (adi);
244 return NULL;
246 /* Store digits in it. */
247 strcpy (adi->buffer, alt_digits);
248 /* Store the pointers into `buffer' into the appropriate `digit' slot. */
249 for (len = 0, aa = adi->buffer; (ae = strchr (aa, ';')) != NULL;
250 ++len, aa = ae + 1)
252 *ae = '\0';
253 adi->digit[len] = aa;
255 adi->digit[len] = aa;
256 return adi;
259 static void
260 free_alt_digits (alt_digits_t *adi)
262 free (adi->digit);
263 free (adi->buffer);
264 free (adi);
267 static const unsigned char *
268 find_alt_digits (const unsigned char *bp, alt_digits_t *adi, uint *pval)
270 /* This is rather error-prone, but the entire idea of alt_digits
271 isn't thought out well. If you start to look for matches at the
272 start, there's a high probability that you find short matches but
273 the entire translation is wrong. So we scan the alt_digits array
274 from the highest to the lowest digits instead, hoping that it's
275 more likely to catch digits consisting of multiple characters. */
276 for (int i = (int) adi->num - 1; i >= 0; --i)
278 size_t len = strlen (adi->digit[i]);
279 if (!strncmp ((const char *) bp, adi->digit[i], len))
281 *pval = i;
282 return bp + len;
285 return NULL;
288 static int
289 is_leap_year (int year)
291 return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
294 static int
295 first_day (int year)
297 int ret = 4;
299 while (--year >= 1970)
300 ret = (ret + 365 + is_leap_year (year)) % 7;
301 return ret;
304 /* This simplifies the calls to __conv_num enormously. */
305 #define ALT_DIGITS ((alt_format & ALT_O) ? *alt_digits : NULL)
307 #define conv_num(_b,_d,_l,_u,_a) \
308 ({ \
309 const unsigned char *_ret; \
310 _ret = __conv_num((_b),(_d),(_l),(_u),(_a)); \
311 if (!_ret) \
312 return NULL; \
313 _ret; \
316 static const unsigned char *__conv_num(const unsigned char *, int *, uint, uint,
317 alt_digits_t *);
318 static const unsigned char *find_string(const unsigned char *, int *,
319 const char * const *,
320 const char * const *, int,
321 locale_t);
323 static char *
324 __strptime(const char *buf, const char *fmt, struct tm *tm,
325 era_info_t **era_info, alt_digits_t **alt_digits,
326 locale_t locale)
328 unsigned char c;
329 const unsigned char *bp;
330 int alt_format, i, split_year = 0;
331 era_info_t *era = NULL;
332 int era_offset, got_eoff = 0;
333 int saw_padding;
334 unsigned long width;
335 const char *new_fmt;
336 uint ulim;
337 int ymd = 0;
338 bool got_I = false;
339 bool got_pm = false;
341 bp = (const unsigned char *)buf;
342 const struct lc_time_T *_CurrentTimeLocale = __get_time_locale (locale);
344 while (bp != NULL && (c = *fmt++) != '\0') {
345 /* Clear `alternate' modifier prior to new conversion. */
346 saw_padding = 0;
347 width = 0;
348 alt_format = 0;
349 i = 0;
351 /* Eat up white-space. */
352 if (isspace_l(c, locale)) {
353 while (isspace_l(*bp, locale))
354 bp++;
355 continue;
358 if (c != '%')
359 goto literal;
362 again: switch (c = *fmt++) {
363 case '%': /* "%%" is converted to "%". */
364 literal:
365 if (c != *bp++)
366 return NULL;
367 LEGAL_ALT(0);
368 continue;
371 * "Alternative" modifiers. Just set the appropriate flag
372 * and start over again.
374 case 'E': /* "%E?" alternative conversion modifier. */
375 LEGAL_ALT(0);
376 alt_format |= ALT_E;
377 if (!*era_info && *_CurrentTimeLocale->era)
378 *era_info = get_era_info (_CurrentTimeLocale->era,
379 locale);
380 goto again;
382 case 'O': /* "%O?" alternative conversion modifier. */
383 LEGAL_ALT(0);
384 alt_format |= ALT_O;
385 if (!*alt_digits && *_CurrentTimeLocale->alt_digits)
386 *alt_digits =
387 get_alt_digits (_CurrentTimeLocale->alt_digits);
388 goto again;
389 case '0':
390 case '+':
391 LEGAL_ALT(0);
392 if (saw_padding)
393 return NULL;
394 saw_padding = 1;
395 goto again;
396 case '1': case '2': case '3': case '4': case '5':
397 case '6': case '7': case '8': case '9':
398 /* POSIX-1.2008 maximum field width. Per POSIX,
399 the width is only defined for the 'C', 'F', and 'Y'
400 conversion specifiers. */
401 LEGAL_ALT(0);
403 char *end;
404 width = strtoul_l (fmt - 1, &end, 10, locale);
405 fmt = (const char *) end;
406 goto again;
409 * "Complex" conversion rules, implemented through recursion.
411 case 'c': /* Date and time, using the locale's format. */
412 new_fmt = (alt_format & ALT_E)
413 ? _ctloc (era_d_t_fmt) : _ctloc(c_fmt);
414 LEGAL_ALT(ALT_E);
415 ymd |= SET_WDAY | SET_YMD;
416 goto recurse;
418 case 'D': /* The date as "%m/%d/%y". */
419 new_fmt = "%m/%d/%y";
420 LEGAL_ALT(0);
421 ymd |= SET_YMD;
422 goto recurse;
424 case 'F': /* The date as "%Y-%m-%d". */
426 LEGAL_ALT(0);
427 char *tmp = __strptime ((const char *) bp, "%Y-%m-%d",
428 tm, era_info, alt_digits,
429 locale);
430 /* width max chars converted, default 10, < 6 => 6 */
431 if (tmp && (char *) bp +
432 (!width ? 10 : width < 6 ? 6 : width) < tmp)
433 return NULL;
434 bp = (const unsigned char *) tmp;
435 ymd |= SET_YMD;
436 continue;
439 case 'R': /* The time as "%H:%M". */
440 new_fmt = "%H:%M";
441 LEGAL_ALT(0);
442 goto recurse;
444 case 'r': /* The time in 12-hour clock representation. */
445 new_fmt =_ctloc(ampm_fmt);
446 LEGAL_ALT(0);
447 goto recurse;
449 case 'T': /* The time as "%H:%M:%S". */
450 new_fmt = "%H:%M:%S";
451 LEGAL_ALT(0);
452 goto recurse;
454 case 'X': /* The time, using the locale's format. */
455 new_fmt = (alt_format & ALT_E)
456 ? _ctloc (era_t_fmt) : _ctloc(X_fmt);
457 LEGAL_ALT(ALT_E);
458 goto recurse;
460 case 'x': /* The date, using the locale's format. */
461 new_fmt = (alt_format & ALT_E)
462 ? _ctloc (era_d_fmt) : _ctloc(x_fmt);
463 LEGAL_ALT(ALT_E);
464 ymd |= SET_YMD;
465 recurse:
466 bp = (const unsigned char *)
467 __strptime((const char *)bp, new_fmt, tm,
468 era_info, alt_digits, locale);
469 continue;
472 * "Elementary" conversion rules.
474 case 'A': /* The day of week, using the locale's form. */
475 case 'a':
476 bp = find_string(bp, &tm->tm_wday, _ctloc(weekday),
477 _ctloc(wday), 7, locale);
478 LEGAL_ALT(0);
479 ymd |= SET_WDAY;
480 continue;
482 case 'B': /* The month, using the locale's form. */
483 case 'b':
484 case 'h':
485 bp = find_string(bp, &tm->tm_mon, _ctloc(month),
486 _ctloc(mon), 12, locale);
487 LEGAL_ALT(0);
488 ymd |= SET_WDAY;
489 continue;
491 case 'C': /* The century number. */
492 LEGAL_ALT(ALT_E);
493 ymd |= SET_YEAR;
494 if ((alt_format & ALT_E) && *era_info)
496 /* With E modifier, an era. We potentially
497 don't know the era offset yet, so we have to
498 store the value in a local variable.
499 The final computation of tm_year is only done
500 right before this function returns. */
501 size_t num = (*era_info)->num;
502 for (size_t i = 0; i < num; ++i)
503 if (!strncmp ((const char *) bp,
504 (*era_info)[i].era_C,
505 strlen ((*era_info)[i].era_C)))
507 era = (*era_info) + i;
508 bp += strlen (era->era_C);
509 break;
511 if (!era)
512 return NULL;
513 continue;
515 i = 20;
516 for (ulim = 99; width && width < 2; ++width)
517 ulim /= 10;
518 bp = conv_num(bp, &i, 0, ulim, NULL);
520 i = i * 100 - TM_YEAR_BASE;
521 if (split_year)
522 i += tm->tm_year % 100;
523 split_year = 1;
524 tm->tm_year = i;
525 era = NULL;
526 got_eoff = 0;
527 continue;
529 case 'd': /* The day of month. */
530 case 'e':
531 LEGAL_ALT(ALT_O);
532 ymd |= SET_MDAY;
533 bp = conv_num(bp, &tm->tm_mday, 1, 31, ALT_DIGITS);
534 continue;
536 case 'k': /* The hour (24-hour clock representation). */
537 LEGAL_ALT(0);
538 fallthrough;
539 case 'H':
540 LEGAL_ALT(ALT_O);
541 bp = conv_num(bp, &tm->tm_hour, 0, 23, ALT_DIGITS);
542 got_I = false;
543 continue;
545 case 'l': /* The hour (12-hour clock representation). */
546 LEGAL_ALT(0);
547 fallthrough;
548 case 'I':
549 LEGAL_ALT(ALT_O);
550 bp = conv_num(bp, &tm->tm_hour, 1, 12, ALT_DIGITS);
551 if (tm->tm_hour == 12)
552 tm->tm_hour = 0;
553 got_I = true;
554 continue;
556 case 'j': /* The day of year. */
557 i = 1;
558 bp = conv_num(bp, &i, 1, 366, NULL);
559 tm->tm_yday = i - 1;
560 LEGAL_ALT(0);
561 ymd |= SET_YDAY;
562 continue;
564 case 'M': /* The minute. */
565 LEGAL_ALT(ALT_O);
566 bp = conv_num(bp, &tm->tm_min, 0, 59, ALT_DIGITS);
567 continue;
569 case 'm': /* The month. */
570 LEGAL_ALT(ALT_O);
571 ymd |= SET_MON;
572 i = 1;
573 bp = conv_num(bp, &i, 1, 12, ALT_DIGITS);
574 tm->tm_mon = i - 1;
575 continue;
577 case 'p': /* The locale's equivalent of AM/PM. */
578 bp = find_string(bp, &i, _ctloc(am_pm), NULL, 2,
579 locale);
580 got_pm = (i == 1);
581 LEGAL_ALT(0);
582 continue;
584 case 'q': /* The quarter year. GNU extension. */
585 LEGAL_ALT(0);
586 i = 1;
587 bp = conv_num(bp, &i, 1, 4, ALT_DIGITS);
588 tm->tm_mon = (i - 1)*3;
589 ymd |= SET_MON;
590 continue;
592 case 'S': /* The seconds. */
593 LEGAL_ALT(ALT_O);
594 bp = conv_num(bp, &tm->tm_sec, 0, 61, ALT_DIGITS);
595 continue;
597 case 's' : /* The seconds since Unix epoch - GNU extension */
599 long long sec;
600 time_t t;
601 char *end;
602 save_errno save;
604 LEGAL_ALT(0);
605 sec = strtoll_l ((char *)bp, &end, 10, locale);
606 t = sec;
607 if (end == (char *)bp
608 || errno != 0
609 || t != sec
610 || localtime_r (&t, tm) != tm)
611 return NULL;
612 bp = (const unsigned char *)end;
613 ymd |= SET_YDAY | SET_WDAY | SET_YMD;
614 break;
617 case 'U': /* The week of year, beginning on sunday. */
618 case 'W': /* The week of year, beginning on monday. */
620 * XXX This is bogus, as we can not assume any valid
621 * information present in the tm structure at this
622 * point to calculate a real value, so just check the
623 * range for now.
625 LEGAL_ALT(ALT_O);
626 bp = conv_num(bp, &i, 0, 53, ALT_DIGITS);
627 continue;
629 case 'u': /* The day of week, beginning on monday. */
630 LEGAL_ALT(ALT_O);
631 ymd |= SET_WDAY;
632 bp = conv_num(bp, &i, 1, 7, ALT_DIGITS);
633 tm->tm_wday = i % 7;
634 continue;
635 case 'w': /* The day of week, beginning on sunday. */
636 LEGAL_ALT(ALT_O);
637 ymd |= SET_WDAY;
638 bp = conv_num(bp, &tm->tm_wday, 0, 6, ALT_DIGITS);
639 continue;
641 case 'Y': /* The year. */
642 LEGAL_ALT(ALT_E);
643 ymd |= SET_YEAR;
644 if ((alt_format & ALT_E) && *era_info)
646 bool gotit = false;
647 size_t num = (*era_info)->num;
648 (*era_info)->num = 1;
649 for (size_t i = 0; i < num; ++i)
651 era_info_t *tmp_ei = (*era_info) + i;
652 char *tmp = __strptime ((const char *) bp,
653 tmp_ei->era_Y,
654 tm, &tmp_ei,
655 alt_digits, locale);
656 if (tmp)
658 bp = (const unsigned char *) tmp;
659 gotit = true;
660 break;
663 (*era_info)->num = num;
664 if (gotit)
665 continue;
666 return NULL;
668 i = TM_YEAR_BASE; /* just for data sanity... */
669 for (ulim = 9999; width && width < 4; ++width)
670 ulim /= 10;
671 bp = conv_num(bp, &i, 0, ulim, NULL);
672 tm->tm_year = i - TM_YEAR_BASE;
673 era = NULL;
674 got_eoff = 0;
675 continue;
677 case 'y': /* The year within 100 years of the century or era. */
678 /* LEGAL_ALT(ALT_E | ALT_O); */
679 ymd |= SET_YEAR;
680 if ((alt_format & ALT_E) && *era_info)
682 /* With E modifier, the offset to the start date
683 of the era specified with %EC. We potentially
684 don't know the era yet, so we have to store the
685 value in a local variable, just like era itself.
686 The final computation of tm_year is only done
687 right before this function returns. */
688 bp = conv_num(bp, &era_offset, 0, UINT_MAX, NULL);
689 got_eoff = 1;
690 continue;
692 bp = conv_num(bp, &i, 0, 99, ALT_DIGITS);
694 if (split_year) /* preserve century */
695 i += (tm->tm_year / 100) * 100;
696 else {
697 split_year = 1;
698 if (i <= 68)
699 i = i + 2000 - TM_YEAR_BASE;
700 else
701 i = i + 1900 - TM_YEAR_BASE;
703 tm->tm_year = i;
704 era = NULL;
705 got_eoff = 0;
706 continue;
708 case 'Z':
709 tzset();
710 if (strncmp((const char *)bp, gmt, 3) == 0) {
711 tm->tm_isdst = 0;
712 #ifdef TM_GMTOFF
713 if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
714 tm->TM_GMTOFF = 0;
715 #endif
716 #ifdef TM_ZONE
717 if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
718 tm->TM_ZONE = gmt;
719 #endif
720 bp += 3;
721 } else {
722 const unsigned char *ep;
724 ep = find_string(bp, &i,
725 (const char * const *)tzname,
726 NULL, 2, locale);
727 if (ep != NULL) {
728 tm->tm_isdst = i;
729 #ifdef TM_GMTOFF
730 if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
731 tm->TM_GMTOFF = -(timezone);
732 #endif
733 #ifdef TM_ZONE
734 if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
735 tm->TM_ZONE = tzname[i];
736 #endif
738 bp = ep;
740 continue;
743 * Miscellaneous conversions.
745 case 'n': /* Any kind of white-space. */
746 case 't':
747 while (isspace_l(*bp, locale))
748 bp++;
749 LEGAL_ALT(0);
750 continue;
753 default: /* Unknown/unsupported conversion. */
754 return NULL;
759 if (got_I && got_pm)
760 tm->tm_hour += 12;
762 if (bp && (era || got_eoff))
764 /* Default to current era. */
765 if (!era)
766 era = *era_info;
767 /* Default to first year of era if offset is missing */
768 if (!got_eoff)
769 era_offset = era->offset;
770 tm->tm_year = (era->start.tm_year != INT_MIN
771 ? era->start.tm_year : era->end.tm_year)
772 + (era_offset - era->offset) * era->dir;
773 /* Check if year falls into the era. If not, it's an
774 invalid combination of era and offset. */
775 if (era->start.tm_year > tm->tm_year
776 || era->end.tm_year < tm->tm_year)
777 return NULL;
778 tm->tm_year -= TM_YEAR_BASE;
781 if ((ymd & SET_YMD) == SET_YMD)
783 /* all of tm_year, tm_mon and tm_mday, but... */
784 if (!(ymd & SET_YDAY))
786 /* ...not tm_yday, so fill it in */
787 tm->tm_yday = _DAYS_BEFORE_MONTH[tm->tm_mon] + tm->tm_mday;
788 if (!is_leap_year (tm->tm_year + TM_YEAR_BASE)
789 || tm->tm_mon < 2)
790 tm->tm_yday--;
791 ymd |= SET_YDAY;
794 else if ((ymd & (SET_YEAR | SET_YDAY)) == (SET_YEAR | SET_YDAY))
796 /* both of tm_year and tm_yday, but... */
797 if (!(ymd & SET_MON))
799 /* ...not tm_mon, so fill it in, and/or... */
800 if (tm->tm_yday < _DAYS_BEFORE_MONTH[1])
801 tm->tm_mon = 0;
802 else
804 int leap = is_leap_year (tm->tm_year + TM_YEAR_BASE);
805 for (i = 2; i < 12; ++i)
806 if (tm->tm_yday < _DAYS_BEFORE_MONTH[i] + leap)
807 break;
808 tm->tm_mon = i - 1;
811 if (!(ymd & SET_MDAY))
813 /* ...not tm_mday, so fill it in */
814 tm->tm_mday = tm->tm_yday - _DAYS_BEFORE_MONTH[tm->tm_mon];
815 if (!is_leap_year (tm->tm_year + TM_YEAR_BASE)
816 || tm->tm_mon < 2)
817 tm->tm_mday++;
821 if ((ymd & (SET_YEAR | SET_YDAY | SET_WDAY)) == (SET_YEAR | SET_YDAY))
823 /* fill in tm_wday */
824 int fday = first_day (tm->tm_year + TM_YEAR_BASE);
825 tm->tm_wday = (fday + tm->tm_yday) % 7;
827 return (char *) bp;
830 char *
831 strptime_l (const char *__restrict buf, const char *__restrict fmt,
832 struct tm *__restrict tm, locale_t locale)
834 era_info_t *era_info = NULL;
835 alt_digits_t *alt_digits = NULL;
836 char *ret = __strptime (buf, fmt, tm, &era_info, &alt_digits, locale);
837 if (era_info)
838 free_era_info (era_info);
839 if (alt_digits)
840 free_alt_digits (alt_digits);
841 return ret;
844 char *
845 strptime (const char *__restrict buf, const char *__restrict fmt,
846 struct tm *__restrict tm)
848 era_info_t *era_info = NULL;
849 alt_digits_t *alt_digits = NULL;
850 char *ret = __strptime (buf, fmt, tm, &era_info, &alt_digits,
851 __get_current_locale ());
852 if (era_info)
853 free_era_info (era_info);
854 if (alt_digits)
855 free_alt_digits (alt_digits);
856 return ret;
859 static const unsigned char *
860 __conv_num(const unsigned char *buf, int *dest, uint llim, uint ulim,
861 alt_digits_t *alt_digits)
863 uint result = 0;
864 unsigned char ch;
866 if (alt_digits)
867 buf = find_alt_digits (buf, alt_digits, &result);
868 else
870 /* The limit also determines the number of valid digits. */
871 uint rulim = ulim;
873 ch = *buf;
874 if (ch < '0' || ch > '9')
875 return NULL;
877 do {
878 result *= 10;
879 result += ch - '0';
880 rulim /= 10;
881 ch = *++buf;
882 } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9');
885 if (result < llim || result > ulim)
886 return NULL;
888 *dest = result;
889 return buf;
892 static const unsigned char *
893 find_string(const unsigned char *bp, int *tgt, const char * const *n1,
894 const char * const *n2, int c, locale_t locale)
896 int i;
897 unsigned int len;
899 /* check full name - then abbreviated ones */
900 for (; n1 != NULL; n1 = n2, n2 = NULL) {
901 for (i = 0; i < c; i++, n1++) {
902 len = strlen(*n1);
903 if (strncasecmp_l(*n1, (const char *)bp, len,
904 locale) == 0) {
905 *tgt = i;
906 return bp + len;
911 /* Nothing matched */
912 return NULL;