fixed more binutils issues (newer gcc/libc)
[zpugcc/jano.git] / toolchain / gcc / newlib / libc / time / strptime.c
blob929ad9211c3c4ccd355df83171c5c8f8a48491f6
1 /*
2 * Copyright (c) 1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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. */
33 #include <stddef.h>
34 #include <stdio.h>
35 #include <time.h>
37 static const char *abb_weekdays[] = {
38 "Sun",
39 "Mon",
40 "Tue",
41 "Wed",
42 "Thu",
43 "Fri",
44 "Sat",
45 NULL
48 static const char *full_weekdays[] = {
49 "Sunday",
50 "Monday",
51 "Tuesday",
52 "Wednesday",
53 "Thursday",
54 "Friday",
55 "Saturday",
56 NULL
59 static const char *abb_month[] = {
60 "Jan",
61 "Feb",
62 "Mar",
63 "Apr",
64 "May",
65 "Jun",
66 "Jul",
67 "Aug",
68 "Sep",
69 "Oct",
70 "Nov",
71 "Dec",
72 NULL
75 static const char *full_month[] = {
76 "January",
77 "February",
78 "Mars",
79 "April",
80 "May",
81 "June",
82 "July",
83 "August",
84 "September",
85 "October",
86 "November",
87 "December",
88 NULL,
91 static const char *ampm[] = {
92 "am",
93 "pm",
94 NULL
98 * tm_year is relative this year
100 const int tm_year_base = 1900;
103 * Return TRUE iff `year' was a leap year.
104 * Needed for strptime.
106 static int
107 is_leap_year (int year)
109 return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
112 /* Needed for strptime. */
113 static int
114 match_string (const char **buf, const char **strs)
116 int i = 0;
118 for (i = 0; strs[i] != NULL; ++i) {
119 int len = strlen (strs[i]);
121 if (strncasecmp (*buf, strs[i], len) == 0) {
122 *buf += len;
123 return i;
126 return -1;
129 /* Needed for strptime. */
130 static int
131 first_day (int year)
133 int ret = 4;
135 for (; year > 1970; --year)
136 ret = (ret + 365 + is_leap_year (year) ? 1 : 0) % 7;
137 return ret;
141 * Set `timeptr' given `wnum' (week number [0, 53])
142 * Needed for strptime
145 static void
146 set_week_number_sun (struct tm *timeptr, int wnum)
148 int fday = first_day (timeptr->tm_year + tm_year_base);
150 timeptr->tm_yday = wnum * 7 + timeptr->tm_wday - fday;
151 if (timeptr->tm_yday < 0) {
152 timeptr->tm_wday = fday;
153 timeptr->tm_yday = 0;
158 * Set `timeptr' given `wnum' (week number [0, 53])
159 * Needed for strptime
162 static void
163 set_week_number_mon (struct tm *timeptr, int wnum)
165 int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
167 timeptr->tm_yday = wnum * 7 + (timeptr->tm_wday + 6) % 7 - fday;
168 if (timeptr->tm_yday < 0) {
169 timeptr->tm_wday = (fday + 1) % 7;
170 timeptr->tm_yday = 0;
175 * Set `timeptr' given `wnum' (week number [0, 53])
176 * Needed for strptime
178 static void
179 set_week_number_mon4 (struct tm *timeptr, int wnum)
181 int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
182 int offset = 0;
184 if (fday < 4)
185 offset += 7;
187 timeptr->tm_yday = offset + (wnum - 1) * 7 + timeptr->tm_wday - fday;
188 if (timeptr->tm_yday < 0) {
189 timeptr->tm_wday = fday;
190 timeptr->tm_yday = 0;
194 /* strptime: roken */
195 //extern "C"
196 char *
197 //strptime (const char *buf, const char *format, struct tm *timeptr)
198 _DEFUN (strptime, (buf, format, timeptr),
199 _CONST char *buf _AND
200 _CONST char *format _AND
201 struct tm *timeptr)
203 char c;
205 for (; (c = *format) != '\0'; ++format) {
206 char *s;
207 int ret;
209 if (isspace (c)) {
210 while (isspace (*buf))
211 ++buf;
212 } else if (c == '%' && format[1] != '\0') {
213 c = *++format;
214 if (c == 'E' || c == 'O')
215 c = *++format;
216 switch (c) {
217 case 'A' :
218 ret = match_string (&buf, full_weekdays);
219 if (ret < 0)
220 return NULL;
221 timeptr->tm_wday = ret;
222 break;
223 case 'a' :
224 ret = match_string (&buf, abb_weekdays);
225 if (ret < 0)
226 return NULL;
227 timeptr->tm_wday = ret;
228 break;
229 case 'B' :
230 ret = match_string (&buf, full_month);
231 if (ret < 0)
232 return NULL;
233 timeptr->tm_mon = ret;
234 break;
235 case 'b' :
236 case 'h' :
237 ret = match_string (&buf, abb_month);
238 if (ret < 0)
239 return NULL;
240 timeptr->tm_mon = ret;
241 break;
242 case 'C' :
243 ret = strtol (buf, &s, 10);
244 if (s == buf)
245 return NULL;
246 timeptr->tm_year = (ret * 100) - tm_year_base;
247 buf = s;
248 break;
249 case 'c' :
250 abort ();
251 case 'D' : /* %m/%d/%y */
252 s = strptime (buf, "%m/%d/%y", timeptr);
253 if (s == NULL)
254 return NULL;
255 buf = s;
256 break;
257 case 'd' :
258 case 'e' :
259 ret = strtol (buf, &s, 10);
260 if (s == buf)
261 return NULL;
262 timeptr->tm_mday = ret;
263 buf = s;
264 break;
265 case 'H' :
266 case 'k' :
267 ret = strtol (buf, &s, 10);
268 if (s == buf)
269 return NULL;
270 timeptr->tm_hour = ret;
271 buf = s;
272 break;
273 case 'I' :
274 case 'l' :
275 ret = strtol (buf, &s, 10);
276 if (s == buf)
277 return NULL;
278 if (ret == 12)
279 timeptr->tm_hour = 0;
280 else
281 timeptr->tm_hour = ret;
282 buf = s;
283 break;
284 case 'j' :
285 ret = strtol (buf, &s, 10);
286 if (s == buf)
287 return NULL;
288 timeptr->tm_yday = ret - 1;
289 buf = s;
290 break;
291 case 'm' :
292 ret = strtol (buf, &s, 10);
293 if (s == buf)
294 return NULL;
295 timeptr->tm_mon = 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_min = ret;
303 buf = s;
304 break;
305 case 'n' :
306 if (*buf == '\n')
307 ++buf;
308 else
309 return NULL;
310 break;
311 case 'p' :
312 ret = match_string (&buf, ampm);
313 if (ret < 0)
314 return NULL;
315 if (timeptr->tm_hour == 0) {
316 if (ret == 1)
317 timeptr->tm_hour = 12;
318 } else
319 timeptr->tm_hour += 12;
320 break;
321 case 'r' : /* %I:%M:%S %p */
322 s = strptime (buf, "%I:%M:%S %p", timeptr);
323 if (s == NULL)
324 return NULL;
325 buf = s;
326 break;
327 case 'R' : /* %H:%M */
328 s = strptime (buf, "%H:%M", timeptr);
329 if (s == NULL)
330 return NULL;
331 buf = s;
332 break;
333 case 'S' :
334 ret = strtol (buf, &s, 10);
335 if (s == buf)
336 return NULL;
337 timeptr->tm_sec = ret;
338 buf = s;
339 break;
340 case 't' :
341 if (*buf == '\t')
342 ++buf;
343 else
344 return NULL;
345 break;
346 case 'T' : /* %H:%M:%S */
347 case 'X' :
348 s = strptime (buf, "%H:%M:%S", timeptr);
349 if (s == NULL)
350 return NULL;
351 buf = s;
352 break;
353 case 'u' :
354 ret = strtol (buf, &s, 10);
355 if (s == buf)
356 return NULL;
357 timeptr->tm_wday = ret - 1;
358 buf = s;
359 break;
360 case 'w' :
361 ret = strtol (buf, &s, 10);
362 if (s == buf)
363 return NULL;
364 timeptr->tm_wday = ret;
365 buf = s;
366 break;
367 case 'U' :
368 ret = strtol (buf, &s, 10);
369 if (s == buf)
370 return NULL;
371 set_week_number_sun (timeptr, ret);
372 buf = s;
373 break;
374 case 'V' :
375 ret = strtol (buf, &s, 10);
376 if (s == buf)
377 return NULL;
378 set_week_number_mon4 (timeptr, ret);
379 buf = s;
380 break;
381 case 'W' :
382 ret = strtol (buf, &s, 10);
383 if (s == buf)
384 return NULL;
385 set_week_number_mon (timeptr, ret);
386 buf = s;
387 break;
388 case 'x' :
389 s = strptime (buf, "%Y:%m:%d", timeptr);
390 if (s == NULL)
391 return NULL;
392 buf = s;
393 break;
394 case 'y' :
395 ret = strtol (buf, &s, 10);
396 if (s == buf)
397 return NULL;
398 if (ret < 70)
399 timeptr->tm_year = 100 + ret;
400 else
401 timeptr->tm_year = ret;
402 buf = s;
403 break;
404 case 'Y' :
405 ret = strtol (buf, &s, 10);
406 if (s == buf)
407 return NULL;
408 timeptr->tm_year = ret - tm_year_base;
409 buf = s;
410 break;
411 case 'Z' :
412 abort ();
413 case '\0' :
414 --format;
415 /* FALLTHROUGH */
416 case '%' :
417 if (*buf == '%')
418 ++buf;
419 else
420 return NULL;
421 break;
422 default :
423 if (*buf == '%' || *++buf == c)
424 ++buf;
425 else
426 return NULL;
427 break;
429 } else {
430 if (*buf == c)
431 ++buf;
432 else
433 return NULL;
436 return (char *)buf;