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