1*c9945492SAndroid Build Coastguard Worker #include <stdlib.h>
2*c9945492SAndroid Build Coastguard Worker #include <langinfo.h>
3*c9945492SAndroid Build Coastguard Worker #include <time.h>
4*c9945492SAndroid Build Coastguard Worker #include <ctype.h>
5*c9945492SAndroid Build Coastguard Worker #include <stddef.h>
6*c9945492SAndroid Build Coastguard Worker #include <string.h>
7*c9945492SAndroid Build Coastguard Worker #include <strings.h>
8*c9945492SAndroid Build Coastguard Worker
strptime(const char * restrict s,const char * restrict f,struct tm * restrict tm)9*c9945492SAndroid Build Coastguard Worker char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
10*c9945492SAndroid Build Coastguard Worker {
11*c9945492SAndroid Build Coastguard Worker int i, w, neg, adj, min, range, *dest, dummy;
12*c9945492SAndroid Build Coastguard Worker const char *ex;
13*c9945492SAndroid Build Coastguard Worker size_t len;
14*c9945492SAndroid Build Coastguard Worker int want_century = 0, century = 0, relyear = 0;
15*c9945492SAndroid Build Coastguard Worker while (*f) {
16*c9945492SAndroid Build Coastguard Worker if (*f != '%') {
17*c9945492SAndroid Build Coastguard Worker if (isspace(*f)) for (; *s && isspace(*s); s++);
18*c9945492SAndroid Build Coastguard Worker else if (*s != *f) return 0;
19*c9945492SAndroid Build Coastguard Worker else s++;
20*c9945492SAndroid Build Coastguard Worker f++;
21*c9945492SAndroid Build Coastguard Worker continue;
22*c9945492SAndroid Build Coastguard Worker }
23*c9945492SAndroid Build Coastguard Worker f++;
24*c9945492SAndroid Build Coastguard Worker if (*f == '+') f++;
25*c9945492SAndroid Build Coastguard Worker if (isdigit(*f)) {
26*c9945492SAndroid Build Coastguard Worker char *new_f;
27*c9945492SAndroid Build Coastguard Worker w=strtoul(f, &new_f, 10);
28*c9945492SAndroid Build Coastguard Worker f = new_f;
29*c9945492SAndroid Build Coastguard Worker } else {
30*c9945492SAndroid Build Coastguard Worker w=-1;
31*c9945492SAndroid Build Coastguard Worker }
32*c9945492SAndroid Build Coastguard Worker adj=0;
33*c9945492SAndroid Build Coastguard Worker switch (*f++) {
34*c9945492SAndroid Build Coastguard Worker case 'a': case 'A':
35*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_wday;
36*c9945492SAndroid Build Coastguard Worker min = ABDAY_1;
37*c9945492SAndroid Build Coastguard Worker range = 7;
38*c9945492SAndroid Build Coastguard Worker goto symbolic_range;
39*c9945492SAndroid Build Coastguard Worker case 'b': case 'B': case 'h':
40*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_mon;
41*c9945492SAndroid Build Coastguard Worker min = ABMON_1;
42*c9945492SAndroid Build Coastguard Worker range = 12;
43*c9945492SAndroid Build Coastguard Worker goto symbolic_range;
44*c9945492SAndroid Build Coastguard Worker case 'c':
45*c9945492SAndroid Build Coastguard Worker s = strptime(s, nl_langinfo(D_T_FMT), tm);
46*c9945492SAndroid Build Coastguard Worker if (!s) return 0;
47*c9945492SAndroid Build Coastguard Worker break;
48*c9945492SAndroid Build Coastguard Worker case 'C':
49*c9945492SAndroid Build Coastguard Worker dest = ¢ury;
50*c9945492SAndroid Build Coastguard Worker if (w<0) w=2;
51*c9945492SAndroid Build Coastguard Worker want_century |= 2;
52*c9945492SAndroid Build Coastguard Worker goto numeric_digits;
53*c9945492SAndroid Build Coastguard Worker case 'd': case 'e':
54*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_mday;
55*c9945492SAndroid Build Coastguard Worker min = 1;
56*c9945492SAndroid Build Coastguard Worker range = 31;
57*c9945492SAndroid Build Coastguard Worker goto numeric_range;
58*c9945492SAndroid Build Coastguard Worker case 'D':
59*c9945492SAndroid Build Coastguard Worker s = strptime(s, "%m/%d/%y", tm);
60*c9945492SAndroid Build Coastguard Worker if (!s) return 0;
61*c9945492SAndroid Build Coastguard Worker break;
62*c9945492SAndroid Build Coastguard Worker case 'F':
63*c9945492SAndroid Build Coastguard Worker /* Use temp buffer to implement the odd requirement
64*c9945492SAndroid Build Coastguard Worker * that entire field be width-limited but the year
65*c9945492SAndroid Build Coastguard Worker * subfield not itself be limited. */
66*c9945492SAndroid Build Coastguard Worker i = 0;
67*c9945492SAndroid Build Coastguard Worker char tmp[20];
68*c9945492SAndroid Build Coastguard Worker if (*s == '-' || *s == '+') tmp[i++] = *s++;
69*c9945492SAndroid Build Coastguard Worker while (*s=='0' && isdigit(s[1])) s++;
70*c9945492SAndroid Build Coastguard Worker for (; *s && i<(size_t)w && i+1<sizeof tmp; i++) {
71*c9945492SAndroid Build Coastguard Worker tmp[i] = *s++;
72*c9945492SAndroid Build Coastguard Worker }
73*c9945492SAndroid Build Coastguard Worker tmp[i] = 0;
74*c9945492SAndroid Build Coastguard Worker char *p = strptime(tmp, "%12Y-%m-%d", tm);
75*c9945492SAndroid Build Coastguard Worker if (!p) return 0;
76*c9945492SAndroid Build Coastguard Worker s -= tmp+i-p;
77*c9945492SAndroid Build Coastguard Worker break;
78*c9945492SAndroid Build Coastguard Worker case 'H':
79*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_hour;
80*c9945492SAndroid Build Coastguard Worker min = 0;
81*c9945492SAndroid Build Coastguard Worker range = 24;
82*c9945492SAndroid Build Coastguard Worker goto numeric_range;
83*c9945492SAndroid Build Coastguard Worker case 'I':
84*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_hour;
85*c9945492SAndroid Build Coastguard Worker min = 1;
86*c9945492SAndroid Build Coastguard Worker range = 12;
87*c9945492SAndroid Build Coastguard Worker goto numeric_range;
88*c9945492SAndroid Build Coastguard Worker case 'j':
89*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_yday;
90*c9945492SAndroid Build Coastguard Worker min = 1;
91*c9945492SAndroid Build Coastguard Worker range = 366;
92*c9945492SAndroid Build Coastguard Worker adj = 1;
93*c9945492SAndroid Build Coastguard Worker goto numeric_range;
94*c9945492SAndroid Build Coastguard Worker case 'm':
95*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_mon;
96*c9945492SAndroid Build Coastguard Worker min = 1;
97*c9945492SAndroid Build Coastguard Worker range = 12;
98*c9945492SAndroid Build Coastguard Worker adj = 1;
99*c9945492SAndroid Build Coastguard Worker goto numeric_range;
100*c9945492SAndroid Build Coastguard Worker case 'M':
101*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_min;
102*c9945492SAndroid Build Coastguard Worker min = 0;
103*c9945492SAndroid Build Coastguard Worker range = 60;
104*c9945492SAndroid Build Coastguard Worker goto numeric_range;
105*c9945492SAndroid Build Coastguard Worker case 'n': case 't':
106*c9945492SAndroid Build Coastguard Worker for (; *s && isspace(*s); s++);
107*c9945492SAndroid Build Coastguard Worker break;
108*c9945492SAndroid Build Coastguard Worker case 'p':
109*c9945492SAndroid Build Coastguard Worker ex = nl_langinfo(AM_STR);
110*c9945492SAndroid Build Coastguard Worker len = strlen(ex);
111*c9945492SAndroid Build Coastguard Worker if (!strncasecmp(s, ex, len)) {
112*c9945492SAndroid Build Coastguard Worker tm->tm_hour %= 12;
113*c9945492SAndroid Build Coastguard Worker s += len;
114*c9945492SAndroid Build Coastguard Worker break;
115*c9945492SAndroid Build Coastguard Worker }
116*c9945492SAndroid Build Coastguard Worker ex = nl_langinfo(PM_STR);
117*c9945492SAndroid Build Coastguard Worker len = strlen(ex);
118*c9945492SAndroid Build Coastguard Worker if (!strncasecmp(s, ex, len)) {
119*c9945492SAndroid Build Coastguard Worker tm->tm_hour %= 12;
120*c9945492SAndroid Build Coastguard Worker tm->tm_hour += 12;
121*c9945492SAndroid Build Coastguard Worker s += len;
122*c9945492SAndroid Build Coastguard Worker break;
123*c9945492SAndroid Build Coastguard Worker }
124*c9945492SAndroid Build Coastguard Worker return 0;
125*c9945492SAndroid Build Coastguard Worker case 'r':
126*c9945492SAndroid Build Coastguard Worker s = strptime(s, nl_langinfo(T_FMT_AMPM), tm);
127*c9945492SAndroid Build Coastguard Worker if (!s) return 0;
128*c9945492SAndroid Build Coastguard Worker break;
129*c9945492SAndroid Build Coastguard Worker case 'R':
130*c9945492SAndroid Build Coastguard Worker s = strptime(s, "%H:%M", tm);
131*c9945492SAndroid Build Coastguard Worker if (!s) return 0;
132*c9945492SAndroid Build Coastguard Worker break;
133*c9945492SAndroid Build Coastguard Worker case 's':
134*c9945492SAndroid Build Coastguard Worker /* Parse only. Effect on tm is unspecified
135*c9945492SAndroid Build Coastguard Worker * and presently no effect is implemented.. */
136*c9945492SAndroid Build Coastguard Worker if (*s == '-') s++;
137*c9945492SAndroid Build Coastguard Worker if (!isdigit(*s)) return 0;
138*c9945492SAndroid Build Coastguard Worker while (isdigit(*s)) s++;
139*c9945492SAndroid Build Coastguard Worker break;
140*c9945492SAndroid Build Coastguard Worker case 'S':
141*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_sec;
142*c9945492SAndroid Build Coastguard Worker min = 0;
143*c9945492SAndroid Build Coastguard Worker range = 61;
144*c9945492SAndroid Build Coastguard Worker goto numeric_range;
145*c9945492SAndroid Build Coastguard Worker case 'T':
146*c9945492SAndroid Build Coastguard Worker s = strptime(s, "%H:%M:%S", tm);
147*c9945492SAndroid Build Coastguard Worker if (!s) return 0;
148*c9945492SAndroid Build Coastguard Worker break;
149*c9945492SAndroid Build Coastguard Worker case 'U':
150*c9945492SAndroid Build Coastguard Worker case 'W':
151*c9945492SAndroid Build Coastguard Worker /* Throw away result of %U, %V, %W, %g, and %G. Effect
152*c9945492SAndroid Build Coastguard Worker * is unspecified and there is no clear right choice. */
153*c9945492SAndroid Build Coastguard Worker dest = &dummy;
154*c9945492SAndroid Build Coastguard Worker min = 0;
155*c9945492SAndroid Build Coastguard Worker range = 54;
156*c9945492SAndroid Build Coastguard Worker goto numeric_range;
157*c9945492SAndroid Build Coastguard Worker case 'V':
158*c9945492SAndroid Build Coastguard Worker dest = &dummy;
159*c9945492SAndroid Build Coastguard Worker min = 1;
160*c9945492SAndroid Build Coastguard Worker range = 53;
161*c9945492SAndroid Build Coastguard Worker goto numeric_range;
162*c9945492SAndroid Build Coastguard Worker case 'g':
163*c9945492SAndroid Build Coastguard Worker dest = &dummy;
164*c9945492SAndroid Build Coastguard Worker w = 2;
165*c9945492SAndroid Build Coastguard Worker goto numeric_digits;
166*c9945492SAndroid Build Coastguard Worker case 'G':
167*c9945492SAndroid Build Coastguard Worker dest = &dummy;
168*c9945492SAndroid Build Coastguard Worker if (w<0) w=4;
169*c9945492SAndroid Build Coastguard Worker goto numeric_digits;
170*c9945492SAndroid Build Coastguard Worker case 'u':
171*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_wday;
172*c9945492SAndroid Build Coastguard Worker min = 1;
173*c9945492SAndroid Build Coastguard Worker range = 7;
174*c9945492SAndroid Build Coastguard Worker goto numeric_range;
175*c9945492SAndroid Build Coastguard Worker case 'w':
176*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_wday;
177*c9945492SAndroid Build Coastguard Worker min = 0;
178*c9945492SAndroid Build Coastguard Worker range = 7;
179*c9945492SAndroid Build Coastguard Worker goto numeric_range;
180*c9945492SAndroid Build Coastguard Worker case 'x':
181*c9945492SAndroid Build Coastguard Worker s = strptime(s, nl_langinfo(D_FMT), tm);
182*c9945492SAndroid Build Coastguard Worker if (!s) return 0;
183*c9945492SAndroid Build Coastguard Worker break;
184*c9945492SAndroid Build Coastguard Worker case 'X':
185*c9945492SAndroid Build Coastguard Worker s = strptime(s, nl_langinfo(T_FMT), tm);
186*c9945492SAndroid Build Coastguard Worker if (!s) return 0;
187*c9945492SAndroid Build Coastguard Worker break;
188*c9945492SAndroid Build Coastguard Worker case 'y':
189*c9945492SAndroid Build Coastguard Worker dest = &relyear;
190*c9945492SAndroid Build Coastguard Worker w = 2;
191*c9945492SAndroid Build Coastguard Worker want_century |= 1;
192*c9945492SAndroid Build Coastguard Worker goto numeric_digits;
193*c9945492SAndroid Build Coastguard Worker case 'Y':
194*c9945492SAndroid Build Coastguard Worker dest = &tm->tm_year;
195*c9945492SAndroid Build Coastguard Worker if (w<0) w=4;
196*c9945492SAndroid Build Coastguard Worker adj = 1900;
197*c9945492SAndroid Build Coastguard Worker want_century = 0;
198*c9945492SAndroid Build Coastguard Worker goto numeric_digits;
199*c9945492SAndroid Build Coastguard Worker case 'z':
200*c9945492SAndroid Build Coastguard Worker if (*s == '+') neg = 0;
201*c9945492SAndroid Build Coastguard Worker else if (*s == '-') neg = 1;
202*c9945492SAndroid Build Coastguard Worker else return 0;
203*c9945492SAndroid Build Coastguard Worker for (i=0; i<4; i++) if (!isdigit(s[1+i])) return 0;
204*c9945492SAndroid Build Coastguard Worker tm->__tm_gmtoff = (s[1]-'0')*36000+(s[2]-'0')*3600
205*c9945492SAndroid Build Coastguard Worker + (s[3]-'0')*600 + (s[4]-'0')*60;
206*c9945492SAndroid Build Coastguard Worker if (neg) tm->__tm_gmtoff = -tm->__tm_gmtoff;
207*c9945492SAndroid Build Coastguard Worker s += 5;
208*c9945492SAndroid Build Coastguard Worker break;
209*c9945492SAndroid Build Coastguard Worker case 'Z':
210*c9945492SAndroid Build Coastguard Worker if (!strncmp(s, tzname[0], len = strlen(tzname[0]))) {
211*c9945492SAndroid Build Coastguard Worker tm->tm_isdst = 0;
212*c9945492SAndroid Build Coastguard Worker s += len;
213*c9945492SAndroid Build Coastguard Worker } else if (!strncmp(s, tzname[1], len=strlen(tzname[1]))) {
214*c9945492SAndroid Build Coastguard Worker tm->tm_isdst = 1;
215*c9945492SAndroid Build Coastguard Worker s += len;
216*c9945492SAndroid Build Coastguard Worker } else {
217*c9945492SAndroid Build Coastguard Worker /* FIXME: is this supposed to be an error? */
218*c9945492SAndroid Build Coastguard Worker while ((*s|32)-'a' <= 'z'-'a') s++;
219*c9945492SAndroid Build Coastguard Worker }
220*c9945492SAndroid Build Coastguard Worker break;
221*c9945492SAndroid Build Coastguard Worker case '%':
222*c9945492SAndroid Build Coastguard Worker if (*s++ != '%') return 0;
223*c9945492SAndroid Build Coastguard Worker break;
224*c9945492SAndroid Build Coastguard Worker default:
225*c9945492SAndroid Build Coastguard Worker return 0;
226*c9945492SAndroid Build Coastguard Worker numeric_range:
227*c9945492SAndroid Build Coastguard Worker if (!isdigit(*s)) return 0;
228*c9945492SAndroid Build Coastguard Worker *dest = 0;
229*c9945492SAndroid Build Coastguard Worker for (i=1; i<=min+range && isdigit(*s); i*=10)
230*c9945492SAndroid Build Coastguard Worker *dest = *dest * 10 + *s++ - '0';
231*c9945492SAndroid Build Coastguard Worker if (*dest - min >= (unsigned)range) return 0;
232*c9945492SAndroid Build Coastguard Worker *dest -= adj;
233*c9945492SAndroid Build Coastguard Worker switch((char *)dest - (char *)tm) {
234*c9945492SAndroid Build Coastguard Worker case offsetof(struct tm, tm_yday):
235*c9945492SAndroid Build Coastguard Worker ;
236*c9945492SAndroid Build Coastguard Worker }
237*c9945492SAndroid Build Coastguard Worker goto update;
238*c9945492SAndroid Build Coastguard Worker numeric_digits:
239*c9945492SAndroid Build Coastguard Worker neg = 0;
240*c9945492SAndroid Build Coastguard Worker if (*s == '+') s++;
241*c9945492SAndroid Build Coastguard Worker else if (*s == '-') neg=1, s++;
242*c9945492SAndroid Build Coastguard Worker if (!isdigit(*s)) return 0;
243*c9945492SAndroid Build Coastguard Worker for (*dest=i=0; i<w && isdigit(*s); i++)
244*c9945492SAndroid Build Coastguard Worker *dest = *dest * 10 + *s++ - '0';
245*c9945492SAndroid Build Coastguard Worker if (neg) *dest = -*dest;
246*c9945492SAndroid Build Coastguard Worker *dest -= adj;
247*c9945492SAndroid Build Coastguard Worker goto update;
248*c9945492SAndroid Build Coastguard Worker symbolic_range:
249*c9945492SAndroid Build Coastguard Worker for (i=2*range-1; i>=0; i--) {
250*c9945492SAndroid Build Coastguard Worker ex = nl_langinfo(min+i);
251*c9945492SAndroid Build Coastguard Worker len = strlen(ex);
252*c9945492SAndroid Build Coastguard Worker if (strncasecmp(s, ex, len)) continue;
253*c9945492SAndroid Build Coastguard Worker s += len;
254*c9945492SAndroid Build Coastguard Worker *dest = i % range;
255*c9945492SAndroid Build Coastguard Worker break;
256*c9945492SAndroid Build Coastguard Worker }
257*c9945492SAndroid Build Coastguard Worker if (i<0) return 0;
258*c9945492SAndroid Build Coastguard Worker goto update;
259*c9945492SAndroid Build Coastguard Worker update:
260*c9945492SAndroid Build Coastguard Worker //FIXME
261*c9945492SAndroid Build Coastguard Worker ;
262*c9945492SAndroid Build Coastguard Worker }
263*c9945492SAndroid Build Coastguard Worker }
264*c9945492SAndroid Build Coastguard Worker if (want_century) {
265*c9945492SAndroid Build Coastguard Worker tm->tm_year = relyear;
266*c9945492SAndroid Build Coastguard Worker if (want_century & 2) tm->tm_year += century * 100 - 1900;
267*c9945492SAndroid Build Coastguard Worker else if (tm->tm_year <= 68) tm->tm_year += 100;
268*c9945492SAndroid Build Coastguard Worker }
269*c9945492SAndroid Build Coastguard Worker return (char *)s;
270*c9945492SAndroid Build Coastguard Worker }
271