Support for parsing RFC3066 Content-Language headers
[mime4j.git] / src / main / javacc / org / apache / james / mime4j / field / datetime / DateTimeParser.jj
bloba8e9536df25f86bf38f07e2346ea1c7eaa1cf210
1 /****************************************************************\r
2  * Licensed to the Apache Software Foundation (ASF) under one   *\r
3  * or more contributor license agreements.  See the NOTICE file *\r
4  * distributed with this work for additional information        *\r
5  * regarding copyright ownership.  The ASF licenses this file   *\r
6  * to you under the Apache License, Version 2.0 (the            *\r
7  * "License"); you may not use this file except in compliance   *\r
8  * with the License.  You may obtain a copy of the License at   *\r
9  *                                                              *\r
10  *   http://www.apache.org/licenses/LICENSE-2.0                 *\r
11  *                                                              *\r
12  * Unless required by applicable law or agreed to in writing,   *\r
13  * software distributed under the License is distributed on an  *\r
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *\r
15  * KIND, either express or implied.  See the License for the    *\r
16  * specific language governing permissions and limitations      *\r
17  * under the License.                                           *\r
18  ****************************************************************/\r
21 /**\r
22  * RFC2822 date parser.\r
23  *\r
24  * Created 9/28/2004\r
25  * by Joe Cheng <code@joecheng.com>\r
26  */\r
28 options {\r
29         STATIC=false;\r
30         LOOKAHEAD=1;\r
31         OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";\r
32         //DEBUG_PARSER=true;\r
33         //DEBUG_TOKEN_MANAGER=true;\r
34 }\r
36 PARSER_BEGIN(DateTimeParser)\r
37 /****************************************************************\r
38  * Licensed to the Apache Software Foundation (ASF) under one   *\r
39  * or more contributor license agreements.  See the NOTICE file *\r
40  * distributed with this work for additional information        *\r
41  * regarding copyright ownership.  The ASF licenses this file   *\r
42  * to you under the Apache License, Version 2.0 (the            *\r
43  * "License"); you may not use this file except in compliance   *\r
44  * with the License.  You may obtain a copy of the License at   *\r
45  *                                                              *\r
46  *   http://www.apache.org/licenses/LICENSE-2.0                 *\r
47  *                                                              *\r
48  * Unless required by applicable law or agreed to in writing,   *\r
49  * software distributed under the License is distributed on an  *\r
50  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *\r
51  * KIND, either express or implied.  See the License for the    *\r
52  * specific language governing permissions and limitations      *\r
53  * under the License.                                           *\r
54  ****************************************************************/\r
55 package org.apache.james.mime4j.field.datetime.parser;\r
57 import org.apache.james.mime4j.field.datetime.DateTime;\r
59 import java.util.Calendar;\r
61 public class DateTimeParser {\r
62     private static final boolean ignoreMilitaryZoneOffset = true;\r
64     public static void main(String args[]) throws ParseException {\r
65                 while (true) {\r
66                     try {\r
67                                 DateTimeParser parser = new DateTimeParser(System.in);\r
68                         parser.parseLine();\r
69                     } catch (Exception x) {\r
70                                 x.printStackTrace();\r
71                                 return;\r
72                     }\r
73                 }\r
74     }\r
76     private static int parseDigits(Token token) {\r
77         return Integer.parseInt(token.image, 10);\r
78     }\r
80     private static int getMilitaryZoneOffset(char c) {\r
81         if (ignoreMilitaryZoneOffset)\r
82             return 0;\r
84         c = Character.toUpperCase(c);\r
86         switch (c) {\r
87             case 'A': return 1;\r
88             case 'B': return 2;\r
89             case 'C': return 3;\r
90             case 'D': return 4;\r
91             case 'E': return 5;\r
92             case 'F': return 6;\r
93             case 'G': return 7;\r
94             case 'H': return 8;\r
95             case 'I': return 9;\r
96             case 'K': return 10;\r
97             case 'L': return 11;\r
98             case 'M': return 12;\r
100             case 'N': return -1;\r
101             case 'O': return -2;\r
102             case 'P': return -3;\r
103             case 'Q': return -4;\r
104             case 'R': return -5;\r
105             case 'S': return -6;\r
106             case 'T': return -7;\r
107             case 'U': return -8;\r
108             case 'V': return -9;\r
109             case 'W': return -10;\r
110             case 'X': return -11;\r
111             case 'Y': return -12;\r
113             case 'Z': return 0;\r
114             default: return 0;\r
115         }\r
116     }\r
118     private static class Time {\r
119         private int hour;\r
120         private int minute;\r
121         private int second;\r
122         private int zone;\r
124         public Time(int hour, int minute, int second, int zone) {\r
125             this.hour = hour;\r
126             this.minute = minute;\r
127             this.second = second;\r
128             this.zone = zone;\r
129         }\r
131         public int getHour() { return hour; }\r
132         public int getMinute() { return minute; }\r
133         public int getSecond() { return second; }\r
134         public int getZone() { return zone; }\r
135     }\r
137     private static class Date {\r
138         private String year;\r
139         private int month;\r
140         private int day;\r
142         public Date(String year, int month, int day) {\r
143             this.year = year;\r
144             this.month = month;\r
145             this.day = day;\r
146         }\r
148         public String getYear() { return year; }\r
149         public int getMonth() { return month; }\r
150         public int getDay() { return day; }\r
151     }\r
154 PARSER_END(DateTimeParser)\r
156 DateTime parseLine() :\r
157 {DateTime dt;}\r
159         dt=date_time() ["\r"] "\n"\r
160         { return dt; }\r
163 DateTime parseAll() :\r
164 {DateTime dt;}\r
166         dt=date_time() <EOF>\r
167         { return dt; }\r
170 DateTime date_time() :\r
171 {Date d; Time t;}\r
173         [ day_of_week() "," ]\r
174         d=date()\r
175         t=time()\r
176         {\r
177             return new DateTime(\r
178                     d.getYear(),\r
179                     d.getMonth(),\r
180                     d.getDay(),\r
181                     t.getHour(),\r
182                     t.getMinute(),\r
183                     t.getSecond(),\r
184                     t.getZone());    // time zone offset\r
185         }\r
188 String day_of_week() :\r
189 {}\r
191 (    "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"\r
193     { return token.image; }\r
196 Date date() :\r
197 {int d, m; String y;}\r
199     d=day() m=month() y=year()\r
200     { return new Date(y, m, d); }\r
203 int day() :\r
204 {Token t;}\r
206     t=<DIGITS> { return parseDigits(t); }\r
209 int month() :\r
210 {}\r
212     "Jan" { return 1; }\r
213 |   "Feb" { return 2; }\r
214 |   "Mar" { return 3; }\r
215 |   "Apr" { return 4; }\r
216 |   "May" { return 5; }\r
217 |   "Jun" { return 6; }\r
218 |   "Jul" { return 7; }\r
219 |   "Aug" { return 8; }\r
220 |   "Sep" { return 9; }\r
221 |   "Oct" { return 10; }\r
222 |   "Nov" { return 11; }\r
223 |   "Dec" { return 12; }\r
226 String year() :\r
227 {Token t;}\r
229     t=<DIGITS> { return t.image; }\r
232 Time time() :\r
233 {int h, m, s=0, z;}\r
235     h=hour() ":" m=minute() [ ":" s=second() ] z=zone()\r
236     { return new Time(h, m, s, z); }\r
239 int hour() :\r
240 {Token t;}\r
242     t=<DIGITS> { return parseDigits(t); }\r
245 int minute() :\r
246 {Token t;}\r
248     t=<DIGITS> { return parseDigits(t); }\r
251 int second() :\r
252 {Token t;}\r
254     t=<DIGITS> { return parseDigits(t); }\r
257 int zone() :\r
258 { Token t, u; int z; }\r
260 (    t=< OFFSETDIR: ["+", "-"] > u=<DIGITS> { z=parseDigits(u)*(t.image.equals("-") ? -1 : 1); }\r
261 |   z=obs_zone()\r
263     { return z; }\r
266 int obs_zone() :\r
267 {Token t; int z;}\r
269 (   "UT"  { z=0; }\r
270 |   "GMT" { z=0; }\r
271 |   "EST" { z=-5; }\r
272 |   "EDT" { z=-4; }\r
273 |   "CST" { z=-6; }\r
274 |   "CDT" { z=-5; }\r
275 |   "MST" { z=-7; }\r
276 |   "MDT" { z=-6; }\r
277 |   "PST" { z=-8; }\r
278 |   "PDT" { z=-7; }\r
279 |   t=< MILITARY_ZONE: ["A"-"I","a"-"i","K"-"Z","k"-"z"] > { z=getMilitaryZoneOffset(t.image.charAt(0)); }\r
281     { return z * 100; }\r
284 SPECIAL_TOKEN :\r
286         < WS: ( [" ", "\t"] )+ >\r
289 TOKEN_MGR_DECLS :\r
291         // Keeps track of how many levels of comment nesting\r
292         // we've encountered.  This is only used when the 2nd\r
293         // level is reached, for example ((this)), not (this).\r
294         // This is because the outermost level must be treated\r
295         // specially anyway, because the outermost ")" has a\r
296         // different token type than inner ")" instances.\r
297         static int commentNest;\r
300 MORE :\r
302         // starts a comment\r
303         "(" : INCOMMENT\r
306 <INCOMMENT>\r
307 SKIP :\r
309         // ends a comment\r
310         < COMMENT: ")" > : DEFAULT\r
311         // if this is ever changed to not be a SKIP, need\r
312         // to make sure matchedToken.token = token.toString()\r
313         // is called.\r
316 <INCOMMENT>\r
317 MORE :\r
319         < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }\r
320 |       "(" { commentNest = 1; } : NESTED_COMMENT\r
321 |       < <ANY>>\r
324 <NESTED_COMMENT>\r
325 MORE :\r
327         < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }\r
328 |       "(" { ++commentNest; }\r
329 |       ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }\r
330 |       < <ANY>>\r
333 TOKEN :\r
335     < DIGITS: ( ["0"-"9"] )+ >\r
338 // GLOBALS\r
340 <*>\r
341 TOKEN :\r
343         < #QUOTEDPAIR: "\\" <ANY> >\r
344 |       < #ANY: ~[] >\r