1 /* Copyright (C) 2002-2018 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 # 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 iput 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
)
498 if (s
.decided
== not &&
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
)
644 if (s
.decided
== not &&
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
);
911 && delta
< (((int64_t) era
->stop_date
[0]
912 - (int64_t) era
->start_date
[0])
913 * era
->absolute_direction
));
921 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
922 _NL_TIME_ERA_NUM_ENTRIES
);
923 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
; ++s
.era_cnt
)
925 era
= _nl_select_era_entry (s
.era_cnt
929 int delta
= ((tm
->tm_year
- era
->offset
)
930 * era
->absolute_direction
);
932 && delta
< (((int64_t) era
->stop_date
[0]
933 - (int64_t) era
->start_date
[0])
934 * era
->absolute_direction
))
941 if (s
.era_cnt
!= (int) num_eras
)
945 if (s
.decided
== loc
)
951 goto match_year_in_century
;
953 if (s
.decided
!= raw
)
955 num_eras
= _NL_CURRENT_WORD (LC_TIME
,
956 _NL_TIME_ERA_NUM_ENTRIES
);
957 for (s
.era_cnt
= 0; s
.era_cnt
< (int) num_eras
;
958 ++s
.era_cnt
, rp
= rp_backup
)
960 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
961 if (era
!= NULL
&& recursive (era
->era_format
))
964 if (s
.era_cnt
== (int) num_eras
)
967 if (s
.decided
== loc
)
980 get_number (0, 9999, 4);
981 tm
->tm_year
= val
- 1900;
986 if (s
.decided
!= raw
)
988 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
);
991 fmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
993 if (!recursive (fmt
))
995 if (s
.decided
== loc
)
1002 if (strcmp (fmt
, HERE_D_FMT
))
1008 if (!recursive (HERE_D_FMT
))
1012 if (s
.decided
!= raw
)
1014 const char *fmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
);
1017 fmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
1019 if (!recursive (fmt
))
1021 if (s
.decided
== loc
)
1028 if (strcmp (fmt
, HERE_T_FMT
))
1034 if (!recursive (HERE_T_FMT
))
1042 /* We have no information about the era format. Just use
1043 the normal format. */
1044 if (*fmt
!= 'c' && *fmt
!= 'C' && *fmt
!= 'y' && *fmt
!= 'Y'
1045 && *fmt
!= 'x' && *fmt
!= 'X')
1046 /* This is an illegal format. */
1057 /* Match month name. Reprocess as plain 'B'. */
1062 /* Match day of month using alternate numeric symbols. */
1063 get_alt_number (1, 31, 2);
1069 /* Match hour in 24-hour clock using alternate numeric
1071 get_alt_number (0, 23, 2);
1076 /* Match hour in 12-hour clock using alternate numeric
1078 get_alt_number (1, 12, 2);
1079 tm
->tm_hour
= val
% 12;
1083 /* Match month using alternate numeric symbols. */
1084 get_alt_number (1, 12, 2);
1085 tm
->tm_mon
= val
- 1;
1090 /* Match minutes using alternate numeric symbols. */
1091 get_alt_number (0, 59, 2);
1095 /* Match seconds using alternate numeric symbols. */
1096 get_alt_number (0, 61, 2);
1100 get_alt_number (0, 53, 2);
1105 get_alt_number (0, 53, 2);
1110 get_alt_number (0, 53, 2);
1111 /* XXX This cannot determine any field in TM without
1112 further information. */
1115 /* Match number of weekday using alternate numeric symbols. */
1116 get_alt_number (0, 6, 1);
1121 /* Match year within century using alternate numeric symbols. */
1122 get_alt_number (0, 99, 2);
1123 tm
->tm_year
= val
>= 69 ? val
: val
+ 100;
1137 /* Recursive invocation, returning success, so
1138 update parent's struct tm and state. */
1139 *(struct __strptime_state
*) statep
= s
;
1144 if (s
.have_I
&& s
.is_pm
)
1147 if (s
.century
!= -1)
1150 tm
->tm_year
= tm
->tm_year
% 100 + (s
.century
- 19) * 100;
1152 /* Only the century, but not the year. Strange, but so be it. */
1153 tm
->tm_year
= (s
.century
- 19) * 100;
1156 if (s
.era_cnt
!= -1)
1158 era
= _nl_select_era_entry (s
.era_cnt HELPER_LOCALE_ARG
);
1162 tm
->tm_year
= (era
->start_date
[0]
1163 + ((tm
->tm_year
- era
->offset
)
1164 * era
->absolute_direction
));
1166 /* Era start year assumed. */
1167 tm
->tm_year
= era
->start_date
[0];
1172 /* No era found but we have seen an E modifier. Rectify some
1174 if (s
.want_century
&& s
.century
== -1 && tm
->tm_year
< 69)
1178 if (s
.want_xday
&& !s
.have_wday
)
1180 if ( !(s
.have_mon
&& s
.have_mday
) && s
.have_yday
)
1182 /* We don't have tm_mon and/or tm_mday, compute them. */
1184 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
] <= tm
->tm_yday
)
1187 tm
->tm_mon
= t_mon
- 1;
1191 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1195 /* Don't crash in day_of_the_week if tm_mon is uninitialized. */
1196 if (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11)
1197 day_of_the_week (tm
);
1200 if (s
.want_xday
&& !s
.have_yday
&& (s
.have_mon
|| (unsigned) tm
->tm_mon
<= 11))
1201 day_of_the_year (tm
);
1203 if ((s
.have_uweek
|| s
.have_wweek
) && s
.have_wday
)
1205 int save_wday
= tm
->tm_wday
;
1206 int save_mday
= tm
->tm_mday
;
1207 int save_mon
= tm
->tm_mon
;
1208 int w_offset
= s
.have_uweek
? 0 : 1;
1212 day_of_the_week (tm
);
1214 tm
->tm_mday
= save_mday
;
1216 tm
->tm_mon
= save_mon
;
1219 tm
->tm_yday
= ((7 - (tm
->tm_wday
- w_offset
)) % 7
1220 + (s
.week_no
- 1) * 7
1221 + (save_wday
- w_offset
+ 7) % 7);
1223 if (!s
.have_mday
|| !s
.have_mon
)
1226 while (__mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
]
1230 tm
->tm_mon
= t_mon
- 1;
1234 - __mon_yday
[__isleap(1900 + tm
->tm_year
)][t_mon
- 1] + 1);
1237 tm
->tm_wday
= save_wday
;
1245 strptime (const char *buf
, const char *format
, struct tm
*tm LOCALE_PARAM
)
1247 return __strptime_internal (buf
, format
, tm
, NULL LOCALE_ARG
);
1251 weak_alias (__strptime_l
, strptime_l
)