Also write empty CONT lines.
[gedcom-parse.git] / gom / func_template.h
1 /* General header for the Gedcom object model, defining function macros
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 __FUNC_TEMPLATE_H
25 #define __FUNC_TEMPLATE_H
26
27 #define MAKEFUNC(STRUCTTYPE)     make_ ## STRUCTTYPE ## _record
28 #define SUB_MAKEFUNC(STRUCTTYPE) make_ ## STRUCTTYPE
29 #define DESTROYFUNC(STRUCTTYPE)  destroy_ ## STRUCTTYPE ## _record
30 #define GETXREFFUNC(STRUCTTYPE)  gom_get_ ## STRUCTTYPE ## _by_xref
31 #define CLEANFUNC(STRUCTTYPE)    STRUCTTYPE ## _cleanup
32 #define ADDFUNC(STRUCTTYPE)      gom_new_ ## STRUCTTYPE
33 #define SUB_SETFUNC(STRUCTTYPE)  gom_set_new_ ## STRUCTTYPE
34 #define SUB_ADDFUNC(STRUCTTYPE)  gom_add_new_ ## STRUCTTYPE
35 #define UNREFALLFUNC(STRUCTTYPE) STRUCTTYPE ## _unref_all
36 #define DELETEFUNC(STRUCTTYPE)   gom_delete_ ## STRUCTTYPE
37 #define SUB_DELETEFUNC(STRUCTTYPE) gom_delete_ ## STRUCTTYPE
38 #define SUB_FINDFUNC(STRUCTTYPE) find_ ## STRUCTTYPE
39 #define SUB_REMOVEFUNC(STRUCTTYPE) gom_remove_ ## STRUCTTYPE
40 #define SUB_MOVEFUNC(STRUCTTYPE) gom_move_ ## STRUCTTYPE
41 #define ADDFUNC2(T1,T2)          T1 ## _add_ ## T2
42 #define ADDFUNC2_TOVAR(T1,T2,F)  T1 ## _add_ ## T2 ## _to_ ## F
43 #define ADDFUNC2_NOLIST(T1,T2)   ADDFUNC2(T1,T2)
44 #define ADDFUNC2_STR(T1,F)       ADDFUNC2(T1,F)
45 #define ADDFUNC2_STRN(T1,F)      ADDFUNC2(T1,F)
46
47 #define DECLARE_MAKEFUNC(STRUCTTYPE)                                          \
48   struct STRUCTTYPE* MAKEFUNC(STRUCTTYPE)(const char* xref)
49
50 #define DECLARE_SUB_MAKEFUNC(STRUCTTYPE)                                      \
51   struct STRUCTTYPE* SUB_MAKEFUNC(STRUCTTYPE)()
52
53 #define DECLARE_CLEANFUNC(STRUCTTYPE)                                         \
54   void CLEANFUNC(STRUCTTYPE)(struct STRUCTTYPE* obj)
55
56 #define DECLARE_UNREFALLFUNC(STRUCTTYPE)                                      \
57   void UNREFALLFUNC(STRUCTTYPE)(struct STRUCTTYPE* obj)
58
59 #define DECLARE_ADDFUNC2(STRUCTTYPE,T2)                                       \
60   void ADDFUNC2(STRUCTTYPE,T2)(Gom_ctxt ctxt, struct T2* obj)
61
62 #define DECLARE_ADDFUNC2_TOVAR(STRUCTTYPE,T2,F)                               \
63   void ADDFUNC2_TOVAR(STRUCTTYPE,T2,F)(Gom_ctxt ctxt, struct T2* obj)
64
65 #define DECLARE_ADDFUNC2_NOLIST(STRUCTTYPE,T2)                                \
66   void ADDFUNC2_NOLIST(STRUCTTYPE,T2)(Gom_ctxt ctxt, struct T2* obj)
67
68 #define DECLARE_ADDFUNC2_STR(STRUCTTYPE,F)                                    \
69   void ADDFUNC2_STR(STRUCTTYPE,F)(Gom_ctxt ctxt, const char* str)
70
71 #define DECLARE_ADDFUNC2_STRN(STRUCTTYPE,F)                                   \
72   void ADDFUNC2_STRN(STRUCTTYPE,F)(Gom_ctxt ctxt, const char* str)
73
74 /* Doubly-linked list, but last rec->next is NULL (doesn't go to first rec) */
75 #define LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
76   {                                                                           \
77     struct STRUCTTYPE *_local_obj = VAL;                                      \
78     if (! FIRSTVAL) {                                                         \
79       VAL->next = NULL;                                                       \
80       VAL->previous = _local_obj;                                             \
81       FIRSTVAL = VAL;                                                         \
82     }                                                                         \
83     else {                                                                    \
84       VAL->next = NULL;                                                       \
85       (FIRSTVAL)->previous->next = VAL;                                       \
86       VAL->previous = (FIRSTVAL)->previous;                                   \
87       (FIRSTVAL)->previous = VAL;                                             \
88     }                                                                         \
89   }
90
91 #define UNLINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                           \
92   {                                                                           \
93     struct STRUCTTYPE *_local_obj = VAL;                                      \
94     if (VAL == FIRSTVAL)                                                      \
95       FIRSTVAL = _local_obj->next;                                            \
96     else                                                                      \
97       VAL->previous->next = VAL->next;                                        \
98     if (VAL->next)                                                            \
99       VAL->next->previous = VAL->previous;                                    \
100     else if (FIRSTVAL)                                                        \
101       (FIRSTVAL)->previous = VAL->previous;                                   \
102   }
103
104 #define MOVE_CHAIN_ELT(STRUCTTYPE, DIR, FIRSTVAL, VAL)                        \
105   {                                                                           \
106     struct STRUCTTYPE *first, *second;                                        \
107     if (DIR == MOVE_UP) {                                                     \
108       first  = VAL->previous;                                                 \
109       second = VAL;                                                           \
110     }                                                                         \
111     else {                                                                    \
112       first  = VAL;                                                           \
113       second = VAL->next;                                                     \
114     }                                                                         \
115     if (second && (second != FIRSTVAL)) {                                     \
116       if (first != FIRSTVAL)                                                  \
117         first->previous->next  = second;                                      \
118       else                                                                    \
119         FIRSTVAL               = second;                                      \
120                                                                               \
121       if (second->next)                                                       \
122         second->next->previous = first;                                       \
123       else                                                                    \
124         (FIRSTVAL)->previous   = first;                                       \
125                                                                               \
126       first->next            = second->next;                                  \
127       second->next           = first;                                         \
128                                                                               \
129       second->previous       = first->previous;                               \
130       first->previous        = second;                                        \
131     }                                                                         \
132     else {                                                                    \
133       gom_move_error(#STRUCTTYPE);                                            \
134     }                                                                         \
135   }
136
137 #define MAKE_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
138   {                                                                           \
139     VAL = (struct STRUCTTYPE*) malloc(sizeof(struct STRUCTTYPE));             \
140     if (! VAL)                                                                \
141       MEMORY_ERROR;                                                           \
142     else {                                                                    \
143       memset (VAL, 0, sizeof(struct STRUCTTYPE));                             \
144       LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                               \
145     }                                                                         \
146   }
147
148 #define DESTROY_CHAIN_ELTS(STRUCTTYPE, FIRSTVAL)                              \
149   {                                                                           \
150     if (FIRSTVAL) {                                                           \
151       struct STRUCTTYPE *runner, *next;                                       \
152       runner = FIRSTVAL;                                                      \
153       FIRSTVAL = NULL;                                                        \
154       while (runner) {                                                        \
155         next = runner->next;                                                  \
156         CLEANFUNC(STRUCTTYPE)(runner);                                        \
157         SAFE_FREE(runner);                                                    \
158         runner = next;                                                        \
159       }                                                                       \
160     }                                                                         \
161   }
162
163 /* General functions */
164 #define DEFINE_MAKEFUNC(STRUCTTYPE,FIRSTVAL)                                  \
165   struct STRUCTTYPE* MAKEFUNC(STRUCTTYPE)(const char* xrefstr) {              \
166     struct STRUCTTYPE* obj = NULL;                                            \
167     if (xrefstr) {                                                            \
168       MAKE_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, obj);                              \
169       if (obj) {                                                              \
170         obj->xrefstr = strdup(xrefstr);                                       \
171         if (!obj->xrefstr) MEMORY_ERROR;                                      \
172       }                                                                       \
173     }                                                                         \
174     return obj;                                                               \
175   }
176
177 #define DEFINE_SUB_MAKEFUNC(STRUCTTYPE)                                       \
178   struct STRUCTTYPE* SUB_MAKEFUNC(STRUCTTYPE)() {                             \
179     struct STRUCTTYPE* obj = NULL;                                            \
180     obj = (struct STRUCTTYPE*) malloc(sizeof(struct STRUCTTYPE));             \
181     if (!obj)                                                                 \
182       MEMORY_ERROR;                                                           \
183     else                                                                      \
184       memset(obj, 0, sizeof(struct STRUCTTYPE));                              \
185     return obj;                                                               \
186   }
187
188 #define DEFINE_DESTROYFUNC(STRUCTTYPE,FIRSTVAL)                               \
189   DECLARE_CLEANFUNC(STRUCTTYPE);                                              \
190   void DESTROYFUNC(STRUCTTYPE)(struct STRUCTTYPE* obj) {                      \
191     if (obj) {                                                                \
192       CLEANFUNC(STRUCTTYPE)(obj);                                             \
193       UNLINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, obj);                            \
194       SAFE_FREE(obj);                                                         \
195     }                                                                         \
196   }
197
198 #define DEFINE_GETXREFFUNC(STRUCTTYPE,XREF_TYPE)                              \
199   struct STRUCTTYPE *GETXREFFUNC(STRUCTTYPE)(const char *xrefstr)             \
200   {                                                                           \
201     struct xref_value* xr = gedcom_get_by_xref(xrefstr);                      \
202     if (xr && (xr->type == XREF_TYPE) && xr->object)                          \
203       return (struct STRUCTTYPE*)(xr->object);                                \
204     else                                                                      \
205       return NULL;                                                            \
206   }
207
208 #define DEFINE_ADDFUNC(STRUCTTYPE,XREF_TYPE)                                  \
209   struct STRUCTTYPE *ADDFUNC(STRUCTTYPE)(const char* xrefstr)                 \
210   {                                                                           \
211     struct STRUCTTYPE *obj = NULL;                                            \
212     struct xref_value* xrv = gedcom_get_by_xref(xrefstr);                     \
213     if (xrv)                                                                  \
214       gom_xref_already_in_use(xrefstr);                                       \
215     else {                                                                    \
216       obj = MAKEFUNC(STRUCTTYPE)(xrefstr);                                    \
217       if (obj) {                                                              \
218         xrv = gedcom_add_xref(XREF_TYPE, xrefstr, (Gedcom_ctxt)obj);          \
219         if (!xrv) {                                                           \
220           DESTROYFUNC(STRUCTTYPE)(obj);                                       \
221           obj = NULL;                                                         \
222         }                                                                     \
223       }                                                                       \
224     }                                                                         \
225     return obj;                                                               \
226   }
227
228 #define DEFINE_SUB_SETFUNC(STRUCTTYPE)                                        \
229   struct STRUCTTYPE *SUB_SETFUNC(STRUCTTYPE)(struct STRUCTTYPE** addto)       \
230   {                                                                           \
231     struct STRUCTTYPE *obj = NULL;                                            \
232     if (addto && ! *addto) {                                                  \
233       obj = SUB_MAKEFUNC(STRUCTTYPE)();                                       \
234       if (obj) *addto = obj;                                                  \
235     }                                                                         \
236     return obj;                                                               \
237   }
238
239 #define DEFINE_SUB_ADDFUNC(STRUCTTYPE)                                        \
240   struct STRUCTTYPE *SUB_ADDFUNC(STRUCTTYPE)(struct STRUCTTYPE** addto)       \
241   {                                                                           \
242     struct STRUCTTYPE *obj = NULL;                                            \
243     if (addto) {                                                              \
244       MAKE_CHAIN_ELT(STRUCTTYPE, *addto, obj);                                \
245     }                                                                         \
246     return obj;                                                               \
247   }
248
249 #define DEFINE_DELETEFUNC(STRUCTTYPE)                                         \
250   DECLARE_UNREFALLFUNC(STRUCTTYPE);                                           \
251   int DELETEFUNC(STRUCTTYPE)(struct STRUCTTYPE* obj)                          \
252   {                                                                           \
253     int result = 1;                                                           \
254     if (obj) {                                                                \
255       result = gedcom_delete_xref(obj->xrefstr);                              \
256       if (result == 0) {                                                      \
257         UNREFALLFUNC(STRUCTTYPE)(obj);                                        \
258         DESTROYFUNC(STRUCTTYPE)(obj);                                         \
259       }                                                                       \
260     }                                                                         \
261     return result;                                                            \
262   }
263
264 #define DEFINE_SUB_DELETEFUNC(STRUCTTYPE)                                     \
265   int SUB_DELETEFUNC(STRUCTTYPE)(struct STRUCTTYPE** obj)                     \
266   {                                                                           \
267     int result = 1;                                                           \
268     if (obj && *obj) {                                                        \
269       UNREFALLFUNC(STRUCTTYPE)(*obj);                                         \
270       CLEANFUNC(STRUCTTYPE)(*obj);                                            \
271       SAFE_FREE(*obj);                                                        \
272       result = 0;                                                             \
273     }                                                                         \
274     return result;                                                            \
275   }
276
277 #define DEFINE_SUB_FINDFUNC(STRUCTTYPE)                                       \
278   struct STRUCTTYPE* SUB_FINDFUNC(STRUCTTYPE)(struct STRUCTTYPE** data,       \
279                                               struct STRUCTTYPE* obj)         \
280   {                                                                           \
281     struct STRUCTTYPE* result = NULL;                                         \
282     struct STRUCTTYPE* runner;                                                \
283     for (runner = *data ; runner ; runner = runner->next) {                   \
284       if (runner == obj) {                                                    \
285         result = runner;                                                      \
286         break;                                                                \
287       }                                                                       \
288     }                                                                         \
289     if (! result)                                                             \
290       gom_find_error(#STRUCTTYPE);                                            \
291     return result;                                                            \
292   }
293
294 #define DEFINE_SUB_REMOVEFUNC(STRUCTTYPE)                                     \
295   int SUB_REMOVEFUNC(STRUCTTYPE) (struct STRUCTTYPE** data,                   \
296                                   struct STRUCTTYPE* obj)                     \
297   {                                                                           \
298     int result = 1;                                                           \
299     if (data && obj) {                                                        \
300       struct STRUCTTYPE* toremove = SUB_FINDFUNC(STRUCTTYPE)(data, obj);      \
301       if (toremove) {                                                         \
302         UNLINK_CHAIN_ELT(STRUCTTYPE, *data, toremove);                        \
303         CLEANFUNC(STRUCTTYPE)(toremove);                                      \
304         SAFE_FREE(toremove);                                                  \
305         result = 0;                                                           \
306       }                                                                       \
307     }                                                                         \
308     return result;                                                            \
309   }
310
311 #define DEFINE_SUB_MOVEFUNC(STRUCTTYPE)                                       \
312   int SUB_MOVEFUNC(STRUCTTYPE)(Gom_direction dir, struct STRUCTTYPE** data,   \
313                                struct STRUCTTYPE* obj)                        \
314   {                                                                           \
315     int result = 1;                                                           \
316     if (data && obj) {                                                        \
317       struct STRUCTTYPE* tomove = SUB_FINDFUNC(STRUCTTYPE)(data, obj);        \
318       if (tomove) {                                                           \
319         MOVE_CHAIN_ELT(STRUCTTYPE, dir, *data, tomove);                       \
320         result = 0;                                                           \
321       }                                                                       \
322     }                                                                         \
323     return result;                                                            \
324   }
325
326 #define DEFINE_ADDFUNC2(STRUCTTYPE,T2,FIELD)                                  \
327   void ADDFUNC2(STRUCTTYPE,T2)(Gom_ctxt ctxt, struct T2* addobj)              \
328   {                                                                           \
329     struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                \
330     if (obj)                                                                  \
331       LINK_CHAIN_ELT(T2, obj->FIELD, addobj);                                 \
332   }
333
334 #define DEFINE_ADDFUNC2_TOVAR(STRUCTTYPE,T2,FIELD)                            \
335   void ADDFUNC2_TOVAR(STRUCTTYPE,T2,FIELD)(Gom_ctxt ctxt, struct T2* addobj)  \
336   {                                                                           \
337     struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                \
338     if (obj)                                                                  \
339       LINK_CHAIN_ELT(T2, obj->FIELD, addobj);                                 \
340   }
341
342 #define DEFINE_ADDFUNC2_NOLIST(STRUCTTYPE,T2, FIELD)                          \
343   void ADDFUNC2_NOLIST(STRUCTTYPE,T2)(Gom_ctxt ctxt, struct T2* addobj)       \
344   {                                                                           \
345     struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                \
346     if (obj)                                                                  \
347       obj->FIELD = addobj;                                                    \
348   }
349
350 #define DEFINE_ADDFUNC2_STR(STRUCTTYPE,FIELD)                                 \
351 void ADDFUNC2_STR(STRUCTTYPE,FIELD)(Gom_ctxt ctxt, const char *str)           \
352 {                                                                             \
353   struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                  \
354   if (obj) {                                                                  \
355     obj->FIELD = strdup(str);                                                 \
356     if (! obj->FIELD) MEMORY_ERROR;                                           \
357   }                                                                           \
358 }
359
360 #define DEFINE_ADDFUNC2_STRN(STRUCTTYPE,FIELD,N)                              \
361 void ADDFUNC2_STRN(STRUCTTYPE,FIELD)(Gom_ctxt ctxt, const char *str)          \
362 {                                                                             \
363   struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                  \
364   if (obj) {                                                                  \
365     int i = 0;                                                                \
366     while (i < N-1 && obj->FIELD[i]) i++;                                     \
367     if (! obj->FIELD[i]) {                                                    \
368       obj->FIELD[i] = strdup(str);                                            \
369       if (! obj->FIELD[i]) MEMORY_ERROR;                                      \
370     }                                                                         \
371   }                                                                           \
372 }
373
374 /* Definition of callbacks */
375 #define _REC_PARAMS_ Gedcom_rec rec UNUSED, int level UNUSED,                 \
376                      Gedcom_val xref UNUSED, char *tag UNUSED,                \
377                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
378                      Gedcom_val parsed_value UNUSED
379
380 #define _REC_END_PARAMS_ Gedcom_rec rec UNUSED, Gedcom_ctxt self UNUSED,      \
381                          Gedcom_val parsed_value UNUSED
382
383 #define _ELT_PARAMS_ Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,        \
384                      int level UNUSED, char *tag UNUSED,                      \
385                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
386                      Gedcom_val parsed_value UNUSED
387
388 #define _ELT_END_PARAMS_ Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,    \
389                          Gedcom_ctxt self UNUSED,                             \
390                          Gedcom_val parsed_value UNUSED
391
392 #define DEFINE_REC_CB(STRUCTTYPE,CB_NAME)                                     \
393   Gedcom_ctxt CB_NAME(_REC_PARAMS_)                                           \
394   {                                                                           \
395     struct xref_value* xr = GEDCOM_XREF_PTR(xref);                            \
396     if (! xr->object)                                                         \
397       xr->object = (Gedcom_ctxt) MAKEFUNC(STRUCTTYPE)(xr->string);            \
398     if (xr->object)                                                           \
399       return (Gedcom_ctxt) MAKE_GOM_CTXT(rec, STRUCTTYPE, xr->object);        \
400     else                                                                      \
401       return NULL;                                                            \
402   }
403
404 #define DEFINE_STRING_CB(STRUCTTYPE,CB_NAME,FIELD)                            \
405   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
406   {                                                                           \
407     Gom_ctxt result = NULL;                                                   \
408     if (! parent)                                                             \
409       NO_CONTEXT;                                                             \
410     else {                                                                    \
411       struct STRUCTTYPE *obj                                                  \
412         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
413       if (obj) {                                                              \
414         char *str = GEDCOM_STRING(parsed_value);                              \
415         obj->FIELD = strdup(str);                                             \
416         if (! obj->FIELD)                                                     \
417           MEMORY_ERROR;                                                       \
418         else                                                                  \
419           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
420       }                                                                       \
421     }                                                                         \
422     return (Gedcom_ctxt)result;                                               \
423   }
424
425 #define DEFINE_STRING_END_CB(STRUCTTYPE,CB_NAME,FIELD)                        \
426   void CB_NAME(_ELT_END_PARAMS_)                                              \
427   {                                                                           \
428     Gom_ctxt ctxt = (Gom_ctxt)self;                                           \
429     if (! ctxt)                                                               \
430       NO_CONTEXT;                                                             \
431     else {                                                                    \
432       struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);              \
433       if (obj) {                                                              \
434         char *str = GEDCOM_STRING(parsed_value);                              \
435         char *newvalue = strdup(str);                                         \
436         if (! newvalue)                                                       \
437           MEMORY_ERROR;                                                       \
438         else                                                                  \
439           obj->FIELD = newvalue;                                              \
440       }                                                                       \
441       destroy_gom_ctxt(ctxt);                                                 \
442     }                                                                         \
443   }
444
445 #define DEFINE_STRING_END_REC_CB(STRUCTTYPE,CB_NAME,FIELD)                    \
446   void CB_NAME(_REC_END_PARAMS_)                                              \
447   {                                                                           \
448     Gom_ctxt ctxt = (Gom_ctxt)self;                                           \
449     if (! ctxt)                                                               \
450       NO_CONTEXT;                                                             \
451     else {                                                                    \
452       struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);              \
453       if (obj) {                                                              \
454         char *str = GEDCOM_STRING(parsed_value);                              \
455         char *newvalue = strdup(str);                                         \
456         if (! newvalue)                                                       \
457           MEMORY_ERROR;                                                       \
458         else                                                                  \
459           obj->FIELD = newvalue;                                              \
460       }                                                                       \
461       destroy_gom_ctxt(ctxt);                                                 \
462     }                                                                         \
463   }
464
465 #define DEFINE_DATE_CB(STRUCTTYPE,CB_NAME,FIELD)                              \
466   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
467   {                                                                           \
468     Gom_ctxt result = NULL;                                                   \
469     if (! parent)                                                             \
470       NO_CONTEXT;                                                             \
471     else {                                                                    \
472       struct STRUCTTYPE *obj                                                  \
473         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
474       if (obj) {                                                              \
475         struct date_value dv = GEDCOM_DATE(parsed_value);                     \
476         obj->FIELD = gedcom_new_date_value(&dv);                              \
477         if (! obj->FIELD)                                                     \
478           MEMORY_ERROR;                                                       \
479         else                                                                  \
480           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
481       }                                                                       \
482     }                                                                         \
483     return (Gedcom_ctxt)result;                                               \
484   }
485
486 #define DEFINE_AGE_CB(STRUCTTYPE,CB_NAME,FIELD)                               \
487   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
488   {                                                                           \
489     Gom_ctxt result = NULL;                                                   \
490     if (! parent)                                                             \
491       NO_CONTEXT;                                                             \
492     else {                                                                    \
493       struct STRUCTTYPE *obj                                                  \
494         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
495       if (obj) {                                                              \
496         struct age_value age = GEDCOM_AGE(parsed_value);                      \
497         obj->FIELD = gedcom_new_age_value(&age);                              \
498         if (! obj->FIELD)                                                     \
499           MEMORY_ERROR;                                                       \
500         else                                                                  \
501           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
502       }                                                                       \
503     }                                                                         \
504     return (Gedcom_ctxt)result;                                               \
505   }
506
507 #define DEFINE_XREF_CB(STRUCTTYPE,CB_NAME,FIELD,LINKSTRTYPE)                  \
508   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
509   {                                                                           \
510     Gom_ctxt result = NULL;                                                   \
511     if (! parent)                                                             \
512       NO_CONTEXT;                                                             \
513     else {                                                                    \
514       struct STRUCTTYPE *obj                                                  \
515         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
516       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
517       if (! xr->object)                                                       \
518         xr->object = (Gedcom_ctxt) MAKEFUNC(LINKSTRTYPE)(xr->string);         \
519       if (obj) {                                                              \
520         obj->FIELD = xr;                                                      \
521         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
522       }                                                                       \
523     }                                                                         \
524     return (Gedcom_ctxt)result;                                               \
525   }
526
527 #define DEFINE_XREF_LIST_CB(STRUCTTYPE,CB_NAME,FIELD,LINKSTRTYPE)             \
528   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
529   {                                                                           \
530     Gom_ctxt result = NULL;                                                   \
531     if (! parent)                                                             \
532       NO_CONTEXT;                                                             \
533     else {                                                                    \
534       struct STRUCTTYPE *obj                                                  \
535         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
536       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
537       struct xref_list *xrl;                                                  \
538       if (! xr->object)                                                       \
539         xr->object = (Gedcom_ctxt) MAKEFUNC(LINKSTRTYPE)(xr->string);         \
540       if (obj) {                                                              \
541         MAKE_CHAIN_ELT(xref_list, obj->FIELD, xrl);                           \
542         if (xrl) {                                                            \
543           xrl->xref = xr;                                                     \
544           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
545         }                                                                     \
546       }                                                                       \
547     }                                                                         \
548     return (Gedcom_ctxt)result;                                               \
549   }
550
551 #define DEFINE_NULL_CB(STRUCTTYPE,CB_NAME)                                    \
552   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
553   {                                                                           \
554     Gom_ctxt result = NULL;                                                   \
555     if (! parent)                                                             \
556       NO_CONTEXT;                                                             \
557     else {                                                                    \
558       struct STRUCTTYPE *obj                                                  \
559         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
560       if (obj)                                                                \
561         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
562     }                                                                         \
563     return (Gedcom_ctxt)result;                                               \
564   }
565
566
567
568 #endif /* __FUNC_TEMPLATE_H */