+++ /dev/null
-/** @file \r
- strptime implementation\r
-\r
- Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials are licensed and made available under\r
- the terms and conditions of the BSD License that accompanies this distribution.\r
- The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php.\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
- * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.\r
- * All rights reserved.\r
- *\r
- * This code was contributed to The NetBSD Foundation by Klaus Klein.\r
- * Heavily optimised by David Laight\r
- *\r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions\r
- * are met:\r
- * 1. Redistributions of source code must retain the above copyright\r
- * notice, this list of conditions and the following disclaimer.\r
- * 2. Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the\r
- * documentation and/or other materials provided with the distribution.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
- * POSSIBILITY OF SUCH DAMAGE.\r
-\r
- $NetBSD: strptime.c,v 1.28 2008/04/28 20:23:01 martin Exp $\r
-\r
-**/\r
-\r
-#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */\r
- #pragma warning ( disable : 4244 )\r
- #pragma warning ( disable : 4018 )\r
-#endif\r
-\r
-#include <LibConfig.h>\r
-\r
-#include <sys/cdefs.h>\r
-\r
-#include "namespace.h"\r
-#include <time.h>\r
-#include "tzfile.h"\r
-#include <TimeVals.h>\r
-#include <fcntl.h>\r
-\r
-#include <sys/localedef.h>\r
-\r
-#include <ctype.h>\r
-#include <locale.h>\r
-#include <string.h>\r
-\r
-#ifdef __weak_alias\r
-__weak_alias(strptime,_strptime)\r
-#endif\r
-\r
-#define _ctloc(x) (_CurrentTimeLocale->x)\r
-\r
-/*\r
- * We do not implement alternate representations. However, we always\r
- * check whether a given modifier is allowed for a certain conversion.\r
- */\r
-#define ALT_E 0x01\r
-#define ALT_O 0x02\r
-#define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; }\r
-\r
-static const unsigned char *conv_num(const unsigned char *, int *, unsigned int, unsigned int);\r
-static const unsigned char *find_string(const unsigned char *, int *, const char * const *,\r
- const char * const *, int);\r
-\r
-\r
-char *\r
-strptime(const char *buf, const char *fmt, struct tm *tm)\r
-{\r
- unsigned char c;\r
- const unsigned char *bp;\r
- int alt_format, i, split_year = 0;\r
- const char *new_fmt;\r
-\r
- bp = (const unsigned char *)buf;\r
-\r
- while (bp != NULL && (c = *fmt++) != '\0') {\r
- /* Clear `alternate' modifier prior to new conversion. */\r
- alt_format = 0;\r
- i = 0;\r
-\r
- /* Eat up white-space. */\r
- if (isspace(c)) {\r
- while (isspace(*bp))\r
- bp++;\r
- continue;\r
- }\r
-\r
- if (c != '%')\r
- goto literal;\r
-\r
-\r
-again: switch (c = *fmt++) {\r
- case '%': /* "%%" is converted to "%". */\r
-literal:\r
- if (c != *bp++)\r
- return NULL;\r
- LEGAL_ALT(0);\r
- continue;\r
-\r
- /*\r
- * "Alternative" modifiers. Just set the appropriate flag\r
- * and start over again.\r
- */\r
- case 'E': /* "%E?" alternative conversion modifier. */\r
- LEGAL_ALT(0);\r
- alt_format |= ALT_E;\r
- goto again;\r
-\r
- case 'O': /* "%O?" alternative conversion modifier. */\r
- LEGAL_ALT(0);\r
- alt_format |= ALT_O;\r
- goto again;\r
-\r
- /*\r
- * "Complex" conversion rules, implemented through recursion.\r
- */\r
- case 'c': /* Date and time, using the locale's format. */\r
- new_fmt = _ctloc(d_t_fmt);\r
- goto recurse;\r
-\r
- case 'D': /* The date as "%m/%d/%y". */\r
- new_fmt = "%m/%d/%y";\r
- LEGAL_ALT(0);\r
- goto recurse;\r
-\r
- case 'F': /* The date as "%Y-%m-%d". */\r
- new_fmt = "%Y-%m-%d";\r
- LEGAL_ALT(0);\r
- goto recurse;\r
-\r
- case 'R': /* The time as "%H:%M". */\r
- new_fmt = "%H:%M";\r
- LEGAL_ALT(0);\r
- goto recurse;\r
-\r
- case 'r': /* The time in 12-hour clock representation. */\r
- new_fmt =_ctloc(t_fmt_ampm);\r
- LEGAL_ALT(0);\r
- goto recurse;\r
-\r
- case 'T': /* The time as "%H:%M:%S". */\r
- new_fmt = "%H:%M:%S";\r
- LEGAL_ALT(0);\r
- goto recurse;\r
-\r
- case 'X': /* The time, using the locale's format. */\r
- new_fmt =_ctloc(t_fmt);\r
- goto recurse;\r
-\r
- case 'x': /* The date, using the locale's format. */\r
- new_fmt =_ctloc(d_fmt);\r
- recurse:\r
- bp = (const unsigned char *)strptime((const char *)bp,\r
- new_fmt, tm);\r
- LEGAL_ALT(ALT_E);\r
- continue;\r
-\r
- /*\r
- * "Elementary" conversion rules.\r
- */\r
- case 'A': /* The day of week, using the locale's form. */\r
- case 'a':\r
- bp = find_string(bp, &tm->tm_wday, _ctloc(day),\r
- _ctloc(abday), 7);\r
- LEGAL_ALT(0);\r
- continue;\r
-\r
- case 'B': /* The month, using the locale's form. */\r
- case 'b':\r
- case 'h':\r
- bp = find_string(bp, &tm->tm_mon, _ctloc(mon),\r
- _ctloc(abmon), 12);\r
- LEGAL_ALT(0);\r
- continue;\r
-\r
- case 'C': /* The century number. */\r
- i = 20;\r
- bp = conv_num(bp, &i, 0, 99);\r
-\r
- i = i * 100 - TM_YEAR_BASE;\r
- if (split_year)\r
- i += tm->tm_year % 100;\r
- split_year = 1;\r
- tm->tm_year = i;\r
- LEGAL_ALT(ALT_E);\r
- continue;\r
-\r
- case 'd': /* The day of month. */\r
- case 'e':\r
- bp = conv_num(bp, &tm->tm_mday, 1, 31);\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'k': /* The hour (24-hour clock representation). */\r
- LEGAL_ALT(0);\r
- /* FALLTHROUGH */\r
- case 'H':\r
- bp = conv_num(bp, &tm->tm_hour, 0, 23);\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'l': /* The hour (12-hour clock representation). */\r
- LEGAL_ALT(0);\r
- /* FALLTHROUGH */\r
- case 'I':\r
- bp = conv_num(bp, &tm->tm_hour, 1, 12);\r
- if (tm->tm_hour == 12)\r
- tm->tm_hour = 0;\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'j': /* The day of year. */\r
- i = 1;\r
- bp = conv_num(bp, &i, 1, 366);\r
- tm->tm_yday = i - 1;\r
- LEGAL_ALT(0);\r
- continue;\r
-\r
- case 'M': /* The minute. */\r
- bp = conv_num(bp, &tm->tm_min, 0, 59);\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'm': /* The month. */\r
- i = 1;\r
- bp = conv_num(bp, &i, 1, 12);\r
- tm->tm_mon = i - 1;\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'p': /* The locale's equivalent of AM/PM. */\r
- bp = find_string(bp, &i, _ctloc(am_pm), NULL, 2);\r
- if (tm->tm_hour > 11)\r
- return NULL;\r
- tm->tm_hour += i * 12;\r
- LEGAL_ALT(0);\r
- continue;\r
-\r
- case 'S': /* The seconds. */\r
- bp = conv_num(bp, &tm->tm_sec, 0, 61);\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'U': /* The week of year, beginning on sunday. */\r
- case 'W': /* The week of year, beginning on monday. */\r
- /*\r
- * XXX This is bogus, as we can not assume any valid\r
- * information present in the tm structure at this\r
- * point to calculate a real value, so just check the\r
- * range for now.\r
- */\r
- bp = conv_num(bp, &i, 0, 53);\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'w': /* The day of week, beginning on sunday. */\r
- bp = conv_num(bp, &tm->tm_wday, 0, 6);\r
- LEGAL_ALT(ALT_O);\r
- continue;\r
-\r
- case 'Y': /* The year. */\r
- i = TM_YEAR_BASE; /* just for data sanity... */\r
- bp = conv_num(bp, &i, 0, 9999);\r
- tm->tm_year = i - TM_YEAR_BASE;\r
- LEGAL_ALT(ALT_E);\r
- continue;\r
-\r
- case 'y': /* The year within 100 years of the epoch. */\r
- /* LEGAL_ALT(ALT_E | ALT_O); */\r
- bp = conv_num(bp, &i, 0, 99);\r
-\r
- if (split_year)\r
- /* preserve century */\r
- i += (tm->tm_year / 100) * 100;\r
- else {\r
- split_year = 1;\r
- if (i <= 68)\r
- i = i + 2000 - TM_YEAR_BASE;\r
- else\r
- i = i + 1900 - TM_YEAR_BASE;\r
- }\r
- tm->tm_year = i;\r
- continue;\r
-\r
- case 'Z':\r
- tzset();\r
- if (strncmp((const char *)bp, gmt, 3) == 0) {\r
- tm->tm_isdst = 0;\r
-#ifdef TM_GMTOFF\r
- tm->TM_GMTOFF = 0;\r
-#endif\r
-#ifdef TM_ZONE\r
- tm->TM_ZONE = gmt;\r
-#endif\r
- bp += 3;\r
- } else {\r
- const unsigned char *ep;\r
-\r
- ep = find_string(bp, &i,\r
- (const char * const *)tzname,\r
- NULL, 2);\r
- if (ep != NULL) {\r
- tm->tm_isdst = i;\r
-#ifdef TM_GMTOFF\r
- tm->TM_GMTOFF = -(timezone);\r
-#endif\r
-#ifdef TM_ZONE\r
- tm->TM_ZONE = tzname[i];\r
-#endif\r
- }\r
- bp = ep;\r
- }\r
- continue;\r
-\r
- /*\r
- * Miscellaneous conversions.\r
- */\r
- case 'n': /* Any kind of white-space. */\r
- case 't':\r
- while (isspace(*bp))\r
- bp++;\r
- LEGAL_ALT(0);\r
- continue;\r
-\r
-\r
- default: /* Unknown/unsupported conversion. */\r
- return NULL;\r
- }\r
- }\r
-\r
- return __UNCONST(bp);\r
-}\r
-\r
-\r
-static const unsigned char *\r
-conv_num(const unsigned char *buf, int *dest, unsigned int llim, unsigned int ulim)\r
-{\r
- unsigned int result = 0;\r
- unsigned char ch;\r
-\r
- /* The limit also determines the number of valid digits. */\r
- unsigned int rulim = ulim;\r
-\r
- ch = *buf;\r
- if (ch < '0' || ch > '9')\r
- return NULL;\r
-\r
- do {\r
- result *= 10;\r
- result += ch - '0';\r
- rulim /= 10;\r
- ch = *++buf;\r
- } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9');\r
-\r
- if (result < llim || result > ulim)\r
- return NULL;\r
-\r
- *dest = result;\r
- return buf;\r
-}\r
-\r
-static const unsigned char *\r
-find_string(const unsigned char *bp, int *tgt, const char * const *n1,\r
- const char * const *n2, int c)\r
-{\r
- int i;\r
- size_t len;\r
-\r
- /* check full name - then abbreviated ones */\r
- for (; n1 != NULL; n1 = n2, n2 = NULL) {\r
- for (i = 0; i < c; i++, n1++) {\r
- len = strlen(*n1);\r
- if (strncasecmp(*n1, (const char *)bp, len) == 0) {\r
- *tgt = i;\r
- return bp + len;\r
- }\r
- }\r
- }\r
-\r
- /* Nothing matched */\r
- return NULL;\r
-}\r