Also write empty CONT lines.
[gedcom-parse.git] / gedcom / gedcom.y
index 3e3667c4d410cbee1c5f2b5fc13bf37b8adcd53c..f6d281e0811eeea3ae84323d71476920a279486a 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);
@@ -174,7 +178,7 @@ Gedcom_ctxt get_parentctxt(int offset);
 void pop_countarray();
 int  count_tag(int tag);
 int  check_occurrence(int tag);
-void clean_up(); 
+void clean_up();
 
 #define HANDLE_ERROR                                                          \
      { if (error_mechanism == IMMED_FAIL) {                                   \
@@ -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);
@@ -490,7 +496,7 @@ head_sub     : head_sour_sect  { OCCUR2(SOUR, 1, 1) }
 
 /* HEAD.SOUR */
 head_sour_sect : OPEN DELIM TAG_SOUR mand_line_item 
-                 { set_compatibility($4);
+                 { set_compatibility_program($4);
                   $<ctxt>$ = start_element(ELT_HEAD_SOUR, PARENT,
                                            $1, $3, $4,
                                            GEDCOM_MAKE_STRING(val1, $4));
@@ -499,7 +505,8 @@ head_sour_sect : OPEN DELIM TAG_SOUR mand_line_item
                  head_sour_subs
                  { CHECK0 }
                 CLOSE
-                 { end_element(ELT_HEAD_SOUR, PARENT, $<ctxt>5,
+                 { compute_compatibility();
+                  end_element(ELT_HEAD_SOUR, PARENT, $<ctxt>5,
                               GEDCOM_MAKE_NULL(val1)); }
                ;
 
@@ -515,7 +522,8 @@ head_sour_sub : head_sour_vers_sect  { OCCUR2(VERS, 0, 1) }
               ;
 
 head_sour_vers_sect : OPEN DELIM TAG_VERS mand_line_item
-                      { $<ctxt>$ = start_element(ELT_HEAD_SOUR_VERS, PARENT,
+                      { set_compatibility_version($4);
+                       $<ctxt>$ = start_element(ELT_HEAD_SOUR_VERS, PARENT,
                                                 $1, $3, $4,
                                                 GEDCOM_MAKE_STRING(val1, $4));
                        START(VERS, $1, $<ctxt>$)
@@ -670,7 +678,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 +1057,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 */
@@ -1223,6 +1234,8 @@ indi_addr_sect : OPEN DELIM TAG_ADDR opt_line_item
                        = start_element(ELT_SUB_ADDR,
                                        par, $1 + 1, $3, $4,
                                        GEDCOM_MAKE_NULL_OR_STRING(val2, $4));
+                     reset_buffer(&concat_buffer);
+                     safe_buf_append(&concat_buffer, $4);
                      START(ADDR, $1 + 1, $<ctxt>$);
                    }
                  else { START(ADDR, $1, NULL) }
@@ -1232,8 +1245,9 @@ indi_addr_sect : OPEN DELIM TAG_ADDR opt_line_item
                   CLOSE
                   { if (compat_mode(C_INDI_ADDR)) {
                      Gedcom_ctxt par = PARENT;
+                     char* complete = get_buf_string(&concat_buffer);
                      end_element(ELT_SUB_ADDR, par, $<ctxt>5,
-                                 GEDCOM_MAKE_NULL(val1));
+                                 GEDCOM_MAKE_STRING(val1, complete));
                      CHECK0;
                      compat_generate_resi_end(PARENT, par);
                    } 
@@ -1409,7 +1423,7 @@ note_line_item : /* empty */
                       gedcom_error(_("Missing value")); YYERROR;
                     }
                     else {
-                      $$ = "";
+                      $$ = VALUE_IF_MISSING;
                     }
                   }
                | DELIM line_item
@@ -2267,12 +2281,13 @@ continuation_sub : cont_sect  /* 0:M */
                  | conc_sect  /* 0:M */
                  ;
 
-cont_sect : OPEN DELIM TAG_CONT mand_line_item 
+cont_sect : OPEN DELIM TAG_CONT opt_line_item 
             { $<ctxt>$ = start_element(ELT_SUB_CONT,
                                       PARENT, $1, $3, $4, 
-                                      GEDCOM_MAKE_STRING(val1, $4));
+                                      GEDCOM_MAKE_NULL_OR_STRING(val1, $4));
              SAFE_BUF_ADDCHAR(&concat_buffer, '\n');
-             safe_buf_append(&concat_buffer, $4);
+             if (GEDCOM_IS_STRING(&val1))
+               safe_buf_append(&concat_buffer, $4);
              START(CONT, $1, $<ctxt>$)  
             }  
             no_std_subs  
@@ -2885,7 +2900,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 +3650,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 +3680,20 @@ 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 if (compat_mode(C_SUBM_COMM) &&
+                          compat_check_subm_comm($4.string, get_parenttag(0),
+                                                 &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
@@ -3669,11 +3705,21 @@ user_sect   : OPEN DELIM opt_xref USERTAG
              CLOSE
               { end_element(ELT_USER, PARENT, $<ctxt>7, 
                            GEDCOM_MAKE_NULL(val1));
+               if (compat_mode(C_SUBM_COMM))
+                 compat_close_subm_comm();
              }
             ;
 
 user_sects   : /* empty */     { }
             | user_sects user_sect { }
+            | user_sects gen_sect
+              { if (compat_mode(C_SUBM_COMM)) {
+                }
+               else {
+                 gedcom_error(_("Standard tag not allowed in user section"));
+                 YYERROR;
+               }
+             }
             ;
 
 opt_xref    : /* empty */        { $$ = NULL; }
@@ -3698,9 +3744,8 @@ 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: ==");
+                    $$ = VALUE_IF_MISSING;
                   }
                   else {
                     gedcom_error(_("Missing value")); YYERROR;
@@ -3763,9 +3808,23 @@ error_sect  : OPEN DELIM opt_xref anytag opt_value error_subs CLOSE { }
             ;
 
 gen_sect    : OPEN DELIM opt_xref anystdtag
-              { INVALID_TAG($4.string); }
-              opt_value opt_sects CLOSE
-              { }
+              { if (compat_mode(C_SUBM_COMM)
+                   && compat_check_subm_comm_cont($4.string)) {
+                 /* Will pass here */
+               }
+               else {
+                 INVALID_TAG($4.string);
+               }
+             }
+              opt_value
+              { if (compat_mode(C_SUBM_COMM)) {
+                 $<ctxt>$ = compat_subm_comm_cont_start(PARENT, $6);
+                }
+             }
+             opt_sects CLOSE
+              { if (compat_mode(C_SUBM_COMM))
+                 compat_subm_comm_cont_end(PARENT, $<ctxt>7);
+             }
             ;
 
 gen_rec : gen_rec_top
@@ -3942,7 +4001,7 @@ Gedcom_ctxt ctxt_stack[MAXGEDCLEVEL+1];
 void push_countarray(int level)
 {
   int *count = NULL;
-  gedcom_debug_print("Push Count level: %d, level: %d\n", count_level, level);
+  gedcom_debug_print("Push Count level: %d, level: %d", count_level, level);
   if (count_level != level + 1) {
     gedcom_error(_("Internal error: count level mismatch"));
     exit(1);
@@ -3952,7 +4011,7 @@ void push_countarray(int level)
     exit(1);
   }
   else {
-    gedcom_debug_print("calloc countarray %d\n", count_level);
+    gedcom_debug_print("calloc countarray %d", count_level);
     count = (int *)calloc(YYNTOKENS, sizeof(int));
     if (count == NULL) {
       gedcom_error(_("Internal error: count array calloc error"));
@@ -3999,14 +4058,14 @@ int check_occurrence(int tag)
 void pop_countarray()
 {
   int *count;
-  gedcom_debug_print("Pop Count level: %d\n", count_level);
+  gedcom_debug_print("Pop Count level: %d", count_level);
   if (count_level < 0) {
     gedcom_error(_("Internal error: count array underflow"));
     exit(1);
   }
   else {
     count = count_arrays[count_level];
-    gedcom_debug_print("free countarray %d\n", count_level);
+    gedcom_debug_print("free countarray %d", count_level);
     free(count);
     count_arrays[count_level] = NULL;
   }
@@ -4014,7 +4073,7 @@ void pop_countarray()
 
 void clean_up()
 {
-  gedcom_debug_print("Cleanup countarrays\n");
+  gedcom_debug_print("Cleanup countarrays");
   while (count_level > 0) {
     pop_countarray();
     --count_level;
@@ -4031,6 +4090,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 */