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