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