strptime.c revision 46051
128019Sjoerg/*
228021Sjoerg * Powerdog Industries kindly requests feedback from anyone modifying
328021Sjoerg * this function:
428021Sjoerg *
528021Sjoerg * Date: Thu, 05 Jun 1997 23:17:17 -0400
628021Sjoerg * From: Kevin Ruddy <kevin.ruddy@powerdog.com>
728021Sjoerg * To: James FitzGibbon <james@nexis.net>
828021Sjoerg * Subject: Re: Use of your strptime(3) code (fwd)
928021Sjoerg *
1028021Sjoerg * The reason for the "no mod" clause was so that modifications would
1128021Sjoerg * come back and we could integrate them and reissue so that a wider
1228021Sjoerg * audience could use it (thereby spreading the wealth).  This has
1328021Sjoerg * made it possible to get strptime to work on many operating systems.
1428021Sjoerg * I'm not sure why that's "plain unacceptable" to the FreeBSD team.
1528021Sjoerg *
1628021Sjoerg * Anyway, you can change it to "with or without modification" as
1728021Sjoerg * you see fit.  Enjoy.
1828021Sjoerg *
1928021Sjoerg * Kevin Ruddy
2028021Sjoerg * Powerdog Industries, Inc.
2128021Sjoerg */
2228021Sjoerg/*
2328019Sjoerg * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
2428019Sjoerg *
2528021Sjoerg * Redistribution and use in source and binary forms, with or without
2628019Sjoerg * modification, are permitted provided that the following conditions
2728019Sjoerg * are met:
2828019Sjoerg * 1. Redistributions of source code must retain the above copyright
2928019Sjoerg *    notice, this list of conditions and the following disclaimer.
3028019Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
3128019Sjoerg *    notice, this list of conditions and the following disclaimer
3228019Sjoerg *    in the documentation and/or other materials provided with the
3328019Sjoerg *    distribution.
3428019Sjoerg * 3. All advertising materials mentioning features or use of this
3528019Sjoerg *    software must display the following acknowledgement:
3628019Sjoerg *      This product includes software developed by Powerdog Industries.
3728019Sjoerg * 4. The name of Powerdog Industries may not be used to endorse or
3828019Sjoerg *    promote products derived from this software without specific prior
3928019Sjoerg *    written permission.
4028019Sjoerg *
4128019Sjoerg * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
4228019Sjoerg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4328019Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4428019Sjoerg * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
4528019Sjoerg * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4628019Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4728019Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4828019Sjoerg * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4928019Sjoerg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5028019Sjoerg * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5128019Sjoerg * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5228019Sjoerg */
5328019Sjoerg
5428021Sjoerg#ifdef LIBC_RCS
5528021Sjoergstatic const char rcsid[] =
5646051Swes	"$Id: strptime.c,v 1.5 1999/04/25 01:42:18 wes Exp $";
5728021Sjoerg#endif
5828021Sjoerg
5928019Sjoerg#ifndef lint
6028021Sjoerg#ifndef NOID
6128019Sjoergstatic char copyright[] =
6228019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
6328021Sjoergstatic char sccsid[] = "@(#)strptime.c	0.1 (Powerdog) 94/03/27";
6428021Sjoerg#endif /* !defined NOID */
6528019Sjoerg#endif /* not lint */
6628019Sjoerg
6728019Sjoerg#include <time.h>
6828019Sjoerg#include <ctype.h>
6928019Sjoerg#include <string.h>
7028021Sjoerg#include "timelocal.h"
7128019Sjoerg
7228021Sjoerg#define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
7328019Sjoerg
7439113Sdtchar *
7528021Sjoergstrptime(const char *buf, const char *fmt, struct tm *tm)
7628019Sjoerg{
7728021Sjoerg	char	c;
7828021Sjoerg	const char *ptr;
7928021Sjoerg	int	i,
8028021Sjoerg		len;
8128019Sjoerg
8228021Sjoerg	ptr = fmt;
8328021Sjoerg	while (*ptr != 0) {
8428021Sjoerg		if (*buf == 0)
8528021Sjoerg			break;
8628019Sjoerg
8728021Sjoerg		c = *ptr++;
8828019Sjoerg
8928021Sjoerg		if (c != '%') {
9028164Sache			if (isspace((unsigned char)c))
9128164Sache				while (*buf != 0 && isspace((unsigned char)*buf))
9228021Sjoerg					buf++;
9328021Sjoerg			else if (c != *buf++)
9428021Sjoerg				return 0;
9528021Sjoerg			continue;
9628021Sjoerg		}
9728019Sjoerg
9828021Sjoerg		c = *ptr++;
9928021Sjoerg		switch (c) {
10028021Sjoerg		case 0:
10128021Sjoerg		case '%':
10228021Sjoerg			if (*buf++ != '%')
10328021Sjoerg				return 0;
10428021Sjoerg			break;
10528019Sjoerg
10628021Sjoerg		case 'C':
10728021Sjoerg			buf = strptime(buf, Locale->date_fmt, tm);
10828021Sjoerg			if (buf == 0)
10928021Sjoerg				return 0;
11028021Sjoerg			break;
11128019Sjoerg
11228021Sjoerg		case 'c':
11328021Sjoerg			buf = strptime(buf, "%x %X", tm);
11428021Sjoerg			if (buf == 0)
11528021Sjoerg				return 0;
11628021Sjoerg			break;
11728019Sjoerg
11828021Sjoerg		case 'D':
11928021Sjoerg			buf = strptime(buf, "%m/%d/%y", tm);
12028021Sjoerg			if (buf == 0)
12128021Sjoerg				return 0;
12228021Sjoerg			break;
12328019Sjoerg
12428021Sjoerg		case 'R':
12528021Sjoerg			buf = strptime(buf, "%H:%M", tm);
12628021Sjoerg			if (buf == 0)
12728021Sjoerg				return 0;
12828021Sjoerg			break;
12928019Sjoerg
13028021Sjoerg		case 'r':
13128021Sjoerg			buf = strptime(buf, "%I:%M:%S %p", tm);
13228021Sjoerg			if (buf == 0)
13328021Sjoerg				return 0;
13428021Sjoerg			break;
13528019Sjoerg
13628021Sjoerg		case 'T':
13728021Sjoerg			buf = strptime(buf, "%H:%M:%S", tm);
13828021Sjoerg			if (buf == 0)
13928021Sjoerg				return 0;
14028021Sjoerg			break;
14128019Sjoerg
14228021Sjoerg		case 'X':
14328021Sjoerg			buf = strptime(buf, Locale->X_fmt, tm);
14428021Sjoerg			if (buf == 0)
14528021Sjoerg				return 0;
14628021Sjoerg			break;
14728019Sjoerg
14828021Sjoerg		case 'x':
14928021Sjoerg			buf = strptime(buf, Locale->x_fmt, tm);
15028021Sjoerg			if (buf == 0)
15128021Sjoerg				return 0;
15228021Sjoerg			break;
15328019Sjoerg
15428021Sjoerg		case 'j':
15528164Sache			if (!isdigit((unsigned char)*buf))
15628021Sjoerg				return 0;
15728019Sjoerg
15828164Sache			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
15928021Sjoerg				i *= 10;
16028021Sjoerg				i += *buf - '0';
16128021Sjoerg			}
16228021Sjoerg			if (i > 365)
16328021Sjoerg				return 0;
16428019Sjoerg
16528021Sjoerg			tm->tm_yday = i;
16628021Sjoerg			break;
16728019Sjoerg
16828021Sjoerg		case 'M':
16928021Sjoerg		case 'S':
17028164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
17128021Sjoerg				break;
17228019Sjoerg
17328164Sache			if (!isdigit((unsigned char)*buf))
17428021Sjoerg				return 0;
17528019Sjoerg
17628164Sache			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
17728021Sjoerg				i *= 10;
17828021Sjoerg				i += *buf - '0';
17928021Sjoerg			}
18028021Sjoerg			if (i > 59)
18128021Sjoerg				return 0;
18228019Sjoerg
18328021Sjoerg			if (c == 'M')
18428021Sjoerg				tm->tm_min = i;
18528021Sjoerg			else
18628021Sjoerg				tm->tm_sec = i;
18728019Sjoerg
18828164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
18928164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
19028021Sjoerg					ptr++;
19128021Sjoerg			break;
19228019Sjoerg
19328021Sjoerg		case 'H':
19428021Sjoerg		case 'I':
19528021Sjoerg		case 'k':
19628021Sjoerg		case 'l':
19728164Sache			if (!isdigit((unsigned char)*buf))
19828021Sjoerg				return 0;
19928019Sjoerg
20028164Sache			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
20128021Sjoerg				i *= 10;
20228021Sjoerg				i += *buf - '0';
20328021Sjoerg			}
20428021Sjoerg			if (c == 'H' || c == 'k') {
20528021Sjoerg				if (i > 23)
20628021Sjoerg					return 0;
20728021Sjoerg			} else if (i > 11)
20828021Sjoerg				return 0;
20928019Sjoerg
21028021Sjoerg			tm->tm_hour = i;
21128019Sjoerg
21228164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
21328164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
21428021Sjoerg					ptr++;
21528021Sjoerg			break;
21628019Sjoerg
21728021Sjoerg		case 'p':
21828021Sjoerg			len = strlen(Locale->am);
21928021Sjoerg			if (strncasecmp(buf, Locale->am, len) == 0) {
22028021Sjoerg				if (tm->tm_hour > 12)
22128021Sjoerg					return 0;
22228021Sjoerg				if (tm->tm_hour == 12)
22328021Sjoerg					tm->tm_hour = 0;
22428021Sjoerg				buf += len;
22528021Sjoerg				break;
22628021Sjoerg			}
22728019Sjoerg
22828021Sjoerg			len = strlen(Locale->pm);
22928021Sjoerg			if (strncasecmp(buf, Locale->pm, len) == 0) {
23028021Sjoerg				if (tm->tm_hour > 12)
23128021Sjoerg					return 0;
23228021Sjoerg				if (tm->tm_hour != 12)
23328021Sjoerg					tm->tm_hour += 12;
23428021Sjoerg				buf += len;
23528021Sjoerg				break;
23628021Sjoerg			}
23728019Sjoerg
23828021Sjoerg			return 0;
23928019Sjoerg
24028021Sjoerg		case 'A':
24128021Sjoerg		case 'a':
24228021Sjoerg			for (i = 0; i < asizeof(Locale->weekday); i++) {
24328021Sjoerg				len = strlen(Locale->weekday[i]);
24428021Sjoerg				if (strncasecmp(buf,
24528021Sjoerg						Locale->weekday[i],
24628021Sjoerg						len) == 0)
24728021Sjoerg					break;
24828019Sjoerg
24928021Sjoerg				len = strlen(Locale->wday[i]);
25028021Sjoerg				if (strncasecmp(buf,
25128021Sjoerg						Locale->wday[i],
25228021Sjoerg						len) == 0)
25328021Sjoerg					break;
25428021Sjoerg			}
25528021Sjoerg			if (i == asizeof(Locale->weekday))
25628021Sjoerg				return 0;
25728019Sjoerg
25828021Sjoerg			tm->tm_wday = i;
25928021Sjoerg			buf += len;
26028021Sjoerg			break;
26128019Sjoerg
26228021Sjoerg		case 'd':
26328021Sjoerg		case 'e':
26428164Sache			if (!isdigit((unsigned char)*buf))
26528021Sjoerg				return 0;
26628019Sjoerg
26728164Sache			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
26828021Sjoerg				i *= 10;
26928021Sjoerg				i += *buf - '0';
27028021Sjoerg			}
27128021Sjoerg			if (i > 31)
27228021Sjoerg				return 0;
27328019Sjoerg
27428021Sjoerg			tm->tm_mday = i;
27528019Sjoerg
27628164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
27728164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
27828021Sjoerg					ptr++;
27928021Sjoerg			break;
28028019Sjoerg
28128021Sjoerg		case 'B':
28228021Sjoerg		case 'b':
28328021Sjoerg		case 'h':
28428021Sjoerg			for (i = 0; i < asizeof(Locale->month); i++) {
28528021Sjoerg				len = strlen(Locale->month[i]);
28628021Sjoerg				if (strncasecmp(buf,
28728021Sjoerg						Locale->month[i],
28828021Sjoerg						len) == 0)
28928021Sjoerg					break;
29028019Sjoerg
29128021Sjoerg				len = strlen(Locale->mon[i]);
29228021Sjoerg				if (strncasecmp(buf,
29328021Sjoerg						Locale->mon[i],
29428021Sjoerg						len) == 0)
29528021Sjoerg					break;
29628021Sjoerg			}
29728021Sjoerg			if (i == asizeof(Locale->month))
29828021Sjoerg				return 0;
29928019Sjoerg
30028021Sjoerg			tm->tm_mon = i;
30128021Sjoerg			buf += len;
30228021Sjoerg			break;
30328019Sjoerg
30428021Sjoerg		case 'm':
30528164Sache			if (!isdigit((unsigned char)*buf))
30628021Sjoerg				return 0;
30728019Sjoerg
30828164Sache			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
30928021Sjoerg				i *= 10;
31028021Sjoerg				i += *buf - '0';
31128021Sjoerg			}
31228021Sjoerg			if (i < 1 || i > 12)
31328021Sjoerg				return 0;
31428019Sjoerg
31528021Sjoerg			tm->tm_mon = i - 1;
31628019Sjoerg
31728164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
31828164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
31928021Sjoerg					ptr++;
32028021Sjoerg			break;
32128019Sjoerg
32228021Sjoerg		case 'Y':
32328021Sjoerg		case 'y':
32428164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
32528021Sjoerg				break;
32628019Sjoerg
32728164Sache			if (!isdigit((unsigned char)*buf))
32828021Sjoerg				return 0;
32928019Sjoerg
33028164Sache			for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
33128021Sjoerg				i *= 10;
33228021Sjoerg				i += *buf - '0';
33328021Sjoerg			}
33428021Sjoerg			if (c == 'Y')
33528021Sjoerg				i -= 1900;
33646051Swes			if (c == 'y' && i < 69)
33746042Swes				i += 100;
33828021Sjoerg			if (i < 0)
33928021Sjoerg				return 0;
34028019Sjoerg
34128021Sjoerg			tm->tm_year = i;
34228019Sjoerg
34328164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
34428164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
34528021Sjoerg					ptr++;
34628021Sjoerg			break;
34728021Sjoerg		}
34828021Sjoerg	}
34928019Sjoerg
35039113Sdt	return (char *)buf;
35128019Sjoerg}
352