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
10 * http://www.apache.org/licenses/LICENSE-2.0 *
\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
22 * RFC2822 date parser.
\r
25 * by Joe Cheng <code@joecheng.com>
\r
31 OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";
\r
32 //DEBUG_PARSER=true;
\r
33 //DEBUG_TOKEN_MANAGER=true;
\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
46 * http://www.apache.org/licenses/LICENSE-2.0 *
\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
67 DateTimeParser parser = new DateTimeParser(System.in);
\r
69 } catch (Exception x) {
\r
70 x.printStackTrace();
\r
76 private static int parseDigits(Token token) {
\r
77 return Integer.parseInt(token.image, 10);
\r
80 private static int getMilitaryZoneOffset(char c) {
\r
81 if (ignoreMilitaryZoneOffset)
\r
84 c = Character.toUpperCase(c);
\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
118 private static class Time {
\r
120 private int minute;
\r
121 private int second;
\r
124 public Time(int hour, int minute, int second, int zone) {
\r
126 this.minute = minute;
\r
127 this.second = second;
\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
137 private static class Date {
\r
138 private String year;
\r
142 public Date(String year, int month, int day) {
\r
144 this.month = month;
\r
148 public String getYear() { return year; }
\r
149 public int getMonth() { return month; }
\r
150 public int getDay() { return day; }
\r
154 PARSER_END(DateTimeParser)
\r
156 DateTime parseLine() :
\r
159 dt=date_time() ["\r"] "\n"
\r
163 DateTime parseAll() :
\r
166 dt=date_time() <EOF>
\r
170 DateTime date_time() :
\r
173 [ day_of_week() "," ]
\r
177 return new DateTime(
\r
184 t.getZone()); // time zone offset
\r
188 String day_of_week() :
\r
191 ( "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
\r
193 { return token.image; }
\r
197 {int d, m; String y;}
\r
199 d=day() m=month() y=year()
\r
200 { return new Date(y, m, d); }
\r
206 t=<DIGITS> { return parseDigits(t); }
\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
229 t=<DIGITS> { return t.image; }
\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
242 t=<DIGITS> { return parseDigits(t); }
\r
248 t=<DIGITS> { return parseDigits(t); }
\r
254 t=<DIGITS> { return parseDigits(t); }
\r
258 { Token t, u; int z; }
\r
260 ( t=< OFFSETDIR: ["+", "-"] > u=<DIGITS> { z=parseDigits(u)*(t.image.equals("-") ? -1 : 1); }
\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
286 < WS: ( [" ", "\t"] )+ >
\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
302 // starts 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
319 < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
\r
320 | "(" { commentNest = 1; } : NESTED_COMMENT
\r
327 < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
\r
328 | "(" { ++commentNest; }
\r
329 | ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }
\r
335 < DIGITS: ( ["0"-"9"] )+ >
\r
343 < #QUOTEDPAIR: "\\" <ANY> >
\r