Unlink xrefs properly when struct is deleted.
[gedcom-parse.git] / gom / gom_modify.c
1 /* Source code for modifying 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 "utf8tools.h"
27 #include "user_rec.h"
28 #include "gom.h"
29 #include "gom_internal.h"
30
31 void gom_set_unknown(const char* unknown)
32 {
33   convert_set_unknown(unknown);
34 }
35
36 char* gom_get_string(char* data)
37 {
38   return data;
39 }
40
41 char* gom_get_string_for_locale(char* data, int* conversion_failures)
42 {
43   return convert_utf8_to_locale(gom_get_string(data), conversion_failures);
44 }
45
46 char* gom_set_string(char** data, const char* utf8_str)
47 {
48   char* result = NULL;
49   char* newptr;
50
51   if (!is_utf8_string(utf8_str)) {
52     gedcom_error(_("The input '%s' is not a valid UTF-8 string"), utf8_str);
53   }
54   else {
55     newptr = strdup(utf8_str);
56     if (!newptr)
57       MEMORY_ERROR;
58     else {
59       if (*data) free(*data);
60       *data = newptr;
61       result = *data;
62     }
63   }
64   
65   return result;
66 }
67
68 char* gom_set_string_for_locale(char** data, const char* locale_str)
69 {
70   char* result = NULL;
71   char* utf8_str = convert_locale_to_utf8(locale_str);
72   
73   if (!utf8_str)
74     gedcom_error(_("The input '%s' is not a valid string for the locale"),
75                  locale_str);
76   else
77     result = gom_set_string(data, utf8_str);
78
79   return result;
80 }
81
82 void unref_xref_value(struct xref_value *xref)
83 {
84   if (xref)
85     gedcom_unlink_xref(xref->type, xref->string);
86 }
87
88 void UNREFALLFUNC(xref_list)(struct xref_list* obj)
89 {
90   if (obj) {
91     struct xref_list* runner;
92     for (runner = obj; runner; runner = runner->next) {
93       unref_xref_value(runner->xref);
94       UNREFALLFUNC(user_data)(runner->extra);
95     }
96   }
97 }
98
99 void CLEANFUNC(xref_list)(struct xref_list *obj)
100 {
101   if (obj) {
102     DESTROY_CHAIN_ELTS(user_data, obj->extra);
103   }
104 }
105
106 struct xref_value* gom_set_xref(struct xref_value** data, const char* xref)
107 {
108   struct xref_value* result = NULL;
109   struct xref_value* newval = NULL;
110   
111   if (data) {
112     if (xref) {
113       newval = gedcom_get_by_xref(xref);
114       if (!newval)
115         gedcom_error(_("No record found for xref '%s'"), xref);
116     }
117     
118     /* Unreference the old value if not NULL */
119     if (*data)
120       result = gedcom_unlink_xref((*data)->type, (*data)->string);
121     else
122       result = newval;
123     
124     /* Reference the new value if not NULL */
125     if (result != NULL && newval) {
126       result = gedcom_link_xref(newval->type, newval->string);
127       /* On error, perform rollback to old value (guaranteed to work) */
128       if (result == NULL)
129         gedcom_link_xref((*data)->type, (*data)->string);
130     }
131     
132     if (result != NULL) {
133       *data = newval;
134       result = newval;
135     }
136   }
137   return result;
138 }
139
140 struct xref_list* gom_add_xref(struct xref_list** data, const char* xref)
141 {
142   struct xref_value* result = NULL;
143   struct xref_value* newval = NULL;
144   struct xref_list* xrl = NULL;
145
146   if (data && xref) {
147     newval = gedcom_get_by_xref(xref);
148     if (!newval)
149       gedcom_error(_("No record found for xref '%s'"), xref);
150     else {
151       result = gedcom_link_xref(newval->type, newval->string);
152       if (result != NULL) {
153         MAKE_CHAIN_ELT(xref_list, *data, xrl);
154         if (xrl) xrl->xref = newval;
155       }
156     }
157   }
158
159   return xrl;
160 }
161
162 int gom_remove_xref(struct xref_list** data, const char* xref)
163 {
164   struct xref_value* xr = NULL;
165   int result = 1;
166   
167   if (data && xref) {
168     xr = gedcom_get_by_xref(xref);
169     if (!xr)
170       gedcom_error(_("No record found for xref '%s'"), xref);
171     else {
172       struct xref_list* xrl = NULL;
173       for (xrl = *data ; xrl ; xrl = xrl->next) {
174         if (xrl->xref == xr) {
175           UNLINK_CHAIN_ELT(xref_list, *data, xrl);
176           gedcom_unlink_xref(xr->type, xr->string);
177           CLEANFUNC(xref_list)(xrl);
178           SAFE_FREE(xrl);
179           result = 0;
180           break;
181         }
182       }
183       if (result == 1)
184         gedcom_error(_("Xref '%s' to remove not part of chain"), xref);
185     }
186   }
187
188   return result;
189 }