%{
#include <stdlib.h>
#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 {
%%
date_value : date { make_date_value(DV_NO_MODIFIER,
- $1, def_date, ""); }
+ &$1, &def_date, ""); }
| date_period
| date_range
| date_approx
| date_interpr
| date_phrase { make_date_value(DV_PHRASE,
- def_date, def_date, $1); }
+ &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);
+ &def_date, &def_date, curr_line_value);
}
| error { /* On error: put entire string in 'phrase' member
as fallback */
+ gedcom_date_error(_("Putting date in 'phrase' member"));
make_date_value(DV_PHRASE,
- def_date, def_date, curr_line_value);
+ &def_date, &def_date, curr_line_value);
+ YYABORT;
}
;
-date : ESC_DATE_GREG date_greg { copy_date(&$$, date_s);
+date : ESC_DATE_GREG date_greg { copy_date(&$$, &date_s);
$$.cal = CAL_GREGORIAN; }
- | ESC_DATE_JULN date_juln { copy_date(&$$, date_s);
+ | ESC_DATE_JULN date_juln { copy_date(&$$, &date_s);
$$.cal = CAL_JULIAN; }
- | ESC_DATE_HEBR date_hebr { copy_date(&$$, date_s);
+ | ESC_DATE_HEBR date_hebr { copy_date(&$$, &date_s);
$$.cal = CAL_HEBREW; }
- | ESC_DATE_FREN date_fren { copy_date(&$$, date_s);
+ | ESC_DATE_FREN date_fren { copy_date(&$$, &date_s);
$$.cal = CAL_FRENCH_REV; }
- | date_greg { copy_date(&$$, date_s);
+ | date_greg { copy_date(&$$, &date_s);
$$.cal = CAL_GREGORIAN; }
;
date_period : MOD_FROM date { make_date_value(DV_FROM,
- $2, def_date, ""); }
+ &$2, &def_date, ""); }
| MOD_TO date { make_date_value(DV_TO,
- $2, def_date, ""); }
- | MOD_FROM date { copy_date(&$<date>$, $2); }
+ &$2, &def_date, ""); }
+ | MOD_FROM date { copy_date(&$<date>$, &$2); }
MOD_TO date
- { make_date_value(DV_FROM_TO, $<date>3, $5, ""); }
+ { make_date_value(DV_FROM_TO, &$<date>3, &$5, ""); }
;
date_range : MOD_BEF date { make_date_value(DV_BEFORE,
- $2, def_date, ""); }
+ &$2, &def_date, ""); }
| MOD_AFT date { make_date_value(DV_AFTER,
- $2, def_date, ""); }
- | MOD_BET date { copy_date(&$<date>$, $2); }
+ &$2, &def_date, ""); }
+ | MOD_BET date { copy_date(&$<date>$, &$2); }
MOD_AND date
- { make_date_value(DV_BETWEEN, $<date>3, $5, ""); }
+ { make_date_value(DV_BETWEEN, &$<date>3, &$5, ""); }
;
date_approx : MOD_ABT date { make_date_value(DV_ABOUT,
- $2, def_date, ""); }
+ &$2, &def_date, ""); }
| MOD_CAL date { make_date_value(DV_CALCULATED,
- $2, def_date, ""); }
+ &$2, &def_date, ""); }
| MOD_EST date { make_date_value(DV_ESTIMATED,
- $2, def_date, ""); }
+ &$2, &def_date, ""); }
;
date_interpr : MOD_INT date date_phrase
- { make_date_value(DV_INTERPRETED, $2, def_date, $3); }
+ { 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
{
- if (strlen($1) <= MAX_DAY_LEN) {
+ int d = _get_day_num($1);
+ if (d != -1) {
strcpy(date_s.day_str, $1);
- date_s.day = atoi($1);
- }
- else {
- gedcom_date_error(_("Too many characters in day '%s'"),
- $1);
+ date_s.day = d;
}
+ else YYERROR;
}
;
;
year : NUMBER
- { if (strlen($1) <= MAX_YEAR_LEN) {
+ { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
+ if (y != -1) {
strcpy(date_s.year_str, $1);
- date_s.year = atoi($1);
+ date_s.year = y;
date_s.year_type = YEAR_SINGLE;
}
- else {
- gedcom_date_error(_("Too many characters in year '%s'"),
- $1);
- }
+ else YYERROR;
}
;
year_greg : NUMBER
- { if (strlen($1) <= MAX_YEAR_LEN) {
+ { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
+ if (y != -1) {
strcpy(date_s.year_str, $1);
- date_s.year = atoi($1);
+ date_s.year = y;
date_s.year_type = YEAR_SINGLE;
}
- else {
- gedcom_date_error(_("Too many characters in year '%s'"),
- $1);
- }
+ else YYERROR;
}
| NUMBER SLASH NUMBER
- { if (strlen($1) + strlen($3) + 1 <= MAX_YEAR_LEN) {
- sprintf(date_s.year_str, "%s/%s", $1, $3);
- date_s.year = atoi($1) + 1;
+ { 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 {
- gedcom_date_error(_("Too many characters in year '%s/%s'"),
- $1, $3);
- }
-
+ 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) {
+ if (compat_mode(C_DOUBLE_DATES_4) && strlen(input2) == 4) {
+ input2 += 2;
+ }
+ else {
+ 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;
+ }
+}