1 /* Copyright (C) 2002-2022 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"
36 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
38 # define localtime_r __localtime_r
40 /* Approximate localtime_r as best we can in its absence. */
41 # define localtime_r my_localtime_r
42 static struct tm
*localtime_r (const time_t *, struct tm
*);
44 localtime_r (const time_t *t
, struct tm
*tp
)
46 struct tm
*l
= localtime (t
);
53 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
56 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
57 #if defined __GNUC__ && __GNUC__ >= 2
58 # define match_string(cs1, s2) \
59 ({ size_t len = strlen (cs1); \
60 int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0; \
61 if (result) (s2) += len; \
64 /* Oh come on. Get a reasonable compiler. */
65 # define match_string(cs1, s2) \
66 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
68 /* We intentionally do not use isdigit() for testing because this will
69 lead to problems with the wide character version. */
70 #define get_number(from, to, n) \
74 while (ISSPACE (*rp)) \
76 if (*rp < '0' || *rp > '9') \
81 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
82 if (val < from || val > to) \
86 # define get_alt_number(from, to, n) \
88 __label__ do_normal; \
90 if (s.decided != raw) \
92 val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG); \
93 if (val == -1 && s.decided != loc) \
98 if (val < from || val > to) \
104 get_number (from, to, n); \
109 # define get_alt_number(from, to, n) \
110 /* We don't have the alternate representation. */ \
111 get_number(from, to, n)
113 #define recursive(new_fmt) \
114 (*(new_fmt) != '\0' \
115 && (rp = __strptime_internal (rp, (new_fmt), tm, &s LOCALE_ARG)) != NULL)
119 /* This is defined in locale/C-time.c in the GNU libc. */
120 extern const struct __locale_data _nl_C_LC_TIME attribute_hidden
;
122 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
123 # define ab_weekday_name \
124 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
125 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
126 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
127 # define alt_month_name \
128 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ALTMON_1)].string)
129 # define ab_alt_month_name \
130 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (_NL_ABALTMON_1)].string)
131 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
132 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
133 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
134 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
135 # define HERE_T_FMT_AMPM \
136 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
137 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
139 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
141 static char const weekday_name
[][10] =
143 "Sunday", "Monday", "Tuesday", "Wednesday",
144 "Thursday", "Friday", "Saturday"
146 static char const ab_weekday_name
[][4] =
148 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
150 static char const month_name
[][10] =
152 "January", "February", "March", "April", "May", "June",
153 "July", "August", "September", "October", "November", "December"
155 static char const ab_month_name
[][4] =
157 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
158 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
160 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
161 # define HERE_D_FMT "%m/%d/%y"
162 # define HERE_AM_STR "AM"
163 # define HERE_PM_STR "PM"
164 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
165 # define HERE_T_FMT "%H:%M:%S"
167 static const unsigned short int __mon_yday
[2][13] =
170 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
172 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
177 /* We use this code also for the extended locale handling where the
178 function gets as an additional argument the locale which has to be
179 used. To access the values we have to redefine the _NL_CURRENT
181 # define strptime __strptime_l
183 # define _NL_CURRENT(category, item) \
184 (current->values[_NL_ITEM_INDEX (item)].string)
185 # undef _NL_CURRENT_WORD
186 # define _NL_CURRENT_WORD(category, item) \
187 (current->values[_NL_ITEM_INDEX (item)].word)
188 # define LOCALE_PARAM , locale_t locale
189 # define LOCALE_ARG , locale
190 # define HELPER_LOCALE_ARG , current
191 # define ISSPACE(Ch) __isspace_l (Ch, locale)
193 # define LOCALE_PARAM
195 # define HELPER_LOCALE_ARG
196 # define ISSPACE(Ch) isspace (Ch)
203 /* Nonzero if YEAR is a leap year (every 4 years,
204 except every 100th isn't, and every 400th is). */
205 # define __isleap(year) \
206 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
209 /* Compute the day of the week. */
211 day_of_the_week (struct tm
*tm
)
213 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
214 difference between this data in the one on TM and so determine
216 int corr_year
= 1900 + tm
->tm_year
- (tm
->tm_mon
< 2);
218 + (365 * (tm
->tm_year
- 70))
220 - ((corr_year
/ 4) / 25) + ((corr_year
/ 4) % 25 < 0)
221 + (((corr_year
/ 4) / 25) / 4)
222 + __mon_yday
[0][tm
->tm_mon
]
224 tm
->tm_wday
= ((wday
% 7) + 7) % 7;
227 /* Compute the day of the year. */
229 day_of_the_year (struct tm
*tm
)
231 tm
->tm_yday
= (__mon_yday
[__isleap (1900 + tm
->tm_year
)][tm
->tm_mon
]
232 + (tm
->tm_mday
- 1));
241 __strptime_internal (const char *rp
, const char *fmt
, struct tm
*tmp
,
242 void *statep LOCALE_PARAM
)
245 struct __locale_data
*const current
= locale
->__locales
[LC_TIME
];
248 const char *rp_backup
;
249 const char *rp_longest
;
254 struct era_entry
*era
= NULL
;
255 enum ptime_locale_status
{ not, loc
, raw
} decided_longest
;
256 struct __strptime_state
258 unsigned int have_I
: 1;
259 unsigned int have_wday
: 1;
260 unsigned int have_yday
: 1;
261 unsigned int have_mon
: 1;
262 unsigned int have_mday
: 1;
263 unsigned int have_uweek
: 1;
264 unsigned int have_wweek
: 1;
265 unsigned int is_pm
: 1;
266 unsigned int want_century
: 1;
267 unsigned int want_era
: 1;
268 unsigned int want_xday
: 1;
269 enum ptime_locale_status decided
: 2;
279 memset (&s
, 0, sizeof (s
));
291 s
= *(struct __strptime_state
*) statep
;
298 /* A white space in the format string matches 0 more or white
299 space in the input string. */
302 while (ISSPACE (*rp
))
308 /* Any character but `%' must be matched by the same character
309 in the input string. */
312 match_char (*fmt
++, *rp
++);
317 /* We discard strftime modifiers. */
318 while (*fmt
== '-' || *fmt
== '_' || *fmt
== '0'
319 || *fmt
== '^' || *fmt
== '#')
322 /* And field width. */
323 while (*fmt
>= '0' && *fmt
<= '9')
326 /* In some cases, modifiers are handled by adjusting state and
327 then restarting the switch statement below. */
330 /* Make back up of current processing pointer. */
336 /* Match the `%' character itself. */
337 match_char ('%', *rp
++);
341 /* Match day of week. */
343 decided_longest
= s
.decided
;
345 for (cnt
= 0; cnt
< 7; ++cnt
)
352 if (match_string (_NL_CURRENT (LC_TIME
, DAY_1
+ cnt
), trp
)
358 && strcmp (_NL_CURRENT (LC_TIME
, DAY_1
+ cnt
),
360 decided_longest
= loc
;
363 if (match_string (_NL_CURRENT (LC_TIME
, ABDAY_1
+ cnt
), trp
)
369 && strcmp (_NL_CURRENT (LC_TIME
, ABDAY_1
+ cnt
),
370 ab_weekday_name
[cnt
]))
371 decided_longest
= loc
;
376 && (((trp
= rp
, match_string (weekday_name
[cnt
], trp
))
378 || ((trp
= rp
, match_string (ab_weekday_name
[cnt
], rp
))
379 && trp
> rp_longest
)))
383 decided_longest
= raw
;
386 if (rp_longest
== NULL
)
387 /* Does not match a weekday name. */
390 s
.decided
= decided_longest
;
391 tm
->tm_wday
= cnt_longest
;
397 /* Match month name. */
399 decided_longest
= s
.decided
;
401 for (cnt
= 0; cnt
< 12; ++cnt
)
408 if (match_string (_NL_CURRENT (LC_TIME
, MON_1
+ cnt
), trp
)
414 && strcmp (_NL_CURRENT (LC_TIME
, MON_1
+ cnt
),
416 decided_longest
= loc
;
419 if (match_string (_NL_CURRENT (LC_TIME
, ABMON_1
+ cnt
), trp
)
425 && strcmp (_NL_CURRENT (LC_TIME
, ABMON_1
+ cnt
),
427 decided_longest
= loc
;
430 /* Now check the alt month. */
432 if (match_string (_NL_CURRENT (LC_TIME
, ALTMON_1
+ cnt
), trp
)
438 && strcmp (_NL_CURRENT (LC_TIME
, ALTMON_1
+ cnt
),
439 alt_month_name
[cnt
]))
440 decided_longest
= loc
;
443 if (match_string (_NL_CURRENT (LC_TIME
, _NL_ABALTMON_1
+ cnt
),
450 && strcmp (_NL_CURRENT (LC_TIME
, _NL_ABALTMON_1
+ cnt
),
451 alt_month_name
[cnt
]))
452 decided_longest
= loc
;
458 && (((trp
= rp
, match_string (month_name
[cnt
], trp
))
460 || ((trp
= rp
, match_string (ab_month_name
[cnt
], trp
))
463 || ((trp
= rp
, match_string (alt_month_name
[cnt
], trp
))
465 || ((trp
= rp
, match_string (ab_alt_month_name
[cnt
], trp
))
472 decided_longest
= raw
;
475 if (rp_longest
== NULL
)
476 /* Does not match a month name. */
479 s
.decided
= decided_longest
;
480 tm
->tm_mon
= cnt_longest
;
485 /* Match locale's date and time format. */
487 if (s
.decided
!= raw
)
489 if (!recursive (_NL_CURRENT (LC_TIME
, D_T_FMT
)))
491 if (s
.decided
== loc
)
499 && strcmp (_NL_CURRENT (LC_TIME
, D_T_FMT
), HERE_D_T_FMT
))
507 if (!recursive (HERE_D_T_FMT
))
512 /* Match century number. */
514 get_number (0, 99, 2);
520 /* Match day of month. */
521 get_number (1, 31, 2);
527 if (!recursive ("%Y-%m-%d"))
533 if (s
.decided
!= raw
)
535 if (!recursive (_NL_CURRENT (LC_TIME
, D_FMT
)))
537 if (s
.decided
== loc
)
545 && strcmp (_NL_CURRENT (LC_TIME
, D_FMT
), HERE_D_FMT
))
555 /* Match standard day format. */
556 if (!recursive (HERE_D_FMT
))
562 /* Match hour in 24-hour clock. */
563 get_number (0, 23, 2);
568 /* Match hour in 12-hour clock. GNU extension. */
570 /* Match hour in 12-hour clock. */
571 get_number (1, 12, 2);
572 tm
->tm_hour
= val
% 12;
576 /* Match day number of year. */
577 get_number (1, 366, 3);
578 tm
->tm_yday
= val
- 1;
582 /* Match number of month. */
583 get_number (1, 12, 2);
584 tm
->tm_mon
= val
- 1;
590 get_number (0, 59, 2);
595 /* Match any white space. */
596 while (ISSPACE (*rp
))
600 /* Match locale's equivalent of AM/PM. */
602 if (s
.decided
!= raw
)
604 if (match_string (_NL_CURRENT (LC_TIME
, AM_STR
), rp
))
606 if (strcmp (_NL_CURRENT (LC_TIME
, AM_STR
), HERE_AM_STR
))
611 if (match_string (_NL_CURRENT (LC_TIME
, PM_STR
), rp
))
613 if (strcmp (_NL_CURRENT (LC_TIME
, PM_STR
), HERE_PM_STR
))
621 if (!match_string (HERE_AM_STR
, rp
))
623 if (match_string (HERE_PM_STR
, rp
))
633 if (s
.decided
!= raw
)
635 if (!recursive (_NL_CURRENT (LC_TIME
, T_FMT_AMPM
)))
637 if (s
.decided
== loc
)
645 && strcmp (_NL_CURRENT (LC_TIME
, T_FMT_AMPM
),
653 if (!recursive (HERE_T_FMT_AMPM
))
657 if (!recursive ("%H:%M"))
662 /* The number of seconds may be very high so we cannot use
663 the `get_number' macro. Instead read the number
664 character for character and construct the result while
667 if (*rp
< '0' || *rp
> '9')
668 /* We need at least one digit. */
676 while (*rp
>= '0' && *rp
<= '9');
678 if (localtime_r (&secs
, tm
) == NULL
)
679 /* Error in function. */
684 get_number (0, 61, 2);
689 if (s
.decided
!= raw
)
691 if (!recursive (_NL_CURRENT (LC_TIME
, T_FMT
)))
693 if (s
.decided
== loc
)
700 if (strcmp (_NL_CURRENT (LC_TIME
, T_FMT
), HERE_T_FMT
))
709 if (!recursive (HERE_T_FMT
))
713 get_number (1, 7, 1);
714 tm
->tm_wday
= val
% 7;
718 get_number (0, 99, 2);
719 /* XXX This cannot determine any field in TM. */
722 if (*rp
< '0' || *rp
> '9')
724 /* XXX Ignore the number since we would need some more
725 information to compute a real date. */
728 while (*rp
>= '0' && *rp
<= '9');
731 get_number (0, 53, 2);
736 get_number (0, 53, 2);
741 get_number (0, 53, 2);
742 /* XXX This cannot determine any field in TM without some
746 /* Match number of weekday. */
747 get_number (0, 6, 1);
752 match_year_in_century
:
753 /* Match year within century. */
754 get_number (0, 99, 2);
755 /* The "Year 2000: The Millennium Rollover" paper suggests that
756 values in the range 69-99 refer to the twentieth century. */
757 tm
->tm_year
= val
>= 69 ? val
: val
+ 100;
758 /* Indicate that we want to use the century, if specified. */
763 /* Match year including century number. */
764 get_number (0, 9999, 4);
765 tm
->tm_year
= val
- 1900;
770 /* Read timezone but perform no conversion. */
771 while (ISSPACE (*rp
))
773 while (!ISSPACE (*rp
) && *rp
!= '\0')
777 /* We recognize four formats:
778 1. Two digits specify hours.
779 2. Four digits specify hours and minutes.
780 3. Two digits, ':', and two digits specify hours and minutes.
781 4. 'Z' is equivalent to +0000. */
784 while (ISSPACE (*rp
))
792 if (*rp
!= '+' && *rp
!= '-')
794 bool neg
= *rp
++ == '-';
796 while (n
< 4 && *rp
>= '0' && *rp
<= '9')
798 val
= val
* 10 + *rp
++ - '0';
800 if (*rp
== ':' && n
== 2 && isdigit (*(rp
+ 1)))
806 /* Only two or four digits recognized. */
808 else if (val
% 100 >= 60)
809 /* Minutes valid range is 0 through 59. */
811 tm
->tm_gmtoff
= (val
/ 100) * 3600 + (val
% 100) * 60;
813 tm
->tm_gmtoff
= -tm
->tm_gmtoff
;
821 /* Match locale's alternate date and time format. */
822 if (s
.decided
!= raw
)
824 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_D_T_FMT
);
827 fmt
= _NL_CURRENT (LC_TIME
, D_T_FMT
);
829 if (!recursive (fmt
))
831 if (s
.decided
== loc
)
838 if (strcmp (fmt
, HERE_D_T_FMT
))
845 /* The C locale has no era information, so use the
846 normal representation. */
847 if (!recursive (HERE_D_T_FMT
))
852 if (s
.decided
!= raw
)
856 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
857 if (era
!= NULL
&& match_string (era
->era_name
, rp
))
866 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
867 _NL_TIME_ERA_NUM_ENTRIES
);
868 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
;
869 ++s
.era_cnt
, rp
= rp_backup
)
871 era
= _nl_select_era_entry (s
.era_cnt
873 if (era
!= NULL
&& match_string (era
->era_name
, rp
))
879 if (s
.era_cnt
!= (int) num_eras
)
883 if (s
.decided
== loc
)
888 /* The C locale has no era information, so use the
889 normal representation. */
892 if (s
.decided
!= raw
)
894 get_number(0, 9999, 4);
902 assert (s
.decided
== loc
);
904 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
908 int delta
= ((tm
->tm_year
- era
->offset
)
909 * era
->absolute_direction
);
910 /* The difference between two sets of years
911 does not include the final year itself,
912 therefore add 1 to the difference to
913 account for that final year. */
915 && delta
< (((int64_t) era
->stop_date
[0]
916 - (int64_t) era
->start_date
[0])
917 * era
->absolute_direction
926 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
927 _NL_TIME_ERA_NUM_ENTRIES
);
928 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
; ++s
.era_cnt
)
930 era
= _nl_select_era_entry (s
.era_cnt
934 int delta
= ((tm
->tm_year
- era
->offset
)
935 * era
->absolute_direction
);
936 /* See comment above about year difference + 1. */
938 && delta
< (((int64_t) era
->stop_date
[0]
939 - (int64_t) era
->start_date
[0])
940 * era
->absolute_direction
948 if (s
.era_cnt
!= (int) num_eras
)
952 if (s
.decided
== loc
)
958 goto match_year_in_century
;
960 if (s
.decided
!= raw
)
962 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
963 _NL_TIME_ERA_NUM_ENTRIES
);
964 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
;
965 ++s
.era_cnt
, rp
= rp_backup
)
967 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
968 if (era
!= NULL
&& recursive (era
->era_format
))
971 if (s
.era_cnt
== (int) num_eras
)
974 if (s
.decided
== loc
)
987 get_number (0, 9999, 4);
988 tm
->tm_year
= val
- 1900;
993 if (s
.decided
!= raw
)
995 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
);
998 fmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
1000 if (!recursive (fmt
))
1002 if (s
.decided
== loc
)
1009 if (strcmp (fmt
, HERE_D_FMT
))
1015 if (!recursive (HERE_D_FMT
))
1019 if (s
.decided
!= raw
)
1021 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
);
1024 fmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
1026 if (!recursive (fmt
))
1028 if (s
.decided
== loc
)
1035 if (strcmp (fmt
, HERE_T_FMT
))
1041 if (!recursive (HERE_T_FMT
))
1049 /* We have no information about the era format. Just use
1050 the normal format. */
1051 if (*fmt
!= 'c' && *fmt
!= 'C' && *fmt
!= 'y' && *fmt
!= 'Y'
1052 && *fmt
!= 'x' && *fmt
!= 'X')
1053 /* This is an illegal format. */
1064 /* Match month name. Reprocess as plain 'B'. */
1069 /* Match day of month using alternate numeric symbols. */
1070 get_alt_number (1, 31, 2);
1076 /* Match hour in 24-hour clock using alternate numeric
1078 get_alt_number (0, 23, 2);
1083 /* Match hour in 12-hour clock using alternate numeric
1085 get_alt_number (1, 12, 2);
1086 tm
->tm_hour
= val
% 12;
1090 /* Match month using alternate numeric symbols. */
1091 get_alt_number (1, 12, 2);
1092 tm
->tm_mon
= val
- 1;
1097 /* Match minutes using alternate numeric symbols. */
1098 get_alt_number (0, 59, 2);
1102 /* Match seconds using alternate numeric symbols. */
1103 get_alt_number (0, 61, 2);
1107 get_alt_number (0, 53, 2);
1112 get_alt_number (0, 53, 2);
1117 get_alt_number (0, 53, 2);
1118 /* XXX This cannot determine any field in TM without
1119 further information. */
1122 /* Match number of weekday using alternate numeric symbols. */
1123 get_alt_number (0, 6, 1);
1128 /* Match year within century using alternate numeric symbols. */
1129 get_alt_number (0, 99, 2);
1130 tm
->tm_year
= val
>= 69 ? val
: val
+ 100;
1144 /* Recursive invocation, returning success, so
1145 update parent's struct tm and state. */
1146 *(struct __strptime_state
*) statep
= s
;
1151 if (s
.have_I
&& s
.is_pm
)
1154 if (s
.century
!= -1)
1157 tm
->tm_year
= tm
->tm_year
% 100 + (s
.century
- 19) * 100;
1159 /* Only the century, but not the year. Strange, but so be it. */
1160 tm
->tm_year
= (s
.century
- 19) * 100;
1163 if (s
.era_cnt
!= -1)
1165 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
1169 tm
->tm_year
= (era
->start_date
[0]
1170 + ((tm
->tm_year
- era
->offset
)
1171 * era
->absolute_direction
));
1173 /* Era start year assumed. */
1174 tm
->tm_year
= era
->start_date
[0];
1179 /* No era found but we have seen an E modifier. Rectify some
1181 if (s
.want_century
&& s
.century
== -1 && tm
->tm_year
< 69)
1185 if (s
.want_xday
&& !s
.have_wday
)
1187 if ( !(s
.have_mon
&& s
.have_mday
) && s
.have_yday
)
1189 /* We don't have tm_mon and/or tm_mday, compute them. */
1191 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
] <= tm
->tm_yday
)
1194 tm
->tm_mon
= t_mon
- 1;
1198 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1202 /* Don't crash in day_of_the_week if tm_mon is uninitialized. */
1203 if (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11)
1204 day_of_the_week (tm
);
1207 if (s
.want_xday
&& !s
.have_yday
&& (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11))
1208 day_of_the_year (tm
);
1210 if ((s
.have_uweek
|| s
.have_wweek
) && s
.have_wday
)
1212 int save_wday
= tm
->tm_wday
;
1213 int save_mday
= tm
->tm_mday
;
1214 int save_mon
= tm
->tm_mon
;
1215 int w_offset
= s
.have_uweek
? 0 : 1;
1219 day_of_the_week (tm
);
1221 tm
->tm_mday
= save_mday
;
1223 tm
->tm_mon
= save_mon
;
1226 tm
->tm_yday
= ((7 - (tm
->tm_wday
- w_offset
)) % 7
1227 + (s
.week_no
- 1) * 7
1228 + (save_wday
- w_offset
+ 7) % 7);
1230 if (!s
.have_mday
|| !s
.have_mon
)
1233 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
]
1237 tm
->tm_mon
= t_mon
- 1;
1241 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1244 tm
->tm_wday
= save_wday
;
1252 strptime (const char *buf
, const char *format
, struct tm
*tm LOCALE_PARAM
)
1254 return __strptime_internal (buf
, format
, tm
, NULL LOCALE_ARG
);
1258 weak_alias (__strptime_l
, strptime_l
)