Annotation of src/lib/libc/time/strptime.c, Revision 1.28
1.28 ! martin 1: /* $NetBSD: strptime.c,v 1.27 2008/04/25 20:51:10 ginsbach Exp $ */
1.1 mrg 2:
1.3 kleink 3: /*-
1.27 ginsbach 4: * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1.3 kleink 5: * All rights reserved.
6: *
7: * This code was contributed to The NetBSD Foundation by Klaus Klein.
1.24 dsl 8: * Heavily optimised by David Laight
1.1 mrg 9: *
1.3 kleink 10: * Redistribution and use in source and binary forms, with or without
1.1 mrg 11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
1.3 kleink 16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.1 mrg 18: *
1.3 kleink 19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1.1 mrg 24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1.3 kleink 25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
1.1 mrg 30: */
31:
1.6 christos 32: #include <sys/cdefs.h>
1.3 kleink 33: #if defined(LIBC_SCCS) && !defined(lint)
1.28 ! martin 34: __RCSID("$NetBSD: strptime.c,v 1.27 2008/04/25 20:51:10 ginsbach Exp $");
1.1 mrg 35: #endif
36:
1.7 jtc 37: #include "namespace.h"
1.3 kleink 38: #include <sys/localedef.h>
39: #include <ctype.h>
1.1 mrg 40: #include <locale.h>
1.3 kleink 41: #include <string.h>
1.1 mrg 42: #include <time.h>
1.12 mycroft 43: #include <tzfile.h>
1.7 jtc 44:
45: #ifdef __weak_alias
1.19 mycroft 46: __weak_alias(strptime,_strptime)
1.7 jtc 47: #endif
1.3 kleink 48:
1.21 cgd 49: #define _ctloc(x) (_CurrentTimeLocale->x)
1.3 kleink 50:
51: /*
52: * We do not implement alternate representations. However, we always
53: * check whether a given modifier is allowed for a certain conversion.
54: */
1.16 kleink 55: #define ALT_E 0x01
56: #define ALT_O 0x02
1.24 dsl 57: #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; }
1.3 kleink 58:
1.26 ginsbach 59: static const char gmt[4] = { "GMT" };
1.3 kleink 60:
1.24 dsl 61: static const u_char *conv_num(const unsigned char *, int *, uint, uint);
1.23 dsl 62: static const u_char *find_string(const u_char *, int *, const char * const *,
63: const char * const *, int);
1.3 kleink 64:
1.1 mrg 65:
1.2 kleink 66: char *
1.23 dsl 67: strptime(const char *buf, const char *fmt, struct tm *tm)
1.1 mrg 68: {
1.20 itohy 69: unsigned char c;
70: const unsigned char *bp;
1.16 kleink 71: int alt_format, i, split_year = 0;
1.23 dsl 72: const char *new_fmt;
1.3 kleink 73:
1.22 christos 74: bp = (const u_char *)buf;
1.3 kleink 75:
1.24 dsl 76: while (bp != NULL && (c = *fmt++) != '\0') {
1.3 kleink 77: /* Clear `alternate' modifier prior to new conversion. */
78: alt_format = 0;
1.23 dsl 79: i = 0;
1.3 kleink 80:
81: /* Eat up white-space. */
82: if (isspace(c)) {
83: while (isspace(*bp))
84: bp++;
1.2 kleink 85: continue;
86: }
1.23 dsl 87:
1.24 dsl 88: if (c != '%')
1.3 kleink 89: goto literal;
90:
91:
92: again: switch (c = *fmt++) {
93: case '%': /* "%%" is converted to "%". */
94: literal:
1.14 tv 95: if (c != *bp++)
1.24 dsl 96: return NULL;
1.23 dsl 97: LEGAL_ALT(0);
98: continue;
1.3 kleink 99:
100: /*
101: * "Alternative" modifiers. Just set the appropriate flag
102: * and start over again.
103: */
104: case 'E': /* "%E?" alternative conversion modifier. */
1.16 kleink 105: LEGAL_ALT(0);
106: alt_format |= ALT_E;
1.3 kleink 107: goto again;
108:
109: case 'O': /* "%O?" alternative conversion modifier. */
1.16 kleink 110: LEGAL_ALT(0);
111: alt_format |= ALT_O;
1.3 kleink 112: goto again;
1.23 dsl 113:
1.3 kleink 114: /*
115: * "Complex" conversion rules, implemented through recursion.
116: */
117: case 'c': /* Date and time, using the locale's format. */
1.23 dsl 118: new_fmt = _ctloc(d_t_fmt);
119: goto recurse;
1.3 kleink 120:
121: case 'D': /* The date as "%m/%d/%y". */
1.23 dsl 122: new_fmt = "%m/%d/%y";
1.16 kleink 123: LEGAL_ALT(0);
1.23 dsl 124: goto recurse;
1.18 tv 125:
1.27 ginsbach 126: case 'F': /* The date as "%Y-%m-%d". */
127: new_fmt = "%Y-%m-%d";
128: LEGAL_ALT(0);
129: goto recurse;
130:
1.3 kleink 131: case 'R': /* The time as "%H:%M". */
1.23 dsl 132: new_fmt = "%H:%M";
1.16 kleink 133: LEGAL_ALT(0);
1.23 dsl 134: goto recurse;
1.3 kleink 135:
136: case 'r': /* The time in 12-hour clock representation. */
1.23 dsl 137: new_fmt =_ctloc(t_fmt_ampm);
1.16 kleink 138: LEGAL_ALT(0);
1.23 dsl 139: goto recurse;
1.3 kleink 140:
141: case 'T': /* The time as "%H:%M:%S". */
1.23 dsl 142: new_fmt = "%H:%M:%S";
1.16 kleink 143: LEGAL_ALT(0);
1.23 dsl 144: goto recurse;
1.3 kleink 145:
146: case 'X': /* The time, using the locale's format. */
1.23 dsl 147: new_fmt =_ctloc(t_fmt);
148: goto recurse;
1.3 kleink 149:
150: case 'x': /* The date, using the locale's format. */
1.23 dsl 151: new_fmt =_ctloc(d_fmt);
152: recurse:
153: bp = (const u_char *)strptime((const char *)bp,
154: new_fmt, tm);
1.16 kleink 155: LEGAL_ALT(ALT_E);
1.23 dsl 156: continue;
1.3 kleink 157:
158: /*
159: * "Elementary" conversion rules.
160: */
161: case 'A': /* The day of week, using the locale's form. */
162: case 'a':
1.23 dsl 163: bp = find_string(bp, &tm->tm_wday, _ctloc(day),
164: _ctloc(abday), 7);
1.16 kleink 165: LEGAL_ALT(0);
1.23 dsl 166: continue;
1.2 kleink 167:
1.3 kleink 168: case 'B': /* The month, using the locale's form. */
169: case 'b':
170: case 'h':
1.23 dsl 171: bp = find_string(bp, &tm->tm_mon, _ctloc(mon),
172: _ctloc(abmon), 12);
1.16 kleink 173: LEGAL_ALT(0);
1.23 dsl 174: continue;
1.2 kleink 175:
1.3 kleink 176: case 'C': /* The century number. */
1.24 dsl 177: i = 20;
1.23 dsl 178: bp = conv_num(bp, &i, 0, 99);
1.2 kleink 179:
1.24 dsl 180: i = i * 100 - TM_YEAR_BASE;
181: if (split_year)
182: i += tm->tm_year % 100;
183: split_year = 1;
184: tm->tm_year = i;
1.23 dsl 185: LEGAL_ALT(ALT_E);
186: continue;
1.2 kleink 187:
1.3 kleink 188: case 'd': /* The day of month. */
189: case 'e':
1.23 dsl 190: bp = conv_num(bp, &tm->tm_mday, 1, 31);
1.16 kleink 191: LEGAL_ALT(ALT_O);
1.23 dsl 192: continue;
1.2 kleink 193:
1.3 kleink 194: case 'k': /* The hour (24-hour clock representation). */
1.16 kleink 195: LEGAL_ALT(0);
1.3 kleink 196: /* FALLTHROUGH */
197: case 'H':
1.23 dsl 198: bp = conv_num(bp, &tm->tm_hour, 0, 23);
1.16 kleink 199: LEGAL_ALT(ALT_O);
1.23 dsl 200: continue;
1.2 kleink 201:
1.3 kleink 202: case 'l': /* The hour (12-hour clock representation). */
1.16 kleink 203: LEGAL_ALT(0);
1.3 kleink 204: /* FALLTHROUGH */
205: case 'I':
1.23 dsl 206: bp = conv_num(bp, &tm->tm_hour, 1, 12);
1.13 tv 207: if (tm->tm_hour == 12)
208: tm->tm_hour = 0;
1.23 dsl 209: LEGAL_ALT(ALT_O);
210: continue;
1.2 kleink 211:
1.3 kleink 212: case 'j': /* The day of year. */
1.23 dsl 213: i = 1;
214: bp = conv_num(bp, &i, 1, 366);
215: tm->tm_yday = i - 1;
1.16 kleink 216: LEGAL_ALT(0);
1.23 dsl 217: continue;
1.2 kleink 218:
1.3 kleink 219: case 'M': /* The minute. */
1.23 dsl 220: bp = conv_num(bp, &tm->tm_min, 0, 59);
1.16 kleink 221: LEGAL_ALT(ALT_O);
1.23 dsl 222: continue;
1.2 kleink 223:
1.3 kleink 224: case 'm': /* The month. */
1.23 dsl 225: i = 1;
226: bp = conv_num(bp, &i, 1, 12);
227: tm->tm_mon = i - 1;
1.16 kleink 228: LEGAL_ALT(ALT_O);
1.23 dsl 229: continue;
1.2 kleink 230:
1.3 kleink 231: case 'p': /* The locale's equivalent of AM/PM. */
1.24 dsl 232: bp = find_string(bp, &i, _ctloc(am_pm), NULL, 2);
1.23 dsl 233: if (tm->tm_hour > 11)
1.24 dsl 234: return NULL;
1.23 dsl 235: tm->tm_hour += i * 12;
1.16 kleink 236: LEGAL_ALT(0);
1.23 dsl 237: continue;
1.2 kleink 238:
1.3 kleink 239: case 'S': /* The seconds. */
1.23 dsl 240: bp = conv_num(bp, &tm->tm_sec, 0, 61);
1.16 kleink 241: LEGAL_ALT(ALT_O);
1.23 dsl 242: continue;
1.1 mrg 243:
1.3 kleink 244: case 'U': /* The week of year, beginning on sunday. */
245: case 'W': /* The week of year, beginning on monday. */
246: /*
247: * XXX This is bogus, as we can not assume any valid
248: * information present in the tm structure at this
249: * point to calculate a real value, so just check the
250: * range for now.
251: */
1.23 dsl 252: bp = conv_num(bp, &i, 0, 53);
253: LEGAL_ALT(ALT_O);
254: continue;
1.2 kleink 255:
1.3 kleink 256: case 'w': /* The day of week, beginning on sunday. */
1.23 dsl 257: bp = conv_num(bp, &tm->tm_wday, 0, 6);
1.16 kleink 258: LEGAL_ALT(ALT_O);
1.23 dsl 259: continue;
1.2 kleink 260:
1.3 kleink 261: case 'Y': /* The year. */
1.24 dsl 262: i = TM_YEAR_BASE; /* just for data sanity... */
1.23 dsl 263: bp = conv_num(bp, &i, 0, 9999);
1.8 mycroft 264: tm->tm_year = i - TM_YEAR_BASE;
1.23 dsl 265: LEGAL_ALT(ALT_E);
266: continue;
1.2 kleink 267:
1.9 mycroft 268: case 'y': /* The year within 100 years of the epoch. */
1.24 dsl 269: /* LEGAL_ALT(ALT_E | ALT_O); */
1.23 dsl 270: bp = conv_num(bp, &i, 0, 99);
1.8 mycroft 271:
1.24 dsl 272: if (split_year)
273: /* preserve century */
274: i += (tm->tm_year / 100) * 100;
275: else {
276: split_year = 1;
277: if (i <= 68)
278: i = i + 2000 - TM_YEAR_BASE;
279: else
280: i = i + 1900 - TM_YEAR_BASE;
1.13 tv 281: }
1.24 dsl 282: tm->tm_year = i;
1.23 dsl 283: continue;
1.2 kleink 284:
1.26 ginsbach 285: case 'Z':
286: tzset();
287: if (strncmp((const char *)bp, gmt, 3) == 0) {
288: tm->tm_isdst = 0;
289: #ifdef TM_GMTOFF
290: tm->TM_GMTOFF = 0;
291: #endif
292: #ifdef TM_ZONE
293: tm->TM_ZONE = gmt;
294: #endif
295: bp += 3;
296: } else {
297: const unsigned char *ep;
298:
299: ep = find_string(bp, &i,
300: (const char * const *)tzname,
301: NULL, 2);
302: if (ep != NULL) {
303: tm->tm_isdst = i;
304: #ifdef TM_GMTOFF
305: tm->TM_GMTOFF = -(timezone);
306: #endif
307: #ifdef TM_ZONE
308: tm->TM_ZONE = tzname[i];
309: #endif
310: }
311: bp = ep;
312: }
313: continue;
314:
1.3 kleink 315: /*
316: * Miscellaneous conversions.
317: */
318: case 'n': /* Any kind of white-space. */
319: case 't':
320: while (isspace(*bp))
321: bp++;
1.23 dsl 322: LEGAL_ALT(0);
323: continue;
1.2 kleink 324:
1.1 mrg 325:
1.3 kleink 326: default: /* Unknown/unsupported conversion. */
1.24 dsl 327: return NULL;
1.3 kleink 328: }
329: }
1.2 kleink 330:
1.25 christos 331: return __UNCONST(bp);
1.3 kleink 332: }
1.2 kleink 333:
334:
1.23 dsl 335: static const u_char *
1.24 dsl 336: conv_num(const unsigned char *buf, int *dest, uint llim, uint ulim)
1.3 kleink 337: {
1.24 dsl 338: uint result = 0;
1.23 dsl 339: unsigned char ch;
1.18 tv 340:
341: /* The limit also determines the number of valid digits. */
1.24 dsl 342: uint rulim = ulim;
1.2 kleink 343:
1.23 dsl 344: ch = *buf;
345: if (ch < '0' || ch > '9')
1.24 dsl 346: return NULL;
1.2 kleink 347:
1.3 kleink 348: do {
1.18 tv 349: result *= 10;
1.23 dsl 350: result += ch - '0';
1.18 tv 351: rulim /= 10;
1.23 dsl 352: ch = *++buf;
353: } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9');
1.2 kleink 354:
1.18 tv 355: if (result < llim || result > ulim)
1.24 dsl 356: return NULL;
1.1 mrg 357:
1.18 tv 358: *dest = result;
1.23 dsl 359: return buf;
360: }
361:
362: static const u_char *
363: find_string(const u_char *bp, int *tgt, const char * const *n1,
364: const char * const *n2, int c)
365: {
366: int i;
367: unsigned int len;
368:
1.24 dsl 369: /* check full name - then abbreviated ones */
370: for (; n1 != NULL; n1 = n2, n2 = NULL) {
371: for (i = 0; i < c; i++, n1++) {
372: len = strlen(*n1);
373: if (strncasecmp(*n1, (const char *)bp, len) == 0) {
374: *tgt = i;
375: return bp + len;
376: }
377: }
1.23 dsl 378: }
1.24 dsl 379:
380: /* Nothing matched */
381: return NULL;
1.1 mrg 382: }
CVSweb <webmaster@jp.NetBSD.org>