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 * Copyright (c) 2011 The FreeBSD Foundation
26 * All rights reserved.
27 * Portions of this software were developed by David Chisnall
28 * under sponsorship from the FreeBSD Foundation.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer
37 * in the documentation and/or other materials provided with the
39 * 3. All advertising materials mentioning features or use of this
40 * software must display the following acknowledgement:
41 * This product includes software developed by Powerdog Industries.
42 * 4. The name of Powerdog Industries may not be used to endorse or
43 * promote products derived from this software without specific prior
46 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
47 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
49 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
50 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
51 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
53 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
54 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
55 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
56 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 * @(#)strptime.c 0.1 (Powerdog) 94/03/27
59 * @(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.
60 * $FreeBSD: head/lib/libc/stdtime/strptime.c 227753 2011-11-20 14:45:42Z theraven $
63 #include "namespace.h"
70 #include "un-namespace.h"
71 #include "libc_private.h"
72 #include "timelocal.h"
74 static char * _strptime(const char *, const char *, struct tm
*, int *, locale_t
);
76 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
79 _strptime(const char *buf
, const char *fmt
, struct tm
*tm
, int *GMTp
,
86 int Ealternative
, Oalternative
;
87 struct lc_time_T
*tptr
= __get_current_time_locale(locale
);
97 if (isspace_l((unsigned char)c
, locale
))
99 isspace_l((unsigned char)*buf
, locale
))
101 else if (c
!= *buf
++)
118 buf
= _strptime(buf
, tptr
->date_fmt
, tm
, GMTp
, locale
);
124 if (!isdigit_l((unsigned char)*buf
, locale
))
127 /* XXX This will break for 3-digit centuries. */
129 for (i
= 0; len
&& *buf
!= 0 &&
130 isdigit_l((unsigned char)*buf
, locale
); buf
++) {
138 tm
->tm_year
= i
* 100 - 1900;
142 buf
= _strptime(buf
, tptr
->c_fmt
, tm
, GMTp
, locale
);
148 buf
= _strptime(buf
, "%m/%d/%y", tm
, GMTp
, locale
);
154 if (Ealternative
|| Oalternative
)
160 if (Ealternative
|| Oalternative
)
166 buf
= _strptime(buf
, "%Y-%m-%d", tm
, GMTp
, locale
);
172 buf
= _strptime(buf
, "%H:%M", tm
, GMTp
, locale
);
178 buf
= _strptime(buf
, tptr
->ampm_fmt
, tm
, GMTp
, locale
);
184 buf
= _strptime(buf
, "%H:%M:%S", tm
, GMTp
, locale
);
190 buf
= _strptime(buf
, tptr
->X_fmt
, tm
, GMTp
, locale
);
196 buf
= _strptime(buf
, tptr
->x_fmt
, tm
, GMTp
, locale
);
202 if (!isdigit_l((unsigned char)*buf
, locale
))
206 for (i
= 0; len
&& *buf
!= 0 &&
207 isdigit_l((unsigned char)*buf
, locale
); buf
++){
212 if (i
< 1 || i
> 366)
221 isspace_l((unsigned char)*buf
, locale
))
224 if (!isdigit_l((unsigned char)*buf
, locale
))
228 for (i
= 0; len
&& *buf
!= 0 &&
229 isdigit_l((unsigned char)*buf
, locale
); buf
++){
246 isspace_l((unsigned char)*buf
, locale
))
248 !isspace_l((unsigned char)*ptr
, locale
))
257 * Of these, %l is the only specifier explicitly
258 * documented as not being zero-padded. However,
259 * there is no harm in allowing zero-padding.
261 * XXX The %l specifier may gobble one too many
262 * digits if used incorrectly.
264 if (!isdigit_l((unsigned char)*buf
, locale
))
268 for (i
= 0; len
&& *buf
!= 0 &&
269 isdigit_l((unsigned char)*buf
, locale
); buf
++) {
274 if (c
== 'H' || c
== 'k') {
283 isspace_l((unsigned char)*buf
, locale
))
285 !isspace_l((unsigned char)*ptr
, locale
))
291 * XXX This is bogus if parsed before hour-related
294 len
= strlen(tptr
->am
);
295 if (strncasecmp_l(buf
, tptr
->am
, len
, locale
) == 0) {
296 if (tm
->tm_hour
> 12)
298 if (tm
->tm_hour
== 12)
304 len
= strlen(tptr
->pm
);
305 if (strncasecmp_l(buf
, tptr
->pm
, len
, locale
) == 0) {
306 if (tm
->tm_hour
> 12)
308 if (tm
->tm_hour
!= 12)
318 for (i
= 0; i
< asizeof(tptr
->weekday
); i
++) {
319 len
= strlen(tptr
->weekday
[i
]);
320 if (strncasecmp_l(buf
, tptr
->weekday
[i
],
323 len
= strlen(tptr
->wday
[i
]);
324 if (strncasecmp_l(buf
, tptr
->wday
[i
],
328 if (i
== asizeof(tptr
->weekday
))
338 * XXX This is bogus, as we can not assume any valid
339 * information present in the tm structure at this
340 * point to calculate a real value, so just check the
343 if (!isdigit_l((unsigned char)*buf
, locale
))
347 for (i
= 0; len
&& *buf
!= 0 &&
348 isdigit_l((unsigned char)*buf
, locale
); buf
++) {
357 isspace_l((unsigned char)*buf
, locale
))
359 !isspace_l((unsigned char)*ptr
, locale
))
364 if (!isdigit_l((unsigned char)*buf
, locale
))
374 isspace_l((unsigned char)*buf
, locale
))
376 !isspace_l((unsigned char)*ptr
, locale
))
383 * The %e specifier is explicitly documented as not
384 * being zero-padded but there is no harm in allowing
387 * XXX The %e specifier may gobble one too many
388 * digits if used incorrectly.
390 if (!isdigit_l((unsigned char)*buf
, locale
))
394 for (i
= 0; len
&& *buf
!= 0 &&
395 isdigit_l((unsigned char)*buf
, locale
); buf
++) {
406 isspace_l((unsigned char)*buf
, locale
))
408 !isspace_l((unsigned char)*ptr
, locale
))
415 for (i
= 0; i
< asizeof(tptr
->month
); i
++) {
418 len
= strlen(tptr
->alt_month
[i
]);
419 if (strncasecmp_l(buf
,
425 len
= strlen(tptr
->month
[i
]);
426 if (strncasecmp_l(buf
, tptr
->month
[i
],
432 * Try the abbreviated month name if the full name
433 * wasn't found and Oalternative was not requested.
435 if (i
== asizeof(tptr
->month
) && !Oalternative
) {
436 for (i
= 0; i
< asizeof(tptr
->month
); i
++) {
437 len
= strlen(tptr
->mon
[i
]);
438 if (strncasecmp_l(buf
, tptr
->mon
[i
],
443 if (i
== asizeof(tptr
->month
))
451 if (!isdigit_l((unsigned char)*buf
, locale
))
455 for (i
= 0; len
&& *buf
!= 0 &&
456 isdigit_l((unsigned char)*buf
, locale
); buf
++) {
467 isspace_l((unsigned char)*buf
, locale
))
469 !isspace_l((unsigned char)*ptr
, locale
))
482 n
= strtol_l(buf
, &cp
, 10, locale
);
483 if (errno
== ERANGE
|| (long)(t
= n
) != n
) {
497 isspace_l((unsigned char)*buf
, locale
))
500 if (!isdigit_l((unsigned char)*buf
, locale
))
503 len
= (c
== 'Y') ? 4 : 2;
504 for (i
= 0; len
&& *buf
!= 0 &&
505 isdigit_l((unsigned char)*buf
, locale
); buf
++) {
512 if (c
== 'y' && i
< 69)
520 isspace_l((unsigned char)*buf
, locale
))
522 !isspace_l((unsigned char)*ptr
, locale
))
531 for (cp
= buf
; *cp
&&
532 isupper_l((unsigned char)*cp
, locale
); ++cp
) {
535 zonestr
= alloca(cp
- buf
+ 1);
536 strncpy(zonestr
, buf
, cp
- buf
);
537 zonestr
[cp
- buf
] = '\0';
539 if (0 == strcmp(zonestr
, "GMT") ||
540 0 == strcmp(zonestr
, "UTC")) {
542 } else if (0 == strcmp(zonestr
, tzname
[0])) {
544 } else if (0 == strcmp(zonestr
, tzname
[1])) {
567 for (len
= 4; len
> 0; len
--) {
568 if (isdigit_l((unsigned char)*buf
, locale
)) {
576 tm
->tm_hour
-= sign
* (i
/ 100);
577 tm
->tm_min
-= sign
* (i
% 100);
588 strptime_l(const char * __restrict buf
, const char * __restrict fmt
,
589 struct tm
* __restrict tm
, locale_t loc
)
596 ret
= _strptime(buf
, fmt
, tm
, &gmt
, loc
);
598 time_t t
= timegm(tm
);
605 strptime(const char * __restrict buf
, const char * __restrict fmt
,
606 struct tm
* __restrict tm
)
608 return strptime_l(buf
, fmt
, tm
, __get_locale());