]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/strptime.c
Update.
[thirdparty/glibc.git] / time / strptime.c
CommitLineData
5290baf0 1/* Convert a string representation of time to a time value.
50304ef0 2 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
8a4b65b4
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
f8adc70c 5
8a4b65b4
UD
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.
f8adc70c 10
8a4b65b4
UD
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.
f8adc70c 15
8a4b65b4
UD
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. */
f8adc70c 20
5290baf0
UD
21/* XXX This version of the implementation is not really complete.
22 Some of the fields cannot add information alone. But if seeing
23 some of them in the same format (such as year, week and weekday)
24 this is enough information for determining the date. */
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
f8adc70c
RM
30#include <ctype.h>
31#include <langinfo.h>
32#include <limits.h>
33#include <string.h>
34#include <time.h>
35
5290baf0
UD
36#ifdef _LIBC
37# include "../locale/localeinfo.h"
38#endif
39
40
41#ifndef __P
42# if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
43# define __P(args) args
44# else
45# define __P(args) ()
46# endif /* GCC. */
47#endif /* Not __P. */
48
49#if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
50#ifdef _LIBC
51#define localtime_r __localtime_r
52#else
53/* Approximate localtime_r as best we can in its absence. */
54#define localtime_r my_localtime_r
55static struct tm *localtime_r __P ((const time_t *, struct tm *));
56static struct tm *
57localtime_r (t, tp)
58 const time_t *t;
59 struct tm *tp;
60{
61 struct tm *l = localtime (t);
62 if (! l)
63 return 0;
64 *tp = *l;
65 return tp;
66}
67#endif /* ! _LIBC */
68#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
f8adc70c
RM
69
70
71#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
5290baf0
UD
72#if defined __GNUC__ && __GNUC__ >= 2
73# define match_string(cs1, s2) \
f8adc70c 74 ({ size_t len = strlen (cs1); \
5290baf0
UD
75 int result = strncasecmp ((cs1), (s2), len) == 0; \
76 if (result) (s2) += len; \
f8adc70c 77 result; })
5290baf0
UD
78#else
79/* Oh come on. Get a reasonable compiler. */
80# define match_string(cs1, s2) \
81 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
82#endif
f8adc70c
RM
83/* We intentionally do not use isdigit() for testing because this will
84 lead to problems with the wide character version. */
5290baf0 85#define get_number(from, to) \
f8adc70c
RM
86 do { \
87 val = 0; \
88 if (*rp < '0' || *rp > '9') \
89 return NULL; \
90 do { \
91 val *= 10; \
92 val += *rp++ - '0'; \
93 } while (val * 10 <= to && *rp >= '0' && *rp <= '9'); \
94 if (val < from || val > to) \
95 return NULL; \
96 } while (0)
5290baf0
UD
97#ifdef _NL_CURRENT
98# define get_alt_number(from, to) \
f8adc70c 99 do { \
5290baf0 100 if (*decided != raw) \
f8adc70c 101 { \
5290baf0
UD
102 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
103 val = 0; \
104 while (*alts != '\0') \
105 { \
106 size_t len = strlen (alts); \
107 if (strncasecmp (alts, rp, len) == 0) \
108 break; \
109 alts = strchr (alts, '\0') + 1; \
110 ++val; \
111 } \
112 if (*alts == '\0') \
113 { \
114 if (*decided == loc && val != 0) \
115 return NULL; \
116 } \
117 else \
118 { \
119 *decided = loc; \
120 break; \
121 } \
f8adc70c 122 } \
5290baf0 123 get_number (from, to); \
f8adc70c 124 } while (0)
5290baf0
UD
125#else
126# define get_alt_number(from, to) \
127 /* We don't have the alternate representation. */ \
128 get_number(from, to)
129#endif
130#define recursive(new_fmt) \
131 (*(new_fmt) != '\0' \
0d8733c4 132 && (rp = strptime_internal (rp, (new_fmt), tm, decided)) != NULL)
d41c6f61 133
f8adc70c 134
5290baf0
UD
135#ifdef _LIBC
136/* This is defined in locale/C-time.c in the GNU libc. */
137extern const struct locale_data _nl_C_LC_TIME;
138
139# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
140# define ab_weekday_name \
141 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
142# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
143# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
144# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
655b26bb 145# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
5290baf0
UD
146# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
147# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
148# define HERE_T_FMT_AMPM \
149 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
150# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
50304ef0
UD
151
152# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
5290baf0
UD
153#else
154static char const weekday_name[][10] =
155 {
156 "Sunday", "Monday", "Tuesday", "Wednesday",
157 "Thursday", "Friday", "Saturday"
158 };
159static char const ab_weekday_name[][4] =
160 {
161 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
162 };
163static char const month_name[][10] =
164 {
165 "January", "February", "March", "April", "May", "June",
166 "July", "August", "September", "October", "November", "December"
167 };
168static char const ab_month_name[][4] =
169 {
170 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
171 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
172 };
173# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
174# define HERE_D_FMT "%m/%d/%y"
175# define HERE_AM_STR "AM"
176# define HERE_PM_STR "PM"
177# define HERE_T_FMT_AMPM "%I:%M:%S %p"
178# define HERE_T_FMT "%H:%M:%S"
179#endif
180
181/* Status of lookup: do we use the locale data or the raw data? */
182enum locale_status { not, loc, raw };
183
0c5ecdc4 184static char *
dfd2257a
UD
185#ifdef _LIBC
186internal_function
187#endif
0c5ecdc4
UD
188strptime_internal __P ((const char *buf, const char *format, struct tm *tm,
189 enum locale_status *decided));
5290baf0
UD
190
191static char *
dfd2257a
UD
192#ifdef _LIBC
193internal_function
194#endif
5290baf0
UD
195strptime_internal (buf, format, tm, decided)
196 const char *buf;
197 const char *format;
198 struct tm *tm;
199 enum locale_status *decided;
f8adc70c
RM
200{
201 const char *rp;
202 const char *fmt;
203 int cnt;
204 size_t val;
205 int have_I, is_pm;
a6ff34d7 206 int century, want_century;
f8adc70c
RM
207
208 rp = buf;
209 fmt = format;
210 have_I = is_pm = 0;
a6ff34d7
UD
211 century = -1;
212 want_century = 0;
f8adc70c
RM
213
214 while (*fmt != '\0')
215 {
216 /* A white space in the format string matches 0 more or white
217 space in the input string. */
218 if (isspace (*fmt))
219 {
220 while (isspace (*rp))
221 ++rp;
222 ++fmt;
223 continue;
224 }
225
226 /* Any character but `%' must be matched by the same character
227 in the iput string. */
228 if (*fmt != '%')
229 {
230 match_char (*fmt++, *rp++);
231 continue;
232 }
233
234 ++fmt;
5290baf0
UD
235#ifndef _NL_CURRENT
236 /* We need this for handling the `E' modifier. */
237 start_over:
238#endif
f8adc70c
RM
239 switch (*fmt++)
240 {
241 case '%':
242 /* Match the `%' character itself. */
243 match_char ('%', *rp++);
244 break;
245 case 'a':
246 case 'A':
247 /* Match day of week. */
248 for (cnt = 0; cnt < 7; ++cnt)
249 {
5290baf0
UD
250#ifdef _NL_CURRENT
251 if (*decided !=raw)
252 {
0d8733c4 253 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
5290baf0
UD
254 {
255 if (*decided == not
0d8733c4
UD
256 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
257 weekday_name[cnt]))
5290baf0
UD
258 *decided = loc;
259 break;
260 }
0d8733c4 261 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
5290baf0
UD
262 {
263 if (*decided == not
0d8733c4
UD
264 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
265 ab_weekday_name[cnt]))
5290baf0
UD
266 *decided = loc;
267 break;
268 }
269 }
270#endif
271 if (*decided != loc
0d8733c4
UD
272 && (match_string (weekday_name[cnt], rp)
273 || match_string (ab_weekday_name[cnt], rp)))
5290baf0
UD
274 {
275 *decided = raw;
276 break;
277 }
f8adc70c
RM
278 }
279 if (cnt == 7)
280 /* Does not match a weekday name. */
281 return NULL;
282 tm->tm_wday = cnt;
283 break;
284 case 'b':
285 case 'B':
286 case 'h':
287 /* Match month name. */
288 for (cnt = 0; cnt < 12; ++cnt)
289 {
5290baf0
UD
290#ifdef _NL_CURRENT
291 if (*decided !=raw)
292 {
0d8733c4 293 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
5290baf0
UD
294 {
295 if (*decided == not
0d8733c4
UD
296 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
297 month_name[cnt]))
5290baf0
UD
298 *decided = loc;
299 break;
300 }
0d8733c4 301 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
5290baf0
UD
302 {
303 if (*decided == not
0d8733c4
UD
304 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
305 ab_month_name[cnt]))
5290baf0
UD
306 *decided = loc;
307 break;
308 }
309 }
310#endif
0d8733c4
UD
311 if (match_string (month_name[cnt], rp)
312 || match_string (ab_month_name[cnt], rp))
5290baf0
UD
313 {
314 *decided = raw;
315 break;
316 }
f8adc70c
RM
317 }
318 if (cnt == 12)
319 /* Does not match a month name. */
320 return NULL;
321 tm->tm_mon = cnt;
322 break;
323 case 'c':
324 /* Match locale's date and time format. */
5290baf0
UD
325#ifdef _NL_CURRENT
326 if (*decided != raw)
327 {
328 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
329 {
330 if (*decided == loc)
331 return NULL;
332 }
333 else
334 {
335 if (*decided == not &&
336 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
337 *decided = loc;
338 break;
339 }
340 *decided = raw;
341 }
342#endif
343 if (!recursive (HERE_D_T_FMT))
344 return NULL;
f8adc70c
RM
345 break;
346 case 'C':
347 /* Match century number. */
348 get_number (0, 99);
a6ff34d7 349 century = val;
f8adc70c
RM
350 break;
351 case 'd':
352 case 'e':
353 /* Match day of month. */
354 get_number (1, 31);
355 tm->tm_mday = val;
356 break;
5290baf0
UD
357 case 'x':
358#ifdef _NL_CURRENT
359 if (*decided != raw)
360 {
361 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
362 {
363 if (*decided == loc)
364 return NULL;
365 }
366 else
367 {
368 if (decided == not
369 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
370 *decided = loc;
371 break;
372 }
373 *decided = raw;
374 }
375#endif
376 /* Fall through. */
f8adc70c
RM
377 case 'D':
378 /* Match standard day format. */
5290baf0
UD
379 if (!recursive (HERE_D_FMT))
380 return NULL;
f8adc70c
RM
381 break;
382 case 'H':
383 /* Match hour in 24-hour clock. */
384 get_number (0, 23);
385 tm->tm_hour = val;
386 have_I = 0;
387 break;
388 case 'I':
389 /* Match hour in 12-hour clock. */
390 get_number (1, 12);
779ae82e 391 tm->tm_hour = val % 12;
f8adc70c
RM
392 have_I = 1;
393 break;
394 case 'j':
395 /* Match day number of year. */
396 get_number (1, 366);
397 tm->tm_yday = val - 1;
398 break;
399 case 'm':
400 /* Match number of month. */
401 get_number (1, 12);
402 tm->tm_mon = val - 1;
403 break;
404 case 'M':
405 /* Match minute. */
406 get_number (0, 59);
407 tm->tm_min = val;
408 break;
409 case 'n':
410 case 't':
411 /* Match any white space. */
412 while (isspace (*rp))
413 ++rp;
414 break;
415 case 'p':
416 /* Match locale's equivalent of AM/PM. */
5290baf0
UD
417#ifdef _NL_CURRENT
418 if (*decided != raw)
f8adc70c 419 {
5290baf0
UD
420 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
421 {
422 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
423 *decided = loc;
424 break;
425 }
426 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
427 {
428 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
429 *decided = loc;
430 is_pm = 1;
431 break;
432 }
433 *decided = raw;
f8adc70c 434 }
5290baf0
UD
435#endif
436 if (!match_string (HERE_AM_STR, rp))
437 if (match_string (HERE_PM_STR, rp))
438 is_pm = 1;
439 else
440 return NULL;
441 break;
f8adc70c 442 case 'r':
5290baf0
UD
443#ifdef _NL_CURRENT
444 if (*decided != raw)
445 {
446 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
447 {
448 if (*decided == loc)
449 return NULL;
450 }
451 else
452 {
453 if (*decided == not &&
454 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
455 HERE_T_FMT_AMPM))
456 *decided = loc;
457 break;
458 }
459 *decided = raw;
460 }
461#endif
462 if (!recursive (HERE_T_FMT_AMPM))
463 return NULL;
f8adc70c
RM
464 break;
465 case 'R':
5290baf0
UD
466 if (!recursive ("%H:%M"))
467 return NULL;
f8adc70c 468 break;
d41c6f61
UD
469 case 's':
470 {
471 /* The number of seconds may be very high so we cannot use
472 the `get_number' macro. Instead read the number
473 character for character and construct the result while
474 doing this. */
475 time_t secs;
476 if (*rp < '0' || *rp > '9')
477 /* We need at least one digit. */
478 return NULL;
479
480 do
481 {
482 secs *= 10;
483 secs += *rp++ - '0';
484 }
485 while (*rp >= '0' && *rp <= '9');
486
5290baf0 487 if (localtime_r (&secs, tm) == NULL)
d41c6f61
UD
488 /* Error in function. */
489 return NULL;
490 }
491 break;
f8adc70c
RM
492 case 'S':
493 get_number (0, 61);
494 tm->tm_sec = val;
495 break;
5290baf0
UD
496 case 'X':
497#ifdef _NL_CURRENT
498 if (*decided != raw)
499 {
500 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
501 {
502 if (*decided == loc)
503 return NULL;
504 }
505 else
506 {
507 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
508 *decided = loc;
509 break;
510 }
511 *decided = raw;
512 }
513#endif
514 /* Fall through. */
f8adc70c 515 case 'T':
5290baf0
UD
516 if (!recursive (HERE_T_FMT))
517 return NULL;
f8adc70c 518 break;
d41c6f61
UD
519 case 'u':
520 get_number (1, 7);
521 tm->tm_wday = val % 7;
522 break;
523 case 'g':
524 get_number (0, 99);
525 /* XXX This cannot determine any field in TM. */
526 break;
527 case 'G':
528 if (*rp < '0' || *rp > '9')
529 return NULL;
530 /* XXX Ignore the number since we would need some more
531 information to compute a real date. */
532 do
533 ++rp;
534 while (*rp >= '0' && *rp <= '9');
535 break;
f8adc70c
RM
536 case 'U':
537 case 'V':
538 case 'W':
539 get_number (0, 53);
5290baf0
UD
540 /* XXX This cannot determine any field in TM without some
541 information. */
f8adc70c
RM
542 break;
543 case 'w':
544 /* Match number of weekday. */
545 get_number (0, 6);
546 tm->tm_wday = val;
547 break;
f8adc70c
RM
548 case 'y':
549 /* Match year within century. */
550 get_number (0, 99);
1cab5444
UD
551 /* The "Year 2000 :The Millennium Rollover" paper suggests that
552 values in the range 69-99 refer to the twentieth century. */
553 tm->tm_year = val >= 69 ? val : val + 100;
a6ff34d7
UD
554 /* Indicate that we want to use the century, if specified
555 want_century = 1;
f8adc70c
RM
556 break;
557 case 'Y':
558 /* Match year including century number. */
1618c590 559 get_number (0, 9999);
0d8733c4 560 tm->tm_year = val - 1900;
a6ff34d7 561 want_century = 0;
f8adc70c
RM
562 break;
563 case 'Z':
564 /* XXX How to handle this? */
565 break;
566 case 'E':
5290baf0 567#ifdef _NL_CURRENT
f8adc70c
RM
568 switch (*fmt++)
569 {
570 case 'c':
571 /* Match locale's alternate date and time format. */
5290baf0
UD
572 if (*decided != raw)
573 {
574 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
575
576 if (*fmt == '\0')
577 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
578
579 if (!recursive (fmt))
580 {
581 if (*decided == loc)
582 return NULL;
583 }
584 else
585 {
586 if (strcmp (fmt, HERE_D_T_FMT))
587 *decided = loc;
588 break;
589 }
590 *decided = raw;
591 }
592 /* The C locale has no era information, so use the
593 normal representation. */
594 if (!recursive (HERE_D_T_FMT))
595 return NULL;
f8adc70c
RM
596 break;
597 case 'C':
598 case 'y':
599 case 'Y':
600 /* Match name of base year in locale's alternate
601 representation. */
602 /* XXX This is currently not implemented. It should
5290baf0 603 use the value _NL_CURRENT (LC_TIME, ERA). */
f8adc70c
RM
604 break;
605 case 'x':
5290baf0
UD
606 if (*decided != raw)
607 {
608 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
609
610 if (*fmt == '\0')
611 fmt = _NL_CURRENT (LC_TIME, D_FMT);
612
613 if (!recursive (fmt))
614 {
615 if (*decided == loc)
616 return NULL;
617 }
618 else
619 {
620 if (strcmp (fmt, HERE_D_FMT))
621 *decided = loc;
622 break;
623 }
624 *decided = raw;
625 }
626 if (!recursive (HERE_D_FMT))
627 return NULL;
f8adc70c
RM
628 break;
629 case 'X':
5290baf0
UD
630 if (*decided != raw)
631 {
632 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
633
634 if (*fmt == '\0')
635 fmt = _NL_CURRENT (LC_TIME, T_FMT);
636
637 if (!recursive (fmt))
638 {
639 if (*decided == loc)
640 return NULL;
641 }
642 else
643 {
644 if (strcmp (fmt, HERE_T_FMT))
645 *decided = loc;
646 break;
647 }
648 *decided = raw;
649 }
650 if (!recursive (HERE_T_FMT))
651 return NULL;
f8adc70c
RM
652 break;
653 default:
654 return NULL;
655 }
656 break;
5290baf0
UD
657#else
658 /* We have no information about the era format. Just use
659 the normal format. */
660 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
661 && *fmt != 'x' && *fmt != 'X')
662 /* This is an illegal format. */
663 return NULL;
664
665 goto start_over;
666#endif
f8adc70c
RM
667 case 'O':
668 switch (*fmt++)
669 {
670 case 'd':
671 case 'e':
672 /* Match day of month using alternate numeric symbols. */
673 get_alt_number (1, 31);
674 tm->tm_mday = val;
675 break;
676 case 'H':
677 /* Match hour in 24-hour clock using alternate numeric
678 symbols. */
679 get_alt_number (0, 23);
680 tm->tm_hour = val;
681 have_I = 0;
682 break;
683 case 'I':
684 /* Match hour in 12-hour clock using alternate numeric
685 symbols. */
686 get_alt_number (1, 12);
687 tm->tm_hour = val - 1;
688 have_I = 1;
689 break;
690 case 'm':
691 /* Match month using alternate numeric symbols. */
692 get_alt_number (1, 12);
693 tm->tm_mon = val - 1;
694 break;
695 case 'M':
696 /* Match minutes using alternate numeric symbols. */
697 get_alt_number (0, 59);
698 tm->tm_min = val;
699 break;
700 case 'S':
701 /* Match seconds using alternate numeric symbols. */
702 get_alt_number (0, 61);
703 tm->tm_sec = val;
704 break;
705 case 'U':
706 case 'V':
707 case 'W':
708 get_alt_number (0, 53);
5290baf0
UD
709 /* XXX This cannot determine any field in TM without
710 further information. */
f8adc70c
RM
711 break;
712 case 'w':
713 /* Match number of weekday using alternate numeric symbols. */
714 get_alt_number (0, 6);
715 tm->tm_wday = val;
716 break;
717 case 'y':
718 /* Match year within century using alternate numeric symbols. */
719 get_alt_number (0, 99);
1618c590 720 tm->tm_year = val >= 69 ? val : val + 100;
f8adc70c
RM
721 break;
722 default:
723 return NULL;
724 }
725 break;
726 default:
727 return NULL;
728 }
729 }
730
731 if (have_I && is_pm)
732 tm->tm_hour += 12;
d41c6f61 733
a6ff34d7
UD
734 if (want_century && century != -1)
735 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
736
f8adc70c
RM
737 return (char *) rp;
738}
5290baf0
UD
739
740
741char *
742strptime (buf, format, tm)
743 const char *buf;
744 const char *format;
745 struct tm *tm;
746{
747 enum locale_status decided;
748#ifdef _NL_CURRENT
749 decided = not;
750#else
751 decided = raw;
752#endif
753 return strptime_internal (buf, format, tm, &decided);
754}