1 /*
2 * Copyright (c) 2014 Gary Mills
3 * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
4 * Copyright (c) 1994 Powerdog Industries. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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
16 * distribution.
17 *
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.
29 *
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.
33 */
34
35 #include "lint.h"
36 #include <time.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <pthread.h>
42 #include <alloca.h>
43 #include "timelocal.h"
44
45 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
46
47 #define F_GMT (1 << 0)
48 #define F_ZERO (1 << 1)
49 #define F_RECURSE (1 << 2)
50
51 static char *
52 __strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)
53 {
54 char c;
55 const char *ptr;
56 int i, len, recurse = 0;
57 int Ealternative, Oalternative;
58 struct lc_time_T *tptr = __get_current_time_locale();
59
60 if (*flagsp & F_RECURSE)
61 recurse = 1;
62 *flagsp |= F_RECURSE;
63
64 if (*flagsp & F_ZERO)
65 (void) memset(tm, 0, sizeof (*tm));
66 *flagsp &= ~F_ZERO;
67
68 ptr = fmt;
69 while (*ptr != 0) {
70 if (*buf == 0)
71 break;
72
73 c = *ptr++;
74
75 if (c != '%') {
76 if (isspace(c))
77 while (isspace(*buf))
78 buf++;
79 else if (c != *buf++)
80 return (NULL);
81 continue;
82 }
83
84 Ealternative = 0;
85 Oalternative = 0;
86 label:
87 c = *ptr++;
88 switch (c) {
89 case 0:
90 case '%':
91 if (*buf++ != '%')
92 return (NULL);
93 break;
94
95 case '+':
96 buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
97 if (buf == NULL)
98 return (NULL);
99 break;
100
101 case 'C':
102 if (!isdigit(*buf))
103 return (NULL);
104
105 /* XXX This will break for 3-digit centuries. */
106 len = 2;
107 for (i = 0; len && isdigit(*buf); buf++) {
108 i *= 10;
109 i += *buf - '0';
110 len--;
111 }
112 if (i < 19)
113 return (NULL);
114
115 tm->tm_year = i * 100 - 1900;
116 break;
117
118 case 'c':
119 buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
120 if (buf == NULL)
121 return (NULL);
122 break;
123
124 case 'D':
125 buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
126 if (buf == NULL)
127 return (NULL);
128 break;
129
130 case 'E':
131 if (Ealternative || Oalternative)
132 break;
133 Ealternative++;
134 goto label;
135
136 case 'O':
137 if (Ealternative || Oalternative)
138 break;
139 Oalternative++;
140 goto label;
141
142 case 'F':
143 buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
144 if (buf == NULL)
145 return (NULL);
146 break;
147
148 case 'R':
149 buf = __strptime(buf, "%H:%M", tm, flagsp);
150 if (buf == NULL)
151 return (NULL);
152 break;
153
154 case 'r':
155 buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
156 if (buf == NULL)
157 return (NULL);
158 break;
159
160 case 'T':
161 buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
162 if (buf == NULL)
163 return (NULL);
164 break;
165
166 case 'X':
167 buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
168 if (buf == NULL)
169 return (NULL);
170 break;
171
172 case 'x':
173 buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
174 if (buf == NULL)
175 return (NULL);
176 break;
177
178 case 'j':
179 if (!isdigit(*buf))
180 return (NULL);
181
182 len = 3;
183 for (i = 0; len && isdigit(*buf); buf++) {
184 i *= 10;
185 i += *buf - '0';
186 len--;
187 }
188 if (i < 1 || i > 366)
189 return (NULL);
190
191 tm->tm_yday = i - 1;
192 break;
193
502 break;
503 case 'n':
504 case 't':
505 while (isspace(*buf))
506 buf++;
507 break;
508 }
509 }
510
511 if (!recurse) {
512 if (buf && (*flagsp & F_GMT)) {
513 time_t t = timegm(tm);
514 (void) localtime_r(&t, tm);
515 }
516 }
517
518 return ((char *)buf);
519 }
520
521 char *
522 strptime(const char *buf, const char *fmt, struct tm *tm)
523 {
524 int flags = F_ZERO;
525
526 return (__strptime(buf, fmt, tm, &flags));
527 }
528
529 /*
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.
532 */
533 char *
534 __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
535 {
536 int flags = 0;
537
538 return (__strptime(buf, fmt, tm, &flags));
539 }
|
1 /*
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.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
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
17 * distribution.
18 *
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.
30 *
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.
34 */
35
36 #include "lint.h"
37 #include <time.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <pthread.h>
43 #include <alloca.h>
44 #include <locale.h>
45 #include "timelocal.h"
46 #include "localeimpl.h"
47
48 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
49
50 #define F_GMT (1 << 0)
51 #define F_RECURSE (1 << 2)
52
53 static char *
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)
57 {
58 char c;
59 const char *ptr;
60 int i, len, recurse = 0;
61 int Ealternative, Oalternative;
62 const struct lc_time *tptr = loc->time;
63
64 if (*flagsp & F_RECURSE)
65 recurse = 1;
66 *flagsp |= F_RECURSE;
67
68 ptr = fmt;
69 while (*ptr != 0) {
70 if (*buf == 0)
71 break;
72
73 c = *ptr++;
74
75 if (c != '%') {
76 if (isspace(c))
77 while (isspace(*buf))
78 buf++;
79 else if (c != *buf++)
80 return (NULL);
81 continue;
82 }
83
84 Ealternative = 0;
85 Oalternative = 0;
86 label:
87 c = *ptr++;
88 switch (c) {
89 case 0:
90 case '%':
91 if (*buf++ != '%')
92 return (NULL);
93 break;
94
95 case '+':
96 buf = __strptime(buf, tptr->date_fmt, tm, flagsp, loc);
97 if (buf == NULL)
98 return (NULL);
99 break;
100
101 case 'C':
102 if (!isdigit(*buf))
103 return (NULL);
104
105 /* XXX This will break for 3-digit centuries. */
106 len = 2;
107 for (i = 0; len && isdigit(*buf); buf++) {
108 i *= 10;
109 i += *buf - '0';
110 len--;
111 }
112 if (i < 19)
113 return (NULL);
114
115 tm->tm_year = i * 100 - 1900;
116 break;
117
118 case 'c':
119 buf = __strptime(buf, tptr->c_fmt, tm, flagsp, loc);
120 if (buf == NULL)
121 return (NULL);
122 break;
123
124 case 'D':
125 buf = __strptime(buf, "%m/%d/%y", tm, flagsp, loc);
126 if (buf == NULL)
127 return (NULL);
128 break;
129
130 case 'E':
131 if (Ealternative || Oalternative)
132 break;
133 Ealternative++;
134 goto label;
135
136 case 'O':
137 if (Ealternative || Oalternative)
138 break;
139 Oalternative++;
140 goto label;
141
142 case 'F':
143 buf = __strptime(buf, "%Y-%m-%d", tm, flagsp, loc);
144 if (buf == NULL)
145 return (NULL);
146 break;
147
148 case 'R':
149 buf = __strptime(buf, "%H:%M", tm, flagsp, loc);
150 if (buf == NULL)
151 return (NULL);
152 break;
153
154 case 'r':
155 buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp, loc);
156 if (buf == NULL)
157 return (NULL);
158 break;
159
160 case 'T':
161 buf = __strptime(buf, "%H:%M:%S", tm, flagsp, loc);
162 if (buf == NULL)
163 return (NULL);
164 break;
165
166 case 'X':
167 buf = __strptime(buf, tptr->X_fmt, tm, flagsp, loc);
168 if (buf == NULL)
169 return (NULL);
170 break;
171
172 case 'x':
173 buf = __strptime(buf, tptr->x_fmt, tm, flagsp, loc);
174 if (buf == NULL)
175 return (NULL);
176 break;
177
178 case 'j':
179 if (!isdigit(*buf))
180 return (NULL);
181
182 len = 3;
183 for (i = 0; len && isdigit(*buf); buf++) {
184 i *= 10;
185 i += *buf - '0';
186 len--;
187 }
188 if (i < 1 || i > 366)
189 return (NULL);
190
191 tm->tm_yday = i - 1;
192 break;
193
502 break;
503 case 'n':
504 case 't':
505 while (isspace(*buf))
506 buf++;
507 break;
508 }
509 }
510
511 if (!recurse) {
512 if (buf && (*flagsp & F_GMT)) {
513 time_t t = timegm(tm);
514 (void) localtime_r(&t, tm);
515 }
516 }
517
518 return ((char *)buf);
519 }
520
521 char *
522 strptime(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
523 struct tm *_RESTRICT_KYWD tm)
524 {
525 int flags = 0;
526
527 (void) memset(tm, 0, sizeof (*tm));
528
529 return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
530 }
531
532 /*
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.
535 */
536 char *
537 __strptime_dontzero(const char *_RESTRICT_KYWD buf,
538 const char *_RESTRICT_KYWD fmt, struct tm *_RESTRICT_KYWD tm)
539 {
540 int flags = 0;
541
542 return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
543 }
544
545 /*
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.
552 *
553 * We are not providing a non-zeroing version at this time.
554 */
555 char *
556 strptime_l(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
557 struct tm *_RESTRICT_KYWD tm, locale_t loc)
558 {
559 int flags = 0;
560
561 (void) memset(tm, 0, sizeof (*tm));
562
563 return (__strptime(buf, fmt, tm, &flags, loc));
564 }
|