Allow elements out of context in GOM.
[gedcom-parse.git] / gom / user_rec.c
1 /* User record object 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 "header.h"
27 #include "submission.h"
28 #include "submitter.h"
29 #include "family.h"
30 #include "individual.h"
31 #include "multimedia.h"
32 #include "note.h"
33 #include "repository.h"
34 #include "source.h"
35 #include "address.h"
36 #include "event.h"
37 #include "place.h"
38 #include "source_citation.h"
39 #include "note_sub.h"
40 #include "multimedia_link.h"
41 #include "lds_event.h"
42 #include "user_ref.h"
43 #include "change_date.h"
44 #include "personal_name.h"
45 #include "family_link.h"
46 #include "association.h"
47 #include "source_event.h"
48 #include "source_description.h"
49 #include "user_rec.h"
50 #include "gom.h"
51 #include "gedcom.h"
52 #include "gom_internal.h"
53
54 struct user_rec* gom_first_user_rec = NULL;
55
56 Gedcom_ctxt user_rec_start(_REC_PARAMS_)
57 {
58   struct user_rec* user = NULL;
59   struct xref_value* xr = NULL;
60   Gom_ctxt result  = NULL;
61   Gedcom_ctxt ctxt = NULL;
62   int err = 0;
63   
64   if (GEDCOM_IS_XREF_PTR(xref))
65     xr = GEDCOM_XREF_PTR(xref);
66   if (xr) {
67     if (! xr->object) {
68       user = MAKEFUNC(user_rec)(xr->string);
69       xr->object = (Gedcom_ctxt) user;
70     }
71     ctxt = xr->object;
72     if (ctxt) {
73       user = (struct user_rec*) ctxt;
74     }
75   }
76   else {
77     user = MAKEFUNC(user_rec)(NULL);
78     ctxt = (Gedcom_ctxt) user;
79   }
80
81   if (user) {
82     user->tag = strdup(tag);
83     if (! user->tag) {
84       MEMORY_ERROR;
85       err = 1;
86     }
87     else if (GEDCOM_IS_STRING(parsed_value)) {
88       user->str_value = strdup(GEDCOM_STRING(parsed_value));
89       if (!user->str_value) {
90         MEMORY_ERROR;
91         err = 1;
92       }
93     }
94     else if (GEDCOM_IS_XREF_PTR(parsed_value))
95       user->xref_value = GEDCOM_XREF_PTR(parsed_value);
96     
97     if (! err)
98       result = MAKE_GOM_CTXT(rec, user_rec, ctxt);
99   }
100   
101   return (Gedcom_ctxt)result;
102 }
103
104 DEFINE_DESTROYFUNC(user_rec, gom_first_user_rec)
105 DEFINE_DELETEFUNC(user_rec)
106 DEFINE_GETXREFFUNC(user_rec, XREF_USER)
107
108 DEFINE_ADDFUNC2(user_rec, user_data, extra)
109
110 /* Specific function, because xrefstr not mandatory here */
111 struct user_rec* MAKEFUNC(user_rec)(const char* xrefstr)
112 {
113   struct user_rec* rec = NULL;
114   MAKE_CHAIN_ELT(user_rec, gom_first_user_rec, rec);
115   if (rec && xrefstr) {
116     rec->xrefstr = strdup(xrefstr);
117     if (! rec->xrefstr) MEMORY_ERROR;
118   }
119   return rec;
120 }
121
122 struct user_rec* ADDFUNC(user_rec)(const char* xrefstr, const char* tag)
123 {
124   struct user_rec *obj = NULL;
125   struct xref_value* xrv = gedcom_get_by_xref(xrefstr);
126   if (tag && tag[0] == '_') {
127     if (xrv)
128       gom_xref_already_in_use(xrefstr);
129     else {
130       obj = MAKEFUNC(user_rec)(xrefstr);
131       if (obj) {
132         obj->tag = strdup(tag);
133         if (! obj->tag)
134           MEMORY_ERROR;
135         else
136           xrv = gedcom_add_xref(XREF_USER, xrefstr, (Gedcom_ctxt)obj);
137         if (!xrv) {
138           DESTROYFUNC(user_rec)(obj);
139           obj = NULL;
140         }
141       }
142     }
143   }
144   return obj;
145 }
146
147 Gedcom_ctxt user_elt_start(_ELT_PARAMS_)
148 {
149   Gom_ctxt ctxt = (Gom_ctxt)parent;
150   Gom_ctxt result = NULL;
151   int err = 0;
152
153   if (! ctxt)
154     NO_CONTEXT;
155   else {
156     struct user_data *data
157       = (struct user_data *)malloc(sizeof(struct user_data));
158
159     if (! data)
160       MEMORY_ERROR;
161     else {
162       memset (data, 0, sizeof(struct user_data));
163       
164       data->level = level;
165       data->tag = strdup(tag);
166       if (! data->tag) {
167         MEMORY_ERROR;
168         free(data);
169         err = 1;
170       }
171       else if (GEDCOM_IS_STRING(parsed_value)) {
172         data->str_value = strdup(GEDCOM_STRING(parsed_value));
173         if (! data->str_value) {
174           MEMORY_ERROR;
175           free(data->tag);
176           free(data->str_value);
177           err = 1;
178         }
179       }
180       else if (GEDCOM_IS_XREF_PTR(parsed_value))
181         data->xref_value = GEDCOM_XREF_PTR(parsed_value);
182
183       if (! err) {
184         switch (ctxt_obj_type(ctxt)) {
185           case T_header:
186             ADDFUNC2(header,user_data)(ctxt, data); break;
187           case T_submission:
188             ADDFUNC2(submission,user_data)(ctxt, data); break;
189           case T_submitter:
190             ADDFUNC2(submitter,user_data)(ctxt, data); break;
191           case T_family:
192             ADDFUNC2(family,user_data)(ctxt, data); break;
193           case T_individual:
194             ADDFUNC2(individual,user_data)(ctxt, data); break;
195           case T_multimedia:
196             ADDFUNC2(multimedia,user_data)(ctxt, data); break;
197           case T_note:
198             ADDFUNC2(note,user_data)(ctxt, data); break;
199           case T_repository:
200             ADDFUNC2(repository,user_data)(ctxt, data); break;
201           case T_source:
202             ADDFUNC2(source,user_data)(ctxt, data); break;
203           case T_user_rec:
204             ADDFUNC2(user_rec,user_data)(ctxt, data); break;
205           case T_address:
206             ADDFUNC2(address,user_data)(ctxt, data); break;
207           case T_event:
208             ADDFUNC2(event,user_data)(ctxt, data); break;
209           case T_place:
210             ADDFUNC2(place,user_data)(ctxt, data); break;
211           case T_source_citation:
212             ADDFUNC2(source_citation,user_data)(ctxt, data); break;
213           case T_note_sub:
214             ADDFUNC2(note_sub,user_data)(ctxt, data); break;
215           case T_multimedia_link:
216             ADDFUNC2(multimedia_link,user_data)(ctxt, data); break;
217           case T_lds_event:
218             ADDFUNC2(lds_event,user_data)(ctxt, data); break;
219           case T_user_ref_number:
220             ADDFUNC2(user_ref_number,user_data)(ctxt, data); break;
221           case T_change_date:
222             ADDFUNC2(change_date,user_data)(ctxt, data); break;
223           case T_personal_name:
224             ADDFUNC2(personal_name,user_data)(ctxt, data); break;
225           case T_family_link:
226             ADDFUNC2(family_link,user_data)(ctxt, data); break;
227           case T_association:
228             ADDFUNC2(association,user_data)(ctxt, data); break;
229           case T_source_event:
230             ADDFUNC2(source_event,user_data)(ctxt, data); break;
231           case T_source_description:
232             ADDFUNC2(source_description,user_data)(ctxt, data); break;
233           default:
234             UNEXPECTED_CONTEXT(ctxt_type(ctxt));
235         }
236         result = dup_gom_ctxt(ctxt, elt);
237       }
238     }
239   }
240   
241   return (Gedcom_ctxt)result;
242 }
243
244 DEFINE_SUB_MAKEFUNC(user_data)
245 DEFINE_SUB_ADDFUNC(user_data)
246 DEFINE_SUB_FINDFUNC(user_data)
247 DEFINE_SUB_REMOVEFUNC(user_data)
248 DEFINE_SUB_MOVEFUNC(user_data)
249      
250 void user_rec_subscribe()
251 {
252   gedcom_subscribe_to_record(REC_USER, user_rec_start, def_rec_end);
253   gedcom_subscribe_to_element(ELT_USER, user_elt_start, def_elt_end);
254 }
255
256 void UNREFALLFUNC(user_data)(struct user_data *obj)
257 {
258   if (obj) {
259     struct user_data* runner;
260     for (runner = obj; runner; runner = runner->next)
261       unref_xref_value(runner->xref_value);
262   }
263 }
264
265 void CLEANFUNC(user_data)(struct user_data* data)
266 {
267   if (data) {
268     SAFE_FREE(data->tag);
269     SAFE_FREE(data->str_value);
270   }
271 }
272
273 void UNREFALLFUNC(user_rec)(struct user_rec *obj)
274 {
275   if (obj) {
276     unref_xref_value(obj->xref_value);
277     UNREFALLFUNC(user_data)(obj->extra);
278   }
279 }
280
281 void CLEANFUNC(user_rec)(struct user_rec* rec)
282 {
283   if (rec) {
284     SAFE_FREE(rec->xrefstr);
285     SAFE_FREE(rec->tag);
286     SAFE_FREE(rec->str_value);
287     DESTROY_CHAIN_ELTS(user_data, rec->extra);
288   }
289 }
290
291 void user_recs_cleanup()
292 {
293   DESTROY_CHAIN_ELTS(user_rec, gom_first_user_rec);
294 }
295
296 struct user_rec* gom_get_first_user_rec()
297 {
298   return gom_first_user_rec;
299 }
300
301 int write_user_recs(Gedcom_write_hndl hndl)
302 {
303   int result = 0;
304   struct user_rec* obj;
305
306   for (obj = gom_first_user_rec; obj; obj = obj->next) {
307     if (obj->xref_value)
308       result |= gedcom_write_user_xref(hndl, 0, obj->tag, obj->xrefstr,
309                                        obj->xref_value);
310     else
311       result |= gedcom_write_user_str(hndl, 0, obj->tag, obj->xrefstr,
312                                       obj->str_value);
313     if (obj->extra)
314       result |= write_user_data(hndl, obj->extra);
315   }
316   return result;  
317 }
318
319 int write_user_data(Gedcom_write_hndl hndl, struct user_data* data)
320 {
321   int result = 0;
322   struct user_data* obj;
323
324   if (!data) return 1;
325
326   for (obj = data; obj; obj = obj->next) {
327     if (obj->xref_value)
328       result |= gedcom_write_user_xref(hndl, obj->level, obj->tag, NULL,
329                                        obj->xref_value);
330     else {
331       result |= gedcom_write_user_str(hndl, obj->level, obj->tag, NULL,
332                                       obj->str_value);
333     }
334   }
335   return result;
336 }