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