| 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 |