60 # define HAVE_LOCALE_H 1
68 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
71 #if defined __GNUC__ && __GNUC__ >= 2
72 # define match_string(cs1, s2) \
73 (__extension__ ({ size_t len = strlen (cs1); \
74 int result = strncasecmp ((cs1), (s2), len) == 0; \
75 if (result) (s2) += len; \
79 # define match_string(cs1, s2) \
80 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
85 #define get_number(from, to, n) \
91 if (*rp < '0' || *rp > '9') \
97 } while (--__n > 0 && *rp >= '0' && *rp <= '9'); \
98 if (int(val) < from || val > to) \
101 # define get_alt_number(from, to, n) \
103 get_number(from, to, n)
104 #define recursive(new_fmt) \
105 (*(new_fmt) != '\0' \
106 && (rp = strptime_internal (rp, (new_fmt), tm, decided, psecs, poffset)) != NULL)
111 static char weekday_name[][20] =
113 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
114 "Thursday",
"Friday",
"Saturday"
116 static char ab_weekday_name[][10] =
118 "Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
120 static char month_name[][20] =
122 "January",
"February",
"March",
"April",
"May",
"June",
123 "July",
"August",
"September",
"October",
"November",
"December"
125 static char ab_month_name[][10] =
127 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
128 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
131 static char am_pm[][4] = {
"AM",
"PM"};
134 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
135 # define HERE_D_FMT "%y/%m/%d"
136 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
137 # define HERE_T_FMT "%H:%M:%S"
139 static const unsigned short int __mon_yday[2][13] =
142 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
144 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
149 enum locale_status { Not, loc, raw };
151 # define __isleap(year) \
152 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
156 day_of_the_week (
struct tm *tm)
164 if(tm->tm_year == NA_INTEGER ||
165 tm->tm_mon == NA_INTEGER ||
166 tm->tm_mday == NA_INTEGER)
return;
168 corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
170 + (365 * (tm->tm_year - 70))
172 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
173 + (((corr_year / 4) / 25) / 4)
174 + __mon_yday[0][tm->tm_mon]
176 tm->tm_wday = ((wday % 7) + 7) % 7;
181 day_of_the_year (
struct tm *tm)
184 if(tm->tm_year == NA_INTEGER ||
185 tm->tm_mon == NA_INTEGER ||
186 tm->tm_mday == NA_INTEGER)
return;
188 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
189 + (tm->tm_mday - 1));
195 static wchar_t w_weekday_name[][20] =
197 L
"Sunday", L
"Monday", L
"Tuesday", L
"Wednesday",
198 L
"Thursday", L
"Friday", L
"Saturday"
200 static wchar_t w_ab_weekday_name[][10] =
202 L
"Sun", L
"Mon", L
"Tue", L
"Wed", L
"Thu", L
"Fri", L
"Sat"
204 static wchar_t w_month_name[][20] =
206 L
"January", L
"February", L
"March", L
"April", L
"May", L
"June",
207 L
"July", L
"August", L
"September", L
"October", L
"November", L
"December"
209 static wchar_t w_ab_month_name[][10] =
211 L
"Jan", L
"Feb", L
"Mar", L
"Apr", L
"May", L
"Jun",
212 L
"Jul", L
"Aug", L
"Sep", L
"Oct", L
"Nov", L
"Dec"
215 static wchar_t w_am_pm[][4] = {L
"AM", L
"PM"};
218 static int Rwcsncasecmp(
const wchar_t *cs1,
const wchar_t *s2)
220 size_t i, n = wcslen(cs1);
221 const wchar_t *a = cs1, *b = s2;
222 for(i = 0; i < n; i++, a++, b++) {
223 if(*b == L
'\0' || towlower(*a) != towlower(*b))
return 1;
228 #define w_match_string(cs1, s2) \
229 (Rwcsncasecmp ((cs1), (s2)) ? 0 : ((s2) += wcslen (cs1), 1))
231 #define w_recursive(new_fmt) \
232 (*(new_fmt) != '\0' \
233 && (rp = w_strptime_internal (rp, (new_fmt), tm, decided, psecs, poffset)) != NULL)
236 w_strptime_internal (
wchar_t *rp,
const wchar_t *fmt,
struct tm *tm,
237 enum locale_status *decided,
double *psecs,
243 int century, want_century;
244 int have_wday, want_xday;
246 int have_mon, have_mday;
247 int have_uweek, have_wweek;
253 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
254 have_uweek = have_wweek = 0;
256 while (*fmt != L
'\0')
262 while (iswspace (*rp))
272 match_char (*fmt++, *rp++);
285 match_char (L
'%', *rp++);
290 for (cnt = 0; cnt < 7; ++cnt)
293 && (w_match_string (w_weekday_name[cnt], rp)
294 || w_match_string (w_ab_weekday_name[cnt], rp)))
310 for (cnt = 0; cnt < 12; ++cnt)
312 if (w_match_string (w_month_name[cnt], rp)
313 || w_match_string (w_ab_month_name[cnt], rp))
327 if (!w_recursive (L
"%a %b %e %H:%M:%S %Y"))
332 get_number (0, 99, 2);
339 get_number (1, 31, 2);
345 if (!w_recursive (L
"%Y-%m-%d"))
353 if (!w_recursive (L
"%y/%m/%d"))
360 get_number (0, 24, 2);
368 get_number (1, 12, 2);
369 tm->tm_hour = val % 12;
374 get_number (1, 366, 3);
375 tm->tm_yday = val - 1;
380 get_number (1, 12, 2);
381 tm->tm_mon = val - 1;
387 get_number (0, 59, 2);
393 while (iswspace (*rp))
398 if (!w_match_string (w_am_pm[0], rp)) {
399 if (w_match_string (w_am_pm[1], rp))
406 if (!w_recursive (L
"%I:%M:%S %p"))
410 if (!w_recursive (L
"%H:%M"))
420 if (*rp < L'0' || *rp > L
'9')
427 secs += *rp++ - L
'0';
429 while (*rp >= L
'0' && *rp <= L
'9');
431 if ((tm = localtime (&secs)) == NULL)
437 get_number (0, 61, 2);
443 if (!w_recursive (L
"%H:%M:%S"))
447 get_number (1, 7, 1);
448 tm->tm_wday = val % 7;
452 get_number (0, 99, 2);
456 if (*rp < L'0' || *rp > L
'9')
462 while (*rp >= L
'0' && *rp <= L
'9');
465 get_number (0, 53, 2);
470 get_number (0, 53, 2);
475 get_number (0, 53, 2);
481 get_number (0, 6, 1);
487 get_number (0, 99, 2);
490 tm->tm_year = val >= 69 ? val : val + 100;
497 get_number (0, 9999, 4);
498 tm->tm_year = val - 1900;
504 int n = 0, neg, off = 0;
506 while (*rp == L
' ') ++rp;
507 if (*rp != L
'+' && *rp != L
'-')
return NULL;
509 while (n < 4 && *rp >= L
'0' && *rp <= L
'9') {
510 val = val * 10 + *rp++ - L
'0';
513 if (n != 4)
return NULL;
516 if (val % 100 >= 60)
return NULL;
517 val = (val / 100) * 100 + ((val % 100) * 50) / 30;
519 if (val > 1200)
return NULL;
520 off = (val * 3600) / 100;
526 error(_(
"use of %s for input is not supported"),
"%Z");
532 if (*fmt != L
'c' && *fmt != L
'C' && *fmt != L
'y' && *fmt != L
'Y'
533 && *fmt != L
'x' && *fmt != L
'X')
544 get_alt_number (1, 31, 2);
552 get_alt_number (0, 23, 2);
559 get_alt_number (1, 12, 2);
560 tm->tm_hour = val % 12;
565 get_alt_number (1, 12, 2);
566 tm->tm_mon = val - 1;
572 get_alt_number (0, 59, 2);
581 sval = wcstod(rp, &end);
582 if( sval >= 0.0 && sval <= 61.0) {
583 tm->tm_sec = int(sval);
590 get_alt_number (0, 53, 2);
595 get_alt_number (0, 53, 2);
600 get_alt_number (0, 53, 2);
606 get_alt_number (0, 6, 1);
612 get_alt_number (0, 99, 2);
613 tm->tm_year = val >= 69 ? val : val + 100;
631 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
634 tm->tm_year = (century - 19) * 100;
637 if (want_xday && !have_wday) {
638 if ( !(have_mon && have_mday) && have_yday) {
641 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
644 tm->tm_mon = t_mon - 1;
646 tm->tm_mday = (tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
648 day_of_the_week (tm);
651 if (want_xday && !have_yday)
652 day_of_the_year (tm);
654 if ((have_uweek || have_wweek) && have_wday) {
655 int save_wday = tm->tm_wday;
656 int save_mday = tm->tm_mday;
657 int save_mon = tm->tm_mon;
658 int w_offset = have_uweek ? 0 : 1;
662 day_of_the_week (tm);
664 tm->tm_mday = save_mday;
666 tm->tm_mon = save_mon;
669 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
671 + save_wday - w_offset);
673 if (!have_mday || !have_mon)
676 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
680 tm->tm_mon = t_mon - 1;
684 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
687 tm->tm_wday = save_wday;
695 strptime_internal (
const char *rp,
const char *fmt,
struct tm *tm,
696 enum locale_status *decided,
double *psecs,
702 int century, want_century;
703 int have_wday, want_xday;
705 int have_mon, have_mday;
706 int have_uweek, have_wweek;
712 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
713 have_uweek = have_wweek = 0;
719 if (isspace ((
int)*fmt))
721 while (isspace ((
int)*rp))
731 match_char (*fmt++, *rp++);
744 match_char (
'%', *rp++);
749 for (cnt = 0; cnt < 7; ++cnt)
752 && (match_string (weekday_name[cnt], rp)
753 || match_string (ab_weekday_name[cnt], rp)))
769 for (cnt = 0; cnt < 12; ++cnt)
771 if (match_string (month_name[cnt], rp)
772 || match_string (ab_month_name[cnt], rp))
786 if (!recursive (HERE_D_T_FMT))
791 get_number (0, 99, 2);
798 get_number (1, 31, 2);
804 if (!recursive (
"%Y-%m-%d"))
812 if (!recursive (HERE_D_FMT))
819 get_number (0, 24, 2);
827 get_number (1, 12, 2);
828 tm->tm_hour = val % 12;
833 get_number (1, 366, 3);
834 tm->tm_yday = val - 1;
839 get_number (1, 12, 2);
840 tm->tm_mon = val - 1;
846 get_number (0, 59, 2);
852 while (isspace ((
int)*rp))
857 if (!match_string (am_pm[0], rp)) {
858 if (match_string (am_pm[1], rp))
865 if (!recursive (HERE_T_FMT_AMPM))
869 if (!recursive (
"%H:%M"))
879 if (*rp < '0' || *rp >
'9')
888 while (*rp >=
'0' && *rp <=
'9');
890 if ((tm = localtime (&secs)) == NULL)
896 get_number (0, 61, 2);
902 if (!recursive (HERE_T_FMT))
906 get_number (1, 7, 1);
907 tm->tm_wday = val % 7;
911 get_number (0, 99, 2);
915 if (*rp < '0' || *rp >
'9')
921 while (*rp >=
'0' && *rp <=
'9');
924 get_number (0, 53, 2);
929 get_number (0, 53, 2);
934 get_number (0, 53, 2);
940 get_number (0, 6, 1);
946 get_number (0, 99, 2);
952 tm->tm_year = val >= 69 ? val : val + 100;
959 get_number (0, 9999, 4);
960 tm->tm_year = val - 1900;
967 int n = 0, neg, off = 0;
969 while (*rp ==
' ') ++rp;
970 if (*rp !=
'+' && *rp !=
'-')
return NULL;
972 while (n < 4 && *rp >=
'0' && *rp <=
'9') {
973 val = val * 10 + *rp++ -
'0';
976 if (n != 4)
return NULL;
979 if (val % 100 >= 60)
return NULL;
980 val = (val / 100) * 100 + ((val % 100) * 50) / 30;
982 if (val > 1200)
return NULL;
983 off = (val * 3600) / 100;
989 error(_(
"use of %s for input is not supported"),
"%Z");
995 if (*fmt !=
'c' && *fmt !=
'C' && *fmt !=
'y' && *fmt !=
'Y'
996 && *fmt !=
'x' && *fmt !=
'X')
1007 get_alt_number (1, 31, 2);
1015 get_alt_number (0, 23, 2);
1022 get_alt_number (1, 12, 2);
1023 tm->tm_hour = val % 12;
1028 get_alt_number (1, 12, 2);
1029 tm->tm_mon = val - 1;
1035 get_alt_number (0, 59, 2);
1044 sval = strtod(rp, &end);
1045 if( sval >= 0.0 && sval <= 61.0) {
1046 tm->tm_sec = int(sval);
1053 get_alt_number (0, 53, 2);
1058 get_alt_number (0, 53, 2);
1063 get_alt_number (0, 53, 2);
1069 get_alt_number (0, 6, 1);
1075 get_alt_number (0, 99, 2);
1076 tm->tm_year = val >= 69 ? val : val + 100;
1088 if (have_I && is_pm)
1094 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
1097 tm->tm_year = (century - 19) * 100;
1100 if (want_xday && !have_wday) {
1101 if ( !(have_mon && have_mday) && have_yday) {
1104 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
1107 tm->tm_mon = t_mon - 1;
1109 tm->tm_mday = (tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1111 day_of_the_week (tm);
1114 if (want_xday && !have_yday)
1115 day_of_the_year (tm);
1117 if ((have_uweek || have_wweek) && have_wday) {
1118 int save_wday = tm->tm_wday;
1119 int save_mday = tm->tm_mday;
1120 int save_mon = tm->tm_mon;
1121 int w_offset = have_uweek ? 0 : 1;
1125 day_of_the_week (tm);
1127 tm->tm_mday = save_mday;
1129 tm->tm_mon = save_mon;
1132 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
1134 + save_wday - w_offset);
1136 if (!have_mday || !have_mon)
1139 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
1143 tm->tm_mon = t_mon - 1;
1147 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1150 tm->tm_wday = save_wday;
1157 #ifdef HAVE_LOCALE_H
1158 # include <locale.h>
1163 static void get_locale_strings(
void)
1169 tm.tm_sec = tm.tm_min = tm.tm_hour = tm.tm_mday = tm.tm_mon
1172 for(i = 0; i < 12; i++) {
1174 strftime(ab_month_name[i], 10,
"%b", &tm);
1175 strftime(month_name[i], 20,
"%B", &tm);
1178 for(i = 0; i < 7; i++) {
1179 tm.tm_mday = tm.tm_yday = i+1;
1181 strftime(ab_weekday_name[i], 10,
"%a", &tm);
1182 strftime(weekday_name[i], 20,
"%A", &tm);
1187 strftime(buff, 4,
"%p", &tm);
1188 if(strlen(buff)) strcpy(am_pm[0], buff);
1190 strftime(buff, 4,
"%p", &tm);
1191 if(strlen(buff)) strcpy(am_pm[1], buff);
1194 #if defined(HAVE_WCSTOD) && defined(HAVE_WCSFTIME)
1195 static void get_locale_w_strings(
void)
1201 tm.tm_sec = tm.tm_min = tm.tm_hour = tm.tm_mday = tm.tm_mon
1204 for(i = 0; i < 12; i++) {
1206 wcsftime(w_ab_month_name[i], 10, L
"%b", &tm);
1207 wcsftime(w_month_name[i], 20, L
"%B", &tm);
1210 for(i = 0; i < 7; i++) {
1211 tm.tm_mday = tm.tm_yday = i+1;
1213 wcsftime(w_ab_weekday_name[i], 10, L
"%a", &tm);
1214 wcsftime(w_weekday_name[i], 20, L
"%A", &tm);
1219 wcsftime(buff, 4, L
"%p", &tm);
1220 if(wcslen(buff)) wcscpy(w_am_pm[0], buff);
1222 wcsftime(buff, 4, L
"%p", &tm);
1223 if(wcslen(buff)) wcscpy(w_am_pm[1], buff);
1231 R_strptime (
const char *buf,
const char *format,
struct tm *tm,
1232 double *psecs,
int *poffset)
1234 enum locale_status decided;
1236 #if defined(HAVE_WCSTOD)
1238 wchar_t wbuf[1001], wfmt[1001];
size_t n;
1239 #if defined(HAVE_LOCALE_H) && defined(HAVE_WCSFTIME)
1240 get_locale_w_strings();
1242 n = mbstowcs(NULL, buf, 1000);
1243 if(n > 1000) error(_(
"input string is too long"));
1244 n = mbstowcs(wbuf, buf, 1000);
1245 if(
CXXRCONSTRUCT(
int, n) == -1) error(_(
"invalid multibyte input string"));
1247 n = mbstowcs(NULL, format, 1000);
1248 if(n > 1000) error(_(
"format string is too long"));
1249 n = mbstowcs(wfmt, format, 1000);
1250 if(
CXXRCONSTRUCT(
int, n) == -1) error(_(
"invalid multibyte format string"));
1251 return (
char *) w_strptime_internal (wbuf, wfmt, tm, &decided, psecs, poffset);
1255 #ifdef HAVE_LOCALE_H
1256 get_locale_strings();
1258 return strptime_internal (buf, format, tm, &decided, psecs, poffset);