More thorough error handling.
[gedcom-parse.git] / gom / gom_internal.h
1 /* General header for 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 #ifndef __GOM_INTERNAL_H
25 #define __GOM_INTERNAL_H
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <libintl.h>
30 #include "gom.h"
31 #include "gedcom.h"
32 #ifdef WITH_DMALLOC
33 #include <dmalloc.h>
34 #endif
35       
36 #define _(string) gettext(string)
37 #define N_(string) (string)
38
39 typedef enum {
40   T_NULL,
41   
42   T_header, T_submission, T_submitter, T_family, T_individual,
43   T_multimedia, T_note, T_repository, T_source, T_user_rec,
44   
45   T_address, T_event, T_place, T_source_citation, T_text,
46   T_note_sub, T_multimedia_link, T_lds_event, T_user_ref_number,
47   T_change_date, T_personal_name, T_family_link, T_pedigree,
48   T_association, T_source_event, T_source_description
49 } OBJ_TYPE;
50
51 /* Assumptions for context:
52     - In case of error, NULL is passed as context
53     - If not NULL, the ctxt_ptr of the context is not NULL also
54     - UNEXPECTED_CONTEXT is not treated as an error, but as a warning
55 */
56
57 struct Gom_ctxt_struct {
58   int ctxt_type;
59   OBJ_TYPE obj_type;
60   void* ctxt_ptr;
61 };
62
63 typedef struct Gom_ctxt_struct *Gom_ctxt;
64
65 Gom_ctxt make_gom_ctxt(int ctxt_type, OBJ_TYPE obj_type, void *ctxt_ptr);
66 void destroy_gom_ctxt(Gom_ctxt ctxt);
67 void gom_cast_error(char* file, int line, OBJ_TYPE expected, OBJ_TYPE found);
68 void gom_no_context(char* file, int line);
69 void gom_unexpected_context(char* file, int line, OBJ_TYPE found);
70
71 #define MAKE_GOM_CTXT(CTXT_TYPE, STRUCTTYPE, CTXT_PTR)                        \
72   make_gom_ctxt(CTXT_TYPE, T_ ## STRUCTTYPE, CTXT_PTR)
73
74 #define SAFE_CTXT_CAST(STRUCTTYPE, VAL)                                       \
75   (((VAL)->obj_type == T_ ## STRUCTTYPE) ?                                    \
76    (VAL)->ctxt_ptr :                                                          \
77    (gom_cast_error(__FILE__, __LINE__, T_ ## STRUCTTYPE, (VAL)->obj_type),    \
78     (VAL)->ctxt_ptr))
79
80 #define SAFE_FREE(PTR)                                                        \
81   if (PTR) {                                                                  \
82     free(PTR);                                                                \
83     PTR = NULL;                                                               \
84   }
85
86 #define UNEXPECTED_CONTEXT(CTXT_TYPE)                                         \
87   gom_unexpected_context(__FILE__, __LINE__, CTXT_TYPE)
88
89 #define NO_CONTEXT                                                            \
90   gom_no_context(__FILE__, __LINE__)
91
92 void gom_mem_error(char *filename, int line);
93
94 #define MEMORY_ERROR gom_mem_error(__FILE__, __LINE__)
95
96 void def_rec_end(Gedcom_rec rec, Gedcom_ctxt self);
97 void def_elt_end(Gedcom_elt elt, Gedcom_ctxt parent, Gedcom_ctxt self,
98                  Gedcom_val parsed_value);
99 void set_xref_type(struct xref_value *xr, char* str);
100
101 typedef enum {
102   WITHOUT_NL,
103   WITH_NL
104 } NL_TYPE;
105
106 char* concat_strings(NL_TYPE type, char *str1, const char *str2);
107 struct date_value* dup_date(struct date_value dv);
108 struct age_value*  dup_age(struct age_value age);
109
110 /* Doubly-linked list, but last rec->next is NULL (doesn't go to first rec) */
111 #define LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
112   {                                                                           \
113     struct STRUCTTYPE *_local_obj = VAL;                                      \
114     if (! FIRSTVAL) {                                                         \
115       VAL->next = NULL;                                                       \
116       VAL->previous = _local_obj;                                             \
117       FIRSTVAL = VAL;                                                         \
118     }                                                                         \
119     else {                                                                    \
120       VAL->next = NULL;                                                       \
121       FIRSTVAL->previous->next = VAL;                                         \
122       VAL->previous = FIRSTVAL->previous;                                     \
123       FIRSTVAL->previous = VAL;                                               \
124     }                                                                         \
125   }
126
127 #define MAKE_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
128   {                                                                           \
129     VAL = (struct STRUCTTYPE*) malloc(sizeof(struct STRUCTTYPE));             \
130     if (! VAL)                                                                \
131       MEMORY_ERROR;                                                           \
132     else {                                                                    \
133       memset (VAL, 0, sizeof(struct STRUCTTYPE));                             \
134       LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                               \
135     }                                                                         \
136   }
137
138 void NULL_DESTROY(void* anything);
139
140 #define DESTROY_CHAIN_ELTS(STRUCTTYPE, FIRSTVAL, DESTROYFUNC)                 \
141   {                                                                           \
142     if (FIRSTVAL) {                                                           \
143       struct STRUCTTYPE *runner, *next;                                       \
144       runner = FIRSTVAL;                                                      \
145       while (runner) {                                                        \
146         next = runner->next;                                                  \
147         DESTROYFUNC(runner);                                                  \
148         SAFE_FREE(runner);                                                    \
149         runner = next;                                                        \
150       }                                                                       \
151     }                                                                         \
152   }
153
154 #define _REC_PARAMS_ Gedcom_rec rec, int level, Gedcom_val xref, char *tag,   \
155                      char *raw_value, int parsed_tag, Gedcom_val parsed_value
156
157 #define _ELT_PARAMS_ Gedcom_elt elt, Gedcom_ctxt parent, int level, char *tag,\
158                      char *raw_value, int parsed_tag, Gedcom_val parsed_value
159
160 #define REC_CB(STRUCTTYPE,CB_NAME,FUNC)                                       \
161   Gedcom_ctxt CB_NAME(_REC_PARAMS_)                                           \
162   {                                                                           \
163     struct xref_value* xr = GEDCOM_XREF_PTR(xref);                            \
164     if (! xr->object)                                                         \
165       xr->object = (Gedcom_ctxt) FUNC(xr->string);                            \
166     if (xr->object)                                                           \
167       return (Gedcom_ctxt) MAKE_GOM_CTXT(rec, STRUCTTYPE, xr->object);        \
168     else                                                                      \
169       return NULL;                                                            \
170   }
171
172 #define GET_REC_BY_XREF(STRUCTTYPE,XREF_TYPE,FUNC_NAME)                       \
173   struct STRUCTTYPE *FUNC_NAME(char *xrefstr)                                 \
174   {                                                                           \
175     struct xref_value* xr = gedcom_get_by_xref(xrefstr);                      \
176     if (xr && (xr->type == XREF_TYPE) && xr->object)                          \
177       return (struct STRUCTTYPE*)(xr->object);                                \
178     else                                                                      \
179       return NULL;                                                            \
180   }
181
182 #define STRING_CB(STRUCTTYPE,CB_NAME,FIELD)                                   \
183   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
184   {                                                                           \
185     Gom_ctxt result = NULL;                                                   \
186     if (! parent)                                                             \
187       NO_CONTEXT;                                                             \
188     else {                                                                    \
189       struct STRUCTTYPE *obj                                                  \
190         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
191       if (obj) {                                                              \
192         char *str = GEDCOM_STRING(parsed_value);                              \
193         obj->FIELD = strdup(str);                                             \
194         if (! obj->FIELD)                                                     \
195           MEMORY_ERROR;                                                       \
196         else                                                                  \
197           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
198       }                                                                       \
199     }                                                                         \
200     return (Gedcom_ctxt)result;                                               \
201   }
202
203 #define DATE_CB(STRUCTTYPE,CB_NAME,FIELD)                                     \
204   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
205   {                                                                           \
206     Gom_ctxt result = NULL;                                                   \
207     if (! parent)                                                             \
208       NO_CONTEXT;                                                             \
209     else {                                                                    \
210       struct STRUCTTYPE *obj                                                  \
211         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
212       if (obj) {                                                              \
213         struct date_value dv = GEDCOM_DATE(parsed_value);                     \
214         obj->FIELD = dup_date(dv);                                            \
215         if (! obj->FIELD)                                                     \
216           MEMORY_ERROR;                                                       \
217         else                                                                  \
218           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
219       }                                                                       \
220     }                                                                         \
221     return (Gedcom_ctxt)result;                                               \
222   }
223
224 #define AGE_CB(STRUCTTYPE,CB_NAME,FIELD)                                      \
225   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
226   {                                                                           \
227     Gom_ctxt result = NULL;                                                   \
228     if (! parent)                                                             \
229       NO_CONTEXT;                                                             \
230     else {                                                                    \
231       struct STRUCTTYPE *obj                                                  \
232         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
233       if (obj) {                                                              \
234         struct age_value age = GEDCOM_AGE(parsed_value);                      \
235         obj->FIELD = dup_age(age);                                            \
236         if (! obj->FIELD)                                                     \
237           MEMORY_ERROR;                                                       \
238         else                                                                  \
239           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
240       }                                                                       \
241     }                                                                         \
242     return (Gedcom_ctxt)result;                                               \
243   }
244
245 #define XREF_CB(STRUCTTYPE,CB_NAME,FIELD,FUNC)                                \
246   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
247   {                                                                           \
248     Gom_ctxt result = NULL;                                                   \
249     if (! parent)                                                             \
250       NO_CONTEXT;                                                             \
251     else {                                                                    \
252       struct STRUCTTYPE *obj                                                  \
253         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
254       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
255       if (! xr->object)                                                       \
256         xr->object = (Gedcom_ctxt) FUNC(xr->string);                          \
257       if (obj) {                                                              \
258         obj->FIELD = xr;                                                      \
259         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
260       }                                                                       \
261     }                                                                         \
262     return (Gedcom_ctxt)result;                                               \
263   }
264
265 #define XREF_LIST_CB(STRUCTTYPE,CB_NAME,FIELD,FUNC)                           \
266   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
267   {                                                                           \
268     Gom_ctxt result = NULL;                                                   \
269     if (! parent)                                                             \
270       NO_CONTEXT;                                                             \
271     else {                                                                    \
272       struct STRUCTTYPE *obj                                                  \
273         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
274       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
275       struct xref_list *xrl;                                                  \
276       if (! xr->object)                                                       \
277         xr->object = (Gedcom_ctxt) FUNC(xr->string);                          \
278       if (obj) {                                                              \
279         MAKE_CHAIN_ELT(xref_list, obj->FIELD, xrl);                           \
280         if (xrl) {                                                            \
281           xrl->xref = xr;                                                     \
282           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
283         }                                                                     \
284       }                                                                       \
285     }                                                                         \
286     return (Gedcom_ctxt)result;                                               \
287   }
288
289 #define NULL_CB(STRUCTTYPE,CB_NAME)                                           \
290   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
291   {                                                                           \
292     Gom_ctxt result = NULL;                                                   \
293     if (! parent)                                                             \
294       NO_CONTEXT;                                                             \
295     else {                                                                    \
296       struct STRUCTTYPE *obj                                                  \
297         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
298       if (obj)                                                                \
299         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
300     }                                                                         \
301     return (Gedcom_ctxt)result;                                               \
302   }
303
304 #endif /* __GOM_INTERNAL_H */