Beginnings of write support.
[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 #define MAKE_GOM_CTXT(CTXT_TYPE, STRUCTTYPE, CTXT_PTR)                        \
79   make_gom_ctxt(CTXT_TYPE, T_ ## STRUCTTYPE, CTXT_PTR)
80
81 #define SAFE_CTXT_CAST(STRUCTTYPE, VAL)                                       \
82   (((VAL)->obj_type == T_ ## STRUCTTYPE) ?                                    \
83    (VAL)->ctxt_ptr :                                                          \
84    (gom_cast_error(__FILE__, __LINE__, T_ ## STRUCTTYPE, (VAL)->obj_type),    \
85     (VAL)->ctxt_ptr))
86
87 #define SAFE_FREE(PTR)                                                        \
88   if (PTR) {                                                                  \
89     free(PTR);                                                                \
90     PTR = NULL;                                                               \
91   }
92
93 #define UNEXPECTED_CONTEXT(CTXT_TYPE)                                         \
94   gom_unexpected_context(__FILE__, __LINE__, CTXT_TYPE)
95
96 #define NO_CONTEXT                                                            \
97   gom_no_context(__FILE__, __LINE__)
98
99 void gom_mem_error(const char *filename, int line);
100
101 #define MEMORY_ERROR gom_mem_error(__FILE__, __LINE__)
102
103 void def_rec_end(Gedcom_rec rec, Gedcom_ctxt self);
104 void def_elt_end(Gedcom_elt elt, Gedcom_ctxt parent,
105                  Gedcom_ctxt self, Gedcom_val parsed_value);
106 void set_xref_type(struct xref_value *xr, const char* str);
107
108 typedef enum {
109   WITHOUT_NL,
110   WITH_NL
111 } NL_TYPE;
112
113 char* concat_strings(NL_TYPE type, char *str1, const char *str2);
114 struct date_value* dup_date(struct date_value dv);
115 struct age_value*  dup_age(struct age_value age);
116
117 /* Doubly-linked list, but last rec->next is NULL (doesn't go to first rec) */
118 #define LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
119   {                                                                           \
120     struct STRUCTTYPE *_local_obj = VAL;                                      \
121     if (! FIRSTVAL) {                                                         \
122       VAL->next = NULL;                                                       \
123       VAL->previous = _local_obj;                                             \
124       FIRSTVAL = VAL;                                                         \
125     }                                                                         \
126     else {                                                                    \
127       VAL->next = NULL;                                                       \
128       FIRSTVAL->previous->next = VAL;                                         \
129       VAL->previous = FIRSTVAL->previous;                                     \
130       FIRSTVAL->previous = VAL;                                               \
131     }                                                                         \
132   }
133
134 #define MAKE_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
135   {                                                                           \
136     VAL = (struct STRUCTTYPE*) malloc(sizeof(struct STRUCTTYPE));             \
137     if (! VAL)                                                                \
138       MEMORY_ERROR;                                                           \
139     else {                                                                    \
140       memset (VAL, 0, sizeof(struct STRUCTTYPE));                             \
141       LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                               \
142     }                                                                         \
143   }
144
145 void NULL_DESTROY(void* anything);
146
147 #define DESTROY_CHAIN_ELTS(STRUCTTYPE, FIRSTVAL, DESTROYFUNC)                 \
148   {                                                                           \
149     if (FIRSTVAL) {                                                           \
150       struct STRUCTTYPE *runner, *next;                                       \
151       runner = FIRSTVAL;                                                      \
152       while (runner) {                                                        \
153         next = runner->next;                                                  \
154         DESTROYFUNC(runner);                                                  \
155         SAFE_FREE(runner);                                                    \
156         runner = next;                                                        \
157       }                                                                       \
158     }                                                                         \
159   }
160
161 #define _REC_PARAMS_ Gedcom_rec rec UNUSED, int level UNUSED,                 \
162                      Gedcom_val xref UNUSED, char *tag UNUSED,                \
163                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
164                      Gedcom_val parsed_value UNUSED
165
166 #define _ELT_PARAMS_ Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,        \
167                      int level UNUSED, char *tag UNUSED,                      \
168                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
169                      Gedcom_val parsed_value UNUSED
170
171 #define REC_CB(STRUCTTYPE,CB_NAME,FUNC)                                       \
172   Gedcom_ctxt CB_NAME(_REC_PARAMS_)                                           \
173   {                                                                           \
174     struct xref_value* xr = GEDCOM_XREF_PTR(xref);                            \
175     if (! xr->object)                                                         \
176       xr->object = (Gedcom_ctxt) FUNC(xr->string);                            \
177     if (xr->object)                                                           \
178       return (Gedcom_ctxt) MAKE_GOM_CTXT(rec, STRUCTTYPE, xr->object);        \
179     else                                                                      \
180       return NULL;                                                            \
181   }
182
183 #define GET_REC_BY_XREF(STRUCTTYPE,XREF_TYPE,FUNC_NAME)                       \
184   struct STRUCTTYPE *FUNC_NAME(const char *xrefstr)                           \
185   {                                                                           \
186     struct xref_value* xr = gedcom_get_by_xref(xrefstr);                      \
187     if (xr && (xr->type == XREF_TYPE) && xr->object)                          \
188       return (struct STRUCTTYPE*)(xr->object);                                \
189     else                                                                      \
190       return NULL;                                                            \
191   }
192
193 #define STRING_CB(STRUCTTYPE,CB_NAME,FIELD)                                   \
194   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
195   {                                                                           \
196     Gom_ctxt result = NULL;                                                   \
197     if (! parent)                                                             \
198       NO_CONTEXT;                                                             \
199     else {                                                                    \
200       struct STRUCTTYPE *obj                                                  \
201         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
202       if (obj) {                                                              \
203         char *str = GEDCOM_STRING(parsed_value);                              \
204         obj->FIELD = strdup(str);                                             \
205         if (! obj->FIELD)                                                     \
206           MEMORY_ERROR;                                                       \
207         else                                                                  \
208           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
209       }                                                                       \
210     }                                                                         \
211     return (Gedcom_ctxt)result;                                               \
212   }
213
214 #define DATE_CB(STRUCTTYPE,CB_NAME,FIELD)                                     \
215   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
216   {                                                                           \
217     Gom_ctxt result = NULL;                                                   \
218     if (! parent)                                                             \
219       NO_CONTEXT;                                                             \
220     else {                                                                    \
221       struct STRUCTTYPE *obj                                                  \
222         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
223       if (obj) {                                                              \
224         struct date_value dv = GEDCOM_DATE(parsed_value);                     \
225         obj->FIELD = dup_date(dv);                                            \
226         if (! obj->FIELD)                                                     \
227           MEMORY_ERROR;                                                       \
228         else                                                                  \
229           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
230       }                                                                       \
231     }                                                                         \
232     return (Gedcom_ctxt)result;                                               \
233   }
234
235 #define AGE_CB(STRUCTTYPE,CB_NAME,FIELD)                                      \
236   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
237   {                                                                           \
238     Gom_ctxt result = NULL;                                                   \
239     if (! parent)                                                             \
240       NO_CONTEXT;                                                             \
241     else {                                                                    \
242       struct STRUCTTYPE *obj                                                  \
243         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
244       if (obj) {                                                              \
245         struct age_value age = GEDCOM_AGE(parsed_value);                      \
246         obj->FIELD = dup_age(age);                                            \
247         if (! obj->FIELD)                                                     \
248           MEMORY_ERROR;                                                       \
249         else                                                                  \
250           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
251       }                                                                       \
252     }                                                                         \
253     return (Gedcom_ctxt)result;                                               \
254   }
255
256 #define XREF_CB(STRUCTTYPE,CB_NAME,FIELD,FUNC)                                \
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       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
266       if (! xr->object)                                                       \
267         xr->object = (Gedcom_ctxt) FUNC(xr->string);                          \
268       if (obj) {                                                              \
269         obj->FIELD = xr;                                                      \
270         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
271       }                                                                       \
272     }                                                                         \
273     return (Gedcom_ctxt)result;                                               \
274   }
275
276 #define XREF_LIST_CB(STRUCTTYPE,CB_NAME,FIELD,FUNC)                           \
277   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
278   {                                                                           \
279     Gom_ctxt result = NULL;                                                   \
280     if (! parent)                                                             \
281       NO_CONTEXT;                                                             \
282     else {                                                                    \
283       struct STRUCTTYPE *obj                                                  \
284         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
285       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
286       struct xref_list *xrl;                                                  \
287       if (! xr->object)                                                       \
288         xr->object = (Gedcom_ctxt) FUNC(xr->string);                          \
289       if (obj) {                                                              \
290         MAKE_CHAIN_ELT(xref_list, obj->FIELD, xrl);                           \
291         if (xrl) {                                                            \
292           xrl->xref = xr;                                                     \
293           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
294         }                                                                     \
295       }                                                                       \
296     }                                                                         \
297     return (Gedcom_ctxt)result;                                               \
298   }
299
300 #define NULL_CB(STRUCTTYPE,CB_NAME)                                           \
301   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
302   {                                                                           \
303     Gom_ctxt result = NULL;                                                   \
304     if (! parent)                                                             \
305       NO_CONTEXT;                                                             \
306     else {                                                                    \
307       struct STRUCTTYPE *obj                                                  \
308         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
309       if (obj)                                                                \
310         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
311     }                                                                         \
312     return (Gedcom_ctxt)result;                                               \
313   }
314
315 #endif /* __GOM_INTERNAL_H */