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