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