Allow elements out of context in GOM.
[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 (utf8_str == NULL) {
52     SAFE_FREE(*data);
53   }
54   else {
55     if (!is_utf8_string(utf8_str)) {
56       gedcom_error(_("The input '%s' is not a valid UTF-8 string"), utf8_str);
57     }
58     else {
59       newptr = strdup(utf8_str);
60       if (!newptr)
61         MEMORY_ERROR;
62       else {
63         SAFE_FREE(*data);
64         *data = newptr;
65         result = *data;
66       }
67     }
68   }
69   
70   return result;
71 }
72
73 char* gom_set_string_for_locale(char** data, const char* locale_str)
74 {
75   char* result = NULL;
76
77   if (locale_str == NULL) {
78     result = gom_set_string(data, NULL);
79   }
80   else {
81     char* utf8_str = convert_locale_to_utf8(locale_str);
82     
83     if (!utf8_str)
84       gedcom_error(_("The input '%s' is not a valid string for the locale"),
85                    locale_str);
86     else
87       result = gom_set_string(data, utf8_str);
88   }
89
90   return result;
91 }
92
93 void unref_xref_value(struct xref_value *xref)
94 {
95   if (xref)
96     gedcom_unlink_xref(xref->type, xref->string);
97 }
98
99 void UNREFALLFUNC(xref_list)(struct xref_list* obj)
100 {
101   if (obj) {
102     struct xref_list* runner;
103     for (runner = obj; runner; runner = runner->next) {
104       unref_xref_value(runner->xref);
105       UNREFALLFUNC(user_data)(runner->extra);
106     }
107   }
108 }
109
110 void CLEANFUNC(xref_list)(struct xref_list *obj)
111 {
112   if (obj) {
113     DESTROY_CHAIN_ELTS(user_data, obj->extra);
114   }
115 }
116
117 struct xref_value* gom_set_xref(struct xref_value** data, const char* xref)
118 {
119   struct xref_value* result = NULL;
120   struct xref_value* newval = NULL;
121   
122   if (data) {
123     if (xref) {
124       newval = gedcom_get_by_xref(xref);
125       if (!newval)
126         gedcom_error(_("No record found for xref '%s'"), xref);
127     }
128     
129     /* Unreference the old value if not NULL */
130     if (*data)
131       result = gedcom_unlink_xref((*data)->type, (*data)->string);
132     else
133       result = newval;
134     
135     /* Reference the new value if not NULL */
136     if (result != NULL && newval) {
137       result = gedcom_link_xref(newval->type, newval->string);
138       /* On error, perform rollback to old value (guaranteed to work) */
139       if (result == NULL)
140         gedcom_link_xref((*data)->type, (*data)->string);
141     }
142     
143     if (result != NULL) {
144       *data = newval;
145       result = newval;
146     }
147   }
148   return result;
149 }
150
151 struct xref_list* gom_add_xref(struct xref_list** data, const char* xref)
152 {
153   struct xref_value* result = NULL;
154   struct xref_value* newval = NULL;
155   struct xref_list* xrl = NULL;
156
157   if (data && xref) {
158     newval = gedcom_get_by_xref(xref);
159     if (!newval)
160       gedcom_error(_("No record found for xref '%s'"), xref);
161     else {
162       result = gedcom_link_xref(newval->type, newval->string);
163       if (result != NULL) {
164         MAKE_CHAIN_ELT(xref_list, *data, xrl);
165         if (xrl) xrl->xref = newval;
166       }
167     }
168   }
169
170   return xrl;
171 }
172
173 struct xref_list* find_xref(struct xref_list** data, const char* xref)
174 {
175   struct xref_list* result = NULL;
176   struct xref_value* xr = gedcom_get_by_xref(xref);
177   if (!xr)
178     gedcom_error(_("No record found for xref '%s'"), xref);
179   else {
180     struct xref_list* xrl;
181     for (xrl = *data ; xrl ; xrl = xrl->next) {
182       if (xrl->xref == xr) {
183         result = xrl;
184         break;
185       }
186     }
187     if (! result)
188       gedcom_error(_("Xref '%s' not part of chain"), xref);
189   }
190   return result;
191 }
192
193 int gom_remove_xref(struct xref_list** data, const char* xref)
194 {
195   int result = 1;
196
197   if (data && xref) {
198     struct xref_list* xrl = find_xref(data, xref);
199     if (xrl) {
200       UNLINK_CHAIN_ELT(xref_list, *data, xrl);
201       gedcom_unlink_xref(xrl->xref->type, xrl->xref->string);
202       CLEANFUNC(xref_list)(xrl);
203       SAFE_FREE(xrl);
204       result = 0;
205     }
206   }
207
208   return result;
209 }
210
211 int gom_move_xref(Gom_direction dir, struct xref_list** data, const char* xref)
212 {
213   int result = 1;
214
215   if (data && xref) {
216     struct xref_list* xrl = find_xref(data, xref);
217     if (xrl) {
218       MOVE_CHAIN_ELT(xref_list, dir, *data, xrl);
219       result = 0;
220     }
221   }
222
223   return result;
224 }