| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: strptime.c,v 1.45 2015/07/15 13:54:38 ginsbach Exp $ */ | | 1 | /* $NetBSD: strptime.c,v 1.46 2015/07/20 14:37:11 ginsbach Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code was contributed to The NetBSD Foundation by Klaus Klein. | | 7 | * This code was contributed to The NetBSD Foundation by Klaus Klein. |
8 | * Heavily optimised by David Laight | | 8 | * Heavily optimised by David Laight |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -21,45 +21,49 @@ | | | @@ -21,45 +21,49 @@ |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #if defined(LIBC_SCCS) && !defined(lint) | | 33 | #if defined(LIBC_SCCS) && !defined(lint) |
34 | __RCSID("$NetBSD: strptime.c,v 1.45 2015/07/15 13:54:38 ginsbach Exp $"); | | 34 | __RCSID("$NetBSD: strptime.c,v 1.46 2015/07/20 14:37:11 ginsbach Exp $"); |
35 | #endif | | 35 | #endif |
36 | | | 36 | |
37 | #include "namespace.h" | | 37 | #include "namespace.h" |
38 | #include <sys/localedef.h> | | 38 | #include <sys/localedef.h> |
39 | #include <sys/types.h> | | 39 | #include <sys/types.h> |
40 | #include <ctype.h> | | 40 | #include <ctype.h> |
41 | #include <locale.h> | | 41 | #include <locale.h> |
42 | #include <string.h> | | 42 | #include <string.h> |
43 | #include <time.h> | | 43 | #include <time.h> |
44 | #include <tzfile.h> | | 44 | #include <tzfile.h> |
45 | #include "private.h" | | 45 | #include "private.h" |
46 | #include "setlocale_local.h" | | 46 | #include "setlocale_local.h" |
47 | | | 47 | |
48 | #ifdef __weak_alias | | 48 | #ifdef __weak_alias |
49 | __weak_alias(strptime,_strptime) | | 49 | __weak_alias(strptime,_strptime) |
50 | __weak_alias(strptime_l, _strptime_l) | | 50 | __weak_alias(strptime_l, _strptime_l) |
51 | #endif | | 51 | #endif |
52 | | | 52 | |
| | | 53 | static const u_char *conv_num(const unsigned char *, int *, uint, uint); |
| | | 54 | static const u_char *find_string(const u_char *, int *, const char * const *, |
| | | 55 | const char * const *, int); |
| | | 56 | |
53 | #define _TIME_LOCALE(loc) \ | | 57 | #define _TIME_LOCALE(loc) \ |
54 | ((_TimeLocale *)((loc)->part_impl[(size_t)LC_TIME])) | | 58 | ((_TimeLocale *)((loc)->part_impl[(size_t)LC_TIME])) |
55 | | | 59 | |
56 | /* | | 60 | /* |
57 | * We do not implement alternate representations. However, we always | | 61 | * We do not implement alternate representations. However, we always |
58 | * check whether a given modifier is allowed for a certain conversion. | | 62 | * check whether a given modifier is allowed for a certain conversion. |
59 | */ | | 63 | */ |
60 | #define ALT_E 0x01 | | 64 | #define ALT_E 0x01 |
61 | #define ALT_O 0x02 | | 65 | #define ALT_O 0x02 |
62 | #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } | | 66 | #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } |
63 | | | 67 | |
64 | #define S_YEAR (1 << 0) | | 68 | #define S_YEAR (1 << 0) |
65 | #define S_MON (1 << 1) | | 69 | #define S_MON (1 << 1) |
| @@ -73,32 +77,34 @@ __weak_alias(strptime_l, _strptime_l) | | | @@ -73,32 +77,34 @@ __weak_alias(strptime_l, _strptime_l) |
73 | #define HAVE_YDAY(s) (s & S_YDAY) | | 77 | #define HAVE_YDAY(s) (s & S_YDAY) |
74 | #define HAVE_YEAR(s) (s & S_YEAR) | | 78 | #define HAVE_YEAR(s) (s & S_YEAR) |
75 | | | 79 | |
76 | static char gmt[] = { "GMT" }; | | 80 | static char gmt[] = { "GMT" }; |
77 | static char utc[] = { "UTC" }; | | 81 | static char utc[] = { "UTC" }; |
78 | /* RFC-822/RFC-2822 */ | | 82 | /* RFC-822/RFC-2822 */ |
79 | static const char * const nast[5] = { | | 83 | static const char * const nast[5] = { |
80 | "EST", "CST", "MST", "PST", "\0\0\0" | | 84 | "EST", "CST", "MST", "PST", "\0\0\0" |
81 | }; | | 85 | }; |
82 | static const char * const nadt[5] = { | | 86 | static const char * const nadt[5] = { |
83 | "EDT", "CDT", "MDT", "PDT", "\0\0\0" | | 87 | "EDT", "CDT", "MDT", "PDT", "\0\0\0" |
84 | }; | | 88 | }; |
85 | | | 89 | |
86 | static const u_char *conv_num(const unsigned char *, int *, uint, uint); | | 90 | /* |
87 | static const u_char *find_string(const u_char *, int *, const char * const *, | | 91 | * Table to determine the ordinal date for the start of a month. |
88 | const char * const *, int); | | 92 | * Ref: http://en.wikipedia.org/wiki/ISO_week_date |
89 | | | 93 | */ |
90 | static const int start_of_month[2][13] = { | | 94 | static const int start_of_month[2][13] = { |
| | | 95 | /* non-leap year */ |
91 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | | 96 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, |
| | | 97 | /* leap year */ |
92 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | | 98 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } |
93 | }; | | 99 | }; |
94 | | | 100 | |
95 | /* | | 101 | /* |
96 | * Calculate the week day of the first day of a year. Valid for | | 102 | * Calculate the week day of the first day of a year. Valid for |
97 | * the Gregorian calendar, which began Sept 14, 1752 in the UK | | 103 | * the Gregorian calendar, which began Sept 14, 1752 in the UK |
98 | * and its colonies. Ref: | | 104 | * and its colonies. Ref: |
99 | * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week | | 105 | * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week |
100 | */ | | 106 | */ |
101 | | | 107 | |
102 | static int | | 108 | static int |
103 | first_wday_of(int yr) | | 109 | first_wday_of(int yr) |
104 | { | | 110 | { |
| @@ -576,67 +582,75 @@ literal: | | | @@ -576,67 +582,75 @@ literal: |
576 | while (isspace(*bp)) | | 582 | while (isspace(*bp)) |
577 | bp++; | | 583 | bp++; |
578 | LEGAL_ALT(0); | | 584 | LEGAL_ALT(0); |
579 | continue; | | 585 | continue; |
580 | | | 586 | |
581 | | | 587 | |
582 | default: /* Unknown/unsupported conversion. */ | | 588 | default: /* Unknown/unsupported conversion. */ |
583 | return NULL; | | 589 | return NULL; |
584 | } | | 590 | } |
585 | } | | 591 | } |
586 | | | 592 | |
587 | if (!HAVE_YDAY(state) && HAVE_YEAR(state)) { | | 593 | if (!HAVE_YDAY(state) && HAVE_YEAR(state)) { |
588 | if (HAVE_MON(state) && HAVE_MDAY(state)) { | | 594 | if (HAVE_MON(state) && HAVE_MDAY(state)) { |
| | | 595 | /* calculate day of year (ordinal date) */ |
589 | tm->tm_yday = start_of_month[isleap_sum(tm->tm_year, | | 596 | tm->tm_yday = start_of_month[isleap_sum(tm->tm_year, |
590 | TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1); | | 597 | TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1); |
591 | state |= S_YDAY; | | 598 | state |= S_YDAY; |
592 | } else if (day_offset != -1) { | | 599 | } else if (day_offset != -1) { |
593 | /* Set the date to the first Sunday (or Monday) | | 600 | /* |
| | | 601 | * Set the date to the first Sunday (or Monday) |
594 | * of the specified week of the year. | | 602 | * of the specified week of the year. |
595 | */ | | 603 | */ |
596 | if (!HAVE_WDAY(state)) { | | 604 | if (!HAVE_WDAY(state)) { |
597 | tm->tm_wday = day_offset; | | 605 | tm->tm_wday = day_offset; |
598 | state |= S_WDAY; | | 606 | state |= S_WDAY; |
599 | } | | 607 | } |
600 | tm->tm_yday = (7 - | | 608 | tm->tm_yday = (7 - |
601 | first_wday_of(tm->tm_year + TM_YEAR_BASE) + | | 609 | first_wday_of(tm->tm_year + TM_YEAR_BASE) + |
602 | day_offset) % 7 + (week_offset - 1) * 7 + | | 610 | day_offset) % 7 + (week_offset - 1) * 7 + |
603 | tm->tm_wday - day_offset; | | 611 | tm->tm_wday - day_offset; |
604 | state |= S_YDAY; | | 612 | state |= S_YDAY; |
605 | } | | 613 | } |
606 | } | | 614 | } |
607 | | | 615 | |
608 | if (HAVE_YDAY(state) && HAVE_YEAR(state)) { | | 616 | if (HAVE_YDAY(state) && HAVE_YEAR(state)) { |
609 | int isleap; | | 617 | int isleap; |
| | | 618 | |
610 | if (!HAVE_MON(state)) { | | 619 | if (!HAVE_MON(state)) { |
| | | 620 | /* calculate month of day of year */ |
611 | i = 0; | | 621 | i = 0; |
612 | isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE); | | 622 | isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE); |
613 | while (tm->tm_yday >= start_of_month[isleap][i]) | | 623 | while (tm->tm_yday >= start_of_month[isleap][i]) |
614 | i++; | | 624 | i++; |
615 | if (i > 12) { | | 625 | if (i > 12) { |
616 | i = 1; | | 626 | i = 1; |
617 | tm->tm_yday -= start_of_month[isleap][12]; | | 627 | tm->tm_yday -= start_of_month[isleap][12]; |
618 | tm->tm_year++; | | 628 | tm->tm_year++; |
619 | } | | 629 | } |
620 | tm->tm_mon = i - 1; | | 630 | tm->tm_mon = i - 1; |
621 | state |= S_MON; | | 631 | state |= S_MON; |
622 | } | | 632 | } |
| | | 633 | |
623 | if (!HAVE_MDAY(state)) { | | 634 | if (!HAVE_MDAY(state)) { |
| | | 635 | /* calculate day of month */ |
624 | isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE); | | 636 | isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE); |
625 | tm->tm_mday = tm->tm_yday - | | 637 | tm->tm_mday = tm->tm_yday - |
626 | start_of_month[isleap][tm->tm_mon] + 1; | | 638 | start_of_month[isleap][tm->tm_mon] + 1; |
627 | state |= S_MDAY; | | 639 | state |= S_MDAY; |
628 | } | | 640 | } |
| | | 641 | |
629 | if (!HAVE_WDAY(state)) { | | 642 | if (!HAVE_WDAY(state)) { |
| | | 643 | /* calculate day of week */ |
630 | i = 0; | | 644 | i = 0; |
631 | week_offset = first_wday_of(tm->tm_year); | | 645 | week_offset = first_wday_of(tm->tm_year); |
632 | while (i++ <= tm->tm_yday) { | | 646 | while (i++ <= tm->tm_yday) { |
633 | if (week_offset++ >= 6) | | 647 | if (week_offset++ >= 6) |
634 | week_offset = 0; | | 648 | week_offset = 0; |
635 | } | | 649 | } |
636 | tm->tm_wday = week_offset; | | 650 | tm->tm_wday = week_offset; |
637 | state |= S_WDAY; | | 651 | state |= S_WDAY; |
638 | } | | 652 | } |
639 | } | | 653 | } |
640 | | | 654 | |
641 | return __UNCONST(bp); | | 655 | return __UNCONST(bp); |
642 | } | | 656 | } |