/*===============================================+ * llrpt_difference -- Create difference of two INDISEQs * usage: difference(SET, SET) -> SET *==============================================*/ PVALUE llrpt_difference (PNODE node, SYMTAB stab, BOOLEAN *eflg) { PNODE arg1 = builtin_args(node); PNODE arg2 = inext(arg1); INDISEQ op2=0, op1=0; PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); PVALUE val2=0; if (*eflg) { prog_var_error(node, stab, arg1, val1, nonsetx, "difference", "1"); return NULL; } /* NULL indiseqs are possible, because of getindiset */ op1 = pvalue_to_seq(val1); val2 = eval_and_coerce(PSET, arg2, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg2, val2, nonsetx, "difference", "2"); return NULL; } op2 = pvalue_to_seq(val2); /* do actual difference */ op2 = difference_indiseq(op1, op2); set_pvalue_seq(val1, op2); /* delay to last minute lest it is a temp owning seq, eg, difference(ancestorset(i),ancestorset(j)) */ delete_pvalue(val2); return val1; }
/*======================================+ * llrpt_newfile -- Switch output to new file * usage: newfile(STRING, BOOL) -> VOID *=====================================*/ PVALUE llrpt_newfile (PNODE node, SYMTAB stab, BOOLEAN *eflg) { PNODE argvar = builtin_args(node); BOOLEAN aflag=FALSE; STRING name=0; PVALUE val = eval_and_coerce(PSTRING, argvar, stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonstrx, "newfile", "1"); delete_pvalue_ptr(&val); return NULL; } name = pvalue_to_string(val); if (!name || !name[0]) { *eflg = TRUE; prog_var_error(node, stab, argvar, val, "1st arg to newfile must be a nonempty string."); delete_pvalue_ptr(&val); return NULL; } strupdate(&outfilename, name); delete_pvalue_ptr(&val); val = eval_and_coerce(PBOOL, argvar=inext(argvar), stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonboox, "newfile", "2"); delete_pvalue_ptr(&val); return NULL; } aflag = pvalue_to_bool(val); delete_pvalue_ptr(&val); if (!set_output_file(outfilename, aflag)) { *eflg = TRUE; prog_var_error(node, stab, argvar, NULL, "Failed to open output file: %s", outfilename); } return NULL; }
/*===================================== * llrpt_createnode -- Create GEDCOM node * usage: createnode(STRING, STRING) -> NODE * args: (tag, value) *===================================*/ PVALUE llrpt_createnode (PNODE node, SYMTAB stab, BOOLEAN *eflg) { PNODE arg = iargs(node); NODE newnode=0; NODE prnt=NULL; /* parent node for new node */ STRING xref=NULL; /* xref for new node */ PVALUE val1=NULL, val2=NULL; STRING str1=NULL; /* 1st arg, which is tag for new node */ STRING str2=NULL; /* 2nd arg, which is value for new node */ val1 = eval_and_coerce(PSTRING, arg, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg, val1, nonstrx, "createnode", "1"); delete_pvalue(val1); return NULL; } /* 1st arg is tag for new node */ str1 = pvalue_to_string(val1); val2 = eval_and_coerce(PSTRING, arg=inext(arg), stab, eflg); if (*eflg) { prog_var_error(node, stab, arg, val2, nonstrx, "createnode", "2"); delete_pvalue(val2); return NULL; } /* 2nd arg is value for new node */ str2 = pvalue_to_string(val2); newnode = create_temp_node(xref, str1, str2, prnt); return create_pvalue_from_node(newnode); }
/*========================================+ * llrpt_row -- Position output to start of row * usage: row(INT) -> VOID *=======================================*/ PVALUE llrpt_row (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INT row=0; PNODE argvar = builtin_args(node); PVALUE val = eval_and_coerce(PINT, argvar, stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonint1, "row"); delete_pvalue_ptr(&val); return NULL; } *eflg = TRUE; row = pvalue_to_int(val); delete_pvalue_ptr(&val); if (outputmode != PAGEMODE) { *eflg = TRUE; prog_var_error(node, stab, argvar, val, "row only valid in page mode"); return NULL; } if (row < 1 || row > __rows) { *eflg = TRUE; prog_var_error(node, stab, argvar, val, badarg1, "row"); return NULL; } *eflg = FALSE; currow = row; curcol = 1; return NULL; }
/*============================================ * 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; }
/*===========================================+ * llrpt_deletefromset -- Remove person from INDISEQ * usage: deletefromset(SET, INDI, BOOL) -> VOID *==========================================*/ PVALUE llrpt_deletefromset (PNODE node, SYMTAB stab, BOOLEAN *eflg) { NODE indi; STRING key=0; BOOLEAN all, rc; INDISEQ seq; PNODE arg1 = builtin_args(node), arg2 = inext(arg1), arg3 = inext(arg2); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); PVALUE val3=0; if (*eflg) { prog_var_error(node, stab, arg1, val1, nonsetx, "deletefromset", "1"); goto dfs_exit; } ASSERT(seq = pvalue_to_seq(val1)); indi = eval_indi(arg2, stab, eflg, NULL); if (*eflg) { prog_var_error(node, stab, arg2, NULL, nonindx, "deletefromset", "2"); goto dfs_exit; } if (!indi) goto dfs_exit; *eflg = TRUE; if (!(key = strsave(rmvat(nxref(indi))))) { prog_error(node, "major error in deletefromset."); goto dfs_exit; } *eflg = FALSE; val3 = eval_and_coerce(PBOOL, arg3, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg2, NULL, nonboox, "deletefromset", "3"); goto dfs_exit; } all = pvalue_to_bool(val3); delete_pvalue(val3); do { rc = delete_indiseq(seq, key, NULL, 0); } while (rc && all); dfs_exit: /* delay delete of val1 to last minute lest it is a temp owning seq, eg, deletefromset(ancestorset(i),j) */ if (val1) delete_pvalue(val1); if (key) strfree(&key); return NULL; }
/*========================================+ * llrpt_pagemode -- Switch output to page mode * usage: pagemode(INT, INT) -> VOID *======================================*/ PVALUE llrpt_pagemode (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INT cols=0, rows=0; PNODE argvar = builtin_args(node); PVALUE val = eval_and_coerce(PINT, argvar, stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonintx, "pagemode", "1"); delete_pvalue_ptr(&val); return NULL; } rows = pvalue_to_int(val); delete_pvalue_ptr(&val); val = eval_and_coerce(PINT, argvar=inext(argvar), stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonintx, "pagemode", "2"); delete_pvalue_ptr(&val); return NULL; } cols = pvalue_to_int(val); delete_pvalue_ptr(&val); *eflg = TRUE; if (!(cols >= 1 && cols <= MAXCOLS)) { *eflg = TRUE; prog_var_error(node, stab, argvar, val, badargx, "pagemode", "1"); return NULL; } if (!(rows >= 1 && rows <= MAXROWS)) { *eflg = TRUE; prog_var_error(node, stab, argvar, val, badargx, "pagemode", "2"); return NULL; } *eflg = FALSE; outputmode = PAGEMODE; __rows = rows; __cols = cols; if (pagebuffer) stdfree(pagebuffer); pagebuffer = (STRING) stdalloc(__rows*__cols); memset(pagebuffer, ' ', __rows*__cols); return NULL; }
/*===============================================+ * llrpt_pos -- Position page output to row and column * usage: pos(INT, INT) -> VOID *==============================================*/ PVALUE llrpt_pos (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INT col=0, row=0; PNODE argvar = builtin_args(node); PVALUE val = eval_and_coerce(PINT, argvar, stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonintx, "pos", "1"); delete_pvalue_ptr(&val); return NULL; } row = pvalue_to_int(val); if (row < 1 || row > __rows) { *eflg = TRUE; prog_var_error(node, stab, argvar, val, badargx, "pos", "1"); return NULL; } delete_pvalue_ptr(&val); val = eval_and_coerce(PINT, argvar=inext(argvar), stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonintx, "pos", "2"); delete_pvalue_ptr(&val); return NULL; } col = pvalue_to_int(val); if (col < 1 || col > __cols) { *eflg = TRUE; prog_var_error(node, stab, argvar, val, badargx, "pos", "2"); return NULL; } delete_pvalue_ptr(&val); if (outputmode != PAGEMODE) { *eflg = TRUE; prog_var_error(node, stab, NULL, val, "pos only valid in page mode"); return NULL; } currow = row; curcol = col; return NULL; }
/*====================================================+ * llrpt_descendentset -- Create descendent set of an INDISEQ * usage: descendantset(SET) -> SET *===================================================*/ PVALUE llrpt_descendentset (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INDISEQ seq=0; PNODE arg1 = builtin_args(node); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg1, val1, nonset1, "descendentset"); return NULL; } ASSERT(seq = pvalue_to_seq(val1)); seq = descendent_indiseq(seq); set_pvalue_seq(val1, seq); return val1; }
/*==========================================+ * llrpt_childset -- Create child set of an INDISEQ * usage: childset(SET) -> SET *=========================================*/ PVALUE llrpt_childset (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INDISEQ seq=0; PNODE arg1 = builtin_args(node); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg1, val1, nonset1, "childset"); return NULL; } ASSERT(seq = pvalue_to_seq(val1)); /* do actual construction of child set */ seq = child_indiseq(seq); set_pvalue_seq(val1, seq); return val1; }
/*=========================================+ * llrpt_uniqueset -- Eliminate dupes from INDISEQ * usage: uniqueset(SET) -> VOID *========================================*/ PVALUE llrpt_uniqueset (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INDISEQ seq=0; PNODE arg1 = builtin_args(node); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg1, val1, nonset1, "uniqueset"); return NULL; } ASSERT(seq = pvalue_to_seq(val1)); unique_indiseq(seq); /* delay to last minute lest it is a temp owning seq, eg, uniqueset(ancestorset(i) */ delete_pvalue(val1); return NULL; }
/*===================================================+ * llrpt_gengedcomstrong -- Generate GEDCOM output from an INDISEQ * usage: gengedcom(SET) -> VOID * Perry 2000/11/03 *==================================================*/ PVALUE llrpt_gengedcomstrong (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INDISEQ seq=0; PNODE arg1 = builtin_args(node); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg1, val1, nonset1, "gengedcomstrong"); return NULL; } ASSERT(seq = pvalue_to_seq(val1)); gen_gedcom(seq, GENGEDCOM_STRONG_DUMP, eflg); /* delay to last minute lest it is a temp owning seq, eg, gengedcom(ancestorset(i)) */ delete_pvalue(val1); return NULL; }
/*=========================================+ * llrpt_parentset -- Create parent set of INDISEQ * usage: parentset(SET) -> SET *========================================*/ PVALUE llrpt_parentset (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INDISEQ seq=0; PNODE arg1 = builtin_args(node); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg1, val1, nonset1, "parentset"); return NULL; } /* NULL indiseqs are possible, because of getindiset */ seq = pvalue_to_seq(val1); /* do actual construction of parent set */ seq = parent_indiseq(seq); set_pvalue_seq(val1, seq); return val1; }
/*=================================== * llrpt_valuesort -- Sort INDISEQ by value * usage: valuesort(SET) -> VOID *=================================*/ PVALUE llrpt_valuesort (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INDISEQ seq; PNODE arg1 = builtin_args(node); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); if (*eflg) { prog_var_error(node, stab, arg1, val1, nonset1, "valuesort"); return NULL; } ASSERT(seq = pvalue_to_seq(val1)); valuesort_indiseq(seq,eflg); if (*eflg) { prog_error(node, _("missing or incorrect value for sort")); return NULL; } /* delay to last minute lest it is a temp owning seq, eg, valuesort(ancestorset(i) */ delete_pvalue(val1); return NULL; }
/*==================================+ * llrpt_addtoset -- Add person to INDISEQ * usage: addtoset(SET, INDI, ANY) -> VOID *=================================*/ PVALUE llrpt_addtoset (PNODE node, SYMTAB stab, BOOLEAN *eflg) { NODE indi=0; STRING key=0; INDISEQ seq=0; PNODE arg1 = builtin_args(node), arg2 = inext(arg1), arg3 = inext(arg2); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); PVALUE val2=0; if (*eflg) { prog_var_error(node, stab, arg1, val1, nonsetx, "addtoset", "1"); return NULL; } ASSERT(seq = pvalue_to_seq(val1)); indi = eval_indi(arg2, stab, eflg, NULL); if (*eflg) { prog_var_error(node, stab, arg2, NULL, nonindx, "addtoset","2"); goto ats_exit; } if (!indi) goto ats_exit; *eflg = TRUE; if (!(key = strsave(rmvat(nxref(indi))))) { prog_error(node, "major error in addtoset."); goto ats_exit; } *eflg = FALSE; val2 = evaluate(arg3, stab, eflg); if (*eflg) { prog_error(node, "3rd arg to addtoset is in error."); goto ats_exit; } append_indiseq_pval(seq, key, NULL, val2, FALSE); ats_exit: if (key) strfree(&key); /* append made its own copy */ /* delay to last minute val1 cleanup lest it is a temp owning seq, eg, addtoset(ancestorset(i),j) */ if (val1) delete_pvalue(val1); return NULL; }
/*==================================+ * llrpt_col -- Position output to column * usage: col(INT) -> VOID *=================================*/ PVALUE llrpt_col (PNODE node, SYMTAB stab, BOOLEAN *eflg) { INT newcol=0; PNODE argvar = builtin_args(node); PVALUE val = eval_and_coerce(PINT, argvar, stab, eflg); if (*eflg) { prog_var_error(node, stab, argvar, val, nonint1, "col"); delete_pvalue_ptr(&val); return NULL; } newcol = pvalue_to_int(val); delete_pvalue_ptr(&val); if (newcol < 1) newcol = 1; if (newcol > MAXCOLS) newcol = MAXCOLS; if (newcol == curcol) return NULL; if (newcol < curcol) poutput("\n", eflg); while (curcol < newcol && !(*eflg)) poutput(" ", eflg); return NULL; }
/*====================================+ * llrpt_inset -- See if person is in INDISEQ * usage: inset(SET, INDI) -> BOOL *==========================================*/ PVALUE llrpt_inset (PNODE node, SYMTAB stab, BOOLEAN *eflg) { NODE indi; STRING key=0; INDISEQ seq; BOOLEAN rel; PNODE arg1 = builtin_args(node), arg2 = inext(arg1); PVALUE val1 = eval_and_coerce(PSET, arg1, stab, eflg); PVALUE valr=0; if (*eflg ||!val1 || !(seq = pvalue_to_seq(val1))) { *eflg = TRUE; prog_var_error(node, stab, arg1, val1, nonsetx, "inset", "1"); goto inset_exit; } indi = eval_indi(arg2, stab, eflg, NULL); if (*eflg) { prog_var_error(node, stab, arg2, NULL, nonindx, "inset", "2"); goto inset_exit; } if (!indi) { rel = FALSE; } else { if (!(key = strsave(rmvat(nxref(indi))))) { *eflg = TRUE; prog_error(node, "major error in inset."); goto inset_exit; } rel = in_indiseq(seq, key); } valr = create_pvalue_from_bool(rel); inset_exit: /* delay delete of val1 to last minute lest it is a temp owning seq, eg, inset(ancestorset(i),j) */ if (val1) delete_pvalue(val1); if (key) strfree(&key); return valr; }
/*======================================= * 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; }