/* Parser for Gedcom dates. Copyright (C) 2001 The Genes Development Team This file is part of the Gedcom parser library. Contributed by Peter Verthez , 2001. The Gedcom parser library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The Gedcom parser library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the Gedcom parser library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* $Id$ */ /* $Name$ */ %{ #include #include "date.h" #include "compat.h" int _get_day_num(const char* input); int _get_year_num(Year_type ytype, const char* input1, const char* input2); void error_missing_year(); void error_missing_month(); %} %union { char *string; struct date_value date_val; struct date date; } %token ESC_DATE_GREG %token ESC_DATE_JULN %token ESC_DATE_HEBR %token ESC_DATE_FREN %token MOD_FROM %token MOD_TO %token MOD_BEF %token MOD_AFT %token MOD_BET %token MOD_AND %token MOD_ABT %token MOD_CAL %token MOD_EST %token MOD_INT %token MON_JAN %token MON_FEB %token MON_MAR %token MON_APR %token MON_MAY %token MON_JUN %token MON_JUL %token MON_AUG %token MON_SEP %token MON_OCT %token MON_NOV %token MON_DEC %token MON_TSH %token MON_CSH %token MON_KSL %token MON_TVT %token MON_SHV %token MON_ADR %token MON_ADS %token MON_NSN %token MON_IYR %token MON_SVN %token MON_TMZ %token MON_AAV %token MON_ELL %token MON_VEND %token MON_BRUM %token MON_FRIM %token MON_NIVO %token MON_PLUV %token MON_VENT %token MON_GERM %token MON_FLOR %token MON_PRAI %token MON_MESS %token MON_THER %token MON_FRUC %token MON_COMP %token OPEN %token CLOSE %token TEXT %token NUMBER %token SLASH %token BADTOKEN %type date_value %type date_period %type date_range %type date_approx %type date_interpr %type date_phrase %type date %% date_value : date { make_date_value(DV_NO_MODIFIER, &$1, &def_date, ""); } | date_period | date_range | date_approx | date_interpr | date_phrase { make_date_value(DV_PHRASE, &def_date, &def_date, $1); } | /* empty */ { /* If empty string: return empty string in 'phrase' member as fallback */ /* Note: this can only happen in compatibility mode */ make_date_value(DV_PHRASE, &def_date, &def_date, curr_line_value); } | error { /* On error: put entire string in 'phrase' member as fallback */ gedcom_date_error(_("Putting date '%s' in 'phrase' member"), curr_line_value); make_date_value(DV_PHRASE, &def_date, &def_date, curr_line_value); YYABORT; } ; date : ESC_DATE_GREG date_greg { copy_date(&$$, &date_s); $$.cal = CAL_GREGORIAN; } | ESC_DATE_JULN date_juln { copy_date(&$$, &date_s); $$.cal = CAL_JULIAN; } | ESC_DATE_HEBR date_hebr { copy_date(&$$, &date_s); $$.cal = CAL_HEBREW; } | ESC_DATE_FREN date_fren { copy_date(&$$, &date_s); $$.cal = CAL_FRENCH_REV; } | date_greg { copy_date(&$$, &date_s); $$.cal = CAL_GREGORIAN; } ; date_period : MOD_FROM date { make_date_value(DV_FROM, &$2, &def_date, ""); } | MOD_TO date { make_date_value(DV_TO, &$2, &def_date, ""); } | MOD_FROM date { copy_date(&$$, &$2); } MOD_TO date { make_date_value(DV_FROM_TO, &$3, &$5, ""); } ; date_range : MOD_BEF date { make_date_value(DV_BEFORE, &$2, &def_date, ""); } | MOD_AFT date { make_date_value(DV_AFTER, &$2, &def_date, ""); } | MOD_BET date { copy_date(&$$, &$2); } MOD_AND date { make_date_value(DV_BETWEEN, &$3, &$5, ""); } ; date_approx : MOD_ABT date { make_date_value(DV_ABOUT, &$2, &def_date, ""); } | MOD_CAL date { make_date_value(DV_CALCULATED, &$2, &def_date, ""); } | MOD_EST date { make_date_value(DV_ESTIMATED, &$2, &def_date, ""); } ; date_interpr : MOD_INT date date_phrase { make_date_value(DV_INTERPRETED, &$2, &def_date, $3); } ; date_phrase : OPEN TEXT CLOSE { $$ = $2; } ; date_greg : day month_greg year_greg | month_greg year_greg | year_greg | day month_greg { error_missing_year(); YYERROR; } | month_greg { error_missing_year(); YYERROR; } | day year_greg { error_missing_month(); YYERROR; } ; date_juln : day month_greg year | month_greg year | year | day month_greg { error_missing_year(); YYERROR; } | month_greg { error_missing_year(); YYERROR; } | day year_greg { error_missing_month(); YYERROR; } ; date_hebr : day month_hebr year | month_hebr year | year | day month_hebr { error_missing_year(); YYERROR; } | month_hebr { error_missing_year(); YYERROR; } | day year { error_missing_month(); YYERROR; } ; date_fren : day month_fren year | month_fren year | year | day month_hebr { error_missing_year(); YYERROR; } | month_hebr { error_missing_year(); YYERROR; } | day year { error_missing_month(); YYERROR; } ; day : NUMBER { int d = _get_day_num($1); if (d != -1) { strcpy(date_s.day_str, $1); date_s.day = d; } else YYERROR; } ; month_greg : MON_JAN { strcpy(date_s.month_str, $1); date_s.month = 1; } | MON_FEB { strcpy(date_s.month_str, $1); date_s.month = 2; } | MON_MAR { strcpy(date_s.month_str, $1); date_s.month = 3; } | MON_APR { strcpy(date_s.month_str, $1); date_s.month = 4; } | MON_MAY { strcpy(date_s.month_str, $1); date_s.month = 5; } | MON_JUN { strcpy(date_s.month_str, $1); date_s.month = 6; } | MON_JUL { strcpy(date_s.month_str, $1); date_s.month = 7; } | MON_AUG { strcpy(date_s.month_str, $1); date_s.month = 8; } | MON_SEP { strcpy(date_s.month_str, $1); date_s.month = 9; } | MON_OCT { strcpy(date_s.month_str, $1); date_s.month = 10; } | MON_NOV { strcpy(date_s.month_str, $1); date_s.month = 11; } | MON_DEC { strcpy(date_s.month_str, $1); date_s.month = 12; } ; month_hebr : MON_TSH { strcpy(date_s.month_str, $1); date_s.month = 1; } | MON_CSH { strcpy(date_s.month_str, $1); date_s.month = 2; } | MON_KSL { strcpy(date_s.month_str, $1); date_s.month = 3; } | MON_TVT { strcpy(date_s.month_str, $1); date_s.month = 4; } | MON_SHV { strcpy(date_s.month_str, $1); date_s.month = 5; } | MON_ADR { strcpy(date_s.month_str, $1); date_s.month = 6; } | MON_ADS { strcpy(date_s.month_str, $1); date_s.month = 7; } | MON_NSN { strcpy(date_s.month_str, $1); date_s.month = 8; } | MON_IYR { strcpy(date_s.month_str, $1); date_s.month = 9; } | MON_SVN { strcpy(date_s.month_str, $1); date_s.month = 10; } | MON_TMZ { strcpy(date_s.month_str, $1); date_s.month = 11; } | MON_AAV { strcpy(date_s.month_str, $1); date_s.month = 12; } | MON_ELL { strcpy(date_s.month_str, $1); date_s.month = 13; } ; month_fren : MON_VEND { strcpy(date_s.month_str, $1); date_s.month = 1; } | MON_BRUM { strcpy(date_s.month_str, $1); date_s.month = 2; } | MON_FRIM { strcpy(date_s.month_str, $1); date_s.month = 3; } | MON_NIVO { strcpy(date_s.month_str, $1); date_s.month = 4; } | MON_PLUV { strcpy(date_s.month_str, $1); date_s.month = 5; } | MON_VENT { strcpy(date_s.month_str, $1); date_s.month = 6; } | MON_GERM { strcpy(date_s.month_str, $1); date_s.month = 7; } | MON_FLOR { strcpy(date_s.month_str, $1); date_s.month = 8; } | MON_PRAI { strcpy(date_s.month_str, $1); date_s.month = 9; } | MON_MESS { strcpy(date_s.month_str, $1); date_s.month = 10; } | MON_THER { strcpy(date_s.month_str, $1); date_s.month = 11; } | MON_FRUC { strcpy(date_s.month_str, $1); date_s.month = 12; } | MON_COMP { strcpy(date_s.month_str, $1); date_s.month = 13; } ; year : NUMBER { int y = _get_year_num(YEAR_SINGLE, $1, NULL); if (y != -1) { strcpy(date_s.year_str, $1); date_s.year = y; date_s.year_type = YEAR_SINGLE; } else YYERROR; } ; year_greg : NUMBER { int y = _get_year_num(YEAR_SINGLE, $1, NULL); if (y != -1) { strcpy(date_s.year_str, $1); date_s.year = y; date_s.year_type = YEAR_SINGLE; } else YYERROR; } | NUMBER SLASH NUMBER { if (compat_double_date_check($3)) { safe_buf_append(&compat_buffer, "BET %s AND %s", $1, $3); } else { int y = _get_year_num(YEAR_DOUBLE, $1, $3); if (y != -1) { sprintf(date_s.year_str, "%d/%02d", y-1, y%100); date_s.year = y; date_s.year_type = YEAR_DOUBLE; } else YYERROR; } } ; %% void error_missing_year() { gedcom_date_error(_("Year is missing: '%s'"), curr_line_value); } void error_missing_month() { gedcom_date_error(_("Month is missing: '%s'"), curr_line_value); } int _get_day_num(const char* input) { if (strlen(input) <= MAX_DAY_LEN) return atoi(input); else { gedcom_date_error(_("Too many characters in day '%s'"), input); return -1; } } int get_day_num(const char* input) { int token = get_date_token(input); if (token == NUMBER) return _get_day_num(input); else { gedcom_date_error(_("Not a valid day number: '%s'"), input); return -1; } } int begin_month[] = { /* CAL_GREGORIAN */ MON_JAN, /* CAL_JULIAN */ MON_JAN, /* CAL_HEBREW */ MON_TSH, /* CAL_FRENCH_REV */ MON_VEND }; int end_month[] = { /* CAL_GREGORIAN */ MON_DEC, /* CAL_JULIAN */ MON_DEC, /* CAL_HEBREW */ MON_ELL, /* CAL_FRENCH_REV */ MON_COMP }; int get_month_num(Calendar_type cal, const char* input) { int token = get_date_token(input); if (token >= begin_month[cal] && token <= end_month[cal]) return token - begin_month[cal] + 1; else { gedcom_date_error(_("Not a valid month for the given calendar: '%s'"), input); return -1; } } int _get_year_num(Year_type ytype, const char* input1, const char* input2) { if (ytype == YEAR_SINGLE) { if (strlen(input1) <= MAX_YEAR_LEN) { return atoi(input1); } else { gedcom_date_error(_("Too many characters in year '%s'"), input1); return -1; } } else { if (strlen(input2) != 2) { gedcom_date_error(_("Year after slash should be two digits: '%s/%s'"), input1, input2); return -1; } if (strlen(input1) <= MAX_YEAR_LEN - 3) { int year1 = atoi(input1) + 1; int year2 = atoi(input2); if (year1 % 100 != year2) { gedcom_date_error(_("Year after slash should be following year: '%s/%s'"), input1, input2); return -1; } else return year1; } else { gedcom_date_error(_("Too many characters in year '%s/%s'"), input1, input2); return -1; } } } int get_year_num(const char* input, Year_type* ytype) { char *year1, *year2 = NULL; int numtok = get_year_tokens(input, &year1, &year2); if (numtok) { *ytype = (numtok == 1 ? YEAR_SINGLE : YEAR_DOUBLE); return _get_year_num (*ytype, year1, year2); } else { gedcom_date_error(_("Not a valid year: '%s'"), input); return -1; } }