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