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