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