2 * Copyright (c) 2014 Gary Mills
3 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
4 * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
5 * Copyright (c) 1994 Powerdog Industries. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
19 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * The views and conclusions contained in the software and documentation
32 * are those of the authors and should not be interpreted as representing
33 * official policies, either expressed or implied, of Powerdog Industries.
45 #include "timelocal.h"
46 #include "localeimpl.h"
48 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
50 #define F_GMT (1 << 0)
51 #define F_RECURSE (1 << 2)
54 __strptime(const char *_RESTRICT_KYWD buf
, const char *_RESTRICT_KYWD fmt
,
55 struct tm
*_RESTRICT_KYWD tm
, int *_RESTRICT_KYWD flagsp
,
56 locale_t _RESTRICT_KYWD loc
)
60 int i
, len
, recurse
= 0;
61 int Ealternative
, Oalternative
;
62 const struct lc_time
*tptr
= loc
->time
;
64 if (*flagsp
& F_RECURSE
)
96 buf
= __strptime(buf
, tptr
->date_fmt
, tm
, flagsp
, loc
);
105 /* XXX This will break for 3-digit centuries. */
107 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
115 tm
->tm_year
= i
* 100 - 1900;
119 buf
= __strptime(buf
, tptr
->c_fmt
, tm
, flagsp
, loc
);
125 buf
= __strptime(buf
, "%m/%d/%y", tm
, flagsp
, loc
);
131 if (Ealternative
|| Oalternative
)
137 if (Ealternative
|| Oalternative
)
143 buf
= __strptime(buf
, "%Y-%m-%d", tm
, flagsp
, loc
);
149 buf
= __strptime(buf
, "%H:%M", tm
, flagsp
, loc
);
155 buf
= __strptime(buf
, tptr
->ampm_fmt
, tm
, flagsp
, loc
);
161 buf
= __strptime(buf
, "%H:%M:%S", tm
, flagsp
, loc
);
167 buf
= __strptime(buf
, tptr
->X_fmt
, tm
, flagsp
, loc
);
173 buf
= __strptime(buf
, tptr
->x_fmt
, tm
, flagsp
, loc
);
183 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
188 if (i
< 1 || i
> 366)
196 if (*buf
== 0 || isspace(*buf
))
203 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
226 * Of these, %l is the only specifier explicitly
227 * documented as not being zero-padded. However,
228 * there is no harm in allowing zero-padding.
230 * XXX The %l specifier may gobble one too many
231 * digits if used incorrectly.
237 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
242 if (c
== 'H' || c
== 'k') {
254 * XXX This is bogus if parsed before hour-related
257 len
= strlen(tptr
->am
);
258 if (strncasecmp(buf
, tptr
->am
, len
) == 0) {
259 if (tm
->tm_hour
> 12)
261 if (tm
->tm_hour
== 12)
267 len
= strlen(tptr
->pm
);
268 if (strncasecmp(buf
, tptr
->pm
, len
) == 0) {
269 if (tm
->tm_hour
> 12)
271 if (tm
->tm_hour
!= 12)
281 for (i
= 0; i
< asizeof(tptr
->weekday
); i
++) {
282 len
= strlen(tptr
->weekday
[i
]);
283 if (strncasecmp(buf
, tptr
->weekday
[i
], len
) ==
286 len
= strlen(tptr
->wday
[i
]);
287 if (strncasecmp(buf
, tptr
->wday
[i
], len
) == 0)
290 if (i
== asizeof(tptr
->weekday
))
300 * XXX This is bogus, as we can not assume any valid
301 * information present in the tm structure at this
302 * point to calculate a real value, so just check the
309 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
334 * The %e format has a space before single digits
335 * which we need to skip.
340 * The %e specifier is explicitly documented as not
341 * being zero-padded but there is no harm in allowing
344 * XXX The %e specifier may gobble one too many
345 * digits if used incorrectly.
351 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
366 for (i
= 0; i
< asizeof(tptr
->month
); i
++) {
367 len
= strlen(tptr
->month
[i
]);
368 if (strncasecmp(buf
, tptr
->month
[i
], len
) == 0)
372 * Try the abbreviated month name if the full name
375 if (i
== asizeof(tptr
->month
)) {
376 for (i
= 0; i
< asizeof(tptr
->month
); i
++) {
377 len
= strlen(tptr
->mon
[i
]);
378 if (strncasecmp(buf
, tptr
->mon
[i
],
383 if (i
== asizeof(tptr
->month
))
395 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
415 t
= strtol(buf
, &cp
, 10);
416 if (errno
== ERANGE
) {
422 (void) gmtime_r(&t
, tm
);
429 if (*buf
== '\0' || isspace(*buf
))
435 len
= (c
== 'Y') ? 4 : 2;
436 for (i
= 0; len
&& isdigit(*buf
); buf
++) {
443 if (c
== 'y' && i
< 69)
454 const char *cp
= buf
;
460 zonestr
= alloca(cp
- buf
+ 1);
461 (void) strncpy(zonestr
, buf
, cp
- buf
);
462 zonestr
[cp
- buf
] = '\0';
464 if (strcmp(zonestr
, "GMT") == 0) {
466 } else if (0 == strcmp(zonestr
, tzname
[0])) {
468 } else if (0 == strcmp(zonestr
, tzname
[1])) {
490 for (len
= 4; len
> 0; len
--) {
498 tm
->tm_hour
-= sign
* (i
/ 100);
499 tm
->tm_min
-= sign
* (i
% 100);
505 while (isspace(*buf
))
512 if (buf
&& (*flagsp
& F_GMT
)) {
513 time_t t
= timegm(tm
);
514 (void) localtime_r(&t
, tm
);
518 return ((char *)buf
);
522 strptime(const char *_RESTRICT_KYWD buf
, const char *_RESTRICT_KYWD fmt
,
523 struct tm
*_RESTRICT_KYWD tm
)
527 (void) memset(tm
, 0, sizeof (*tm
));
529 return (__strptime(buf
, fmt
, tm
, &flags
, uselocale(NULL
)));
533 * This is used by Solaris, and is a variant that does not clear the
534 * incoming tm. It is triggered by -D_STRPTIME_DONTZERO.
537 __strptime_dontzero(const char *_RESTRICT_KYWD buf
,
538 const char *_RESTRICT_KYWD fmt
, struct tm
*_RESTRICT_KYWD tm
)
542 return (__strptime(buf
, fmt
, tm
, &flags
, uselocale(NULL
)));
546 * strptime_l is an extension that seems natural, and indeed, MacOS X
547 * includes it within their <xlocale.h> and it is part of GNU libc as well.
548 * For now we restrict it to the cases where strict namespaces are not
549 * included. We expect to see it in a future version of POSIX. locale_t is
550 * not a restrict, since the spec for it doesn't assume its a pointer. We
551 * therefore pass it analagously to the way strftime_l is specified.
553 * We are not providing a non-zeroing version at this time.
556 strptime_l(const char *_RESTRICT_KYWD buf
, const char *_RESTRICT_KYWD fmt
,
557 struct tm
*_RESTRICT_KYWD tm
, locale_t loc
)
561 (void) memset(tm
, 0, sizeof (*tm
));
563 return (__strptime(buf
, fmt
, tm
, &flags
, loc
));