Start of documentation in doxygen.
[gedcom-parse.git] / gedcom / compat.c
index dcba760c6420840c4050550528c6fc94ae960978..ce45d41195543c56e3f7c50fd9336b5fb5259331 100644 (file)
@@ -36,6 +36,14 @@ 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"
@@ -95,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
@@ -110,11 +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[] =
@@ -127,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,
@@ -137,7 +150,9 @@ int compat_matrix[] =
   /* C_NOTE_NOTE */           C_EASYTREE,
   /* C_TAB_CHARACTER */       C_PAF5,
   /* C_SUBM_CTRY */           C_PAF4,
-  /* C_NOTE_TOO_LONG */       C_PAF4
+  /* C_NOTE_TOO_LONG */       C_PAF4 | C_PAF5,
+  /* C_NOTE_CONC_SOUR */      C_EASYTREE,
+  /* C_NONSTD_SOUR_TAGS */    C_EASYTREE,
 };
 
 union _COMPAT_STATE {
@@ -260,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                                                  */
 /********************************************************************/
@@ -630,6 +651,51 @@ void compat_subm_comm_cont_end(Gedcom_ctxt parent, Gedcom_ctxt self)
   }
 }
 
+/********************************************************************/
+/*  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                                                 */
 /********************************************************************/
@@ -680,3 +746,96 @@ void compat_long_line_finish(Gedcom_ctxt parent, int level)
     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;
+}