Allow elements out of context in GOM.
[gedcom-parse.git] / gom / gom_internal.c
1 /* Internals for building the gedcom object model.
2    Copyright (C) 2002 The Genes Development Team
3    This file is part of the Gedcom parser library.
4    Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2002.
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 "gom.h"
25 #include "gom_internal.h"
26
27 const char* ctxt_names[] =
28 {
29   "NULL",
30   
31   "header", "submission", "submitter", "family", "individual",
32   "multimedia", "note", "repository", "source", "user_rec",
33   
34   "address", "event", "place", "source_citation", "text",
35   "note_sub", "multimedia_link", "lds_event", "user_ref_number",
36   "change_date", "personal_name", "family_link", "pedigree",
37   "association", "source_event", "source_description"
38 };
39
40 /* Assumptions for context:
41     - In case of error, NULL is passed as context
42     - If not NULL, the ctxt_ptr of the context is not NULL also
43     - UNEXPECTED_CONTEXT is not treated as an error, but as a warning
44
45    The context chain keeps contexts until the end of the record, so that
46    elements out of context can be handled.
47 */
48
49 struct Gom_ctxt_struct {
50   int ctxt_type;
51   OBJ_TYPE obj_type;
52   void* ctxt_ptr;
53   struct Gom_ctxt_struct* next;
54 };
55
56 struct Gom_ctxt_struct* ctxt_chain = NULL;
57
58 Gom_ctxt make_gom_ctxt(int ctxt_type, OBJ_TYPE obj_type, void *ctxt_ptr)
59 {
60   Gom_ctxt ctxt   = (Gom_ctxt)malloc(sizeof(struct Gom_ctxt_struct));
61   if (! ctxt)
62     MEMORY_ERROR;
63   else {
64     ctxt->ctxt_type = ctxt_type;
65     ctxt->obj_type  = obj_type;
66     ctxt->ctxt_ptr  = ctxt_ptr;
67     ctxt->next      = ctxt_chain;
68     ctxt_chain      = ctxt;
69   }
70   return ctxt;
71 }
72
73 Gom_ctxt dup_gom_ctxt(Gom_ctxt ctxt, int ctxt_type)
74 {
75   return make_gom_ctxt(ctxt_type, ctxt->obj_type, ctxt->ctxt_ptr);
76 }
77
78 int ctxt_type(Gom_ctxt ctxt)
79 {
80   return ctxt->ctxt_type;
81 }
82
83 OBJ_TYPE ctxt_obj_type(Gom_ctxt ctxt)
84 {
85   return ctxt->obj_type;
86 }
87
88 void* safe_ctxt_cast(Gom_ctxt ctxt, OBJ_TYPE type, const char* file, int line)
89 {
90   if (ctxt->obj_type != type) {
91     gom_cast_error(file, line, type, ctxt->obj_type);
92   }
93   return ctxt->ctxt_ptr;
94 }
95
96 void NULL_DESTROY(void* anything UNUSED)
97 {
98 }
99
100 void destroy_gom_ctxt(Gom_ctxt ctxt)
101 {
102   SAFE_FREE(ctxt);
103 }
104
105 void gom_cast_error(const char* file, int line,
106                     OBJ_TYPE expected, OBJ_TYPE found)
107 {
108   const char* expected_name = "<out-of-bounds>";
109   const char* found_name    = "<out-of-bounds>";
110   if (expected < T_LAST)
111     expected_name = ctxt_names[expected];
112   if (found < T_LAST)
113     found_name = ctxt_names[found];
114   fprintf(stderr,
115           "Wrong gom ctxt cast at %s, line %d: expected %s, found %s\n",
116           file, line, expected_name, found_name);
117   abort();
118 }
119
120 void gom_unexpected_context(const char* file, int line, OBJ_TYPE found)
121 {
122   const char* found_name    = "<out-of-bounds>";
123   if (found < T_LAST)
124     found_name = ctxt_names[found];
125   gedcom_warning(_("Internal error: Unexpected context at %s, line %d: %s"),
126                  file, line, found_name);
127 }
128
129 void gom_no_context(const char* file, int line)
130 {
131   gedcom_warning(_("Internal error: No context at %s, line %d"),
132                  file, line);
133 }
134
135 void def_rec_end(Gedcom_rec rec UNUSED, Gedcom_ctxt self UNUSED,
136                  Gedcom_val parsed_value UNUSED)
137 {
138   Gom_ctxt ctxt;
139   while (ctxt_chain) {
140     ctxt = ctxt_chain;
141     ctxt_chain = ctxt->next;
142     destroy_gom_ctxt(ctxt);
143   }
144 }
145
146 void def_elt_end(Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,
147                  Gedcom_ctxt self UNUSED, Gedcom_val parsed_value UNUSED)
148 {
149 }