]> git.saurik.com Git - apple/libc.git/blob - stdtime/FreeBSD/strptime.c.patch
Libc-498.1.7.tar.gz
[apple/libc.git] / stdtime / FreeBSD / strptime.c.patch
1 --- strptime.c.orig 2008-04-24 01:10:36.000000000 -0700
2 +++ strptime.c 2008-04-24 02:01:31.000000000 -0700
3 @@ -61,10 +61,13 @@ static char sccsid[] __unused = "@(#)str
4 #endif /* not lint */
5 __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.35 2003/11/17 04:19:15 nectar Exp $");
6
7 +#include "xlocale_private.h"
8 +
9 #include "namespace.h"
10 #include <time.h>
11 #include <ctype.h>
12 #include <errno.h>
13 +#include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <pthread.h>
17 @@ -72,30 +75,41 @@ __FBSDID("$FreeBSD: src/lib/libc/stdtime
18 #include "libc_private.h"
19 #include "timelocal.h"
20
21 -static char * _strptime(const char *, const char *, struct tm *, int *);
22 +static char * _strptime(const char *, const char *, struct tm *, int *, locale_t) __DARWIN_ALIAS(_strptime);
23 +time_t _mktime(struct tm *, const char *);
24
25 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
26
27 +enum {CONVERT_NONE, CONVERT_GMT, CONVERT_ZONE};
28 +
29 static char *
30 -_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
31 +_strptime(const char *buf, const char *fmt, struct tm *tm, int *convp, locale_t loc)
32 {
33 char c;
34 const char *ptr;
35 int i,
36 + year = -1,
37 + yday = 0,
38 + wday = -1,
39 len;
40 int Ealternative, Oalternative;
41 - struct lc_time_T *tptr = __get_current_time_locale();
42 + struct lc_time_T *tptr = __get_current_time_locale(loc);
43
44 ptr = fmt;
45 while (*ptr != 0) {
46 - if (*buf == 0)
47 - break;
48 + if (*buf == 0) {
49 + fmt = ptr;
50 + while (isspace_l((unsigned char)*ptr, loc)) {
51 + ptr++;
52 + }
53 + return ((*ptr)==0) ? fmt : 0; /* trailing whitespace is ok */
54 + }
55
56 c = *ptr++;
57
58 if (c != '%') {
59 - if (isspace((unsigned char)c))
60 - while (*buf != 0 && isspace((unsigned char)*buf))
61 + if (isspace_l((unsigned char)c, loc))
62 + while (*buf != 0 && isspace_l((unsigned char)*buf, loc))
63 buf++;
64 else if (c != *buf++)
65 return 0;
66 @@ -114,18 +128,18 @@ label:
67 break;
68
69 case '+':
70 - buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
71 + buf = _strptime(buf, tptr->date_fmt, tm, convp, loc);
72 if (buf == 0)
73 return 0;
74 break;
75
76 case 'C':
77 - if (!isdigit((unsigned char)*buf))
78 + if (!isdigit_l((unsigned char)*buf, loc))
79 return 0;
80
81 /* XXX This will break for 3-digit centuries. */
82 len = 2;
83 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
84 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
85 i *= 10;
86 i += *buf - '0';
87 len--;
88 @@ -133,17 +147,21 @@ label:
89 if (i < 19)
90 return 0;
91
92 + if (year != -1)
93 + tm->tm_year = (year % 100) + i * 100 - 1900;
94 + else
95 tm->tm_year = i * 100 - 1900;
96 + year = tm->tm_year;
97 break;
98
99 case 'c':
100 - buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
101 + buf = _strptime(buf, tptr->c_fmt, tm, convp, loc);
102 if (buf == 0)
103 return 0;
104 break;
105
106 case 'D':
107 - buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
108 + buf = _strptime(buf, "%m/%d/%y", tm, convp, loc);
109 if (buf == 0)
110 return 0;
111 break;
112 @@ -161,47 +179,55 @@ label:
113 goto label;
114
115 case 'F':
116 - buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
117 + buf = _strptime(buf, "%Y-%m-%d", tm, convp, loc);
118 if (buf == 0)
119 return 0;
120 break;
121
122 case 'R':
123 - buf = _strptime(buf, "%H:%M", tm, GMTp);
124 + buf = _strptime(buf, "%H:%M", tm, convp, loc);
125 if (buf == 0)
126 return 0;
127 break;
128
129 case 'r':
130 - buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
131 + buf = _strptime(buf, tptr->ampm_fmt, tm, convp, loc);
132 if (buf == 0)
133 return 0;
134 break;
135
136 + case 'n':
137 + case 't':
138 + if (!isspace((unsigned char)*buf))
139 + return 0;
140 + while (isspace((unsigned char)*buf))
141 + buf++;
142 + break;
143 +
144 case 'T':
145 - buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
146 + buf = _strptime(buf, "%H:%M:%S", tm, convp, loc);
147 if (buf == 0)
148 return 0;
149 break;
150
151 case 'X':
152 - buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
153 + buf = _strptime(buf, tptr->X_fmt, tm, convp, loc);
154 if (buf == 0)
155 return 0;
156 break;
157
158 case 'x':
159 - buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
160 + buf = _strptime(buf, tptr->x_fmt, tm, convp, loc);
161 if (buf == 0)
162 return 0;
163 break;
164
165 case 'j':
166 - if (!isdigit((unsigned char)*buf))
167 + if (!isdigit_l((unsigned char)*buf, loc))
168 return 0;
169
170 len = 3;
171 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
172 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
173 i *= 10;
174 i += *buf - '0';
175 len--;
176 @@ -209,19 +235,19 @@ label:
177 if (i < 1 || i > 366)
178 return 0;
179
180 - tm->tm_yday = i - 1;
181 + tm->tm_yday = yday = i - 1;
182 break;
183
184 case 'M':
185 case 'S':
186 - if (*buf == 0 || isspace((unsigned char)*buf))
187 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
188 break;
189
190 - if (!isdigit((unsigned char)*buf))
191 + if (!isdigit_l((unsigned char)*buf, loc))
192 return 0;
193
194 len = 2;
195 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
196 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
197 i *= 10;
198 i += *buf - '0';
199 len--;
200 @@ -237,8 +263,8 @@ label:
201 tm->tm_sec = i;
202 }
203
204 - if (*buf != 0 && isspace((unsigned char)*buf))
205 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
206 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
207 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
208 ptr++;
209 break;
210
211 @@ -254,11 +280,11 @@ label:
212 * XXX The %l specifier may gobble one too many
213 * digits if used incorrectly.
214 */
215 - if (!isdigit((unsigned char)*buf))
216 + if (!isdigit_l((unsigned char)*buf, loc))
217 return 0;
218
219 len = 2;
220 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
221 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
222 i *= 10;
223 i += *buf - '0';
224 len--;
225 @@ -271,8 +297,8 @@ label:
226
227 tm->tm_hour = i;
228
229 - if (*buf != 0 && isspace((unsigned char)*buf))
230 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
231 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
232 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
233 ptr++;
234 break;
235
236 @@ -282,7 +308,7 @@ label:
237 * specifiers.
238 */
239 len = strlen(tptr->am);
240 - if (strncasecmp(buf, tptr->am, len) == 0) {
241 + if (strncasecmp_l(buf, tptr->am, len, loc) == 0) {
242 if (tm->tm_hour > 12)
243 return 0;
244 if (tm->tm_hour == 12)
245 @@ -292,7 +318,7 @@ label:
246 }
247
248 len = strlen(tptr->pm);
249 - if (strncasecmp(buf, tptr->pm, len) == 0) {
250 + if (strncasecmp_l(buf, tptr->pm, len, loc) == 0) {
251 if (tm->tm_hour > 12)
252 return 0;
253 if (tm->tm_hour != 12)
254 @@ -307,34 +333,28 @@ label:
255 case 'a':
256 for (i = 0; i < asizeof(tptr->weekday); i++) {
257 len = strlen(tptr->weekday[i]);
258 - if (strncasecmp(buf, tptr->weekday[i],
259 - len) == 0)
260 + if (strncasecmp_l(buf, tptr->weekday[i],
261 + len, loc) == 0)
262 break;
263 len = strlen(tptr->wday[i]);
264 - if (strncasecmp(buf, tptr->wday[i],
265 - len) == 0)
266 + if (strncasecmp_l(buf, tptr->wday[i],
267 + len, loc) == 0)
268 break;
269 }
270 if (i == asizeof(tptr->weekday))
271 return 0;
272
273 - tm->tm_wday = i;
274 + tm->tm_wday = wday = i;
275 buf += len;
276 break;
277
278 - case 'U':
279 - case 'W':
280 - /*
281 - * XXX This is bogus, as we can not assume any valid
282 - * information present in the tm structure at this
283 - * point to calculate a real value, so just check the
284 - * range for now.
285 - */
286 - if (!isdigit((unsigned char)*buf))
287 + case 'U': /* Sunday week */
288 + case 'W': /* Monday week */
289 + if (!isdigit_l((unsigned char)*buf, loc))
290 return 0;
291
292 len = 2;
293 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
294 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
295 i *= 10;
296 i += *buf - '0';
297 len--;
298 @@ -342,23 +362,46 @@ label:
299 if (i > 53)
300 return 0;
301
302 - if (*buf != 0 && isspace((unsigned char)*buf))
303 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
304 + /* Calculate yday if we have enough data */
305 + if ((year != -1) && (wday != -1)) {
306 + struct tm mktm;
307 + mktm.tm_year = year;
308 + mktm.tm_mon = 0;
309 + mktm.tm_mday = 1;
310 + mktm.tm_sec = 1;
311 + mktm.tm_min = mktm.tm_hour = 0;
312 + mktm.tm_isdst = 0;
313 + mktm.tm_gmtoff = 0;
314 + if (mktime(&mktm) != -1) {
315 + /* yday0 == Jan 1 == mktm.tm_wday */
316 + int delta = wday - mktm.tm_wday;
317 + if (!wday && c =='W')
318 + i++; /* Sunday is part of the following week */
319 + yday = 7 * i + delta;
320 + if (yday < 0)
321 + yday += 7;
322 + tm->tm_yday = yday;
323 + }
324 + }
325 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
326 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
327 ptr++;
328 break;
329
330 - case 'w':
331 - if (!isdigit((unsigned char)*buf))
332 + case 'u': /* [1,7] */
333 + case 'w': /* [0,6] */
334 + if (!isdigit_l((unsigned char)*buf, loc))
335 return 0;
336
337 i = *buf - '0';
338 - if (i > 6)
339 + if (i > 6 + (c == 'u'))
340 return 0;
341 -
342 - tm->tm_wday = i;
343 -
344 - if (*buf != 0 && isspace((unsigned char)*buf))
345 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
346 + if (i == 7)
347 + i = 0;
348 + tm->tm_wday = wday = i;
349 + buf++;
350 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
351 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
352 ptr++;
353 break;
354
355 @@ -372,11 +415,18 @@ label:
356 * XXX The %e specifier may gobble one too many
357 * digits if used incorrectly.
358 */
359 - if (!isdigit((unsigned char)*buf))
360 + /* Leading space is ok if date is single digit */
361 + len = 2;
362 + if (isspace_l((unsigned char)buf[0], loc) &&
363 + isdigit_l((unsigned char)buf[1], loc) &&
364 + !isdigit_l((unsigned char)buf[2], loc)) {
365 + len = 1;
366 + buf++;
367 + }
368 + if (!isdigit_l((unsigned char)*buf, loc))
369 return 0;
370
371 - len = 2;
372 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
373 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
374 i *= 10;
375 i += *buf - '0';
376 len--;
377 @@ -386,8 +436,8 @@ label:
378
379 tm->tm_mday = i;
380
381 - if (*buf != 0 && isspace((unsigned char)*buf))
382 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
383 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
384 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
385 ptr++;
386 break;
387
388 @@ -398,19 +448,19 @@ label:
389 if (Oalternative) {
390 if (c == 'B') {
391 len = strlen(tptr->alt_month[i]);
392 - if (strncasecmp(buf,
393 + if (strncasecmp_l(buf,
394 tptr->alt_month[i],
395 - len) == 0)
396 + len, loc) == 0)
397 break;
398 }
399 } else {
400 len = strlen(tptr->month[i]);
401 - if (strncasecmp(buf, tptr->month[i],
402 - len) == 0)
403 + if (strncasecmp_l(buf, tptr->month[i],
404 + len, loc) == 0)
405 break;
406 len = strlen(tptr->mon[i]);
407 - if (strncasecmp(buf, tptr->mon[i],
408 - len) == 0)
409 + if (strncasecmp_l(buf, tptr->mon[i],
410 + len, loc) == 0)
411 break;
412 }
413 }
414 @@ -422,11 +472,11 @@ label:
415 break;
416
417 case 'm':
418 - if (!isdigit((unsigned char)*buf))
419 + if (!isdigit_l((unsigned char)*buf, loc))
420 return 0;
421
422 len = 2;
423 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
424 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
425 i *= 10;
426 i += *buf - '0';
427 len--;
428 @@ -436,8 +486,8 @@ label:
429
430 tm->tm_mon = i - 1;
431
432 - if (*buf != 0 && isspace((unsigned char)*buf))
433 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
434 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
435 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
436 ptr++;
437 break;
438
439 @@ -450,7 +500,7 @@ label:
440
441 sverrno = errno;
442 errno = 0;
443 - n = strtol(buf, &cp, 10);
444 + n = strtol_l(buf, &cp, 10, loc);
445 if (errno == ERANGE || (long)(t = n) != n) {
446 errno = sverrno;
447 return 0;
448 @@ -458,24 +508,37 @@ label:
449 errno = sverrno;
450 buf = cp;
451 gmtime_r(&t, tm);
452 - *GMTp = 1;
453 + *convp = CONVERT_GMT;
454 }
455 break;
456
457 case 'Y':
458 case 'y':
459 - if (*buf == 0 || isspace((unsigned char)*buf))
460 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
461 break;
462
463 - if (!isdigit((unsigned char)*buf))
464 + if (!isdigit_l((unsigned char)*buf, loc))
465 return 0;
466
467 +#if __DARWIN_UNIX03
468 + if (c == 'Y') {
469 + for (i = 0; *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
470 + i *= 10;
471 + i += *buf - '0';
472 + }
473 + } else {
474 + len = 2;
475 +#else /* !__DARWIN_UNIX03 */
476 len = (c == 'Y') ? 4 : 2;
477 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
478 +#endif /* __DARWIN_UNIX03 */
479 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
480 i *= 10;
481 i += *buf - '0';
482 len--;
483 }
484 +#if __DARWIN_UNIX03
485 + }
486 +#endif /* __DARWIN_UNIX03 */
487 if (c == 'Y')
488 i -= 1900;
489 if (c == 'y' && i < 69)
490 @@ -483,35 +546,58 @@ label:
491 if (i < 0)
492 return 0;
493
494 - tm->tm_year = i;
495 + tm->tm_year = year = i;
496
497 - if (*buf != 0 && isspace((unsigned char)*buf))
498 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
499 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
500 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
501 ptr++;
502 break;
503
504 case 'Z':
505 {
506 const char *cp;
507 - char *zonestr;
508 + size_t tzlen, len;
509
510 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
511 - if (cp - buf) {
512 - zonestr = alloca(cp - buf + 1);
513 - strncpy(zonestr, buf, cp - buf);
514 - zonestr[cp - buf] = '\0';
515 - tzset();
516 - if (0 == strcmp(zonestr, "GMT")) {
517 - *GMTp = 1;
518 - } else if (0 == strcmp(zonestr, tzname[0])) {
519 - tm->tm_isdst = 0;
520 - } else if (0 == strcmp(zonestr, tzname[1])) {
521 - tm->tm_isdst = 1;
522 - } else {
523 - return 0;
524 - }
525 - buf += cp - buf;
526 + len = cp - buf;
527 + if (len == 3 && strncmp(buf, "GMT", 3) == 0) {
528 + *convp = CONVERT_GMT;
529 + buf += len;
530 + break;
531 }
532 + tzset();
533 + tzlen = strlen(tzname[0]);
534 + if (len == tzlen && strncmp(buf, tzname[0], tzlen) == 0) {
535 + tm->tm_isdst = 0;
536 + buf += len;
537 + break;
538 + }
539 + tzlen = strlen(tzname[1]);
540 + if (len == tzlen && strncmp(buf, tzname[1], tzlen) == 0) {
541 + tm->tm_isdst = 1;
542 + buf += len;
543 + break;
544 + }
545 + return 0;
546 + }
547 +
548 + case 'z':
549 + {
550 + char sign;
551 + int hr, min;
552 +
553 + if ((buf[0] != '+' && buf[0] != '-')
554 + || !isdigit_l((unsigned char)buf[1], loc)
555 + || !isdigit_l((unsigned char)buf[2], loc)
556 + || !isdigit_l((unsigned char)buf[3], loc)
557 + || !isdigit_l((unsigned char)buf[4], loc))
558 + return 0;
559 + sscanf(buf, "%c%2d%2d", &sign, &hr, &min);
560 + *convp = CONVERT_ZONE;
561 + tm->tm_gmtoff = 60 * (60 * hr + min);
562 + if (sign == '-')
563 + tm->tm_gmtoff = -tm->tm_gmtoff;
564 + buf += 5;
565 }
566 break;
567 }
568 @@ -524,14 +610,39 @@ char *
569 strptime(const char * __restrict buf, const char * __restrict fmt,
570 struct tm * __restrict tm)
571 {
572 + return strptime_l(buf, fmt, tm, __current_locale());
573 +}
574 +
575 +extern time_t timeoff(struct tm *, long);
576 +
577 +char *
578 +strptime_l(const char * __restrict buf, const char * __restrict fmt,
579 + struct tm * __restrict tm, locale_t loc)
580 +{
581 char *ret;
582 - int gmt;
583 + int conv;
584
585 - gmt = 0;
586 - ret = _strptime(buf, fmt, tm, &gmt);
587 - if (ret && gmt) {
588 - time_t t = timegm(tm);
589 - localtime_r(&t, tm);
590 + NORMALIZE_LOCALE(loc);
591 + conv = CONVERT_NONE;
592 + tm->tm_zone = NULL;
593 + ret = _strptime(buf, fmt, tm, &conv, loc);
594 + if (ret) {
595 + time_t t;
596 +
597 + switch(conv) {
598 + case CONVERT_GMT:
599 + t = timegm(tm);
600 + localtime_r(&t, tm);
601 + break;
602 + case CONVERT_ZONE:
603 + {
604 + long offset = tm->tm_gmtoff;
605 + tm->tm_gmtoff = 0;
606 + t = timeoff(tm, offset);
607 + localtime_r(&t, tm);
608 + break;
609 + }
610 + }
611 }
612
613 return (ret);