1 /*
2    Copyright (c) 1991-2005 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 /* modified 05 Jan 2000 by Paul B. McBride (pmcbride@tiac.net) */
25 /*=============================================================
26  * gedcom_macros.h -- Macros used by or implemented by gedcom module
27  *===========================================================*/
28 
29 #ifndef GEDCOM_MACROS_H_INCLUDED
30 #define GEDCOM_MACROS_H_INCLUDED
31 
32 /*******************
33  various Macros
34  *******************/
35 
36 
37 #define NAME(indi)  find_tag(nchild(indi),"NAME")
38 #define REFN(indi)  find_tag(nchild(indi),"REFN")
39 #define SEX(indi)   val_to_sex(find_tag(nchild(indi),"SEX"))
40 #define BIRT(indi)  find_tag(nchild(indi),"BIRT")
41 #define DEAT(indi)  find_tag(nchild(indi),"DEAT")
42 #define BAPT(indi)  find_tag(nchild(indi),"CHR")
43 #define BURI(indi)  find_tag(nchild(indi),"BURI")
44 #define FAMC(indi)  find_tag(nchild(indi),"FAMC")
45 #define FAMS(indi)  find_tag(nchild(indi),"FAMS")
46 
47 #define HUSB(fam)   find_tag(nchild(fam),"HUSB")
48 #define WIFE(fam)   find_tag(nchild(fam),"WIFE")
49 #define MARR(fam)   find_tag(nchild(fam),"MARR")
50 #define CHIL(fam)   find_tag(nchild(fam),"CHIL")
51 
52 #define DATE(evnt)   find_tag(nchild(evnt),"DATE")
53 #define PLAC(evnt)   find_tag(nchild(evnt),"PLAC")
54 
55 /*=============================================
56  * indi_to_key, fam_to_key - return key of node
57  *  eg, "I21"
58  *  returns static buffer
59  *===========================================*/
60 #define indi_to_key(indi)  (rmvat(nxref(indi)))
61 #define fam_to_key(fam)    (rmvat(nxref(fam)))
62 #define node_to_key(node)  (rmvat(nxref(node)))
63 
64 /*=============================================
65  * indi_to_keynum, fam_to_keynum, etc -
66  *  return keynum of node, eg, 21
67  *===========================================*/
68 #define indi_to_keynum(indi) (node_to_keynum('I', indi))
69 #define fam_to_keynum(fam)  (node_to_keynum('F', fam))
70 #define sour_to_keynum(sour) (node_to_keynum('S', sour))
71 
72 /*=============================================
73  * num_families - count spouses of indi
74  *===========================================*/
75 #define num_families(indi) (length_nodes(FAMS(indi)))
76 
77  /*=============================================
78  * num_children - count children of indi
79  *===========================================*/
80 #define num_children(fam)  (length_nodes(CHIL(fam)))
81 
82 /*
83   Possibly all of these should lock their main argument in the cache
84   Instead of having some of the client code do it, and some not
85   Now that NODE has a pointer to its parent RECORD,
86   and RECORD has a pointer to the cacheel, it is possible
87 */
88 /*
89  FORCHILDRENx takes a node as its first arg
90  FORCHILDREN takes a record as its first arg
91 */
92 
93 #define FORCHILDRENx(fam,child,num) \
94 	{\
95 	NODE __node = find_tag(nchild(fam), "CHIL");\
96 	RECORD irec=0;\
97 	NODE child=0;\
98 	STRING __key=0;\
99 	num = 0;\
100 	while (__node) {\
101 		if (!eqstr(ntag(__node), "CHIL")) break;\
102 		__key = rmvat(nval(__node));\
103 		__node = nsibling(__node);\
104 		++num;\
105 		if (!__key || !(irec=qkey_to_irecord(__key)) || !(child=nztop(irec))) {\
106 			continue;\
107 		}\
108 		{
109 
110 #define ENDCHILDRENx \
111 		}\
112 		release_record(irec);\
113 	}}
114 
115 #define FORCHILDREN(fam,child,num) \
116 	{\
117 	NODE __node = find_tag(nchild(fam), "CHIL");\
118 	RECORD child=0, irec=0;\
119 	STRING __key=0;\
120 	num = 0;\
121 	while (__node) {\
122 		if (!eqstr(ntag(__node), "CHIL")) break;\
123 		__key = rmvat(nval(__node));\
124 		__node = nsibling(__node);\
125 		++num;\
126 		if (!__key || !(child = key_to_irecord(__key))) {\
127 			continue;\
128 		}\
129 		irec=child;\
130 		{
131 
132 #define ENDCHILDREN \
133 		}\
134 		release_record(irec);\
135 	}}
136 
137 /* FORSPOUSES iterate over all FAMS nodes & all spouses of indi
138  * if there are multiple spouses, user will see same fam with multiple spouses
139  * if there are no spouses for a particular family the family is not returned.
140  * the counter, num, is only incremented for each spouse returned
141  *     i.e. it doesn't count indi as a spouse.
142  */
143 #define FORSPOUSES(indi,spouse,fam,num) \
144 	{\
145 	NODE __node = find_tag(nchild(indi),"FAMS");\
146 	NODE __node1=0, fam=0;\
147 	STRING __key=0;\
148 	num = 0;\
149 	while (__node) {\
150 		if (!eqstr(ntag(__node), "FAMS")) break;\
151 	    __key = rmvat(nval(__node));\
152 	    __node = nsibling(__node);\
153 	    if (!__key || !(fam = qkey_to_fam(__key))) {\
154 			continue;\
155 		}\
156 		__node1 = nchild(fam);\
157 		/* Now loop through fam node tree looking for spouses */\
158 		while (__node1) {\
159 			NODE spouse=0;\
160 			INT __hits=0;\
161 			if (eqstr(ntag(__node1), "HUSB")||eqstr(ntag(__node1), "WIFE")) ++__hits;\
162 			else if (__hits)\
163 				/* Its not HUSB or WIFE, and we've seen a HUSB or WIFE before */ \
164 				/* So we must be out of the HUSB & WIFE section of the node tree */ \
165 				break;\
166 			__key = rmvat(nval(__node1));\
167 			__node1 = nsibling(__node1);\
168 			if (!__hits || !__key || !(spouse = qkey_to_indi(__key))||spouse==indi){\
169 				continue;\
170 			}\
171 			/* It is a valid HUSB or WIFE, not self, has key, and in database */\
172 			++num;\
173 			{
174 
175 #define ENDSPOUSES \
176 			}\
177 	    }\
178 	}}
179 
180 /* FORFAMS iterate over all FAMS nodes of indi
181  *    this is an optimization of FORFAMSS for cases where spouse is not used
182  *    or computed in other ways.
183  */
184 #define FORFAMS(indi,fam,num) \
185 	{\
186 	RECORD frec=0; \
187 	NODE __node = find_tag(nchild(indi),"FAMS");\
188 	NODE fam=0;\
189 	STRING __key=0;\
190 	num = 0;\
191 	while (__node) {\
192 		if (!eqstr(ntag(__node), "FAMS")) break;\
193 		__key = rmvat(nval(__node));\
194 		__node = nsibling(__node);\
195 		++num;\
196 	    if (!__key || !(frec=qkey_to_frecord(__key)) || !(fam=nztop(frec))) {\
197 			continue;\
198 		}\
199 		{
200 
201 #define ENDFAMS \
202 		}\
203 		release_record(frec); \
204 	}}
205 
206 /* FORFAMSS iterate over all FAMS nodes & all spouses of indi
207  * if there are multiple spouses, user will see same fam with multiple spouses
208  * if there are no spouses for a particular family NULL is returned for spouse
209  */
210 #define FORFAMSS(indi,fam,spouse,num) \
211 	{\
212 	INT first_sp=0; /* have reported spouse in current family? */\
213 	RECORD frec=0; \
214 	NODE __node = find_tag(nchild(indi),"FAMS");\
215 	NODE __node1=0, fam=0;\
216 	STRING __key=0;\
217 	num = 0;\
218 	while (__node) {\
219 		if (!eqstr(ntag(__node), "FAMS")) break;\
220 	    __key = rmvat(nval(__node));\
221 	    __node = nsibling(__node);\
222 	    if (__key && (frec=qkey_to_frecord(__key)) && (fam=nztop(frec))) {\
223 			first_sp=0; /* not yet reported this family */\
224 			__node1 = nchild(fam);\
225 			while (__node1 || !first_sp) {\
226 				NODE spouse=0;\
227 				if (__node1) { \
228 				    if (eqstr("HUSB", ntag(__node1)) || eqstr("WIFE", ntag(__node1))) { \
229 					__key = rmvat(nval(__node1));\
230 					__node1 = nsibling(__node1);\
231 					if (!__key || !(spouse = qkey_to_indi(__key))||spouse==indi) {\
232 						    /* invalid spouse, or self */\
233 						    continue;\
234 					}\
235 				    } else {\
236 					    /* Not a spouse (not HUSB or WIFE) */\
237 					    if (first_sp)\
238 						    break; /* finished HUSB/WIFE section & reported already */\
239 						__node1 = nsibling(__node1);\
240 					    if (__node1) continue;\
241 						/* fall through here for end of family not yet reported */\
242 					}\
243 				/* } else { \
244 				 * !__node1 && !first_sp fall thru to report * fam*/ \
245 				}\
246 				++num; \
247 				++first_sp; /* reporting this family */\
248 				{
249 
250 #define ENDFAMSS \
251 				}\
252 			}\
253 			release_record(frec); \
254 		}\
255 	}}
256 
257 /* FORFAMCS iterate over all parent families of indi
258  * Up to one father and mother are given for each
259  * (This ignores non-traditional parents)
260  */
261 #define FORFAMCS(indi,fam,fath,moth,num) \
262 	{\
263 	RECORD frec=0; \
264 	NODE __node = find_tag(nchild(indi),"FAMC");\
265 	NODE fam, fath, moth;\
266 	STRING __key=0;\
267 	num = 0;\
268 	while (__node) {\
269 		if (!eqstr(ntag(__node), "FAMC")) break;\
270 		__key = rmvat(nval(__node));\
271 		 __node = nsibling(__node);\
272 		 ++num;\
273 	    if (!__key || !(frec=qkey_to_frecord(__key)) || !(fam=nztop(frec))) {\
274 			 continue;\
275 		}\
276 		fath = fam_to_husb_node(fam);\
277 		moth = fam_to_wife_node(fam);\
278 		{
279 
280 #define ENDFAMCS \
281 		}\
282 		release_record(frec); \
283 	}}
284 
285 /* FORHUSBS iterate over all husbands in one family
286  * (This handles more than one husband in a family)
287  */
288 #define FORHUSBS(fam,husb,num) \
289 	{\
290 	NODE __node = find_tag(nchild(fam), "HUSB");\
291 	NODE husb=0;\
292 	STRING __key=0;\
293 	num = 0;\
294 	while (__node) {\
295 		__key = rmvat(nval(__node));\
296 		if (!__key || !(husb = key_to_indi(__key))) {\
297 			++num;\
298 			__node = nsibling(__node);\
299 			continue;\
300 		}\
301 		++num;\
302 		{
303 
304 #define ENDHUSBS \
305 		}\
306 		__node = nsibling(__node);\
307 		if (__node && nestr(ntag(__node), "HUSB")) __node = NULL;\
308 	}}
309 
310 /* FORWIFES iterate over all wives in one family
311  * (This handles more than one wife in a family)
312  */
313 #define FORWIFES(fam,wife,num) \
314 	{\
315 	NODE __node = find_tag(nchild(fam), "WIFE");\
316 	NODE wife=0;\
317 	STRING __key=0;\
318 	num = 0;\
319 	while (__node) {\
320 		__key = rmvat(nval(__node));\
321 		if (!__key || !(wife = qkey_to_indi(__key))) {\
322 			++num;\
323 			__node = nsibling(__node);\
324 			if (__node && nestr(ntag(__node), "WIFE")) __node = NULL;\
325 			continue;\
326 		}\
327 		ASSERT(wife);\
328 		num++;\
329 		{
330 
331 #define ENDWIFES \
332 		}\
333 		__node = nsibling(__node);\
334 		if (__node && nestr(ntag(__node), "WIFE")) __node = NULL;\
335 	}}
336 
337 /* FORFAMSPOUSES iterate over all spouses in one family
338  * (All husbands and wives)
339  */
340 #define FORFAMSPOUSES(fam,spouse,num) \
341 	{\
342 	NODE __node = nchild(fam);\
343 	NODE spouse=0;\
344 	STRING __key=0;\
345 	num = 0;\
346 	while (__node) {\
347 		if (!eqstr(ntag(__node), "HUSB") && !eqstr(ntag(__node), "WIFE")) {\
348 			__node = nsibling(__node);\
349 			continue;\
350 		}\
351 		__key = rmvat(nval(__node));\
352 		if (!__key || !(spouse = qkey_to_indi(__key))) {\
353 			++num;\
354 			__node = nsibling(__node);\
355 			continue;\
356 		}\
357 		++num;\
358 		{
359 
360 #define ENDFAMSPOUSES \
361 		}\
362 		__node = nsibling(__node);\
363 	}}
364 
365 #define FORTAGVALUES(root,tag,node,value)\
366 	{\
367 	NODE node, __node = nchild(root);\
368 	STRING value, __value;\
369 	while (__node) {\
370 		while (__node && nestr(tag, ntag(__node)))\
371 			__node = nsibling(__node);\
372 		if (__node == NULL) break;\
373 		__value = value = full_value(__node, "\n");/*OBLIGATION*/\
374 		node = __node;\
375 		{
376 #define ENDTAGVALUES \
377 		}\
378 		if (__value) stdfree(__value);/*RELEASE*/\
379 		 __node = nsibling(__node);\
380 	}}
381 
382 
383 #endif /* GEDCOM_MACROS_H_INCLUDED */
384