diff options
Diffstat (limited to 'time')
-rw-r--r-- | time/Makefile | 3 | ||||
-rw-r--r-- | time/strptime.c | 344 | ||||
-rw-r--r-- | time/time.h | 9 |
3 files changed, 354 insertions, 2 deletions
diff --git a/time/Makefile b/time/Makefile index bb8bd20d48..ac422bfc42 100644 --- a/time/Makefile +++ b/time/Makefile @@ -29,7 +29,8 @@ routines := offtime asctime clock ctime difftime gmtime \ localtime mktime strftime time tzset tzfile \ gettimeofday settimeofday adjtime \ getitimer setitimer \ - stime dysize timegm ftime + stime dysize timegm ftime \ + strptime others := ap zdump zic tests := test_time clocktest diff --git a/time/strptime.c b/time/strptime.c new file mode 100644 index 0000000000..cb3d126b9c --- /dev/null +++ b/time/strptime.c @@ -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; +} diff --git a/time/time.h b/time/time.h index fda7f20387..12c3ce43e8 100644 --- a/time/time.h +++ b/time/time.h @@ -124,7 +124,14 @@ extern time_t __mktime_internal __P ((struct tm *__tp, Write no more than MAXSIZE characters and return the number of characters written, or 0 if it would exceed MAXSIZE. */ extern size_t strftime __P ((char *__s, size_t __maxsize, - __const char *__format, __const struct tm *__tp)); + __const char *__format, __const struct tm *__tp)); + +#ifdef __USE_MISC +/* Parse S according to FORMAT and store binary time information in TP. + The return value is a pointer to the first unparsed character in S. */ +extern char *strptime __P ((__const char *__s, __const char *__fmt, + struct tm *__tp)); +#endif /* Return the `struct tm' representation of *TIMER |