diff options
author | Roland McGrath <roland@gnu.org> | 1996-05-15 15:49:26 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1996-05-15 15:49:26 +0000 |
commit | f8adc70c3f27250d5768ff922c0ac39f0e77c058 (patch) | |
tree | 8ab82a13daaf342b64db23292efe40b6bffd08ca /time/strptime.c | |
parent | 64166d98349c01ccaaa848a30b12ae0d83de9bb8 (diff) | |
download | glibc-f8adc70c3f27250d5768ff922c0ac39f0e77c058.tar.gz glibc-f8adc70c3f27250d5768ff922c0ac39f0e77c058.tar.xz glibc-f8adc70c3f27250d5768ff922c0ac39f0e77c058.zip |
Tue May 14 19:42:04 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* sysdeps/generic/strrchr.c: Deansideclized. * elf/Makefile (ldd): Depend on Makefile. Find ld.so in $(slibdir) instead of $(libdir). * sysdeps/i386/strrchr.S: Use `testl $3, %esi' instead of `testb $3, %esi'; gas misassembles the latter into `testb $3, %dh'. * mach/Machrules (%.udeps rule): Do $(make-target-directory) first. Tue May 14 16:38:44 1996 David Mosberger-Tang <davidm@AZStarNet.com> * sunrpc/getrpcent.c (interpret): Declare args. Rewrite parsing using strpbrk. Tue May 14 20:18:38 1996 Ulrich Drepper <drepper@cygnus.com> * time/Makefile (routines): Add strptime. * time/time.h: Add prototype for strptime. * time/strptime.c: New file. Implementation according to XPG4.
Diffstat (limited to 'time/strptime.c')
-rw-r--r-- | time/strptime.c | 344 |
1 files changed, 344 insertions, 0 deletions
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; +} |