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