strptime.c revision 46051
1/*
2 * Powerdog Industries kindly requests feedback from anyone modifying
3 * this function:
4 *
5 * Date: Thu, 05 Jun 1997 23:17:17 -0400
6 * From: Kevin Ruddy <kevin.ruddy@powerdog.com>
7 * To: James FitzGibbon <james@nexis.net>
8 * Subject: Re: Use of your strptime(3) code (fwd)
9 *
10 * The reason for the "no mod" clause was so that modifications would
11 * come back and we could integrate them and reissue so that a wider
12 * audience could use it (thereby spreading the wealth).  This has
13 * made it possible to get strptime to work on many operating systems.
14 * I'm not sure why that's "plain unacceptable" to the FreeBSD team.
15 *
16 * Anyway, you can change it to "with or without modification" as
17 * you see fit.  Enjoy.
18 *
19 * Kevin Ruddy
20 * Powerdog Industries, Inc.
21 */
22/*
23 * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
24 *
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
27 * are met:
28 * 1. Redistributions of source code must retain the above copyright
29 *    notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 *    notice, this list of conditions and the following disclaimer
32 *    in the documentation and/or other materials provided with the
33 *    distribution.
34 * 3. All advertising materials mentioning features or use of this
35 *    software must display the following acknowledgement:
36 *      This product includes software developed by Powerdog Industries.
37 * 4. The name of Powerdog Industries may not be used to endorse or
38 *    promote products derived from this software without specific prior
39 *    written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
42 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
45 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
46 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
47 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
48 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
49 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
50 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
51 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 */
53
54#ifdef LIBC_RCS
55static const char rcsid[] =
56	"$Id: strptime.c,v 1.5 1999/04/25 01:42:18 wes Exp $";
57#endif
58
59#ifndef lint
60#ifndef NOID
61static char copyright[] =
62"@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
63static char sccsid[] = "@(#)strptime.c	0.1 (Powerdog) 94/03/27";
64#endif /* !defined NOID */
65#endif /* not lint */
66
67#include <time.h>
68#include <ctype.h>
69#include <string.h>
70#include "timelocal.h"
71
72#define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
73
74char *
75strptime(const char *buf, const char *fmt, struct tm *tm)
76{
77	char	c;
78	const char *ptr;
79	int	i,
80		len;
81
82	ptr = fmt;
83	while (*ptr != 0) {
84		if (*buf == 0)
85			break;
86
87		c = *ptr++;
88
89		if (c != '%') {
90			if (isspace((unsigned char)c))
91				while (*buf != 0 && isspace((unsigned char)*buf))
92					buf++;
93			else if (c != *buf++)
94				return 0;
95			continue;
96		}
97
98		c = *ptr++;
99		switch (c) {
100		case 0:
101		case '%':
102			if (*buf++ != '%')
103				return 0;
104			break;
105
106		case 'C':
107			buf = strptime(buf, Locale->date_fmt, tm);
108			if (buf == 0)
109				return 0;
110			break;
111
112		case 'c':
113			buf = strptime(buf, "%x %X", tm);
114			if (buf == 0)
115				return 0;
116			break;
117
118		case 'D':
119			buf = strptime(buf, "%m/%d/%y", tm);
120			if (buf == 0)
121				return 0;
122			break;
123
124		case 'R':
125			buf = strptime(buf, "%H:%M", tm);
126			if (buf == 0)
127				return 0;
128			break;
129
130		case 'r':
131			buf = strptime(buf, "%I:%M:%S %p", tm);
132			if (buf == 0)
133				return 0;
134			break;
135
136		case 'T':
137			buf = strptime(buf, "%H:%M:%S", tm);
138			if (buf == 0)
139				return 0;
140			break;
141
142		case 'X':
143			buf = strptime(buf, Locale->X_fmt, tm);
144			if (buf == 0)
145				return 0;
146			break;
147
148		case 'x':
149			buf = strptime(buf, Locale->x_fmt, tm);
150			if (buf == 0)
151				return 0;
152			break;
153
154		case 'j':
155			if (!isdigit((unsigned char)*buf))
156				return 0;
157
158			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
159				i *= 10;
160				i += *buf - '0';
161			}
162			if (i > 365)
163				return 0;
164
165			tm->tm_yday = i;
166			break;
167
168		case 'M':
169		case 'S':
170			if (*buf == 0 || isspace((unsigned char)*buf))
171				break;
172
173			if (!isdigit((unsigned char)*buf))
174				return 0;
175
176			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
177				i *= 10;
178				i += *buf - '0';
179			}
180			if (i > 59)
181				return 0;
182
183			if (c == 'M')
184				tm->tm_min = i;
185			else
186				tm->tm_sec = i;
187
188			if (*buf != 0 && isspace((unsigned char)*buf))
189				while (*ptr != 0 && !isspace((unsigned char)*ptr))
190					ptr++;
191			break;
192
193		case 'H':
194		case 'I':
195		case 'k':
196		case 'l':
197			if (!isdigit((unsigned char)*buf))
198				return 0;
199
200			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
201				i *= 10;
202				i += *buf - '0';
203			}
204			if (c == 'H' || c == 'k') {
205				if (i > 23)
206					return 0;
207			} else if (i > 11)
208				return 0;
209
210			tm->tm_hour = i;
211
212			if (*buf != 0 && isspace((unsigned char)*buf))
213				while (*ptr != 0 && !isspace((unsigned char)*ptr))
214					ptr++;
215			break;
216
217		case 'p':
218			len = strlen(Locale->am);
219			if (strncasecmp(buf, Locale->am, len) == 0) {
220				if (tm->tm_hour > 12)
221					return 0;
222				if (tm->tm_hour == 12)
223					tm->tm_hour = 0;
224				buf += len;
225				break;
226			}
227
228			len = strlen(Locale->pm);
229			if (strncasecmp(buf, Locale->pm, len) == 0) {
230				if (tm->tm_hour > 12)
231					return 0;
232				if (tm->tm_hour != 12)
233					tm->tm_hour += 12;
234				buf += len;
235				break;
236			}
237
238			return 0;
239
240		case 'A':
241		case 'a':
242			for (i = 0; i < asizeof(Locale->weekday); i++) {
243				len = strlen(Locale->weekday[i]);
244				if (strncasecmp(buf,
245						Locale->weekday[i],
246						len) == 0)
247					break;
248
249				len = strlen(Locale->wday[i]);
250				if (strncasecmp(buf,
251						Locale->wday[i],
252						len) == 0)
253					break;
254			}
255			if (i == asizeof(Locale->weekday))
256				return 0;
257
258			tm->tm_wday = i;
259			buf += len;
260			break;
261
262		case 'd':
263		case 'e':
264			if (!isdigit((unsigned char)*buf))
265				return 0;
266
267			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
268				i *= 10;
269				i += *buf - '0';
270			}
271			if (i > 31)
272				return 0;
273
274			tm->tm_mday = i;
275
276			if (*buf != 0 && isspace((unsigned char)*buf))
277				while (*ptr != 0 && !isspace((unsigned char)*ptr))
278					ptr++;
279			break;
280
281		case 'B':
282		case 'b':
283		case 'h':
284			for (i = 0; i < asizeof(Locale->month); i++) {
285				len = strlen(Locale->month[i]);
286				if (strncasecmp(buf,
287						Locale->month[i],
288						len) == 0)
289					break;
290
291				len = strlen(Locale->mon[i]);
292				if (strncasecmp(buf,
293						Locale->mon[i],
294						len) == 0)
295					break;
296			}
297			if (i == asizeof(Locale->month))
298				return 0;
299
300			tm->tm_mon = i;
301			buf += len;
302			break;
303
304		case 'm':
305			if (!isdigit((unsigned char)*buf))
306				return 0;
307
308			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
309				i *= 10;
310				i += *buf - '0';
311			}
312			if (i < 1 || i > 12)
313				return 0;
314
315			tm->tm_mon = i - 1;
316
317			if (*buf != 0 && isspace((unsigned char)*buf))
318				while (*ptr != 0 && !isspace((unsigned char)*ptr))
319					ptr++;
320			break;
321
322		case 'Y':
323		case 'y':
324			if (*buf == 0 || isspace((unsigned char)*buf))
325				break;
326
327			if (!isdigit((unsigned char)*buf))
328				return 0;
329
330			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
331				i *= 10;
332				i += *buf - '0';
333			}
334			if (c == 'Y')
335				i -= 1900;
336			if (c == 'y' && i < 69)
337				i += 100;
338			if (i < 0)
339				return 0;
340
341			tm->tm_year = i;
342
343			if (*buf != 0 && isspace((unsigned char)*buf))
344				while (*ptr != 0 && !isspace((unsigned char)*ptr))
345					ptr++;
346			break;
347		}
348	}
349
350	return (char *)buf;
351}
352