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