xref: /freebsd/crypto/openssh/openbsd-compat/strptime.c (revision 1170f3d12ebd03d02f8bb4f075319f461e38d7d9)
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