Separate the modification of GCONV_PATH from the rest of the initialization,
[gedcom-parse.git] / gedcom / xref.c
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.
5
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.
10
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.
15
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
19    02111-1307 USA.  */
20
21 /* $Id$ */
22 /* $Name$ */
23
24 #include "gedcom_internal.h"
25 #include "xref.h"
26 #include "hash.h"
27
28 struct xref_value def_xref_val = { XREF_NONE, "<error>", NULL };
29 static hash_t *xrefs = NULL;
30
31 char* xref_type_str[] = { N_("nothing"),
32                           N_("a family"),
33                           N_("an individual"),
34                           N_("a note"),
35                           N_("a multimedia object"),
36                           N_("a source repository"),
37                           N_("a source"),
38                           N_("a submitter"),
39                           N_("a submission record"),
40                           N_("an application-specific record"),
41                         };
42
43 struct xref_node {
44   struct xref_value xref;
45   Xref_type defined_type;
46   Xref_type used_type;
47   int defined_line;
48   int used_line;
49 };
50
51 hnode_t *xref_alloc(void *c __attribute__((unused)))
52 {
53   return malloc(sizeof *xref_alloc(NULL));
54 }
55
56 void xref_free(hnode_t *n, void *c __attribute__((unused)))
57 {
58   struct xref_node *xr = (struct xref_node *)hnode_get(n);
59   free((void*)hnode_getkey(n));
60   free(xr->xref.string);
61   free(xr);
62   free(n);
63 }
64
65 struct xref_node *make_xref_node()
66 {
67   struct xref_node *xr = (struct xref_node *)malloc(sizeof(struct xref_node));
68   xr->xref.type    = XREF_NONE;
69   xr->xref.string  = NULL;
70   xr->xref.object  = NULL;
71   xr->defined_type = XREF_NONE;
72   xr->used_type    = XREF_NONE;
73   xr->defined_line = -1;
74   xr->used_line    = -1;
75   return xr;
76 }
77
78 void make_xref_table()
79 {
80   xrefs = hash_create(HASHCOUNT_T_MAX, NULL, NULL);
81   hash_set_allocator(xrefs, xref_alloc, xref_free, NULL);
82 }
83
84 int check_xref_table()
85 {
86   int result = 0;
87   hscan_t hs;
88   hnode_t *node;
89   struct xref_node *xr;
90
91   /* Check for undefined and unused xrefs */
92   hash_scan_begin(&hs, xrefs);
93   while ((node = hash_scan_next(&hs))) {
94     xr = (struct xref_node *)hnode_get(node);
95     if (xr->defined_type == XREF_NONE && xr->used_type != XREF_NONE) {
96       gedcom_error(_("Cross-reference %s used on line %d is not defined"),
97                    xr->xref.string, xr->used_line);
98       result |= 1;
99     }
100     if (xr->used_type == XREF_NONE && xr->defined_type != XREF_NONE) {
101       gedcom_warning(_("Cross-reference %s defined on line %d is never used"),
102                      xr->xref.string, xr->defined_line);
103     }
104   }
105   
106   hash_free(xrefs);
107   return result;
108 }
109
110 struct xref_value *gedcom_parse_xref(char *raw_value,
111                                      Xref_ctxt ctxt, Xref_type xref_type)
112 {
113   struct xref_node *xr = NULL;
114   
115   hnode_t *node = hash_lookup(xrefs, raw_value);
116   if (node) {
117     xr = (struct xref_node *)hnode_get(node);
118   }
119   else {
120     char *key = strdup(raw_value);
121     xr = make_xref_node();
122     xr->xref.type = xref_type;
123     xr->xref.string = strdup(raw_value);
124     hash_alloc_insert(xrefs, key, xr);
125   }
126     
127   if (ctxt == XREF_DEFINED && xr->defined_type == XREF_NONE) {
128     xr->defined_type = xref_type;
129     xr->defined_line = line_no;
130   }
131   else if (ctxt == XREF_USED && xr->used_type == XREF_NONE) {
132     xr->used_type = xref_type;
133     xr->used_line = line_no;
134   }
135   
136   if ((ctxt == XREF_DEFINED && xr->defined_type != xref_type)
137       || (ctxt == XREF_USED &&
138           (xr->defined_type != XREF_NONE && xr->defined_type != xref_type))) {
139     gedcom_error(_("Cross-reference %s previously defined as pointer to %s, "
140                    "on line %d"),
141                  xr->xref.string, xref_type_str[xr->defined_type],
142                  xr->defined_line);
143     return NULL;
144   }
145   
146   if ((ctxt == XREF_USED && xr->used_type != xref_type)
147       || (ctxt == XREF_DEFINED &&
148           (xr->used_type != XREF_NONE && xr->used_type != xref_type))) {
149     gedcom_error(_("Cross-reference %s previously used as pointer to %s, "
150                    "on line %d"),
151                  xr->xref.string, xref_type_str[xr->used_type], xr->used_line);
152     return NULL;
153   }
154   
155   return &(xr->xref);
156 }