#include "gedcom.h"
int compat_enabled = 1;
+Gedcom_compat compat_options = 0;
int compatibility = 0;
int compatibility_program = 0;
int compatibility_version = 0;
- 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
+ - non-standard date formats
- 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'
+ - non-standard date formats
- Family Origins:
- '@' not written as '@@' in values
- 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
+ - non-standard date formats
*/
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,
/* 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,
+ /* C_PAF_DATES */ C_PAF2 | C_PAF4 | C_PAF5
};
union _COMPAT_STATE {
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)
Gedcom_ctxt compat_generate_head_time_start(int level, struct tag_struct ts,
char* value)
{
- 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
+ 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)
{
- Gedcom_ctxt parent = compat_state[C_HEAD_TIME].vp;
- if (parent)
- end_element(ELT_HEAD_DATE_TIME,
- parent, self, GEDCOM_MAKE_NULL(val1));
+ 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;
}
/********************************************************************/
compat_state[C_SUBM_COMM].i = 1;
}
}
+
+/********************************************************************/
+/* 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;
+}