1 /*
2 Copyright (c) 1991-1999 Thomas T. Wetmore IV
3
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use, copy,
8 modify, merge, publish, distribute, sublicense, and/or sell copies
9 of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 /*=============================================================
25 * valid.c -- Record validation functions
26 * Copyright(c) 1992-96 by T.T. Wetmore IV; all rights reserved
27 * pre-SourceForge version information:
28 * 2.3.4 - 24 Jun 93 2.3.5 - 02 Sep 93
29 * 3.0.0 - 11 Sep 94 3.0.2 - 13 Dec 94
30 * 3.0.3 - 23 Jul 96
31 *===========================================================*/
32
33 #include "llstdlib.h"
34 #include "table.h"
35 #include "translat.h"
36 #include "gedcom.h"
37 #include "liflines.h"
38 #include "lloptions.h"
39
40
41 extern STRING qSbadind,qSbadfmc,qSbadfms,qSbadfam,qSbadhsb,qSbadwif,qSbadchl;
42 extern STRING qSbademp,qSbadin0,qSbadfm0,qSbadsr0,qSbadev0,qSbadothr0;
43 extern STRING qSbadmul,qSbadenm,qSbadparsex,qSbadirefn;
44
45 /*===================================
46 * valid_indi_tree -- Validate person tree
47 * indi1: [IN] person to validate
48 * pmsg: [OUT] error message, if any
49 * orig: [IN] person to match - may be NULL
50 * rtn: FALSE for bad
51 * Should be replaced by valid_indi(RECORD,...) ?
52 *=================================*/
53 BOOLEAN
valid_indi_tree(NODE indi1,STRING * pmsg,NODE orig)54 valid_indi_tree (NODE indi1, STRING *pmsg, NODE orig)
55 {
56 NODE refn;
57 NODE name1, refn1, sex1, body1, famc1, fams1, node;
58 NODE name0, refn0, sex0, body0, famc0, fams0;
59 INT isex, num;
60 STRING *keys, ukey;
61
62 if (!indi1) {
63 *pmsg = _(qSbademp);
64 return FALSE;
65 }
66 if (nestr("INDI", ntag(indi1))) {
67 *pmsg = _(qSbadin0);
68 return FALSE;
69 }
70 if (nsibling(indi1)) {
71 *pmsg = _(qSbadmul);
72 return FALSE;
73 }
74 split_indi_old(indi1, &name1, &refn1, &sex1, &body1, &famc1, &fams1);
75 if (getlloptint("RequireNames", 0) && !name1) {
76 *pmsg = _("This person record does not have a name line.");
77 goto bad2;
78 }
79 for (node = name1; node; node = nsibling(node)) {
80 if (!valid_name(nval(node))) {
81 *pmsg = _(qSbadenm);
82 goto bad2;
83 }
84 }
85 name0 = refn0 = sex0 = body0 = famc0 = fams0 = NULL;
86 if (orig)
87 split_indi_old(orig, &name0, &refn0, &sex0, &body0, &famc0,
88 &fams0);
89 if (orig && !iso_nodes(indi1, orig, FALSE, FALSE)) {
90 *pmsg = _(qSbadind);
91 goto bad1;
92 }
93 if (!iso_nodes(famc1, famc0, FALSE, TRUE)) {
94 *pmsg = _(qSbadfmc);
95 goto bad1;
96 }
97 if (!iso_nodes(fams1, fams0, FALSE, TRUE)) {
98 *pmsg = _(qSbadfms);
99 goto bad1;
100 }
101 isex = val_to_sex(sex0);
102 if (!fams0) isex = SEX_UNKNOWN;
103 if (isex != SEX_UNKNOWN && isex != val_to_sex(sex1)) {
104 *pmsg = _(qSbadparsex);
105 goto bad1;
106 }
107 /* if there are more than one refn should check each */
108 for (refn = refn1; refn != NULL; refn = nsibling(refn)) {
109 ukey = nval(refn);
110 get_refns(ukey, &num, &keys, 'I');
111 if (num > 1 || (num == 1 && (!orig ||
112 nestr(keys[0], rmvat(nxref(indi1)))))) {
113 *pmsg = _(qSbadirefn);
114 goto bad1;
115 }
116 }
117 if (orig)
118 join_indi(orig, name0, refn0, sex0, body0, famc0, fams0);
119 join_indi(indi1, name1, refn1, sex1, body1, famc1, fams1);
120 return TRUE;
121 bad1:
122 if (orig)
123 join_indi(orig, name0, refn0, sex0, body0, famc0, fams0);
124 bad2:
125 join_indi(indi1, name1, refn1, sex1, body1, famc1, fams1);
126 return FALSE;
127 }
128 /*===============================
129 * valid_fam_tree -- Validate FAM tree
130 * fam1, [IN] family to validate
131 * pmsg: [OUT] error message, if any
132 * fam0: [IN] family to match - may be NULL
133 * Should be replaced by valid_fam(RECORD,...) ?
134 *=============================*/
135 BOOLEAN
valid_fam_tree(NODE fam1,STRING * pmsg,NODE fam0)136 valid_fam_tree (NODE fam1, STRING *pmsg, NODE fam0)
137 {
138 NODE refn0, husb0, wife0, chil0, body0;
139 NODE refn1, husb1, wife1, chil1, body1;
140
141 if (!fam1) {
142 *pmsg = _(qSbademp);
143 return FALSE;
144 }
145 if (nestr("FAM", ntag(fam1))) {
146 *pmsg = _(qSbadfm0);
147 return FALSE;
148 }
149 if (nsibling(fam1)) {
150 *pmsg = _(qSbadmul);
151 return FALSE;
152 }
153
154 refn0 = husb0 = wife0 = chil0 = body0 = NULL;
155 if (fam0)
156 split_fam(fam0, &refn0, &husb0, &wife0, &chil0, &body0);
157 split_fam(fam1, &refn1, &husb1, &wife1, &chil1, &body1);
158
159 if (fam0 && !iso_nodes(fam1, fam0, FALSE, TRUE)) {
160 *pmsg = _(qSbadfam);
161 goto bad3;
162 }
163 if (!iso_nodes(husb1, husb0, FALSE, TRUE)) {
164 *pmsg = _(qSbadhsb);
165 goto bad3;
166 }
167 if (!iso_nodes(wife1, wife0, FALSE, TRUE)) {
168 *pmsg = _(qSbadwif);
169 goto bad3;
170 }
171 if (!iso_nodes(chil1, chil0, FALSE, TRUE)) {
172 *pmsg = _(qSbadchl);
173 goto bad3;
174 }
175 if (fam0)
176 join_fam(fam0, refn0, husb0, wife0, chil0, body0);
177 join_fam(fam1, refn1, husb1, wife1, chil1, body1);
178 return TRUE;
179 bad3:
180 if (fam0)
181 join_fam(fam0, refn0, husb0, wife0, chil0, body0);
182 join_fam(fam1, refn1, husb1, wife1, chil1, body1);
183 return FALSE;
184 }
185 /*============================
186 * valid_name -- Validate name
187 *==========================*/
188 BOOLEAN
valid_name(STRING name)189 valid_name (STRING name)
190 {
191 INT c, n = 0;
192 if (!name) return FALSE;
193 if (pointer_value(name)) return FALSE;
194 while ((c = *name++)) {
195 if (c == NAMESEP) n++;
196 }
197 return n <= 2;
198 }
199 /*======================================
200 * valid_node_type -- Validate top-level node tree
201 * node: [IN] node to validate
202 * ntype: [IN] I/F/S/E/X
203 * pmsg, [OUT] error message, if any
204 * orig: [IN] node to match (may be null)
205 *====================================*/
206 BOOLEAN
valid_node_type(NODE node,char ntype,STRING * pmsg,NODE node0)207 valid_node_type (NODE node, char ntype, STRING *pmsg, NODE node0)
208 {
209 switch(ntype) {
210 case 'I': return valid_indi_tree(node, pmsg, node0);
211 case 'F': return valid_fam_tree(node, pmsg, node0);
212 case 'S': return valid_sour_tree(node, pmsg, node0);
213 case 'E': return valid_even_tree(node, pmsg, node0);
214 default: return valid_othr_tree(node, pmsg, node0);
215 }
216 }
217 /*======================================
218 * valid_sour_tree -- Validate SOUR tree
219 * node: [IN] source to validate
220 * pmsg: [OUT] error message, if any
221 * orig: [IN] SOUR node to match
222 *====================================*/
223 BOOLEAN
valid_sour_tree(NODE node,STRING * pmsg,NODE orig)224 valid_sour_tree (NODE node, STRING *pmsg, NODE orig)
225 {
226 orig = NULL; /* keep compiler happy */
227 *pmsg = NULL;
228 if (!node) {
229 *pmsg = _(qSbademp);
230 return FALSE;
231 }
232 if (nestr("SOUR", ntag(node))) {
233 *pmsg = _(qSbadsr0);
234 return FALSE;
235 }
236 return TRUE;
237 }
238 /*======================================
239 * valid_even_tree -- Validate EVEN tree
240 * node: [IN] source to validate
241 * pmsg, [OUT] error message, if any
242 * orig: [IN] EVEN node to match
243 *====================================*/
244 BOOLEAN
valid_even_tree(NODE node,STRING * pmsg,NODE orig)245 valid_even_tree (NODE node, STRING *pmsg, NODE orig)
246 {
247 orig = NULL; /* keep compiler happy */
248 *pmsg = NULL;
249 if (!node) {
250 *pmsg = _(qSbademp);
251 return FALSE;
252 }
253 if (nestr("EVEN", ntag(node))) {
254 *pmsg = _(qSbadev0);
255 return FALSE;
256 }
257 return TRUE;
258 }
259 /*======================================
260 * valid_othr_tree -- Validate OTHR tree
261 * node: [IN] source to validate
262 * pmsg, [OUT] error message, if any
263 * orig: [IN] OTHR node to match
264 *====================================*/
265 BOOLEAN
valid_othr_tree(NODE node,STRING * pmsg,NODE orig)266 valid_othr_tree (NODE node, STRING *pmsg, NODE orig)
267 {
268 orig = NULL; /* keep compiler happy */
269 *pmsg = NULL;
270 if (!node) {
271 *pmsg = _(qSbademp);
272 return FALSE;
273 }
274 if (eqstr("INDI", ntag(node)) || eqstr("FAM", ntag(node))
275 || eqstr("SOUR", ntag(node)) || eqstr("EVEN", ntag(node))) {
276 *pmsg = _(qSbadothr0);
277 return FALSE;
278 }
279 return TRUE;
280 }
281 /*=========================================
282 * pointer_value -- See if value is pointer
283 *=======================================*/
284 BOOLEAN
pointer_value(STRING val)285 pointer_value (STRING val)
286 {
287 if (!val || *val != '@' || strlen(val) < 3) return FALSE;
288 return val[strlen(val)-1] == '@';
289 }
290