X-Git-Url: https://git.dlugolecki.net.pl/?a=blobdiff_plain;f=gedcom%2Fcompat.c;h=ce45d41195543c56e3f7c50fd9336b5fb5259331;hb=6103dd898c4de86c68891cc0222543988a2caab7;hp=196113ffe1b576dd59ba476cb0ce3d22a42c02a1;hpb=9d87c36948e5cc9c90c14bd09b5007c519ed8b4b;p=gedcom-parse.git diff --git a/gedcom/compat.c b/gedcom/compat.c index 196113f..ce45d41 100644 --- a/gedcom/compat.c +++ b/gedcom/compat.c @@ -30,11 +30,20 @@ #include "gedcom.h" int compat_enabled = 1; +Gedcom_compat compat_options = 0; int compatibility = 0; int compatibility_program = 0; int compatibility_version = 0; const char* default_charset = ""; +void cleanup_compat_buffer(); +struct safe_buffer compat_buffer = { NULL, 0, NULL, 0, cleanup_compat_buffer }; + +void cleanup_compat_buffer() +{ + cleanup_buffer(&compat_buffer); +} + #define SUBMITTER_LINK "@__COMPAT__SUBM__@" #define SLGC_FAMC_LINK "@__COMPAT__FAM_SLGC__@" #define DEFAULT_SUBMITTER_NAME "Submitter" @@ -94,11 +103,13 @@ struct program_data data[] = { - some 5.5.1 (draft) tags are used: EMAIL, FONE, ROMN - no FAMC field in SLGC - uses tab character (will be converted to 8 spaces here) + - lines too long + - double dates written as e.g. '1815/1816' - Personal Ancestral File 2: - '@' not written as '@@' in values - COMM tag in submitter record - - double dates written as e.g. '1815/1816' instead of '1815/16' + - double dates written as e.g. '1815/1816' - Family Origins: - '@' not written as '@@' in values @@ -109,9 +120,14 @@ struct program_data data[] = { - no submitter link in the header - NOTE doesn't have a value - NOTE.NOTE instead of NOTE.COND + - NOTE.CONC.SOUR instead of NOTE.SOUR + - non-standard tags in SOUR records - Personal Ancestral File 4: - '@' not written as '@@' in values + - SUBM.CTRY instead of SUBM.ADDR.CTRY + - lines too long + - double dates written as e.g. '1815/1816' */ int compat_matrix[] = @@ -124,7 +140,7 @@ int compat_matrix[] = /* C_HEAD_TIME */ C_LIFELINES, /* C_NO_DOUBLE_AT */ C_LIFELINES | C_PAF5 | C_PAF2 | C_FAMORIG | C_PAF4, - /* C_NO_REQUIRED_VALUES */ C_LIFELINES | C_PAF5, + /* C_NO_REQUIRED_VALUES */ C_LIFELINES | C_PAF5 | C_EASYTREE, /* C_551_TAGS */ C_PAF5, /* C_NO_SLGC_FAMC */ C_PAF5, /* C_SUBM_COMM */ C_PAF2, @@ -132,10 +148,17 @@ int compat_matrix[] = /* C_CONC_NEEDS_SPACE */ C_FAMORIG, /* C_NO_GEDC_FORM */ C_EASYTREE, /* C_NOTE_NOTE */ C_EASYTREE, - /* C_TAB_CHARACTER */ C_PAF5 + /* C_TAB_CHARACTER */ C_PAF5, + /* C_SUBM_CTRY */ C_PAF4, + /* C_NOTE_TOO_LONG */ C_PAF4 | C_PAF5, + /* C_NOTE_CONC_SOUR */ C_EASYTREE, + /* C_NONSTD_SOUR_TAGS */ C_EASYTREE, }; -int compat_state[C_NR_OF_RULES]; +union _COMPAT_STATE { + int i; + void* vp; +} compat_state[C_NR_OF_RULES]; /* Compatibility handling */ @@ -144,6 +167,11 @@ void gedcom_set_compat_handling(int enable_compat) compat_enabled = enable_compat; } +void gedcom_set_compat_options(Gedcom_compat options) +{ + compat_options = options; +} + void enable_compat_msg(const char* program_name, int version) { if (version > 0) @@ -200,7 +228,7 @@ void compute_compatibility() default_charset = ""; compatibility = 0; for (i = 0; i < C_NR_OF_RULES; i++) - compat_state[i] = 0; + compat_state[i].i = 0; switch (compatibility_program) { case CP_PAF: @@ -247,6 +275,12 @@ int compat_mode(Compat_rule rule) return (compat_matrix[rule] & compatibility); } +void compat_close() +{ + compatibility_program = 0; + compatibility = 0; +} + /********************************************************************/ /* C_NO_SUBMITTER */ /********************************************************************/ @@ -266,12 +300,12 @@ void compat_generate_submitter_link(Gedcom_ctxt parent) parent, 1, ts, SUBMITTER_LINK, GEDCOM_MAKE_XREF_PTR(val1, xr)); end_element(ELT_HEAD_SUBM, parent, self, NULL); - compat_state[C_NO_SUBMITTER] = 1; + compat_state[C_NO_SUBMITTER].i = 1; } void compat_generate_submitter() { - if (compat_state[C_NO_SUBMITTER]) { + if (compat_state[C_NO_SUBMITTER].i) { struct xref_value *xr = gedcom_parse_xref(SUBMITTER_LINK, XREF_DEFINED, XREF_SUBM); struct tag_struct ts; @@ -294,7 +328,7 @@ void compat_generate_submitter() /* close "0 SUBM" */ end_record(REC_SUBM, self1, NULL); - compat_state[C_NO_SUBMITTER] = 0; + compat_state[C_NO_SUBMITTER].i = 0; } } @@ -383,6 +417,90 @@ int compat_generate_char(Gedcom_ctxt parent) return 0; } +/********************************************************************/ +/* C_HEAD_TIME */ +/********************************************************************/ + +void compat_save_head_date_context(Gedcom_ctxt parent) +{ + compat_state[C_HEAD_TIME].vp = parent; +} + +Gedcom_ctxt compat_generate_head_time_start(int level, struct tag_struct ts, + char* value) +{ + if (compat_options & COMPAT_ALLOW_OUT_OF_CONTEXT) { + Gedcom_ctxt parent = compat_state[C_HEAD_TIME].vp; + if (!value) + value = "-"; + if (parent) + return start_element(ELT_HEAD_DATE_TIME, + parent, level, ts, value, + GEDCOM_MAKE_STRING(val1, value)); + else + return NULL; + } + else { + gedcom_warning(_("Header change time '%s' lost in the compatibility (out of context)"), + value); + return NULL; + } +} + +void compat_generate_head_time_end(Gedcom_ctxt self) +{ + if (compat_options & COMPAT_ALLOW_OUT_OF_CONTEXT) { + Gedcom_ctxt parent = compat_state[C_HEAD_TIME].vp; + if (parent) + end_element(ELT_HEAD_DATE_TIME, + parent, self, GEDCOM_MAKE_NULL(val1)); + } +} + +/********************************************************************/ +/* C_SUBM_CTRY */ +/********************************************************************/ + +void compat_save_ctry_parent_context(Gedcom_ctxt parent) +{ + compat_state[C_SUBM_CTRY].vp = parent; +} + +Gedcom_ctxt compat_generate_addr_ctry_start(int level, struct tag_struct ts, + char* value) +{ + if (compat_options & COMPAT_ALLOW_OUT_OF_CONTEXT) { + Gedcom_ctxt parent = compat_state[C_SUBM_CTRY].vp; + if (!value) + value = "-"; + if (parent) + return start_element(ELT_SUB_ADDR_CTRY, + parent, level, ts, value, + GEDCOM_MAKE_STRING(val1, value)); + else + return NULL; + } + else { + gedcom_warning(_("Country '%s' lost in the compatibility (out of context)"), value); + return NULL; + } +} + +void compat_generate_addr_ctry_end(Gedcom_ctxt self) +{ + if (compat_options & COMPAT_ALLOW_OUT_OF_CONTEXT) { + Gedcom_ctxt parent = compat_state[C_SUBM_CTRY].vp; + if (parent) + end_element(ELT_SUB_ADDR_CTRY, + parent, self, GEDCOM_MAKE_NULL(val1)); + } +} + +void compat_free_ctry_parent_context() +{ + compat_state[C_SUBM_CTRY].vp = NULL; +} + /********************************************************************/ /* C_INDI_ADDR */ /********************************************************************/ @@ -453,13 +571,13 @@ void compat_generate_slgc_famc_link(Gedcom_ctxt parent) parent, 2, ts, SLGC_FAMC_LINK, GEDCOM_MAKE_XREF_PTR(val1, xr)); end_element(ELT_SUB_LIO_SLGC_FAMC, parent, self, NULL); - compat_state[C_NO_SLGC_FAMC]++; + compat_state[C_NO_SLGC_FAMC].i++; } void compat_generate_slgc_famc_fam() { /* If bigger than 1, then the FAM record has already been generated */ - if (compat_state[C_NO_SLGC_FAMC] == 1) { + if (compat_state[C_NO_SLGC_FAMC].i == 1) { struct xref_value *xr = gedcom_parse_xref(SLGC_FAMC_LINK, XREF_DEFINED, XREF_FAM); struct tag_struct ts; @@ -489,7 +607,7 @@ int compat_check_subm_comm(const char* tag, const char* parent_tag, safe_buf_append(b, tag); gedcom_warning(_("Converting non-standard tag '%s' to user tag '%s'"), tag, get_buf_string(b)); - compat_state[C_SUBM_COMM] = 1; + compat_state[C_SUBM_COMM].i = 1; return 1; } else @@ -498,13 +616,13 @@ int compat_check_subm_comm(const char* tag, const char* parent_tag, void compat_close_subm_comm() { - compat_state[C_SUBM_COMM] = 0; + compat_state[C_SUBM_COMM].i = 0; } int compat_check_subm_comm_cont(const char* tag) { - if (compat_state[C_SUBM_COMM] && !strcmp(tag, "CONT")) { - compat_state[C_SUBM_COMM] = 2; + if (compat_state[C_SUBM_COMM].i && !strcmp(tag, "CONT")) { + compat_state[C_SUBM_COMM].i = 2; return 1; } else @@ -516,7 +634,7 @@ Gedcom_ctxt compat_subm_comm_cont_start(Gedcom_ctxt parent, char* str) Gedcom_ctxt self = NULL; struct tag_struct ts; - if (compat_state[C_SUBM_COMM] == 2) { + if (compat_state[C_SUBM_COMM].i == 2) { ts.string = "_CONT"; ts.value = USERTAG; self = start_element(ELT_USER, parent, 2, ts, str, &val2); @@ -527,8 +645,197 @@ Gedcom_ctxt compat_subm_comm_cont_start(Gedcom_ctxt parent, char* str) void compat_subm_comm_cont_end(Gedcom_ctxt parent, Gedcom_ctxt self) { - if (compat_state[C_SUBM_COMM] == 2) { + if (compat_state[C_SUBM_COMM].i == 2) { end_element(ELT_USER, parent, self, NULL); - compat_state[C_SUBM_COMM] = 1; + compat_state[C_SUBM_COMM].i = 1; + } +} + +/********************************************************************/ +/* C_DOUBLE_DATES_4 */ +/********************************************************************/ + +void compat_date_start() +{ + if (compat_mode(C_DOUBLE_DATES_4)) { + reset_buffer(&compat_buffer); + compat_state[C_DOUBLE_DATES_4].i = 0; + } +} + +int compat_double_date_check(char* year2) +{ + return (compat_mode(C_DOUBLE_DATES_4) + && !compat_state[C_DOUBLE_DATES_4].i + && strlen(year2) == 4); +} + +int compat_double_date_final(struct date_value* dv, const char** curr_line) +{ + char* compat_line_value = get_buf_string(&compat_buffer); + compat_state[C_DOUBLE_DATES_4].i = 1; + if (compat_line_value && compat_line_value[0] + && (dv->type == DV_NO_MODIFIER || dv->type == DV_ABOUT) + && dv->date1.day == -1 + && dv->date1.month == -1) { + gedcom_warning(_("Converting '%s' to standard '%s'"), + *curr_line, compat_line_value); + *curr_line = compat_line_value; + } + return 1; +} + +int compat_date_check(struct date_value* dv, const char** curr_line) +{ + if (compat_mode(C_DOUBLE_DATES_4) + && compat_double_date_final(dv, curr_line)) { + return 1; + } + else { + return 0; } } + +/********************************************************************/ +/* C_NOTE_TOO_LONG */ +/********************************************************************/ + +char compat_prefix[MAXGEDCLINELEN]; + +int compat_long_line(int level, int tag) +{ + return compat_mode(C_NOTE_TOO_LONG) && (level > 0) && (tag == TAG_NOTE); +} + +char* compat_long_line_get_prefix(char* str) +{ + if (str && utf8_strlen(str) > MAXGEDCLINELEN - 7) { + int len = MAXGEDCLINELEN - 7; + char* ch = nth_utf8_char(str, len - 1); + char* nextch = next_utf8_char(ch); + memset(compat_prefix, 0, MAXGEDCLINELEN); + while (len > 1 && (*ch == ' ' || *nextch == ' ')) { + len--; + nextch = ch; + ch = nth_utf8_char(str, len - 1); + } + len = nextch - str; + strncpy(compat_prefix, str, len); + compat_state[C_NOTE_TOO_LONG].vp = (void*)nextch; + return compat_prefix; + } + else { + compat_state[C_NOTE_TOO_LONG].vp = NULL; + return str; + } +} + +void compat_long_line_finish(Gedcom_ctxt parent, int level) +{ + struct tag_struct ts; + ts.string = "CONC"; + ts.value = TAG_CONC; + + while (compat_state[C_NOTE_TOO_LONG].vp) { + Gedcom_ctxt ctxt; + char* input = (char*)compat_state[C_NOTE_TOO_LONG].vp; + char* output = compat_long_line_get_prefix(input); + + ctxt = start_element(ELT_SUB_CONC, parent, level + 1, ts, output, + GEDCOM_MAKE_STRING(val1, output)); + end_element(ELT_SUB_CONC, parent, ctxt, GEDCOM_MAKE_NULL(val1)); + } +} + +/********************************************************************/ +/* C_NOTE_CONC_SOUR */ +/********************************************************************/ + +Gedcom_ctxt compat_generate_note_sour_start(Gedcom_ctxt parent, + int level, struct tag_struct ts, + char* pointer) +{ + Gedcom_ctxt self; + struct xref_value *xr = gedcom_parse_xref(pointer, XREF_USED, XREF_SOUR); + if (xr == NULL) { + self = (void*)-1; + } + else { + self = start_element(ELT_SUB_SOUR, parent, level-1, ts, pointer, + GEDCOM_MAKE_XREF_PTR(val1, xr)); + } + compat_state[C_NOTE_CONC_SOUR].vp = parent; + return self; +} + +void compat_generate_note_sour_end(Gedcom_ctxt self) +{ + if (self != (void*) -1) { + end_element(ELT_SUB_SOUR, compat_state[C_NOTE_CONC_SOUR].vp, + self, GEDCOM_MAKE_NULL(val1)); + } +} + +/********************************************************************/ +/* C_NONSTD_SOUR_TAGS */ +/********************************************************************/ + +int is_nonstd_sour_tag(const char* tag) +{ + if (strncmp(tag, "FILN", 5)) + return 1; + else if (strncmp(tag, "URL", 4)) + return 1; + else if (strncmp(tag, "LOCA", 5)) + return 1; + else if (strncmp(tag, "REGI", 5)) + return 1; + else if (strncmp(tag, "VOL", 4)) + return 1; + else + return 0; +} + +int compat_check_sour_tag(const char* tag, struct safe_buffer* b) +{ + if (is_nonstd_sour_tag(tag)) { + reset_buffer(b); + SAFE_BUF_ADDCHAR(b, '_'); + safe_buf_append(b, tag); + gedcom_warning(_("Converting undefined tag '%s' to user tag '%s'"), + tag, get_buf_string(b)); + return 1; + } + else + return 0; +} + +Gedcom_ctxt compat_generate_nonstd_sour_start(Gedcom_ctxt parent, int level, + struct tag_struct ts, + char* value, + struct safe_buffer* b) +{ + Gedcom_ctxt self = NULL; + reset_buffer(b); + SAFE_BUF_ADDCHAR(b, '_'); + safe_buf_append(b, ts.string); + gedcom_warning(_("Converting invalidly used tag '%s' to user tag '%s'"), + ts.string, get_buf_string(b)); + ts.string = get_buf_string(b); + + self = start_element(ELT_USER, parent, level, ts, value, + GEDCOM_MAKE_NULL_OR_STRING(val1, value)); + compat_state[C_NONSTD_SOUR_TAGS].i = 1; + return self; +} + +void compat_generate_nonstd_sour_end(Gedcom_ctxt parent, Gedcom_ctxt self) +{ + end_element(ELT_USER, parent, self, NULL); + compat_state[C_NONSTD_SOUR_TAGS].i = 0; +} + +int compat_generate_nonstd_sour_state() +{ + return compat_state[C_NONSTD_SOUR_TAGS].i; +}