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 int compatibility_program = 0;
35 int compatibility_version = 0;
36 const char* default_charset = "";
38 #define SUBMITTER_LINK "@__COMPAT__SUBM__@"
39 #define SLGC_FAMC_LINK "@__COMPAT__FAM_SLGC__@"
40 #define DEFAULT_SUBMITTER_NAME "Submitter"
41 #define DEFAULT_GEDCOM_VERS "5.5"
42 #define DEFAULT_GEDCOM_FORM "LINEAGE-LINKED"
44 enum _COMPAT_PROGRAM {
56 /* Incompatibility list (with GEDCOM 5.5):
59 - no submitter record, no submitter link in the header
60 - INDI.ADDR instead of INDI.RESI.ADDR
61 - NOTE doesn't have a value
64 - no submitter record, no submitter link in the header
65 - no GEDC field in the header
66 - no CHAR field in the header
67 - HEAD.TIME instead of HEAD.DATE.TIME (will be ignored here)
68 - '@' not written as '@@' in values
69 - lots of missing required values
71 - Personal Ancestral File:
72 - '@' not written as '@@' in values
73 - some 5.5.1 (draft) tags are used: EMAIL, FONE, ROMN
74 - no FAMC field in SLGC
79 /* C_NO_SUBMITTER */ C_FTREE | C_LIFELINES,
80 /* C_INDI_ADDR */ C_FTREE,
81 /* C_NOTE_NO_VALUE */ C_FTREE,
82 /* C_NO_GEDC */ C_LIFELINES,
83 /* C_NO_CHAR */ C_LIFELINES,
84 /* C_HEAD_TIME */ C_LIFELINES,
85 /* C_NO_DOUBLE_AT */ C_LIFELINES | C_PAF,
86 /* C_NO_REQUIRED_VALUES */ C_LIFELINES,
87 /* C_551_TAGS */ C_PAF,
88 /* C_NO_SLGC_FAMC */ C_PAF
91 int compat_state[C_NR_OF_RULES];
93 /* Compatibility handling */
95 void gedcom_set_compat_handling(int enable_compat)
97 compat_enabled = enable_compat;
100 void enable_compat_msg(const char* program_name, int version)
103 gedcom_warning(_("Enabling compatibility with '%s', version %d"),
104 program_name, version);
106 gedcom_warning(_("Enabling compatibility with '%s'"),
110 void set_compatibility_program(const char* program)
112 if (compat_enabled) {
113 if (! strncmp(program, "ftree", 6)) {
114 compatibility_program = CP_FTREE;
116 else if (! strncmp(program, "LIFELINES", 9)) {
117 compatibility_program = CP_LIFELINES;
118 if (strlen(program) > 10 && program[9] = ' ')
119 set_compatibility_version(program + 10);
121 else if (! strncmp(program, "PAF", 3)) {
122 compatibility_program = CP_PAF;
123 if (strlen(program) > 4 && program[3] = ' ')
124 set_compatibility_version(program + 4);
129 void set_compatibility_version(const char* version)
131 if (compat_enabled) {
132 unsigned int major=0, minor=0, patch=0;
135 result = sscanf(version, "%u.%u.%u", &major, &minor, &patch);
137 compatibility_version = major * 10000 + minor * 100 + patch;
142 void compute_compatibility()
144 /* Reinitialize compatibility */
146 default_charset = "";
148 for (i = 0; i < C_NR_OF_RULES; i++)
151 switch (compatibility_program) {
153 enable_compat_msg("ftree", 0);
154 compatibility = C_FTREE;
157 enable_compat_msg("Lifelines", 0);
158 compatibility = C_LIFELINES;
159 default_charset = "ANSI";
162 enable_compat_msg("Personal Ancestral File", 0);
163 compatibility = C_PAF;
170 int compat_mode(Compat_rule rule)
172 return (compat_matrix[rule] & compatibility);
175 void compat_generate_submitter_link(Gedcom_ctxt parent)
177 struct xref_value *xr = gedcom_parse_xref(SUBMITTER_LINK, XREF_USED,
179 struct tag_struct ts;
184 gedcom_warning(_("Adding link to submitter record with xref '%s'"),
186 self = start_element(ELT_HEAD_SUBM,
187 parent, 1, ts, SUBMITTER_LINK,
188 GEDCOM_MAKE_XREF_PTR(val1, xr));
189 end_element(ELT_HEAD_SUBM, parent, self, NULL);
190 compat_state[C_NO_SUBMITTER] = 1;
193 void compat_generate_submitter()
195 if (compat_state[C_NO_SUBMITTER]) {
196 struct xref_value *xr = gedcom_parse_xref(SUBMITTER_LINK, XREF_DEFINED,
198 struct tag_struct ts;
199 Gedcom_ctxt self1, self2;
201 /* first generate "0 SUBM" */
204 self1 = start_record(REC_SUBM, 0, GEDCOM_MAKE_XREF_PTR(val1, xr), ts,
205 NULL, GEDCOM_MAKE_NULL(val2));
207 /* then generate "1 NAME ..." */
210 self2 = start_element(ELT_SUBM_NAME, self1, 1, ts, DEFAULT_SUBMITTER_NAME,
211 GEDCOM_MAKE_STRING(val1, DEFAULT_SUBMITTER_NAME));
213 /* close "1 NAME ..." */
214 end_element(ELT_SUBM_NAME, self1, self2, NULL);
217 end_record(REC_SUBM, self1, NULL);
218 compat_state[C_NO_SUBMITTER] = 0;
222 void compat_generate_gedcom(Gedcom_ctxt parent)
224 struct tag_struct ts;
225 Gedcom_ctxt self1, self2;
227 /* first generate "1 GEDC" */
230 self1 = start_element(ELT_HEAD_GEDC, parent, 1, ts, NULL,
231 GEDCOM_MAKE_NULL(val1));
233 /* then generate "2 VERS <DEFAULT_GEDC_VERS>" */
236 self2 = start_element(ELT_HEAD_GEDC_VERS, self1, 2, ts,
238 GEDCOM_MAKE_STRING(val1, DEFAULT_GEDCOM_VERS));
241 end_element(ELT_HEAD_GEDC_VERS, self1, self2, NULL);
243 /* then generate "2 FORM <DEFAULT_GEDCOM_FORM> */
246 self2 = start_element(ELT_HEAD_GEDC_FORM, self1, 2, ts,
248 GEDCOM_MAKE_STRING(val1, DEFAULT_GEDCOM_FORM));
251 end_element(ELT_HEAD_GEDC_FORM, self1, self2, NULL);
254 end_element(ELT_HEAD_GEDC, parent, self1, NULL);
257 int compat_generate_char(Gedcom_ctxt parent)
259 struct tag_struct ts;
263 /* first generate "1 CHAR <DEFAULT_CHAR>" */
267 /* Must strdup, because default_charset is const char */
268 charset = strdup(default_charset);
272 self1 = start_element(ELT_HEAD_CHAR, parent, 1, ts, charset,
273 GEDCOM_MAKE_STRING(val1, charset));
277 end_element(ELT_HEAD_CHAR, parent, self1, NULL);
279 if (open_conv_to_internal(default_charset) == 0)
285 Gedcom_ctxt compat_generate_resi_start(Gedcom_ctxt parent)
288 struct tag_struct ts;
292 self = start_element(ELT_SUB_INDIV_RESI, parent, 1, ts, NULL,
293 GEDCOM_MAKE_NULL(val1));
297 void compat_generate_resi_end(Gedcom_ctxt parent, Gedcom_ctxt self)
299 end_element(ELT_SUB_INDIV_RESI, parent, self, NULL);
302 int is_551_tag(const char* tag)
304 if (strncmp(tag, "EMAIL", 6))
306 else if (strncmp(tag, "FONE", 5))
308 else if (strncmp(tag, "ROMN", 5))
314 int compat_check_551_tag(const char* tag, struct safe_buffer* b)
316 if (is_551_tag(tag)) {
318 SAFE_BUF_ADDCHAR(b, '_');
319 safe_buf_append(b, tag);
320 gedcom_warning(_("Converting 5.5.1 tag '%s' to standard 5.5 user tag '%s'"),
321 tag, get_buf_string(b));
328 void compat_generate_slgc_famc_link(Gedcom_ctxt parent)
330 struct xref_value *xr = gedcom_parse_xref(SLGC_FAMC_LINK, XREF_USED,
332 struct tag_struct ts;
337 gedcom_warning(_("Adding link to family record with xref '%s'"),
339 self = start_element(ELT_SUB_LIO_SLGC_FAMC,
340 parent, 2, ts, SLGC_FAMC_LINK,
341 GEDCOM_MAKE_XREF_PTR(val1, xr));
342 end_element(ELT_SUB_LIO_SLGC_FAMC, parent, self, NULL);
343 compat_state[C_NO_SLGC_FAMC]++;
346 void compat_generate_slgc_famc_fam()
348 /* If bigger than 1, then the FAM record has already been generated */
349 if (compat_state[C_NO_SLGC_FAMC] == 1) {
350 struct xref_value *xr = gedcom_parse_xref(SLGC_FAMC_LINK, XREF_DEFINED,
352 struct tag_struct ts;
355 /* generate "0 FAM" */
358 self = start_record(REC_FAM, 0, GEDCOM_MAKE_XREF_PTR(val1, xr), ts,
359 NULL, GEDCOM_MAKE_NULL(val2));
362 end_record(REC_FAM, self, NULL);