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