Unlink xrefs properly when struct is deleted.
[gedcom-parse.git] / gom / event.c
1 /* Event sub-structure in the gedcom object model.
2    Copyright (C) 2002 The Genes Development Team
3    This file is part of the Gedcom parser library.
4    Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2002.
5
6    The Gedcom parser library is free software; you can redistribute it
7    and/or modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The Gedcom parser library is distributed in the hope that it will be
12    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the Gedcom parser library; if not, write to the
18    Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 /* $Id$ */
22 /* $Name$ */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include "family.h"
27 #include "individual.h"
28 #include "event.h"
29 #include "place.h"
30 #include "address.h"
31 #include "source_citation.h"
32 #include "multimedia_link.h"
33 #include "note_sub.h"
34 #include "user_rec.h"
35 #include "gom.h"
36 #include "gedcom.h"
37 #include "gom_internal.h"
38
39 Gedcom_ctxt sub_evt_start(_ELT_PARAMS_)
40 {
41   Gom_ctxt ctxt = (Gom_ctxt)parent;
42   Gom_ctxt result = NULL;
43
44   if (! ctxt)
45     NO_CONTEXT;
46   else {
47     struct event *evt = SUB_MAKEFUNC(event)();
48     if (evt) {
49       evt->event = parsed_tag;
50       evt->event_name = strdup(tag);
51       if (! evt->event_name) {
52         MEMORY_ERROR;
53         free(evt);
54       }
55       else {
56         int err = 0;
57         if (GEDCOM_IS_STRING(parsed_value)) {
58           evt->val = strdup(GEDCOM_STRING(parsed_value));
59           if (! evt->val) {
60             MEMORY_ERROR;
61             free(evt->event_name);
62             free(evt);
63             err = 1;
64           }
65         }
66
67         if (! err) {
68           switch (ctxt->ctxt_type) {
69             case REC_FAM:
70               ADDFUNC2(family,event)(ctxt, evt); break;
71             case REC_INDI:
72               ADDFUNC2(individual,event)(ctxt, evt); break;
73             default:
74               UNEXPECTED_CONTEXT(ctxt->ctxt_type);
75           }
76           result = MAKE_GOM_CTXT(elt, event, evt);
77         }
78       }
79     }
80   }
81
82   return (Gedcom_ctxt)result;
83 }
84
85 Gedcom_ctxt sub_attr_start(_ELT_PARAMS_)
86 {
87   Gom_ctxt ctxt = (Gom_ctxt)parent;
88   Gom_ctxt result = NULL;
89
90   if (! ctxt)
91     NO_CONTEXT;
92   else {
93     struct event *evt = SUB_MAKEFUNC(event)();
94     if (evt) {
95       evt->event = parsed_tag;
96       evt->event_name = strdup(tag);
97       if (! evt->event_name) {
98         MEMORY_ERROR;
99         free(evt);
100       }
101       else {
102         int err = 0;
103         if (GEDCOM_IS_STRING(parsed_value)) {
104           evt->val = strdup(GEDCOM_STRING(parsed_value));
105           if (! evt->val) {
106             MEMORY_ERROR;
107             free(evt->event_name);
108             free(evt);
109             err = 1;
110           }
111         }
112
113         if (! err) {
114           switch (ctxt->ctxt_type) {
115             case REC_INDI:
116               ADDFUNC2_TOVAR(individual,event,attribute)(ctxt, evt); break;
117             default:
118               UNEXPECTED_CONTEXT(ctxt->ctxt_type);
119           }
120           result = MAKE_GOM_CTXT(elt, event, evt);
121         }
122       }
123     }
124   }
125   return (Gedcom_ctxt)result;
126 }
127
128 DEFINE_SUB_MAKEFUNC(event)
129      
130 DEFINE_STRING_CB(event, sub_evt_type_start, type)
131 DEFINE_DATE_CB(event, sub_evt_date_start, date)
132 DEFINE_AGE_CB(event, sub_evt_age_start, age)
133 DEFINE_STRING_CB(event, sub_evt_agnc_start, agency)
134 DEFINE_STRING_CB(event, sub_evt_caus_start, cause)
135 DEFINE_NULL_CB(event, sub_fam_evt_husb_wife_start)
136 DEFINE_XREF_CB(event, sub_evt_famc_start, family, family)
137 DEFINE_STRING_CB(event, sub_evt_famc_adop_start, adoption_parent)
138      
139 DEFINE_ADDFUNC2(event, source_citation, citation)
140 DEFINE_ADDFUNC2(event, multimedia_link, mm_link)
141 DEFINE_ADDFUNC2(event, note_sub, note)
142 DEFINE_ADDFUNC2(event, user_data, extra)
143 DEFINE_ADDFUNC2_NOLIST(event, place, place)
144 DEFINE_ADDFUNC2_NOLIST(event, address, address)
145 DEFINE_ADDFUNC2_STRN(event, phone, 3)
146
147 Gedcom_ctxt sub_fam_evt_age_start(_ELT_PARAMS_)
148 {
149   Gom_ctxt ctxt = (Gom_ctxt)parent;
150   Gom_ctxt result = NULL;
151   
152   if (! ctxt)
153     NO_CONTEXT;
154   else {
155     struct event *evt = SAFE_CTXT_CAST(event, ctxt);
156     if (evt) {
157       int err = 0;
158       struct age_value age = GEDCOM_AGE(parsed_value);
159       switch (ctxt->ctxt_type) {
160         case ELT_SUB_FAM_EVT_HUSB:
161           evt->husband_age = gedcom_new_age_value(&age);
162           if (! evt->husband_age) {
163             MEMORY_ERROR;
164             err = 1;
165           }
166           break;
167         case ELT_SUB_FAM_EVT_WIFE:
168           evt->wife_age = gedcom_new_age_value(&age);
169           if (! evt->wife_age) {
170             MEMORY_ERROR;
171             err = 1;
172           }
173           break;
174         default:
175           UNEXPECTED_CONTEXT(ctxt->ctxt_type);
176       }
177       if (! err)
178         result = MAKE_GOM_CTXT(elt, event, evt);
179     }
180   }
181   return (Gedcom_ctxt)result;
182 }
183
184 void event_subscribe()
185 {
186   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT, sub_evt_start, def_elt_end);
187   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_EVEN,
188                               sub_evt_start, def_elt_end);
189   gedcom_subscribe_to_element(ELT_SUB_INDIV_ATTR,
190                               sub_attr_start, def_elt_end);  
191   gedcom_subscribe_to_element(ELT_SUB_INDIV_RESI,
192                               sub_attr_start, def_elt_end);
193   gedcom_subscribe_to_element(ELT_SUB_INDIV_BIRT,
194                               sub_evt_start, def_elt_end);
195   gedcom_subscribe_to_element(ELT_SUB_INDIV_BIRT_FAMC,
196                               sub_evt_famc_start, def_elt_end);
197   gedcom_subscribe_to_element(ELT_SUB_INDIV_GEN,
198                               sub_evt_start, def_elt_end);
199   gedcom_subscribe_to_element(ELT_SUB_INDIV_ADOP,
200                               sub_evt_start, def_elt_end);
201   gedcom_subscribe_to_element(ELT_SUB_INDIV_ADOP_FAMC,
202                               sub_evt_famc_start, def_elt_end);
203   gedcom_subscribe_to_element(ELT_SUB_INDIV_ADOP_FAMC_ADOP,
204                               sub_evt_famc_adop_start, def_elt_end);
205   gedcom_subscribe_to_element(ELT_SUB_INDIV_EVEN,
206                               sub_evt_start, def_elt_end);
207   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_HUSB,
208                               sub_fam_evt_husb_wife_start, def_elt_end);
209   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_WIFE,
210                               sub_fam_evt_husb_wife_start, def_elt_end);
211   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_AGE,
212                               sub_fam_evt_age_start, def_elt_end);
213   gedcom_subscribe_to_element(ELT_SUB_EVT_TYPE,
214                               sub_evt_type_start, def_elt_end);
215   gedcom_subscribe_to_element(ELT_SUB_EVT_DATE,
216                               sub_evt_date_start, def_elt_end);
217   gedcom_subscribe_to_element(ELT_SUB_EVT_AGE,
218                               sub_evt_age_start, def_elt_end);
219   gedcom_subscribe_to_element(ELT_SUB_EVT_AGNC,
220                               sub_evt_agnc_start, def_elt_end);
221   gedcom_subscribe_to_element(ELT_SUB_EVT_CAUS,
222                               sub_evt_caus_start, def_elt_end);
223 }
224
225 void UNREFALLFUNC(event)(struct event* obj)
226 {
227   if (obj) {
228     struct event* runner;
229     for (runner = obj; runner; runner = runner->next) {
230       UNREFALLFUNC(place)(runner->place);
231       UNREFALLFUNC(address)(runner->address);
232       UNREFALLFUNC(source_citation)(runner->citation);
233       UNREFALLFUNC(multimedia_link)(runner->mm_link);
234       UNREFALLFUNC(note_sub)(runner->note);
235       unref_xref_value(runner->family);
236       UNREFALLFUNC(user_data)(runner->extra);
237     }
238   }
239 }
240
241 void CLEANFUNC(event)(struct event* evt)
242 {
243   if (evt) {
244     SAFE_FREE(evt->event_name);
245     SAFE_FREE(evt->val);
246     SAFE_FREE(evt->type);
247     SAFE_FREE(evt->date);
248     CLEANFUNC(place)(evt->place);
249     CLEANFUNC(address)(evt->address);
250     SAFE_FREE(evt->phone[0]);
251     SAFE_FREE(evt->phone[1]);
252     SAFE_FREE(evt->phone[2]);
253     SAFE_FREE(evt->age);
254     SAFE_FREE(evt->agency);
255     SAFE_FREE(evt->cause);
256     DESTROY_CHAIN_ELTS(source_citation, evt->citation);
257     DESTROY_CHAIN_ELTS(multimedia_link, evt->mm_link);
258     DESTROY_CHAIN_ELTS(note_sub, evt->note);
259     SAFE_FREE(evt->husband_age);
260     SAFE_FREE(evt->wife_age);
261     SAFE_FREE(evt->adoption_parent);
262     DESTROY_CHAIN_ELTS(user_data, evt->extra);
263   }
264 }
265
266 static int get_gedcom_elt(EventType evt_type, int parsed_tag)
267 {
268   int obj_elt = 0;
269   switch (evt_type) {
270     case EVT_TYPE_FAMILY:
271       obj_elt = (parsed_tag == TAG_EVEN ? ELT_SUB_FAM_EVT_EVEN :
272                  ELT_SUB_FAM_EVT);
273       break;
274     case EVT_TYPE_INDIV_ATTR:
275       obj_elt = (parsed_tag == TAG_RESI ? ELT_SUB_INDIV_RESI :
276                  ELT_SUB_INDIV_ATTR);
277       break;
278     case EVT_TYPE_INDIV_EVT:
279       switch (parsed_tag) {
280         case TAG_BIRT: case TAG_CHR:
281           obj_elt = ELT_SUB_INDIV_BIRT; break;
282         case TAG_DEAT: case TAG_BURI: case TAG_CREM: case TAG_BAPM:
283         case TAG_BARM: case TAG_BASM: case TAG_BLES: case TAG_CHRA:
284         case TAG_CONF: case TAG_FCOM: case TAG_ORDN: case TAG_NATU:
285         case TAG_EMIG: case TAG_IMMI: case TAG_CENS: case TAG_PROB:
286         case TAG_WILL: case TAG_GRAD: case TAG_RETI:
287           obj_elt = ELT_SUB_INDIV_GEN; break;
288         case TAG_ADOP:
289           obj_elt = ELT_SUB_INDIV_ADOP; break;
290         case TAG_EVEN:
291           obj_elt = ELT_SUB_INDIV_EVEN; break;
292         default:
293           gedcom_warning(_("Internal error: unknown evt tag %d"), parsed_tag);
294       }
295       break;
296     default:
297       gedcom_warning(_("Internal error: unknown evt type %d"), evt_type);
298   }
299   return obj_elt;
300 }
301
302 int get_gedcom_fam_elt(int elt)
303 {
304   int fam_obj_elt = 0;
305   switch (elt) {
306     case ELT_SUB_INDIV_BIRT:
307       fam_obj_elt = ELT_SUB_INDIV_BIRT_FAMC;
308       break;
309     case ELT_SUB_INDIV_ADOP:
310       fam_obj_elt = ELT_SUB_INDIV_ADOP_FAMC;
311       break;
312     default:
313       gedcom_warning(_("Internal error: wrong parent for evt->family"));
314   }
315   return fam_obj_elt;
316 }
317
318 int write_events(Gedcom_write_hndl hndl, int parent, EventType evt_type,
319                  struct event* evt)
320 {
321   int result = 0;
322   int i;
323   struct event* obj;
324
325   if (!evt) return 1;
326
327   for (obj = evt; obj; obj = obj->next) {
328     int obj_elt = get_gedcom_elt(evt_type, obj->event);
329     result |= gedcom_write_element_str(hndl, obj_elt, obj->event,
330                                        parent, obj->val);
331     if (obj->type)
332       result |= gedcom_write_element_str(hndl, ELT_SUB_EVT_TYPE, 0,
333                                          obj_elt, obj->type);
334     if (obj->date)
335       result |= gedcom_write_element_date(hndl, ELT_SUB_EVT_DATE, 0,
336                                           obj_elt, obj->date);
337     if (obj->place)
338       result |= write_place(hndl, obj_elt, obj->place);
339     if (obj->address)
340       result |= write_address(hndl, obj_elt, obj->address);
341     for (i = 0; i < 3 && obj->phone[i]; i++)
342       result |= gedcom_write_element_str(hndl, ELT_SUB_PHON, 0, obj_elt,
343                                          obj->phone[i]);
344     if (obj->age)
345       result |= gedcom_write_element_age(hndl, ELT_SUB_EVT_AGE, 0,
346                                          obj_elt, obj->age);
347     if (obj->agency)
348       result |= gedcom_write_element_str(hndl, ELT_SUB_EVT_AGNC, 0,
349                                          obj_elt, obj->agency);
350     if (obj->cause)
351       result |= gedcom_write_element_str(hndl, ELT_SUB_EVT_CAUS, 0,
352                                          obj_elt, obj->cause);
353     if (obj->citation)
354       result |= write_citations(hndl, obj_elt, obj->citation);
355     if (obj->mm_link)
356       result |= write_multimedia_links(hndl, obj_elt, obj->mm_link);
357     if (obj->note)
358       result |= write_note_subs(hndl, obj_elt, obj->note);
359     if (obj->husband_age) {
360       result |= gedcom_write_element_str(hndl, ELT_SUB_FAM_EVT_HUSB, 0,
361                                          obj_elt, NULL);
362       result |= gedcom_write_element_age(hndl, ELT_SUB_FAM_EVT_AGE, 0,
363                                          ELT_SUB_FAM_EVT_HUSB,
364                                          obj->husband_age);
365     }
366     if (obj->wife_age) {
367       result |= gedcom_write_element_str(hndl, ELT_SUB_FAM_EVT_WIFE, 0,
368                                          obj_elt, NULL);
369       result |= gedcom_write_element_age(hndl, ELT_SUB_FAM_EVT_AGE, 0,
370                                          ELT_SUB_FAM_EVT_WIFE,
371                                          obj->wife_age);
372     }
373     if (obj->family) {
374       int fam_obj_elt = get_gedcom_fam_elt(obj_elt);
375       result |= gedcom_write_element_xref(hndl, fam_obj_elt, 0,
376                                           obj_elt, obj->family);
377       if (obj->adoption_parent) {
378         result |= gedcom_write_element_str(hndl, ELT_SUB_INDIV_ADOP_FAMC_ADOP,
379                                            0, fam_obj_elt,
380                                            obj->adoption_parent);
381       }
382     }
383     if (obj->extra)
384       result |= write_user_data(hndl, obj->extra);
385   }
386   
387   return result;
388 }
389