2 * Copyright (c) 2014 Gary Mills
3 * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
4 * Copyright (c) 1994 Powerdog Industries. All rights reserved.
6 * Copyright (c) 2011 The FreeBSD Foundation
8 * Portions of this software were developed by David Chisnall
9 * under sponsorship from the FreeBSD Foundation.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer
18 * in the documentation and/or other materials provided with the
21 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * The views and conclusions contained in the software and documentation
34 * are those of the authors and should not be interpreted as representing
35 * official policies, either expressed or implied, of Powerdog Industries.
38 #include <sys/cdefs.h>
41 static char copyright[] __unused =
42 "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
43 static char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
44 #endif /* !defined NOID */
46 __FBSDID("$FreeBSD$");
48 #include "namespace.h"
55 #include "un-namespace.h"
56 #include "libc_private.h"
57 #include "timelocal.h"
59 static char * _strptime(const char *, const char *, struct tm *, int *, locale_t);
61 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
64 _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
70 int Ealternative, Oalternative;
71 struct lc_time_T *tptr = __get_current_time_locale(locale);
81 if (isspace_l((unsigned char)c, locale))
83 isspace_l((unsigned char)*buf, locale))
102 buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale);
108 if (!isdigit_l((unsigned char)*buf, locale))
111 /* XXX This will break for 3-digit centuries. */
113 for (i = 0; len && *buf != 0 &&
114 isdigit_l((unsigned char)*buf, locale); buf++) {
122 tm->tm_year = i * 100 - 1900;
126 buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale);
132 buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale);
138 if (Ealternative || Oalternative)
144 if (Ealternative || Oalternative)
150 buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);
156 buf = _strptime(buf, "%H:%M", tm, GMTp, locale);
162 buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale);
168 buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale);
174 buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale);
180 buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);
186 if (!isdigit_l((unsigned char)*buf, locale))
190 for (i = 0; len && *buf != 0 &&
191 isdigit_l((unsigned char)*buf, locale); buf++){
196 if (i < 1 || i > 366)
205 isspace_l((unsigned char)*buf, locale))
208 if (!isdigit_l((unsigned char)*buf, locale))
212 for (i = 0; len && *buf != 0 &&
213 isdigit_l((unsigned char)*buf, locale); buf++){
236 * Of these, %l is the only specifier explicitly
237 * documented as not being zero-padded. However,
238 * there is no harm in allowing zero-padding.
240 * XXX The %l specifier may gobble one too many
241 * digits if used incorrectly.
243 if (!isdigit_l((unsigned char)*buf, locale))
247 for (i = 0; len && *buf != 0 &&
248 isdigit_l((unsigned char)*buf, locale); buf++) {
253 if (c == 'H' || c == 'k') {
265 * XXX This is bogus if parsed before hour-related
268 len = strlen(tptr->am);
269 if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
270 if (tm->tm_hour > 12)
272 if (tm->tm_hour == 12)
278 len = strlen(tptr->pm);
279 if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
280 if (tm->tm_hour > 12)
282 if (tm->tm_hour != 12)
292 for (i = 0; i < asizeof(tptr->weekday); i++) {
293 len = strlen(tptr->weekday[i]);
294 if (strncasecmp_l(buf, tptr->weekday[i],
297 len = strlen(tptr->wday[i]);
298 if (strncasecmp_l(buf, tptr->wday[i],
302 if (i == asizeof(tptr->weekday))
312 * XXX This is bogus, as we can not assume any valid
313 * information present in the tm structure at this
314 * point to calculate a real value, so just check the
317 if (!isdigit_l((unsigned char)*buf, locale))
321 for (i = 0; len && *buf != 0 &&
322 isdigit_l((unsigned char)*buf, locale); buf++) {
333 if (!isdigit_l((unsigned char)*buf, locale))
346 * With %e format, our strftime(3) adds a blank space
347 * before single digits.
350 isspace_l((unsigned char)*buf, locale))
355 * The %e specifier was once explicitly documented as
356 * not being zero-padded but was later changed to
357 * equivalent to %d. There is no harm in allowing
360 * XXX The %e specifier may gobble one too many
361 * digits if used incorrectly.
363 if (!isdigit_l((unsigned char)*buf, locale))
367 for (i = 0; len && *buf != 0 &&
368 isdigit_l((unsigned char)*buf, locale); buf++) {
383 for (i = 0; i < asizeof(tptr->month); i++) {
386 len = strlen(tptr->alt_month[i]);
387 if (strncasecmp_l(buf,
393 len = strlen(tptr->month[i]);
394 if (strncasecmp_l(buf, tptr->month[i],
400 * Try the abbreviated month name if the full name
401 * wasn't found and Oalternative was not requested.
403 if (i == asizeof(tptr->month) && !Oalternative) {
404 for (i = 0; i < asizeof(tptr->month); i++) {
405 len = strlen(tptr->mon[i]);
406 if (strncasecmp_l(buf, tptr->mon[i],
411 if (i == asizeof(tptr->month))
419 if (!isdigit_l((unsigned char)*buf, locale))
423 for (i = 0; len && *buf != 0 &&
424 isdigit_l((unsigned char)*buf, locale); buf++) {
445 n = strtol_l(buf, &cp, 10, locale);
446 if (errno == ERANGE || (long)(t = n) != n) {
460 isspace_l((unsigned char)*buf, locale))
463 if (!isdigit_l((unsigned char)*buf, locale))
466 len = (c == 'Y') ? 4 : 2;
467 for (i = 0; len && *buf != 0 &&
468 isdigit_l((unsigned char)*buf, locale); buf++) {
475 if (c == 'y' && i < 69)
489 for (cp = buf; *cp &&
490 isupper_l((unsigned char)*cp, locale); ++cp) {
493 zonestr = alloca(cp - buf + 1);
494 strncpy(zonestr, buf, cp - buf);
495 zonestr[cp - buf] = '\0';
497 if (0 == strcmp(zonestr, "GMT")) {
499 } else if (0 == strcmp(zonestr, tzname[0])) {
501 } else if (0 == strcmp(zonestr, tzname[1])) {
524 for (len = 4; len > 0; len--) {
525 if (isdigit_l((unsigned char)*buf, locale)) {
533 tm->tm_hour -= sign * (i / 100);
534 tm->tm_min -= sign * (i % 100);
541 while (isspace_l((unsigned char)*buf, locale))
546 return ((char *)buf);
551 strptime_l(const char * __restrict buf, const char * __restrict fmt,
552 struct tm * __restrict tm, locale_t loc)
559 ret = _strptime(buf, fmt, tm, &gmt, loc);
561 time_t t = timegm(tm);
568 strptime(const char * __restrict buf, const char * __restrict fmt,
569 struct tm * __restrict tm)
571 return strptime_l(buf, fmt, tm, __get_locale());