Completed writing of strings and xrefs.
[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 struct date_value* dup_date(struct date_value dv);
113 struct age_value*  dup_age(struct age_value age);
114
115 /* Doubly-linked list, but last rec->next is NULL (doesn't go to first rec) */
116 #define LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
117   {                                                                           \
118     struct STRUCTTYPE *_local_obj = VAL;                                      \
119     if (! FIRSTVAL) {                                                         \
120       VAL->next = NULL;                                                       \
121       VAL->previous = _local_obj;                                             \
122       FIRSTVAL = VAL;                                                         \
123     }                                                                         \
124     else {                                                                    \
125       VAL->next = NULL;                                                       \
126       FIRSTVAL->previous->next = VAL;                                         \
127       VAL->previous = FIRSTVAL->previous;                                     \
128       FIRSTVAL->previous = VAL;                                               \
129     }                                                                         \
130   }
131
132 #define MAKE_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
133   {                                                                           \
134     VAL = (struct STRUCTTYPE*) malloc(sizeof(struct STRUCTTYPE));             \
135     if (! VAL)                                                                \
136       MEMORY_ERROR;                                                           \
137     else {                                                                    \
138       memset (VAL, 0, sizeof(struct STRUCTTYPE));                             \
139       LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                               \
140     }                                                                         \
141   }
142
143 void NULL_DESTROY(void* anything);
144
145 #define DESTROY_CHAIN_ELTS(STRUCTTYPE, FIRSTVAL, DESTROYFUNC)                 \
146   {                                                                           \
147     if (FIRSTVAL) {                                                           \
148       struct STRUCTTYPE *runner, *next;                                       \
149       runner = FIRSTVAL;                                                      \
150       while (runner) {                                                        \
151         next = runner->next;                                                  \
152         DESTROYFUNC(runner);                                                  \
153         SAFE_FREE(runner);                                                    \
154         runner = next;                                                        \
155       }                                                                       \
156     }                                                                         \
157   }
158
159 #define _REC_PARAMS_ Gedcom_rec rec UNUSED, int level UNUSED,                 \
160                      Gedcom_val xref UNUSED, char *tag UNUSED,                \
161                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
162                      Gedcom_val parsed_value UNUSED
163
164 #define _REC_END_PARAMS_ Gedcom_rec rec UNUSED, Gedcom_ctxt self UNUSED,      \
165                          Gedcom_val parsed_value UNUSED
166
167 #define _ELT_PARAMS_ Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,        \
168                      int level UNUSED, char *tag UNUSED,                      \
169                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
170                      Gedcom_val parsed_value UNUSED
171
172 #define _ELT_END_PARAMS_ Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,    \
173                          Gedcom_ctxt self UNUSED,                             \
174                          Gedcom_val parsed_value UNUSED
175
176 #define REC_CB(STRUCTTYPE,CB_NAME,FUNC)                                       \
177   Gedcom_ctxt CB_NAME(_REC_PARAMS_)                                           \
178   {                                                                           \
179     struct xref_value* xr = GEDCOM_XREF_PTR(xref);                            \
180     if (! xr->object)                                                         \
181       xr->object = (Gedcom_ctxt) FUNC(xr->string);                            \
182     if (xr->object)                                                           \
183       return (Gedcom_ctxt) MAKE_GOM_CTXT(rec, STRUCTTYPE, xr->object);        \
184     else                                                                      \
185       return NULL;                                                            \
186   }
187
188 #define GET_REC_BY_XREF(STRUCTTYPE,XREF_TYPE,FUNC_NAME)                       \
189   struct STRUCTTYPE *FUNC_NAME(const char *xrefstr)                           \
190   {                                                                           \
191     struct xref_value* xr = gedcom_get_by_xref(xrefstr);                      \
192     if (xr && (xr->type == XREF_TYPE) && xr->object)                          \
193       return (struct STRUCTTYPE*)(xr->object);                                \
194     else                                                                      \
195       return NULL;                                                            \
196   }
197
198 #define STRING_CB(STRUCTTYPE,CB_NAME,FIELD)                                   \
199   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
200   {                                                                           \
201     Gom_ctxt result = NULL;                                                   \
202     if (! parent)                                                             \
203       NO_CONTEXT;                                                             \
204     else {                                                                    \
205       struct STRUCTTYPE *obj                                                  \
206         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
207       if (obj) {                                                              \
208         char *str = GEDCOM_STRING(parsed_value);                              \
209         obj->FIELD = strdup(str);                                             \
210         if (! obj->FIELD)                                                     \
211           MEMORY_ERROR;                                                       \
212         else                                                                  \
213           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
214       }                                                                       \
215     }                                                                         \
216     return (Gedcom_ctxt)result;                                               \
217   }
218
219 #define STRING_END_CB(STRUCTTYPE,CB_NAME,FIELD)                               \
220   void CB_NAME(_ELT_END_PARAMS_)                                              \
221   {                                                                           \
222     Gom_ctxt ctxt = (Gom_ctxt)self;                                           \
223     if (! ctxt)                                                               \
224       NO_CONTEXT;                                                             \
225     else {                                                                    \
226       struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);              \
227       if (obj) {                                                              \
228         char *str = GEDCOM_STRING(parsed_value);                              \
229         char *newvalue = strdup(str);                                         \
230         if (! newvalue)                                                       \
231           MEMORY_ERROR;                                                       \
232         else                                                                  \
233           obj->FIELD = newvalue;                                              \
234       }                                                                       \
235       destroy_gom_ctxt(ctxt);                                                 \
236     }                                                                         \
237   }
238
239 #define STRING_END_REC_CB(STRUCTTYPE,CB_NAME,FIELD)                           \
240   void CB_NAME(_REC_END_PARAMS_)                                              \
241   {                                                                           \
242     Gom_ctxt ctxt = (Gom_ctxt)self;                                           \
243     if (! ctxt)                                                               \
244       NO_CONTEXT;                                                             \
245     else {                                                                    \
246       struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);              \
247       if (obj) {                                                              \
248         char *str = GEDCOM_STRING(parsed_value);                              \
249         char *newvalue = strdup(str);                                         \
250         if (! newvalue)                                                       \
251           MEMORY_ERROR;                                                       \
252         else                                                                  \
253           obj->FIELD = newvalue;                                              \
254       }                                                                       \
255       destroy_gom_ctxt(ctxt);                                                 \
256     }                                                                         \
257   }
258
259 #define DATE_CB(STRUCTTYPE,CB_NAME,FIELD)                                     \
260   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
261   {                                                                           \
262     Gom_ctxt result = NULL;                                                   \
263     if (! parent)                                                             \
264       NO_CONTEXT;                                                             \
265     else {                                                                    \
266       struct STRUCTTYPE *obj                                                  \
267         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
268       if (obj) {                                                              \
269         struct date_value dv = GEDCOM_DATE(parsed_value);                     \
270         obj->FIELD = dup_date(dv);                                            \
271         if (! obj->FIELD)                                                     \
272           MEMORY_ERROR;                                                       \
273         else                                                                  \
274           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
275       }                                                                       \
276     }                                                                         \
277     return (Gedcom_ctxt)result;                                               \
278   }
279
280 #define AGE_CB(STRUCTTYPE,CB_NAME,FIELD)                                      \
281   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
282   {                                                                           \
283     Gom_ctxt result = NULL;                                                   \
284     if (! parent)                                                             \
285       NO_CONTEXT;                                                             \
286     else {                                                                    \
287       struct STRUCTTYPE *obj                                                  \
288         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
289       if (obj) {                                                              \
290         struct age_value age = GEDCOM_AGE(parsed_value);                      \
291         obj->FIELD = dup_age(age);                                            \
292         if (! obj->FIELD)                                                     \
293           MEMORY_ERROR;                                                       \
294         else                                                                  \
295           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
296       }                                                                       \
297     }                                                                         \
298     return (Gedcom_ctxt)result;                                               \
299   }
300
301 #define XREF_CB(STRUCTTYPE,CB_NAME,FIELD,FUNC)                                \
302   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
303   {                                                                           \
304     Gom_ctxt result = NULL;                                                   \
305     if (! parent)                                                             \
306       NO_CONTEXT;                                                             \
307     else {                                                                    \
308       struct STRUCTTYPE *obj                                                  \
309         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
310       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
311       if (! xr->object)                                                       \
312         xr->object = (Gedcom_ctxt) FUNC(xr->string);                          \
313       if (obj) {                                                              \
314         obj->FIELD = xr;                                                      \
315         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
316       }                                                                       \
317     }                                                                         \
318     return (Gedcom_ctxt)result;                                               \
319   }
320
321 #define XREF_LIST_CB(STRUCTTYPE,CB_NAME,FIELD,FUNC)                           \
322   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
323   {                                                                           \
324     Gom_ctxt result = NULL;                                                   \
325     if (! parent)                                                             \
326       NO_CONTEXT;                                                             \
327     else {                                                                    \
328       struct STRUCTTYPE *obj                                                  \
329         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
330       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
331       struct xref_list *xrl;                                                  \
332       if (! xr->object)                                                       \
333         xr->object = (Gedcom_ctxt) FUNC(xr->string);                          \
334       if (obj) {                                                              \
335         MAKE_CHAIN_ELT(xref_list, obj->FIELD, xrl);                           \
336         if (xrl) {                                                            \
337           xrl->xref = xr;                                                     \
338           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
339         }                                                                     \
340       }                                                                       \
341     }                                                                         \
342     return (Gedcom_ctxt)result;                                               \
343   }
344
345 #define NULL_CB(STRUCTTYPE,CB_NAME)                                           \
346   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
347   {                                                                           \
348     Gom_ctxt result = NULL;                                                   \
349     if (! parent)                                                             \
350       NO_CONTEXT;                                                             \
351     else {                                                                    \
352       struct STRUCTTYPE *obj                                                  \
353         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
354       if (obj)                                                                \
355         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
356     }                                                                         \
357     return (Gedcom_ctxt)result;                                               \
358   }
359
360 #endif /* __GOM_INTERNAL_H */