Compatibility with Personal Ancestral File.
authorPeter Verthez <Peter.Verthez@advalvas.be>
Sat, 4 Jan 2003 18:46:54 +0000 (18:46 +0000)
committerPeter Verthez <Peter.Verthez@advalvas.be>
Sat, 4 Jan 2003 18:46:54 +0000 (18:46 +0000)
gedcom/compat.c
gedcom/compat.h
gedcom/gedcom.y

index 8b5ed50f3e1e8dd414651ee64d7ac9a7282ee89b..5bc93edfa078b348d63420d99cf9765da797c202 100644 (file)
@@ -25,6 +25,7 @@
 #include "interface.h"
 #include "encoding.h"
 #include "xref.h"
+#include "buffer.h"
 #include "gedcom_internal.h"
 #include "gedcom.h"
 
@@ -33,13 +34,15 @@ int compatibility  = 0;
 const char* default_charset = "";
 
 #define SUBMITTER_LINK         "@__COMPAT__SUBM__@"
+#define SLGC_FAMC_LINK         "@__COMPAT__FAM_SLGC__@"
 #define DEFAULT_SUBMITTER_NAME "Submitter"
 #define DEFAULT_GEDCOM_VERS    "5.5"
 #define DEFAULT_GEDCOM_FORM    "LINEAGE-LINKED"
 
 enum _COMPAT {
   C_FTREE = 0x01,
-  C_LIFELINES = 0x02
+  C_LIFELINES = 0x02,
+  C_PAF = 0x04
 };
 
 /* Incompatibility list (with GEDCOM 5.5):
@@ -56,6 +59,11 @@ enum _COMPAT {
        - HEAD.TIME instead of HEAD.DATE.TIME (will be ignored here)
        - '@' not written as '@@' in values
        - lots of missing required values
+
+    - Personal Ancestral File:
+        - '@' not written as '@@' in values
+       - some 5.5.1 (draft) tags are used: EMAIL, FONE, ROMN
+       - no FAMC field in SLGC
  */
 
 int compat_matrix[] =
@@ -66,8 +74,26 @@ int compat_matrix[] =
   /* C_NO_GEDC */             C_LIFELINES,
   /* C_NO_CHAR */             C_LIFELINES,
   /* C_HEAD_TIME */           C_LIFELINES,
-  /* C_NO_DOUBLE_AT */        C_LIFELINES,
-  /* C_NO_REQUIRED_VALUES */  C_LIFELINES
+  /* C_NO_DOUBLE_AT */        C_LIFELINES | C_PAF,
+  /* C_NO_REQUIRED_VALUES */  C_LIFELINES,
+  /* C_551_TAGS */            C_PAF,
+  /* C_NO_SLGC_FAMC */        C_PAF,
+  /* C_NR_OF_RULES */         0
+};
+
+int compat_state[] =
+{
+  /* C_NO_SUBMITTER */        0,
+  /* C_INDI_ADDR */           0,
+  /* C_NOTE_NO_VALUE */       0,
+  /* C_NO_GEDC */             0,
+  /* C_NO_CHAR */             0,
+  /* C_HEAD_TIME */           0,
+  /* C_NO_DOUBLE_AT */        0,
+  /* C_NO_REQUIRED_VALUES */  0,
+  /* C_551_TAGS */            0,
+  /* C_NO_SLGC_FAMC */        0,
+  /* C_NR_OF_RULES */         0
 };
 
 /* Compatibility handling */
@@ -77,23 +103,35 @@ void gedcom_set_compat_handling(int enable_compat)
   compat_enabled = enable_compat;
 }
 
+void enable_compat_msg(const char* program_name)
+{
+  gedcom_warning(_("Enabling compatibility with '%s'"), program_name);
+}
+
 void set_compatibility(const char* program)
 {
   /* Reinitialize compatibility */
+  int i;
   default_charset = "";
   compatibility = 0;
+  for (i = 0; i < C_NR_OF_RULES; i++)
+    compat_state[i] = 0;
   
   if (compat_enabled) {
     if (! strncmp(program, "ftree", 6)) {
-      gedcom_warning(_("Enabling compatibility with 'ftree'"));
+      enable_compat_msg("ftree");
       compatibility = C_FTREE;
     }
     else if (! strncmp(program, "LIFELINES", 9)) {
       /* Matches "LIFELINES 3.0.2" */
-      gedcom_warning(_("Enabling compatibility with 'Lifelines'"));
+      enable_compat_msg("Lifelines");
       compatibility = C_LIFELINES;
       default_charset = "ANSI";
     }
+    else if (! strncmp(program, "PAF", 4)) {
+      enable_compat_msg("Personal Ancestral File");
+      compatibility = C_PAF;
+    }
   }
 }
 
@@ -111,36 +149,42 @@ void compat_generate_submitter_link(Gedcom_ctxt parent)
   
   ts.string = "SUBM";
   ts.value  = TAG_SUBM;
+  gedcom_warning(_("Adding link to submitter record with xref '%s'"),
+                SUBMITTER_LINK);
   self = start_element(ELT_HEAD_SUBM,
                       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;
 }
 
 void compat_generate_submitter()
 {
-  struct xref_value *xr = gedcom_parse_xref(SUBMITTER_LINK, XREF_DEFINED,
-                                           XREF_SUBM);
-  struct tag_struct ts;
-  Gedcom_ctxt self1, self2;
-
-  /* first generate "0 SUBM" */
-  ts.string = "SUBM";
-  ts.value  = TAG_SUBM;
-  self1 = start_record(REC_SUBM, 0, GEDCOM_MAKE_XREF_PTR(val1, xr), ts,
-                      NULL, GEDCOM_MAKE_NULL(val2));
-
-  /* then generate "1 NAME ..." */
-  ts.string = "NAME";
-  ts.value  = TAG_NAME;
-  self2 = start_element(ELT_SUBM_NAME, self1, 1, ts, DEFAULT_SUBMITTER_NAME,
-                       GEDCOM_MAKE_STRING(val1, DEFAULT_SUBMITTER_NAME));
-
-  /* close "1 NAME ..." */
-  end_element(ELT_SUBM_NAME, self1, self2, NULL);
-
-  /* close "0 SUBM" */
-  end_record(REC_SUBM, self1, NULL);
+  if (compat_state[C_NO_SUBMITTER]) {
+    struct xref_value *xr = gedcom_parse_xref(SUBMITTER_LINK, XREF_DEFINED,
+                                             XREF_SUBM);
+    struct tag_struct ts;
+    Gedcom_ctxt self1, self2;
+    
+    /* first generate "0 SUBM" */
+    ts.string = "SUBM";
+    ts.value  = TAG_SUBM;
+    self1 = start_record(REC_SUBM, 0, GEDCOM_MAKE_XREF_PTR(val1, xr), ts,
+                        NULL, GEDCOM_MAKE_NULL(val2));
+    
+    /* then generate "1 NAME ..." */
+    ts.string = "NAME";
+    ts.value  = TAG_NAME;
+    self2 = start_element(ELT_SUBM_NAME, self1, 1, ts, DEFAULT_SUBMITTER_NAME,
+                         GEDCOM_MAKE_STRING(val1, DEFAULT_SUBMITTER_NAME));
+    
+    /* close "1 NAME ..." */
+    end_element(ELT_SUBM_NAME, self1, self2, NULL);
+    
+    /* close "0 SUBM" */
+    end_record(REC_SUBM, self1, NULL);
+    compat_state[C_NO_SUBMITTER] = 0;
+  }
 }
 
 void compat_generate_gedcom(Gedcom_ctxt parent)
@@ -222,3 +266,67 @@ void compat_generate_resi_end(Gedcom_ctxt parent, Gedcom_ctxt self)
 {
   end_element(ELT_SUB_INDIV_RESI, parent, self, NULL);
 }
+
+int is_551_tag(const char* tag)
+{
+  if (strncmp(tag, "EMAIL", 6))
+    return 1;
+  else if (strncmp(tag, "FONE", 5))
+    return 1;
+  else if (strncmp(tag, "ROMN", 5))
+    return 1;
+  else
+    return 0;
+}
+
+int compat_check_551_tag(const char* tag, struct safe_buffer* b)
+{
+  if (is_551_tag(tag)) {
+    reset_buffer(b);
+    SAFE_BUF_ADDCHAR(b, '_');
+    safe_buf_append(b, tag);
+    gedcom_warning(_("Converting 5.5.1 tag '%s' to standard 5.5 user tag '%s'"),
+                  tag, get_buf_string(b));
+    return 1;
+  }
+  else
+    return 0;
+}
+
+void compat_generate_slgc_famc_link(Gedcom_ctxt parent)
+{
+  struct xref_value *xr = gedcom_parse_xref(SLGC_FAMC_LINK, XREF_USED,
+                                           XREF_FAM);
+  struct tag_struct ts;
+  Gedcom_ctxt self;
+  
+  ts.string = "FAMC";
+  ts.value  = TAG_FAMC;
+  gedcom_warning(_("Adding link to family record with xref '%s'"),
+                SLGC_FAMC_LINK);
+  self = start_element(ELT_SUB_LIO_SLGC_FAMC,
+                      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]++;
+}
+
+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) {
+    struct xref_value *xr = gedcom_parse_xref(SLGC_FAMC_LINK, XREF_DEFINED,
+                                             XREF_FAM);
+    struct tag_struct ts;
+    Gedcom_ctxt self;
+    
+    /* generate "0 FAM" */
+    ts.string = "FAM";
+    ts.value  = TAG_FAM;
+    self = start_record(REC_FAM, 0, GEDCOM_MAKE_XREF_PTR(val1, xr), ts,
+                       NULL, GEDCOM_MAKE_NULL(val2));
+    
+    /* close "0 FAM" */
+    end_record(REC_FAM, self, NULL);
+  }
+}
index 03971d1fd2ded377456aa10ee2ed553692e2b34f..f5fc8f1e40174a34aaab0ccd49d289a2b5533a93 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef __COMPAT_H
 #define __COMPAT_H
 
+#include "buffer.h"
 #include "gedcom.h"
 
 typedef enum _COMPAT_RULES {
@@ -34,7 +35,10 @@ typedef enum _COMPAT_RULES {
   C_NO_CHAR,
   C_HEAD_TIME,
   C_NO_DOUBLE_AT,
-  C_NO_REQUIRED_VALUES
+  C_NO_REQUIRED_VALUES,
+  C_551_TAGS,
+  C_NO_SLGC_FAMC,
+  C_NR_OF_RULES
 } Compat_rule;
 
 void set_compatibility(const char* program);
@@ -45,5 +49,8 @@ void compat_generate_gedcom(Gedcom_ctxt parent);
 int  compat_generate_char(Gedcom_ctxt parent);
 Gedcom_ctxt compat_generate_resi_start(Gedcom_ctxt parent);
 void compat_generate_resi_end(Gedcom_ctxt parent, Gedcom_ctxt self);
+int  compat_check_551_tag(const char* tag, struct safe_buffer* b);
+void compat_generate_slgc_famc_link(Gedcom_ctxt parent);
+void compat_generate_slgc_famc_fam();
 
 #endif /* __COMPAT_H */
index 3e3667c4d410cbee1c5f2b5fc13bf37b8adcd53c..4a131b04a6718da38792cdd6af3dbdad1a4395bb 100644 (file)
@@ -164,6 +164,10 @@ struct safe_buffer line_item_buffer = { NULL, 0, NULL, 0,
 
 void cleanup_concat_buffer(); 
 struct safe_buffer concat_buffer = { NULL, 0, NULL, 0, cleanup_concat_buffer };
+
+void cleanup_usertag_buffer();
+struct safe_buffer usertag_buffer = { NULL, 0, NULL, 0,
+                                     cleanup_usertag_buffer};
  
 /* These are defined at the bottom of the file */ 
 void push_countarray(int level);
@@ -210,7 +214,9 @@ void clean_up();
                      #TAG, parenttag);                                       \
          HANDLE_ERROR;                                                        \
        }                                                                      \
-     } 
+     }
+#define CHK_COND(TAG)                                                         \
+     check_occurrence(TAG_##TAG)
 #define POP                                                                   \
      { pop_countarray();                                                      \
        --count_level;                                                         \
@@ -444,15 +450,15 @@ head_sect    : OPEN DELIM TAG_HEAD
                                         NULL, GEDCOM_MAKE_NULL(val2));
                 START(HEAD, $1, $<ctxt>$) }
                head_subs
-               { if (compat_mode(C_NO_SUBMITTER))
+               { if (compat_mode(C_NO_SUBMITTER) && ! CHK_COND(SUBM))
                   compat_generate_submitter_link($<ctxt>4);
                 else CHK(SUBM);
 
-                if (compat_mode(C_NO_GEDC))
+                if (compat_mode(C_NO_GEDC) && ! CHK_COND(GEDC))
                   compat_generate_gedcom($<ctxt>4);
                 else CHK(GEDC);
 
-                if (compat_mode(C_NO_CHAR)) {
+                if (compat_mode(C_NO_CHAR) && ! CHK_COND(CHAR)) {
                   if (compat_generate_char($<ctxt>4)) HANDLE_ERROR;
                 }
                 else CHK(CHAR);
@@ -670,7 +676,7 @@ head_date_time_sect : OPEN DELIM TAG_TIME mand_line_item
                      }
                     ;
 
-/* HEAD.TIME (Only for 'Lifelines' compatibility) */
+/* HEAD.TIME (Only for compatibility) */
 /* Just ignore the time... */
 head_time_sect : OPEN DELIM TAG_TIME opt_line_item CLOSE
                  { gedcom_warning(_("Header change time lost in the compatibility"));
@@ -1049,7 +1055,10 @@ indiv_rec   : OPEN DELIM POINTER DELIM TAG_INDI
               indi_subs
              { CHECK0 }
               CLOSE
-              { end_record(REC_INDI, $<ctxt>6, GEDCOM_MAKE_NULL(val1)); }
+              { end_record(REC_INDI, $<ctxt>6, GEDCOM_MAKE_NULL(val1));
+               if (compat_mode(C_NO_SLGC_FAMC))
+                 compat_generate_slgc_famc_fam();
+             }
             ;
 
 indi_subs   : /* empty */
@@ -2885,7 +2894,11 @@ lio_slgc_sect : OPEN DELIM TAG_SLGC
                  START(SLGC, $1, $<ctxt>$) 
                 }
                 lio_slgc_subs
-               { CHECK1(FAMC) }
+                { if (compat_mode(C_NO_SLGC_FAMC) && ! CHK_COND(FAMC))
+                   compat_generate_slgc_famc_link($<ctxt>4);
+                 else CHK(FAMC);
+                 CHECK0;
+               }
                 CLOSE 
                 { end_element(ELT_SUB_LIO_SLGC, PARENT, $<ctxt>4, 
                              GEDCOM_MAKE_NULL(val1));
@@ -3631,9 +3644,15 @@ no_std_rec  : user_rec /* 0:M */
 
 user_rec    : OPEN DELIM opt_xref USERTAG
               { if ($4.string[0] != '_') {
-                 gedcom_error(_("Undefined tag (and not a valid user tag): %s"),
-                              $4);
-                 YYERROR;
+                 if (compat_mode(C_551_TAGS)
+                     && compat_check_551_tag($4.string, &usertag_buffer)) {
+                   $4.string = get_buf_string(&usertag_buffer);
+                 }
+                 else {                  
+                   gedcom_error(_("Undefined tag (and not a valid user tag): %s"),
+                                $4);
+                   YYERROR;
+                 }
                }
              }
               opt_value
@@ -3655,9 +3674,15 @@ user_rec    : OPEN DELIM opt_xref USERTAG
             ;
 user_sect   : OPEN DELIM opt_xref USERTAG
               { if ($4.string[0] != '_') {
-                 gedcom_error(_("Undefined tag (and not a valid user tag): %s"),
-                              $4);
-                 YYERROR;
+                 if (compat_mode(C_551_TAGS)
+                     && compat_check_551_tag($4.string, &usertag_buffer)) {
+                   $4.string = get_buf_string(&usertag_buffer);
+                 }
+                 else {
+                   gedcom_error(_("Undefined tag (and not a valid user tag): %s"),
+                                $4);
+                   YYERROR;
+                 }
                }
              }
               opt_value
@@ -3698,8 +3723,7 @@ mand_pointer : /* empty */ { gedcom_error(_("Missing pointer")); YYERROR; }
 
 mand_line_item : /* empty */
                  { if (compat_mode(C_NO_REQUIRED_VALUES)) {
-                     /* Lifelines tends to not care about mandatory values */
-                    gedcom_debug_print("==Val: ==");
+                     gedcom_debug_print("==Val: ==");
                     $$ = "";
                   }
                   else {
@@ -4031,6 +4055,11 @@ void cleanup_line_item_buffer()
   cleanup_buffer(&line_item_buffer);
 }
 
+void cleanup_usertag_buffer()
+{
+  cleanup_buffer(&usertag_buffer);
+}
+
 /* Enabling debug mode */
 /* level 0: no debugging */
 /* level 1: only internal */