/*============================================ * llrpt_detachnode -- Remove node from GEDCOM tree * usage: detachnode(NODE) -> VOID * (This is the historic deletenode) *==========================================*/ PVALUE llrpt_detachnode (PNODE node, SYMTAB stab, BOOLEAN *eflg) { PNODE arg = iargs(node); NODE dead, prnt; PVALUE val = eval_and_coerce(PGNODE, arg, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg, val, nonnod1, "detachnode"); delete_pvalue(val); return NULL; } dead = pvalue_to_node(val); if ((prnt = nparent(dead))) { NODE prev = NULL, next; NODE curs = nchild(prnt); while (curs && curs != dead) { prev = curs; curs = nsibling(curs); } ASSERT(curs); /* else broken tree: dead was not child of its parent */ next = nsibling(dead); if (prev == NULL) nchild(prnt) = next; else nsibling(prev) = next; } /* unparent node, but ensure its locking is only releative to new parent */ dolock_node_in_cache(dead, FALSE); nparent(dead) = NULL; dolock_node_in_cache(dead, TRUE); nsibling(dead) = NULL; /* we don't actually delete the node, garbage collection must get it */ return NULL; }
/*======================================== * string_to_node -- Read tree from string * (modifies string -- adds 0s between lines) *======================================*/ NODE string_to_node (STRING str) { INT lev; INT lev0; STRING xref; STRING tag; STRING val; INT curlev; NODE root=NULL, node, curnode; STRING msg; flineno = 0; if (!string_to_line(&str, &lev, &xref, &tag, &val, &msg)) goto string_to_node_fail; lev0 = curlev = lev; root = curnode = create_node(xref, tag, val, NULL); while (string_to_line(&str, &lev, &xref, &tag, &val, &msg)) { if (lev == curlev) { node = create_node(xref, tag, val, nparent(curnode)); nsibling(curnode) = node; curnode = node; } else if (lev == curlev + 1) { node = create_node(xref, tag, val, curnode); nchild(curnode) = node; curnode = node; curlev = lev; } else if (lev < curlev) { if (lev < lev0) { llwprintf("Error: line %d: illegal level", flineno); goto string_to_node_fail; } while (lev < curlev) { curnode = nparent(curnode); curlev--; } node = create_node(xref, tag, val, nparent(curnode)); nsibling(curnode) = node; curnode = node; } else { llwprintf("Error: line %d: illegal level", flineno); goto string_to_node_fail; } } if (!msg) { nodechk(root, "string_to_node"); return root; } string_to_node_fail: free_nodes(root); return NULL; }
/*================================================= * nodechk -- Check node tree to which this node belongs *===============================================*/ void nodechk (NODE node, CNSTRING scope) { NODE root = node; CNSTRING key = 0; if (!nodechecking) return; while (nparent(root)) { root = nparent(root); } key = nxref(node); check_node_recursively(root, NULL, 1, key, scope); }
/*============================================== * check_node -- Check node (that structure is valid) *============================================*/ static void check_node (NODE node, NODE parent, INT level, CNSTRING key, CNSTRING scope) { if (nparent(node) != parent) { failreport("bad parent link", level, key, scope); } if (parent) { if (node->n_cel != parent->n_cel) { failreport("bad cel", level, key, scope); } } }
/*================================================================= * expand_tree -- Create copy of node tree with additional link info *===============================================================*/ static NODE expand_tree (NODE root0) { NODE copy, node, sub; STRING key; static NODE root; /* root of record being edited */ LIST subs; /* list of contained records */ NODE expd; /* expanded main record - copy - our retval */ root = root0; expd = copy_nodes(root, TRUE, TRUE); subs = create_list(); traverse_nodes(expd, advedit_expand_traverse, subs); /* expand the list of records into the copied record */ FORLIST(subs, el) node = (NODE) el; #ifdef DEBUG llwprintf("in list: %s %s\n", ntag(node), nval(node)); #endif key = rmvat(nval(node)); if ((sub = nztop(key_possible_to_record(key, *key)))) { copy = copy_node_subtree(sub); nxref(node) = nxref(copy); ntag(node) = ntag(copy); nchild(node) = nchild(copy); nparent(node) = nparent(copy); /*MEMORY LEAK; MEMORY LEAK; MEMORY LEAK: node not removed (because its value and possibly xref [probably not] are still being referred to */ } ENDLIST /* Shouldn't we free subs now ? Perry 2001/06/22 */ #ifdef DEBUG show_node(expd); #endif return expd; }
/*============================================================== * next_fp_to_node -- Convert next GEDCOM record in file to tree * * fp: [IN] file that holds GEDCOM record/s * list: [IN] can be list at level 0? * ttm: [IN] character translation table * pmsg: [OUT] possible error message * peof: [OUT] set true if file is at end of file * callers should probably be converted to calling next_fp_to_record *============================================================*/ NODE next_fp_to_node (FILE *fp, BOOLEAN list, XLAT ttm, STRING *pmsg, BOOLEAN *peof) { INT curlev, bcode, rc; NODE root, node, curnode; static char scratch[100]; /*we return errors with this, keep it around*/ *pmsg = NULL; *peof = FALSE; if (ateof) { ateof = *peof = TRUE; lahead = FALSE; return NULL; } if (!lahead) { rc = file_to_line(fp, ttm, &lev, &xref, &tag, &val, pmsg); if (rc == DONE) { ateof = *peof = TRUE; return NULL; } else if (rc == ERROR) return NULL; lahead = TRUE; } curlev = lev; if (curlev != lev0) { *pmsg = _(qSrerwlv); return NULL; } root = curnode = create_node(xref, tag, val, NULL); bcode = OKAY; rc = file_to_line(fp, ttm, &lev, &xref, &tag, &val, pmsg); while (rc == OKAY) { if (lev == curlev) { if (lev == lev0 && !list) { bcode = DONE; break; } node = create_node(xref, tag, val, nparent(curnode)); nsibling(curnode) = node; curnode = node; } else if (lev == curlev + 1) { node = create_node(xref, tag, val, curnode); nchild(curnode) = node; curnode = node; curlev = lev; } else if (lev < curlev) { if (lev < lev0) { sprintf(scratch, _(qSrerilv), flineno); *pmsg = scratch; bcode = ERROR; break; } if (lev == lev0 && !list) { bcode = DONE; break; } while (lev < curlev) { curnode = nparent(curnode); curlev--; } node = create_node(xref, tag, val, nparent(curnode)); nsibling(curnode) = node; curnode = node; } else { sprintf(scratch, _(qSrerilv), flineno); *pmsg = scratch; bcode = ERROR; break; } rc = file_to_line(fp, ttm, &lev, &xref, &tag, &val, pmsg); } if (bcode == DONE) return root; if (bcode == ERROR || rc == ERROR) { free_nodes(root); return NULL; } lahead = FALSE; ateof = *peof = TRUE; return root; }
/*======================================= * llrpt_addnode -- Add a node to a GEDCOM tree * usage: addnode(NODE, NODE, NODE) -> VOID * args: (node being added, parent, previous child) *=====================================*/ PVALUE llrpt_addnode (PNODE node, SYMTAB stab, BOOLEAN *eflg) { PNODE arg = iargs(node); NODE newchild, next, prnt, prev; /* first argument, node (must be nonnull) */ PVALUE val = eval_and_coerce(PGNODE, arg, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg, val, nonnodx, "addnode", "1"); delete_pvalue(val); return NULL; } newchild = remove_node_and_delete_pvalue(&val); if (!newchild) { prog_var_error(node, stab, arg, val, nonnodx, "addnode", "1"); return NULL; } /* second argument, parent (must be nonnull) */ val = eval_and_coerce(PGNODE, arg=inext(arg), stab, eflg); if (*eflg) { prog_var_error(node, stab, arg, val, nonnodx, "addnode", "2"); return NULL; } prnt = remove_node_and_delete_pvalue(&val); if (!prnt) { prog_var_error(node, stab, arg, val, nonnodx, "addnode", "2"); return NULL; } /* third argument, prior sibling (may be null) */ val = eval_and_coerce(PGNODE, arg=inext(arg), stab, eflg); if (*eflg) { prog_var_error(node, stab, arg, val, nonnodx, "addnode", "3"); delete_pvalue(val); return NULL; } prev = remove_node_and_delete_pvalue(&val); if (prev) { /* Check that previous sibling actually is child of new parent */ if (prnt != nparent(prev)) { prog_error(node, "2nd arg to addnode must be parent of 3rd arg"); *eflg = 1; return NULL; } } /* reparent node, but ensure its locking is only relative to new parent */ dolock_node_in_cache(newchild, FALSE); nparent(newchild) = prnt; newchild->n_cel = prnt->n_cel; set_temp_node(newchild, is_temp_node(prnt)); dolock_node_in_cache(newchild, TRUE); if (prev == NULL) { next = nchild(prnt); nchild(prnt) = newchild; } else { next = nsibling(prev); nsibling(prev) = newchild; } nsibling(newchild) = next; return NULL; }