1 /* Cross-reference manipulation routines.
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
24 #include "gedcom_internal.h"
26 #include "gedcom.tabgen.h"
30 struct xref_value def_xref_val = { XREF_NONE, "<error>", NULL };
31 static hash_t *xrefs = NULL;
33 const char* xref_type_str[] = { N_("nothing"),
37 N_("a multimedia object"),
38 N_("a source repository"),
41 N_("a submission record"),
42 N_("an application-specific record"),
46 struct xref_value xref;
47 Xref_type defined_type;
54 hnode_t *xref_alloc(void *c __attribute__((unused)))
56 return malloc(sizeof *xref_alloc(NULL));
59 void xref_free(hnode_t *n, void *c __attribute__((unused)))
61 struct xref_node *xr = (struct xref_node *)hnode_get(n);
62 free((void*)hnode_getkey(n));
63 free(xr->xref.string);
68 void clear_xref_node(struct xref_node *xr)
70 xr->xref.type = XREF_NONE;
71 /* Make sure that the 'string' member always contains a valid string */
73 xr->xref.string = strdup("");
74 if (!xr->xref.string) MEMORY_ERROR;
75 xr->xref.object = NULL;
76 xr->defined_type = XREF_NONE;
77 xr->used_type = XREF_NONE;
78 xr->defined_line = -1;
83 struct xref_node *make_xref_node()
85 struct xref_node *xr = (struct xref_node *)malloc(sizeof(struct xref_node));
87 xr->xref.string = NULL;
95 void delete_xref_node(struct xref_node* xr)
98 free(xr->xref.string);
108 void make_xref_table()
113 /* Only register initially (if xrefs is still NULL) */
114 /* So that it is only registered once */
115 if (atexit(cleanup_xrefs) != 0) {
116 gedcom_warning(_("Could not register xref cleanup function"));
118 xrefs = hash_create(HASHCOUNT_T_MAX, NULL, NULL);
119 hash_set_allocator(xrefs, xref_alloc, xref_free, NULL);
122 int check_xref_table()
127 struct xref_node *xr;
129 /* Check for undefined and unused xrefs */
130 hash_scan_begin(&hs, xrefs);
131 while ((node = hash_scan_next(&hs))) {
132 xr = (struct xref_node *)hnode_get(node);
133 if (xr->defined_type == XREF_NONE && xr->used_type != XREF_NONE) {
134 gedcom_error(_("Cross-reference %s used on line %d is not defined"),
135 xr->xref.string, xr->used_line);
138 if (xr->used_type == XREF_NONE && xr->defined_type != XREF_NONE) {
139 gedcom_warning(_("Cross-reference %s defined on line %d is never used"),
140 xr->xref.string, xr->defined_line);
147 struct xref_node* add_xref(Xref_type xref_type, const char* xrefstr,
150 struct xref_node *xr = NULL;
151 const char *key = strdup(xrefstr);
153 xr = make_xref_node();
154 xr->xref.type = xref_type;
155 xr->xref.object = object;
157 free(xr->xref.string);
158 xr->xref.string = strdup(xrefstr);
159 if (! xr->xref.string) MEMORY_ERROR;
160 hash_alloc_insert(xrefs, key, xr);
167 void remove_xref(struct xref_node* xr)
169 hnode_t *node = hash_lookup(xrefs, xr->xref.string);
170 hash_delete_free(xrefs, node);
173 int set_xref_fields(struct xref_node* xr, Xref_ctxt ctxt, Xref_type xref_type)
177 if (xr->defined_type != XREF_NONE && xr->defined_type != xref_type &&
178 xr->defined_type != XREF_ANY) {
179 if (xr->defined_line != 0)
180 gedcom_error(_("Cross-reference %s previously defined as pointer to %s, "
182 xr->xref.string, xref_type_str[xr->defined_type],
185 gedcom_error(_("Cross-reference %s previously defined as pointer to %s"),
186 xr->xref.string, xref_type_str[xr->defined_type]);
190 else if (xr->used_type != XREF_NONE && xr->used_type != xref_type) {
191 if (xr->used_line != 0)
192 gedcom_error(_("Cross-reference %s previously used as pointer to %s, "
194 xr->xref.string, xref_type_str[xr->used_type],
197 gedcom_error(_("Cross-reference %s previously used as pointer to %s"),
198 xr->xref.string, xref_type_str[xr->used_type]);
204 if (ctxt == XREF_USED)
206 if (ctxt == XREF_DEFINED && xr->defined_type == XREF_NONE) {
207 xr->defined_type = xref_type;
208 xr->defined_line = line_no;
210 else if (ctxt == XREF_USED && xr->used_type == XREF_NONE) {
211 xr->used_type = xref_type;
212 xr->used_line = line_no;
219 struct xref_value *gedcom_parse_xref(const char *raw_value,
220 Xref_ctxt ctxt, Xref_type xref_type)
222 struct xref_node *xr = NULL;
224 hnode_t *node = hash_lookup(xrefs, raw_value);
226 xr = (struct xref_node *)hnode_get(node);
229 xr = add_xref(xref_type, raw_value, NULL);
232 set_xref_fields(xr, ctxt, xref_type);
236 /* Functions for retrieving, modifying and deleting cross-references */
238 struct xref_value* gedcom_get_by_xref(const char *key)
240 if (gedcom_check_token(key, STATE_NORMAL, POINTER) != 0) {
241 gedcom_error(_("String '%s' is not a valid cross-reference key"), key);
245 hnode_t *node = hash_lookup(xrefs, key);
247 struct xref_node *xr = (struct xref_node *)hnode_get(node);
255 struct xref_value* gedcom_add_xref(Xref_type type, const char* xrefstr,
258 struct xref_node *xr = NULL;
260 if (gedcom_check_token(xrefstr, STATE_NORMAL, POINTER) != 0) {
261 gedcom_error(_("String '%s' is not a valid cross-reference key"), xrefstr);
264 hnode_t *node = hash_lookup(xrefs, xrefstr);
266 gedcom_error(_("Cross-reference %s already exists"), xrefstr);
269 xr = add_xref(type, xrefstr, object);
270 set_xref_fields(xr, XREF_DEFINED, type);
279 struct xref_value* gedcom_link_xref(Xref_type type, const char* xrefstr)
281 struct xref_node *xr = NULL;
283 if (gedcom_check_token(xrefstr, STATE_NORMAL, POINTER) != 0) {
284 gedcom_error(_("String '%s' is not a valid cross-reference key"), xrefstr);
287 hnode_t *node = hash_lookup(xrefs, xrefstr);
289 gedcom_error(_("Cross-reference %s not defined"), xrefstr);
292 xr = (struct xref_node *)hnode_get(node);
293 if (set_xref_fields(xr, XREF_USED, type) != 0)
304 struct xref_value* gedcom_unlink_xref(Xref_type type, const char* xrefstr)
306 struct xref_node *xr = NULL;
307 if (gedcom_check_token(xrefstr, STATE_NORMAL, POINTER) != 0) {
308 gedcom_error(_("String '%s' is not a valid cross-reference key"), xrefstr);
311 hnode_t *node = hash_lookup(xrefs, xrefstr);
313 gedcom_error(_("Cross-reference %s not defined"), xrefstr);
316 xr = (struct xref_node*) hnode_get(node);
317 if (xr->defined_type != type && xr->defined_type != XREF_ANY) {
319 (_("Cross-reference %s previously defined as pointer to %s"),
320 xr->xref.string, xref_type_str[xr->defined_type]);
333 int gedcom_delete_xref(const char* xrefstr)
335 struct xref_node *xr = NULL;
338 if (gedcom_check_token(xrefstr, STATE_NORMAL, POINTER) != 0) {
339 gedcom_error(_("String '%s' is not a valid cross-reference key"), xrefstr);
342 hnode_t *node = hash_lookup(xrefs, xrefstr);
344 gedcom_error(_("Cross-reference %s not defined"), xrefstr);
347 xr = (struct xref_node*) hnode_get(node);
348 if (xr->use_count != 0) {
349 gedcom_error(_("Cross-reference %s still in use"), xrefstr);