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.
59 #include <sys/cdefs.h>
62 static char copyright[] __unused =
63 "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
64 static char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
65 #endif /* !defined NOID */
67 __FBSDID("$FreeBSD$");
69 #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);
82 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
85 _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
92 int Ealternative, Oalternative;
93 struct lc_time_T *tptr = __get_current_time_locale(locale);
103 if (isspace_l((unsigned char)c, locale))
105 isspace_l((unsigned char)*buf, locale))
107 else if (c != *buf++)
124 buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale);
130 if (!isdigit_l((unsigned char)*buf, locale))
133 /* XXX This will break for 3-digit centuries. */
135 for (i = 0; len && *buf != 0 &&
136 isdigit_l((unsigned char)*buf, locale); buf++) {
144 tm->tm_year = i * 100 - 1900;
148 buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale);
154 buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale);
160 if (Ealternative || Oalternative)
166 if (Ealternative || Oalternative)
172 buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);
178 buf = _strptime(buf, "%H:%M", tm, GMTp, locale);
184 buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale);
190 buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale);
196 buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale);
202 buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);
208 if (!isdigit_l((unsigned char)*buf, locale))
212 for (i = 0; len && *buf != 0 &&
213 isdigit_l((unsigned char)*buf, locale); buf++){
218 if (i < 1 || i > 366)
227 isspace_l((unsigned char)*buf, locale))
230 if (!isdigit_l((unsigned char)*buf, locale))
234 for (i = 0; len && *buf != 0 &&
235 isdigit_l((unsigned char)*buf, locale); buf++){
252 isspace_l((unsigned char)*buf, locale))
254 !isspace_l((unsigned char)*ptr, locale))
263 * Of these, %l is the only specifier explicitly
264 * documented as not being zero-padded. However,
265 * there is no harm in allowing zero-padding.
267 * XXX The %l specifier may gobble one too many
268 * digits if used incorrectly.
270 if (!isdigit_l((unsigned char)*buf, locale))
274 for (i = 0; len && *buf != 0 &&
275 isdigit_l((unsigned char)*buf, locale); buf++) {
280 if (c == 'H' || c == 'k') {
289 isspace_l((unsigned char)*buf, locale))
291 !isspace_l((unsigned char)*ptr, locale))
297 * XXX This is bogus if parsed before hour-related
300 len = strlen(tptr->am);
301 if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
302 if (tm->tm_hour > 12)
304 if (tm->tm_hour == 12)
310 len = strlen(tptr->pm);
311 if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
312 if (tm->tm_hour > 12)
314 if (tm->tm_hour != 12)
324 for (i = 0; i < asizeof(tptr->weekday); i++) {
325 len = strlen(tptr->weekday[i]);
326 if (strncasecmp_l(buf, tptr->weekday[i],
329 len = strlen(tptr->wday[i]);
330 if (strncasecmp_l(buf, tptr->wday[i],
334 if (i == asizeof(tptr->weekday))
344 * XXX This is bogus, as we can not assume any valid
345 * information present in the tm structure at this
346 * point to calculate a real value, so just check the
349 if (!isdigit_l((unsigned char)*buf, locale))
353 for (i = 0; len && *buf != 0 &&
354 isdigit_l((unsigned char)*buf, locale); buf++) {
363 isspace_l((unsigned char)*buf, locale))
365 !isspace_l((unsigned char)*ptr, locale))
370 if (!isdigit_l((unsigned char)*buf, locale))
380 isspace_l((unsigned char)*buf, locale))
382 !isspace_l((unsigned char)*ptr, locale))
389 * The %e specifier is explicitly documented as not
390 * being zero-padded but there is no harm in allowing
393 * XXX The %e specifier may gobble one too many
394 * digits if used incorrectly.
396 if (!isdigit_l((unsigned char)*buf, locale))
400 for (i = 0; len && *buf != 0 &&
401 isdigit_l((unsigned char)*buf, locale); buf++) {
412 isspace_l((unsigned char)*buf, locale))
414 !isspace_l((unsigned char)*ptr, locale))
421 for (i = 0; i < asizeof(tptr->month); i++) {
424 len = strlen(tptr->alt_month[i]);
425 if (strncasecmp_l(buf,
431 len = strlen(tptr->month[i]);
432 if (strncasecmp_l(buf, tptr->month[i],
438 * Try the abbreviated month name if the full name
439 * wasn't found and Oalternative was not requested.
441 if (i == asizeof(tptr->month) && !Oalternative) {
442 for (i = 0; i < asizeof(tptr->month); i++) {
443 len = strlen(tptr->mon[i]);
444 if (strncasecmp_l(buf, tptr->mon[i],
449 if (i == asizeof(tptr->month))
457 if (!isdigit_l((unsigned char)*buf, locale))
461 for (i = 0; len && *buf != 0 &&
462 isdigit_l((unsigned char)*buf, locale); buf++) {
473 isspace_l((unsigned char)*buf, locale))
475 !isspace_l((unsigned char)*ptr, locale))
488 n = strtol_l(buf, &cp, 10, locale);
489 if (errno == ERANGE || (long)(t = n) != n) {
503 isspace_l((unsigned char)*buf, locale))
506 if (!isdigit_l((unsigned char)*buf, locale))
509 len = (c == 'Y') ? 4 : 2;
510 for (i = 0; len && *buf != 0 &&
511 isdigit_l((unsigned char)*buf, locale); buf++) {
518 if (c == 'y' && i < 69)
526 isspace_l((unsigned char)*buf, locale))
528 !isspace_l((unsigned char)*ptr, locale))
537 for (cp = buf; *cp &&
538 isupper_l((unsigned char)*cp, locale); ++cp) {
541 zonestr = alloca(cp - buf + 1);
542 strncpy(zonestr, buf, cp - buf);
543 zonestr[cp - buf] = '\0';
545 if (0 == strcmp(zonestr, "GMT")) {
547 } else if (0 == strcmp(zonestr, tzname[0])) {
549 } else if (0 == strcmp(zonestr, tzname[1])) {
572 for (len = 4; len > 0; len--) {
573 if (isdigit_l((unsigned char)*buf, locale)) {
581 tm->tm_hour -= sign * (i / 100);
582 tm->tm_min -= sign * (i % 100);
593 strptime_l(const char * __restrict buf, const char * __restrict fmt,
594 struct tm * __restrict tm, locale_t loc)
601 ret = _strptime(buf, fmt, tm, &gmt, loc);
603 time_t t = timegm(tm);
610 strptime(const char * __restrict buf, const char * __restrict fmt,
611 struct tm * __restrict tm)
613 return strptime_l(buf, fmt, tm, __get_locale());