mips: add vdso support
[musl.git] / src / time / strptime.c
blobf41f55f24cf4bcf8a100178440a15e8efdfc14ad
1 #include <stdlib.h>
2 #include <langinfo.h>
3 #include <time.h>
4 #include <ctype.h>
5 #include <stddef.h>
6 #include <string.h>
7 #include <strings.h>
9 char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
11 int i, w, neg, adj, min, range, *dest, dummy;
12 const char *ex;
13 size_t len;
14 int want_century = 0, century = 0;
15 while (*f) {
16 if (*f != '%') {
17 if (isspace(*f)) for (; *s && isspace(*s); s++);
18 else if (*s != *f) return 0;
19 else s++;
20 f++;
21 continue;
23 f++;
24 if (*f == '+') f++;
25 if (isdigit(*f)) w=strtoul(f, (void *)&f, 10);
26 else w=-1;
27 adj=0;
28 switch (*f++) {
29 case 'a': case 'A':
30 dest = &tm->tm_wday;
31 min = ABDAY_1;
32 range = 7;
33 goto symbolic_range;
34 case 'b': case 'B': case 'h':
35 dest = &tm->tm_mon;
36 min = ABMON_1;
37 range = 12;
38 goto symbolic_range;
39 case 'c':
40 s = strptime(s, nl_langinfo(D_T_FMT), tm);
41 if (!s) return 0;
42 break;
43 case 'C':
44 dest = &century;
45 if (w<0) w=2;
46 want_century |= 2;
47 goto numeric_digits;
48 case 'd': case 'e':
49 dest = &tm->tm_mday;
50 min = 1;
51 range = 31;
52 goto numeric_range;
53 case 'D':
54 s = strptime(s, "%m/%d/%y", tm);
55 if (!s) return 0;
56 break;
57 case 'H':
58 dest = &tm->tm_hour;
59 min = 0;
60 range = 24;
61 goto numeric_range;
62 case 'I':
63 dest = &tm->tm_hour;
64 min = 1;
65 range = 12;
66 goto numeric_range;
67 case 'j':
68 dest = &tm->tm_yday;
69 min = 1;
70 range = 366;
71 goto numeric_range;
72 case 'm':
73 dest = &tm->tm_mon;
74 min = 1;
75 range = 12;
76 adj = 1;
77 goto numeric_range;
78 case 'M':
79 dest = &tm->tm_min;
80 min = 0;
81 range = 60;
82 goto numeric_range;
83 case 'n': case 't':
84 for (; *s && isspace(*s); s++);
85 break;
86 case 'p':
87 ex = nl_langinfo(AM_STR);
88 len = strlen(ex);
89 if (!strncasecmp(s, ex, len)) {
90 tm->tm_hour %= 12;
91 break;
93 ex = nl_langinfo(PM_STR);
94 len = strlen(ex);
95 if (!strncasecmp(s, ex, len)) {
96 tm->tm_hour %= 12;
97 tm->tm_hour += 12;
98 break;
100 return 0;
101 case 'r':
102 s = strptime(s, nl_langinfo(T_FMT_AMPM), tm);
103 if (!s) return 0;
104 break;
105 case 'R':
106 s = strptime(s, "%H:%M", tm);
107 if (!s) return 0;
108 break;
109 case 'S':
110 dest = &tm->tm_sec;
111 min = 0;
112 range = 61;
113 goto numeric_range;
114 case 'T':
115 s = strptime(s, "%H:%M:%S", tm);
116 if (!s) return 0;
117 break;
118 case 'U':
119 case 'W':
120 /* Throw away result, for now. (FIXME?) */
121 dest = &dummy;
122 min = 0;
123 range = 54;
124 goto numeric_range;
125 case 'w':
126 dest = &tm->tm_wday;
127 min = 0;
128 range = 7;
129 goto numeric_range;
130 case 'x':
131 s = strptime(s, nl_langinfo(D_FMT), tm);
132 if (!s) return 0;
133 break;
134 case 'X':
135 s = strptime(s, nl_langinfo(T_FMT), tm);
136 if (!s) return 0;
137 break;
138 case 'y':
139 dest = &tm->tm_year;
140 w = 2;
141 want_century |= 1;
142 goto numeric_digits;
143 case 'Y':
144 dest = &tm->tm_year;
145 if (w<0) w=4;
146 adj = 1900;
147 want_century = 0;
148 goto numeric_digits;
149 case '%':
150 if (*s++ != '%') return 0;
151 break;
152 default:
153 return 0;
154 numeric_range:
155 if (!isdigit(*s)) return 0;
156 *dest = 0;
157 for (i=1; i<=min+range && isdigit(*s); i*=10)
158 *dest = *dest * 10 + *s++ - '0';
159 if (*dest - min >= (unsigned)range) return 0;
160 *dest -= adj;
161 switch((char *)dest - (char *)tm) {
162 case offsetof(struct tm, tm_yday):
165 goto update;
166 numeric_digits:
167 neg = 0;
168 if (*s == '+') s++;
169 else if (*s == '-') neg=1, s++;
170 if (!isdigit(*s)) return 0;
171 for (*dest=i=0; i<w && isdigit(*s); i++)
172 *dest = *dest * 10 + *s++ - '0';
173 if (neg) *dest = -*dest;
174 *dest -= adj;
175 goto update;
176 symbolic_range:
177 for (i=2*range-1; i>=0; i--) {
178 ex = nl_langinfo(min+i);
179 len = strlen(ex);
180 if (strncasecmp(s, ex, len)) continue;
181 s += len;
182 *dest = i % range;
183 break;
185 if (i<0) return 0;
186 goto update;
187 update:
188 //FIXME
192 if (want_century) {
193 if (want_century & 2) tm->tm_year += century * 100 - 1900;
194 else if (tm->tm_year <= 68) tm->tm_year += 100;
196 return (char *)s;