~ubuntu-branches/debian/jessie/lftp/jessie

« back to all changes in this revision

Viewing changes to lib/strptime.c

  • Committer: Bazaar Package Importer
  • Author(s): Noèl Köthe
  • Date: 2004-06-01 04:01:39 UTC
  • Revision ID: james.westby@ubuntu.com-20040601040139-negt39q17jhkv3i4
Tags: upstream-3.0.5
Import upstream version 3.0.5

Show diffs side-by-side

added added

removed removed

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