#include "compat.h"
#include "interface.h"
+#include "encoding.h"
#include "xref.h"
#include "gedcom_internal.h"
#include "gedcom.h"
-#define SUBMITTER_LINK "@__COMPAT__SUBM__@"
+int compat_at = 0;
+
+#define SUBMITTER_LINK "@__COMPAT__SUBM__@"
#define DEFAULT_SUBMITTER_NAME "Submitter"
+#define DEFAULT_GEDCOM_VERS "5.5"
+#define DEFAULT_GEDCOM_FORM "LINEAGE-LINKED"
+/* Make default character set ANSI, for all 'special characters'
+ typically used in non-compliant gedcom generators */
+#define DEFAULT_CHAR "ANSI"
/* Incompatibily list (with GEDCOM 5.5):
- INDI.ADDR instead of INDI.RESI.ADDR
- NOTE doesn't have a value
+ - Lifelines (3.0.2):
+ - no submitter record, no submitter link in the header
+ - no GEDC field in the header
+ - no CHAR field in the header
+ - TIME field outside of DATE field in the header (will be ignored here)
+ - '@' not written as '@@' in values
*/
void compat_generate_submitter_link(Gedcom_ctxt parent)
end_record(REC_SUBM, self1);
}
+void compat_generate_gedcom(Gedcom_ctxt parent)
+{
+ struct tag_struct ts;
+ Gedcom_ctxt self1, self2;
+
+ /* first generate "1 GEDC" */
+ ts.string = "GEDC";
+ ts.value = TAG_GEDC;
+ self1 = start_element(ELT_HEAD_GEDC, parent, 1, ts, NULL,
+ GEDCOM_MAKE_NULL(val1));
+
+ /* then generate "2 VERS <DEFAULT_GEDC_VERS>" */
+ ts.string = "VERS";
+ ts.value = TAG_VERS;
+ self2 = start_element(ELT_HEAD_GEDC_VERS, self1, 2, ts,
+ DEFAULT_GEDCOM_VERS,
+ GEDCOM_MAKE_STRING(val1, DEFAULT_GEDCOM_VERS));
+
+ /* close "2 VERS" */
+ end_element(ELT_HEAD_GEDC_VERS, self1, self2, NULL);
+
+ /* then generate "2 FORM <DEFAULT_GEDCOM_FORM> */
+ ts.string = "FORM";
+ ts.value = TAG_FORM;
+ self2 = start_element(ELT_HEAD_GEDC_FORM, self1, 2, ts,
+ DEFAULT_GEDCOM_FORM,
+ GEDCOM_MAKE_STRING(val1, DEFAULT_GEDCOM_FORM));
+
+ /* close "2 FORM" */
+ end_element(ELT_HEAD_GEDC_FORM, self1, self2, NULL);
+
+ /* close "1 GEDC" */
+ end_element(ELT_HEAD_GEDC, parent, self1, NULL);
+}
+
+int compat_generate_char(Gedcom_ctxt parent)
+{
+ struct tag_struct ts;
+ Gedcom_ctxt self1;
+
+ /* first generate "1 CHAR <DEFAULT_CHAR>" */
+ ts.string = "CHAR";
+ ts.value = TAG_CHAR;
+ self1 = start_element(ELT_HEAD_CHAR, parent, 1, ts, DEFAULT_CHAR,
+ GEDCOM_MAKE_STRING(val1, DEFAULT_CHAR));
+
+ /* close "1 CHAR" */
+ end_element(ELT_HEAD_CHAR, parent, self1, NULL);
+ if (open_conv_to_internal(DEFAULT_CHAR) == 0)
+ return 1;
+ else
+ return 0;
+}
+
Gedcom_ctxt compat_generate_resi_start(Gedcom_ctxt parent)
{
Gedcom_ctxt self;
#include "gedcom.h"
+extern int compat_at;
+
void compat_generate_submitter_link(Gedcom_ctxt parent);
void compat_generate_submitter();
+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);
char *line_item_buf_ptr;
enum _COMPAT {
- C_FTREE = 0x01
+ C_FTREE = 0x01,
+ C_LIFELINES = 0x02
};
/* These are defined at the bottom of the file */
}
%token_table
-%expect 303
+%expect 304
%token <string> BADTOKEN
%token <number> OPEN
CHECK3(SOUR, GEDC, CHAR);
compat_generate_submitter_link($<ctxt>4);
}
+ else if (compat_mode(C_LIFELINES)) {
+ CHECK1(SOUR);
+ compat_generate_submitter_link($<ctxt>4);
+ compat_generate_gedcom($<ctxt>4);
+ if (compat_generate_char($<ctxt>4)) YYABORT;
+ }
else
CHECK4(SOUR, SUBM, GEDC, CHAR)
}
CLOSE
{ end_record(REC_HEAD, $<ctxt>4);
- if (compat_mode(C_FTREE))
+ if (compat_mode(C_FTREE | C_LIFELINES))
compat_generate_submitter();
}
;
head_sub : head_sour_sect { OCCUR2(SOUR, 1, 1) }
| head_dest_sect { OCCUR2(DEST, 0, 1) }
| head_date_sect { OCCUR2(DATE, 0, 1) }
+ | head_time_sect { if (!compat_mode(C_LIFELINES))
+ INVALID_TAG("TIME");
+ OCCUR2(TIME, 0, 1) }
| head_subm_sect { OCCUR2(SUBM, 1, 1) }
| head_subn_sect { OCCUR2(SUBN, 0, 1) }
| head_file_sect { OCCUR2(FILE, 0, 1) }
}
;
+/* HEAD.TIME (Only for 'Lifelines' compatibility) */
+/* Just ignore the time... */
+head_time_sect : OPEN DELIM TAG_TIME opt_line_item
+ { }
+ CLOSE
+ ;
+
/* HEAD.SUBM */
head_subm_sect : OPEN DELIM TAG_SUBM mand_pointer
{ struct xref_value *xr = gedcom_parse_xref($4, XREF_USED,
$$ = $2; }
;
-mand_line_item : /* empty */ { gedcom_error(_("Missing value")); YYERROR; }
+mand_line_item : /* empty */
+ { if (compat_mode(C_LIFELINES)) {
+ /* Lifelines tends to not care about mandatory values */
+ gedcom_debug_print("==Val: ==");
+ $$ = "";
+ }
+ else {
+ gedcom_error(_("Missing value")); YYERROR;
+ }
+ }
| DELIM line_item { gedcom_debug_print("==Val: %s==", $2);
$$ = $2; }
;
gedcom_warning(_("Enabling compatibility with 'ftree'"));
compatibility = C_FTREE;
}
+ else if (! strncmp(program, "LIFELINES", 9)) {
+ /* Matches "LIFELINES 3.0.2" */
+ gedcom_warning(_("Enabling compatibility with 'Lifelines'"));
+ compatibility = C_LIFELINES;
+ compat_at = 1;
+ }
else {
compatibility = 0;
}
tab [\t]
hash #
literal_at @@
+normal_at @
otherchar [\x21-\x22\x24-\x2F\x3A-\x3F\x5B-\x5E\x60\x7B-\x7E\x80-\xFE]
terminator \x0D|\x0A|\x0D\x0A|\x0A\x0D
<<EOF>> ACTION_EOF
+{normal_at} ACTION_NORMAL_AT
+
. ACTION_UNEXPECTED
%%
tab \x00[\t]
hash \x00#
literal_at \x00@\x00@
+normal_at \x00@
otherchar \x00[\x21-\x22\x24-\x2F\x3A-\x3F\x5B-\x5E\x60\x7B-\x7E\x80-\xFF]|[\x01-\xFF][\x00-\xFF]
terminator \x00\x0D|\x00\x0A|\x00\x0D\x00\x0A|\x00\x0A\x00\x0D
<<EOF>> ACTION_EOF
+{normal_at} ACTION_NORMAL_AT
+
. ACTION_UNEXPECTED
%%
tab [\t]\x00
hash #\x00
literal_at @\x00@\x00
+normal_at @\x00
otherchar [\x21-\x22\x24-\x2F\x3A-\x3F\x5B-\x5E\x60\x7B-\x7E\x80-\xFF]\x00|[\x00-\xFF][\x01-\xFF]
terminator \x0D\x00|\x0A\x00|\x0D\x00\x0A\x00|\x0A\x00\x0D\x00
<<EOF>> ACTION_EOF
+{normal_at} ACTION_NORMAL_AT
+
. ACTION_UNEXPECTED
%%