Use safe buffer mechanism for storing gedcom value (to avoid fixed
[gedcom-parse.git] / gedcom / gedcom_date.y
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.
5
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.
10
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.
15
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
19    02111-1307 USA.  */
20
21 /* $Id$ */
22 /* $Name$ */
23
24 %{
25 #include <stdlib.h>
26 #include "date.h"
27 %}
28
29 %union {
30   char *string;
31   struct date_value date_val;
32   struct date date;
33 }
34
35 %token <string> ESC_DATE_GREG
36 %token <string> ESC_DATE_JULN
37 %token <string> ESC_DATE_HEBR
38 %token <string> ESC_DATE_FREN
39 %token <string> MOD_FROM
40 %token <string> MOD_TO
41 %token <string> MOD_BEF
42 %token <string> MOD_AFT
43 %token <string> MOD_BET
44 %token <string> MOD_AND
45 %token <string> MOD_ABT
46 %token <string> MOD_CAL
47 %token <string> MOD_EST
48 %token <string> MOD_INT
49 %token <string> MON_JAN
50 %token <string> MON_FEB
51 %token <string> MON_MAR
52 %token <string> MON_APR
53 %token <string> MON_MAY
54 %token <string> MON_JUN
55 %token <string> MON_JUL
56 %token <string> MON_AUG
57 %token <string> MON_SEP
58 %token <string> MON_OCT
59 %token <string> MON_NOV
60 %token <string> MON_DEC
61 %token <string> MON_TSH
62 %token <string> MON_CSH
63 %token <string> MON_KSL
64 %token <string> MON_TVT
65 %token <string> MON_SHV
66 %token <string> MON_ADR
67 %token <string> MON_ADS
68 %token <string> MON_NSN
69 %token <string> MON_IYR
70 %token <string> MON_SVN
71 %token <string> MON_TMZ
72 %token <string> MON_AAV
73 %token <string> MON_ELL
74 %token <string> MON_VEND
75 %token <string> MON_BRUM
76 %token <string> MON_FRIM
77 %token <string> MON_NIVO
78 %token <string> MON_PLUV
79 %token <string> MON_VENT
80 %token <string> MON_GERM
81 %token <string> MON_FLOR
82 %token <string> MON_PRAI
83 %token <string> MON_MESS
84 %token <string> MON_THER
85 %token <string> MON_FRUC
86 %token <string> MON_COMP
87 %token <string> OPEN
88 %token <string> CLOSE
89 %token <string> TEXT
90 %token <string> NUMBER
91 %token <string> SLASH
92 %token <string> BADTOKEN
93
94 %type <date_val> date_value
95 %type <date_val> date_period
96 %type <date_val> date_range
97 %type <date_val> date_approx
98 %type <date_val> date_interpr
99 %type <string> date_phrase
100 %type <date> date
101
102 %%
103
104 date_value   : date           { make_date_value(DV_NO_MODIFIER,
105                                                 $1, def_date, ""); }
106              | date_period    
107              | date_range
108              | date_approx
109              | date_interpr
110              | date_phrase    { make_date_value(DV_PHRASE,
111                                                 def_date, def_date, $1); }
112              | /* empty */
113                {
114                  /* If empty string: return empty string in 'phrase'
115                     member as fallback */
116                  /* Note: this can only happen in compatibility mode */
117                  make_date_value(DV_PHRASE,
118                                  def_date, def_date, curr_line_value);
119                }
120              | error { /* On error: put entire string in 'phrase' member
121                           as fallback */
122                        make_date_value(DV_PHRASE,
123                                        def_date, def_date, curr_line_value);
124                      }
125              ;
126
127 date         : ESC_DATE_GREG date_greg { copy_date(&$$, date_s);
128                                          $$.cal = CAL_GREGORIAN; }
129              | ESC_DATE_JULN date_juln { copy_date(&$$, date_s);
130                                          $$.cal = CAL_JULIAN;  }
131              | ESC_DATE_HEBR date_hebr { copy_date(&$$, date_s);
132                                          $$.cal = CAL_HEBREW;  }
133              | ESC_DATE_FREN date_fren { copy_date(&$$, date_s);
134                                          $$.cal = CAL_FRENCH_REV;  }
135              | date_greg               { copy_date(&$$, date_s);
136                                          $$.cal = CAL_GREGORIAN;  }
137              ;
138
139 date_period  : MOD_FROM date   { make_date_value(DV_FROM,
140                                                  $2, def_date, ""); }
141              | MOD_TO date     { make_date_value(DV_TO,
142                                                  $2, def_date, ""); }
143              | MOD_FROM date   { copy_date(&$<date>$, $2); }
144                MOD_TO date
145                       { make_date_value(DV_FROM_TO, $<date>3, $5, ""); }
146              ;
147
148 date_range   : MOD_BEF date    { make_date_value(DV_BEFORE,
149                                                  $2, def_date, ""); }
150              | MOD_AFT date    { make_date_value(DV_AFTER,
151                                                  $2, def_date, ""); }
152              | MOD_BET date    { copy_date(&$<date>$, $2); }
153                MOD_AND date
154                       { make_date_value(DV_BETWEEN, $<date>3, $5, ""); }
155              ;
156
157 date_approx  : MOD_ABT date    { make_date_value(DV_ABOUT,
158                                                  $2, def_date, ""); }
159              | MOD_CAL date    { make_date_value(DV_CALCULATED,
160                                                  $2, def_date, ""); }
161              | MOD_EST date    { make_date_value(DV_ESTIMATED,
162                                                  $2, def_date, ""); }
163              ;
164
165 date_interpr : MOD_INT date date_phrase
166                  { make_date_value(DV_INTERPRETED, $2, def_date, $3); }
167              ;
168
169 date_phrase  : OPEN TEXT CLOSE { $$ = $2; }
170              ;
171
172 date_greg    : day month_greg year_greg
173              | month_greg year_greg
174              | year_greg
175              ;
176
177 date_juln    : day month_greg year
178              | month_greg year
179              | year
180              ;
181
182 date_hebr    : day month_hebr year
183              | month_hebr year
184              | year
185              ;
186
187 date_fren    : day month_fren year
188              | month_fren year
189              | year
190              ;
191
192 day          : NUMBER
193                {
194                  if (strlen($1) <= MAX_DAY_LEN) {
195                    strcpy(date_s.day_str, $1);
196                    date_s.day = atoi($1);
197                  }
198                  else {
199                    gedcom_date_error(_("Too many characters in day '%s'"),
200                                      $1); 
201                  }
202                }
203              ;
204
205 month_greg   : MON_JAN { strcpy(date_s.month_str, $1);
206                          date_s.month = 1; }
207              | MON_FEB { strcpy(date_s.month_str, $1);
208                          date_s.month = 2; }
209              | MON_MAR { strcpy(date_s.month_str, $1);
210                          date_s.month = 3; }
211              | MON_APR { strcpy(date_s.month_str, $1);
212                          date_s.month = 4; }
213              | MON_MAY { strcpy(date_s.month_str, $1);
214                          date_s.month = 5; }
215              | MON_JUN { strcpy(date_s.month_str, $1);
216                          date_s.month = 6; }
217              | MON_JUL { strcpy(date_s.month_str, $1);
218                          date_s.month = 7; }
219              | MON_AUG { strcpy(date_s.month_str, $1);
220                          date_s.month = 8; }
221              | MON_SEP { strcpy(date_s.month_str, $1);
222                          date_s.month = 9; }
223              | MON_OCT { strcpy(date_s.month_str, $1);
224                          date_s.month = 10; }
225              | MON_NOV { strcpy(date_s.month_str, $1);
226                          date_s.month = 11; }
227              | MON_DEC { strcpy(date_s.month_str, $1);
228                          date_s.month = 12; }
229              ;
230
231 month_hebr   : MON_TSH { strcpy(date_s.month_str, $1);
232                          date_s.month = 1; }
233              | MON_CSH { strcpy(date_s.month_str, $1);
234                          date_s.month = 2; }
235              | MON_KSL { strcpy(date_s.month_str, $1);
236                          date_s.month = 3; }
237              | MON_TVT { strcpy(date_s.month_str, $1);
238                          date_s.month = 4; }
239              | MON_SHV { strcpy(date_s.month_str, $1);
240                          date_s.month = 5; }
241              | MON_ADR { strcpy(date_s.month_str, $1);
242                          date_s.month = 6; }
243              | MON_ADS { strcpy(date_s.month_str, $1);
244                          date_s.month = 7; }
245              | MON_NSN { strcpy(date_s.month_str, $1);
246                          date_s.month = 8; }
247              | MON_IYR { strcpy(date_s.month_str, $1);
248                          date_s.month = 9; }
249              | MON_SVN { strcpy(date_s.month_str, $1);
250                          date_s.month = 10; }
251              | MON_TMZ { strcpy(date_s.month_str, $1);
252                          date_s.month = 11; }
253              | MON_AAV { strcpy(date_s.month_str, $1);
254                          date_s.month = 12; }
255              | MON_ELL { strcpy(date_s.month_str, $1);
256                          date_s.month = 13; }
257              ;
258
259 month_fren   : MON_VEND { strcpy(date_s.month_str, $1);
260                          date_s.month = 1; }
261              | MON_BRUM { strcpy(date_s.month_str, $1);
262                          date_s.month = 2; }
263              | MON_FRIM { strcpy(date_s.month_str, $1);
264                          date_s.month = 3; }
265              | MON_NIVO { strcpy(date_s.month_str, $1);
266                          date_s.month = 4; }
267              | MON_PLUV { strcpy(date_s.month_str, $1);
268                          date_s.month = 5; }
269              | MON_VENT { strcpy(date_s.month_str, $1);
270                          date_s.month = 6; }
271              | MON_GERM { strcpy(date_s.month_str, $1);
272                          date_s.month = 7; }
273              | MON_FLOR { strcpy(date_s.month_str, $1);
274                          date_s.month = 8; }
275              | MON_PRAI { strcpy(date_s.month_str, $1);
276                          date_s.month = 9; }
277              | MON_MESS { strcpy(date_s.month_str, $1);
278                          date_s.month = 10; }
279              | MON_THER { strcpy(date_s.month_str, $1);
280                          date_s.month = 11; }
281              | MON_FRUC { strcpy(date_s.month_str, $1);
282                          date_s.month = 12; }
283              | MON_COMP { strcpy(date_s.month_str, $1);
284                          date_s.month = 13; }
285              ;
286
287 year         : NUMBER
288                  { if (strlen($1) <= MAX_YEAR_LEN) {
289                      strcpy(date_s.year_str, $1);
290                      date_s.year = atoi($1);
291                      date_s.year_type = YEAR_SINGLE;
292                    }
293                    else {
294                      gedcom_date_error(_("Too many characters in year '%s'"),
295                                      $1); 
296                    }
297                  }
298              ;
299
300 year_greg    : NUMBER
301                  { if (strlen($1) <= MAX_YEAR_LEN) {
302                      strcpy(date_s.year_str, $1);
303                      date_s.year = atoi($1);
304                      date_s.year_type = YEAR_SINGLE;
305                    }
306                    else {
307                      gedcom_date_error(_("Too many characters in year '%s'"),
308                                      $1); 
309                    }
310                  }
311              | NUMBER SLASH NUMBER
312                  { if (strlen($1) + strlen($3) + 1 <= MAX_YEAR_LEN) {
313                      sprintf(date_s.year_str, "%s/%s", $1, $3);
314                      date_s.year = atoi($1) + 1;
315                      date_s.year_type = YEAR_DOUBLE;
316                    }
317                    else {
318                      gedcom_date_error(_("Too many characters in year '%s/%s'"),
319                                      $1, $3); 
320                    }
321                  
322                  }
323              ;
324
325 %%