Tue May 14 20:18:38 1996 Ulrich Drepper <drepper@cygnus.com>
authorroland <roland>
Wed, 15 May 1996 15:49:02 +0000 (15:49 +0000)
committerroland <roland>
Wed, 15 May 1996 15:49:02 +0000 (15:49 +0000)
* time/Makefile (routines): Add strptime.
* time/time.h: Add prototype for strptime.
* time/strptime.c: New file.  Implementation according to XPG4.

time/strptime.c [new file with mode: 0644]

diff --git a/time/strptime.c b/time/strptime.c
new file mode 100644 (file)
index 0000000..cb3d126
--- /dev/null
@@ -0,0 +1,344 @@
+/* strptime - Convert a string representation of time to a time value.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include <ctype.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <string.h>
+#include <time.h>
+
+#include "../locale/localeinfo.h"
+
+
+#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
+#define match_string(cs1, s2)                                                \
+  ({ size_t len = strlen (cs1);                                                      \
+     int result = strncasecmp (cs1, s2, len) == 0;                           \
+     if (result) s2 += len;                                                  \
+     result; })
+/* We intentionally do not use isdigit() for testing because this will
+   lead to problems with the wide character version.  */
+#define get_number(from, to)                                                 \
+  do {                                                                       \
+    val = 0;                                                                 \
+    if (*rp < '0' || *rp > '9')                                                      \
+      return NULL;                                                           \
+    do {                                                                     \
+      val *= 10;                                                             \
+      val += *rp++ - '0';                                                    \
+    } while (val * 10 <= to && *rp >= '0' && *rp <= '9');                    \
+    if (val < from || val > to)                                                      \
+      return NULL;                                                           \
+  } while (0)
+#define get_alt_number(from, to)                                             \
+  do {                                                                       \
+    const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS);                    \
+    val = 0;                                                                 \
+    while (*alts != '\0')                                                    \
+      {                                                                              \
+       size_t len = strlen (alts);                                           \
+       if (strncasecmp (alts, rp, len) == 0)                                 \
+         break;                                                              \
+       alts = strchr (alts, '\0') + 1;                                       \
+       ++val;                                                                \
+      }                                                                              \
+    if (*alts == '\0')                                                       \
+      return NULL;                                                           \
+  } while (0)
+#define recursive(new_fmt)                                                   \
+  do {                                                                       \
+    if (*new_fmt == '\0')                                                    \
+      return NULL;                                                           \
+    rp = strptime (rp, new_fmt, tm);                                         \
+    if (rp == NULL)                                                          \
+      return NULL;                                                           \
+  } while (0)
+  
+
+char *
+strptime (const char *buf, const char *format, struct tm *tm)
+{
+  const char *rp;
+  const char *fmt;
+  int cnt;
+  size_t val;
+  int have_I, is_pm;
+
+  rp = buf;
+  fmt = format;
+  have_I = is_pm = 0;
+
+  while (*fmt != '\0')
+    {
+      /* A white space in the format string matches 0 more or white
+        space in the input string.  */
+      if (isspace (*fmt))
+       {
+         while (isspace (*rp))
+           ++rp;
+         ++fmt;
+         continue;
+       }
+
+      /* Any character but `%' must be matched by the same character
+        in the iput string.  */
+      if (*fmt != '%')
+       {
+         match_char (*fmt++, *rp++);
+         continue;
+       }
+
+      ++fmt;
+      switch (*fmt++)
+       {
+       case '%':
+         /* Match the `%' character itself.  */
+         match_char ('%', *rp++);
+         break;
+       case 'a':
+       case 'A':
+         /* Match day of week.  */
+         for (cnt = 0; cnt < 7; ++cnt)
+           {
+             if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
+               break;
+             if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
+               break;
+           }
+         if (cnt == 7)
+           /* Does not match a weekday name.  */
+           return NULL;
+         tm->tm_wday = cnt;
+         break;
+       case 'b':
+       case 'B':
+       case 'h':
+         /* Match month name.  */
+         for (cnt = 0; cnt < 12; ++cnt)
+           {
+             if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
+               break;
+             if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
+               break;
+           }
+         if (cnt == 12)
+           /* Does not match a month name.  */
+           return NULL;
+         tm->tm_mon = cnt;
+         break;
+       case 'c':
+         /* Match locale's date and time format.  */
+         recursive (_NL_CURRENT (LC_TIME, D_T_FMT));
+         break;
+       case 'C':
+         /* Match century number.  */
+         get_number (0, 99);
+         /* We don't need the number.  */
+         break;
+       case 'd':
+       case 'e':
+         /* Match day of month.  */
+         get_number (1, 31);
+         tm->tm_mday = val;
+         break;
+       case 'D':
+         /* Match standard day format.  */
+         recursive ("%m/%d/%y");
+         break;
+       case 'H':
+         /* Match hour in 24-hour clock.  */
+         get_number (0, 23);
+         tm->tm_hour = val;
+         have_I = 0;
+         break;
+       case 'I':
+         /* Match hour in 12-hour clock.  */
+         get_number (1, 12);
+         tm->tm_hour = val - 1;
+         have_I = 1;
+         break;
+       case 'j':
+         /* Match day number of year.  */
+         get_number (1, 366);
+         tm->tm_yday = val - 1;
+         break;
+       case 'm':
+         /* Match number of month.  */
+         get_number (1, 12);
+         tm->tm_mon = val - 1;
+         break;
+       case 'M':
+         /* Match minute.  */
+         get_number (0, 59);
+         tm->tm_min = val;
+         break;
+       case 'n':
+       case 't':
+         /* Match any white space.  */
+         while (isspace (*rp))
+           ++rp;
+         break;
+       case 'p':
+         /* Match locale's equivalent of AM/PM.  */
+         if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
+           break;
+         if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
+           {
+             is_pm = 1;
+             break;
+           }
+         return NULL;
+       case 'r':
+         recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM));
+         break;
+       case 'R':
+         recursive ("%H:%M");
+         break;
+       case 'S':
+         get_number (0, 61);
+         tm->tm_sec = val;
+         break;
+       case 'T':
+         recursive ("%H:%M:%S");
+         break;
+       case 'U':
+       case 'V':
+       case 'W':
+         get_number (0, 53);
+         /* XXX This cannot determine any field in TM.  */
+         break;
+       case 'w':
+         /* Match number of weekday.  */
+         get_number (0, 6);
+         tm->tm_wday = val;
+         break;
+       case 'x':
+         recursive (_NL_CURRENT (LC_TIME, D_FMT));
+         break;
+       case 'X':
+         recursive (_NL_CURRENT (LC_TIME, T_FMT));
+         break;
+       case 'y':
+         /* Match year within century.  */
+         get_number (0, 99);
+         tm->tm_year = val;
+         break;
+       case 'Y':
+         /* Match year including century number.  */
+         get_number (0, INT_MAX);
+         tm->tm_year = val - (val >= 2000 ? 2000 : 1900);
+         break;
+       case 'Z':
+         /* XXX How to handle this?  */
+         break;
+       case 'E':
+         switch (*fmt++)
+           {
+           case 'c':
+             /* Match locale's alternate date and time format.  */
+             recursive (_NL_CURRENT (LC_TIME, ERA_D_T_FMT));
+             break;
+           case 'C':
+           case 'y':
+           case 'Y':
+             /* Match name of base year in locale's alternate
+                representation.  */
+             /* XXX This is currently not implemented.  It should
+                use the value _NL_CURRENT (LC_TIME, ERA) but POSIX
+                leaves this implementation defined and we haven't
+                figured out how to do it yet.  */
+             break;
+           case 'x':
+             recursive (_NL_CURRENT (LC_TIME, ERA_D_FMT));
+             break;
+           case 'X':
+             recursive (_NL_CURRENT (LC_TIME, ERA_T_FMT));
+             break;
+           default:
+             return NULL;
+           }
+         break;
+       case 'O':
+         switch (*fmt++)
+           {
+           case 'd':
+           case 'e':
+             /* Match day of month using alternate numeric symbols.  */
+             get_alt_number (1, 31);
+             tm->tm_mday = val;
+             break;
+           case 'H':
+             /* Match hour in 24-hour clock using alternate numeric
+                symbols.  */
+             get_alt_number (0, 23);
+             tm->tm_hour = val;
+             have_I = 0;
+             break;
+           case 'I':
+             /* Match hour in 12-hour clock using alternate numeric
+                symbols.  */
+             get_alt_number (1, 12);
+             tm->tm_hour = val - 1;
+             have_I = 1;
+             break;
+           case 'm':
+             /* Match month using alternate numeric symbols.  */
+             get_alt_number (1, 12);
+             tm->tm_mon = val - 1;
+             break;
+           case 'M':
+             /* Match minutes using alternate numeric symbols.  */
+             get_alt_number (0, 59);
+             tm->tm_min = val;
+             break;
+           case 'S':
+             /* Match seconds using alternate numeric symbols.  */
+             get_alt_number (0, 61);
+             tm->tm_sec = val;
+             break;
+           case 'U':
+           case 'V':
+           case 'W':
+             get_alt_number (0, 53);
+             /* XXX This cannot determine any field in TM.  */
+             break;
+           case 'w':
+             /* Match number of weekday using alternate numeric symbols.  */
+             get_alt_number (0, 6);
+             tm->tm_wday = val;
+             break;
+           case 'y':
+             /* Match year within century using alternate numeric symbols.  */
+             get_alt_number (0, 99);
+             break;
+           default:
+             return NULL;
+           }
+         break;
+       default:
+         return NULL;
+       }
+    }
+
+  if (have_I && is_pm)
+    tm->tm_hour += 12;
+  
+  return (char *) rp;
+}