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