1 /* strptime - Convert a string representation of time to a time value.
2 Copyright (C) 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
27 #include "../locale/localeinfo.h"
30 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
31 #define match_string(cs1, s2) \
32 ({ size_t len = strlen (cs1); \
33 int result = strncasecmp (cs1, s2, len) == 0; \
34 if (result) s2 += len; \
36 /* We intentionally do not use isdigit() for testing because this will
37 lead to problems with the wide character version. */
38 #define get_number(from, to) \
41 if (*rp < '0' || *rp > '9') \
46 } while (val * 10 <= to && *rp >= '0' && *rp <= '9'); \
47 if (val < from || val > to) \
50 #define get_alt_number(from, to) \
52 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
54 while (*alts != '\0') \
56 size_t len = strlen (alts); \
57 if (strncasecmp (alts, rp, len) == 0) \
59 alts = strchr (alts, '\0') + 1; \
65 #define recursive(new_fmt) \
67 if (*new_fmt == '\0') \
69 rp = strptime (rp, new_fmt, tm); \
76 strptime (const char *buf
, const char *format
, struct tm
*tm
)
90 /* A white space in the format string matches 0 more or white
91 space in the input string. */
100 /* Any character but `%' must be matched by the same character
101 in the iput string. */
104 match_char (*fmt
++, *rp
++);
112 /* Match the `%' character itself. */
113 match_char ('%', *rp
++);
117 /* Match day of week. */
118 for (cnt
= 0; cnt
< 7; ++cnt
)
120 if (match_string (_NL_CURRENT (LC_TIME
, ABDAY_1
+ cnt
), rp
))
122 if (match_string (_NL_CURRENT (LC_TIME
, DAY_1
+ cnt
), rp
))
126 /* Does not match a weekday name. */
133 /* Match month name. */
134 for (cnt
= 0; cnt
< 12; ++cnt
)
136 if (match_string (_NL_CURRENT (LC_TIME
, ABMON_1
+ cnt
), rp
))
138 if (match_string (_NL_CURRENT (LC_TIME
, MON_1
+ cnt
), rp
))
142 /* Does not match a month name. */
147 /* Match locale's date and time format. */
148 recursive (_NL_CURRENT (LC_TIME
, D_T_FMT
));
151 /* Match century number. */
153 /* We don't need the number. */
157 /* Match day of month. */
162 /* Match standard day format. */
163 recursive ("%m/%d/%y");
166 /* Match hour in 24-hour clock. */
172 /* Match hour in 12-hour clock. */
174 tm
->tm_hour
= val
- 1;
178 /* Match day number of year. */
180 tm
->tm_yday
= val
- 1;
183 /* Match number of month. */
185 tm
->tm_mon
= val
- 1;
194 /* Match any white space. */
195 while (isspace (*rp
))
199 /* Match locale's equivalent of AM/PM. */
200 if (match_string (_NL_CURRENT (LC_TIME
, AM_STR
), rp
))
202 if (match_string (_NL_CURRENT (LC_TIME
, PM_STR
), rp
))
209 recursive (_NL_CURRENT (LC_TIME
, T_FMT_AMPM
));
216 /* The number of seconds may be very high so we cannot use
217 the `get_number' macro. Instead read the number
218 character for character and construct the result while
221 if (*rp
< '0' || *rp
> '9')
222 /* We need at least one digit. */
230 while (*rp
>= '0' && *rp
<= '9');
232 if (__localtime_r (&secs
, tm
) == NULL
)
233 /* Error in function. */
242 recursive ("%H:%M:%S");
246 tm
->tm_wday
= val
% 7;
250 /* XXX This cannot determine any field in TM. */
253 if (*rp
< '0' || *rp
> '9')
255 /* XXX Ignore the number since we would need some more
256 information to compute a real date. */
259 while (*rp
>= '0' && *rp
<= '9');
265 /* XXX This cannot determine any field in TM. */
268 /* Match number of weekday. */
273 recursive (_NL_CURRENT (LC_TIME
, D_FMT
));
276 recursive (_NL_CURRENT (LC_TIME
, T_FMT
));
279 /* Match year within century. */
284 /* Match year including century number. */
285 get_number (0, INT_MAX
);
286 tm
->tm_year
= val
- (val
>= 2000 ? 2000 : 1900);
289 /* XXX How to handle this? */
295 /* Match locale's alternate date and time format. */
296 recursive (_NL_CURRENT (LC_TIME
, ERA_D_T_FMT
));
301 /* Match name of base year in locale's alternate
303 /* XXX This is currently not implemented. It should
304 use the value _NL_CURRENT (LC_TIME, ERA) but POSIX
305 leaves this implementation defined and we haven't
306 figured out how to do it yet. */
309 recursive (_NL_CURRENT (LC_TIME
, ERA_D_FMT
));
312 recursive (_NL_CURRENT (LC_TIME
, ERA_T_FMT
));
323 /* Match day of month using alternate numeric symbols. */
324 get_alt_number (1, 31);
328 /* Match hour in 24-hour clock using alternate numeric
330 get_alt_number (0, 23);
335 /* Match hour in 12-hour clock using alternate numeric
337 get_alt_number (1, 12);
338 tm
->tm_hour
= val
- 1;
342 /* Match month using alternate numeric symbols. */
343 get_alt_number (1, 12);
344 tm
->tm_mon
= val
- 1;
347 /* Match minutes using alternate numeric symbols. */
348 get_alt_number (0, 59);
352 /* Match seconds using alternate numeric symbols. */
353 get_alt_number (0, 61);
359 get_alt_number (0, 53);
360 /* XXX This cannot determine any field in TM. */
363 /* Match number of weekday using alternate numeric symbols. */
364 get_alt_number (0, 6);
368 /* Match year within century using alternate numeric symbols. */
369 get_alt_number (0, 99);