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 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
18 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and documentation
31 * are those of the authors and should not be interpreted as representing
32 * official policies, either expressed or implied, of Powerdog Industries.
43 #include "timelocal.h"
45 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
47 #define F_GMT (1 << 0)
48 #define F_ZERO (1 << 1)
49 #define F_RECURSE (1 << 2)
52 __strptime(const char *buf
, const char *fmt
, struct tm
*tm
, int *flagsp
)
56 int i
, len
, recurse
= 0;
57 int Ealternative
, Oalternative
;
58 struct lc_time_T
*tptr
= __get_current_time_locale();
60 if (*flagsp
& F_RECURSE
)
65 (void) memset(tm
, 0, sizeof (*tm
));
96 buf
= __strptime(buf
, tptr
->date_fmt
, tm
, flagsp
);
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
);
125 buf
= __strptime(buf
, "%m/%d/%y", tm
, flagsp
);
131 if (Ealternative
|| Oalternative
)
137 if (Ealternative
|| Oalternative
)
143 buf
= __strptime(buf
, "%Y-%m-%d", tm
, flagsp
);
149 buf
= __strptime(buf
, "%H:%M", tm
, flagsp
);
155 buf
= __strptime(buf
, tptr
->ampm_fmt
, tm
, flagsp
);
161 buf
= __strptime(buf
, "%H:%M:%S", tm
, flagsp
);
167 buf
= __strptime(buf
, tptr
->X_fmt
, tm
, flagsp
);
173 buf
= __strptime(buf
, tptr
->x_fmt
, tm
, flagsp
);
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
== NULL
|| 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 *buf
, const char *fmt
, struct tm
*tm
)
526 return (__strptime(buf
, fmt
, tm
, &flags
));
530 * This is used by Solaris, and is a variant that does not clear the
531 * incoming tm. It is triggered by -D_STRPTIME_DONTZERO.
534 __strptime_dontzero(const char *buf
, const char *fmt
, struct tm
*tm
)
538 return (__strptime(buf
, fmt
, tm
, &flags
));