#include "interface.h"
#include "encoding.h"
#include "xref.h"
+#include "buffer.h"
#include "gedcom_internal.h"
#include "gedcom.h"
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):
- 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[] =
/* 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 */
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;
+ }
}
}
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)
{
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);
+ }
+}
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);
#TAG, parenttag); \
HANDLE_ERROR; \
} \
- }
+ }
+#define CHK_COND(TAG) \
+ check_occurrence(TAG_##TAG)
#define POP \
{ pop_countarray(); \
--count_level; \
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);
}
;
-/* 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"));
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 */
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));
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
;
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
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 {
cleanup_buffer(&line_item_buffer);
}
+void cleanup_usertag_buffer()
+{
+ cleanup_buffer(&usertag_buffer);
+}
+
/* Enabling debug mode */
/* level 0: no debugging */
/* level 1: only internal */