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