1 /* $NetBSD: src/lib/libc/time/strptime.c,v 1.22 2000/12/20 20:56:34 christos Exp $ */
2 /* $DragonFly: src/lib/libc/stdtime/strptime.c,v 1.5 2005/12/04 23:25:40 swildner Exp $ */
5 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
8 * This code was contributed to The NetBSD Foundation by Klaus Klein.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
39 #include <sys/localedef.h>
47 #define _ctloc(x) (_CurrentTimeLocale->x)
50 * We do not implement alternate representations. However, we always
51 * check whether a given modifier is allowed for a certain conversion.
55 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
57 static int conv_num(const unsigned char **, int *, int, int);
60 strptime(const char *buf, const char *fmt, struct tm *tm)
63 const unsigned char *bp;
65 int alt_format, i, split_year = 0;
67 bp = (const u_char *)buf;
69 while ((c = *fmt) != '\0') {
70 /* Clear `alternate' modifier prior to new conversion. */
73 /* Eat up white-space. */
82 if ((c = *fmt++) != '%')
86 again: switch (c = *fmt++) {
87 case '%': /* "%%" is converted to "%". */
94 * "Alternative" modifiers. Just set the appropriate flag
95 * and start over again.
97 case 'E': /* "%E?" alternative conversion modifier. */
102 case 'O': /* "%O?" alternative conversion modifier. */
108 * "Complex" conversion rules, implemented through recursion.
110 case 'c': /* Date and time, using the locale's format. */
112 if (!(bp = (const u_char *)strptime((const char *)bp,
113 _ctloc(d_t_fmt), tm)))
117 case 'D': /* The date as "%m/%d/%y". */
119 if (!(bp = (const u_char *) strptime((const char *)bp,
124 case 'R': /* The time as "%H:%M". */
126 if (!(bp = (const u_char *)strptime((const char *)bp,
131 case 'r': /* The time in 12-hour clock representation. */
133 if (!(bp = (const u_char *)strptime((const char *)bp,
134 _ctloc(t_fmt_ampm), tm)))
138 case 'T': /* The time as "%H:%M:%S". */
140 if (!(bp = (const u_char *)strptime((const char *)bp,
145 case 'X': /* The time, using the locale's format. */
147 if (!(bp = (const u_char *)strptime((const char *)bp,
152 case 'x': /* The date, using the locale's format. */
154 if (!(bp = (const u_char *)strptime((const char *)bp,
160 * "Elementary" conversion rules.
162 case 'A': /* The day of week, using the locale's form. */
165 for (i = 0; i < 7; i++) {
167 len = strlen(_ctloc(day[i]));
168 if (strncasecmp(_ctloc(day[i]),
169 (const char *)bp, len) == 0)
172 /* Abbreviated name. */
173 len = strlen(_ctloc(abday[i]));
174 if (strncasecmp(_ctloc(abday[i]),
175 (const char *)bp, len) == 0)
179 /* Nothing matched. */
187 case 'B': /* The month, using the locale's form. */
191 for (i = 0; i < 12; i++) {
193 len = strlen(_ctloc(mon[i]));
194 if (strncasecmp(_ctloc(mon[i]),
195 (const char *)bp, len) == 0)
198 /* Abbreviated name. */
199 len = strlen(_ctloc(abmon[i]));
200 if (strncasecmp(_ctloc(abmon[i]),
201 (const char *)bp, len) == 0)
205 /* Nothing matched. */
213 case 'C': /* The century number. */
215 if (!(conv_num(&bp, &i, 0, 99)))
219 tm->tm_year = (tm->tm_year % 100) + (i * 100);
221 tm->tm_year = i * 100;
226 case 'd': /* The day of month. */
229 if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
233 case 'k': /* The hour (24-hour clock representation). */
238 if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
242 case 'l': /* The hour (12-hour clock representation). */
247 if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
249 if (tm->tm_hour == 12)
253 case 'j': /* The day of year. */
255 if (!(conv_num(&bp, &i, 1, 366)))
260 case 'M': /* The minute. */
262 if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
266 case 'm': /* The month. */
268 if (!(conv_num(&bp, &i, 1, 12)))
273 case 'p': /* The locale's equivalent of AM/PM. */
276 if (strcasecmp(_ctloc(am_pm[0]),
277 (const char *)bp) == 0) {
278 if (tm->tm_hour > 11)
281 bp += strlen(_ctloc(am_pm[0]));
285 else if (strcasecmp(_ctloc(am_pm[1]),
286 (const char *)bp) == 0) {
287 if (tm->tm_hour > 11)
291 bp += strlen(_ctloc(am_pm[1]));
295 /* Nothing matched. */
298 case 'S': /* The seconds. */
300 if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
304 case 'U': /* The week of year, beginning on sunday. */
305 case 'W': /* The week of year, beginning on monday. */
308 * XXX This is bogus, as we can not assume any valid
309 * information present in the tm structure at this
310 * point to calculate a real value, so just check the
313 if (!(conv_num(&bp, &i, 0, 53)))
317 case 'w': /* The day of week, beginning on sunday. */
319 if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
323 case 'Y': /* The year. */
325 if (!(conv_num(&bp, &i, 0, 9999)))
328 tm->tm_year = i - TM_YEAR_BASE;
331 case 'y': /* The year within 100 years of the epoch. */
332 LEGAL_ALT(ALT_E | ALT_O);
333 if (!(conv_num(&bp, &i, 0, 99)))
337 tm->tm_year = ((tm->tm_year / 100) * 100) + i;
342 tm->tm_year = i + 2000 - TM_YEAR_BASE;
344 tm->tm_year = i + 1900 - TM_YEAR_BASE;
348 * Miscellaneous conversions.
350 case 'n': /* Any kind of white-space. */
358 default: /* Unknown/unsupported conversion. */
365 /* LINTED functional specification */
371 conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
375 /* The limit also determines the number of valid digits. */
378 if (**buf < '0' || **buf > '9')
383 result += *(*buf)++ - '0';
385 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
387 if (result < llim || result > ulim)