]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/language/c/libc/time/v2_0/src/strptime.cxx
6c857e735dd33db262f9bb814a3c796c35564d5a
[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     timeptr->tm_yday = 1;  // Initialize to a well known, valid date
190     timeptr->tm_isdst = 0; //   Tuesday March 18 14:05:00 2003 UTC
191     timeptr->tm_sec = 0;
192     timeptr->tm_min = 5;
193     timeptr->tm_hour = 14;
194     timeptr->tm_mday = 18;
195     timeptr->tm_mon = 2;
196     timeptr->tm_year = 103;
197     timeptr->tm_wday = 2;
198     timeptr->tm_yday = 77;
199
200     for (; (c = *format) != '\0'; ++format) {
201         char *s;
202         int ret;
203
204         if (isspace (c)) {
205             while (isspace (*buf))
206                 ++buf;
207         } else if (c == '%' && format[1] != '\0') {
208             c = *++format;
209             if (c == 'E' || c == 'O')
210                 c = *++format;
211             switch (c) {
212             case 'A' :
213                 ret = match_string (&buf, weekdays, 0);
214                 if (ret < 0)
215                     return NULL;
216                 timeptr->tm_wday = ret;
217                 break;
218             case 'a' :
219                 ret = match_string (&buf, weekdays, 3);
220                 if (ret < 0)
221                     return NULL;
222                 timeptr->tm_wday = ret;
223                 break;
224             case 'B' :
225                 ret = match_string (&buf, month, 0);
226                 if (ret < 0)
227                     return NULL;
228                 timeptr->tm_mon = ret;
229                 break;
230             case 'b' :
231             case 'h' :
232                 ret = match_string (&buf, month, 3);
233                 if (ret < 0)
234                     return NULL;
235                 timeptr->tm_mon = ret;
236                 break;
237             case 'C' :
238                 ret = strtol (buf, &s, 10);
239                 if (s == buf)
240                     return NULL;
241                 timeptr->tm_year = (ret * 100) - tm_year_base;
242                 buf = s;
243                 break;
244             case 'c' :
245                 // Date and Time in the current locale - unsupported
246                 return NULL;
247             case 'D' :          /* %m/%d/%y */
248                 s = strptime (buf, "%m/%d/%y", timeptr);
249                 if (s == NULL)
250                     return NULL;
251                 buf = s;
252                 break;
253             case 'd' :
254             case 'e' :
255                 ret = strtol (buf, &s, 10);
256                 if (s == buf)
257                     return NULL;
258                 timeptr->tm_mday = ret;
259                 buf = s;
260                 break;
261             case 'H' :
262             case 'k' :
263                 ret = strtol (buf, &s, 10);
264                 if (s == buf)
265                     return NULL;
266                 timeptr->tm_hour = ret;
267                 buf = s;
268                 break;
269             case 'I' :
270             case 'l' :
271                 ret = strtol (buf, &s, 10);
272                 if (s == buf)
273                     return NULL;
274                 if (ret == 12)
275                     timeptr->tm_hour = 0;
276                 else
277                     timeptr->tm_hour = ret;
278                 buf = s;
279                 break;
280             case 'j' :
281                 ret = strtol (buf, &s, 10);
282                 if (s == buf)
283                     return NULL;
284                 timeptr->tm_yday = ret - 1;
285                 buf = s;
286                 break;
287             case 'm' :
288                 ret = strtol (buf, &s, 10);
289                 if (s == buf)
290                     return NULL;
291                 timeptr->tm_mon = ret - 1;
292                 buf = s;
293                 break;
294             case 'M' :
295                 ret = strtol (buf, &s, 10);
296                 if (s == buf)
297                     return NULL;
298                 timeptr->tm_min = ret;
299                 buf = s;
300                 break;
301             case 'n' :
302                 if (*buf == '\n')
303                     ++buf;
304                 else
305                     return NULL;
306                 break;
307             case 'p' :
308                 ret = match_string (&buf, ampm, 0);
309                 if (ret < 0)
310                     return NULL;
311                 if (timeptr->tm_hour == 0) {
312                     if (ret == 1)
313                         timeptr->tm_hour = 12;
314                 } else
315                     timeptr->tm_hour += 12;
316                 break;
317             case 'r' :          /* %I:%M:%S %p */
318                 s = strptime (buf, "%I:%M:%S %p", timeptr);
319                 if (s == NULL)
320                     return NULL;
321                 buf = s;
322                 break;
323             case 'R' :          /* %H:%M */
324                 s = strptime (buf, "%H:%M", timeptr);
325                 if (s == NULL)
326                     return NULL;
327                 buf = s;
328                 break;
329             case 'S' :
330                 ret = strtol (buf, &s, 10);
331                 if (s == buf)
332                     return NULL;
333                 timeptr->tm_sec = ret;
334                 buf = s;
335                 break;
336             case 't' :
337                 if (*buf == '\t')
338                     ++buf;
339                 else
340                     return NULL;
341                 break;
342             case 'T' :          /* %H:%M:%S */
343             case 'X' :
344                 s = strptime (buf, "%H:%M:%S", timeptr);
345                 if (s == NULL)
346                     return NULL;
347                 buf = s;
348                 break;
349             case 'u' :
350                 ret = strtol (buf, &s, 10);
351                 if (s == buf)
352                     return NULL;
353                 timeptr->tm_wday = ret - 1;
354                 buf = s;
355                 break;
356             case 'w' :
357                 ret = strtol (buf, &s, 10);
358                 if (s == buf)
359                     return NULL;
360                 timeptr->tm_wday = ret;
361                 buf = s;
362                 break;
363             case 'U' :
364                 ret = strtol (buf, &s, 10);
365                 if (s == buf)
366                     return NULL;
367                 set_week_number_sun (timeptr, ret);
368                 buf = s;
369                 break;
370             case 'V' :
371                 ret = strtol (buf, &s, 10);
372                 if (s == buf)
373                     return NULL;
374                 set_week_number_mon4 (timeptr, ret);
375                 buf = s;
376                 break;
377             case 'W' :
378                 ret = strtol (buf, &s, 10);
379                 if (s == buf)
380                     return NULL;
381                 set_week_number_mon (timeptr, ret);
382                 buf = s;
383                 break;
384             case 'x' :
385                 s = strptime (buf, "%Y:%m:%d", timeptr);
386                 if (s == NULL)
387                     return NULL;
388                 buf = s;
389                 break;
390             case 'y' :
391                 ret = strtol (buf, &s, 10);
392                 if (s == buf)
393                     return NULL;
394                 if (ret < 70)
395                     timeptr->tm_year = 100 + ret;
396                 else
397                     timeptr->tm_year = ret;
398                 buf = s;
399                 break;
400             case 'Y' :
401                 ret = strtol (buf, &s, 10);
402                 if (s == buf)
403                     return NULL;
404                 timeptr->tm_year = ret - tm_year_base;
405                 buf = s;
406                 break;
407             case 'Z' :
408                 // Timezone spec not handled
409                 return NULL;
410             case '\0' :
411                 --format;
412                 /* FALLTHROUGH */
413             case '%' :
414                 if (*buf == '%')
415                     ++buf;
416                 else
417                     return NULL;
418                 break;
419             default :
420                 if (*buf == '%' || *++buf == c)
421                     ++buf;
422                 else
423                     return NULL;
424                 break;
425             }
426         } else {
427             if (*buf == c)
428                 ++buf;
429             else
430                 return NULL;
431         }
432     }
433     return (char *)buf;
434 }
435
436 // strptime.cxx