]>
git.saurik.com Git - apple/libc.git/blob - stdtime/strptime-fbsd.c
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.35 2003/11/17 04:19:15 nectar 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 static char * _strptime(const char *, const char *, struct tm
*, int *, locale_t
) __DARWIN_ALIAS(_strptime
);
81 time_t _mktime(struct tm
*, const char *);
83 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
85 enum {CONVERT_NONE
, CONVERT_GMT
, CONVERT_ZONE
};
87 #define _strptime(b,f,t,c,l) _strptime0(b,f,t,c,l,-1,0,-1)
90 _strptime0(const char *buf
, const char *fmt
, struct tm
*tm
, int *convp
, locale_t loc
, int year
, int yday
, int wday
)
96 int Ealternative
, Oalternative
;
97 struct lc_time_T
*tptr
= __get_current_time_locale(loc
);
103 while (isspace_l((unsigned char)*ptr
, loc
)) {
106 return ((*ptr
)==0) ? fmt
: 0; /* trailing whitespace is ok */
112 if (isspace_l((unsigned char)c
, loc
))
113 while (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
115 else if (c
!= *buf
++)
132 buf
= _strptime(buf
, tptr
->date_fmt
, tm
, convp
, loc
);
138 if (!isdigit_l((unsigned char)*buf
, loc
))
141 /* XXX This will break for 3-digit centuries. */
143 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
152 tm
->tm_year
= (year
% 100) + i
* 100 - 1900;
154 tm
->tm_year
= i
* 100 - 1900;
159 buf
= _strptime(buf
, tptr
->c_fmt
, tm
, convp
, loc
);
165 buf
= _strptime(buf
, "%m/%d/%y", tm
, convp
, loc
);
171 if (Ealternative
|| Oalternative
)
177 if (Ealternative
|| Oalternative
)
183 buf
= _strptime(buf
, "%Y-%m-%d", tm
, convp
, loc
);
189 buf
= _strptime(buf
, "%H:%M", tm
, convp
, loc
);
195 buf
= _strptime(buf
, tptr
->ampm_fmt
, tm
, convp
, loc
);
202 if (!isspace((unsigned char)*buf
))
204 while (isspace((unsigned char)*buf
))
209 buf
= _strptime(buf
, "%H:%M:%S", tm
, convp
, loc
);
215 buf
= _strptime(buf
, tptr
->X_fmt
, tm
, convp
, loc
);
221 buf
= _strptime(buf
, tptr
->x_fmt
, tm
, convp
, loc
);
227 if (!isdigit_l((unsigned char)*buf
, loc
))
231 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
236 if (i
< 1 || i
> 366)
239 tm
->tm_yday
= yday
= i
- 1;
244 if (*buf
== 0 || isspace_l((unsigned char)*buf
, loc
))
247 if (!isdigit_l((unsigned char)*buf
, loc
))
251 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
267 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
268 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
277 * Of these, %l is the only specifier explicitly
278 * documented as not being zero-padded. However,
279 * there is no harm in allowing zero-padding.
281 * XXX The %l specifier may gobble one too many
282 * digits if used incorrectly.
284 if (!isdigit_l((unsigned char)*buf
, loc
))
288 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
293 if (c
== 'H' || c
== 'k') {
301 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
302 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
308 * XXX This is bogus if parsed before hour-related
311 len
= strlen(tptr
->am
);
312 if (strncasecmp_l(buf
, tptr
->am
, len
, loc
) == 0) {
313 if (tm
->tm_hour
> 12)
315 if (tm
->tm_hour
== 12)
321 len
= strlen(tptr
->pm
);
322 if (strncasecmp_l(buf
, tptr
->pm
, len
, loc
) == 0) {
323 if (tm
->tm_hour
> 12)
325 if (tm
->tm_hour
!= 12)
335 for (i
= 0; i
< asizeof(tptr
->weekday
); i
++) {
336 len
= strlen(tptr
->weekday
[i
]);
337 if (strncasecmp_l(buf
, tptr
->weekday
[i
],
340 len
= strlen(tptr
->wday
[i
]);
341 if (strncasecmp_l(buf
, tptr
->wday
[i
],
345 if (i
== asizeof(tptr
->weekday
))
348 tm
->tm_wday
= wday
= i
;
352 case 'U': /* Sunday week */
353 case 'W': /* Monday week */
354 if (!isdigit_l((unsigned char)*buf
, loc
))
358 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
366 /* Calculate yday if we have enough data */
367 if ((year
!= -1) && (wday
!= -1)) {
373 mktm
.tm_min
= mktm
.tm_hour
= 0;
376 if (mktime(&mktm
) != -1) {
377 /* yday0 == Jan 1 == mktm.tm_wday */
378 int delta
= wday
- mktm
.tm_wday
;
379 if (!wday
&& c
=='W')
380 i
++; /* Sunday is part of the following week */
381 yday
= 7 * i
+ delta
;
387 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
388 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
392 case 'u': /* [1,7] */
393 case 'w': /* [0,6] */
394 if (!isdigit_l((unsigned char)*buf
, loc
))
398 if (i
> 6 + (c
== 'u'))
402 tm
->tm_wday
= wday
= i
;
404 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
405 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
412 * The %e specifier is explicitly documented as not
413 * being zero-padded but there is no harm in allowing
416 * XXX The %e specifier may gobble one too many
417 * digits if used incorrectly.
419 /* Leading space is ok if date is single digit */
421 if (isspace_l((unsigned char)buf
[0], loc
) &&
422 isdigit_l((unsigned char)buf
[1], loc
) &&
423 !isdigit_l((unsigned char)buf
[2], loc
)) {
427 if (!isdigit_l((unsigned char)*buf
, loc
))
430 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
440 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
441 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
448 for (i
= 0; i
< asizeof(tptr
->month
); i
++) {
451 len
= strlen(tptr
->alt_month
[i
]);
452 if (strncasecmp_l(buf
,
458 len
= strlen(tptr
->month
[i
]);
459 if (strncasecmp_l(buf
, tptr
->month
[i
],
462 len
= strlen(tptr
->mon
[i
]);
463 if (strncasecmp_l(buf
, tptr
->mon
[i
],
468 if (i
== asizeof(tptr
->month
))
476 if (!isdigit_l((unsigned char)*buf
, loc
))
480 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
490 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
491 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
504 n
= strtol_l(buf
, &cp
, 10, loc
);
505 if (errno
== ERANGE
|| (long)(t
= n
) != n
) {
512 *convp
= CONVERT_GMT
;
518 if (*buf
== 0 || isspace_l((unsigned char)*buf
, loc
))
521 if (!isdigit_l((unsigned char)*buf
, loc
))
527 const char *savebuf
= buf
;
531 for (len
= 0; *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
544 * Conformance requires %Y to be more then 4
545 * digits. However, there are several cases
546 * where %Y is immediately followed by other
547 * digits values. So we do the conformance
548 * case first (as many digits as possible),
549 * and if we fail, we backup and try just 4
552 if (len
> 4 && !overflow
) {
553 struct tm savetm
= *tm
;
554 int saveconv
= *convp
;
555 const char *saveptr
= ptr
;
561 tm
->tm_year
= i64
- 1900;
563 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
564 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
566 ret
= _strptime0(buf
, ptr
, tm
, convp
, loc
, tm
->tm_year
, yday
, wday
);
568 /* Failed, so try 4-digit year */
577 #else /* !__DARWIN_UNIX03 */
578 len
= (c
== 'Y') ? 4 : 2;
579 #endif /* __DARWIN_UNIX03 */
580 for (i
= 0; len
&& *buf
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) {
587 #endif /* __DARWIN_UNIX03 */
590 if (c
== 'y' && i
< 69)
595 tm
->tm_year
= year
= i
;
597 if (*buf
!= 0 && isspace_l((unsigned char)*buf
, loc
))
598 while (*ptr
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr
!= '%')
607 for (cp
= buf
; *cp
&& isupper((unsigned char)*cp
); ++cp
) {/*empty*/}
609 if (len
== 3 && strncmp(buf
, "GMT", 3) == 0) {
610 *convp
= CONVERT_GMT
;
615 tzlen
= strlen(tzname
[0]);
616 if (len
== tzlen
&& strncmp(buf
, tzname
[0], tzlen
) == 0) {
621 tzlen
= strlen(tzname
[1]);
622 if (len
== tzlen
&& strncmp(buf
, tzname
[1], tzlen
) == 0) {
635 if ((buf
[0] != '+' && buf
[0] != '-')
636 || !isdigit_l((unsigned char)buf
[1], loc
)
637 || !isdigit_l((unsigned char)buf
[2], loc
)
638 || !isdigit_l((unsigned char)buf
[3], loc
)
639 || !isdigit_l((unsigned char)buf
[4], loc
))
641 sscanf(buf
, "%c%2d%2d", &sign
, &hr
, &min
);
642 *convp
= CONVERT_ZONE
;
643 tm
->tm_gmtoff
= 60 * (60 * hr
+ min
);
645 tm
->tm_gmtoff
= -tm
->tm_gmtoff
;
656 strptime(const char * __restrict buf
, const char * __restrict fmt
,
657 struct tm
* __restrict tm
)
659 return strptime_l(buf
, fmt
, tm
, __current_locale());
662 extern time_t timeoff(struct tm
*, long);
665 strptime_l(const char * __restrict buf
, const char * __restrict fmt
,
666 struct tm
* __restrict tm
, locale_t loc
)
671 NORMALIZE_LOCALE(loc
);
674 ret
= _strptime(buf
, fmt
, tm
, &conv
, loc
);
685 long offset
= tm
->tm_gmtoff
;
687 t
= timeoff(tm
, offset
);