1 /* Parser for Gedcom dates.
2 Copyright (C) 2001 The Genes Development Team
3 This file is part of the Gedcom parser library.
4 Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
6 The Gedcom parser library is free software; you can redistribute it
7 and/or modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The Gedcom parser library is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the Gedcom parser library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 int _get_day_num(const char* input);
30 int _get_year_num(Year_type ytype, const char* input1, const char* input2);
36 struct date_value date_val;
40 %token <string> ESC_DATE_GREG
41 %token <string> ESC_DATE_JULN
42 %token <string> ESC_DATE_HEBR
43 %token <string> ESC_DATE_FREN
44 %token <string> MOD_FROM
45 %token <string> MOD_TO
46 %token <string> MOD_BEF
47 %token <string> MOD_AFT
48 %token <string> MOD_BET
49 %token <string> MOD_AND
50 %token <string> MOD_ABT
51 %token <string> MOD_CAL
52 %token <string> MOD_EST
53 %token <string> MOD_INT
54 %token <string> MON_JAN
55 %token <string> MON_FEB
56 %token <string> MON_MAR
57 %token <string> MON_APR
58 %token <string> MON_MAY
59 %token <string> MON_JUN
60 %token <string> MON_JUL
61 %token <string> MON_AUG
62 %token <string> MON_SEP
63 %token <string> MON_OCT
64 %token <string> MON_NOV
65 %token <string> MON_DEC
66 %token <string> MON_TSH
67 %token <string> MON_CSH
68 %token <string> MON_KSL
69 %token <string> MON_TVT
70 %token <string> MON_SHV
71 %token <string> MON_ADR
72 %token <string> MON_ADS
73 %token <string> MON_NSN
74 %token <string> MON_IYR
75 %token <string> MON_SVN
76 %token <string> MON_TMZ
77 %token <string> MON_AAV
78 %token <string> MON_ELL
79 %token <string> MON_VEND
80 %token <string> MON_BRUM
81 %token <string> MON_FRIM
82 %token <string> MON_NIVO
83 %token <string> MON_PLUV
84 %token <string> MON_VENT
85 %token <string> MON_GERM
86 %token <string> MON_FLOR
87 %token <string> MON_PRAI
88 %token <string> MON_MESS
89 %token <string> MON_THER
90 %token <string> MON_FRUC
91 %token <string> MON_COMP
95 %token <string> NUMBER
97 %token <string> BADTOKEN
99 %type <date_val> date_value
100 %type <date_val> date_period
101 %type <date_val> date_range
102 %type <date_val> date_approx
103 %type <date_val> date_interpr
104 %type <string> date_phrase
109 date_value : date { make_date_value(DV_NO_MODIFIER,
110 &$1, &def_date, ""); }
115 | date_phrase { make_date_value(DV_PHRASE,
116 &def_date, &def_date, $1); }
119 /* If empty string: return empty string in 'phrase'
120 member as fallback */
121 /* Note: this can only happen in compatibility mode */
122 make_date_value(DV_PHRASE,
123 &def_date, &def_date, curr_line_value);
125 | error { /* On error: put entire string in 'phrase' member
127 make_date_value(DV_PHRASE,
128 &def_date, &def_date, curr_line_value);
132 date : ESC_DATE_GREG date_greg { copy_date(&$$, &date_s);
133 $$.cal = CAL_GREGORIAN; }
134 | ESC_DATE_JULN date_juln { copy_date(&$$, &date_s);
135 $$.cal = CAL_JULIAN; }
136 | ESC_DATE_HEBR date_hebr { copy_date(&$$, &date_s);
137 $$.cal = CAL_HEBREW; }
138 | ESC_DATE_FREN date_fren { copy_date(&$$, &date_s);
139 $$.cal = CAL_FRENCH_REV; }
140 | date_greg { copy_date(&$$, &date_s);
141 $$.cal = CAL_GREGORIAN; }
144 date_period : MOD_FROM date { make_date_value(DV_FROM,
145 &$2, &def_date, ""); }
146 | MOD_TO date { make_date_value(DV_TO,
147 &$2, &def_date, ""); }
148 | MOD_FROM date { copy_date(&$<date>$, &$2); }
150 { make_date_value(DV_FROM_TO, &$<date>3, &$5, ""); }
153 date_range : MOD_BEF date { make_date_value(DV_BEFORE,
154 &$2, &def_date, ""); }
155 | MOD_AFT date { make_date_value(DV_AFTER,
156 &$2, &def_date, ""); }
157 | MOD_BET date { copy_date(&$<date>$, &$2); }
159 { make_date_value(DV_BETWEEN, &$<date>3, &$5, ""); }
162 date_approx : MOD_ABT date { make_date_value(DV_ABOUT,
163 &$2, &def_date, ""); }
164 | MOD_CAL date { make_date_value(DV_CALCULATED,
165 &$2, &def_date, ""); }
166 | MOD_EST date { make_date_value(DV_ESTIMATED,
167 &$2, &def_date, ""); }
170 date_interpr : MOD_INT date date_phrase
171 { make_date_value(DV_INTERPRETED, &$2, &def_date, $3); }
174 date_phrase : OPEN TEXT CLOSE { $$ = $2; }
177 date_greg : day month_greg year_greg
178 | month_greg year_greg
182 date_juln : day month_greg year
187 date_hebr : day month_hebr year
192 date_fren : day month_fren year
199 int d = _get_day_num($1);
201 strcpy(date_s.day_str, $1);
207 month_greg : MON_JAN { strcpy(date_s.month_str, $1);
209 | MON_FEB { strcpy(date_s.month_str, $1);
211 | MON_MAR { strcpy(date_s.month_str, $1);
213 | MON_APR { strcpy(date_s.month_str, $1);
215 | MON_MAY { strcpy(date_s.month_str, $1);
217 | MON_JUN { strcpy(date_s.month_str, $1);
219 | MON_JUL { strcpy(date_s.month_str, $1);
221 | MON_AUG { strcpy(date_s.month_str, $1);
223 | MON_SEP { strcpy(date_s.month_str, $1);
225 | MON_OCT { strcpy(date_s.month_str, $1);
227 | MON_NOV { strcpy(date_s.month_str, $1);
229 | MON_DEC { strcpy(date_s.month_str, $1);
233 month_hebr : MON_TSH { strcpy(date_s.month_str, $1);
235 | MON_CSH { strcpy(date_s.month_str, $1);
237 | MON_KSL { strcpy(date_s.month_str, $1);
239 | MON_TVT { strcpy(date_s.month_str, $1);
241 | MON_SHV { strcpy(date_s.month_str, $1);
243 | MON_ADR { strcpy(date_s.month_str, $1);
245 | MON_ADS { strcpy(date_s.month_str, $1);
247 | MON_NSN { strcpy(date_s.month_str, $1);
249 | MON_IYR { strcpy(date_s.month_str, $1);
251 | MON_SVN { strcpy(date_s.month_str, $1);
253 | MON_TMZ { strcpy(date_s.month_str, $1);
255 | MON_AAV { strcpy(date_s.month_str, $1);
257 | MON_ELL { strcpy(date_s.month_str, $1);
261 month_fren : MON_VEND { strcpy(date_s.month_str, $1);
263 | MON_BRUM { strcpy(date_s.month_str, $1);
265 | MON_FRIM { strcpy(date_s.month_str, $1);
267 | MON_NIVO { strcpy(date_s.month_str, $1);
269 | MON_PLUV { strcpy(date_s.month_str, $1);
271 | MON_VENT { strcpy(date_s.month_str, $1);
273 | MON_GERM { strcpy(date_s.month_str, $1);
275 | MON_FLOR { strcpy(date_s.month_str, $1);
277 | MON_PRAI { strcpy(date_s.month_str, $1);
279 | MON_MESS { strcpy(date_s.month_str, $1);
281 | MON_THER { strcpy(date_s.month_str, $1);
283 | MON_FRUC { strcpy(date_s.month_str, $1);
285 | MON_COMP { strcpy(date_s.month_str, $1);
290 { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
292 strcpy(date_s.year_str, $1);
294 date_s.year_type = YEAR_SINGLE;
300 { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
302 strcpy(date_s.year_str, $1);
304 date_s.year_type = YEAR_SINGLE;
307 | NUMBER SLASH NUMBER
308 { int y = _get_year_num(YEAR_DOUBLE, $1, $3);
310 sprintf(date_s.year_str, "%d/%d", y-1, y%100);
312 date_s.year_type = YEAR_DOUBLE;
319 int _get_day_num(const char* input)
321 if (strlen(input) <= MAX_DAY_LEN)
324 gedcom_date_error(_("Too many characters in day '%s'"), input);
329 int get_day_num(const char* input)
331 int token = get_date_token(input);
333 return _get_day_num(input);
335 gedcom_date_error(_("Not a valid day number: '%s'"), input);
341 { /* CAL_GREGORIAN */ MON_JAN,
342 /* CAL_JULIAN */ MON_JAN,
343 /* CAL_HEBREW */ MON_TSH,
344 /* CAL_FRENCH_REV */ MON_VEND
348 { /* CAL_GREGORIAN */ MON_DEC,
349 /* CAL_JULIAN */ MON_DEC,
350 /* CAL_HEBREW */ MON_ELL,
351 /* CAL_FRENCH_REV */ MON_COMP
354 int get_month_num(Calendar_type cal, const char* input)
356 int token = get_date_token(input);
357 if (token >= begin_month[cal] && token <= end_month[cal])
358 return token - begin_month[cal] + 1;
360 gedcom_date_error(_("Not a valid month for the given calendar: '%s'"),
366 int _get_year_num(Year_type ytype, const char* input1, const char* input2)
368 if (ytype == YEAR_SINGLE) {
369 if (strlen(input1) <= MAX_YEAR_LEN) {
373 gedcom_date_error(_("Too many characters in year '%s'"), input1);
378 if (strlen(input2) != 2) {
379 if (compat_mode(C_DOUBLE_DATES_4) && strlen(input2) == 4) {
383 gedcom_date_error(_("Year after slash should be two digits: '%s/%s'"),
388 if (strlen(input1) <= MAX_YEAR_LEN - 3) {
389 int year1 = atoi(input1) + 1;
390 int year2 = atoi(input2);
391 if (year1 % 100 != year2) {
392 gedcom_date_error(_("Year after slash should be following year: '%s/%s'"),
400 gedcom_date_error(_("Too many characters in year '%s/%s'"),
407 int get_year_num(const char* input, Year_type* ytype)
409 char *year1, *year2 = NULL;
410 int numtok = get_year_tokens(input, &year1, &year2);
412 *ytype = (numtok == 1 ? YEAR_SINGLE : YEAR_DOUBLE);
413 return _get_year_num (*ytype, year1, year2);
416 gedcom_date_error(_("Not a valid year: '%s'"), input);