1 /* Copyright (C) 2002-2013 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
31 # include "../locale/localeinfo.h"
35 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
37 # define localtime_r __localtime_r
39 /* Approximate localtime_r as best we can in its absence. */
40 # define localtime_r my_localtime_r
41 static struct tm
*localtime_r (const time_t *, struct tm
*);
47 struct tm
*l
= localtime (t
);
54 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
57 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
58 #if defined __GNUC__ && __GNUC__ >= 2
59 # define match_string(cs1, s2) \
60 ({ size_t len = strlen (cs1); \
61 int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0; \
62 if (result) (s2) += len; \
65 /* Oh come on. Get a reasonable compiler. */
66 # define match_string(cs1, s2) \
67 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
69 /* We intentionally do not use isdigit() for testing because this will
70 lead to problems with the wide character version. */
71 #define get_number(from, to, n) \
75 while (ISSPACE (*rp)) \
77 if (*rp < '0' || *rp > '9') \
82 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
83 if (val < from || val > to) \
87 # define get_alt_number(from, to, n) \
89 __label__ do_normal; \
91 if (s.decided != raw) \
93 val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG); \
94 if (val == -1 && s.decided != loc) \
99 if (val < from || val > to) \
105 get_number (from, to, n); \
110 # define get_alt_number(from, to, n) \
111 /* We don't have the alternate representation. */ \
112 get_number(from, to, n)
114 #define recursive(new_fmt) \
115 (*(new_fmt) != '\0' \
116 && (rp = __strptime_internal (rp, (new_fmt), tm, &s LOCALE_ARG)) != NULL)
120 /* This is defined in locale/C-time.c in the GNU libc. */
121 extern const struct __locale_data _nl_C_LC_TIME attribute_hidden
;
123 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
124 # define ab_weekday_name \
125 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
126 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
127 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
128 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
129 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
130 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
131 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
132 # define HERE_T_FMT_AMPM \
133 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
134 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
136 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
138 static char const weekday_name
[][10] =
140 "Sunday", "Monday", "Tuesday", "Wednesday",
141 "Thursday", "Friday", "Saturday"
143 static char const ab_weekday_name
[][4] =
145 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
147 static char const month_name
[][10] =
149 "January", "February", "March", "April", "May", "June",
150 "July", "August", "September", "October", "November", "December"
152 static char const ab_month_name
[][4] =
154 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
155 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
157 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
158 # define HERE_D_FMT "%m/%d/%y"
159 # define HERE_AM_STR "AM"
160 # define HERE_PM_STR "PM"
161 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
162 # define HERE_T_FMT "%H:%M:%S"
164 static const unsigned short int __mon_yday
[2][13] =
167 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
169 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
174 /* We use this code also for the extended locale handling where the
175 function gets as an additional argument the locale which has to be
176 used. To access the values we have to redefine the _NL_CURRENT
178 # define strptime __strptime_l
180 # define _NL_CURRENT(category, item) \
181 (current->values[_NL_ITEM_INDEX (item)].string)
182 # undef _NL_CURRENT_WORD
183 # define _NL_CURRENT_WORD(category, item) \
184 (current->values[_NL_ITEM_INDEX (item)].word)
185 # define LOCALE_PARAM , locale
186 # define LOCALE_ARG , locale
187 # define LOCALE_PARAM_PROTO , __locale_t locale
188 # define LOCALE_PARAM_DECL __locale_t locale;
189 # define HELPER_LOCALE_ARG , current
190 # define ISSPACE(Ch) __isspace_l (Ch, locale)
192 # define LOCALE_PARAM
194 # define LOCALE_PARAM_DECL
195 # define LOCALE_PARAM_PROTO
196 # define HELPER_LOCALE_ARG
197 # define ISSPACE(Ch) isspace (Ch)
204 /* Nonzero if YEAR is a leap year (every 4 years,
205 except every 100th isn't, and every 400th is). */
206 # define __isleap(year) \
207 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
210 /* Compute the day of the week. */
212 day_of_the_week (struct tm
*tm
)
214 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
215 difference between this data in the one on TM and so determine
217 int corr_year
= 1900 + tm
->tm_year
- (tm
->tm_mon
< 2);
219 + (365 * (tm
->tm_year
- 70))
221 - ((corr_year
/ 4) / 25) + ((corr_year
/ 4) % 25 < 0)
222 + (((corr_year
/ 4) / 25) / 4)
223 + __mon_yday
[0][tm
->tm_mon
]
225 tm
->tm_wday
= ((wday
% 7) + 7) % 7;
228 /* Compute the day of the year. */
230 day_of_the_year (struct tm
*tm
)
232 tm
->tm_yday
= (__mon_yday
[__isleap (1900 + tm
->tm_year
)][tm
->tm_mon
]
233 + (tm
->tm_mday
- 1));
243 __strptime_internal (rp
, fmt
, tmp
, statep LOCALE_PARAM
)
251 struct __locale_data
*const current
= locale
->__locales
[LC_TIME
];
254 const char *rp_backup
;
255 const char *rp_longest
;
260 struct era_entry
*era
= NULL
;
261 enum ptime_locale_status
{ not, loc
, raw
} decided_longest
;
262 struct __strptime_state
264 unsigned int have_I
: 1;
265 unsigned int have_wday
: 1;
266 unsigned int have_yday
: 1;
267 unsigned int have_mon
: 1;
268 unsigned int have_mday
: 1;
269 unsigned int have_uweek
: 1;
270 unsigned int have_wweek
: 1;
271 unsigned int is_pm
: 1;
272 unsigned int want_century
: 1;
273 unsigned int want_era
: 1;
274 unsigned int want_xday
: 1;
275 enum ptime_locale_status decided
: 2;
285 memset (&s
, 0, sizeof (s
));
297 s
= *(struct __strptime_state
*) statep
;
304 /* A white space in the format string matches 0 more or white
305 space in the input string. */
308 while (ISSPACE (*rp
))
314 /* Any character but `%' must be matched by the same character
315 in the iput string. */
318 match_char (*fmt
++, *rp
++);
325 /* In recursive calls silently discard strftime modifiers. */
326 while (*fmt
== '-' || *fmt
== '_' || *fmt
== '0'
327 || *fmt
== '^' || *fmt
== '#')
330 /* And field width. */
331 while (*fmt
>= '0' && *fmt
<= '9')
336 /* We need this for handling the `E' modifier. */
340 /* Make back up of current processing pointer. */
346 /* Match the `%' character itself. */
347 match_char ('%', *rp
++);
351 /* Match day of week. */
353 decided_longest
= s
.decided
;
355 for (cnt
= 0; cnt
< 7; ++cnt
)
362 if (match_string (_NL_CURRENT (LC_TIME
, DAY_1
+ cnt
), trp
)
368 && strcmp (_NL_CURRENT (LC_TIME
, DAY_1
+ cnt
),
370 decided_longest
= loc
;
373 if (match_string (_NL_CURRENT (LC_TIME
, ABDAY_1
+ cnt
), trp
)
379 && strcmp (_NL_CURRENT (LC_TIME
, ABDAY_1
+ cnt
),
380 ab_weekday_name
[cnt
]))
381 decided_longest
= loc
;
386 && (((trp
= rp
, match_string (weekday_name
[cnt
], trp
))
388 || ((trp
= rp
, match_string (ab_weekday_name
[cnt
], rp
))
389 && trp
> rp_longest
)))
393 decided_longest
= raw
;
396 if (rp_longest
== NULL
)
397 /* Does not match a weekday name. */
400 s
.decided
= decided_longest
;
401 tm
->tm_wday
= cnt_longest
;
407 /* Match month name. */
409 decided_longest
= s
.decided
;
411 for (cnt
= 0; cnt
< 12; ++cnt
)
418 if (match_string (_NL_CURRENT (LC_TIME
, MON_1
+ cnt
), trp
)
424 && strcmp (_NL_CURRENT (LC_TIME
, MON_1
+ cnt
),
426 decided_longest
= loc
;
429 if (match_string (_NL_CURRENT (LC_TIME
, ABMON_1
+ cnt
), trp
)
435 && strcmp (_NL_CURRENT (LC_TIME
, ABMON_1
+ cnt
),
437 decided_longest
= loc
;
442 && (((trp
= rp
, match_string (month_name
[cnt
], trp
))
444 || ((trp
= rp
, match_string (ab_month_name
[cnt
], trp
))
445 && trp
> rp_longest
)))
449 decided_longest
= raw
;
452 if (rp_longest
== NULL
)
453 /* Does not match a month name. */
456 s
.decided
= decided_longest
;
457 tm
->tm_mon
= cnt_longest
;
462 /* Match locale's date and time format. */
464 if (s
.decided
!= raw
)
466 if (!recursive (_NL_CURRENT (LC_TIME
, D_T_FMT
)))
468 if (s
.decided
== loc
)
475 if (s
.decided
== not &&
476 strcmp (_NL_CURRENT (LC_TIME
, D_T_FMT
), HERE_D_T_FMT
))
484 if (!recursive (HERE_D_T_FMT
))
489 /* Match century number. */
491 get_number (0, 99, 2);
497 /* Match day of month. */
498 get_number (1, 31, 2);
504 if (!recursive ("%Y-%m-%d"))
510 if (s
.decided
!= raw
)
512 if (!recursive (_NL_CURRENT (LC_TIME
, D_FMT
)))
514 if (s
.decided
== loc
)
522 && strcmp (_NL_CURRENT (LC_TIME
, D_FMT
), HERE_D_FMT
))
532 /* Match standard day format. */
533 if (!recursive (HERE_D_FMT
))
539 /* Match hour in 24-hour clock. */
540 get_number (0, 23, 2);
545 /* Match hour in 12-hour clock. GNU extension. */
547 /* Match hour in 12-hour clock. */
548 get_number (1, 12, 2);
549 tm
->tm_hour
= val
% 12;
553 /* Match day number of year. */
554 get_number (1, 366, 3);
555 tm
->tm_yday
= val
- 1;
559 /* Match number of month. */
560 get_number (1, 12, 2);
561 tm
->tm_mon
= val
- 1;
567 get_number (0, 59, 2);
572 /* Match any white space. */
573 while (ISSPACE (*rp
))
577 /* Match locale's equivalent of AM/PM. */
579 if (s
.decided
!= raw
)
581 if (match_string (_NL_CURRENT (LC_TIME
, AM_STR
), rp
))
583 if (strcmp (_NL_CURRENT (LC_TIME
, AM_STR
), HERE_AM_STR
))
588 if (match_string (_NL_CURRENT (LC_TIME
, PM_STR
), rp
))
590 if (strcmp (_NL_CURRENT (LC_TIME
, PM_STR
), HERE_PM_STR
))
598 if (!match_string (HERE_AM_STR
, rp
))
600 if (match_string (HERE_PM_STR
, rp
))
610 if (s
.decided
!= raw
)
612 if (!recursive (_NL_CURRENT (LC_TIME
, T_FMT_AMPM
)))
614 if (s
.decided
== loc
)
621 if (s
.decided
== not &&
622 strcmp (_NL_CURRENT (LC_TIME
, T_FMT_AMPM
),
630 if (!recursive (HERE_T_FMT_AMPM
))
634 if (!recursive ("%H:%M"))
639 /* The number of seconds may be very high so we cannot use
640 the `get_number' macro. Instead read the number
641 character for character and construct the result while
644 if (*rp
< '0' || *rp
> '9')
645 /* We need at least one digit. */
653 while (*rp
>= '0' && *rp
<= '9');
655 if (localtime_r (&secs
, tm
) == NULL
)
656 /* Error in function. */
661 get_number (0, 61, 2);
666 if (s
.decided
!= raw
)
668 if (!recursive (_NL_CURRENT (LC_TIME
, T_FMT
)))
670 if (s
.decided
== loc
)
677 if (strcmp (_NL_CURRENT (LC_TIME
, T_FMT
), HERE_T_FMT
))
686 if (!recursive (HERE_T_FMT
))
690 get_number (1, 7, 1);
691 tm
->tm_wday
= val
% 7;
695 get_number (0, 99, 2);
696 /* XXX This cannot determine any field in TM. */
699 if (*rp
< '0' || *rp
> '9')
701 /* XXX Ignore the number since we would need some more
702 information to compute a real date. */
705 while (*rp
>= '0' && *rp
<= '9');
708 get_number (0, 53, 2);
713 get_number (0, 53, 2);
718 get_number (0, 53, 2);
719 /* XXX This cannot determine any field in TM without some
723 /* Match number of weekday. */
724 get_number (0, 6, 1);
729 match_year_in_century
:
730 /* Match year within century. */
731 get_number (0, 99, 2);
732 /* The "Year 2000: The Millennium Rollover" paper suggests that
733 values in the range 69-99 refer to the twentieth century. */
734 tm
->tm_year
= val
>= 69 ? val
: val
+ 100;
735 /* Indicate that we want to use the century, if specified. */
740 /* Match year including century number. */
741 get_number (0, 9999, 4);
742 tm
->tm_year
= val
- 1900;
747 /* XXX How to handle this? */
750 /* We recognize two formats: if two digits are given, these
751 specify hours. If fours digits are used, minutes are
755 while (ISSPACE (*rp
))
757 if (*rp
!= '+' && *rp
!= '-')
759 bool neg
= *rp
++ == '-';
761 while (n
< 4 && *rp
>= '0' && *rp
<= '9')
763 val
= val
* 10 + *rp
++ - '0';
769 /* Only two or four digits recognized. */
773 /* We have to convert the minutes into decimal. */
776 val
= (val
/ 100) * 100 + ((val
% 100) * 50) / 30;
780 tm
->tm_gmtoff
= (val
* 3600) / 100;
782 tm
->tm_gmtoff
= -tm
->tm_gmtoff
;
790 /* Match locale's alternate date and time format. */
791 if (s
.decided
!= raw
)
793 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_D_T_FMT
);
796 fmt
= _NL_CURRENT (LC_TIME
, D_T_FMT
);
798 if (!recursive (fmt
))
800 if (s
.decided
== loc
)
807 if (strcmp (fmt
, HERE_D_T_FMT
))
814 /* The C locale has no era information, so use the
815 normal representation. */
816 if (!recursive (HERE_D_T_FMT
))
821 if (s
.decided
!= raw
)
825 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
826 if (era
!= NULL
&& match_string (era
->era_name
, rp
))
835 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
836 _NL_TIME_ERA_NUM_ENTRIES
);
837 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
;
838 ++s
.era_cnt
, rp
= rp_backup
)
840 era
= _nl_select_era_entry (s
.era_cnt
842 if (era
!= NULL
&& match_string (era
->era_name
, rp
))
848 if (s
.era_cnt
!= (int) num_eras
)
852 if (s
.decided
== loc
)
857 /* The C locale has no era information, so use the
858 normal representation. */
861 if (s
.decided
!= raw
)
863 get_number(0, 9999, 4);
871 assert (s
.decided
== loc
);
873 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
877 int delta
= ((tm
->tm_year
- era
->offset
)
878 * era
->absolute_direction
);
880 && delta
< (((int64_t) era
->stop_date
[0]
881 - (int64_t) era
->start_date
[0])
882 * era
->absolute_direction
));
890 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
891 _NL_TIME_ERA_NUM_ENTRIES
);
892 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
; ++s
.era_cnt
)
894 era
= _nl_select_era_entry (s
.era_cnt
898 int delta
= ((tm
->tm_year
- era
->offset
)
899 * era
->absolute_direction
);
901 && delta
< (((int64_t) era
->stop_date
[0]
902 - (int64_t) era
->start_date
[0])
903 * era
->absolute_direction
))
910 if (s
.era_cnt
!= (int) num_eras
)
914 if (s
.decided
== loc
)
920 goto match_year_in_century
;
922 if (s
.decided
!= raw
)
924 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
925 _NL_TIME_ERA_NUM_ENTRIES
);
926 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
;
927 ++s
.era_cnt
, rp
= rp_backup
)
929 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
930 if (era
!= NULL
&& recursive (era
->era_format
))
933 if (s
.era_cnt
== (int) num_eras
)
936 if (s
.decided
== loc
)
949 get_number (0, 9999, 4);
950 tm
->tm_year
= val
- 1900;
955 if (s
.decided
!= raw
)
957 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
);
960 fmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
962 if (!recursive (fmt
))
964 if (s
.decided
== loc
)
971 if (strcmp (fmt
, HERE_D_FMT
))
977 if (!recursive (HERE_D_FMT
))
981 if (s
.decided
!= raw
)
983 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
);
986 fmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
988 if (!recursive (fmt
))
990 if (s
.decided
== loc
)
997 if (strcmp (fmt
, HERE_T_FMT
))
1003 if (!recursive (HERE_T_FMT
))
1011 /* We have no information about the era format. Just use
1012 the normal format. */
1013 if (*fmt
!= 'c' && *fmt
!= 'C' && *fmt
!= 'y' && *fmt
!= 'Y'
1014 && *fmt
!= 'x' && *fmt
!= 'X')
1015 /* This is an illegal format. */
1025 /* Match day of month using alternate numeric symbols. */
1026 get_alt_number (1, 31, 2);
1032 /* Match hour in 24-hour clock using alternate numeric
1034 get_alt_number (0, 23, 2);
1039 /* Match hour in 12-hour clock using alternate numeric
1041 get_alt_number (1, 12, 2);
1042 tm
->tm_hour
= val
% 12;
1046 /* Match month using alternate numeric symbols. */
1047 get_alt_number (1, 12, 2);
1048 tm
->tm_mon
= val
- 1;
1053 /* Match minutes using alternate numeric symbols. */
1054 get_alt_number (0, 59, 2);
1058 /* Match seconds using alternate numeric symbols. */
1059 get_alt_number (0, 61, 2);
1063 get_alt_number (0, 53, 2);
1068 get_alt_number (0, 53, 2);
1073 get_alt_number (0, 53, 2);
1074 /* XXX This cannot determine any field in TM without
1075 further information. */
1078 /* Match number of weekday using alternate numeric symbols. */
1079 get_alt_number (0, 6, 1);
1084 /* Match year within century using alternate numeric symbols. */
1085 get_alt_number (0, 99, 2);
1086 tm
->tm_year
= val
>= 69 ? val
: val
+ 100;
1100 /* Recursive invocation, returning success, so
1101 update parent's struct tm and state. */
1102 *(struct __strptime_state
*) statep
= s
;
1107 if (s
.have_I
&& s
.is_pm
)
1110 if (s
.century
!= -1)
1113 tm
->tm_year
= tm
->tm_year
% 100 + (s
.century
- 19) * 100;
1115 /* Only the century, but not the year. Strange, but so be it. */
1116 tm
->tm_year
= (s
.century
- 19) * 100;
1119 if (s
.era_cnt
!= -1)
1121 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
1125 tm
->tm_year
= (era
->start_date
[0]
1126 + ((tm
->tm_year
- era
->offset
)
1127 * era
->absolute_direction
));
1129 /* Era start year assumed. */
1130 tm
->tm_year
= era
->start_date
[0];
1135 /* No era found but we have seen an E modifier. Rectify some
1137 if (s
.want_century
&& s
.century
== -1 && tm
->tm_year
< 69)
1141 if (s
.want_xday
&& !s
.have_wday
)
1143 if ( !(s
.have_mon
&& s
.have_mday
) && s
.have_yday
)
1145 /* We don't have tm_mon and/or tm_mday, compute them. */
1147 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
] <= tm
->tm_yday
)
1150 tm
->tm_mon
= t_mon
- 1;
1154 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1158 /* Don't crash in day_of_the_week if tm_mon is uninitialized. */
1159 if (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11)
1160 day_of_the_week (tm
);
1163 if (s
.want_xday
&& !s
.have_yday
&& (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11))
1164 day_of_the_year (tm
);
1166 if ((s
.have_uweek
|| s
.have_wweek
) && s
.have_wday
)
1168 int save_wday
= tm
->tm_wday
;
1169 int save_mday
= tm
->tm_mday
;
1170 int save_mon
= tm
->tm_mon
;
1171 int w_offset
= s
.have_uweek
? 0 : 1;
1175 day_of_the_week (tm
);
1177 tm
->tm_mday
= save_mday
;
1179 tm
->tm_mon
= save_mon
;
1182 tm
->tm_yday
= ((7 - (tm
->tm_wday
- w_offset
)) % 7
1183 + (s
.week_no
- 1) *7
1184 + save_wday
- w_offset
);
1186 if (!s
.have_mday
|| !s
.have_mon
)
1189 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
]
1193 tm
->tm_mon
= t_mon
- 1;
1197 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1200 tm
->tm_wday
= save_wday
;
1208 strptime (buf
, format
, tm LOCALE_PARAM
)
1214 return __strptime_internal (buf
, format
, tm
, NULL LOCALE_ARG
);
1218 weak_alias (__strptime_l
, strptime_l
)