strptime.c revision 46051
11558Srgrimes/*
21558Srgrimes * Powerdog Industries kindly requests feedback from anyone modifying
31558Srgrimes * this function:
41558Srgrimes *
51558Srgrimes * Date: Thu, 05 Jun 1997 23:17:17 -0400
61558Srgrimes * From: Kevin Ruddy <kevin.ruddy@powerdog.com>
71558Srgrimes * To: James FitzGibbon <james@nexis.net>
81558Srgrimes * Subject: Re: Use of your strptime(3) code (fwd)
91558Srgrimes *
101558Srgrimes * The reason for the "no mod" clause was so that modifications would
111558Srgrimes * come back and we could integrate them and reissue so that a wider
121558Srgrimes * audience could use it (thereby spreading the wealth).  This has
131558Srgrimes * made it possible to get strptime to work on many operating systems.
141558Srgrimes * I'm not sure why that's "plain unacceptable" to the FreeBSD team.
151558Srgrimes *
161558Srgrimes * Anyway, you can change it to "with or without modification" as
171558Srgrimes * you see fit.  Enjoy.
181558Srgrimes *
191558Srgrimes * Kevin Ruddy
201558Srgrimes * Powerdog Industries, Inc.
211558Srgrimes */
221558Srgrimes/*
231558Srgrimes * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
241558Srgrimes *
251558Srgrimes * Redistribution and use in source and binary forms, with or without
261558Srgrimes * modification, are permitted provided that the following conditions
271558Srgrimes * are met:
281558Srgrimes * 1. Redistributions of source code must retain the above copyright
291558Srgrimes *    notice, this list of conditions and the following disclaimer.
30114589Sobrien * 2. Redistributions in binary form must reproduce the above copyright
311558Srgrimes *    notice, this list of conditions and the following disclaimer
3238040Scharnier *    in the documentation and/or other materials provided with the
331558Srgrimes *    distribution.
341558Srgrimes * 3. All advertising materials mentioning features or use of this
351558Srgrimes *    software must display the following acknowledgement:
361558Srgrimes *      This product includes software developed by Powerdog Industries.
371558Srgrimes * 4. The name of Powerdog Industries may not be used to endorse or
381558Srgrimes *    promote products derived from this software without specific prior
39114589Sobrien *    written permission.
4038040Scharnier *
41114589Sobrien * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
42114589Sobrien * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
431558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
441558Srgrimes * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
45102231Strhodes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
461558Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
471558Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4842873Sluoqi * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4996478Sphk * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
501558Srgrimes * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
511558Srgrimes * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5298542Smckusick */
5398542Smckusick
541558Srgrimes#ifdef LIBC_RCS
55207141Sjeffstatic const char rcsid[] =
561558Srgrimes	"$Id: strptime.c,v 1.5 1999/04/25 01:42:18 wes Exp $";
57110174Sgordon#endif
581558Srgrimes
591558Srgrimes#ifndef lint
601558Srgrimes#ifndef NOID
61109597Sjmallettstatic char copyright[] =
6238040Scharnier"@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
631558Srgrimesstatic char sccsid[] = "@(#)strptime.c	0.1 (Powerdog) 94/03/27";
641558Srgrimes#endif /* !defined NOID */
65207141Sjeff#endif /* not lint */
6658047Ssheldonh
671558Srgrimes#include <time.h>
681558Srgrimes#include <ctype.h>
691558Srgrimes#include <string.h>
701558Srgrimes#include "timelocal.h"
711558Srgrimes
72109597Sjmallett#define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
73109597Sjmallett
741558Srgrimeschar *
7592883Simpstrptime(const char *buf, const char *fmt, struct tm *tm)
7692883Simp{
77207141Sjeff	char	c;
78207141Sjeff	const char *ptr;
79207141Sjeff	int	i,
801558Srgrimes		len;
811558Srgrimes
82109597Sjmallett	ptr = fmt;
831558Srgrimes	while (*ptr != 0) {
84207141Sjeff		if (*buf == 0)
85109963Sjmallett			break;
8679750Sdd
87127455Sbde		c = *ptr++;
88207141Sjeff
89207141Sjeff		if (c != '%') {
90207141Sjeff			if (isspace((unsigned char)c))
91127441Sbde				while (*buf != 0 && isspace((unsigned char)*buf))
9279750Sdd					buf++;
9342873Sluoqi			else if (c != *buf++)
9442873Sluoqi				return 0;
951558Srgrimes			continue;
96127441Sbde		}
97127441Sbde
98207141Sjeff		c = *ptr++;
99207141Sjeff		switch (c) {
100207141Sjeff		case 0:
101207141Sjeff		case '%':
102127455Sbde			if (*buf++ != '%')
103127441Sbde				return 0;
104207141Sjeff			break;
105127441Sbde
106127441Sbde		case 'C':
107127441Sbde			buf = strptime(buf, Locale->date_fmt, tm);
108127441Sbde			if (buf == 0)
109127441Sbde				return 0;
110127441Sbde			break;
111127441Sbde
112127441Sbde		case 'c':
113127441Sbde			buf = strptime(buf, "%x %X", tm);
114200796Strasz			if (buf == 0)
115127441Sbde				return 0;
116127441Sbde			break;
117127441Sbde
118127441Sbde		case 'D':
119127441Sbde			buf = strptime(buf, "%m/%d/%y", tm);
120127441Sbde			if (buf == 0)
121127441Sbde				return 0;
122127441Sbde			break;
123127441Sbde
124127441Sbde		case 'R':
125127441Sbde			buf = strptime(buf, "%H:%M", tm);
126127441Sbde			if (buf == 0)
127127441Sbde				return 0;
128127441Sbde			break;
129127441Sbde
130127441Sbde		case 'r':
131127441Sbde			buf = strptime(buf, "%I:%M:%S %p", tm);
132127441Sbde			if (buf == 0)
133127441Sbde				return 0;
134127441Sbde			break;
135127441Sbde
136127441Sbde		case 'T':
137127441Sbde			buf = strptime(buf, "%H:%M:%S", tm);
138127441Sbde			if (buf == 0)
139127441Sbde				return 0;
140127441Sbde			break;
141127441Sbde
142127441Sbde		case 'X':
143127441Sbde			buf = strptime(buf, Locale->X_fmt, tm);
144207141Sjeff			if (buf == 0)
145207141Sjeff				return 0;
146207141Sjeff			break;
147207141Sjeff
148207141Sjeff		case 'x':
149207141Sjeff			buf = strptime(buf, Locale->x_fmt, tm);
150207141Sjeff			if (buf == 0)
151207141Sjeff				return 0;
152207141Sjeff			break;
153207141Sjeff
154207141Sjeff		case 'j':
155207141Sjeff			if (!isdigit((unsigned char)*buf))
156163842Spjd				return 0;
157163842Spjd
158163842Spjd			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
159163842Spjd				i *= 10;
160163842Spjd				i += *buf - '0';
161163842Spjd			}
162163842Spjd			if (i > 365)
163163842Spjd				return 0;
164163842Spjd
165163842Spjd			tm->tm_yday = i;
166163842Spjd			break;
167163842Spjd
168163842Spjd		case 'M':
169127441Sbde		case 'S':
170127441Sbde			if (*buf == 0 || isspace((unsigned char)*buf))
171127441Sbde				break;
172127441Sbde
173127441Sbde			if (!isdigit((unsigned char)*buf))
174127441Sbde				return 0;
175127441Sbde
176127441Sbde			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
177127441Sbde				i *= 10;
178127441Sbde				i += *buf - '0';
179127441Sbde			}
180127441Sbde			if (i > 59)
181127441Sbde				return 0;
182127441Sbde
183127441Sbde			if (c == 'M')
184127441Sbde				tm->tm_min = i;
185127441Sbde			else
186127441Sbde				tm->tm_sec = i;
187127441Sbde
188127441Sbde			if (*buf != 0 && isspace((unsigned char)*buf))
189127441Sbde				while (*ptr != 0 && !isspace((unsigned char)*ptr))
190127441Sbde					ptr++;
191127441Sbde			break;
192127441Sbde
193127441Sbde		case 'H':
194127441Sbde		case 'I':
195127441Sbde		case 'k':
196127441Sbde		case 'l':
197127441Sbde			if (!isdigit((unsigned char)*buf))
198127441Sbde				return 0;
199127441Sbde
200127441Sbde			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
201127441Sbde				i *= 10;
202127441Sbde				i += *buf - '0';
203127441Sbde			}
204127441Sbde			if (c == 'H' || c == 'k') {
205127441Sbde				if (i > 23)
206127441Sbde					return 0;
207127441Sbde			} else if (i > 11)
208200796Strasz				return 0;
209200796Strasz
210200796Strasz			tm->tm_hour = i;
211200796Strasz
212200796Strasz			if (*buf != 0 && isspace((unsigned char)*buf))
213200796Strasz				while (*ptr != 0 && !isspace((unsigned char)*ptr))
214200796Strasz					ptr++;
215200796Strasz			break;
216200796Strasz
217200796Strasz		case 'p':
218200796Strasz			len = strlen(Locale->am);
219200796Strasz			if (strncasecmp(buf, Locale->am, len) == 0) {
220127441Sbde				if (tm->tm_hour > 12)
221127441Sbde					return 0;
222127441Sbde				if (tm->tm_hour == 12)
223127441Sbde					tm->tm_hour = 0;
224127455Sbde				buf += len;
225127455Sbde				break;
226127441Sbde			}
227127441Sbde
228127441Sbde			len = strlen(Locale->pm);
229127441Sbde			if (strncasecmp(buf, Locale->pm, len) == 0) {
230127441Sbde				if (tm->tm_hour > 12)
231127441Sbde					return 0;
232127441Sbde				if (tm->tm_hour != 12)
233127441Sbde					tm->tm_hour += 12;
234127441Sbde				buf += len;
235127455Sbde				break;
236127441Sbde			}
237127455Sbde
238127441Sbde			return 0;
239127441Sbde
240127441Sbde		case 'A':
241127441Sbde		case 'a':
242127441Sbde			for (i = 0; i < asizeof(Locale->weekday); i++) {
243127441Sbde				len = strlen(Locale->weekday[i]);
244127441Sbde				if (strncasecmp(buf,
245127441Sbde						Locale->weekday[i],
246127441Sbde						len) == 0)
247127441Sbde					break;
248127441Sbde
249127441Sbde				len = strlen(Locale->wday[i]);
250127441Sbde				if (strncasecmp(buf,
251127441Sbde						Locale->wday[i],
252127441Sbde						len) == 0)
253127441Sbde					break;
254127441Sbde			}
255127441Sbde			if (i == asizeof(Locale->weekday))
256127441Sbde				return 0;
257127441Sbde
258127441Sbde			tm->tm_wday = i;
259127441Sbde			buf += len;
260127441Sbde			break;
261207141Sjeff
262207141Sjeff		case 'd':
263207141Sjeff		case 'e':
264207141Sjeff			if (!isdigit((unsigned char)*buf))
265207141Sjeff				return 0;
266207141Sjeff
267207141Sjeff			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
268207141Sjeff				i *= 10;
269207141Sjeff				i += *buf - '0';
270207141Sjeff			}
271127441Sbde			if (i > 31)
272127441Sbde				return 0;
273105120Srwatson
27469314Scharnier			tm->tm_mday = i;
27569314Scharnier
27669314Scharnier			if (*buf != 0 && isspace((unsigned char)*buf))
277127441Sbde				while (*ptr != 0 && !isspace((unsigned char)*ptr))
27869314Scharnier					ptr++;
279109963Sjmallett			break;
280109963Sjmallett
281109963Sjmallett		case 'B':
282109963Sjmallett		case 'b':
283207421Sjeff		case 'h':
284207421Sjeff			for (i = 0; i < asizeof(Locale->month); i++) {
285207421Sjeff				len = strlen(Locale->month[i]);
28669829Scharnier				if (strncasecmp(buf,
28769829Scharnier						Locale->month[i],
28869829Scharnier						len) == 0)
28969829Scharnier					break;
29069829Scharnier
29169829Scharnier				len = strlen(Locale->mon[i]);
29269829Scharnier				if (strncasecmp(buf,
293110174Sgordon						Locale->mon[i],
294110174Sgordon						len) == 0)
295110174Sgordon					break;
296110174Sgordon			}
297105120Srwatson			if (i == asizeof(Locale->month))
298200796Strasz				return 0;
299105120Srwatson
300105120Srwatson			tm->tm_mon = i;
301105120Srwatson			buf += len;
302200796Strasz			break;
303200796Strasz
304200796Strasz		case 'm':
305105120Srwatson			if (!isdigit((unsigned char)*buf))
306105120Srwatson				return 0;
307105120Srwatson
308105120Srwatson			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
309105120Srwatson				i *= 10;
310105120Srwatson				i += *buf - '0';
311105120Srwatson			}
312105120Srwatson			if (i < 1 || i > 12)
313105120Srwatson				return 0;
314105120Srwatson
315105120Srwatson			tm->tm_mon = i - 1;
316105206Srwatson
317105120Srwatson			if (*buf != 0 && isspace((unsigned char)*buf))
318105120Srwatson				while (*ptr != 0 && !isspace((unsigned char)*ptr))
319105120Srwatson					ptr++;
32069829Scharnier			break;
32169829Scharnier
322127455Sbde		case 'Y':
32369829Scharnier		case 'y':
32469829Scharnier			if (*buf == 0 || isspace((unsigned char)*buf))
32569829Scharnier				break;
326127455Sbde
32769829Scharnier			if (!isdigit((unsigned char)*buf))
32869829Scharnier				return 0;
32969829Scharnier
33075377Smckusick			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
33175377Smckusick				i *= 10;
332203769Smckusick				i += *buf - '0';
33375377Smckusick			}
33475377Smckusick			if (c == 'Y')
33575377Smckusick				i -= 1900;
33675377Smckusick			if (c == 'y' && i < 69)
33775377Smckusick				i += 100;
33875377Smckusick			if (i < 0)
33975377Smckusick				return 0;
34075377Smckusick
341207141Sjeff			tm->tm_year = i;
342207141Sjeff
343207141Sjeff			if (*buf != 0 && isspace((unsigned char)*buf))
344207141Sjeff				while (*ptr != 0 && !isspace((unsigned char)*ptr))
345207141Sjeff					ptr++;
346207141Sjeff			break;
347207141Sjeff		}
348207141Sjeff	}
349207141Sjeff
350207141Sjeff	return (char *)buf;
351207141Sjeff}
352207141Sjeff