1 /* Compatibility handling for the GEDCOM parser.
2 Copyright (C) 2001, 2002 The Genes Development Team
3 This file is part of the Gedcom parser library.
4 Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
6 The Gedcom parser library is free software; you can redistribute it
7 and/or modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The Gedcom parser library is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the Gedcom parser library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 #include "interface.h"
29 #include "gedcom_internal.h"
32 int compat_enabled = 1;
33 int compatibility = 0;
34 const char* default_charset = "";
36 #define SUBMITTER_LINK "@__COMPAT__SUBM__@"
37 #define SLGC_FAMC_LINK "@__COMPAT__FAM_SLGC__@"
38 #define DEFAULT_SUBMITTER_NAME "Submitter"
39 #define DEFAULT_GEDCOM_VERS "5.5"
40 #define DEFAULT_GEDCOM_FORM "LINEAGE-LINKED"
48 /* Incompatibility list (with GEDCOM 5.5):
51 - no submitter record, no submitter link in the header
52 - INDI.ADDR instead of INDI.RESI.ADDR
53 - NOTE doesn't have a value
56 - no submitter record, no submitter link in the header
57 - no GEDC field in the header
58 - no CHAR field in the header
59 - HEAD.TIME instead of HEAD.DATE.TIME (will be ignored here)
60 - '@' not written as '@@' in values
61 - lots of missing required values
63 - Personal Ancestral File:
64 - '@' not written as '@@' in values
65 - some 5.5.1 (draft) tags are used: EMAIL, FONE, ROMN
66 - no FAMC field in SLGC
71 /* C_NO_SUBMITTER */ C_FTREE | C_LIFELINES,
72 /* C_INDI_ADDR */ C_FTREE,
73 /* C_NOTE_NO_VALUE */ C_FTREE,
74 /* C_NO_GEDC */ C_LIFELINES,
75 /* C_NO_CHAR */ C_LIFELINES,
76 /* C_HEAD_TIME */ C_LIFELINES,
77 /* C_NO_DOUBLE_AT */ C_LIFELINES | C_PAF,
78 /* C_NO_REQUIRED_VALUES */ C_LIFELINES,
79 /* C_551_TAGS */ C_PAF,
80 /* C_NO_SLGC_FAMC */ C_PAF
83 int compat_state[C_NR_OF_RULES];
85 /* Compatibility handling */
87 void gedcom_set_compat_handling(int enable_compat)
89 compat_enabled = enable_compat;
92 void enable_compat_msg(const char* program_name)
94 gedcom_warning(_("Enabling compatibility with '%s'"), program_name);
97 void set_compatibility(const char* program)
99 /* Reinitialize compatibility */
101 default_charset = "";
103 for (i = 0; i < C_NR_OF_RULES; i++)
106 if (compat_enabled) {
107 if (! strncmp(program, "ftree", 6)) {
108 enable_compat_msg("ftree");
109 compatibility = C_FTREE;
111 else if (! strncmp(program, "LIFELINES", 9)) {
112 /* Matches "LIFELINES 3.0.2" */
113 enable_compat_msg("Lifelines");
114 compatibility = C_LIFELINES;
115 default_charset = "ANSI";
117 else if (! strncmp(program, "PAF", 4)) {
118 enable_compat_msg("Personal Ancestral File");
119 compatibility = C_PAF;
124 int compat_mode(Compat_rule rule)
126 return (compat_matrix[rule] & compatibility);
129 void compat_generate_submitter_link(Gedcom_ctxt parent)
131 struct xref_value *xr = gedcom_parse_xref(SUBMITTER_LINK, XREF_USED,
133 struct tag_struct ts;
138 gedcom_warning(_("Adding link to submitter record with xref '%s'"),
140 self = start_element(ELT_HEAD_SUBM,
141 parent, 1, ts, SUBMITTER_LINK,
142 GEDCOM_MAKE_XREF_PTR(val1, xr));
143 end_element(ELT_HEAD_SUBM, parent, self, NULL);
144 compat_state[C_NO_SUBMITTER] = 1;
147 void compat_generate_submitter()
149 if (compat_state[C_NO_SUBMITTER]) {
150 struct xref_value *xr = gedcom_parse_xref(SUBMITTER_LINK, XREF_DEFINED,
152 struct tag_struct ts;
153 Gedcom_ctxt self1, self2;
155 /* first generate "0 SUBM" */
158 self1 = start_record(REC_SUBM, 0, GEDCOM_MAKE_XREF_PTR(val1, xr), ts,
159 NULL, GEDCOM_MAKE_NULL(val2));
161 /* then generate "1 NAME ..." */
164 self2 = start_element(ELT_SUBM_NAME, self1, 1, ts, DEFAULT_SUBMITTER_NAME,
165 GEDCOM_MAKE_STRING(val1, DEFAULT_SUBMITTER_NAME));
167 /* close "1 NAME ..." */
168 end_element(ELT_SUBM_NAME, self1, self2, NULL);
171 end_record(REC_SUBM, self1, NULL);
172 compat_state[C_NO_SUBMITTER] = 0;
176 void compat_generate_gedcom(Gedcom_ctxt parent)
178 struct tag_struct ts;
179 Gedcom_ctxt self1, self2;
181 /* first generate "1 GEDC" */
184 self1 = start_element(ELT_HEAD_GEDC, parent, 1, ts, NULL,
185 GEDCOM_MAKE_NULL(val1));
187 /* then generate "2 VERS <DEFAULT_GEDC_VERS>" */
190 self2 = start_element(ELT_HEAD_GEDC_VERS, self1, 2, ts,
192 GEDCOM_MAKE_STRING(val1, DEFAULT_GEDCOM_VERS));
195 end_element(ELT_HEAD_GEDC_VERS, self1, self2, NULL);
197 /* then generate "2 FORM <DEFAULT_GEDCOM_FORM> */
200 self2 = start_element(ELT_HEAD_GEDC_FORM, self1, 2, ts,
202 GEDCOM_MAKE_STRING(val1, DEFAULT_GEDCOM_FORM));
205 end_element(ELT_HEAD_GEDC_FORM, self1, self2, NULL);
208 end_element(ELT_HEAD_GEDC, parent, self1, NULL);
211 int compat_generate_char(Gedcom_ctxt parent)
213 struct tag_struct ts;
217 /* first generate "1 CHAR <DEFAULT_CHAR>" */
221 /* Must strdup, because default_charset is const char */
222 charset = strdup(default_charset);
226 self1 = start_element(ELT_HEAD_CHAR, parent, 1, ts, charset,
227 GEDCOM_MAKE_STRING(val1, charset));
231 end_element(ELT_HEAD_CHAR, parent, self1, NULL);
233 if (open_conv_to_internal(default_charset) == 0)
239 Gedcom_ctxt compat_generate_resi_start(Gedcom_ctxt parent)
242 struct tag_struct ts;
246 self = start_element(ELT_SUB_INDIV_RESI, parent, 1, ts, NULL,
247 GEDCOM_MAKE_NULL(val1));
251 void compat_generate_resi_end(Gedcom_ctxt parent, Gedcom_ctxt self)
253 end_element(ELT_SUB_INDIV_RESI, parent, self, NULL);
256 int is_551_tag(const char* tag)
258 if (strncmp(tag, "EMAIL", 6))
260 else if (strncmp(tag, "FONE", 5))
262 else if (strncmp(tag, "ROMN", 5))
268 int compat_check_551_tag(const char* tag, struct safe_buffer* b)
270 if (is_551_tag(tag)) {
272 SAFE_BUF_ADDCHAR(b, '_');
273 safe_buf_append(b, tag);
274 gedcom_warning(_("Converting 5.5.1 tag '%s' to standard 5.5 user tag '%s'"),
275 tag, get_buf_string(b));
282 void compat_generate_slgc_famc_link(Gedcom_ctxt parent)
284 struct xref_value *xr = gedcom_parse_xref(SLGC_FAMC_LINK, XREF_USED,
286 struct tag_struct ts;
291 gedcom_warning(_("Adding link to family record with xref '%s'"),
293 self = start_element(ELT_SUB_LIO_SLGC_FAMC,
294 parent, 2, ts, SLGC_FAMC_LINK,
295 GEDCOM_MAKE_XREF_PTR(val1, xr));
296 end_element(ELT_SUB_LIO_SLGC_FAMC, parent, self, NULL);
297 compat_state[C_NO_SLGC_FAMC]++;
300 void compat_generate_slgc_famc_fam()
302 /* If bigger than 1, then the FAM record has already been generated */
303 if (compat_state[C_NO_SLGC_FAMC] == 1) {
304 struct xref_value *xr = gedcom_parse_xref(SLGC_FAMC_LINK, XREF_DEFINED,
306 struct tag_struct ts;
309 /* generate "0 FAM" */
312 self = start_record(REC_FAM, 0, GEDCOM_MAKE_XREF_PTR(val1, xr), ts,
313 NULL, GEDCOM_MAKE_NULL(val2));
316 end_record(REC_FAM, self, NULL);