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