00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 void get_locale_strings(void);
00028
00029
00030
00031
00032
00033
00034 #include <ctype.h>
00035 #include <limits.h>
00036 #include <string.h>
00037 #include <time.h>
00038
00039 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
00040
00041 #ifndef Macintosh
00042 #if defined __GNUC__ && __GNUC__ >= 2
00043 # define match_string(cs1, s2) \
00044 ({ size_t len = strlen (cs1); \
00045 int result = strncasecmp ((cs1), (s2), len) == 0; \
00046 if (result) (s2) += len; \
00047 result; })
00048 #else
00049
00050 # define match_string(cs1, s2) \
00051 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
00052 #endif
00053 #else
00054 # define match_string(cs1, s2) \
00055 (strncmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
00056 #endif
00057
00058
00059
00060 #define get_number(from, to, n) \
00061 do { \
00062 int __n = n; \
00063 val = 0; \
00064 while (*rp == ' ') \
00065 ++rp; \
00066 if (*rp < '0' || *rp > '9') \
00067 return NULL; \
00068 do { \
00069 val *= 10; \
00070 val += *rp++ - '0'; \
00071 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
00072 if (val < from || val > to) \
00073 return NULL; \
00074 } while (0)
00075 # define get_alt_number(from, to, n) \
00076 \
00077 get_number(from, to, n)
00078 #define recursive(new_fmt) \
00079 (*(new_fmt) != '\0' \
00080 && (rp = strptime_internal (rp, (new_fmt), tm, decided)) != NULL)
00081
00082
00083 static char weekday_name[][20] =
00084 {
00085 "Sunday", "Monday", "Tuesday", "Wednesday",
00086 "Thursday", "Friday", "Saturday"
00087 };
00088 static char ab_weekday_name[][10] =
00089 {
00090 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00091 };
00092 static char month_name[][20] =
00093 {
00094 "January", "February", "March", "April", "May", "June",
00095 "July", "August", "September", "October", "November", "December"
00096 };
00097 static char ab_month_name[][10] =
00098 {
00099 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00100 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00101 };
00102
00103 static char am_pm[][4] = {"AM", "PM"};
00104
00105
00106 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
00107 # define HERE_D_FMT "%y/%m/%d"
00108 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
00109 # define HERE_T_FMT "%H:%M:%S"
00110
00111 static const unsigned short int __mon_yday[2][13] =
00112 {
00113
00114 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
00115
00116 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
00117 };
00118
00119
00120
00121 enum locale_status { not, loc, raw };
00122
00123 # define __isleap(year) \
00124 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
00125
00126
00127 void
00128 day_of_the_week (struct tm *tm)
00129 {
00130
00131
00132
00133 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
00134 int wday = (-473
00135 + (365 * (tm->tm_year - 70))
00136 + (corr_year / 4)
00137 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
00138 + (((corr_year / 4) / 25) / 4)
00139 + __mon_yday[0][tm->tm_mon]
00140 + tm->tm_mday - 1);
00141 tm->tm_wday = ((wday % 7) + 7) % 7;
00142 }
00143
00144
00145 void
00146 day_of_the_year (struct tm *tm)
00147 {
00148 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
00149 + (tm->tm_mday - 1));
00150 }
00151
00152 char *
00153 strptime_internal (const char *rp, const char *fmt, struct tm *tm,
00154 enum locale_status *decided)
00155 {
00156 const char *rp_backup;
00157 int cnt;
00158 size_t val;
00159 int have_I, is_pm;
00160 int century, want_century;
00161 int have_wday, want_xday;
00162 int have_yday;
00163 int have_mon, have_mday;
00164
00165 have_I = is_pm = 0;
00166 century = -1;
00167 want_century = 0;
00168 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
00169
00170 while (*fmt != '\0')
00171 {
00172
00173
00174 if (isspace (*fmt))
00175 {
00176 while (isspace (*rp))
00177 ++rp;
00178 ++fmt;
00179 continue;
00180 }
00181
00182
00183
00184 if (*fmt != '%')
00185 {
00186 match_char (*fmt++, *rp++);
00187 continue;
00188 }
00189
00190 ++fmt;
00191
00192
00193 start_over:
00194
00195
00196 rp_backup = rp;
00197
00198 switch (*fmt++)
00199 {
00200 case '%':
00201
00202 match_char ('%', *rp++);
00203 break;
00204 case 'a':
00205 case 'A':
00206
00207 for (cnt = 0; cnt < 7; ++cnt)
00208 {
00209 if (*decided != loc
00210 && (match_string (weekday_name[cnt], rp)
00211 || match_string (ab_weekday_name[cnt], rp)))
00212 {
00213 *decided = raw;
00214 break;
00215 }
00216 }
00217 if (cnt == 7)
00218
00219 return NULL;
00220 tm->tm_wday = cnt;
00221 have_wday = 1;
00222 break;
00223 case 'b':
00224 case 'B':
00225 case 'h':
00226
00227 for (cnt = 0; cnt < 12; ++cnt)
00228 {
00229 if (match_string (month_name[cnt], rp)
00230 || match_string (ab_month_name[cnt], rp))
00231 {
00232 *decided = raw;
00233 break;
00234 }
00235 }
00236 if (cnt == 12)
00237
00238 return NULL;
00239 tm->tm_mon = cnt;
00240 want_xday = 1;
00241 break;
00242 case 'c':
00243
00244 if (!recursive (HERE_T_FMT_AMPM))
00245 return NULL;
00246 break;
00247 case 'C':
00248
00249 get_number (0, 99, 2);
00250 century = val;
00251 want_xday = 1;
00252 break;
00253 case 'd':
00254 case 'e':
00255
00256 get_number (1, 31, 2);
00257 tm->tm_mday = val;
00258 have_mday = 1;
00259 want_xday = 1;
00260 break;
00261 case 'F':
00262 if (!recursive ("%Y-%m-%d"))
00263 return NULL;
00264 want_xday = 1;
00265 break;
00266 case 'x':
00267
00268 case 'D':
00269
00270 if (!recursive (HERE_D_FMT))
00271 return NULL;
00272 want_xday = 1;
00273 break;
00274 case 'k':
00275 case 'H':
00276
00277 get_number (0, 23, 2);
00278 tm->tm_hour = val;
00279 have_I = 0;
00280 break;
00281 case 'I':
00282
00283 get_number (1, 12, 2);
00284 tm->tm_hour = val % 12;
00285 have_I = 1;
00286 break;
00287 case 'j':
00288
00289 get_number (1, 366, 3);
00290 tm->tm_yday = val - 1;
00291 have_yday = 1;
00292 break;
00293 case 'm':
00294
00295 get_number (1, 12, 2);
00296 tm->tm_mon = val - 1;
00297 have_mon = 1;
00298 want_xday = 1;
00299 break;
00300 case 'M':
00301
00302 get_number (0, 59, 2);
00303 tm->tm_min = val;
00304 break;
00305 case 'n':
00306 case 't':
00307
00308 while (isspace (*rp))
00309 ++rp;
00310 break;
00311 case 'p':
00312
00313 if (!match_string (am_pm[0], rp))
00314 if (match_string (am_pm[1], rp))
00315 is_pm = 1;
00316 else
00317 return NULL;
00318 break;
00319 case 'r':
00320 if (!recursive (HERE_T_FMT_AMPM))
00321 return NULL;
00322 break;
00323 case 'R':
00324 if (!recursive ("%H:%M"))
00325 return NULL;
00326 break;
00327 case 's':
00328 {
00329
00330
00331
00332
00333 time_t secs = 0;
00334 if (*rp < '0' || *rp > '9')
00335
00336 return NULL;
00337
00338 do
00339 {
00340 secs *= 10;
00341 secs += *rp++ - '0';
00342 }
00343 while (*rp >= '0' && *rp <= '9');
00344
00345 if ((tm = localtime (&secs)) == NULL)
00346
00347 return NULL;
00348 }
00349 break;
00350 case 'S':
00351 get_number (0, 61, 2);
00352 tm->tm_sec = val;
00353 break;
00354 case 'X':
00355
00356 case 'T':
00357 if (!recursive (HERE_T_FMT))
00358 return NULL;
00359 break;
00360 case 'u':
00361 get_number (1, 7, 1);
00362 tm->tm_wday = val % 7;
00363 have_wday = 1;
00364 break;
00365 case 'g':
00366 get_number (0, 99, 2);
00367
00368 break;
00369 case 'G':
00370 if (*rp < '0' || *rp > '9')
00371 return NULL;
00372
00373
00374 do
00375 ++rp;
00376 while (*rp >= '0' && *rp <= '9');
00377 break;
00378 case 'U':
00379 case 'V':
00380 case 'W':
00381 get_number (0, 53, 2);
00382
00383
00384 break;
00385 case 'w':
00386
00387 get_number (0, 6, 1);
00388 tm->tm_wday = val;
00389 have_wday = 1;
00390 break;
00391 case 'y':
00392
00393 get_number (0, 99, 2);
00394
00395
00396 tm->tm_year = val >= 69 ? val : val + 100;
00397
00398 want_century = 1;
00399 want_xday = 1;
00400 break;
00401 case 'Y':
00402
00403 get_number (0, 9999, 4);
00404 tm->tm_year = val - 1900;
00405 want_century = 0;
00406 want_xday = 1;
00407 break;
00408 case 'Z':
00409
00410 break;
00411 case 'E':
00412
00413
00414 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
00415 && *fmt != 'x' && *fmt != 'X')
00416
00417 return NULL;
00418
00419 goto start_over;
00420 case 'O':
00421 switch (*fmt++)
00422 {
00423 case 'd':
00424 case 'e':
00425
00426 get_alt_number (1, 31, 2);
00427 tm->tm_mday = val;
00428 have_mday = 1;
00429 want_xday = 1;
00430 break;
00431 case 'H':
00432
00433
00434 get_alt_number (0, 23, 2);
00435 tm->tm_hour = val;
00436 have_I = 0;
00437 break;
00438 case 'I':
00439
00440
00441 get_alt_number (1, 12, 2);
00442 tm->tm_hour = val - 1;
00443 have_I = 1;
00444 break;
00445 case 'm':
00446
00447 get_alt_number (1, 12, 2);
00448 tm->tm_mon = val - 1;
00449 have_mon = 1;
00450 want_xday = 1;
00451 break;
00452 case 'M':
00453
00454 get_alt_number (0, 59, 2);
00455 tm->tm_min = val;
00456 break;
00457 case 'S':
00458
00459 get_alt_number (0, 61, 2);
00460 tm->tm_sec = val;
00461 break;
00462 case 'U':
00463 case 'V':
00464 case 'W':
00465 get_alt_number (0, 53, 2);
00466
00467
00468 break;
00469 case 'w':
00470
00471 get_alt_number (0, 6, 1);
00472 tm->tm_wday = val;
00473 have_wday = 1;
00474 break;
00475 case 'y':
00476
00477 get_alt_number (0, 99, 2);
00478 tm->tm_year = val >= 69 ? val : val + 100;
00479 want_xday = 1;
00480 break;
00481 default:
00482 return NULL;
00483 }
00484 break;
00485 default:
00486 return NULL;
00487 }
00488 }
00489
00490 if (have_I && is_pm)
00491 tm->tm_hour += 12;
00492
00493 if (century != -1)
00494 {
00495 if (want_century)
00496 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
00497 else
00498
00499 tm->tm_year = (century - 19) * 100;
00500 }
00501
00502 if (want_xday && !have_wday) {
00503 if ( !(have_mon && have_mday) && have_yday) {
00504
00505 int t_mon = 0;
00506 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
00507 t_mon++;
00508 if (!have_mon)
00509 tm->tm_mon = t_mon - 1;
00510 if (!have_mday)
00511 tm->tm_mday = tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1;
00512 }
00513 day_of_the_week (tm);
00514 }
00515 if (want_xday && !have_yday)
00516 day_of_the_year (tm);
00517
00518 return (char *) rp;
00519 }
00520
00521 char *
00522 strptime (const char *buf, const char *format, struct tm *tm)
00523 {
00524 enum locale_status decided;
00525 #ifdef HAVE_LOCALE_H
00526 if(!have_used_strptime) {
00527 get_locale_strings();
00528
00529 }
00530 #endif
00531 decided = raw;
00532 return strptime_internal (buf, format, tm, &decided);
00533 }
00534
00535 #ifdef HAVE_LOCALE_H
00536 void get_locale_strings(void)
00537 {
00538 int i;
00539 struct tm tm;
00540 char buff[4];
00541
00542 tm.tm_sec = tm.tm_min = tm.tm_hour = tm.tm_mday = tm.tm_mon
00543 = tm.tm_isdst = 0;
00544 tm.tm_year = 30;
00545 for(i = 0; i < 12; i++) {
00546 tm.tm_mon = i;
00547 strftime(ab_month_name[i], 10, "%b", &tm);
00548 strftime(month_name[i], 20, "%B", &tm);
00549 }
00550 tm.tm_mon = 0;
00551 for(i = 0; i < 7; i++) {
00552 tm.tm_mday = tm.tm_yday = i+1;
00553 tm.tm_wday = i;
00554 strftime(ab_weekday_name[i], 10, "%a", &tm);
00555 strftime(weekday_name[i], 20, "%A", &tm);
00556 }
00557 tm.tm_hour = 1;
00558
00559
00560 strftime(buff, 4, "%p", &tm);
00561 if(strlen(buff)) strcpy(am_pm[0], buff);
00562 tm.tm_hour = 13;
00563 strftime(buff, 4, "%p", &tm);
00564 if(strlen(buff)) strcpy(am_pm[1], buff);
00565 }
00566 #endif