]> git.saurik.com Git - apple/libc.git/blame - stdtime/FreeBSD/strptime.c
Libc-1158.50.2.tar.gz
[apple/libc.git] / stdtime / FreeBSD / strptime.c
CommitLineData
974e3884
A
1/*-
2 * Copyright (c) 2014 Gary Mills
3 * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
5b2abdfb
A
4 * Copyright (c) 1994 Powerdog Industries. All rights reserved.
5 *
974e3884
A
6 * Copyright (c) 2011 The FreeBSD Foundation
7 * All rights reserved.
8 * Portions of this software were developed by David Chisnall
9 * under sponsorship from the FreeBSD Foundation.
10 *
5b2abdfb
A
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer
18 * in the documentation and/or other materials provided with the
19 * distribution.
5b2abdfb
A
20 *
21 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
974e3884
A
32 *
33 * The views and conclusions contained in the software and documentation
34 * are those of the authors and should not be interpreted as representing
35 * official policies, either expressed or implied, of Powerdog Industries.
5b2abdfb
A
36 */
37
9385eb3d 38#include <sys/cdefs.h>
5b2abdfb
A
39#ifndef lint
40#ifndef NOID
9385eb3d 41static char copyright[] __unused =
5b2abdfb 42"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
9385eb3d 43static char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
5b2abdfb
A
44#endif /* !defined NOID */
45#endif /* not lint */
974e3884 46__FBSDID("$FreeBSD$");
5b2abdfb 47
ad3c9f2a
A
48#include "xlocale_private.h"
49
9385eb3d 50#include "namespace.h"
5b2abdfb
A
51#include <time.h>
52#include <ctype.h>
3d9156a7 53#include <errno.h>
ad3c9f2a 54#include <stdio.h>
5b2abdfb
A
55#include <stdlib.h>
56#include <string.h>
5b2abdfb 57#include <pthread.h>
9385eb3d
A
58#include "un-namespace.h"
59#include "libc_private.h"
5b2abdfb 60#include "timelocal.h"
974e3884 61#include "tzfile.h"
5b2abdfb 62
ad3c9f2a 63time_t _mktime(struct tm *, const char *);
5b2abdfb 64
974e3884 65#define asizeof(a) (sizeof(a) / sizeof((a)[0]))
5b2abdfb 66
ad3c9f2a 67enum {CONVERT_NONE, CONVERT_GMT, CONVERT_ZONE};
974e3884
A
68enum week_kind { WEEK_U = 'U', WEEK_V = 'V', WEEK_W = 'W'};
69
70#define _strptime(b,f,t,c,l) _strptime0(b,f,t,c,l,FLAG_NONE,0,WEEK_U)
ad3c9f2a 71
974e3884
A
72#define FLAG_NONE 0x01
73#define FLAG_YEAR 0x02
74#define FLAG_MONTH 0x04
75#define FLAG_YDAY 0x08
76#define FLAG_MDAY 0x10
77#define FLAG_WDAY 0x20
78#define FLAG_WEEK 0x40
79#define FLAG_CENTURY 0x100
80#define FLAG_YEAR_IN_CENTURY 0x200
6465356a 81
974e3884
A
82/*
83 * Calculate the week day of the first day of a year. Valid for
84 * the Gregorian calendar, which began Sept 14, 1752 in the UK
85 * and its colonies. Ref:
86 * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
87 */
6465356a
A
88
89static int
974e3884 90first_wday_of(int year)
6465356a 91{
974e3884
A
92 return (((2 * (3 - (year / 100) % 4)) + (year % 100) +
93 ((year % 100) / 4) + (isleap(year) ? 6 : 0) + 1) % 7);
6465356a 94}
ad3c9f2a 95
5b2abdfb 96static char *
974e3884 97_strptime0(const char *buf, const char *fmt, struct tm *tm, int *convp, locale_t locale, int flags, int week_number, enum week_kind week_kind)
5b2abdfb
A
98{
99 char c;
100 const char *ptr;
974e3884
A
101 int wday_offset;
102 int i, len;
5b2abdfb 103 int Ealternative, Oalternative;
974e3884
A
104 const struct lc_time_T *tptr = __get_current_time_locale(locale);
105 static int start_of_month[2][13] = {
106 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
107 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
108 };
5b2abdfb
A
109
110 ptr = fmt;
111 while (*ptr != 0) {
5b2abdfb
A
112 c = *ptr++;
113
114 if (c != '%') {
974e3884
A
115 if (isspace_l((unsigned char)c, locale))
116 while (*buf != 0 &&
117 isspace_l((unsigned char)*buf, locale))
5b2abdfb
A
118 buf++;
119 else if (c != *buf++)
974e3884 120 return (NULL);
5b2abdfb
A
121 continue;
122 }
123
124 Ealternative = 0;
125 Oalternative = 0;
126label:
127 c = *ptr++;
128 switch (c) {
5b2abdfb
A
129 case '%':
130 if (*buf++ != '%')
974e3884 131 return (NULL);
5b2abdfb
A
132 break;
133
134 case '+':
974e3884
A
135 buf = _strptime(buf, tptr->date_fmt, tm, convp, locale);
136 if (buf == NULL)
137 return (NULL);
138 flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
5b2abdfb
A
139 break;
140
141 case 'C':
974e3884
A
142 if (!isdigit_l((unsigned char)*buf, locale))
143 return (NULL);
5b2abdfb
A
144
145 /* XXX This will break for 3-digit centuries. */
146 len = 2;
974e3884
A
147 for (i = 0; len && *buf != 0 &&
148 isdigit_l((unsigned char)*buf, locale); buf++) {
5b2abdfb
A
149 i *= 10;
150 i += *buf - '0';
151 len--;
152 }
153 if (i < 19)
974e3884
A
154 return (NULL);
155
156 if (flags & FLAG_YEAR_IN_CENTURY) {
157 tm->tm_year = i * 100 + (tm->tm_year % 100) - TM_YEAR_BASE;
158 flags &= ~FLAG_YEAR_IN_CENTURY;
159 } else {
160 tm->tm_year = i * 100 - TM_YEAR_BASE;
161 flags |= FLAG_YEAR;
162 flags |= FLAG_CENTURY;
163 }
5b2abdfb 164
5b2abdfb
A
165 break;
166
167 case 'c':
974e3884
A
168 buf = _strptime(buf, tptr->c_fmt, tm, convp, locale);
169 if (buf == NULL)
170 return (NULL);
171 flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
172 flags &= ~(FLAG_CENTURY | FLAG_YEAR_IN_CENTURY);
5b2abdfb
A
173 break;
174
175 case 'D':
974e3884
A
176 buf = _strptime(buf, "%m/%d/%y", tm, convp, locale);
177 if (buf == NULL)
178 return (NULL);
179 flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
180 flags &= ~(FLAG_CENTURY | FLAG_YEAR_IN_CENTURY);
5b2abdfb
A
181 break;
182
183 case 'E':
184 if (Ealternative || Oalternative)
185 break;
186 Ealternative++;
974e3884 187 if (*ptr == '%') return (NULL);
5b2abdfb
A
188 goto label;
189
190 case 'O':
191 if (Ealternative || Oalternative)
192 break;
193 Oalternative++;
974e3884 194 if (*ptr == '%') return (NULL);
5b2abdfb
A
195 goto label;
196
197 case 'F':
974e3884
A
198 buf = _strptime(buf, "%Y-%m-%d", tm, convp, locale);
199 if (buf == NULL)
200 return (NULL);
201 flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
202 flags &= ~(FLAG_CENTURY | FLAG_YEAR_IN_CENTURY);
5b2abdfb
A
203 break;
204
205 case 'R':
974e3884
A
206 buf = _strptime(buf, "%H:%M", tm, convp, locale);
207 if (buf == NULL)
208 return (NULL);
5b2abdfb
A
209 break;
210
211 case 'r':
974e3884
A
212 buf = _strptime(buf, tptr->ampm_fmt, tm, convp, locale);
213 if (buf == NULL)
214 return (NULL);
ad3c9f2a
A
215 break;
216
5b2abdfb 217 case 'T':
974e3884
A
218 buf = _strptime(buf, "%H:%M:%S", tm, convp, locale);
219 if (buf == NULL)
220 return (NULL);
5b2abdfb
A
221 break;
222
223 case 'X':
974e3884
A
224 buf = _strptime(buf, tptr->X_fmt, tm, convp, locale);
225 if (buf == NULL)
226 return (NULL);
5b2abdfb
A
227 break;
228
229 case 'x':
974e3884
A
230 buf = _strptime(buf, tptr->x_fmt, tm, convp, locale);
231 if (buf == NULL)
232 return (NULL);
233 flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
234 flags &= ~(FLAG_CENTURY | FLAG_YEAR_IN_CENTURY);
5b2abdfb
A
235 break;
236
237 case 'j':
974e3884
A
238 if (!isdigit_l((unsigned char)*buf, locale))
239 return (NULL);
5b2abdfb
A
240
241 len = 3;
974e3884
A
242 for (i = 0; len && *buf != 0 &&
243 isdigit_l((unsigned char)*buf, locale); buf++){
5b2abdfb
A
244 i *= 10;
245 i += *buf - '0';
246 len--;
247 }
248 if (i < 1 || i > 366)
974e3884
A
249 return (NULL);
250
251 tm->tm_yday = i - 1;
252 flags |= FLAG_YDAY;
5b2abdfb 253
5b2abdfb
A
254 break;
255
256 case 'M':
257 case 'S':
974e3884
A
258 if (*buf == 0 ||
259 isspace_l((unsigned char)*buf, locale))
5b2abdfb
A
260 break;
261
974e3884
A
262 if (!isdigit_l((unsigned char)*buf, locale))
263 return (NULL);
5b2abdfb
A
264
265 len = 2;
974e3884
A
266 for (i = 0; len && *buf != 0 &&
267 isdigit_l((unsigned char)*buf, locale); buf++){
5b2abdfb
A
268 i *= 10;
269 i += *buf - '0';
270 len--;
271 }
272
273 if (c == 'M') {
274 if (i > 59)
974e3884 275 return (NULL);
5b2abdfb
A
276 tm->tm_min = i;
277 } else {
278 if (i > 60)
974e3884 279 return (NULL);
5b2abdfb
A
280 tm->tm_sec = i;
281 }
282
5b2abdfb
A
283 break;
284
285 case 'H':
286 case 'I':
287 case 'k':
288 case 'l':
289 /*
290 * Of these, %l is the only specifier explicitly
291 * documented as not being zero-padded. However,
292 * there is no harm in allowing zero-padding.
293 *
294 * XXX The %l specifier may gobble one too many
295 * digits if used incorrectly.
296 */
974e3884
A
297 if (!isdigit_l((unsigned char)*buf, locale))
298 return (NULL);
5b2abdfb
A
299
300 len = 2;
974e3884
A
301 for (i = 0; len && *buf != 0 &&
302 isdigit_l((unsigned char)*buf, locale); buf++) {
5b2abdfb
A
303 i *= 10;
304 i += *buf - '0';
305 len--;
306 }
307 if (c == 'H' || c == 'k') {
308 if (i > 23)
974e3884 309 return (NULL);
5b2abdfb 310 } else if (i > 12)
974e3884 311 return (NULL);
5b2abdfb
A
312
313 tm->tm_hour = i;
314
5b2abdfb
A
315 break;
316
317 case 'p':
318 /*
319 * XXX This is bogus if parsed before hour-related
320 * specifiers.
321 */
9385eb3d 322 len = strlen(tptr->am);
974e3884 323 if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
5b2abdfb 324 if (tm->tm_hour > 12)
974e3884 325 return (NULL);
5b2abdfb
A
326 if (tm->tm_hour == 12)
327 tm->tm_hour = 0;
328 buf += len;
329 break;
330 }
331
9385eb3d 332 len = strlen(tptr->pm);
974e3884 333 if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
5b2abdfb 334 if (tm->tm_hour > 12)
974e3884 335 return (NULL);
5b2abdfb
A
336 if (tm->tm_hour != 12)
337 tm->tm_hour += 12;
338 buf += len;
339 break;
340 }
341
974e3884 342 return (NULL);
5b2abdfb
A
343
344 case 'A':
345 case 'a':
9385eb3d
A
346 for (i = 0; i < asizeof(tptr->weekday); i++) {
347 len = strlen(tptr->weekday[i]);
ad3c9f2a 348 if (strncasecmp_l(buf, tptr->weekday[i],
974e3884 349 len, locale) == 0)
9385eb3d
A
350 break;
351 len = strlen(tptr->wday[i]);
ad3c9f2a 352 if (strncasecmp_l(buf, tptr->wday[i],
974e3884 353 len, locale) == 0)
9385eb3d 354 break;
5b2abdfb 355 }
9385eb3d 356 if (i == asizeof(tptr->weekday))
974e3884 357 return (NULL);
5b2abdfb 358
5b2abdfb 359 buf += len;
974e3884
A
360 tm->tm_wday = i;
361 flags |= FLAG_WDAY;
5b2abdfb
A
362 break;
363
974e3884
A
364 case 'U': /* Sunday week */
365 case 'V': /* ISO 8601 week */
366 case 'W': /* Monday week */
367 if (!isdigit_l((unsigned char)*buf, locale))
368 return (NULL);
5b2abdfb
A
369
370 len = 2;
974e3884
A
371 for (i = 0; len && *buf != 0 &&
372 isdigit_l((unsigned char)*buf, locale); buf++) {
5b2abdfb
A
373 i *= 10;
374 i += *buf - '0';
375 len--;
376 }
377 if (i > 53)
974e3884
A
378 return (NULL);
379 if (c == WEEK_V && i < 1)
380 return (NULL);
6465356a 381
974e3884
A
382 week_number = i;
383 week_kind = c;
384 flags |= FLAG_WEEK;
5b2abdfb 385
5b2abdfb
A
386 break;
387
974e3884
A
388 case 'u': /* [1,7] */
389 case 'w': /* [0,6] */
390 if (!isdigit_l((unsigned char)*buf, locale))
391 return (NULL);
5b2abdfb
A
392
393 i = *buf - '0';
ad3c9f2a 394 if (i > 6 + (c == 'u'))
974e3884 395 return (NULL);
ad3c9f2a
A
396 if (i == 7)
397 i = 0;
6465356a 398
974e3884
A
399 tm->tm_wday = i;
400 flags |= FLAG_WDAY;
ad3c9f2a 401 buf++;
974e3884 402
5b2abdfb
A
403 break;
404
5b2abdfb
A
405 case 'e':
406 /*
974e3884
A
407 * With %e format, our strftime(3) adds a blank space
408 * before single digits.
409 */
410 if (*buf != 0 &&
411 isspace_l((unsigned char)*buf, locale))
412 buf++;
413 /* FALLTHROUGH */
414 case 'd':
415 /*
416 * The %e specifier was once explicitly documented as
417 * not being zero-padded but was later changed to
418 * equivalent to %d. There is no harm in allowing
5b2abdfb
A
419 * such padding.
420 *
421 * XXX The %e specifier may gobble one too many
422 * digits if used incorrectly.
423 */
ad3c9f2a
A
424 /* Leading space is ok if date is single digit */
425 len = 2;
974e3884
A
426 if (isspace_l((unsigned char)buf[0], locale) &&
427 isdigit_l((unsigned char)buf[1], locale) &&
428 !isdigit_l((unsigned char)buf[2], locale)) {
ad3c9f2a
A
429 len = 1;
430 buf++;
431 }
974e3884
A
432 if (!isdigit_l((unsigned char)*buf, locale))
433 return (NULL);
5b2abdfb 434
974e3884
A
435 for (i = 0; len && *buf != 0 &&
436 isdigit_l((unsigned char)*buf, locale); buf++) {
5b2abdfb
A
437 i *= 10;
438 i += *buf - '0';
439 len--;
440 }
441 if (i > 31)
974e3884 442 return (NULL);
5b2abdfb
A
443
444 tm->tm_mday = i;
974e3884 445 flags |= FLAG_MDAY;
5b2abdfb 446
5b2abdfb
A
447 break;
448
449 case 'B':
450 case 'b':
451 case 'h':
9385eb3d 452 for (i = 0; i < asizeof(tptr->month); i++) {
5b2abdfb
A
453 if (Oalternative) {
454 if (c == 'B') {
9385eb3d 455 len = strlen(tptr->alt_month[i]);
ad3c9f2a 456 if (strncasecmp_l(buf,
9385eb3d 457 tptr->alt_month[i],
974e3884 458 len, locale) == 0)
5b2abdfb
A
459 break;
460 }
461 } else {
9385eb3d 462 len = strlen(tptr->month[i]);
ad3c9f2a 463 if (strncasecmp_l(buf, tptr->month[i],
974e3884 464 len, locale) == 0)
9385eb3d 465 break;
974e3884
A
466 }
467 }
468 /*
469 * Try the abbreviated month name if the full name
470 * wasn't found and Oalternative was not requested.
471 */
472 if (i == asizeof(tptr->month) && !Oalternative) {
473 for (i = 0; i < asizeof(tptr->month); i++) {
9385eb3d 474 len = strlen(tptr->mon[i]);
ad3c9f2a 475 if (strncasecmp_l(buf, tptr->mon[i],
974e3884 476 len, locale) == 0)
9385eb3d 477 break;
5b2abdfb
A
478 }
479 }
9385eb3d 480 if (i == asizeof(tptr->month))
974e3884 481 return (NULL);
5b2abdfb
A
482
483 tm->tm_mon = i;
484 buf += len;
974e3884
A
485 flags |= FLAG_MONTH;
486
5b2abdfb
A
487 break;
488
489 case 'm':
974e3884
A
490 if (!isdigit_l((unsigned char)*buf, locale))
491 return (NULL);
5b2abdfb
A
492
493 len = 2;
974e3884
A
494 for (i = 0; len && *buf != 0 &&
495 isdigit_l((unsigned char)*buf, locale); buf++) {
5b2abdfb
A
496 i *= 10;
497 i += *buf - '0';
498 len--;
499 }
500 if (i < 1 || i > 12)
974e3884 501 return (NULL);
5b2abdfb
A
502
503 tm->tm_mon = i - 1;
974e3884 504 flags |= FLAG_MONTH;
5b2abdfb 505
5b2abdfb
A
506 break;
507
508 case 's':
509 {
510 char *cp;
3d9156a7
A
511 int sverrno;
512 long n;
5b2abdfb
A
513 time_t t;
514
3d9156a7
A
515 sverrno = errno;
516 errno = 0;
974e3884 517 n = strtol_l(buf, &cp, 10, locale);
3d9156a7
A
518 if (errno == ERANGE || (long)(t = n) != n) {
519 errno = sverrno;
974e3884 520 return (NULL);
3d9156a7
A
521 }
522 errno = sverrno;
5b2abdfb 523 buf = cp;
974e3884
A
524 if (gmtime_r(&t, tm) == NULL)
525 return (NULL);
ad3c9f2a 526 *convp = CONVERT_GMT;
974e3884
A
527 flags |= FLAG_YDAY | FLAG_WDAY | FLAG_MONTH |
528 FLAG_MDAY | FLAG_YEAR;
529 flags &= ~(FLAG_CENTURY | FLAG_YEAR_IN_CENTURY);
5b2abdfb
A
530 }
531 break;
532
533 case 'Y':
534 case 'y':
974e3884
A
535 if (*buf == 0 ||
536 isspace_l((unsigned char)*buf, locale))
5b2abdfb
A
537 break;
538
974e3884
A
539 if (!isdigit_l((unsigned char)*buf, locale))
540 return (NULL);
5b2abdfb 541
ad3c9f2a
A
542#if __DARWIN_UNIX03
543 if (c == 'Y') {
544 int savei = 0;
545 const char *savebuf = buf;
546 int64_t i64 = 0;
547 int overflow = 0;
548
974e3884 549 for (len = 0; *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
ad3c9f2a
A
550 i64 *= 10;
551 i64 += *buf - '0';
552 if (++len <= 4) {
553 savei = i64;
554 savebuf = buf + 1;
555 }
556 if (i64 > INT_MAX) {
557 overflow++;
558 break;
559 }
560 }
561 /*
562 * Conformance requires %Y to be more then 4
563 * digits. However, there are several cases
564 * where %Y is immediately followed by other
565 * digits values. So we do the conformance
566 * case first (as many digits as possible),
567 * and if we fail, we backup and try just 4
568 * digits for %Y.
569 */
570 if (len > 4 && !overflow) {
571 struct tm savetm = *tm;
572 int saveconv = *convp;
573 const char *saveptr = ptr;
574 char *ret;
575
576 if (i64 < 1900)
577 return 0;
578
579 tm->tm_year = i64 - 1900;
580
974e3884
A
581 if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
582 while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale) && *ptr != '%')
ad3c9f2a 583 ptr++;
974e3884 584 ret = _strptime0(buf, ptr, tm, convp, locale, flags, week_number, week_kind);
ad3c9f2a
A
585 if (ret) return ret;
586 /* Failed, so try 4-digit year */
587 *tm = savetm;
588 *convp = saveconv;
589 ptr = saveptr;
590 }
591 buf = savebuf;
592 i = savei;
593 } else {
594 len = 2;
595#else /* !__DARWIN_UNIX03 */
974e3884 596 len = (c == 'Y') ? 4 : 2;
ad3c9f2a 597#endif /* __DARWIN_UNIX03 */
974e3884
A
598
599 for (i = 0; len && *buf != 0 &&
600 isdigit_l((unsigned char)*buf, locale); buf++) {
601 i *= 10;
602 i += *buf - '0';
603 len--;
604 }
ad3c9f2a
A
605#if __DARWIN_UNIX03
606 }
607#endif /* __DARWIN_UNIX03 */
5b2abdfb 608
974e3884
A
609 if (i < 0)
610 return (NULL);
611
612 if (c == 'Y'){
613 i -= TM_YEAR_BASE;
614 } else if (c == 'y' && flags & FLAG_CENTURY) {
615 i = tm->tm_year + (i % 100);
616 flags &= ~FLAG_CENTURY;
617 } else if (c == 'y'){
618 if (i < 69) i += 100;
619 flags |= FLAG_YEAR_IN_CENTURY;
620 }
5b2abdfb 621
974e3884
A
622 tm->tm_year = i;
623 flags |= FLAG_YEAR;
624 if (c == 'Y'){
625 flags &= ~(FLAG_CENTURY | FLAG_YEAR_IN_CENTURY);
6465356a
A
626 }
627
5b2abdfb
A
628 break;
629
630 case 'Z':
631 {
974e3884
A
632 const char *cp;
633 size_t tzlen, len;
5b2abdfb 634
974e3884
A
635 for (cp = buf; *cp &&
636 isupper_l((unsigned char)*cp, locale); ++cp) {
637 /*empty*/
638 }
639 len = cp - buf;
640 if (len == 3 && strncmp(buf, "GMT", 3) == 0) {
641 *convp = CONVERT_GMT;
642 buf += len;
643 break;
644 }
645
646 tzset();
647 tzlen = strlen(tzname[0]);
648 if (len == tzlen && strncmp(buf, tzname[0], tzlen) == 0) {
649 tm->tm_isdst = 0;
650 buf += len;
651 break;
652 }
653 tzlen = strlen(tzname[1]);
654 if (len == tzlen && strncmp(buf, tzname[1], tzlen) == 0) {
655 tm->tm_isdst = 1;
656 buf += len;
657 break;
658 }
659 return (NULL);
5b2abdfb 660 }
1f2f436a
A
661
662 case 'z':
663 {
974e3884
A
664 char sign;
665 int hr, min;
666 if ((buf[0] != '+' && buf[0] != '-')
667 || !isdigit_l((unsigned char)buf[1], locale)
668 || !isdigit_l((unsigned char)buf[2], locale)
669 || !isdigit_l((unsigned char)buf[3], locale)
670 || !isdigit_l((unsigned char)buf[4], locale))
1f2f436a 671 return 0;
974e3884
A
672 sscanf(buf, "%c%2d%2d", &sign, &hr, &min);
673 *convp = CONVERT_ZONE;
674 tm->tm_gmtoff = 60 * (60 * hr + min);
675 if (sign == '-')
676 tm->tm_gmtoff = -tm->tm_gmtoff;
677 buf += 5;
1f2f436a 678 }
974e3884 679 break;
1f2f436a 680
974e3884
A
681 case 'n':
682 case 't':
683 if (!isspace((unsigned char)*buf))
684 return 0;
685 while (isspace_l((unsigned char)*buf, locale))
686 buf++;
687 break;
688
689 default:
690 return (NULL);
691 }
692 }
693
694 if (!(flags & FLAG_YDAY) && (flags & FLAG_YEAR)) {
695 if ((flags & (FLAG_MONTH | FLAG_MDAY)) ==
696 (FLAG_MONTH | FLAG_MDAY)) {
697 tm->tm_yday = start_of_month[isleap(tm->tm_year +
698 TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1);
699 flags |= FLAG_YDAY;
700 } else if (flags & FLAG_WEEK){
701 if (!(flags & FLAG_WDAY)) {
702 tm->tm_wday = week_kind == WEEK_U ? TM_SUNDAY : TM_MONDAY;
703 flags |= FLAG_WDAY;
1f2f436a
A
704 }
705
974e3884
A
706 struct tm t = {0};
707 t.tm_mday = week_kind == WEEK_V ? 4 : 1;
708 t.tm_hour = 12; /* avoid any DST effects */
709 t.tm_year = tm->tm_year;
710 if (timegm(&t) == (time_t)-1) return 0;
711
712 int off = t.tm_wday;
713 int wday = tm->tm_wday;
714
715 if (week_kind != WEEK_U) {
716 off = (off + 6) % 7;
717 wday = (wday + 6) % 7;
1f2f436a 718 }
974e3884
A
719
720 if (week_kind == WEEK_V) {
721 t.tm_mday = 7 * week_number + wday - off - 3;
722 } else {
723 if(off == 0) off = 7;
724 t.tm_mday = 7 * week_number + wday - off + 1;
725 }
726 if (timegm(&t) == (time_t)-1) return 0;
727
728 tm->tm_yday = t.tm_yday;
729
730 flags |= FLAG_YDAY;
5b2abdfb
A
731 }
732 }
974e3884
A
733
734 if ((flags & (FLAG_YEAR | FLAG_YDAY)) == (FLAG_YEAR | FLAG_YDAY)) {
735 if (!(flags & FLAG_MONTH)) {
736 i = 0;
737 while (tm->tm_yday >=
738 start_of_month[isleap(tm->tm_year +
739 TM_YEAR_BASE)][i])
740 i++;
741 if (i > 12) {
742 i = 1;
743 tm->tm_yday -=
744 start_of_month[isleap(tm->tm_year +
745 TM_YEAR_BASE)][12];
746 tm->tm_year++;
747 }
748 tm->tm_mon = i - 1;
749 flags |= FLAG_MONTH;
750 }
751 if (!(flags & FLAG_MDAY)) {
752 tm->tm_mday = tm->tm_yday -
753 start_of_month[isleap(tm->tm_year + TM_YEAR_BASE)]
754 [tm->tm_mon] + 1;
755 flags |= FLAG_MDAY;
756 }
757 if (!(flags & FLAG_WDAY)) {
758 i = 0;
759 wday_offset = first_wday_of(tm->tm_year);
760 while (i++ <= tm->tm_yday) {
761 if (wday_offset++ >= 6)
762 wday_offset = 0;
763 }
764 tm->tm_wday = wday_offset;
765 flags |= FLAG_WDAY;
766 }
767 }
768
769 return ((char *)buf);
5b2abdfb
A
770}
771
772
773char *
9385eb3d 774strptime(const char * __restrict buf, const char * __restrict fmt,
974e3884 775 struct tm * __restrict tm)
5b2abdfb 776{
ad3c9f2a
A
777 return strptime_l(buf, fmt, tm, __current_locale());
778}
779
780extern time_t timeoff(struct tm *, long);
5b2abdfb 781
ad3c9f2a
A
782char *
783strptime_l(const char * __restrict buf, const char * __restrict fmt,
784 struct tm * __restrict tm, locale_t loc)
785{
786 char *ret;
787 int conv;
788
789 NORMALIZE_LOCALE(loc);
790 conv = CONVERT_NONE;
791 tm->tm_zone = NULL;
792 ret = _strptime(buf, fmt, tm, &conv, loc);
793 if (ret) {
794 time_t t;
795
796 switch(conv) {
797 case CONVERT_GMT:
798 t = timegm(tm);
799 localtime_r(&t, tm);
800 break;
801 case CONVERT_ZONE:
802 {
803 long offset = tm->tm_gmtoff;
804 tm->tm_gmtoff = 0;
805 t = timeoff(tm, offset);
806 localtime_r(&t, tm);
807 break;
808 }
809 }
5b2abdfb
A
810 }
811
9385eb3d 812 return (ret);
5b2abdfb 813}