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