]>
git.saurik.com Git - apple/libc.git/blob - stdtime/FreeBSD/strptime.c
2cac16184cf92bd22cd63fa425331b7fe07b2af3
2 * Powerdog Industries kindly requests feedback from anyone modifying
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)
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.
16 * Anyway, you can change it to "with or without modification" as
20 * Powerdog Industries, Inc.
23 * Copyright (c) 1994 Powerdog Industries. All rights reserved.
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
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
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
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.
54 #include <sys/cdefs.h>
57 static char copyright
[] __unused
=
58 "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
59 static char sccsid
[] __unused
= "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
60 #endif /* !defined NOID */
62 __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.37 2009/09/02 04:56:30 ache Exp $");
64 #include "xlocale_private.h"
66 #include "namespace.h"
76 #include "un-namespace.h"
77 #include "libc_private.h"
78 #include "timelocal.h"
80 time_t _mktime(struct tm
*, const char *);
82 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
84 enum {CONVERT_NONE
, CONVERT_GMT
, CONVERT_ZONE
};
86 #define _strptime(b,f,t,c,l) _strptime0(b,f,t,c,l,-1,0,-1,-1,'U')
93 calcweeknum(struct tm
*tm
, int weeknum
, int wday
, int year
, int kind
)
99 t
.tm_mday
= kind
== WEEK_V
? 4 : 1;
100 t
.tm_hour
= 12; /* avoid any DST effects */
102 if (mktime(&t
) == (time_t)-1) return 0;
105 bzero(&t
, sizeof(t
));
106 if (kind
!= WEEK_U
) {
108 wday
= (wday
+ 6) % 7;
110 if (kind
== WEEK_V
) {
111 t
.tm_mday
= 7 * weeknum
+ wday
- off
- 3;
113 if(off
== 0) off
= 7;
114 t
.tm_mday
= 7 * weeknum
+ wday
- off
+ 1;
116 t
.tm_hour
= 12; /* avoid any DST effects */
118 if (mktime(&t
) == (time_t)-1) return 0;
120 tm
->tm_mday
= t
.tm_mday
;
121 tm
->tm_mon
= t
.tm_mon
;
122 tm
->tm_yday
= t
.tm_yday
;
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
)
133 int Ealternative
, Oalternative
;
134 struct lc_time_T
*tptr
= __get_current_time_locale(loc
);
140 while (isspace_l((unsigned char)*ptr
, loc
)) {
143 return ((*ptr
)==0) ? (char *)fmt
: 0; /* trailing whitespace is ok */
149 if (isspace_l((unsigned char)c
, loc
))
150 while (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
152 else if (c
!= *buf
++)
169 buf
= _strptime(buf
, tptr
->date_fmt
, tm
, convp
, loc
);
175 if (!isdigit_l((unsigned char)*buf
, loc
))
178 /* XXX This will break for 3-digit centuries. */
180 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
189 tm
->tm_year
= (year
% 100) + i
* 100 - 1900;
191 tm
->tm_year
= i
* 100 - 1900;
196 buf
= _strptime(buf
, tptr
->c_fmt
, tm
, convp
, loc
);
202 buf
= _strptime(buf
, "%m/%d/%y", tm
, convp
, loc
);
208 if (Ealternative
|| Oalternative
)
214 if (Ealternative
|| Oalternative
)
220 buf
= _strptime(buf
, "%Y-%m-%d", tm
, convp
, loc
);
226 buf
= _strptime(buf
, "%H:%M", tm
, convp
, loc
);
232 buf
= _strptime(buf
, tptr
->ampm_fmt
, tm
, convp
, loc
);
239 if (!isspace((unsigned char)*buf
))
241 while (isspace((unsigned char)*buf
))
246 buf
= _strptime(buf
, "%H:%M:%S", tm
, convp
, loc
);
252 buf
= _strptime(buf
, tptr
->X_fmt
, tm
, convp
, loc
);
258 buf
= _strptime(buf
, tptr
->x_fmt
, tm
, convp
, loc
);
264 if (!isdigit_l((unsigned char)*buf
, loc
))
268 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
273 if (i
< 1 || i
> 366)
276 tm
->tm_yday
= yday
= i
- 1;
281 if (*buf
== 0 || isspace_l((unsigned char)*buf
, loc
))
284 if (!isdigit_l((unsigned char)*buf
, loc
))
288 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
304 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
305 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
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.
318 * XXX The %l specifier may gobble one too many
319 * digits if used incorrectly.
321 if (!isdigit_l((unsigned char)*buf
, loc
))
325 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
330 if (c
== 'H' || c
== 'k') {
338 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
339 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
345 * XXX This is bogus if parsed before hour-related
348 len
= strlen(tptr
->am
);
349 if (strncasecmp_l(buf
, tptr
->am
, len
, loc
) == 0) {
350 if (tm
->tm_hour
> 12)
352 if (tm
->tm_hour
== 12)
358 len
= strlen(tptr
->pm
);
359 if (strncasecmp_l(buf
, tptr
->pm
, len
, loc
) == 0) {
360 if (tm
->tm_hour
> 12)
362 if (tm
->tm_hour
!= 12)
372 for (i
= 0; i
< asizeof(tptr
->weekday
); i
++) {
373 len
= strlen(tptr
->weekday
[i
]);
374 if (strncasecmp_l(buf
, tptr
->weekday
[i
],
377 len
= strlen(tptr
->wday
[i
]);
378 if (strncasecmp_l(buf
, tptr
->wday
[i
],
382 if (i
== asizeof(tptr
->weekday
))
385 tm
->tm_wday
= wday
= i
;
389 case 'U': /* Sunday week */
390 case 'V': /* ISO 8601 week */
391 case 'W': /* Monday week */
392 if (!isdigit_l((unsigned char)*buf
, loc
))
396 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
403 if (c
== 'V' && i
< 1)
409 /* Calculate mon/mday/yday if we have enough data */
410 if ((year
!= -1) && (wday
!= -1)) {
411 if (!calcweeknum(tm
, weeknum
, wday
, year
, weekkind
)) return 0;
413 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
414 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
418 case 'u': /* [1,7] */
419 case 'w': /* [0,6] */
420 if (!isdigit_l((unsigned char)*buf
, loc
))
424 if (i
> 6 + (c
== 'u'))
428 tm
->tm_wday
= wday
= i
;
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;
436 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
437 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
444 * The %e specifier is explicitly documented as not
445 * being zero-padded but there is no harm in allowing
448 * XXX The %e specifier may gobble one too many
449 * digits if used incorrectly.
451 /* Leading space is ok if date is single digit */
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
)) {
459 if (!isdigit_l((unsigned char)*buf
, loc
))
462 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
472 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
473 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
480 for (i
= 0; i
< asizeof(tptr
->month
); i
++) {
483 len
= strlen(tptr
->alt_month
[i
]);
484 if (strncasecmp_l(buf
,
490 len
= strlen(tptr
->month
[i
]);
491 if (strncasecmp_l(buf
, tptr
->month
[i
],
494 len
= strlen(tptr
->mon
[i
]);
495 if (strncasecmp_l(buf
, tptr
->mon
[i
],
500 if (i
== asizeof(tptr
->month
))
508 if (!isdigit_l((unsigned char)*buf
, loc
))
512 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
522 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
523 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
536 n
= strtol_l(buf
, &cp
, 10, loc
);
537 if (errno
== ERANGE
|| (long)(t
= n
) != n
) {
544 *convp
= CONVERT_GMT
;
550 if (*buf
== 0 || isspace_l((unsigned char)*buf
, loc
))
553 if (!isdigit_l((unsigned char)*buf
, loc
))
559 const char *savebuf
= buf
;
563 for (len
= 0; *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
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
584 if (len
> 4 && !overflow
) {
585 struct tm savetm
= *tm
;
586 int saveconv
= *convp
;
587 const char *saveptr
= ptr
;
593 tm
->tm_year
= i64
- 1900;
595 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
596 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
598 ret
= _strptime0(buf
, ptr
, tm
, convp
, loc
, tm
->tm_year
, yday
, wday
, weeknum
, weekkind
);
600 /* Failed, so try 4-digit year */
609 #else /* !__DARWIN_UNIX03 */
610 len
= (c
== 'Y') ? 4 : 2;
611 #endif /* __DARWIN_UNIX03 */
612 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
619 #endif /* __DARWIN_UNIX03 */
622 if (c
== 'y' && i
< 69)
627 tm
->tm_year
= year
= i
;
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;
634 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
635 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
644 for (cp
= buf
; *cp
&& isupper((unsigned char)*cp
); ++cp
) {/*empty*/}
646 if (len
== 3 && strncmp(buf
, "GMT", 3) == 0) {
647 *convp
= CONVERT_GMT
;
652 tzlen
= strlen(tzname
[0]);
653 if (len
== tzlen
&& strncmp(buf
, tzname
[0], tzlen
) == 0) {
658 tzlen
= strlen(tzname
[1]);
659 if (len
== tzlen
&& strncmp(buf
, tzname
[1], tzlen
) == 0) {
680 for (len
= 4; len
> 0; len
--) {
681 if (isdigit_l((unsigned char)*buf
, loc
)) {
689 tm
->tm_hour
-= sign
* (i
/ 100);
690 tm
->tm_min
-= sign
* (i
% 100);
691 *convp
= CONVERT_GMT
;
701 strptime(const char * __restrict buf
, const char * __restrict fmt
,
702 struct tm
* __restrict tm
)
704 return strptime_l(buf
, fmt
, tm
, __current_locale());
707 extern time_t timeoff(struct tm
*, long);
710 strptime_l(const char * __restrict buf
, const char * __restrict fmt
,
711 struct tm
* __restrict tm
, locale_t loc
)
716 NORMALIZE_LOCALE(loc
);
719 ret
= _strptime(buf
, fmt
, tm
, &conv
, loc
);
730 long offset
= tm
->tm_gmtoff
;
732 t
= timeoff(tm
, offset
);