OLD | NEW |
(Empty) | |
| 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> |
| 8 |
| 9 char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
ct tm) |
| 10 { |
| 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; |
| 22 } |
| 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 = ¢ury; |
| 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; |
| 92 } |
| 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; |
| 99 } |
| 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): |
| 163 ; |
| 164 } |
| 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; |
| 184 } |
| 185 if (i<0) return 0; |
| 186 goto update; |
| 187 update: |
| 188 //FIXME |
| 189 ; |
| 190 } |
| 191 } |
| 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; |
| 195 } |
| 196 return (char *)s; |
| 197 } |
OLD | NEW |