Unlink xrefs properly when struct is deleted.
[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_add_ ## STRUCTTYPE
33 #define SUB_ADDFUNC(STRUCTTYPE)  gom_add_ ## 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 MAKE_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                             \
101   {                                                                           \
102     VAL = (struct STRUCTTYPE*) malloc(sizeof(struct STRUCTTYPE));             \
103     if (! VAL)                                                                \
104       MEMORY_ERROR;                                                           \
105     else {                                                                    \
106       memset (VAL, 0, sizeof(struct STRUCTTYPE));                             \
107       LINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, VAL)                               \
108     }                                                                         \
109   }
110
111 #define DESTROY_CHAIN_ELTS(STRUCTTYPE, FIRSTVAL)                              \
112   {                                                                           \
113     if (FIRSTVAL) {                                                           \
114       struct STRUCTTYPE *runner, *next;                                       \
115       runner = FIRSTVAL;                                                      \
116       FIRSTVAL = NULL;                                                        \
117       while (runner) {                                                        \
118         next = runner->next;                                                  \
119         CLEANFUNC(STRUCTTYPE)(runner);                                        \
120         SAFE_FREE(runner);                                                    \
121         runner = next;                                                        \
122       }                                                                       \
123     }                                                                         \
124   }
125
126 /* General functions */
127 #define DEFINE_MAKEFUNC(STRUCTTYPE,FIRSTVAL)                                  \
128   struct STRUCTTYPE* MAKEFUNC(STRUCTTYPE)(const char* xrefstr) {              \
129     struct STRUCTTYPE* obj = NULL;                                            \
130     if (xrefstr) {                                                            \
131       MAKE_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, obj);                              \
132       if (obj) {                                                              \
133         obj->xrefstr = strdup(xrefstr);                                       \
134         if (!obj->xrefstr) MEMORY_ERROR;                                      \
135       }                                                                       \
136     }                                                                         \
137     return obj;                                                               \
138   }
139
140 #define DEFINE_SUB_MAKEFUNC(STRUCTTYPE)                                       \
141   struct STRUCTTYPE* SUB_MAKEFUNC(STRUCTTYPE)() {                             \
142     struct STRUCTTYPE* obj = NULL;                                            \
143     obj = (struct STRUCTTYPE*) malloc(sizeof(struct STRUCTTYPE));             \
144     if (!obj)                                                                 \
145       MEMORY_ERROR;                                                           \
146     else                                                                      \
147       memset(obj, 0, sizeof(struct STRUCTTYPE));                              \
148     return obj;                                                               \
149   }
150
151 #define DEFINE_DESTROYFUNC(STRUCTTYPE,FIRSTVAL)                               \
152   DECLARE_CLEANFUNC(STRUCTTYPE);                                              \
153   void DESTROYFUNC(STRUCTTYPE)(struct STRUCTTYPE* obj) {                      \
154     if (obj) {                                                                \
155       CLEANFUNC(STRUCTTYPE)(obj);                                             \
156       UNLINK_CHAIN_ELT(STRUCTTYPE, FIRSTVAL, obj);                            \
157       SAFE_FREE(obj);                                                         \
158     }                                                                         \
159   }
160
161 #define DEFINE_GETXREFFUNC(STRUCTTYPE,XREF_TYPE)                              \
162   struct STRUCTTYPE *GETXREFFUNC(STRUCTTYPE)(const char *xrefstr)             \
163   {                                                                           \
164     struct xref_value* xr = gedcom_get_by_xref(xrefstr);                      \
165     if (xr && (xr->type == XREF_TYPE) && xr->object)                          \
166       return (struct STRUCTTYPE*)(xr->object);                                \
167     else                                                                      \
168       return NULL;                                                            \
169   }
170
171 #define DEFINE_ADDFUNC(STRUCTTYPE,XREF_TYPE)                                  \
172   struct STRUCTTYPE *ADDFUNC(STRUCTTYPE)(const char* xrefstr)                 \
173   {                                                                           \
174     struct STRUCTTYPE *obj = NULL;                                            \
175     struct xref_value* xrv = gedcom_get_by_xref(xrefstr);                     \
176     if (xrv)                                                                  \
177       gom_xref_already_in_use(xrefstr);                                       \
178     else {                                                                    \
179       obj = MAKEFUNC(STRUCTTYPE)(xrefstr);                                    \
180       if (obj) {                                                              \
181         xrv = gedcom_add_xref(XREF_TYPE, xrefstr, (Gedcom_ctxt)obj);          \
182         if (!xrv) {                                                           \
183           DESTROYFUNC(STRUCTTYPE)(obj);                                       \
184           obj = NULL;                                                         \
185         }                                                                     \
186       }                                                                       \
187     }                                                                         \
188     return obj;                                                               \
189   }
190
191 #define DEFINE_SUB_ADDFUNC(STRUCTTYPE)                                        \
192   struct STRUCTTYPE *SUB_ADDFUNC(STRUCTTYPE)(struct STRUCTTYPE** addto)       \
193   {                                                                           \
194     struct STRUCTTYPE *obj = NULL;                                            \
195     if (addto && ! *addto) {                                                  \
196       obj = SUB_MAKEFUNC(STRUCTTYPE)();                                       \
197       if (obj) *addto = obj;                                                  \
198     }                                                                         \
199     return obj;                                                               \
200   }
201
202 #define DEFINE_DELETEFUNC(STRUCTTYPE)                                         \
203   DECLARE_UNREFALLFUNC(STRUCTTYPE);                                           \
204   int DELETEFUNC(STRUCTTYPE)(struct STRUCTTYPE* obj)                          \
205   {                                                                           \
206     int result = 1;                                                           \
207     if (obj) {                                                                \
208       result = gedcom_delete_xref(obj->xrefstr);                              \
209       if (result == 0) {                                                      \
210         UNREFALLFUNC(STRUCTTYPE)(obj);                                        \
211         DESTROYFUNC(STRUCTTYPE)(obj);                                         \
212       }                                                                       \
213     }                                                                         \
214     return result;                                                            \
215   }
216
217 #define DEFINE_SUB_DELETEFUNC(STRUCTTYPE)                                     \
218   int SUB_DELETEFUNC(STRUCTTYPE)(struct STRUCTTYPE** obj)                     \
219   {                                                                           \
220     int result = 1;                                                           \
221     if (obj && *obj) {                                                        \
222       UNREFALLFUNC(STRUCTTYPE)(*obj);                                         \
223       CLEANFUNC(STRUCTTYPE)(*obj);                                            \
224       SAFE_FREE(*obj);                                                        \
225       result = 0;                                                             \
226     }                                                                         \
227     return result;                                                            \
228   }
229
230 #define DEFINE_ADDFUNC2(STRUCTTYPE,T2,FIELD)                                  \
231   void ADDFUNC2(STRUCTTYPE,T2)(Gom_ctxt ctxt, struct T2* addobj)              \
232   {                                                                           \
233     struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                \
234     if (obj)                                                                  \
235       LINK_CHAIN_ELT(T2, obj->FIELD, addobj);                                 \
236   }
237
238 #define DEFINE_ADDFUNC2_TOVAR(STRUCTTYPE,T2,FIELD)                            \
239   void ADDFUNC2_TOVAR(STRUCTTYPE,T2,FIELD)(Gom_ctxt ctxt, struct T2* addobj)  \
240   {                                                                           \
241     struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                \
242     if (obj)                                                                  \
243       LINK_CHAIN_ELT(T2, obj->FIELD, addobj);                                 \
244   }
245
246 #define DEFINE_ADDFUNC2_NOLIST(STRUCTTYPE,T2, FIELD)                          \
247   void ADDFUNC2_NOLIST(STRUCTTYPE,T2)(Gom_ctxt ctxt, struct T2* addobj)       \
248   {                                                                           \
249     struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                \
250     if (obj)                                                                  \
251       obj->FIELD = addobj;                                                    \
252   }
253
254 #define DEFINE_ADDFUNC2_STR(STRUCTTYPE,FIELD)                                 \
255 void ADDFUNC2_STR(STRUCTTYPE,FIELD)(Gom_ctxt ctxt, const char *str)           \
256 {                                                                             \
257   struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                  \
258   if (obj) {                                                                  \
259     obj->FIELD = strdup(str);                                                 \
260     if (! obj->FIELD) MEMORY_ERROR;                                           \
261   }                                                                           \
262 }
263
264 #define DEFINE_ADDFUNC2_STRN(STRUCTTYPE,FIELD,N)                              \
265 void ADDFUNC2_STRN(STRUCTTYPE,FIELD)(Gom_ctxt ctxt, const char *str)          \
266 {                                                                             \
267   struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);                  \
268   if (obj) {                                                                  \
269     int i = 0;                                                                \
270     while (i < N-1 && obj->FIELD[i]) i++;                                     \
271     if (! obj->FIELD[i]) {                                                    \
272       obj->FIELD[i] = strdup(str);                                            \
273       if (! obj->FIELD[i]) MEMORY_ERROR;                                      \
274     }                                                                         \
275   }                                                                           \
276 }
277
278 /* Definition of callbacks */
279 #define _REC_PARAMS_ Gedcom_rec rec UNUSED, int level UNUSED,                 \
280                      Gedcom_val xref UNUSED, char *tag UNUSED,                \
281                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
282                      Gedcom_val parsed_value UNUSED
283
284 #define _REC_END_PARAMS_ Gedcom_rec rec UNUSED, Gedcom_ctxt self UNUSED,      \
285                          Gedcom_val parsed_value UNUSED
286
287 #define _ELT_PARAMS_ Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,        \
288                      int level UNUSED, char *tag UNUSED,                      \
289                      char *raw_value UNUSED, int parsed_tag UNUSED,           \
290                      Gedcom_val parsed_value UNUSED
291
292 #define _ELT_END_PARAMS_ Gedcom_elt elt UNUSED, Gedcom_ctxt parent UNUSED,    \
293                          Gedcom_ctxt self UNUSED,                             \
294                          Gedcom_val parsed_value UNUSED
295
296 #define DEFINE_REC_CB(STRUCTTYPE,CB_NAME)                                     \
297   Gedcom_ctxt CB_NAME(_REC_PARAMS_)                                           \
298   {                                                                           \
299     struct xref_value* xr = GEDCOM_XREF_PTR(xref);                            \
300     if (! xr->object)                                                         \
301       xr->object = (Gedcom_ctxt) MAKEFUNC(STRUCTTYPE)(xr->string);            \
302     if (xr->object)                                                           \
303       return (Gedcom_ctxt) MAKE_GOM_CTXT(rec, STRUCTTYPE, xr->object);        \
304     else                                                                      \
305       return NULL;                                                            \
306   }
307
308 #define DEFINE_STRING_CB(STRUCTTYPE,CB_NAME,FIELD)                            \
309   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
310   {                                                                           \
311     Gom_ctxt result = NULL;                                                   \
312     if (! parent)                                                             \
313       NO_CONTEXT;                                                             \
314     else {                                                                    \
315       struct STRUCTTYPE *obj                                                  \
316         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
317       if (obj) {                                                              \
318         char *str = GEDCOM_STRING(parsed_value);                              \
319         obj->FIELD = strdup(str);                                             \
320         if (! obj->FIELD)                                                     \
321           MEMORY_ERROR;                                                       \
322         else                                                                  \
323           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
324       }                                                                       \
325     }                                                                         \
326     return (Gedcom_ctxt)result;                                               \
327   }
328
329 #define DEFINE_STRING_END_CB(STRUCTTYPE,CB_NAME,FIELD)                        \
330   void CB_NAME(_ELT_END_PARAMS_)                                              \
331   {                                                                           \
332     Gom_ctxt ctxt = (Gom_ctxt)self;                                           \
333     if (! ctxt)                                                               \
334       NO_CONTEXT;                                                             \
335     else {                                                                    \
336       struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);              \
337       if (obj) {                                                              \
338         char *str = GEDCOM_STRING(parsed_value);                              \
339         char *newvalue = strdup(str);                                         \
340         if (! newvalue)                                                       \
341           MEMORY_ERROR;                                                       \
342         else                                                                  \
343           obj->FIELD = newvalue;                                              \
344       }                                                                       \
345       destroy_gom_ctxt(ctxt);                                                 \
346     }                                                                         \
347   }
348
349 #define DEFINE_STRING_END_REC_CB(STRUCTTYPE,CB_NAME,FIELD)                    \
350   void CB_NAME(_REC_END_PARAMS_)                                              \
351   {                                                                           \
352     Gom_ctxt ctxt = (Gom_ctxt)self;                                           \
353     if (! ctxt)                                                               \
354       NO_CONTEXT;                                                             \
355     else {                                                                    \
356       struct STRUCTTYPE *obj = SAFE_CTXT_CAST(STRUCTTYPE, ctxt);              \
357       if (obj) {                                                              \
358         char *str = GEDCOM_STRING(parsed_value);                              \
359         char *newvalue = strdup(str);                                         \
360         if (! newvalue)                                                       \
361           MEMORY_ERROR;                                                       \
362         else                                                                  \
363           obj->FIELD = newvalue;                                              \
364       }                                                                       \
365       destroy_gom_ctxt(ctxt);                                                 \
366     }                                                                         \
367   }
368
369 #define DEFINE_DATE_CB(STRUCTTYPE,CB_NAME,FIELD)                              \
370   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
371   {                                                                           \
372     Gom_ctxt result = NULL;                                                   \
373     if (! parent)                                                             \
374       NO_CONTEXT;                                                             \
375     else {                                                                    \
376       struct STRUCTTYPE *obj                                                  \
377         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
378       if (obj) {                                                              \
379         struct date_value dv = GEDCOM_DATE(parsed_value);                     \
380         obj->FIELD = gedcom_new_date_value(&dv);                              \
381         if (! obj->FIELD)                                                     \
382           MEMORY_ERROR;                                                       \
383         else                                                                  \
384           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
385       }                                                                       \
386     }                                                                         \
387     return (Gedcom_ctxt)result;                                               \
388   }
389
390 #define DEFINE_AGE_CB(STRUCTTYPE,CB_NAME,FIELD)                               \
391   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
392   {                                                                           \
393     Gom_ctxt result = NULL;                                                   \
394     if (! parent)                                                             \
395       NO_CONTEXT;                                                             \
396     else {                                                                    \
397       struct STRUCTTYPE *obj                                                  \
398         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
399       if (obj) {                                                              \
400         struct age_value age = GEDCOM_AGE(parsed_value);                      \
401         obj->FIELD = gedcom_new_age_value(&age);                              \
402         if (! obj->FIELD)                                                     \
403           MEMORY_ERROR;                                                       \
404         else                                                                  \
405           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
406       }                                                                       \
407     }                                                                         \
408     return (Gedcom_ctxt)result;                                               \
409   }
410
411 #define DEFINE_XREF_CB(STRUCTTYPE,CB_NAME,FIELD,LINKSTRTYPE)                  \
412   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
413   {                                                                           \
414     Gom_ctxt result = NULL;                                                   \
415     if (! parent)                                                             \
416       NO_CONTEXT;                                                             \
417     else {                                                                    \
418       struct STRUCTTYPE *obj                                                  \
419         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
420       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
421       if (! xr->object)                                                       \
422         xr->object = (Gedcom_ctxt) MAKEFUNC(LINKSTRTYPE)(xr->string);         \
423       if (obj) {                                                              \
424         obj->FIELD = xr;                                                      \
425         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
426       }                                                                       \
427     }                                                                         \
428     return (Gedcom_ctxt)result;                                               \
429   }
430
431 #define DEFINE_XREF_LIST_CB(STRUCTTYPE,CB_NAME,FIELD,LINKSTRTYPE)             \
432   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
433   {                                                                           \
434     Gom_ctxt result = NULL;                                                   \
435     if (! parent)                                                             \
436       NO_CONTEXT;                                                             \
437     else {                                                                    \
438       struct STRUCTTYPE *obj                                                  \
439         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
440       struct xref_value *xr = GEDCOM_XREF_PTR(parsed_value);                  \
441       struct xref_list *xrl;                                                  \
442       if (! xr->object)                                                       \
443         xr->object = (Gedcom_ctxt) MAKEFUNC(LINKSTRTYPE)(xr->string);         \
444       if (obj) {                                                              \
445         MAKE_CHAIN_ELT(xref_list, obj->FIELD, xrl);                           \
446         if (xrl) {                                                            \
447           xrl->xref = xr;                                                     \
448           result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                       \
449         }                                                                     \
450       }                                                                       \
451     }                                                                         \
452     return (Gedcom_ctxt)result;                                               \
453   }
454
455 #define DEFINE_NULL_CB(STRUCTTYPE,CB_NAME)                                    \
456   Gedcom_ctxt CB_NAME(_ELT_PARAMS_)                                           \
457   {                                                                           \
458     Gom_ctxt result = NULL;                                                   \
459     if (! parent)                                                             \
460       NO_CONTEXT;                                                             \
461     else {                                                                    \
462       struct STRUCTTYPE *obj                                                  \
463         = SAFE_CTXT_CAST(STRUCTTYPE, (Gom_ctxt)parent);                       \
464       if (obj)                                                                \
465         result = MAKE_GOM_CTXT(elt, STRUCTTYPE, obj);                         \
466     }                                                                         \
467     return (Gedcom_ctxt)result;                                               \
468   }
469
470
471
472 #endif /* __FUNC_TEMPLATE_H */