1 /* Copyright (C) 2002-2024 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 <https://www.gnu.org/licenses/>. */
31 # define HAVE_LOCALTIME_R 0
32 # include "../locale/localeinfo.h"
34 # define time_t __time64_t
35 # define __localtime_r(t, tp) __localtime64_r (t, tp)
38 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
40 # define localtime_r __localtime_r
42 /* Approximate localtime_r as best we can in its absence. */
43 # define localtime_r my_localtime_r
44 static struct tm
*localtime_r (const time_t *, struct tm
*);
46 localtime_r (const time_t *t
, struct tm
*tp
)
48 struct tm
*l
= localtime (t
);
55 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
58 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
59 #if defined __GNUC__ && __GNUC__ >= 2
60 # define match_string(cs1, s2) \
61 ({ size_t len = strlen (cs1); \
62 int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0; \
63 if (result) (s2) += len; \
66 /* Oh come on. Get a reasonable compiler. */
67 # define match_string(cs1, s2) \
68 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
70 /* We intentionally do not use isdigit() for testing because this will
71 lead to problems with the wide character version. */
72 #define get_number(from, to, n) \
76 while (ISSPACE (*rp)) \
78 if (*rp < '0' || *rp > '9') \
83 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
84 if (val < from || val > to) \
88 # define get_alt_number(from, to, n) \
90 __label__ do_normal; \
92 if (s.decided != raw) \
94 val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG); \
95 if (val == -1 && s.decided != loc) \
100 if (val < from || val > to) \
106 get_number (from, to, n); \
111 # define get_alt_number(from, to, n) \
112 /* We don't have the alternate representation. */ \
113 get_number(from, to, n)
115 #define recursive(new_fmt) \
116 (*(new_fmt) != '\0' \
117 && (rp = __strptime_internal (rp, (new_fmt), tm, &s LOCALE_ARG)) != NULL)
121 /* This is defined in locale/C-time.c in the GNU libc. */
122 extern const struct __locale_data _nl_C_LC_TIME attribute_hidden
;
124 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
125 # define ab_weekday_name \
126 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
127 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
128 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
129 # define alt_month_name \
130 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ALTMON_1)].string)
131 # define ab_alt_month_name \
132 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (_NL_ABALTMON_1)].string)
133 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
134 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
135 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
136 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
137 # define HERE_T_FMT_AMPM \
138 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
139 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
141 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
143 static char const weekday_name
[][10] =
145 "Sunday", "Monday", "Tuesday", "Wednesday",
146 "Thursday", "Friday", "Saturday"
148 static char const ab_weekday_name
[][4] =
150 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
152 static char const month_name
[][10] =
154 "January", "February", "March", "April", "May", "June",
155 "July", "August", "September", "October", "November", "December"
157 static char const ab_month_name
[][4] =
159 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
160 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
162 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
163 # define HERE_D_FMT "%m/%d/%y"
164 # define HERE_AM_STR "AM"
165 # define HERE_PM_STR "PM"
166 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
167 # define HERE_T_FMT "%H:%M:%S"
169 static const unsigned short int __mon_yday
[2][13] =
172 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
174 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
179 /* We use this code also for the extended locale handling where the
180 function gets as an additional argument the locale which has to be
181 used. To access the values we have to redefine the _NL_CURRENT
183 # define strptime __strptime_l
185 # define _NL_CURRENT(category, item) \
186 (current->values[_NL_ITEM_INDEX (item)].string)
187 # undef _NL_CURRENT_WORD
188 # define _NL_CURRENT_WORD(category, item) \
189 (current->values[_NL_ITEM_INDEX (item)].word)
190 # define LOCALE_PARAM , locale_t locale
191 # define LOCALE_ARG , locale
192 # define HELPER_LOCALE_ARG , current
193 # define ISSPACE(Ch) __isspace_l (Ch, locale)
195 # define LOCALE_PARAM
197 # define HELPER_LOCALE_ARG
198 # define ISSPACE(Ch) isspace (Ch)
205 /* Nonzero if YEAR is a leap year (every 4 years,
206 except every 100th isn't, and every 400th is). */
207 # define __isleap(year) \
208 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
211 /* Compute the day of the week. */
213 day_of_the_week (struct tm
*tm
)
215 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
216 difference between this data in the one on TM and so determine
218 int corr_year
= 1900 + tm
->tm_year
- (tm
->tm_mon
< 2);
220 + (365 * (tm
->tm_year
- 70))
222 - ((corr_year
/ 4) / 25) + ((corr_year
/ 4) % 25 < 0)
223 + (((corr_year
/ 4) / 25) / 4)
224 + __mon_yday
[0][tm
->tm_mon
]
226 tm
->tm_wday
= ((wday
% 7) + 7) % 7;
229 /* Compute the day of the year. */
231 day_of_the_year (struct tm
*tm
)
233 tm
->tm_yday
= (__mon_yday
[__isleap (1900 + tm
->tm_year
)][tm
->tm_mon
]
234 + (tm
->tm_mday
- 1));
243 __strptime_internal (const char *rp
, const char *fmt
, struct tm
*tmp
,
244 void *statep LOCALE_PARAM
)
247 struct __locale_data
*const current
= locale
->__locales
[LC_TIME
];
250 const char *rp_backup
;
251 const char *rp_longest
;
256 struct era_entry
*era
= NULL
;
257 enum ptime_locale_status
{ not, loc
, raw
} decided_longest
;
258 struct __strptime_state
260 unsigned int have_I
: 1;
261 unsigned int have_wday
: 1;
262 unsigned int have_yday
: 1;
263 unsigned int have_mon
: 1;
264 unsigned int have_mday
: 1;
265 unsigned int have_uweek
: 1;
266 unsigned int have_wweek
: 1;
267 unsigned int is_pm
: 1;
268 unsigned int want_century
: 1;
269 unsigned int want_era
: 1;
270 unsigned int want_xday
: 1;
271 enum ptime_locale_status decided
: 2;
281 memset (&s
, 0, sizeof (s
));
293 s
= *(struct __strptime_state
*) statep
;
300 /* A white space in the format string matches 0 more or white
301 space in the input string. */
304 while (ISSPACE (*rp
))
310 /* Any character but `%' must be matched by the same character
311 in the input string. */
314 match_char (*fmt
++, *rp
++);
319 /* We discard strftime modifiers. */
320 while (*fmt
== '-' || *fmt
== '_' || *fmt
== '0'
321 || *fmt
== '^' || *fmt
== '#')
324 /* And field width. */
325 while (*fmt
>= '0' && *fmt
<= '9')
328 /* In some cases, modifiers are handled by adjusting state and
329 then restarting the switch statement below. */
332 /* Make back up of current processing pointer. */
338 /* Match the `%' character itself. */
339 match_char ('%', *rp
++);
343 /* Match day of week. */
345 decided_longest
= s
.decided
;
347 for (cnt
= 0; cnt
< 7; ++cnt
)
354 if (match_string (_NL_CURRENT (LC_TIME
, DAY_1
+ cnt
), trp
)
360 && strcmp (_NL_CURRENT (LC_TIME
, DAY_1
+ cnt
),
362 decided_longest
= loc
;
365 if (match_string (_NL_CURRENT (LC_TIME
, ABDAY_1
+ cnt
), trp
)
371 && strcmp (_NL_CURRENT (LC_TIME
, ABDAY_1
+ cnt
),
372 ab_weekday_name
[cnt
]))
373 decided_longest
= loc
;
378 && (((trp
= rp
, match_string (weekday_name
[cnt
], trp
))
380 || ((trp
= rp
, match_string (ab_weekday_name
[cnt
], rp
))
381 && trp
> rp_longest
)))
385 decided_longest
= raw
;
388 if (rp_longest
== NULL
)
389 /* Does not match a weekday name. */
392 s
.decided
= decided_longest
;
393 tm
->tm_wday
= cnt_longest
;
399 /* Match month name. */
401 decided_longest
= s
.decided
;
403 for (cnt
= 0; cnt
< 12; ++cnt
)
410 if (match_string (_NL_CURRENT (LC_TIME
, MON_1
+ cnt
), trp
)
416 && strcmp (_NL_CURRENT (LC_TIME
, MON_1
+ cnt
),
418 decided_longest
= loc
;
421 if (match_string (_NL_CURRENT (LC_TIME
, ABMON_1
+ cnt
), trp
)
427 && strcmp (_NL_CURRENT (LC_TIME
, ABMON_1
+ cnt
),
429 decided_longest
= loc
;
432 /* Now check the alt month. */
434 if (match_string (_NL_CURRENT (LC_TIME
, ALTMON_1
+ cnt
), trp
)
440 && strcmp (_NL_CURRENT (LC_TIME
, ALTMON_1
+ cnt
),
441 alt_month_name
[cnt
]))
442 decided_longest
= loc
;
445 if (match_string (_NL_CURRENT (LC_TIME
, _NL_ABALTMON_1
+ cnt
),
452 && strcmp (_NL_CURRENT (LC_TIME
, _NL_ABALTMON_1
+ cnt
),
453 alt_month_name
[cnt
]))
454 decided_longest
= loc
;
460 && (((trp
= rp
, match_string (month_name
[cnt
], trp
))
462 || ((trp
= rp
, match_string (ab_month_name
[cnt
], trp
))
465 || ((trp
= rp
, match_string (alt_month_name
[cnt
], trp
))
467 || ((trp
= rp
, match_string (ab_alt_month_name
[cnt
], trp
))
474 decided_longest
= raw
;
477 if (rp_longest
== NULL
)
478 /* Does not match a month name. */
481 s
.decided
= decided_longest
;
482 tm
->tm_mon
= cnt_longest
;
487 /* Match locale's date and time format. */
489 if (s
.decided
!= raw
)
491 if (!recursive (_NL_CURRENT (LC_TIME
, D_T_FMT
)))
493 if (s
.decided
== loc
)
501 && strcmp (_NL_CURRENT (LC_TIME
, D_T_FMT
), HERE_D_T_FMT
))
509 if (!recursive (HERE_D_T_FMT
))
514 /* Match century number. */
516 get_number (0, 99, 2);
522 /* Match day of month. */
523 get_number (1, 31, 2);
529 if (!recursive ("%Y-%m-%d"))
535 if (s
.decided
!= raw
)
537 if (!recursive (_NL_CURRENT (LC_TIME
, D_FMT
)))
539 if (s
.decided
== loc
)
547 && strcmp (_NL_CURRENT (LC_TIME
, D_FMT
), HERE_D_FMT
))
557 /* Match standard day format. */
558 if (!recursive (HERE_D_FMT
))
564 /* Match hour in 24-hour clock. */
565 get_number (0, 23, 2);
570 /* Match hour in 12-hour clock. GNU extension. */
572 /* Match hour in 12-hour clock. */
573 get_number (1, 12, 2);
574 tm
->tm_hour
= val
% 12;
578 /* Match day number of year. */
579 get_number (1, 366, 3);
580 tm
->tm_yday
= val
- 1;
584 /* Match number of month. */
585 get_number (1, 12, 2);
586 tm
->tm_mon
= val
- 1;
592 get_number (0, 59, 2);
597 /* Match any white space. */
598 while (ISSPACE (*rp
))
602 /* Match locale's equivalent of AM/PM. */
604 if (s
.decided
!= raw
)
606 if (match_string (_NL_CURRENT (LC_TIME
, AM_STR
), rp
))
608 if (strcmp (_NL_CURRENT (LC_TIME
, AM_STR
), HERE_AM_STR
))
613 if (match_string (_NL_CURRENT (LC_TIME
, PM_STR
), rp
))
615 if (strcmp (_NL_CURRENT (LC_TIME
, PM_STR
), HERE_PM_STR
))
623 if (!match_string (HERE_AM_STR
, rp
))
625 if (match_string (HERE_PM_STR
, rp
))
635 if (s
.decided
!= raw
)
637 if (!recursive (_NL_CURRENT (LC_TIME
, T_FMT_AMPM
)))
639 if (s
.decided
== loc
)
647 && strcmp (_NL_CURRENT (LC_TIME
, T_FMT_AMPM
),
655 if (!recursive (HERE_T_FMT_AMPM
))
659 if (!recursive ("%H:%M"))
664 /* The number of seconds may be very high so we cannot use
665 the `get_number' macro. Instead read the number
666 character for character and construct the result while
669 if (*rp
< '0' || *rp
> '9')
670 /* We need at least one digit. */
678 while (*rp
>= '0' && *rp
<= '9');
680 if (localtime_r (&secs
, tm
) == NULL
)
681 /* Error in function. */
686 get_number (0, 61, 2);
691 if (s
.decided
!= raw
)
693 if (!recursive (_NL_CURRENT (LC_TIME
, T_FMT
)))
695 if (s
.decided
== loc
)
702 if (strcmp (_NL_CURRENT (LC_TIME
, T_FMT
), HERE_T_FMT
))
711 if (!recursive (HERE_T_FMT
))
715 get_number (1, 7, 1);
716 tm
->tm_wday
= val
% 7;
720 get_number (0, 99, 2);
721 /* XXX This cannot determine any field in TM. */
724 if (*rp
< '0' || *rp
> '9')
726 /* XXX Ignore the number since we would need some more
727 information to compute a real date. */
730 while (*rp
>= '0' && *rp
<= '9');
733 get_number (0, 53, 2);
738 get_number (0, 53, 2);
743 get_number (0, 53, 2);
744 /* XXX This cannot determine any field in TM without some
748 /* Match number of weekday. */
749 get_number (0, 6, 1);
754 match_year_in_century
:
755 /* Match year within century. */
756 get_number (0, 99, 2);
757 /* The "Year 2000: The Millennium Rollover" paper suggests that
758 values in the range 69-99 refer to the twentieth century. */
759 tm
->tm_year
= val
>= 69 ? val
: val
+ 100;
760 /* Indicate that we want to use the century, if specified. */
765 /* Match year including century number. */
766 get_number (0, 9999, 4);
767 tm
->tm_year
= val
- 1900;
772 /* Read timezone but perform no conversion. */
773 while (ISSPACE (*rp
))
775 while (!ISSPACE (*rp
) && *rp
!= '\0')
779 /* We recognize four formats:
780 1. Two digits specify hours.
781 2. Four digits specify hours and minutes.
782 3. Two digits, ':', and two digits specify hours and minutes.
783 4. 'Z' is equivalent to +0000. */
786 while (ISSPACE (*rp
))
794 if (*rp
!= '+' && *rp
!= '-')
796 bool neg
= *rp
++ == '-';
798 while (n
< 4 && *rp
>= '0' && *rp
<= '9')
800 val
= val
* 10 + *rp
++ - '0';
802 if (*rp
== ':' && n
== 2 && isdigit (*(rp
+ 1)))
808 /* Only two or four digits recognized. */
810 else if (val
% 100 >= 60)
811 /* Minutes valid range is 0 through 59. */
813 tm
->tm_gmtoff
= (val
/ 100) * 3600 + (val
% 100) * 60;
815 tm
->tm_gmtoff
= -tm
->tm_gmtoff
;
823 /* Match locale's alternate date and time format. */
824 if (s
.decided
!= raw
)
826 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_D_T_FMT
);
829 fmt
= _NL_CURRENT (LC_TIME
, D_T_FMT
);
831 if (!recursive (fmt
))
833 if (s
.decided
== loc
)
840 if (strcmp (fmt
, HERE_D_T_FMT
))
847 /* The C locale has no era information, so use the
848 normal representation. */
849 if (!recursive (HERE_D_T_FMT
))
854 if (s
.decided
!= raw
)
858 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
859 if (era
!= NULL
&& match_string (era
->era_name
, rp
))
868 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
869 _NL_TIME_ERA_NUM_ENTRIES
);
870 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
;
871 ++s
.era_cnt
, rp
= rp_backup
)
873 era
= _nl_select_era_entry (s
.era_cnt
875 if (era
!= NULL
&& match_string (era
->era_name
, rp
))
881 if (s
.era_cnt
!= (int) num_eras
)
885 if (s
.decided
== loc
)
890 /* The C locale has no era information, so use the
891 normal representation. */
894 if (s
.decided
!= raw
)
896 get_number(0, 9999, 4);
904 assert (s
.decided
== loc
);
906 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
910 int delta
= ((tm
->tm_year
- era
->offset
)
911 * era
->absolute_direction
);
912 /* The difference between two sets of years
913 does not include the final year itself,
914 therefore add 1 to the difference to
915 account for that final year. */
917 && delta
< (((int64_t) era
->stop_date
[0]
918 - (int64_t) era
->start_date
[0])
919 * era
->absolute_direction
928 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
929 _NL_TIME_ERA_NUM_ENTRIES
);
930 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
; ++s
.era_cnt
)
932 era
= _nl_select_era_entry (s
.era_cnt
936 int delta
= ((tm
->tm_year
- era
->offset
)
937 * era
->absolute_direction
);
938 /* See comment above about year difference + 1. */
940 && delta
< (((int64_t) era
->stop_date
[0]
941 - (int64_t) era
->start_date
[0])
942 * era
->absolute_direction
950 if (s
.era_cnt
!= (int) num_eras
)
954 if (s
.decided
== loc
)
960 goto match_year_in_century
;
962 if (s
.decided
!= raw
)
964 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
965 _NL_TIME_ERA_NUM_ENTRIES
);
966 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
;
967 ++s
.era_cnt
, rp
= rp_backup
)
969 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
970 if (era
!= NULL
&& recursive (era
->era_format
))
973 if (s
.era_cnt
== (int) num_eras
)
976 if (s
.decided
== loc
)
989 get_number (0, 9999, 4);
990 tm
->tm_year
= val
- 1900;
995 if (s
.decided
!= raw
)
997 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
);
1000 fmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
1002 if (!recursive (fmt
))
1004 if (s
.decided
== loc
)
1011 if (strcmp (fmt
, HERE_D_FMT
))
1017 if (!recursive (HERE_D_FMT
))
1021 if (s
.decided
!= raw
)
1023 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
);
1026 fmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
1028 if (!recursive (fmt
))
1030 if (s
.decided
== loc
)
1037 if (strcmp (fmt
, HERE_T_FMT
))
1043 if (!recursive (HERE_T_FMT
))
1051 /* We have no information about the era format. Just use
1052 the normal format. */
1053 if (*fmt
!= 'c' && *fmt
!= 'C' && *fmt
!= 'y' && *fmt
!= 'Y'
1054 && *fmt
!= 'x' && *fmt
!= 'X')
1055 /* This is an illegal format. */
1066 /* Match month name. Reprocess as plain 'B'. */
1071 /* Match day of month using alternate numeric symbols. */
1072 get_alt_number (1, 31, 2);
1078 /* Match hour in 24-hour clock using alternate numeric
1080 get_alt_number (0, 23, 2);
1085 /* Match hour in 12-hour clock using alternate numeric
1087 get_alt_number (1, 12, 2);
1088 tm
->tm_hour
= val
% 12;
1092 /* Match month using alternate numeric symbols. */
1093 get_alt_number (1, 12, 2);
1094 tm
->tm_mon
= val
- 1;
1099 /* Match minutes using alternate numeric symbols. */
1100 get_alt_number (0, 59, 2);
1104 /* Match seconds using alternate numeric symbols. */
1105 get_alt_number (0, 61, 2);
1109 get_alt_number (0, 53, 2);
1114 get_alt_number (0, 53, 2);
1119 get_alt_number (0, 53, 2);
1120 /* XXX This cannot determine any field in TM without
1121 further information. */
1124 /* Match number of weekday using alternate numeric symbols. */
1125 get_alt_number (0, 6, 1);
1130 /* Match year within century using alternate numeric symbols. */
1131 get_alt_number (0, 99, 2);
1132 tm
->tm_year
= val
>= 69 ? val
: val
+ 100;
1146 /* Recursive invocation, returning success, so
1147 update parent's struct tm and state. */
1148 *(struct __strptime_state
*) statep
= s
;
1153 if (s
.have_I
&& s
.is_pm
)
1156 if (s
.century
!= -1)
1159 tm
->tm_year
= tm
->tm_year
% 100 + (s
.century
- 19) * 100;
1161 /* Only the century, but not the year. Strange, but so be it. */
1162 tm
->tm_year
= (s
.century
- 19) * 100;
1165 if (s
.era_cnt
!= -1)
1167 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
1171 tm
->tm_year
= (era
->start_date
[0]
1172 + ((tm
->tm_year
- era
->offset
)
1173 * era
->absolute_direction
));
1175 /* Era start year assumed. */
1176 tm
->tm_year
= era
->start_date
[0];
1181 /* No era found but we have seen an E modifier. Rectify some
1183 if (s
.want_century
&& s
.century
== -1 && tm
->tm_year
< 69)
1187 if (s
.want_xday
&& !s
.have_wday
)
1189 if ( !(s
.have_mon
&& s
.have_mday
) && s
.have_yday
)
1191 /* We don't have tm_mon and/or tm_mday, compute them. */
1193 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
] <= tm
->tm_yday
)
1196 tm
->tm_mon
= t_mon
- 1;
1200 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1204 /* Don't crash in day_of_the_week if tm_mon is uninitialized. */
1205 if (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11)
1206 day_of_the_week (tm
);
1209 if (s
.want_xday
&& !s
.have_yday
&& (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11))
1210 day_of_the_year (tm
);
1212 if ((s
.have_uweek
|| s
.have_wweek
) && s
.have_wday
)
1214 int save_wday
= tm
->tm_wday
;
1215 int save_mday
= tm
->tm_mday
;
1216 int save_mon
= tm
->tm_mon
;
1217 int w_offset
= s
.have_uweek
? 0 : 1;
1221 day_of_the_week (tm
);
1223 tm
->tm_mday
= save_mday
;
1225 tm
->tm_mon
= save_mon
;
1228 tm
->tm_yday
= ((7 - (tm
->tm_wday
- w_offset
)) % 7
1229 + (s
.week_no
- 1) * 7
1230 + (save_wday
- w_offset
+ 7) % 7);
1232 if (!s
.have_mday
|| !s
.have_mon
)
1235 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
]
1239 tm
->tm_mon
= t_mon
- 1;
1243 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1246 tm
->tm_wday
= save_wday
;
1254 strptime (const char *buf
, const char *format
, struct tm
*tm LOCALE_PARAM
)
1256 return __strptime_internal (buf
, format
, tm
, NULL LOCALE_ARG
);
1260 weak_alias (__strptime_l
, strptime_l
)