| @@ -1,1355 +1,1355 @@ | | | @@ -1,1355 +1,1355 @@ |
1 | %{ | | 1 | %{ |
2 | /* | | 2 | /* |
3 | ** Originally written by Steven M. Bellovin <smb@research.att.com> while | | 3 | ** Originally written by Steven M. Bellovin <smb@research.att.com> while |
4 | ** at the University of North Carolina at Chapel Hill. Later tweaked by | | 4 | ** at the University of North Carolina at Chapel Hill. Later tweaked by |
5 | ** a couple of people on Usenet. Completely overhauled by Rich $alz | | 5 | ** a couple of people on Usenet. Completely overhauled by Rich $alz |
6 | ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; | | 6 | ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; |
7 | ** | | 7 | ** |
8 | ** This grammar has 10 shift/reduce conflicts. | | 8 | ** This grammar has 10 shift/reduce conflicts. |
9 | ** | | 9 | ** |
10 | ** This code is in the public domain and has no copyright. | | 10 | ** This code is in the public domain and has no copyright. |
11 | */ | | 11 | */ |
12 | /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ | | 12 | /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ |
13 | /* SUPPRESS 288 on yyerrlab *//* Label unused */ | | 13 | /* SUPPRESS 288 on yyerrlab *//* Label unused */ |
14 | | | 14 | |
15 | #include <sys/cdefs.h> | | 15 | #include <sys/cdefs.h> |
16 | #ifdef __RCSID | | 16 | #ifdef __RCSID |
17 | __RCSID("$NetBSD: parsedate.y,v 1.36 2020/10/30 22:03:11 kre Exp $"); | | 17 | __RCSID("$NetBSD: parsedate.y,v 1.37 2022/04/23 13:02:04 christos Exp $"); |
18 | #endif | | 18 | #endif |
19 | | | 19 | |
20 | #include <stdio.h> | | 20 | #include <stdio.h> |
21 | #include <ctype.h> | | 21 | #include <ctype.h> |
22 | #include <errno.h> | | 22 | #include <errno.h> |
23 | #include <limits.h> | | 23 | #include <limits.h> |
24 | #include <string.h> | | 24 | #include <string.h> |
25 | #include <time.h> | | 25 | #include <time.h> |
26 | #include <util.h> | | 26 | #include <util.h> |
27 | #include <stdlib.h> | | 27 | #include <stdlib.h> |
28 | | | 28 | |
29 | /* NOTES on rebuilding parsedate.c (particularly for inclusion in CVS | | 29 | /* NOTES on rebuilding parsedate.c (particularly for inclusion in CVS |
30 | releases): | | 30 | releases): |
31 | | | 31 | |
32 | We don't want to mess with all the portability hassles of alloca. | | 32 | We don't want to mess with all the portability hassles of alloca. |
33 | In particular, most (all?) versions of bison will use alloca in | | 33 | In particular, most (all?) versions of bison will use alloca in |
34 | their parser. If bison works on your system (e.g. it should work | | 34 | their parser. If bison works on your system (e.g. it should work |
35 | with gcc), then go ahead and use it, but the more general solution | | 35 | with gcc), then go ahead and use it, but the more general solution |
36 | is to use byacc instead of bison, which should generate a portable | | 36 | is to use byacc instead of bison, which should generate a portable |
37 | parser. I played with adding "#define alloca dont_use_alloca", to | | 37 | parser. I played with adding "#define alloca dont_use_alloca", to |
38 | give an error if the parser generator uses alloca (and thus detect | | 38 | give an error if the parser generator uses alloca (and thus detect |
39 | unportable parsedate.c's), but that seems to cause as many problems | | 39 | unportable parsedate.c's), but that seems to cause as many problems |
40 | as it solves. */ | | 40 | as it solves. */ |
41 | | | 41 | |
42 | #define EPOCH 1970 | | 42 | #define EPOCH 1970 |
43 | #define HOUR(x) ((time_t)((x) * 60)) | | 43 | #define HOUR(x) ((time_t)((x) * 60)) |
44 | #define SECSPERDAY (24L * 60L * 60L) | | 44 | #define SECSPERDAY (24L * 60L * 60L) |
45 | | | 45 | |
46 | #define MAXREL 16 /* hours mins secs days weeks months years - maybe twice each ...*/ | | 46 | #define MAXREL 16 /* hours mins secs days weeks months years - maybe twice each ...*/ |
47 | | | 47 | |
48 | #define USE_LOCAL_TIME 99999 /* special case for Convert() and yyTimezone */ | | 48 | #define USE_LOCAL_TIME 99999 /* special case for Convert() and yyTimezone */ |
49 | | | 49 | |
50 | /* | | 50 | /* |
51 | ** An entry in the lexical lookup table. | | 51 | ** An entry in the lexical lookup table. |
52 | */ | | 52 | */ |
53 | typedef struct _TABLE { | | 53 | typedef struct _TABLE { |
54 | const char *name; | | 54 | const char *name; |
55 | int type; | | 55 | int type; |
56 | time_t value; | | 56 | time_t value; |
57 | } TABLE; | | 57 | } TABLE; |
58 | | | 58 | |
59 | | | 59 | |
60 | /* | | 60 | /* |
61 | ** Daylight-savings mode: on, off, or not yet known. | | 61 | ** Daylight-savings mode: on, off, or not yet known. |
62 | */ | | 62 | */ |
63 | typedef enum _DSTMODE { | | 63 | typedef enum _DSTMODE { |
64 | DSTon, DSToff, DSTmaybe | | 64 | DSTon, DSToff, DSTmaybe |
65 | } DSTMODE; | | 65 | } DSTMODE; |
66 | | | 66 | |
67 | /* | | 67 | /* |
68 | ** Meridian: am, pm, or 24-hour style (plus "noon" and "midnight"). | | 68 | ** Meridian: am, pm, or 24-hour style (plus "noon" and "midnight"). |
69 | */ | | 69 | */ |
70 | typedef enum _MERIDIAN { | | 70 | typedef enum _MERIDIAN { |
71 | MERam, MERpm, MER24, MER_NOON, MER_MN | | 71 | MERam, MERpm, MER24, MER_NOON, MER_MN |
72 | } MERIDIAN; | | 72 | } MERIDIAN; |
73 | | | 73 | |
74 | | | 74 | |
75 | struct dateinfo { | | 75 | struct dateinfo { |
76 | DSTMODE yyDSTmode; /* DST on/off/maybe */ | | 76 | DSTMODE yyDSTmode; /* DST on/off/maybe */ |
77 | time_t yyDayOrdinal; | | 77 | time_t yyDayOrdinal; |
78 | time_t yyDayNumber; | | 78 | time_t yyDayNumber; |
79 | int yyHaveDate; | | 79 | int yyHaveDate; |
80 | int yyHaveFullYear; /* if true, year is not abbreviated. */ | | 80 | int yyHaveFullYear; /* if true, year is not abbreviated. */ |
81 | /* if false, need to call AdjustYear(). */ | | 81 | /* if false, need to call AdjustYear(). */ |
82 | int yyHaveDay; | | 82 | int yyHaveDay; |
83 | int yyHaveRel; | | 83 | int yyHaveRel; |
84 | int yyHaveTime; | | 84 | int yyHaveTime; |
85 | int yyHaveZone; | | 85 | int yyHaveZone; |
86 | time_t yyTimezone; /* Timezone as minutes ahead/east of UTC */ | | 86 | time_t yyTimezone; /* Timezone as minutes ahead/east of UTC */ |
87 | time_t yyDay; /* Day of month [1-31] */ | | 87 | time_t yyDay; /* Day of month [1-31] */ |
88 | time_t yyHour; /* Hour of day [0-24] or [1-12] */ | | 88 | time_t yyHour; /* Hour of day [0-24] or [1-12] */ |
89 | time_t yyMinutes; /* Minute of hour [0-59] */ | | 89 | time_t yyMinutes; /* Minute of hour [0-59] */ |
90 | time_t yyMonth; /* Month of year [1-12] */ | | 90 | time_t yyMonth; /* Month of year [1-12] */ |
91 | time_t yySeconds; /* Second of minute [0-60] */ | | 91 | time_t yySeconds; /* Second of minute [0-60] */ |
92 | time_t yyYear; /* Year, see also yyHaveFullYear */ | | 92 | time_t yyYear; /* Year, see also yyHaveFullYear */ |
93 | MERIDIAN yyMeridian; /* Interpret yyHour as AM/PM/24 hour clock */ | | 93 | MERIDIAN yyMeridian; /* Interpret yyHour as AM/PM/24 hour clock */ |
94 | struct { | | 94 | struct { |
95 | time_t yyRelVal; | | 95 | time_t yyRelVal; |
96 | int yyRelMonth; | | 96 | int yyRelMonth; |
97 | } yyRel[MAXREL]; | | 97 | } yyRel[MAXREL]; |
98 | }; | | 98 | }; |
99 | | | 99 | |
100 | static int RelVal(struct dateinfo *, time_t, time_t, int, int); | | 100 | static int RelVal(struct dateinfo *, time_t, time_t, int, int); |
101 | | | 101 | |
102 | #define CheckRelVal(a, b, c, d, e) do { \ | | 102 | #define CheckRelVal(a, b, c, d, e) do { \ |
103 | if (!RelVal((a), (b), (c), (d), (e))) { \ | | 103 | if (!RelVal((a), (b), (c), (d), (e))) { \ |
104 | YYREJECT; \ | | 104 | YYREJECT; \ |
105 | } \ | | 105 | } \ |
106 | } while (0) | | 106 | } while (0) |
107 | | | 107 | |
108 | %} | | 108 | %} |
109 | | | 109 | |
110 | %union { | | 110 | %union { |
111 | time_t Number; | | 111 | time_t Number; |
112 | enum _MERIDIAN Meridian; | | 112 | enum _MERIDIAN Meridian; |
113 | } | | 113 | } |
114 | | | 114 | |
115 | %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT | | 115 | %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT |
116 | %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN tTIME | | 116 | %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN tTIME |
117 | | | 117 | |
118 | %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT | | 118 | %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT |
119 | %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE tTIME | | 119 | %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE tTIME |
120 | %type <Meridian> tMERIDIAN | | 120 | %type <Meridian> tMERIDIAN |
121 | | | 121 | |
122 | %type <Number> at_number | | 122 | %type <Number> at_number |
123 | %type <Meridian> o_merid | | 123 | %type <Meridian> o_merid |
124 | | | 124 | |
125 | %parse-param { struct dateinfo *param } | | 125 | %parse-param { struct dateinfo *param } |
126 | %parse-param { const char **yyInput } | | 126 | %parse-param { const char **yyInput } |
127 | %lex-param { const char **yyInput } | | 127 | %lex-param { const char **yyInput } |
128 | %pure-parser | | 128 | %pure-parser |
129 | | | 129 | |
130 | %% | | 130 | %% |
131 | | | 131 | |
132 | spec: | | 132 | spec: |
133 | /* empty */ | | 133 | /* empty */ |
134 | | spec item | | 134 | | spec item |
135 | ; | | 135 | ; |
136 | | | 136 | |
137 | item: | | 137 | item: |
138 | time { param->yyHaveTime++; } | | 138 | time { param->yyHaveTime++; } |
139 | | time_numericzone { param->yyHaveTime++; param->yyHaveZone++; } | | 139 | | time_numericzone { param->yyHaveTime++; param->yyHaveZone++; } |
140 | | zone { param->yyHaveZone++; } | | 140 | | zone { param->yyHaveZone++; } |
141 | | date { param->yyHaveDate++; } | | 141 | | date { param->yyHaveDate++; } |
142 | | day { param->yyHaveDay++; } | | 142 | | day { param->yyHaveDay++; } |
143 | | rel { param->yyHaveRel++; } | | 143 | | rel { param->yyHaveRel++; } |
144 | | cvsstamp { param->yyHaveTime++; param->yyHaveDate++; | | 144 | | cvsstamp { param->yyHaveTime++; param->yyHaveDate++; |
145 | param->yyHaveZone++; } | | 145 | param->yyHaveZone++; } |
146 | | epochdate { param->yyHaveTime++; param->yyHaveDate++; | | 146 | | epochdate { param->yyHaveTime++; param->yyHaveDate++; |
147 | param->yyHaveZone++; } | | 147 | param->yyHaveZone++; } |
148 | | number | | 148 | | number |
149 | ; | | 149 | ; |
150 | | | 150 | |
151 | cvsstamp: | | 151 | cvsstamp: |
152 | tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' | | 152 | tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' |
153 | tUNUMBER '.' tUNUMBER '.' tUNUMBER { | | 153 | tUNUMBER '.' tUNUMBER '.' tUNUMBER { |
154 | param->yyYear = $1; | | 154 | param->yyYear = $1; |
155 | if (param->yyYear < 100) { | | 155 | if (param->yyYear < 100) { |
156 | param->yyYear += 1900; | | 156 | param->yyYear += 1900; |
157 | } | | 157 | } |
158 | param->yyHaveFullYear = 1; | | 158 | param->yyHaveFullYear = 1; |
159 | param->yyMonth = $3; | | 159 | param->yyMonth = $3; |
160 | param->yyDay = $5; | | 160 | param->yyDay = $5; |
161 | param->yyHour = $7; | | 161 | param->yyHour = $7; |
162 | param->yyMinutes = $9; | | 162 | param->yyMinutes = $9; |
163 | param->yySeconds = $11; | | 163 | param->yySeconds = $11; |
164 | param->yyDSTmode = DSToff; | | 164 | param->yyDSTmode = DSToff; |
165 | param->yyTimezone = 0; | | 165 | param->yyTimezone = 0; |
166 | } | | 166 | } |
167 | ; | | 167 | ; |
168 | | | 168 | |
169 | epochdate: | | 169 | epochdate: |
170 | AT_SIGN at_number { | | 170 | AT_SIGN at_number { |
171 | time_t when = $2; | | 171 | time_t when = $2; |
172 | struct tm tmbuf; | | 172 | struct tm tmbuf; |
173 | | | 173 | |
174 | if (gmtime_r(&when, &tmbuf) != NULL) { | | 174 | if (gmtime_r(&when, &tmbuf) != NULL) { |
175 | param->yyYear = tmbuf.tm_year + 1900; | | 175 | param->yyYear = tmbuf.tm_year + 1900; |
176 | param->yyMonth = tmbuf.tm_mon + 1; | | 176 | param->yyMonth = tmbuf.tm_mon + 1; |
177 | param->yyDay = tmbuf.tm_mday; | | 177 | param->yyDay = tmbuf.tm_mday; |
178 | | | 178 | |
179 | param->yyHour = tmbuf.tm_hour; | | 179 | param->yyHour = tmbuf.tm_hour; |
180 | param->yyMinutes = tmbuf.tm_min; | | 180 | param->yyMinutes = tmbuf.tm_min; |
181 | param->yySeconds = tmbuf.tm_sec; | | 181 | param->yySeconds = tmbuf.tm_sec; |
182 | } else { | | 182 | } else { |
183 | param->yyYear = EPOCH; | | 183 | param->yyYear = EPOCH; |
184 | param->yyMonth = 1; | | 184 | param->yyMonth = 1; |
185 | param->yyDay = 1; | | 185 | param->yyDay = 1; |
186 | | | 186 | |
187 | param->yyHour = 0; | | 187 | param->yyHour = 0; |
188 | param->yyMinutes = 0; | | 188 | param->yyMinutes = 0; |
189 | param->yySeconds = 0; | | 189 | param->yySeconds = 0; |
190 | } | | 190 | } |
191 | param->yyHaveFullYear = 1; | | 191 | param->yyHaveFullYear = 1; |
192 | param->yyDSTmode = DSToff; | | 192 | param->yyDSTmode = DSToff; |
193 | param->yyTimezone = 0; | | 193 | param->yyTimezone = 0; |
194 | } | | 194 | } |
195 | ; | | 195 | ; |
196 | | | 196 | |
197 | at_number: | | 197 | at_number: |
198 | tUNUMBER | | 198 | tUNUMBER |
199 | | tSNUMBER | | 199 | | tSNUMBER |
200 | ; | | 200 | ; |
201 | | | 201 | |
202 | time: | | 202 | time: |
203 | tUNUMBER tMERIDIAN { | | 203 | tUNUMBER tMERIDIAN { |
204 | if ($1 > 24) | | 204 | if ($1 > 24) |
205 | YYREJECT; | | 205 | YYREJECT; |
206 | param->yyMinutes = 0; | | 206 | param->yyMinutes = 0; |
207 | param->yySeconds = 0; | | 207 | param->yySeconds = 0; |
208 | if ($2 == MER_NOON || $2 == MER_MN) { | | 208 | if ($2 == MER_NOON || $2 == MER_MN) { |
209 | if ($1 == 12) { | | 209 | if ($1 == 12) { |
210 | switch ($2) { | | 210 | switch ($2) { |
211 | case MER_NOON: param->yyHour = 12; break; | | 211 | case MER_NOON: param->yyHour = 12; break; |
212 | case MER_MN : param->yyHour = 0; break; | | 212 | case MER_MN : param->yyHour = 0; break; |
213 | default: /* impossible */; break; | | 213 | default: /* impossible */; break; |
214 | } | | 214 | } |
215 | param->yyMeridian = MER24; | | 215 | param->yyMeridian = MER24; |
216 | } else | | 216 | } else |
217 | YYREJECT; | | 217 | YYREJECT; |
218 | } else { | | 218 | } else { |
219 | param->yyHour = $1; | | 219 | param->yyHour = $1; |
220 | param->yyMeridian = $2; | | 220 | param->yyMeridian = $2; |
221 | } | | 221 | } |
222 | } | | 222 | } |
223 | | tUNUMBER ':' tUNUMBER o_merid { | | 223 | | tUNUMBER ':' tUNUMBER o_merid { |
224 | if ($1 > 24 || $3 >= 60) | | 224 | if ($1 > 24 || $3 >= 60) |
225 | YYREJECT; | | 225 | YYREJECT; |
226 | param->yyMinutes = $3; | | 226 | param->yyMinutes = $3; |
227 | param->yySeconds = 0; | | 227 | param->yySeconds = 0; |
228 | if ($4 == MER_NOON || $4 == MER_MN) { | | 228 | if ($4 == MER_NOON || $4 == MER_MN) { |
229 | if ($1 == 12 && $3 == 0) { | | 229 | if ($1 == 12 && $3 == 0) { |
230 | switch ($4) { | | 230 | switch ($4) { |
231 | case MER_NOON: param->yyHour = 12; break; | | 231 | case MER_NOON: param->yyHour = 12; break; |
232 | case MER_MN : param->yyHour = 0; break; | | 232 | case MER_MN : param->yyHour = 0; break; |
233 | default: /* impossible */; break; | | 233 | default: /* impossible */; break; |
234 | } | | 234 | } |
235 | param->yyMeridian = MER24; | | 235 | param->yyMeridian = MER24; |
236 | } else | | 236 | } else |
237 | YYREJECT; | | 237 | YYREJECT; |
238 | } else { | | 238 | } else { |
239 | param->yyHour = $1; | | 239 | param->yyHour = $1; |
240 | param->yyMeridian = $4; | | 240 | param->yyMeridian = $4; |
241 | } | | 241 | } |
242 | } | | 242 | } |
243 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { | | 243 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { |
244 | if ($1 > 24 || $3 >= 60 || $5 > 60) | | 244 | if ($1 > 24 || $3 >= 60 || $5 > 60) |
245 | YYREJECT; | | 245 | YYREJECT; |
246 | param->yyMinutes = $3; | | 246 | param->yyMinutes = $3; |
247 | param->yySeconds = $5; | | 247 | param->yySeconds = $5; |
248 | if ($6 == MER_NOON || $6 == MER_MN) { | | 248 | if ($6 == MER_NOON || $6 == MER_MN) { |
249 | if ($1 == 12 && $3 == 0 && $5 == 0) { | | 249 | if ($1 == 12 && $3 == 0 && $5 == 0) { |
250 | switch ($6) { | | 250 | switch ($6) { |
251 | case MER_NOON: param->yyHour = 12; break; | | 251 | case MER_NOON: param->yyHour = 12; break; |
252 | case MER_MN : param->yyHour = 0; break; | | 252 | case MER_MN : param->yyHour = 0; break; |
253 | default: /* impossible */; break; | | 253 | default: /* impossible */; break; |
254 | } | | 254 | } |
255 | param->yyMeridian = MER24; | | 255 | param->yyMeridian = MER24; |
256 | } else | | 256 | } else |
257 | YYREJECT; | | 257 | YYREJECT; |
258 | } else { | | 258 | } else { |
259 | param->yyHour = $1; | | 259 | param->yyHour = $1; |
260 | param->yyMeridian = $6; | | 260 | param->yyMeridian = $6; |
261 | } | | 261 | } |
262 | } | | 262 | } |
263 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER '.' tUNUMBER { | | 263 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER '.' tUNUMBER { |
264 | if ($1 > 24 || $3 >= 60 || $5 > 60) | | 264 | if ($1 > 24 || $3 >= 60 || $5 > 60) |
265 | YYREJECT; | | 265 | YYREJECT; |
266 | param->yyHour = $1; | | 266 | param->yyHour = $1; |
267 | param->yyMinutes = $3; | | 267 | param->yyMinutes = $3; |
268 | param->yySeconds = $5; | | 268 | param->yySeconds = $5; |
269 | param->yyMeridian = MER24; | | 269 | param->yyMeridian = MER24; |
270 | /* XXX: Do nothing with fractional secs ($7) */ | | 270 | /* XXX: Do nothing with fractional secs ($7) */ |
271 | } | | 271 | } |
272 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER ',' tUNUMBER { | | 272 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER ',' tUNUMBER { |
273 | if ($1 > 24 || $3 >= 60 || $5 > 60) | | 273 | if ($1 > 24 || $3 >= 60 || $5 > 60) |
274 | YYREJECT; | | 274 | YYREJECT; |
275 | param->yyHour = $1; | | 275 | param->yyHour = $1; |
276 | param->yyMinutes = $3; | | 276 | param->yyMinutes = $3; |
277 | param->yySeconds = $5; | | 277 | param->yySeconds = $5; |
278 | param->yyMeridian = MER24; | | 278 | param->yyMeridian = MER24; |
279 | /* XXX: Do nothing with fractional seconds ($7) */ | | 279 | /* XXX: Do nothing with fractional seconds ($7) */ |
280 | } | | 280 | } |
281 | | tTIME { | | 281 | | tTIME { |
282 | param->yyHour = $1; | | 282 | param->yyHour = $1; |
283 | param->yyMinutes = 0; | | 283 | param->yyMinutes = 0; |
284 | param->yySeconds = 0; | | 284 | param->yySeconds = 0; |
285 | param->yyMeridian = MER24; | | 285 | param->yyMeridian = MER24; |
286 | /* Tues midnight --> Weds 00:00, midnight Tues -> Tues 00:00 */ | | 286 | /* Tues midnight --> Weds 00:00, midnight Tues -> Tues 00:00 */ |
287 | if ($1 == 0 && param->yyHaveDay) | | 287 | if ($1 == 0 && param->yyHaveDay) |
288 | param->yyDayNumber++; | | 288 | param->yyDayNumber++; |
289 | } | | 289 | } |
290 | | tUNUMBER tTIME { | | 290 | | tUNUMBER tTIME { |
291 | if ($1 == 12 && ($2 == 0 || $2 == 12)) { | | 291 | if ($1 == 12 && ($2 == 0 || $2 == 12)) { |
292 | param->yyHour = $2; | | 292 | param->yyHour = $2; |
293 | param->yyMinutes = 0; | | 293 | param->yyMinutes = 0; |
294 | param->yySeconds = 0; | | 294 | param->yySeconds = 0; |
295 | param->yyMeridian = MER24; | | 295 | param->yyMeridian = MER24; |
296 | } else | | 296 | } else |
297 | YYREJECT; | | 297 | YYREJECT; |
298 | } | | 298 | } |
299 | ; | | 299 | ; |
300 | | | 300 | |
301 | time_numericzone: | | 301 | time_numericzone: |
302 | tUNUMBER ':' tUNUMBER tSNUMBER { | | 302 | tUNUMBER ':' tUNUMBER tSNUMBER { |
303 | if ($4 < -(47 * 100 + 59) || $4 > (47 * 100 + 59)) | | 303 | if ($4 < -(47 * 100 + 59) || $4 > (47 * 100 + 59)) |
304 | YYREJECT; | | 304 | YYREJECT; |
305 | if ($1 > 24 || $3 > 59) | | 305 | if ($1 > 24 || $3 > 59) |
306 | YYREJECT; | | 306 | YYREJECT; |
307 | param->yyHour = $1; | | 307 | param->yyHour = $1; |
308 | param->yyMinutes = $3; | | 308 | param->yyMinutes = $3; |
309 | param->yyMeridian = MER24; | | 309 | param->yyMeridian = MER24; |
310 | param->yyDSTmode = DSToff; | | 310 | param->yyDSTmode = DSToff; |
311 | param->yyTimezone = - ($4 % 100 + ($4 / 100) * 60); | | 311 | param->yyTimezone = - ($4 % 100 + ($4 / 100) * 60); |
312 | } | | 312 | } |
313 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { | | 313 | | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { |
314 | if ($6 < -(47 * 100 + 59) || $6 > (47 * 100 + 59)) | | 314 | if ($6 < -(47 * 100 + 59) || $6 > (47 * 100 + 59)) |
315 | YYREJECT; | | 315 | YYREJECT; |
316 | if ($1 > 24 || $3 > 59 || $5 > 60) | | 316 | if ($1 > 24 || $3 > 59 || $5 > 60) |
317 | YYREJECT; | | 317 | YYREJECT; |
318 | param->yyHour = $1; | | 318 | param->yyHour = $1; |
319 | param->yyMinutes = $3; | | 319 | param->yyMinutes = $3; |
320 | param->yySeconds = $5; | | 320 | param->yySeconds = $5; |
321 | param->yyMeridian = MER24; | | 321 | param->yyMeridian = MER24; |
322 | param->yyDSTmode = DSToff; | | 322 | param->yyDSTmode = DSToff; |
323 | param->yyTimezone = - ($6 % 100 + ($6 / 100) * 60); | | 323 | param->yyTimezone = - ($6 % 100 + ($6 / 100) * 60); |
324 | } | | 324 | } |
325 | ; | | 325 | ; |
326 | | | 326 | |
327 | zone: | | 327 | zone: |
328 | tZONE { param->yyTimezone = $1; param->yyDSTmode = DSToff; } | | 328 | tZONE { param->yyTimezone = $1; param->yyDSTmode = DSToff; } |
329 | | tDAYZONE { param->yyTimezone = $1; param->yyDSTmode = DSTon; } | | 329 | | tDAYZONE { param->yyTimezone = $1; param->yyDSTmode = DSTon; } |
330 | | tZONE tDST { param->yyTimezone = $1; param->yyDSTmode = DSTon; } | | 330 | | tZONE tDST { param->yyTimezone = $1; param->yyDSTmode = DSTon; } |
331 | | tSNUMBER { | | 331 | | tSNUMBER { |
332 | if (param->yyHaveDate == 0 && param->yyHaveTime == 0) | | 332 | if (param->yyHaveDate == 0 && param->yyHaveTime == 0) |
333 | YYREJECT; | | 333 | YYREJECT; |
334 | if ($1 < -(47 * 100 + 59) || $1 > (47 * 100 + 59)) | | 334 | if ($1 < -(47 * 100 + 59) || $1 > (47 * 100 + 59)) |
335 | YYREJECT; | | 335 | YYREJECT; |
336 | param->yyTimezone = - ($1 % 100 + ($1 / 100) * 60); | | 336 | param->yyTimezone = - ($1 % 100 + ($1 / 100) * 60); |
337 | param->yyDSTmode = DSTmaybe; | | 337 | param->yyDSTmode = DSTmaybe; |
338 | } | | 338 | } |
339 | ; | | 339 | ; |
340 | | | 340 | |
341 | day: | | 341 | day: |
342 | tDAY { param->yyDayOrdinal = 1; param->yyDayNumber = $1; } | | 342 | tDAY { param->yyDayOrdinal = 1; param->yyDayNumber = $1; } |
343 | | tDAY ',' { param->yyDayOrdinal = 1; param->yyDayNumber = $1; } | | 343 | | tDAY ',' { param->yyDayOrdinal = 1; param->yyDayNumber = $1; } |
344 | | tUNUMBER tDAY { param->yyDayOrdinal = $1; param->yyDayNumber = $2; } | | 344 | | tUNUMBER tDAY { param->yyDayOrdinal = $1; param->yyDayNumber = $2; } |
345 | ; | | 345 | ; |
346 | | | 346 | |
347 | date: | | 347 | date: |
348 | tUNUMBER '/' tUNUMBER { | | 348 | tUNUMBER '/' tUNUMBER { |
349 | if ($1 > 12 || $3 > 31 || $1 == 0 || $3 == 0) | | 349 | if ($1 > 12 || $3 > 31 || $1 == 0 || $3 == 0) |
350 | YYREJECT; | | 350 | YYREJECT; |
351 | param->yyMonth = $1; | | 351 | param->yyMonth = $1; |
352 | param->yyDay = $3; | | 352 | param->yyDay = $3; |
353 | } | | 353 | } |
354 | | tUNUMBER '/' tUNUMBER '/' tUNUMBER { | | 354 | | tUNUMBER '/' tUNUMBER '/' tUNUMBER { |
355 | if ($1 >= 100) { | | 355 | if ($1 >= 100) { |
356 | if ($3 > 12 || $5 > 31 || $3 == 0 || $5 == 0) | | 356 | if ($3 > 12 || $5 > 31 || $3 == 0 || $5 == 0) |
357 | YYREJECT; | | 357 | YYREJECT; |
358 | param->yyYear = $1; | | 358 | param->yyYear = $1; |
359 | param->yyMonth = $3; | | 359 | param->yyMonth = $3; |
360 | param->yyDay = $5; | | 360 | param->yyDay = $5; |
361 | } else { | | 361 | } else { |
362 | if ($1 >= 12 || $3 > 31 || $1 == 0 || $3 == 0) | | 362 | if ($1 > 12 || $3 > 31 || $1 == 0 || $3 == 0) |
363 | YYREJECT; | | 363 | YYREJECT; |
364 | param->yyMonth = $1; | | 364 | param->yyMonth = $1; |
365 | param->yyDay = $3; | | 365 | param->yyDay = $3; |
366 | param->yyYear = $5; | | 366 | param->yyYear = $5; |
367 | } | | 367 | } |
368 | } | | 368 | } |
369 | | tUNUMBER tSNUMBER tSNUMBER { | | 369 | | tUNUMBER tSNUMBER tSNUMBER { |
370 | /* ISO 8601 format. yyyy-mm-dd. */ | | 370 | /* ISO 8601 format. yyyy-mm-dd. */ |
371 | if ($2 >= 0 || $2 < -12 || $3 >= 0 || $3 < -31) | | 371 | if ($2 >= 0 || $2 < -12 || $3 >= 0 || $3 < -31) |
372 | YYREJECT; | | 372 | YYREJECT; |
373 | param->yyYear = $1; | | 373 | param->yyYear = $1; |
374 | param->yyHaveFullYear = 1; | | 374 | param->yyHaveFullYear = 1; |
375 | param->yyMonth = -$2; | | 375 | param->yyMonth = -$2; |
376 | param->yyDay = -$3; | | 376 | param->yyDay = -$3; |
377 | } | | 377 | } |
378 | | tUNUMBER tMONTH tSNUMBER { | | 378 | | tUNUMBER tMONTH tSNUMBER { |
379 | if ($3 > 0 || $1 == 0 || $1 > 31) | | 379 | if ($3 > 0 || $1 == 0 || $1 > 31) |
380 | YYREJECT; | | 380 | YYREJECT; |
381 | /* e.g. 17-JUN-1992. */ | | 381 | /* e.g. 17-JUN-1992. */ |
382 | param->yyDay = $1; | | 382 | param->yyDay = $1; |
383 | param->yyMonth = $2; | | 383 | param->yyMonth = $2; |
384 | param->yyYear = -$3; | | 384 | param->yyYear = -$3; |
385 | } | | 385 | } |
386 | | tMONTH tUNUMBER { | | 386 | | tMONTH tUNUMBER { |
387 | if ($2 == 0 || $2 > 31) | | 387 | if ($2 == 0 || $2 > 31) |
388 | YYREJECT; | | 388 | YYREJECT; |
389 | param->yyMonth = $1; | | 389 | param->yyMonth = $1; |
390 | param->yyDay = $2; | | 390 | param->yyDay = $2; |
391 | } | | 391 | } |
392 | | tMONTH tUNUMBER ',' tUNUMBER { | | 392 | | tMONTH tUNUMBER ',' tUNUMBER { |
393 | if ($2 == 0 || $2 > 31) | | 393 | if ($2 == 0 || $2 > 31) |
394 | YYREJECT; | | 394 | YYREJECT; |
395 | param->yyMonth = $1; | | 395 | param->yyMonth = $1; |
396 | param->yyDay = $2; | | 396 | param->yyDay = $2; |
397 | param->yyYear = $4; | | 397 | param->yyYear = $4; |
398 | } | | 398 | } |
399 | | tUNUMBER tMONTH { | | 399 | | tUNUMBER tMONTH { |
400 | if ($1 == 0 || $1 > 31) | | 400 | if ($1 == 0 || $1 > 31) |
401 | YYREJECT; | | 401 | YYREJECT; |
402 | param->yyMonth = $2; | | 402 | param->yyMonth = $2; |
403 | param->yyDay = $1; | | 403 | param->yyDay = $1; |
404 | } | | 404 | } |
405 | | tUNUMBER tMONTH tUNUMBER { | | 405 | | tUNUMBER tMONTH tUNUMBER { |
406 | if ($1 > 31 && $3 > 31) | | 406 | if ($1 > 31 && $3 > 31) |
407 | YYREJECT; | | 407 | YYREJECT; |
408 | if ($1 < 35) { | | 408 | if ($1 < 35) { |
409 | if ($1 == 0) | | 409 | if ($1 == 0) |
410 | YYREJECT; | | 410 | YYREJECT; |
411 | param->yyDay = $1; | | 411 | param->yyDay = $1; |
412 | param->yyYear = $3; | | 412 | param->yyYear = $3; |
413 | } else { | | 413 | } else { |
414 | if ($3 == 0) | | 414 | if ($3 == 0) |
415 | YYREJECT; | | 415 | YYREJECT; |
416 | param->yyDay = $3; | | 416 | param->yyDay = $3; |
417 | param->yyYear = $1; | | 417 | param->yyYear = $1; |
418 | } | | 418 | } |
419 | param->yyMonth = $2; | | 419 | param->yyMonth = $2; |
420 | } | | 420 | } |
421 | ; | | 421 | ; |
422 | | | 422 | |
423 | rel: | | 423 | rel: |
424 | relunit | | 424 | relunit |
425 | | relunit tAGO { | | 425 | | relunit tAGO { |
426 | param->yyRel[param->yyHaveRel].yyRelVal = | | 426 | param->yyRel[param->yyHaveRel].yyRelVal = |
427 | -param->yyRel[param->yyHaveRel].yyRelVal; | | 427 | -param->yyRel[param->yyHaveRel].yyRelVal; |
428 | } | | 428 | } |
429 | ; | | 429 | ; |
430 | | | 430 | |
431 | relunit: | | 431 | relunit: |
432 | tUNUMBER tMINUTE_UNIT { CheckRelVal(param, $1, $2, 60, 0); } | | 432 | tUNUMBER tMINUTE_UNIT { CheckRelVal(param, $1, $2, 60, 0); } |
433 | | tSNUMBER tMINUTE_UNIT { CheckRelVal(param, $1, $2, 60, 0); } | | 433 | | tSNUMBER tMINUTE_UNIT { CheckRelVal(param, $1, $2, 60, 0); } |
434 | | tMINUTE_UNIT { CheckRelVal(param, 1, $1, 60, 0); } | | 434 | | tMINUTE_UNIT { CheckRelVal(param, 1, $1, 60, 0); } |
435 | | tSNUMBER tSEC_UNIT { CheckRelVal(param, $1, 1, 1, 0); } | | 435 | | tSNUMBER tSEC_UNIT { CheckRelVal(param, $1, 1, 1, 0); } |
436 | | tUNUMBER tSEC_UNIT { CheckRelVal(param, $1, 1, 1, 0); } | | 436 | | tUNUMBER tSEC_UNIT { CheckRelVal(param, $1, 1, 1, 0); } |
437 | | tSEC_UNIT { CheckRelVal(param, 1, 1, 1, 0); } | | 437 | | tSEC_UNIT { CheckRelVal(param, 1, 1, 1, 0); } |
438 | | tSNUMBER tMONTH_UNIT { CheckRelVal(param, $1, $2, 1, 1); } | | 438 | | tSNUMBER tMONTH_UNIT { CheckRelVal(param, $1, $2, 1, 1); } |
439 | | tUNUMBER tMONTH_UNIT { CheckRelVal(param, $1, $2, 1, 1); } | | 439 | | tUNUMBER tMONTH_UNIT { CheckRelVal(param, $1, $2, 1, 1); } |
440 | | tMONTH_UNIT { CheckRelVal(param, 1, $1, 1, 1); } | | 440 | | tMONTH_UNIT { CheckRelVal(param, 1, $1, 1, 1); } |
441 | ; | | 441 | ; |
442 | | | 442 | |
443 | number: | | 443 | number: |
444 | tUNUMBER { | | 444 | tUNUMBER { |
445 | if (param->yyHaveTime && param->yyHaveDate && | | 445 | if (param->yyHaveTime && param->yyHaveDate && |
446 | !param->yyHaveRel) { | | 446 | !param->yyHaveRel) { |
447 | param->yyYear = $1; | | 447 | param->yyYear = $1; |
448 | } else { | | 448 | } else { |
449 | if ($1 > 10000) { | | 449 | if ($1 > 10000) { |
450 | param->yyHaveDate++; | | 450 | param->yyHaveDate++; |
451 | param->yyDay = ($1)%100; | | 451 | param->yyDay = ($1)%100; |
452 | param->yyMonth = ($1/100)%100; | | 452 | param->yyMonth = ($1/100)%100; |
453 | param->yyYear = $1/10000; | | 453 | param->yyYear = $1/10000; |
454 | } | | 454 | } |
455 | else { | | 455 | else { |
456 | param->yyHaveTime++; | | 456 | param->yyHaveTime++; |
457 | if ($1 < 100) { | | 457 | if ($1 < 100) { |
458 | param->yyHour = $1; | | 458 | param->yyHour = $1; |
459 | param->yyMinutes = 0; | | 459 | param->yyMinutes = 0; |
460 | } | | 460 | } |
461 | else { | | 461 | else { |
462 | param->yyHour = $1 / 100; | | 462 | param->yyHour = $1 / 100; |
463 | param->yyMinutes = $1 % 100; | | 463 | param->yyMinutes = $1 % 100; |
464 | } | | 464 | } |
465 | param->yySeconds = 0; | | 465 | param->yySeconds = 0; |
466 | param->yyMeridian = MER24; | | 466 | param->yyMeridian = MER24; |
467 | } | | 467 | } |
468 | } | | 468 | } |
469 | } | | 469 | } |
470 | ; | | 470 | ; |
471 | | | 471 | |
472 | o_merid: | | 472 | o_merid: |
473 | /* empty */ { $$ = MER24; } | | 473 | /* empty */ { $$ = MER24; } |
474 | | tMERIDIAN { $$ = $1; } | | 474 | | tMERIDIAN { $$ = $1; } |
475 | | tTIME { $$ = $1 == 0 ? MER_MN : MER_NOON; } | | 475 | | tTIME { $$ = $1 == 0 ? MER_MN : MER_NOON; } |
476 | ; | | 476 | ; |
477 | | | 477 | |
478 | %% | | 478 | %% |
479 | | | 479 | |
480 | static short DaysInMonth[12] = { | | 480 | static short DaysInMonth[12] = { |
481 | 31, 28, 31, 30, 31, 30, | | 481 | 31, 28, 31, 30, 31, 30, |
482 | 31, 31, 30, 31, 30, 31 | | 482 | 31, 31, 30, 31, 30, 31 |
483 | }; | | 483 | }; |
484 | | | 484 | |
485 | /* | | 485 | /* |
486 | * works with tm.tm_year (ie: rel to 1900) | | 486 | * works with tm.tm_year (ie: rel to 1900) |
487 | */ | | 487 | */ |
488 | #define isleap(yr) (((yr) & 3) == 0 && (((yr) % 100) != 0 || \ | | 488 | #define isleap(yr) (((yr) & 3) == 0 && (((yr) % 100) != 0 || \ |
489 | ((1900+(yr)) % 400) == 0)) | | 489 | ((1900+(yr)) % 400) == 0)) |
490 | | | 490 | |
491 | /* Month and day table. */ | | 491 | /* Month and day table. */ |
492 | static const TABLE MonthDayTable[] = { | | 492 | static const TABLE MonthDayTable[] = { |
493 | { "january", tMONTH, 1 }, | | 493 | { "january", tMONTH, 1 }, |
494 | { "february", tMONTH, 2 }, | | 494 | { "february", tMONTH, 2 }, |
495 | { "march", tMONTH, 3 }, | | 495 | { "march", tMONTH, 3 }, |
496 | { "april", tMONTH, 4 }, | | 496 | { "april", tMONTH, 4 }, |
497 | { "may", tMONTH, 5 }, | | 497 | { "may", tMONTH, 5 }, |
498 | { "june", tMONTH, 6 }, | | 498 | { "june", tMONTH, 6 }, |
499 | { "july", tMONTH, 7 }, | | 499 | { "july", tMONTH, 7 }, |
500 | { "august", tMONTH, 8 }, | | 500 | { "august", tMONTH, 8 }, |
501 | { "september", tMONTH, 9 }, | | 501 | { "september", tMONTH, 9 }, |
502 | { "sept", tMONTH, 9 }, | | 502 | { "sept", tMONTH, 9 }, |
503 | { "october", tMONTH, 10 }, | | 503 | { "october", tMONTH, 10 }, |
504 | { "november", tMONTH, 11 }, | | 504 | { "november", tMONTH, 11 }, |
505 | { "december", tMONTH, 12 }, | | 505 | { "december", tMONTH, 12 }, |
506 | { "sunday", tDAY, 0 }, | | 506 | { "sunday", tDAY, 0 }, |
507 | { "su", tDAY, 0 }, | | 507 | { "su", tDAY, 0 }, |
508 | { "monday", tDAY, 1 }, | | 508 | { "monday", tDAY, 1 }, |
509 | { "mo", tDAY, 1 }, | | 509 | { "mo", tDAY, 1 }, |
510 | { "tuesday", tDAY, 2 }, | | 510 | { "tuesday", tDAY, 2 }, |
511 | { "tues", tDAY, 2 }, | | 511 | { "tues", tDAY, 2 }, |
512 | { "tu", tDAY, 2 }, | | 512 | { "tu", tDAY, 2 }, |
513 | { "wednesday", tDAY, 3 }, | | 513 | { "wednesday", tDAY, 3 }, |
514 | { "wednes", tDAY, 3 }, | | 514 | { "wednes", tDAY, 3 }, |
515 | { "weds", tDAY, 3 }, | | 515 | { "weds", tDAY, 3 }, |
516 | { "we", tDAY, 3 }, | | 516 | { "we", tDAY, 3 }, |
517 | { "thursday", tDAY, 4 }, | | 517 | { "thursday", tDAY, 4 }, |
518 | { "thurs", tDAY, 4 }, | | 518 | { "thurs", tDAY, 4 }, |
519 | { "thur", tDAY, 4 }, | | 519 | { "thur", tDAY, 4 }, |
520 | { "th", tDAY, 4 }, | | 520 | { "th", tDAY, 4 }, |
521 | { "friday", tDAY, 5 }, | | 521 | { "friday", tDAY, 5 }, |
522 | { "fr", tDAY, 5 }, | | 522 | { "fr", tDAY, 5 }, |
523 | { "saturday", tDAY, 6 }, | | 523 | { "saturday", tDAY, 6 }, |
524 | { "sa", tDAY, 6 }, | | 524 | { "sa", tDAY, 6 }, |
525 | { NULL, 0, 0 } | | 525 | { NULL, 0, 0 } |
526 | }; | | 526 | }; |
527 | | | 527 | |
528 | /* Time units table. */ | | 528 | /* Time units table. */ |
529 | static const TABLE UnitsTable[] = { | | 529 | static const TABLE UnitsTable[] = { |
530 | { "year", tMONTH_UNIT, 12 }, | | 530 | { "year", tMONTH_UNIT, 12 }, |
531 | { "month", tMONTH_UNIT, 1 }, | | 531 | { "month", tMONTH_UNIT, 1 }, |
532 | { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, | | 532 | { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, |
533 | { "week", tMINUTE_UNIT, 7 * 24 * 60 }, | | 533 | { "week", tMINUTE_UNIT, 7 * 24 * 60 }, |
534 | { "day", tMINUTE_UNIT, 1 * 24 * 60 }, | | 534 | { "day", tMINUTE_UNIT, 1 * 24 * 60 }, |
535 | { "hour", tMINUTE_UNIT, 60 }, | | 535 | { "hour", tMINUTE_UNIT, 60 }, |
536 | { "minute", tMINUTE_UNIT, 1 }, | | 536 | { "minute", tMINUTE_UNIT, 1 }, |
537 | { "min", tMINUTE_UNIT, 1 }, | | 537 | { "min", tMINUTE_UNIT, 1 }, |
538 | { "second", tSEC_UNIT, 1 }, | | 538 | { "second", tSEC_UNIT, 1 }, |
539 | { "sec", tSEC_UNIT, 1 }, | | 539 | { "sec", tSEC_UNIT, 1 }, |
540 | { NULL, 0, 0 } | | 540 | { NULL, 0, 0 } |
541 | }; | | 541 | }; |
542 | | | 542 | |
543 | /* Assorted relative-time words. */ | | 543 | /* Assorted relative-time words. */ |
544 | static const TABLE OtherTable[] = { | | 544 | static const TABLE OtherTable[] = { |
545 | { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, | | 545 | { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, |
546 | { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, | | 546 | { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, |
547 | { "today", tMINUTE_UNIT, 0 }, | | 547 | { "today", tMINUTE_UNIT, 0 }, |
548 | { "now", tMINUTE_UNIT, 0 }, | | 548 | { "now", tMINUTE_UNIT, 0 }, |
549 | { "last", tUNUMBER, -1 }, | | 549 | { "last", tUNUMBER, -1 }, |
550 | { "this", tMINUTE_UNIT, 0 }, | | 550 | { "this", tMINUTE_UNIT, 0 }, |
551 | { "next", tUNUMBER, 2 }, | | 551 | { "next", tUNUMBER, 2 }, |
552 | { "first", tUNUMBER, 1 }, | | 552 | { "first", tUNUMBER, 1 }, |
553 | { "one", tUNUMBER, 1 }, | | 553 | { "one", tUNUMBER, 1 }, |
554 | /* { "second", tUNUMBER, 2 }, */ | | 554 | /* { "second", tUNUMBER, 2 }, */ |
555 | { "two", tUNUMBER, 2 }, | | 555 | { "two", tUNUMBER, 2 }, |
556 | { "third", tUNUMBER, 3 }, | | 556 | { "third", tUNUMBER, 3 }, |
557 | { "three", tUNUMBER, 3 }, | | 557 | { "three", tUNUMBER, 3 }, |
558 | { "fourth", tUNUMBER, 4 }, | | 558 | { "fourth", tUNUMBER, 4 }, |
559 | { "four", tUNUMBER, 4 }, | | 559 | { "four", tUNUMBER, 4 }, |
560 | { "fifth", tUNUMBER, 5 }, | | 560 | { "fifth", tUNUMBER, 5 }, |
561 | { "five", tUNUMBER, 5 }, | | 561 | { "five", tUNUMBER, 5 }, |
562 | { "sixth", tUNUMBER, 6 }, | | 562 | { "sixth", tUNUMBER, 6 }, |
563 | { "six", tUNUMBER, 6 }, | | 563 | { "six", tUNUMBER, 6 }, |
564 | { "seventh", tUNUMBER, 7 }, | | 564 | { "seventh", tUNUMBER, 7 }, |
565 | { "seven", tUNUMBER, 7 }, | | 565 | { "seven", tUNUMBER, 7 }, |
566 | { "eighth", tUNUMBER, 8 }, | | 566 | { "eighth", tUNUMBER, 8 }, |
567 | { "eight", tUNUMBER, 8 }, | | 567 | { "eight", tUNUMBER, 8 }, |
568 | { "ninth", tUNUMBER, 9 }, | | 568 | { "ninth", tUNUMBER, 9 }, |
569 | { "nine", tUNUMBER, 9 }, | | 569 | { "nine", tUNUMBER, 9 }, |
570 | { "tenth", tUNUMBER, 10 }, | | 570 | { "tenth", tUNUMBER, 10 }, |
571 | { "ten", tUNUMBER, 10 }, | | 571 | { "ten", tUNUMBER, 10 }, |
572 | { "eleventh", tUNUMBER, 11 }, | | 572 | { "eleventh", tUNUMBER, 11 }, |
573 | { "eleven", tUNUMBER, 11 }, | | 573 | { "eleven", tUNUMBER, 11 }, |
574 | { "twelfth", tUNUMBER, 12 }, | | 574 | { "twelfth", tUNUMBER, 12 }, |
575 | { "twelve", tUNUMBER, 12 }, | | 575 | { "twelve", tUNUMBER, 12 }, |
576 | { "ago", tAGO, 1 }, | | 576 | { "ago", tAGO, 1 }, |
577 | { NULL, 0, 0 } | | 577 | { NULL, 0, 0 } |
578 | }; | | 578 | }; |
579 | | | 579 | |
580 | /* The timezone table. */ | | 580 | /* The timezone table. */ |
581 | /* Some of these are commented out because a time_t can't store a float. */ | | 581 | /* Some of these are commented out because a time_t can't store a float. */ |
582 | static const TABLE TimezoneTable[] = { | | 582 | static const TABLE TimezoneTable[] = { |
583 | { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ | | 583 | { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ |
584 | { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ | | 584 | { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ |
585 | { "utc", tZONE, HOUR( 0) }, | | 585 | { "utc", tZONE, HOUR( 0) }, |
586 | { "wet", tZONE, HOUR( 0) }, /* Western European */ | | 586 | { "wet", tZONE, HOUR( 0) }, /* Western European */ |
587 | { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ | | 587 | { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ |
588 | { "wat", tZONE, HOUR( 1) }, /* West Africa */ | | 588 | { "wat", tZONE, HOUR( 1) }, /* West Africa */ |
589 | { "at", tZONE, HOUR( 2) }, /* Azores */ | | 589 | { "at", tZONE, HOUR( 2) }, /* Azores */ |
590 | #if 0 | | 590 | #if 0 |
591 | /* For completeness. BST is also British Summer, and GST is | | 591 | /* For completeness. BST is also British Summer, and GST is |
592 | * also Guam Standard. */ | | 592 | * also Guam Standard. */ |
593 | { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ | | 593 | { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ |
594 | { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ | | 594 | { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ |
595 | #endif | | 595 | #endif |
596 | { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ | | 596 | { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ |
597 | { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ | | 597 | { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ |
598 | { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ | | 598 | { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ |
599 | { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ | | 599 | { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ |
600 | { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ | | 600 | { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ |
601 | { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ | | 601 | { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ |
602 | { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ | | 602 | { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ |
603 | { "cst", tZONE, HOUR( 6) }, /* Central Standard */ | | 603 | { "cst", tZONE, HOUR( 6) }, /* Central Standard */ |
604 | { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ | | 604 | { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ |
605 | { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ | | 605 | { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ |
606 | { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ | | 606 | { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ |
607 | { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ | | 607 | { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ |
608 | { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ | | 608 | { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ |
609 | { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ | | 609 | { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ |
610 | { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ | | 610 | { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ |
611 | { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ | | 611 | { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ |
612 | { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ | | 612 | { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ |
613 | { "cat", tZONE, HOUR(10) }, /* Central Alaska */ | | 613 | { "cat", tZONE, HOUR(10) }, /* Central Alaska */ |
614 | { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ | | 614 | { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ |
615 | { "nt", tZONE, HOUR(11) }, /* Nome */ | | 615 | { "nt", tZONE, HOUR(11) }, /* Nome */ |
616 | { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ | | 616 | { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ |
617 | { "cet", tZONE, -HOUR(1) }, /* Central European */ | | 617 | { "cet", tZONE, -HOUR(1) }, /* Central European */ |
618 | { "met", tZONE, -HOUR(1) }, /* Middle European */ | | 618 | { "met", tZONE, -HOUR(1) }, /* Middle European */ |
619 | { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ | | 619 | { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ |
620 | { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ | | 620 | { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ |
621 | { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ | | 621 | { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ |
622 | { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ | | 622 | { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ |
623 | { "fwt", tZONE, -HOUR(1) }, /* French Winter */ | | 623 | { "fwt", tZONE, -HOUR(1) }, /* French Winter */ |
624 | { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ | | 624 | { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ |
625 | { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ | | 625 | { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ |
626 | { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ | | 626 | { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ |
627 | { "it", tZONE, -HOUR(3.5) },/* Iran */ | | 627 | { "it", tZONE, -HOUR(3.5) },/* Iran */ |
628 | { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ | | 628 | { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ |
629 | { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ | | 629 | { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ |
630 | { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ | | 630 | { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ |
631 | { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ | | 631 | { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ |
632 | #if 0 | | 632 | #if 0 |
633 | /* For completeness. NST is also Newfoundland Stanard, and SST is | | 633 | /* For completeness. NST is also Newfoundland Stanard, and SST is |
634 | * also Swedish Summer. */ | | 634 | * also Swedish Summer. */ |
635 | { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ | | 635 | { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ |
636 | { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ | | 636 | { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ |
637 | #endif /* 0 */ | | 637 | #endif /* 0 */ |
638 | { "ict", tZONE, -HOUR(7) }, /* Indo China Time (Thai) */ | | 638 | { "ict", tZONE, -HOUR(7) }, /* Indo China Time (Thai) */ |
639 | #if 0 /* this one looks to be bogus */ | | 639 | #if 0 /* this one looks to be bogus */ |
640 | { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ | | 640 | { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ |
641 | #endif | | 641 | #endif |
642 | { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ | | 642 | { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ |
643 | { "awst", tZONE, -HOUR(8) }, /* West Australian Standard */ | | 643 | { "awst", tZONE, -HOUR(8) }, /* West Australian Standard */ |
644 | { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ | | 644 | { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ |
645 | { "awdt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ | | 645 | { "awdt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ |
646 | { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ | | 646 | { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ |
647 | { "sgt", tZONE, -HOUR(8) }, /* Singapore */ | | 647 | { "sgt", tZONE, -HOUR(8) }, /* Singapore */ |
648 | { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ | | 648 | { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ |
649 | { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ | | 649 | { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ |
650 | { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ | | 650 | { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ |
651 | { "acst", tZONE, -HOUR(9.5) },/* Central Australian Standard */ | | 651 | { "acst", tZONE, -HOUR(9.5) },/* Central Australian Standard */ |
652 | { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ | | 652 | { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ |
653 | { "acdt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ | | 653 | { "acdt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ |
654 | { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ | | 654 | { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ |
655 | { "aest", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ | | 655 | { "aest", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ |
656 | { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ | | 656 | { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ |
657 | { "aedt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ | | 657 | { "aedt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ |
658 | { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ | | 658 | { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ |
659 | { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ | | 659 | { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ |
660 | { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ | | 660 | { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ |
661 | { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ | | 661 | { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ |
662 | { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ | | 662 | { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ |
663 | { NULL, 0, 0 } | | 663 | { NULL, 0, 0 } |
664 | }; | | 664 | }; |
665 | | | 665 | |
666 | /* Military timezone table. */ | | 666 | /* Military timezone table. */ |
667 | static const TABLE MilitaryTable[] = { | | 667 | static const TABLE MilitaryTable[] = { |
668 | { "a", tZONE, HOUR( 1) }, | | 668 | { "a", tZONE, HOUR( 1) }, |
669 | { "b", tZONE, HOUR( 2) }, | | 669 | { "b", tZONE, HOUR( 2) }, |
670 | { "c", tZONE, HOUR( 3) }, | | 670 | { "c", tZONE, HOUR( 3) }, |
671 | { "d", tZONE, HOUR( 4) }, | | 671 | { "d", tZONE, HOUR( 4) }, |
672 | { "e", tZONE, HOUR( 5) }, | | 672 | { "e", tZONE, HOUR( 5) }, |
673 | { "f", tZONE, HOUR( 6) }, | | 673 | { "f", tZONE, HOUR( 6) }, |
674 | { "g", tZONE, HOUR( 7) }, | | 674 | { "g", tZONE, HOUR( 7) }, |
675 | { "h", tZONE, HOUR( 8) }, | | 675 | { "h", tZONE, HOUR( 8) }, |
676 | { "i", tZONE, HOUR( 9) }, | | 676 | { "i", tZONE, HOUR( 9) }, |
677 | { "k", tZONE, HOUR( 10) }, | | 677 | { "k", tZONE, HOUR( 10) }, |
678 | { "l", tZONE, HOUR( 11) }, | | 678 | { "l", tZONE, HOUR( 11) }, |
679 | { "m", tZONE, HOUR( 12) }, | | 679 | { "m", tZONE, HOUR( 12) }, |
680 | { "n", tZONE, HOUR(- 1) }, | | 680 | { "n", tZONE, HOUR(- 1) }, |
681 | { "o", tZONE, HOUR(- 2) }, | | 681 | { "o", tZONE, HOUR(- 2) }, |
682 | { "p", tZONE, HOUR(- 3) }, | | 682 | { "p", tZONE, HOUR(- 3) }, |
683 | { "q", tZONE, HOUR(- 4) }, | | 683 | { "q", tZONE, HOUR(- 4) }, |
684 | { "r", tZONE, HOUR(- 5) }, | | 684 | { "r", tZONE, HOUR(- 5) }, |
685 | { "s", tZONE, HOUR(- 6) }, | | 685 | { "s", tZONE, HOUR(- 6) }, |
686 | { "t", tZONE, HOUR(- 7) }, | | 686 | { "t", tZONE, HOUR(- 7) }, |
687 | { "u", tZONE, HOUR(- 8) }, | | 687 | { "u", tZONE, HOUR(- 8) }, |
688 | { "v", tZONE, HOUR(- 9) }, | | 688 | { "v", tZONE, HOUR(- 9) }, |
689 | { "w", tZONE, HOUR(-10) }, | | 689 | { "w", tZONE, HOUR(-10) }, |
690 | { "x", tZONE, HOUR(-11) }, | | 690 | { "x", tZONE, HOUR(-11) }, |
691 | { "y", tZONE, HOUR(-12) }, | | 691 | { "y", tZONE, HOUR(-12) }, |
692 | { "z", tZONE, HOUR( 0) }, | | 692 | { "z", tZONE, HOUR( 0) }, |
693 | { NULL, 0, 0 } | | 693 | { NULL, 0, 0 } |
694 | }; | | 694 | }; |
695 | | | 695 | |
696 | static const TABLE TimeNames[] = { | | 696 | static const TABLE TimeNames[] = { |
697 | { "midnight", tTIME, 0 }, | | 697 | { "midnight", tTIME, 0 }, |
698 | { "mn", tTIME, 0 }, | | 698 | { "mn", tTIME, 0 }, |
699 | { "noon", tTIME, 12 }, | | 699 | { "noon", tTIME, 12 }, |
700 | { "midday", tTIME, 12 }, | | 700 | { "midday", tTIME, 12 }, |
701 | { NULL, 0, 0 } | | 701 | { NULL, 0, 0 } |
702 | }; | | 702 | }; |
703 | | | 703 | |
704 | | | 704 | |
705 | | | 705 | |
706 | /* ARGSUSED */ | | 706 | /* ARGSUSED */ |
707 | static int | | 707 | static int |
708 | yyerror(struct dateinfo *param, const char **inp, const char *s __unused) | | 708 | yyerror(struct dateinfo *param, const char **inp, const char *s __unused) |
709 | { | | 709 | { |
710 | return 0; | | 710 | return 0; |
711 | } | | 711 | } |
712 | | | 712 | |
713 | /* | | 713 | /* |
714 | * Save a relative value, if it fits | | 714 | * Save a relative value, if it fits |
715 | */ | | 715 | */ |
716 | static int | | 716 | static int |
717 | RelVal(struct dateinfo *param, time_t num, time_t unit, int scale, int type) | | 717 | RelVal(struct dateinfo *param, time_t num, time_t unit, int scale, int type) |
718 | { | | 718 | { |
719 | int i; | | 719 | int i; |
720 | time_t v; | | 720 | time_t v; |
721 | uintmax_t m; | | 721 | uintmax_t m; |
722 | int sign = 1; | | 722 | int sign = 1; |
723 | | | 723 | |
724 | if ((i = param->yyHaveRel) >= MAXREL) | | 724 | if ((i = param->yyHaveRel) >= MAXREL) |
725 | return 0; | | 725 | return 0; |
726 | | | 726 | |
727 | if (num < 0) { | | 727 | if (num < 0) { |
728 | sign = -sign; | | 728 | sign = -sign; |
729 | num = -num; | | 729 | num = -num; |
730 | } | | 730 | } |
731 | if (unit < 0) { | | 731 | if (unit < 0) { |
732 | sign = -sign; | | 732 | sign = -sign; |
733 | unit = -unit; | | 733 | unit = -unit; |
734 | } | | 734 | } |
735 | /* scale is always positive */ | | 735 | /* scale is always positive */ |
736 | | | 736 | |
737 | m = LLONG_MAX; /* TIME_T_MAX */ | | 737 | m = LLONG_MAX; /* TIME_T_MAX */ |
738 | if (scale > 1) | | 738 | if (scale > 1) |
739 | m /= scale; | | 739 | m /= scale; |
740 | if (unit > 1) | | 740 | if (unit > 1) |
741 | m /= unit; | | 741 | m /= unit; |
742 | if ((uintmax_t)num > m) | | 742 | if ((uintmax_t)num > m) |
743 | return 0; | | 743 | return 0; |
744 | | | 744 | |
745 | m = num * unit * scale; | | 745 | m = num * unit * scale; |
746 | v = (time_t) m; | | 746 | v = (time_t) m; |
747 | if (v < 0 || (uintmax_t)v != m) | | 747 | if (v < 0 || (uintmax_t)v != m) |
748 | return 0; | | 748 | return 0; |
749 | if (sign < 0) | | 749 | if (sign < 0) |
750 | v = -v; | | 750 | v = -v; |
751 | | | 751 | |
752 | param->yyRel[i].yyRelMonth = type; | | 752 | param->yyRel[i].yyRelMonth = type; |
753 | param->yyRel[i].yyRelVal = v; | | 753 | param->yyRel[i].yyRelVal = v; |
754 | | | 754 | |
755 | return 1; | | 755 | return 1; |
756 | } | | 756 | } |
757 | | | 757 | |
758 | /* | | 758 | /* |
759 | * Adjust year from a value that might be abbreviated, to a full value. | | 759 | * Adjust year from a value that might be abbreviated, to a full value. |
760 | * e.g. convert 70 to 1970. | | 760 | * e.g. convert 70 to 1970. |
761 | * Input Year is either: | | 761 | * Input Year is either: |
762 | * - A negative number, which means to use its absolute value (why?) | | 762 | * - A negative number, which means to use its absolute value (why?) |
763 | * - A number from 0 to 68, which means a year from 2000 to 2068, | | 763 | * - A number from 0 to 68, which means a year from 2000 to 2068, |
764 | * - A number from 69 to 99, which means a year from 1969 to 1999, or | | 764 | * - A number from 69 to 99, which means a year from 1969 to 1999, or |
765 | * - The actual year (>=100). | | 765 | * - The actual year (>=100). |
766 | * Returns the full year. | | 766 | * Returns the full year. |
767 | */ | | 767 | */ |
768 | static time_t | | 768 | static time_t |
769 | AdjustYear(time_t Year) | | 769 | AdjustYear(time_t Year) |
770 | { | | 770 | { |
771 | /* XXX Y2K */ | | 771 | /* XXX Y2K */ |
772 | if (Year < 0) | | 772 | if (Year < 0) |
773 | Year = -Year; | | 773 | Year = -Year; |
774 | if (Year < 69) /* POSIX compliant, 0..68 is 2000's, 69-99 1900's */ | | 774 | if (Year < 69) /* POSIX compliant, 0..68 is 2000's, 69-99 1900's */ |
775 | Year += 2000; | | 775 | Year += 2000; |
776 | else if (Year < 100) | | 776 | else if (Year < 100) |
777 | Year += 1900; | | 777 | Year += 1900; |
778 | return Year; | | 778 | return Year; |
779 | } | | 779 | } |
780 | | | 780 | |
781 | static time_t | | 781 | static time_t |
782 | Convert( | | 782 | Convert( |
783 | time_t Month, /* month of year [1-12] */ | | 783 | time_t Month, /* month of year [1-12] */ |
784 | time_t Day, /* day of month [1-31] */ | | 784 | time_t Day, /* day of month [1-31] */ |
785 | time_t Year, /* year, not abbreviated in any way */ | | 785 | time_t Year, /* year, not abbreviated in any way */ |
786 | time_t Hours, /* Hour of day [0-24] */ | | 786 | time_t Hours, /* Hour of day [0-24] */ |
787 | time_t Minutes, /* Minute of hour [0-59] */ | | 787 | time_t Minutes, /* Minute of hour [0-59] */ |
788 | time_t Seconds, /* Second of minute [0-60] */ | | 788 | time_t Seconds, /* Second of minute [0-60] */ |
789 | time_t Timezone, /* Timezone as minutes east of UTC, | | 789 | time_t Timezone, /* Timezone as minutes east of UTC, |
790 | * or USE_LOCAL_TIME special case */ | | 790 | * or USE_LOCAL_TIME special case */ |
791 | MERIDIAN Meridian, /* Hours are am/pm/24 hour clock */ | | 791 | MERIDIAN Meridian, /* Hours are am/pm/24 hour clock */ |
792 | DSTMODE DSTmode /* DST on/off/maybe */ | | 792 | DSTMODE DSTmode /* DST on/off/maybe */ |
793 | ) | | 793 | ) |
794 | { | | 794 | { |
795 | struct tm tm = {.tm_sec = 0}; | | 795 | struct tm tm = {.tm_sec = 0}; |
796 | struct tm otm; | | 796 | struct tm otm; |
797 | time_t result; | | 797 | time_t result; |
798 | | | 798 | |
799 | tm.tm_sec = Seconds; | | 799 | tm.tm_sec = Seconds; |
800 | tm.tm_min = Minutes; | | 800 | tm.tm_min = Minutes; |
801 | tm.tm_hour = ((Hours == 12 && Meridian != MER24) ? 0 : Hours) + | | 801 | tm.tm_hour = ((Hours == 12 && Meridian != MER24) ? 0 : Hours) + |
802 | (Meridian == MERpm ? 12 : 0); | | 802 | (Meridian == MERpm ? 12 : 0); |
803 | | | 803 | |
804 | tm.tm_mday = Day; | | 804 | tm.tm_mday = Day; |
805 | tm.tm_mon = Month - 1; | | 805 | tm.tm_mon = Month - 1; |
806 | tm.tm_year = Year - 1900; | | 806 | tm.tm_year = Year - 1900; |
807 | if ((time_t)tm.tm_year + 1900 != Year) { | | 807 | if ((time_t)tm.tm_year + 1900 != Year) { |
808 | errno = EOVERFLOW; | | 808 | errno = EOVERFLOW; |
809 | return -1; | | 809 | return -1; |
810 | } | | 810 | } |
811 | if (Timezone == USE_LOCAL_TIME) { | | 811 | if (Timezone == USE_LOCAL_TIME) { |
812 | switch (DSTmode) { | | 812 | switch (DSTmode) { |
813 | case DSTon: tm.tm_isdst = 1; break; | | 813 | case DSTon: tm.tm_isdst = 1; break; |
814 | case DSToff: tm.tm_isdst = 0; break; | | 814 | case DSToff: tm.tm_isdst = 0; break; |
815 | default: tm.tm_isdst = -1; break; | | 815 | default: tm.tm_isdst = -1; break; |
816 | } | | 816 | } |
817 | otm = tm; | | 817 | otm = tm; |
818 | result = mktime(&tm); | | 818 | result = mktime(&tm); |
819 | } else { | | 819 | } else { |
820 | /* We rely on mktime_z(NULL, ...) working in UTC */ | | 820 | /* We rely on mktime_z(NULL, ...) working in UTC */ |
821 | tm.tm_isdst = 0; /* hence cannot be summer time */ | | 821 | tm.tm_isdst = 0; /* hence cannot be summer time */ |
822 | otm = tm; | | 822 | otm = tm; |
823 | errno = 0; | | 823 | errno = 0; |
824 | result = mktime_z(NULL, &tm); | | 824 | result = mktime_z(NULL, &tm); |
825 | if (result != -1 || errno == 0) { | | 825 | if (result != -1 || errno == 0) { |
826 | result += Timezone * 60; | | 826 | result += Timezone * 60; |
827 | if (DSTmode == DSTon) /* if specified sumer time */ | | 827 | if (DSTmode == DSTon) /* if specified sumer time */ |
828 | result -= 3600; /* UTC is 1 hour earlier XXX */ | | 828 | result -= 3600; /* UTC is 1 hour earlier XXX */ |
829 | } | | 829 | } |
830 | } | | 830 | } |
831 | | | 831 | |
832 | #if PARSEDATE_DEBUG | | 832 | #if PARSEDATE_DEBUG |
833 | fprintf(stderr, "%s(M=%jd D=%jd Y=%jd H=%jd M=%jd S=%jd Z=%jd" | | 833 | fprintf(stderr, "%s(M=%jd D=%jd Y=%jd H=%jd M=%jd S=%jd Z=%jd" |
834 | " mer=%d DST=%d)", | | 834 | " mer=%d DST=%d)", |
835 | __func__, | | 835 | __func__, |
836 | (intmax_t)Month, (intmax_t)Day, (intmax_t)Year, | | 836 | (intmax_t)Month, (intmax_t)Day, (intmax_t)Year, |
837 | (intmax_t)Hours, (intmax_t)Minutes, (intmax_t)Seconds, | | 837 | (intmax_t)Hours, (intmax_t)Minutes, (intmax_t)Seconds, |
838 | (intmax_t)Timezone, (int)Meridian, (int)DSTmode); | | 838 | (intmax_t)Timezone, (int)Meridian, (int)DSTmode); |
839 | fprintf(stderr, " -> %jd", (intmax_t)result); | | 839 | fprintf(stderr, " -> %jd", (intmax_t)result); |
840 | fprintf(stderr, " %s", ctime(&result)); | | 840 | fprintf(stderr, " %s", ctime(&result)); |
841 | #endif | | 841 | #endif |
842 | | | 842 | |
843 | #define TM_NE(fld) (otm.tm_ ## fld != tm.tm_ ## fld) | | 843 | #define TM_NE(fld) (otm.tm_ ## fld != tm.tm_ ## fld) |
844 | if (TM_NE(year) || TM_NE(mon) || TM_NE(mday) || | | 844 | if (TM_NE(year) || TM_NE(mon) || TM_NE(mday) || |
845 | TM_NE(hour) || TM_NE(min) || TM_NE(sec)) { | | 845 | TM_NE(hour) || TM_NE(min) || TM_NE(sec)) { |
846 | /* mktime() "corrected" our tm, so it must have been invalid */ | | 846 | /* mktime() "corrected" our tm, so it must have been invalid */ |
847 | result = -1; | | 847 | result = -1; |
848 | errno = EAGAIN; | | 848 | errno = EAGAIN; |
849 | } | | 849 | } |
850 | #undef TM_NE | | 850 | #undef TM_NE |
851 | | | 851 | |
852 | return result; | | 852 | return result; |
853 | } | | 853 | } |
854 | | | 854 | |
855 | | | 855 | |
856 | static time_t | | 856 | static time_t |
857 | DSTcorrect( | | 857 | DSTcorrect( |
858 | time_t Start, | | 858 | time_t Start, |
859 | time_t Future | | 859 | time_t Future |
860 | ) | | 860 | ) |
861 | { | | 861 | { |
862 | time_t StartDay; | | 862 | time_t StartDay; |
863 | time_t FutureDay; | | 863 | time_t FutureDay; |
864 | struct tm tm; | | 864 | struct tm tm; |
865 | | | 865 | |
866 | if (localtime_r(&Start, &tm) == NULL) | | 866 | if (localtime_r(&Start, &tm) == NULL) |
867 | return -1; | | 867 | return -1; |
868 | StartDay = (tm.tm_hour + 1) % 24; | | 868 | StartDay = (tm.tm_hour + 1) % 24; |
869 | | | 869 | |
870 | if (localtime_r(&Future, &tm) == NULL) | | 870 | if (localtime_r(&Future, &tm) == NULL) |
871 | return -1; | | 871 | return -1; |
872 | FutureDay = (tm.tm_hour + 1) % 24; | | 872 | FutureDay = (tm.tm_hour + 1) % 24; |
873 | | | 873 | |
874 | return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; | | 874 | return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; |
875 | } | | 875 | } |
876 | | | 876 | |
877 | | | 877 | |
878 | static time_t | | 878 | static time_t |
879 | RelativeDate( | | 879 | RelativeDate( |
880 | time_t Start, | | 880 | time_t Start, |
881 | time_t DayOrdinal, | | 881 | time_t DayOrdinal, |
882 | time_t DayNumber | | 882 | time_t DayNumber |
883 | ) | | 883 | ) |
884 | { | | 884 | { |
885 | struct tm tm; | | 885 | struct tm tm; |
886 | time_t now; | | 886 | time_t now; |
887 | time_t change; | | 887 | time_t change; |
888 | | | 888 | |
889 | now = Start; | | 889 | now = Start; |
890 | if (localtime_r(&now, &tm) == NULL) | | 890 | if (localtime_r(&now, &tm) == NULL) |
891 | return -1; | | 891 | return -1; |
892 | | | 892 | |
893 | /* should be using TIME_T_MAX but there is no such thing, so just "know" */ | | 893 | /* should be using TIME_T_MAX but there is no such thing, so just "know" */ |
894 | if (llabs(DayOrdinal) >= LLONG_MAX / (7 * SECSPERDAY)) { | | 894 | if (llabs(DayOrdinal) >= LLONG_MAX / (7 * SECSPERDAY)) { |
895 | errno = EOVERFLOW; | | 895 | errno = EOVERFLOW; |
896 | return -1; | | 896 | return -1; |
897 | } | | 897 | } |
898 | | | 898 | |
899 | change = SECSPERDAY * ((DayNumber - tm.tm_wday + 7) % 7); | | 899 | change = SECSPERDAY * ((DayNumber - tm.tm_wday + 7) % 7); |
900 | change += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); | | 900 | change += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); |
901 | | | 901 | |
902 | /* same here for _MAX and _MIN */ | | 902 | /* same here for _MAX and _MIN */ |
903 | if ((change > 0 && LLONG_MAX - change < now) || | | 903 | if ((change > 0 && LLONG_MAX - change < now) || |
904 | (change < 0 && LLONG_MIN - change > now)) { | | 904 | (change < 0 && LLONG_MIN - change > now)) { |
905 | errno = EOVERFLOW; | | 905 | errno = EOVERFLOW; |
906 | return -1; | | 906 | return -1; |
907 | } | | 907 | } |
908 | | | 908 | |
909 | now += change; | | 909 | now += change; |
910 | return DSTcorrect(Start, now); | | 910 | return DSTcorrect(Start, now); |
911 | } | | 911 | } |
912 | | | 912 | |
913 | | | 913 | |
914 | static time_t | | 914 | static time_t |
915 | RelativeMonth( | | 915 | RelativeMonth( |
916 | time_t Start, | | 916 | time_t Start, |
917 | time_t RelMonth, | | 917 | time_t RelMonth, |
918 | time_t Timezone | | 918 | time_t Timezone |
919 | ) | | 919 | ) |
920 | { | | 920 | { |
921 | struct tm tm; | | 921 | struct tm tm; |
922 | time_t Month; | | 922 | time_t Month; |
923 | time_t Then; | | 923 | time_t Then; |
924 | int Day; | | 924 | int Day; |
925 | | | 925 | |
926 | if (RelMonth == 0) | | 926 | if (RelMonth == 0) |
927 | return 0; | | 927 | return 0; |
928 | /* | | 928 | /* |
929 | * It doesn't matter what timezone we use to do this computation, | | 929 | * It doesn't matter what timezone we use to do this computation, |
930 | * as long as we use the same one to reassemble the time that we | | 930 | * as long as we use the same one to reassemble the time that we |
931 | * used to disassemble it. So always use localtime and mktime. In | | 931 | * used to disassemble it. So always use localtime and mktime. In |
932 | * particular, don't use Convert() to reassemble, because it will | | 932 | * particular, don't use Convert() to reassemble, because it will |
933 | * not only reassemble with the wrong timezone but it will also | | 933 | * not only reassemble with the wrong timezone but it will also |
934 | * fail if we do e.g. three months from March 31 yielding July 1. | | 934 | * fail if we do e.g. three months from March 31 yielding July 1. |
935 | */ | | 935 | */ |
936 | (void)Timezone; | | 936 | (void)Timezone; |
937 | | | 937 | |
938 | if (localtime_r(&Start, &tm) == NULL) | | 938 | if (localtime_r(&Start, &tm) == NULL) |
939 | return -1; | | 939 | return -1; |
940 | | | 940 | |
941 | if (RelMonth >= LLONG_MAX - 12*((time_t)tm.tm_year + 1900) - tm.tm_mon) { | | 941 | if (RelMonth >= LLONG_MAX - 12*((time_t)tm.tm_year + 1900) - tm.tm_mon) { |
942 | errno = EOVERFLOW; | | 942 | errno = EOVERFLOW; |
943 | return -1; | | 943 | return -1; |
944 | } | | 944 | } |
945 | Month = 12 * (tm.tm_year + 1900) + tm.tm_mon + RelMonth; | | 945 | Month = 12 * (tm.tm_year + 1900) + tm.tm_mon + RelMonth; |
946 | tm.tm_year = (Month / 12) - 1900; | | 946 | tm.tm_year = (Month / 12) - 1900; |
947 | /* check for tm_year (an int) overflow */ | | 947 | /* check for tm_year (an int) overflow */ |
948 | if (((time_t)tm.tm_year + 1900) != Month/12) { | | 948 | if (((time_t)tm.tm_year + 1900) != Month/12) { |
949 | errno = EOVERFLOW; | | 949 | errno = EOVERFLOW; |
950 | return -1; | | 950 | return -1; |
951 | } | | 951 | } |
952 | tm.tm_mon = Month % 12; | | 952 | tm.tm_mon = Month % 12; |
953 | if (tm.tm_mday > (Day = DaysInMonth[tm.tm_mon] + | | 953 | if (tm.tm_mday > (Day = DaysInMonth[tm.tm_mon] + |
954 | ((tm.tm_mon==1) ? isleap(tm.tm_year) : 0))) | | 954 | ((tm.tm_mon==1) ? isleap(tm.tm_year) : 0))) |
955 | tm.tm_mday = Day; | | 955 | tm.tm_mday = Day; |
956 | errno = 0; | | 956 | errno = 0; |
957 | Then = mktime(&tm); | | 957 | Then = mktime(&tm); |
958 | if (Then == -1 && errno != 0) | | 958 | if (Then == -1 && errno != 0) |
959 | return -1; | | 959 | return -1; |
960 | return DSTcorrect(Start, Then); | | 960 | return DSTcorrect(Start, Then); |
961 | } | | 961 | } |
962 | | | 962 | |
963 | | | 963 | |
964 | static int | | 964 | static int |
965 | LookupWord(YYSTYPE *yylval, char *buff) | | 965 | LookupWord(YYSTYPE *yylval, char *buff) |
966 | { | | 966 | { |
967 | register char *p; | | 967 | register char *p; |
968 | register char *q; | | 968 | register char *q; |
969 | register const TABLE *tp; | | 969 | register const TABLE *tp; |
970 | int i; | | 970 | int i; |
971 | int abbrev; | | 971 | int abbrev; |
972 | | | 972 | |
973 | /* Make it lowercase. */ | | 973 | /* Make it lowercase. */ |
974 | for (p = buff; *p; p++) | | 974 | for (p = buff; *p; p++) |
975 | if (isupper((unsigned char)*p)) | | 975 | if (isupper((unsigned char)*p)) |
976 | *p = tolower((unsigned char)*p); | | 976 | *p = tolower((unsigned char)*p); |
977 | | | 977 | |
978 | if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { | | 978 | if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { |
979 | yylval->Meridian = MERam; | | 979 | yylval->Meridian = MERam; |
980 | return tMERIDIAN; | | 980 | return tMERIDIAN; |
981 | } | | 981 | } |
982 | if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { | | 982 | if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { |
983 | yylval->Meridian = MERpm; | | 983 | yylval->Meridian = MERpm; |
984 | return tMERIDIAN; | | 984 | return tMERIDIAN; |
985 | } | | 985 | } |
986 | | | 986 | |
987 | /* See if we have an abbreviation for a month. */ | | 987 | /* See if we have an abbreviation for a month. */ |
988 | if (strlen(buff) == 3) | | 988 | if (strlen(buff) == 3) |
989 | abbrev = 1; | | 989 | abbrev = 1; |
990 | else if (strlen(buff) == 4 && buff[3] == '.') { | | 990 | else if (strlen(buff) == 4 && buff[3] == '.') { |
991 | abbrev = 1; | | 991 | abbrev = 1; |
992 | buff[3] = '\0'; | | 992 | buff[3] = '\0'; |
993 | } | | 993 | } |
994 | else | | 994 | else |
995 | abbrev = 0; | | 995 | abbrev = 0; |
996 | | | 996 | |
997 | for (tp = MonthDayTable; tp->name; tp++) { | | 997 | for (tp = MonthDayTable; tp->name; tp++) { |
998 | if (abbrev) { | | 998 | if (abbrev) { |
999 | if (strncmp(buff, tp->name, 3) == 0) { | | 999 | if (strncmp(buff, tp->name, 3) == 0) { |
1000 | yylval->Number = tp->value; | | 1000 | yylval->Number = tp->value; |
1001 | return tp->type; | | 1001 | return tp->type; |
1002 | } | | 1002 | } |
1003 | } | | 1003 | } |
1004 | else if (strcmp(buff, tp->name) == 0) { | | 1004 | else if (strcmp(buff, tp->name) == 0) { |
1005 | yylval->Number = tp->value; | | 1005 | yylval->Number = tp->value; |
1006 | return tp->type; | | 1006 | return tp->type; |
1007 | } | | 1007 | } |
1008 | } | | 1008 | } |
1009 | | | 1009 | |
1010 | for (tp = TimezoneTable; tp->name; tp++) | | 1010 | for (tp = TimezoneTable; tp->name; tp++) |
1011 | if (strcmp(buff, tp->name) == 0) { | | 1011 | if (strcmp(buff, tp->name) == 0) { |
1012 | yylval->Number = tp->value; | | 1012 | yylval->Number = tp->value; |
1013 | return tp->type; | | 1013 | return tp->type; |
1014 | } | | 1014 | } |
1015 | | | 1015 | |
1016 | if (strcmp(buff, "dst") == 0) | | 1016 | if (strcmp(buff, "dst") == 0) |
1017 | return tDST; | | 1017 | return tDST; |
1018 | | | 1018 | |
1019 | for (tp = TimeNames; tp->name; tp++) | | 1019 | for (tp = TimeNames; tp->name; tp++) |
1020 | if (strcmp(buff, tp->name) == 0) { | | 1020 | if (strcmp(buff, tp->name) == 0) { |
1021 | yylval->Number = tp->value; | | 1021 | yylval->Number = tp->value; |
1022 | return tp->type; | | 1022 | return tp->type; |
1023 | } | | 1023 | } |
1024 | | | 1024 | |
1025 | for (tp = UnitsTable; tp->name; tp++) | | 1025 | for (tp = UnitsTable; tp->name; tp++) |
1026 | if (strcmp(buff, tp->name) == 0) { | | 1026 | if (strcmp(buff, tp->name) == 0) { |
1027 | yylval->Number = tp->value; | | 1027 | yylval->Number = tp->value; |
1028 | return tp->type; | | 1028 | return tp->type; |
1029 | } | | 1029 | } |
1030 | | | 1030 | |
1031 | /* Strip off any plural and try the units table again. */ | | 1031 | /* Strip off any plural and try the units table again. */ |
1032 | i = strlen(buff) - 1; | | 1032 | i = strlen(buff) - 1; |
1033 | if (buff[i] == 's') { | | 1033 | if (buff[i] == 's') { |
1034 | buff[i] = '\0'; | | 1034 | buff[i] = '\0'; |
1035 | for (tp = UnitsTable; tp->name; tp++) | | 1035 | for (tp = UnitsTable; tp->name; tp++) |
1036 | if (strcmp(buff, tp->name) == 0) { | | 1036 | if (strcmp(buff, tp->name) == 0) { |
1037 | yylval->Number = tp->value; | | 1037 | yylval->Number = tp->value; |
1038 | return tp->type; | | 1038 | return tp->type; |
1039 | } | | 1039 | } |
1040 | buff[i] = 's'; /* Put back for "this" in OtherTable. */ | | 1040 | buff[i] = 's'; /* Put back for "this" in OtherTable. */ |
1041 | } | | 1041 | } |
1042 | | | 1042 | |
1043 | for (tp = OtherTable; tp->name; tp++) | | 1043 | for (tp = OtherTable; tp->name; tp++) |
1044 | if (strcmp(buff, tp->name) == 0) { | | 1044 | if (strcmp(buff, tp->name) == 0) { |
1045 | yylval->Number = tp->value; | | 1045 | yylval->Number = tp->value; |
1046 | return tp->type; | | 1046 | return tp->type; |
1047 | } | | 1047 | } |
1048 | | | 1048 | |
1049 | /* Military timezones. */ | | 1049 | /* Military timezones. */ |
1050 | if (buff[1] == '\0' && isalpha((unsigned char)*buff)) { | | 1050 | if (buff[1] == '\0' && isalpha((unsigned char)*buff)) { |
1051 | for (tp = MilitaryTable; tp->name; tp++) | | 1051 | for (tp = MilitaryTable; tp->name; tp++) |
1052 | if (strcmp(buff, tp->name) == 0) { | | 1052 | if (strcmp(buff, tp->name) == 0) { |
1053 | yylval->Number = tp->value; | | 1053 | yylval->Number = tp->value; |
1054 | return tp->type; | | 1054 | return tp->type; |
1055 | } | | 1055 | } |
1056 | } | | 1056 | } |
1057 | | | 1057 | |
1058 | /* Drop out any periods and try the timezone table again. */ | | 1058 | /* Drop out any periods and try the timezone table again. */ |
1059 | for (i = 0, p = q = buff; *q; q++) | | 1059 | for (i = 0, p = q = buff; *q; q++) |
1060 | if (*q != '.') | | 1060 | if (*q != '.') |
1061 | *p++ = *q; | | 1061 | *p++ = *q; |
1062 | else | | 1062 | else |
1063 | i++; | | 1063 | i++; |
1064 | *p = '\0'; | | 1064 | *p = '\0'; |
1065 | if (i) | | 1065 | if (i) |
1066 | for (tp = TimezoneTable; tp->name; tp++) | | 1066 | for (tp = TimezoneTable; tp->name; tp++) |
1067 | if (strcmp(buff, tp->name) == 0) { | | 1067 | if (strcmp(buff, tp->name) == 0) { |
1068 | yylval->Number = tp->value; | | 1068 | yylval->Number = tp->value; |
1069 | return tp->type; | | 1069 | return tp->type; |
1070 | } | | 1070 | } |
1071 | | | 1071 | |
1072 | return tID; | | 1072 | return tID; |
1073 | } | | 1073 | } |
1074 | | | 1074 | |
1075 | | | 1075 | |
1076 | static int | | 1076 | static int |
1077 | yylex(YYSTYPE *yylval, const char **yyInput) | | 1077 | yylex(YYSTYPE *yylval, const char **yyInput) |
1078 | { | | 1078 | { |
1079 | register char c; | | 1079 | register char c; |
1080 | register char *p; | | 1080 | register char *p; |
1081 | char buff[20]; | | 1081 | char buff[20]; |
1082 | int Count; | | 1082 | int Count; |
1083 | int sign; | | 1083 | int sign; |
1084 | const char *inp = *yyInput; | | 1084 | const char *inp = *yyInput; |
1085 | | | 1085 | |
1086 | for ( ; ; ) { | | 1086 | for ( ; ; ) { |
1087 | while (isspace((unsigned char)*inp)) | | 1087 | while (isspace((unsigned char)*inp)) |
1088 | inp++; | | 1088 | inp++; |
1089 | | | 1089 | |
1090 | if (isdigit((unsigned char)(c = *inp)) || c == '-' || c == '+') { | | 1090 | if (isdigit((unsigned char)(c = *inp)) || c == '-' || c == '+') { |
1091 | if (c == '-' || c == '+') { | | 1091 | if (c == '-' || c == '+') { |
1092 | sign = c == '-' ? -1 : 1; | | 1092 | sign = c == '-' ? -1 : 1; |
1093 | if (!isdigit((unsigned char)*++inp)) | | 1093 | if (!isdigit((unsigned char)*++inp)) |
1094 | /* skip the '-' sign */ | | 1094 | /* skip the '-' sign */ |
1095 | continue; | | 1095 | continue; |
1096 | } | | 1096 | } |
1097 | else | | 1097 | else |
1098 | sign = 0; | | 1098 | sign = 0; |
1099 | for (yylval->Number = 0; isdigit((unsigned char)(c = *inp++)); ) { | | 1099 | for (yylval->Number = 0; isdigit((unsigned char)(c = *inp++)); ) { |
1100 | time_t v; | | 1100 | time_t v; |
1101 | | | 1101 | |
1102 | v = yylval->Number; | | 1102 | v = yylval->Number; |
1103 | if (v > LLONG_MAX/10 || | | 1103 | if (v > LLONG_MAX/10 || |
1104 | (v == LLONG_MAX/10 && (v * 10 > LLONG_MAX - (c - '0')))) | | 1104 | (v == LLONG_MAX/10 && (v * 10 > LLONG_MAX - (c - '0')))) |
1105 | yylval->Number = LLONG_MAX; | | 1105 | yylval->Number = LLONG_MAX; |
1106 | else | | 1106 | else |
1107 | yylval->Number = 10 * yylval->Number + c - '0'; | | 1107 | yylval->Number = 10 * yylval->Number + c - '0'; |
1108 | } | | 1108 | } |
1109 | if (sign < 0) | | 1109 | if (sign < 0) |
1110 | yylval->Number = -yylval->Number; | | 1110 | yylval->Number = -yylval->Number; |
1111 | *yyInput = --inp; | | 1111 | *yyInput = --inp; |
1112 | return sign ? tSNUMBER : tUNUMBER; | | 1112 | return sign ? tSNUMBER : tUNUMBER; |
1113 | } | | 1113 | } |
1114 | if (isalpha((unsigned char)c)) { | | 1114 | if (isalpha((unsigned char)c)) { |
1115 | for (p = buff; isalpha((unsigned char)(c = *inp++)) || c == '.'; ) | | 1115 | for (p = buff; isalpha((unsigned char)(c = *inp++)) || c == '.'; ) |
1116 | if (p < &buff[sizeof buff - 1]) | | 1116 | if (p < &buff[sizeof buff - 1]) |
1117 | *p++ = c; | | 1117 | *p++ = c; |
1118 | *p = '\0'; | | 1118 | *p = '\0'; |
1119 | *yyInput = --inp; | | 1119 | *yyInput = --inp; |
1120 | return LookupWord(yylval, buff); | | 1120 | return LookupWord(yylval, buff); |
1121 | } | | 1121 | } |
1122 | if (c == '@') { | | 1122 | if (c == '@') { |
1123 | *yyInput = ++inp; | | 1123 | *yyInput = ++inp; |
1124 | return AT_SIGN; | | 1124 | return AT_SIGN; |
1125 | } | | 1125 | } |
1126 | if (c != '(') { | | 1126 | if (c != '(') { |
1127 | *yyInput = ++inp; | | 1127 | *yyInput = ++inp; |
1128 | return c; | | 1128 | return c; |
1129 | } | | 1129 | } |
1130 | Count = 0; | | 1130 | Count = 0; |
1131 | do { | | 1131 | do { |
1132 | c = *inp++; | | 1132 | c = *inp++; |
1133 | if (c == '\0') | | 1133 | if (c == '\0') |
1134 | return c; | | 1134 | return c; |
1135 | if (c == '(') | | 1135 | if (c == '(') |
1136 | Count++; | | 1136 | Count++; |
1137 | else if (c == ')') | | 1137 | else if (c == ')') |
1138 | Count--; | | 1138 | Count--; |
1139 | } while (Count > 0); | | 1139 | } while (Count > 0); |
1140 | } | | 1140 | } |
1141 | } | | 1141 | } |
1142 | | | 1142 | |
1143 | #define TM_YEAR_ORIGIN 1900 | | 1143 | #define TM_YEAR_ORIGIN 1900 |
1144 | | | 1144 | |
1145 | time_t | | 1145 | time_t |
1146 | parsedate(const char *p, const time_t *now, const int *zone) | | 1146 | parsedate(const char *p, const time_t *now, const int *zone) |
1147 | { | | 1147 | { |
1148 | struct tm local, *tm; | | 1148 | struct tm local, *tm; |
1149 | time_t nowt; | | 1149 | time_t nowt; |
1150 | int zonet; | | 1150 | int zonet; |
1151 | time_t Start; | | 1151 | time_t Start; |
1152 | time_t tod, rm; | | 1152 | time_t tod, rm; |
1153 | struct dateinfo param; | | 1153 | struct dateinfo param; |
1154 | int saved_errno; | | 1154 | int saved_errno; |
1155 | int i; | | 1155 | int i; |
1156 | | | 1156 | |
1157 | saved_errno = errno; | | 1157 | saved_errno = errno; |
1158 | errno = 0; | | 1158 | errno = 0; |
1159 | | | 1159 | |
1160 | if (now == NULL) { | | 1160 | if (now == NULL) { |
1161 | now = &nowt; | | 1161 | now = &nowt; |
1162 | (void)time(&nowt); | | 1162 | (void)time(&nowt); |
1163 | } | | 1163 | } |
1164 | if (zone == NULL) { | | 1164 | if (zone == NULL) { |
1165 | zone = &zonet; | | 1165 | zone = &zonet; |
1166 | zonet = USE_LOCAL_TIME; | | 1166 | zonet = USE_LOCAL_TIME; |
1167 | if ((tm = localtime_r(now, &local)) == NULL) | | 1167 | if ((tm = localtime_r(now, &local)) == NULL) |
1168 | return -1; | | 1168 | return -1; |
1169 | } else { | | 1169 | } else { |
1170 | /* | | 1170 | /* |
1171 | * Should use the specified zone, not localtime. | | 1171 | * Should use the specified zone, not localtime. |
1172 | * Fake it using gmtime and arithmetic. | | 1172 | * Fake it using gmtime and arithmetic. |
1173 | * This is good enough because we use only the year/month/day, | | 1173 | * This is good enough because we use only the year/month/day, |
1174 | * not other fields of struct tm. | | 1174 | * not other fields of struct tm. |
1175 | */ | | 1175 | */ |
1176 | time_t fake = *now + (*zone * 60); | | 1176 | time_t fake = *now + (*zone * 60); |
1177 | if ((tm = gmtime_r(&fake, &local)) == NULL) | | 1177 | if ((tm = gmtime_r(&fake, &local)) == NULL) |
1178 | return -1; | | 1178 | return -1; |
1179 | } | | 1179 | } |
1180 | param.yyYear = tm->tm_year + 1900; | | 1180 | param.yyYear = tm->tm_year + 1900; |
1181 | param.yyMonth = tm->tm_mon + 1; | | 1181 | param.yyMonth = tm->tm_mon + 1; |
1182 | param.yyDay = tm->tm_mday; | | 1182 | param.yyDay = tm->tm_mday; |
1183 | param.yyTimezone = *zone; | | 1183 | param.yyTimezone = *zone; |
1184 | param.yyDSTmode = DSTmaybe; | | 1184 | param.yyDSTmode = DSTmaybe; |
1185 | param.yyHour = 0; | | 1185 | param.yyHour = 0; |
1186 | param.yyMinutes = 0; | | 1186 | param.yyMinutes = 0; |
1187 | param.yySeconds = 0; | | 1187 | param.yySeconds = 0; |
1188 | param.yyMeridian = MER24; | | 1188 | param.yyMeridian = MER24; |
1189 | param.yyHaveDate = 0; | | 1189 | param.yyHaveDate = 0; |
1190 | param.yyHaveFullYear = 0; | | 1190 | param.yyHaveFullYear = 0; |
1191 | param.yyHaveDay = 0; | | 1191 | param.yyHaveDay = 0; |
1192 | param.yyHaveRel = 0; | | 1192 | param.yyHaveRel = 0; |
1193 | param.yyHaveTime = 0; | | 1193 | param.yyHaveTime = 0; |
1194 | param.yyHaveZone = 0; | | 1194 | param.yyHaveZone = 0; |
1195 | | | 1195 | |
1196 | /* | | 1196 | /* |
1197 | * This one is too hard to parse using a grammar (the lexer would | | 1197 | * This one is too hard to parse using a grammar (the lexer would |
1198 | * confuse the 'T' with the Mil format timezone designator) | | 1198 | * confuse the 'T' with the Mil format timezone designator) |
1199 | * so handle it as a special case. | | 1199 | * so handle it as a special case. |
1200 | */ | | 1200 | */ |
1201 | do { | | 1201 | do { |
1202 | const unsigned char *pp = (const unsigned char *)p; | | 1202 | const unsigned char *pp = (const unsigned char *)p; |
1203 | char *ep; /* starts as "expected, becomes "end ptr" */ | | 1203 | char *ep; /* starts as "expected, becomes "end ptr" */ |
1204 | static char format[] = "-dd-ddTdd:dd:dd"; | | 1204 | static char format[] = "-dd-ddTdd:dd:dd"; |
1205 | time_t yr; | | 1205 | time_t yr; |
1206 | | | 1206 | |
1207 | while (isdigit(*pp)) | | 1207 | while (isdigit(*pp)) |
1208 | pp++; | | 1208 | pp++; |
1209 | | | 1209 | |
1210 | if (pp == (const unsigned char *)p) | | 1210 | if (pp == (const unsigned char *)p) |
1211 | break; | | 1211 | break; |
1212 | | | 1212 | |
1213 | for (ep = format; *ep; ep++, pp++) { | | 1213 | for (ep = format; *ep; ep++, pp++) { |
1214 | switch (*ep) { | | 1214 | switch (*ep) { |
1215 | case 'd': | | 1215 | case 'd': |
1216 | if (isdigit(*pp)) | | 1216 | if (isdigit(*pp)) |
1217 | continue; | | 1217 | continue; |
1218 | break; | | 1218 | break; |
1219 | case 'T': | | 1219 | case 'T': |
1220 | if (*pp == 'T' || *pp == 't' || *pp == ' ') | | 1220 | if (*pp == 'T' || *pp == 't' || *pp == ' ') |
1221 | continue; | | 1221 | continue; |
1222 | break; | | 1222 | break; |
1223 | default: | | 1223 | default: |
1224 | if (*pp == *ep) | | 1224 | if (*pp == *ep) |
1225 | continue; | | 1225 | continue; |
1226 | break; | | 1226 | break; |
1227 | } | | 1227 | } |
1228 | break; | | 1228 | break; |
1229 | } | | 1229 | } |
1230 | if (*ep != '\0') | | 1230 | if (*ep != '\0') |
1231 | break; | | 1231 | break; |
1232 | if (*pp == '.' || *pp == ',') { | | 1232 | if (*pp == '.' || *pp == ',') { |
1233 | if (!isdigit(pp[1])) | | 1233 | if (!isdigit(pp[1])) |
1234 | break; | | 1234 | break; |
1235 | while (isdigit(*++pp)) | | 1235 | while (isdigit(*++pp)) |
1236 | continue; | | 1236 | continue; |
1237 | } | | 1237 | } |
1238 | if (*pp == 'Z' || *pp == 'z') | | 1238 | if (*pp == 'Z' || *pp == 'z') |
1239 | pp++; | | 1239 | pp++; |
1240 | else if (isdigit(*pp)) | | 1240 | else if (isdigit(*pp)) |
1241 | break; | | 1241 | break; |
1242 | | | 1242 | |
1243 | if (*pp != '\0' && !isspace(*pp)) | | 1243 | if (*pp != '\0' && !isspace(*pp)) |
1244 | break; | | 1244 | break; |
1245 | | | 1245 | |
1246 | errno = 0; | | 1246 | errno = 0; |
1247 | yr = (time_t)strtol(p, &ep, 10); | | 1247 | yr = (time_t)strtol(p, &ep, 10); |
1248 | if (errno != 0) /* out of range (can be big number) */ | | 1248 | if (errno != 0) /* out of range (can be big number) */ |
1249 | break; /* the ones below are all 2 digits */ | | 1249 | break; /* the ones below are all 2 digits */ |
1250 | | | 1250 | |
1251 | /* | | 1251 | /* |
1252 | * This is good enough to commit to there being an ISO format | | 1252 | * This is good enough to commit to there being an ISO format |
1253 | * timestamp leading the input string. We permit standard | | 1253 | * timestamp leading the input string. We permit standard |
1254 | * parsedate() modifiers to follow but not precede this string. | | 1254 | * parsedate() modifiers to follow but not precede this string. |
1255 | */ | | 1255 | */ |
1256 | param.yyHaveTime = 1; | | 1256 | param.yyHaveTime = 1; |
1257 | param.yyHaveDate = 1; | | 1257 | param.yyHaveDate = 1; |
1258 | param.yyHaveFullYear = 1; | | 1258 | param.yyHaveFullYear = 1; |
1259 | | | 1259 | |
1260 | if (pp[-1] == 'Z' || pp[-1] == 'z') { | | 1260 | if (pp[-1] == 'Z' || pp[-1] == 'z') { |
1261 | param.yyTimezone = 0; | | 1261 | param.yyTimezone = 0; |
1262 | param.yyHaveZone = 1; | | 1262 | param.yyHaveZone = 1; |
1263 | } | | 1263 | } |
1264 | | | 1264 | |
1265 | param.yyYear = yr; | | 1265 | param.yyYear = yr; |
1266 | param.yyMonth = (time_t)strtol(ep + 1, &ep, 10); | | 1266 | param.yyMonth = (time_t)strtol(ep + 1, &ep, 10); |
1267 | param.yyDay = (time_t)strtol(ep + 1, &ep, 10); | | 1267 | param.yyDay = (time_t)strtol(ep + 1, &ep, 10); |
1268 | param.yyHour = (time_t)strtol(ep + 1, &ep, 10); | | 1268 | param.yyHour = (time_t)strtol(ep + 1, &ep, 10); |
1269 | param.yyMinutes = (time_t)strtol(ep + 1, &ep, 10); | | 1269 | param.yyMinutes = (time_t)strtol(ep + 1, &ep, 10); |
1270 | param.yySeconds = (time_t)strtol(ep + 1, &ep, 10); | | 1270 | param.yySeconds = (time_t)strtol(ep + 1, &ep, 10); |
1271 | /* ignore any fractional seconds, no way to return them in a time_t */ | | 1271 | /* ignore any fractional seconds, no way to return them in a time_t */ |
1272 | | | 1272 | |
1273 | param.yyMeridian = MER24; | | 1273 | param.yyMeridian = MER24; |
1274 | | | 1274 | |
1275 | p = (const char *)pp; | | 1275 | p = (const char *)pp; |
1276 | } while (0); | | 1276 | } while (0); |
1277 | | | 1277 | |
1278 | if (yyparse(¶m, &p) || param.yyHaveTime > 1 || param.yyHaveZone > 1 || | | 1278 | if (yyparse(¶m, &p) || param.yyHaveTime > 1 || param.yyHaveZone > 1 || |
1279 | param.yyHaveDate > 1 || param.yyHaveDay > 1) { | | 1279 | param.yyHaveDate > 1 || param.yyHaveDay > 1) { |
1280 | errno = EINVAL; | | 1280 | errno = EINVAL; |
1281 | return -1; | | 1281 | return -1; |
1282 | } | | 1282 | } |
1283 | | | 1283 | |
1284 | if (param.yyHaveDate || param.yyHaveTime || param.yyHaveDay) { | | 1284 | if (param.yyHaveDate || param.yyHaveTime || param.yyHaveDay) { |
1285 | if (! param.yyHaveFullYear) { | | 1285 | if (! param.yyHaveFullYear) { |
1286 | param.yyYear = AdjustYear(param.yyYear); | | 1286 | param.yyYear = AdjustYear(param.yyYear); |
1287 | param.yyHaveFullYear = 1; | | 1287 | param.yyHaveFullYear = 1; |
1288 | } | | 1288 | } |
1289 | errno = 0; | | 1289 | errno = 0; |
1290 | Start = Convert(param.yyMonth, param.yyDay, param.yyYear, param.yyHour, | | 1290 | Start = Convert(param.yyMonth, param.yyDay, param.yyYear, param.yyHour, |
1291 | param.yyMinutes, param.yySeconds, param.yyTimezone, | | 1291 | param.yyMinutes, param.yySeconds, param.yyTimezone, |
1292 | param.yyMeridian, param.yyDSTmode); | | 1292 | param.yyMeridian, param.yyDSTmode); |
1293 | if (Start == -1 && errno != 0) | | 1293 | if (Start == -1 && errno != 0) |
1294 | return -1; | | 1294 | return -1; |
1295 | } | | 1295 | } |
1296 | else { | | 1296 | else { |
1297 | Start = *now; | | 1297 | Start = *now; |
1298 | if (!param.yyHaveRel) | | 1298 | if (!param.yyHaveRel) |
1299 | Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; | | 1299 | Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; |
1300 | } | | 1300 | } |
1301 | | | 1301 | |
1302 | if (param.yyHaveRel > MAXREL) { | | 1302 | if (param.yyHaveRel > MAXREL) { |
1303 | errno = EINVAL; | | 1303 | errno = EINVAL; |
1304 | return -1; | | 1304 | return -1; |
1305 | } | | 1305 | } |
1306 | for (i = 0; i < param.yyHaveRel; i++) { | | 1306 | for (i = 0; i < param.yyHaveRel; i++) { |
1307 | if (param.yyRel[i].yyRelMonth) { | | 1307 | if (param.yyRel[i].yyRelMonth) { |
1308 | errno = 0; | | 1308 | errno = 0; |
1309 | rm = RelativeMonth(Start, param.yyRel[i].yyRelVal, param.yyTimezone); | | 1309 | rm = RelativeMonth(Start, param.yyRel[i].yyRelVal, param.yyTimezone); |
1310 | if (rm == -1 && errno != 0) | | 1310 | if (rm == -1 && errno != 0) |
1311 | return -1; | | 1311 | return -1; |
1312 | Start += rm; | | 1312 | Start += rm; |
1313 | } else | | 1313 | } else |
1314 | Start += param.yyRel[i].yyRelVal; | | 1314 | Start += param.yyRel[i].yyRelVal; |
1315 | } | | 1315 | } |
1316 | | | 1316 | |
1317 | if (param.yyHaveDay && !param.yyHaveDate) { | | 1317 | if (param.yyHaveDay && !param.yyHaveDate) { |
1318 | errno = 0; | | 1318 | errno = 0; |
1319 | tod = RelativeDate(Start, param.yyDayOrdinal, param.yyDayNumber); | | 1319 | tod = RelativeDate(Start, param.yyDayOrdinal, param.yyDayNumber); |
1320 | if (tod == -1 && errno != 0) | | 1320 | if (tod == -1 && errno != 0) |
1321 | return -1; | | 1321 | return -1; |
1322 | Start += tod; | | 1322 | Start += tod; |
1323 | } | | 1323 | } |
1324 | | | 1324 | |
1325 | errno = saved_errno; | | 1325 | errno = saved_errno; |
1326 | return Start; | | 1326 | return Start; |
1327 | } | | 1327 | } |
1328 | | | 1328 | |
1329 | | | 1329 | |
1330 | #if defined(TEST) | | 1330 | #if defined(TEST) |
1331 | | | 1331 | |
1332 | /* ARGSUSED */ | | 1332 | /* ARGSUSED */ |
1333 | int | | 1333 | int |
1334 | main(int ac, char *av[]) | | 1334 | main(int ac, char *av[]) |
1335 | { | | 1335 | { |
1336 | char buff[128]; | | 1336 | char buff[128]; |
1337 | time_t d; | | 1337 | time_t d; |
1338 | | | 1338 | |
1339 | (void)printf("Enter date, or blank line to exit.\n\t> "); | | 1339 | (void)printf("Enter date, or blank line to exit.\n\t> "); |
1340 | (void)fflush(stdout); | | 1340 | (void)fflush(stdout); |
1341 | while (fgets(buff, sizeof(buff), stdin) && buff[0] != '\n') { | | 1341 | while (fgets(buff, sizeof(buff), stdin) && buff[0] != '\n') { |
1342 | errno = 0; | | 1342 | errno = 0; |
1343 | d = parsedate(buff, NULL, NULL); | | 1343 | d = parsedate(buff, NULL, NULL); |
1344 | if (d == -1 && errno != 0) | | 1344 | if (d == -1 && errno != 0) |
1345 | (void)printf("Bad format - couldn't convert: %s\n", | | 1345 | (void)printf("Bad format - couldn't convert: %s\n", |
1346 | strerror(errno)); | | 1346 | strerror(errno)); |
1347 | else | | 1347 | else |
1348 | (void)printf("%jd\t%s", (intmax_t)d, ctime(&d)); | | 1348 | (void)printf("%jd\t%s", (intmax_t)d, ctime(&d)); |
1349 | (void)printf("\t> "); | | 1349 | (void)printf("\t> "); |
1350 | (void)fflush(stdout); | | 1350 | (void)fflush(stdout); |
1351 | } | | 1351 | } |
1352 | exit(0); | | 1352 | exit(0); |
1353 | /* NOTREACHED */ | | 1353 | /* NOTREACHED */ |
1354 | } | | 1354 | } |
1355 | #endif /* defined(TEST) */ | | 1355 | #endif /* defined(TEST) */ |