Remove building with NOCRYPTO option
[minix.git] / crypto / external / bsd / heimdal / dist / lib / roken / strptime.c
blob975fd763cc08bc2fa54bb758e29ef57bcc2cf592
1 /* $NetBSD: strptime.c,v 1.1.1.1 2011/04/13 18:15:43 elric Exp $ */
3 /*
4 * Copyright (c) 1999, 2003, 2005 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of KTH nor the names of its contributors may be
20 * used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
35 #include <config.h>
36 #include <krb5/roken.h>
37 #ifdef TEST_STRPFTIME
38 #include "strpftime-test.h"
39 #endif
40 #include <ctype.h>
42 static const char *abb_weekdays[] = {
43 "Sun",
44 "Mon",
45 "Tue",
46 "Wed",
47 "Thu",
48 "Fri",
49 "Sat",
50 NULL
53 static const char *full_weekdays[] = {
54 "Sunday",
55 "Monday",
56 "Tuesday",
57 "Wednesday",
58 "Thursday",
59 "Friday",
60 "Saturday",
61 NULL
64 static const char *abb_month[] = {
65 "Jan",
66 "Feb",
67 "Mar",
68 "Apr",
69 "May",
70 "Jun",
71 "Jul",
72 "Aug",
73 "Sep",
74 "Oct",
75 "Nov",
76 "Dec",
77 NULL
80 static const char *full_month[] = {
81 "January",
82 "February",
83 "March",
84 "April",
85 "May",
86 "June",
87 "July",
88 "August",
89 "September",
90 "October",
91 "November",
92 "December",
93 NULL,
96 static const char *ampm[] = {
97 "am",
98 "pm",
99 NULL
103 * Try to match `*buf' to one of the strings in `strs'. Return the
104 * index of the matching string (or -1 if none). Also advance buf.
107 static int
108 match_string (const char **buf, const char **strs)
110 int i = 0;
112 for (i = 0; strs[i] != NULL; ++i) {
113 int len = strlen (strs[i]);
115 if (strncasecmp (*buf, strs[i], len) == 0) {
116 *buf += len;
117 return i;
120 return -1;
124 * Try to match `*buf' to at the most `n' characters and return the
125 * resulting number in `num'. Returns 0 or an error. Also advance
126 * buf.
129 static int
130 parse_number (const char **buf, int n, int *num)
132 char *s, *str;
133 int i;
135 str = malloc(n + 1);
136 if (str == NULL)
137 return -1;
139 /* skip whitespace */
140 for (; **buf != '\0' && isspace((unsigned char)(**buf)); (*buf)++)
143 /* parse at least n characters */
144 for (i = 0; **buf != '\0' && i < n && isdigit((unsigned char)(**buf)); i++, (*buf)++)
145 str[i] = **buf;
146 str[i] = '\0';
148 *num = strtol (str, &s, 10);
149 free(str);
150 if (s == str)
151 return -1;
153 return 0;
157 * tm_year is relative this year
160 const int tm_year_base = 1900;
163 * Return TRUE iff `year' was a leap year.
166 static int
167 is_leap_year (int year)
169 return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
173 * Return the weekday [0,6] (0 = Sunday) of the first day of `year'
176 static int
177 first_day (int year)
179 int ret = 4;
181 for (; year > 1970; --year)
182 ret = (ret + (is_leap_year (year) ? 366 : 365)) % 7;
183 return ret;
187 * Set `timeptr' given `wnum' (week number [0, 53])
190 static void
191 set_week_number_sun (struct tm *timeptr, int wnum)
193 int fday = first_day (timeptr->tm_year + tm_year_base);
195 timeptr->tm_yday = wnum * 7 + timeptr->tm_wday - fday;
196 if (timeptr->tm_yday < 0) {
197 timeptr->tm_wday = fday;
198 timeptr->tm_yday = 0;
203 * Set `timeptr' given `wnum' (week number [0, 53])
206 static void
207 set_week_number_mon (struct tm *timeptr, int wnum)
209 int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
211 timeptr->tm_yday = wnum * 7 + (timeptr->tm_wday + 6) % 7 - fday;
212 if (timeptr->tm_yday < 0) {
213 timeptr->tm_wday = (fday + 1) % 7;
214 timeptr->tm_yday = 0;
219 * Set `timeptr' given `wnum' (week number [0, 53])
222 static void
223 set_week_number_mon4 (struct tm *timeptr, int wnum)
225 int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
226 int offset = 0;
228 if (fday < 4)
229 offset += 7;
231 timeptr->tm_yday = offset + (wnum - 1) * 7 + timeptr->tm_wday - fday;
232 if (timeptr->tm_yday < 0) {
233 timeptr->tm_wday = fday;
234 timeptr->tm_yday = 0;
242 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
243 strptime (const char *buf, const char *format, struct tm *timeptr)
245 char c;
247 for (; (c = *format) != '\0'; ++format) {
248 char *s;
249 int ret;
251 if (isspace ((unsigned char)c)) {
252 while (isspace ((unsigned char)*buf))
253 ++buf;
254 } else if (c == '%' && format[1] != '\0') {
255 c = *++format;
256 if (c == 'E' || c == 'O')
257 c = *++format;
258 switch (c) {
259 case 'A' :
260 ret = match_string (&buf, full_weekdays);
261 if (ret < 0)
262 return NULL;
263 timeptr->tm_wday = ret;
264 break;
265 case 'a' :
266 ret = match_string (&buf, abb_weekdays);
267 if (ret < 0)
268 return NULL;
269 timeptr->tm_wday = ret;
270 break;
271 case 'B' :
272 ret = match_string (&buf, full_month);
273 if (ret < 0)
274 return NULL;
275 timeptr->tm_mon = ret;
276 break;
277 case 'b' :
278 case 'h' :
279 ret = match_string (&buf, abb_month);
280 if (ret < 0)
281 return NULL;
282 timeptr->tm_mon = ret;
283 break;
284 case 'C' :
285 if (parse_number(&buf, 2, &ret))
286 return NULL;
287 timeptr->tm_year = (ret * 100) - tm_year_base;
288 break;
289 case 'c' :
290 abort ();
291 case 'D' : /* %m/%d/%y */
292 s = strptime (buf, "%m/%d/%y", timeptr);
293 if (s == NULL)
294 return NULL;
295 buf = s;
296 break;
297 case 'd' :
298 case 'e' :
299 if (parse_number(&buf, 2, &ret))
300 return NULL;
301 timeptr->tm_mday = ret;
302 break;
303 case 'H' :
304 case 'k' :
305 if (parse_number(&buf, 2, &ret))
306 return NULL;
307 timeptr->tm_hour = ret;
308 break;
309 case 'I' :
310 case 'l' :
311 if (parse_number(&buf, 2, &ret))
312 return NULL;
313 if (ret == 12)
314 timeptr->tm_hour = 0;
315 else
316 timeptr->tm_hour = ret;
317 break;
318 case 'j' :
319 if (parse_number(&buf, 3, &ret))
320 return NULL;
321 if (ret == 0)
322 return NULL;
323 timeptr->tm_yday = ret - 1;
324 break;
325 case 'm' :
326 if (parse_number(&buf, 2, &ret))
327 return NULL;
328 if (ret == 0)
329 return NULL;
330 timeptr->tm_mon = ret - 1;
331 break;
332 case 'M' :
333 if (parse_number(&buf, 2, &ret))
334 return NULL;
335 timeptr->tm_min = ret;
336 break;
337 case 'n' :
338 while (isspace ((unsigned char)*buf))
339 buf++;
340 break;
341 case 'p' :
342 ret = match_string (&buf, ampm);
343 if (ret < 0)
344 return NULL;
345 if (timeptr->tm_hour == 0) {
346 if (ret == 1)
347 timeptr->tm_hour = 12;
348 } else
349 timeptr->tm_hour += 12;
350 break;
351 case 'r' : /* %I:%M:%S %p */
352 s = strptime (buf, "%I:%M:%S %p", timeptr);
353 if (s == NULL)
354 return NULL;
355 buf = s;
356 break;
357 case 'R' : /* %H:%M */
358 s = strptime (buf, "%H:%M", timeptr);
359 if (s == NULL)
360 return NULL;
361 buf = s;
362 break;
363 case 'S' :
364 if (parse_number(&buf, 2, &ret))
365 return NULL;
366 timeptr->tm_sec = ret;
367 break;
368 case 't' :
369 while (isspace ((unsigned char)*buf))
370 buf++;
371 break;
372 case 'T' : /* %H:%M:%S */
373 case 'X' :
374 s = strptime (buf, "%H:%M:%S", timeptr);
375 if (s == NULL)
376 return NULL;
377 buf = s;
378 break;
379 case 'u' :
380 if (parse_number(&buf, 1, &ret))
381 return NULL;
382 if (ret <= 0)
383 return NULL;
384 timeptr->tm_wday = ret - 1;
385 break;
386 case 'w' :
387 if (parse_number(&buf, 1, &ret))
388 return NULL;
389 timeptr->tm_wday = ret;
390 break;
391 case 'U' :
392 if (parse_number(&buf, 2, &ret))
393 return NULL;
394 set_week_number_sun (timeptr, ret);
395 break;
396 case 'V' :
397 if (parse_number(&buf, 2, &ret))
398 return NULL;
399 set_week_number_mon4 (timeptr, ret);
400 break;
401 case 'W' :
402 if (parse_number(&buf, 2, &ret))
403 return NULL;
404 set_week_number_mon (timeptr, ret);
405 break;
406 case 'x' :
407 s = strptime (buf, "%Y:%m:%d", timeptr);
408 if (s == NULL)
409 return NULL;
410 buf = s;
411 break;
412 case 'y' :
413 if (parse_number(&buf, 2, &ret))
414 return NULL;
415 if (ret < 70)
416 timeptr->tm_year = 100 + ret;
417 else
418 timeptr->tm_year = ret;
419 break;
420 case 'Y' :
421 if (parse_number(&buf, 4, &ret))
422 return NULL;
423 timeptr->tm_year = ret - tm_year_base;
424 break;
425 case 'Z' :
426 abort ();
427 case '\0' :
428 --format;
429 /* FALLTHROUGH */
430 case '%' :
431 if (*buf == '%')
432 ++buf;
433 else
434 return NULL;
435 break;
436 default :
437 if (*buf == '%' || *++buf == c)
438 ++buf;
439 else
440 return NULL;
441 break;
443 } else {
444 if (*buf == c)
445 ++buf;
446 else
447 return NULL;
450 return rk_UNCONST(buf);