xref: /freebsd/lib/libc/stdtime/strptime.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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
55 static 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
61 static char copyright[] =
62 "@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
63 static 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 
74 char *
75 strptime(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