Пример #1
0
/*=================================
 * node_lineprint -- print a node line
 *  in a node tree
 * This is used in gedcom view & extended
 *  gedcom views
 * returns static buffer
 * Created: 2001/01/27, Perry Rapp
 *===============================*/
static STRING
node_lineprint (INT width, void * param)
{
	static char line[120];
	STRING ptr=line;
	INT mylen=sizeof(line);
	NODE_PRINT_PARAM npp = (NODE_PRINT_PARAM)param;
	NODE node=npp->node;

	if (mylen>width)
		mylen=width;
	if (nxref(node)) {
		llstrcatn(&ptr, nxref(node), &mylen);
		llstrcatn(&ptr, " ", &mylen);
	}
	if (ntag(node)) {
		llstrcatn(&ptr, ntag(node), &mylen);
		llstrcatn(&ptr, " ", &mylen);
	}
	if (nval(node)) {
		llstrcatn(&ptr, nval(node), &mylen);
		llstrcatn(&ptr, " ", &mylen);
	}
	if (npp->gdvw == GDVW_EXPANDED && nval(node)) {
		STRING key = rmvat(nval(node)), str;
		if (key) {
			str = generic_to_list_string(NULL, key, mylen, ",", &disp_long_rfmt, TRUE);
			llstrcatn(&ptr, " : ", &mylen);
			llstrcatn(&ptr, str, &mylen);
		}
	}
	return line;
}
Пример #2
0
/*====================================================
 * disp_pvalue -- Display details of specified pvalue
 *  Drilldown in variable debugger
 *  This is primarily to display contents of container values
 *  val:   [IN]  value to display
 *==================================================*/
static void
disp_pvalue (PVALUE val)
{
	switch (which_pvalue_type(val)) {
		case PGNODE:
			{
				NODE node = pvalue_to_node(val);
				char buffer[256] = "";
				size_t len = sizeof(buffer);
				STRING str = buffer;
				if (ntag(node)) {
					llstrappf(str, len, uu8, "%s: ", ntag(node));
				}
				if (nval(node)) {
					llstrapps(str, len, uu8, nval(node));
				}
				msg_info(str);
			}
			return;
		case PINDI:
		case PFAM:
		case PSOUR:
		case PEVEN:
		case POTHR:
			{
				RECORD rec = pvalue_to_record(val);
				NODE node = nztop(rec);
				size_t len = 128;
				STRING txt = generic_to_list_string(node, NULL, len, " ", NULL, TRUE);
				msg_info(txt);
			}
			return;
		case PLIST:
			{
				LIST list = pvalue_to_list(val);
				disp_list(list);
			}
			return;
		case PTABLE:
			{
				TABLE tab = pvalue_to_table(val);
				disp_table(tab);
			}
			return;
		case PSET:
			{
				INDISEQ seq = pvalue_to_seq(val);
				disp_seq(seq);
			}
			return;
	}
}
Пример #3
0
/*=======================================================
 * resolve_node -- Traverse routine for resolve_refn_links (q.v.)
 *  node:    Current node in traversal
 *  returns FALSE if bad refn pointer
 *=====================================================*/
static BOOLEAN
resolve_node (NODE node, BOOLEAN annotate_pointers)
{
	STRING val = nval(node);
	STRING refn=0;

	if (!val) return TRUE;
	refn = symbolic_link(val);
	if (refn) {
		INT letr = record_letter(ntag(node));
		NODE refr = refn_to_record(refn, letr);
		if (refr) {
			stdfree(nval(node));
			nval(node) = strsave(nxref(refr));
		} else {
			return FALSE;
		}
	}
	if (annotate_pointers) {
		INT i=0,len=0;
		if (is_annotated_xref(nval(node), &len)) {
			char newval[20];
			ASSERT(len < (INT)sizeof(newval));
			for (i=0; i<len; ++i) {
				newval[i] = nval(node)[i];
			}
			newval[i] = 0;
			stdfree(nval(node));
			nval(node) = strsave(newval);
		}
	}

	return TRUE;
}
Пример #4
0
/*=====================================
 * check_node -- check node for bad pointers
 *  and bad levels, and continue traverse
 * 2001/02/18, Perry Rapp
 *===================================*/
static void
check_node (CNSTRING n0key, NODE node, INT level)
{
    BOOLEAN lineage=FALSE;
    /* ignore lineage links - they are checked elsewhere */
    if (level==1) {
        INT i;
        for (i=0; i<ARRSIZE(lineage_tags); i++) {
            if (eqstr(ntag(node), lineage_tags[i])) {
                lineage=TRUE;
                break;
            }
        }
    }
    /*
    TO DO: How do we tell non-pointers that *ought* to
    be pointers, eg "1 SOUR <FamilyHistory>" ?
    */
    if (!lineage) {
        STRING skey = rmvat(nval(node));
        if (skey) {
            NODE xnode = qkey_to_type(skey);
            if (!xnode) {
                report_error(ERR_BADPOINTER
                             , _("Bad pointer (in %s): %s")
                             , n0key, nval(node));
            }
        }
    }
    if (nchild(node))
        check_node(n0key, nchild(node), level+1);
    if (nsibling(node))
        check_node(n0key, nsibling(node), level);
}
Пример #5
0
/*======================================
 * valid_othr_tree -- Validate OTHR tree
 *  node:  [IN]  source to validate
 *  pmsg,  [OUT] error message, if any
 *  orig:  [IN]  OTHR node to match
 *====================================*/
BOOLEAN
valid_othr_tree (NODE node, STRING *pmsg, NODE orig)
{
	orig = NULL;         /* keep compiler happy */
	*pmsg = NULL;
	if (!node) {
		*pmsg = _(qSbademp);
  		return FALSE;
	}
	if (eqstr("INDI", ntag(node)) || eqstr("FAM", ntag(node))
		|| eqstr("SOUR", ntag(node)) || eqstr("EVEN", ntag(node))) {
		*pmsg = _(qSbadothr0);
		return FALSE;
	}
	return TRUE;
}
Пример #6
0
/*====================================
 * swrite_node -- Write NODE to string
 *==================================*/
static STRING
swrite_node (INT levl,       /* level */
             NODE node,      /* node */
             STRING p)       /* write string */
{
	char scratch[600];
	STRING q = scratch;
	sprintf(q, "%ld ", levl);
	q += strlen(q);
	if (nxref(node)) {
		strcpy(q, nxref(node));
		q += strlen(q);
		*q++ = ' ';
	}
	strcpy(q, ntag(node));
	q += strlen(q);
	if (nval(node)) {
		*q++ = ' ';
		strcpy(q, nval(node));
		q += strlen(q);
	}
	*q++ = '\n';
	*q = 0;
	strcpy(p, scratch);
	return p + strlen(p);
}
Пример #7
0
/*===============================================
 * index_by_refn - Index node tree by REFN values
 * Adds all REFN values in node tree to refn index
 * Assumes all are new (only for use with brand new records)
 *=============================================*/
void
index_by_refn (NODE node,
               STRING key)
{
	if (!node || !key) return;
	for (node = nchild(node); node; node = nsibling(node)) {
		if (eqstr("REFN", ntag(node)) && nval(node))
			add_refn(nval(node), key);
	}
}
Пример #8
0
/*===================================
 * find_xref -- Search node for a cross-reference key
 * 2001/01/21, Perry Rapp
 *=================================*/
static BOOLEAN
find_xref (CNSTRING key, NODE node, CNSTRING tag1, CNSTRING tag2)
{
    NODE node2;
    CACHEEL ncel2;
    BOOLEAN found=FALSE;
    ncel2 = node_to_cacheel_old(node);
    lock_cache(ncel2);
    for (node2 = nchild(node); node2; node2 = nsibling(node2)) {
        if (eqstr(tag1, ntag(node2))
                || (tag2 && eqstr(tag2, ntag(node2)))) {
            STRING key2 = rmvat(nval(node2));
            if (key2 && eqstr(key, key2)) {
                found = TRUE;
                goto exit_find;
            }
        }
    }
exit_find:
    unlock_cache(ncel2);
    return found;
}
Пример #9
0
/*===============================
 * valid_fam_tree -- Validate FAM tree
 *  fam1,  [IN]  family to validate
 *  pmsg:  [OUT] error message, if any
 *  fam0:  [IN]  family to match - may be NULL
 * Should be replaced by valid_fam(RECORD,...) ?
 *=============================*/
BOOLEAN
valid_fam_tree (NODE fam1, STRING *pmsg, NODE fam0)
{
	NODE refn0, husb0, wife0, chil0, body0;
	NODE refn1, husb1, wife1, chil1, body1;

	if (!fam1) {
		*pmsg = _(qSbademp);
  		return FALSE;
	}
	if (nestr("FAM", ntag(fam1))) {
		*pmsg = _(qSbadfm0);
		return FALSE;
	}
	if (nsibling(fam1)) {
		*pmsg = _(qSbadmul);
		return FALSE;
	}

	refn0 = husb0 = wife0 = chil0 = body0 = NULL;
	if (fam0)
		split_fam(fam0, &refn0, &husb0, &wife0, &chil0, &body0);
	split_fam(fam1, &refn1, &husb1, &wife1, &chil1, &body1);
	
	if (fam0 && !iso_nodes(fam1, fam0, FALSE, TRUE)) {
		*pmsg = _(qSbadfam); 
		goto bad3;
	}
	if (!iso_nodes(husb1, husb0, FALSE, TRUE)) {
		*pmsg = _(qSbadhsb);
		goto bad3;
	}
	if (!iso_nodes(wife1, wife0, FALSE, TRUE)) {
		*pmsg = _(qSbadwif);
		goto bad3;
	}
	if (!iso_nodes(chil1, chil0, FALSE, TRUE)) {
		*pmsg = _(qSbadchl);
		goto bad3;
	}
	if (fam0)
		join_fam(fam0, refn0, husb0, wife0, chil0, body0);
	join_fam(fam1, refn1, husb1, wife1, chil1, body1);
	return TRUE;
bad3:
	if (fam0)
		join_fam(fam0, refn0, husb0, wife0, chil0, body0);
	join_fam(fam1, refn1, husb1, wife1, chil1, body1);
	return FALSE;
}
Пример #10
0
/*=================================================================
 * 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;
}
Пример #11
0
/*======================================
 * valid_even_tree -- Validate EVEN tree
 *  node:  [IN]  source to validate
 *  pmsg,  [OUT] error message, if any
 *  orig:  [IN]  EVEN node to match
 *====================================*/
BOOLEAN
valid_even_tree (NODE node, STRING *pmsg, NODE orig)
{
	orig = NULL;         /* keep compiler happy */
	*pmsg = NULL;
	if (!node) {
		*pmsg = _(qSbademp);
  		return FALSE;
	}
	if (nestr("EVEN", ntag(node))) {
		*pmsg = _(qSbadev0);
		return FALSE;
	}
	return TRUE;
}
Пример #12
0
/*=================================================================
 * advanced_person_edit --
 *===============================================================*/
void
advanced_person_edit (NODE root0)
{
	FILE *fp;
	NODE expd;

#ifdef DEBUG
	llwprintf("advanced_person_edit: %s %s %s\n", nxref(root0), 
		  ntag(root0),nval(root0));
#endif
	expd = expand_tree(root0);
	ASSERT(fp = fopen(editfile, LLWRITETEXT));
	write_nodes(0, fp, NULL, expd, TRUE, TRUE, TRUE);
	fclose(fp);
	do_edit();
}
Пример #13
0
/*========================================
 * write_node -- Write NODE to GEDCOM file
 *
 * INT levl:       [in] level
 * FILE *fp:       [in] file
 * TRANTABLE tt    [in] char map
 * NODE node:      [in] node
 * BOOLEAN indent: [in]indent?
 *======================================*/
static void
write_node (INT levl, FILE *fp, XLAT ttm, NODE node,
	BOOLEAN indent)
{
	char out[MAXLINELEN+1];
	STRING p;
	if (indent) {
		INT i;
		for (i = 1;  i < levl;  i++)
			fprintf(fp, "  ");
	}
	fprintf(fp, "%ld", levl);
	if (nxref(node)) fprintf(fp, " %s", nxref(node));
	fprintf(fp, " %s", ntag(node));
	if ((p = nval(node))) {
		if (ttm) {
			translate_string(ttm, nval(node), out, MAXLINELEN+1);
			p = out;
		}
		fprintf(fp, " %s", p);
	}
	fprintf(fp, "\n");
}
Пример #14
0
/*=================================================================
 * advedit_expand_traverse -- Traverse routine called when expanding record
 *===============================================================*/
static BOOLEAN
advedit_expand_traverse (NODE node, VPTR param)
{
	LIST subs = (LIST)param;
	STRING key = value_to_xref(nval(node));
	if (!key) return TRUE;
	key = strsave(key);
#ifdef DEBUG
	llwprintf("expand_traverse: %s %s\n", ntag(node), nval(node));
#endif /* DEBUG */
	FORLIST(subs, el)
#ifdef DEBUG
	llwprintf("expand_traverse: %s %s\n", key, rmvat(nval((NODE) el)));
#endif /* DEBUG */
		if (eqstr(key, rmvat(nval((NODE) el)))) {
			STOPLIST
			stdfree(key);
			return TRUE;
		}
	ENDLIST
	enqueue_list(subs, node);
	stdfree(key);
	return TRUE;
}
Пример #15
0
/*=================================================
 * do_import -- Read GEDCOM file to database
 *  ifeed: [IN]  output methods
 *  fp:    [I/O] GEDCOM file whence to load data
 *===============================================*/
static BOOLEAN
do_import (IMPORT_FEEDBACK ifeed, FILE *fp)
{
	NODE node, conv;
	XLAT ttm = 0;
	STRING msg;
	BOOLEAN emp;
	INT nindi = 0, nfam = 0, neven = 0;
	INT nsour = 0, nothr = 0, type, num = 0;
	INT totkeys = 0, totused = 0;
	char msgbuf[80];
	BOOLEAN succeeded=FALSE;
	STRING str,unistr=0;
	ZSTR zerr=0;
	TABLE metadatatab = create_table_str();
	STRING gdcodeset=0;
	INT warnings=0;

	/* start by assuming default */
	strupdate(&gdcodeset, gedcom_codeset_in);

/*	rptui_init(); *//* clear ui time counter */

/* Open and validate GEDCOM file */
	if ((unistr=check_file_for_unicode(fp)) && !eqstr(unistr, "UTF-8")) {
		msg_error(_(qSunsupuniv), unistr);
		goto end_import;
	}
	if (eqstr_ex(unistr, "UTF-8")) {
		strupdate(&gdcodeset, "UTF-8");
	}

	if (!scan_header(fp, metadatatab, &zerr)) {
		msg_error(zs_str(zerr));
		goto end_import;
	}

	if ((str = valueof_str(metadatatab, "GEDC.FORM"))!= NULL) {
		if (!eqstr(str, "LINEAGE-LINKED")) {
			if (!ask_yes_or_no_msg(
				_("This is not a lineage linked GEDCOM file.")
				, _("Proceed anyway?")
				))
				goto end_import;
		}
	}
	if (!unistr && (str = valueof_str(metadatatab, "CHAR"))!= NULL) {
		/* if no BOM, use file's declared encoding if present */
		strupdate(&gdcodeset, str);
	}

	/* TODO: Push this codeset question down to after the validation, where we can know if
	the incoming file happened to really be all ASCII */

	if (!int_codeset[0]) {
		/* TODO: ask if user would like to adopt codeset of incoming file, if we found it */
		if (!ask_yes_or_no_msg(
			_("No current internal codeset, so no codeset conversion can be done")
			, _("Proceed without codeset conversion?")
			))
			goto end_import;
	}

	/* Warn if lossy code conversion likely */
	if (gdcodeset[0] && int_codeset[0]) {
		if (is_lossy_conversion(gdcodeset, int_codeset)) {
			ZSTR zstr=zs_new();
			zs_setf(zstr, _("Lossy codeset conversion (from <%s> to <%s>) likely")
				, gdcodeset, int_codeset);
			if (!ask_yes_or_no_msg(
				zs_str(zstr)
				, _("Proceed anyway?")
				))
				goto end_import;
		}
	}

	/* validate */
	if (ifeed && ifeed->validating_fnc)
		(*ifeed->validating_fnc)();

	if (!validate_gedcom(ifeed, fp)) {
		if (ifeed && ifeed->error_invalid_fnc)
			(*ifeed->error_invalid_fnc)(_(qSgdnadd));
		goto end_import;
	}
	warnings = validate_get_warning_count();
	if (warnings) {
		ZSTR zstr=zs_new();
		zs_setf(zstr, _pl("%d warning during import",
			"%d warnings during import", warnings), warnings);
		if (!ask_yes_or_no_msg(zs_str(zstr), _(qSproceed))) {
			goto end_import;
		}
	}

	if (gdcodeset[0] && int_codeset[0]) {
retry_input_codeset:
		ttm = transl_get_xlat(gdcodeset, int_codeset);
		if (!transl_is_xlat_valid(ttm)) {
			ZSTR zstr=zs_new();
			char csname[64];
			BOOLEAN b;
			transl_release_xlat(ttm);
			ttm = 0;
			zs_setf(zstr, _("Cannot convert codeset (from <%s> to <%s>)")
				, gdcodeset, int_codeset);
			b = ask_for_string(zs_str(zstr)
				, _("Enter codeset to assume (* for none)")
				, csname, sizeof(csname)) && csname[0];
			zs_free(&zstr);
			if (!b)
				goto end_import;
			if (!eqstr(csname, "*")) {
				strupdate(&gdcodeset, csname);
				goto retry_input_codeset;
			}
		}
	}
	
	if((num_indis() > 0)
		|| (num_fams() > 0)
		|| (num_sours() > 0)
		|| (num_evens() > 0)
		|| (num_othrs() > 0)) gd_reuse = FALSE;
	else if((gd_reuse = check_stdkeys())) {
		totused = gd_itot + gd_ftot + gd_stot + gd_etot + gd_xtot;
		totkeys = gd_imax + gd_fmax + gd_smax + gd_emax + gd_xmax;
		if((totkeys-totused) > 0) {
			INT delkeys = totkeys-totused;
			snprintf(msgbuf, sizeof(msgbuf)
				, _pl("Using original keys, %d deleted record will be in the database."
					, "Using original keys, %d deleted records will be in the database."
					, delkeys)
				, delkeys
				);
		}
		else strcpy(msgbuf, " ");
		gd_reuse = ask_yes_or_no_msg(msgbuf, _(qScfoldk));
/*
TODO: why were these here ?
		touchwin(uiw_win(stdout_win));
		wrefresh(uiw_win(stdout_win));
*/
	}

	/* start loading the file */
	rewind(fp);

	/* test for read-only database here */

	if(readonly) {
		if (ifeed && ifeed->error_readonly_fnc)
			(*ifeed->error_readonly_fnc)();
		goto end_import;
	}

	/* tell user we are beginning real part of import */
	if (ifeed && ifeed->beginning_import_fnc) {
		if(gd_reuse)
			(*ifeed->beginning_import_fnc)(_(qSdboldk));
		else
			(*ifeed->beginning_import_fnc)(_(qSdbnewk));
	}


/* Add records to database */
	node = convert_first_fp_to_node(fp, FALSE, ttm, &msg, &emp);
	while (node) {
		if (!(conv = node_to_node(node, &type))) {
			free_nodes(node);
			node = next_fp_to_node(fp, FALSE, ttm, &msg, &emp);
			continue;
		}
		switch (type) {
		case INDI_REC: num = ++nindi; break;
		case FAM_REC:  num = ++nfam;  break;
		case EVEN_REC: num = ++neven; break;
		case SOUR_REC: num = ++nsour; break;
		case OTHR_REC: num = ++nothr; break;
		default: FATAL();
		}
		restore_record(conv, type, num);
		if (ifeed && ifeed->added_rec_fnc)
			ifeed->added_rec_fnc(nxref(conv)[1], ntag(conv), num);
		free_nodes(node);
		node = next_fp_to_node(fp, FALSE, ttm, &msg, &emp);
	}
	if (msg) {
		msg_error(msg);
	}
	if(gd_reuse && ((totkeys - totused) > 0)) {
		if (ifeed && ifeed->adding_unused_keys_fnc)
			(*ifeed->adding_unused_keys_fnc)();
		addmissingkeys(INDI_REC);
		addmissingkeys(FAM_REC);
		addmissingkeys(EVEN_REC);
		addmissingkeys(SOUR_REC);
		addmissingkeys(OTHR_REC);
	}
	succeeded = TRUE;

end_import:
	validate_end_import();
	zs_free(&zerr);
	destroy_table(metadatatab);
	strfree(&gdcodeset);
	return succeeded;
}
Пример #16
0
/*=================================================
 * add_dnodes -- add dnodes to dnode tree
 *  recursively, traversing NODE tree & building corresponding
 *  dnode tree
 * if a line overflows, give it succeeding sibling dnodes
 * also, check for subordinate CONT & CONC dnodes to be assimilated
 *===============================================*/
static DISPNODE
add_dnodes (NODE node, INT gen, INT indent, INT maxgen, INT * count, CANVASDATA canvas)
{
	DISPNODE tn;
	DISPNODE tn0, tn1, tn2;
	NODE child, anode;
	INT width = (canvas->rect->right - canvas->rect->left) - 2 - gen*indent;
	static char line[MAXLINELEN], output[MAXLINELEN]; /* must be same size */
	STRING ptr=output;
	INT leader;
	LIST list=NULL;
	INT mylen=sizeof(output), mylenorig;
	if (mylen>width)
		mylen = width;
	mylenorig = mylen;

	/* build xref & tag into line */
	line[0] = 0;
	ptr = line;
	mylen = sizeof(line);

	if (nxref(node)) {
		llstrcatn(&ptr, nxref(node), &mylen);
		llstrcatn(&ptr, " ", &mylen);
	}
	if (ntag(node)) {
		llstrcatn(&ptr, ntag(node), &mylen);
		llstrcatn(&ptr, " ", &mylen);
	}
	leader = ptr-line;
	width -= leader;
	if (width < 10) {
		/* insufficient space */
		return NULL;
	}

	/* output is available as scratch */

	list = text_to_list("", width, LISTDOFREE);
	if (nval(node)) {
		STRING valtxt = nval(node);
		append_to_text_list(list, valtxt, width, FALSE); 
	}

	/* anode is first child */
	anode = nchild(node);
	/* check for text continuation nodes to assimilate */
	if (nchild(node)) {
		for ( ; anode && !nchild(anode); anode = nsibling(anode)) {
			BOOLEAN newline=FALSE;
			STRING valtxt=NULL;
			if (eqstr(ntag(anode), "CONC")) {
				append_to_text_list(list, " ", width, FALSE);
				newline = FALSE;
			} else if (eqstr(ntag(anode), "CONT")) {
				newline = TRUE;
			} else {
				break;
			}
			valtxt = nval(anode);
			append_to_text_list(list, valtxt, width, newline); 
		}
	}
	/* anode is now first non-assimilated child */
	/*
	now add all list elements to tree as siblings
	first one will be tn, which we return as our result
	tn0 refers to previous one, for the nsibling links
	*/
	tn = tn0 = tn1 = 0;
	FORLIST(list, el)
		tn1 = alloc_displaynode();
		if (!tn) {
			INT i;
			tn = tn1;
			/* ptr & mylen still point after leader */
			llstrcatn(&ptr, el, &mylen);
			/* put original line */
			tn1->str = strsave(line);
			/* now build leader we will keep reusing */
			for (i=0; i<leader; i++)
				line[i] = '.';
			line[leader-1] = ' ';
		} else {
			llstrcatn(&ptr, el, &mylen);
			tn1->str = strsave(line);
		}
		/* now we keep resetting ptr & mylen to after blank leader */
		/* so we keep reusing that leader we built in line earlier */
		ptr=line+leader;
		mylen=mylenorig-leader;
		tn1->firstchild = 0;
		tn1->nextsib = 0;
		if (tn0)
			tn0->nextsib = tn1;
		tn0 = tn1;
		(*count)++;
	ENDLIST
	/* special handling for empty list, which didn't get its leader */
	if (is_empty_list(list)) {
		tn1 = alloc_displaynode();
		tn = tn1;
		tn1->str = strsave(line);
		tn1->firstchild = 0;
		tn1->nextsib = 0;
		tn0 = tn1;
		(*count)++;
	}
	destroy_list(list);
	list=0;

	if (gen < maxgen) {
		/* our children hang off of tn2, which is last node of our
		sibling tree; tn0 is previously added child */
		tn2 = tn1;
		tn0 = 0;
		/* anode was last unassimilated child */
		for (child = anode; child; child = nsibling(child)) {
			tn1 = add_dnodes(child, gen+1, indent, maxgen, count, canvas);
			if (!tn1)
				continue; /* child was skipped */
			/* link new displaynode into tree we're building */
			if (tn0)
				tn0 = tn0->nextsib = tn1;
			else /* first child - first time thru loop */
				tn0 = tn2->firstchild = tn1;
			/* child displaynode might have (overflow or assimilated) siblings */
			while (tn0->nextsib)
				tn0 = tn0->nextsib;
		}
	}
	return tn;
}
Пример #17
0
/*================================================
 * edit_add_record -- Add record to database by editing
 *  recstr:  [IN] default record
 *  redt:    [IN] re-edit message
 *  ntype,   [IN] S, E, or X
 *  cfrm:    [IN] confirm message
 *==============================================*/
static RECORD
edit_add_record (STRING recstr, STRING redt, STRING redtopt, char ntype, STRING cfrm)
{
	FILE *fp;
	NODE node=0, refn;
	STRING msg, key;
	BOOLEAN emp;
	XLAT ttmi = transl_get_predefined_xlat(MEDIN);
	STRING (*getreffnc)(void) = NULL; /* get next internal key */
	void (*todbasefnc)(NODE) = NULL;  /* write record to dbase */
	void (*tocachefnc)(NODE) = NULL;  /* write record to cache */
	
	/* set up functions according to type */
	if (ntype == 'S') {
		getreffnc = getsxref;
		todbasefnc = sour_to_dbase;
		tocachefnc = sour_to_cache;
	} else if (ntype == 'E') {
		getreffnc = getexref;
		todbasefnc = even_to_dbase;
		tocachefnc = even_to_cache;
	} else { /* X */
		getreffnc = getxxref;
		todbasefnc = othr_to_dbase;
		tocachefnc = othr_to_cache;
	}

/* Create template for user to edit */
	if (!(fp = fopen(editfile, LLWRITETEXT))) {
		msg_error(_(qSnofopn), editfile);
		return FALSE;
	}
	prefix_file_for_edit(fp);
	fprintf(fp, "%s\n", recstr);

/* Have user edit new record */
	fclose(fp);
	do_edit();
	while (TRUE) {
		INT cnt;
		node = file_to_node(editfile, ttmi, &msg, &emp);
		if (!node) {
			if (ask_yes_or_no_msg(msg, redt)) { /* yes, edit again */
				do_edit();
				continue;
			} 
			break;
		}
		cnt = resolve_refn_links(node);
		/* check validation & allow user to reedit if invalid */
		/* this is a showstopper, so alternative is to abort */
		if (!valid_node_type(node, ntype, &msg, NULL)) {
			if (ask_yes_or_no_msg(msg, redt)) {
				do_edit();
				continue;
			}
			free_nodes(node);
			node = NULL; /* fail out */
			break;
		}
		/* Allow user to reedit if desired if any refn links unresolved */
		/* this is not a showstopper, so alternative is to continue */
		if (cnt > 0) {
			char msgb[120];
			snprintf(msgb, sizeof(msgb)
				, get_unresolved_ref_error_string(cnt), cnt);
			if (ask_yes_or_no_msg(msgb, redtopt)) {
				write_node_to_editfile(node);
				do_edit();
				continue;
			}
		}
		break;
	}
	if (!node || !ask_yes_or_no(cfrm)) {
		if (node) free_nodes(node);
		return NULL;
	}
	nxref(node) = strsave((STRING)(*getreffnc)());
	key = rmvat(nxref(node));
	for (refn = nchild(node); refn; refn = nsibling(refn)) {
		if (eqstr("REFN", ntag(refn)) && nval(refn))
			add_refn(nval(refn), key);
	}
	(*todbasefnc)(node);
	(*tocachefnc)(node);
	return key_to_record(key);
}
Пример #18
0
/*===================================
 * valid_indi_tree -- Validate person tree
 *  indi1:  [IN]  person to validate
 *  pmsg:   [OUT] error message, if any
 *  orig:   [IN]  person to match - may be NULL
 * rtn: FALSE for bad
 * Should be replaced by valid_indi(RECORD,...) ?
 *=================================*/
BOOLEAN
valid_indi_tree (NODE indi1, STRING *pmsg, NODE orig)
{
	NODE name1, refn1, sex1, body1, famc1, fams1, node;
	NODE name0, refn0, sex0, body0, famc0, fams0;
	INT isex, num;
	STRING *keys, ukey;

	if (!indi1) {
		*pmsg = _(qSbademp);
  		return FALSE;
	}
	if (nestr("INDI", ntag(indi1))) {
		*pmsg = _(qSbadin0);
		return FALSE;
	}
	if (nsibling(indi1)) {
		*pmsg = _(qSbadmul);
		return FALSE;
	}
	split_indi_old(indi1, &name1, &refn1, &sex1, &body1, &famc1, &fams1);
	if (getlloptint("RequireNames", 0) && !name1) {
		*pmsg = _("This person record does not have a name line.");
		goto bad2;
	}
	for (node = name1; node; node = nsibling(node)) {
		if (!valid_name(nval(node))) {
			*pmsg = _(qSbadenm);
			goto bad2;
		}
	}
	name0 = refn0 = sex0 = body0 = famc0 = fams0 = NULL;
	if (orig)
		split_indi_old(orig, &name0, &refn0, &sex0, &body0, &famc0,
		    &fams0);
	if (orig && !iso_nodes(indi1, orig, FALSE, FALSE)) {
		*pmsg = _(qSbadind); 
		goto bad1;
	}
	if (!iso_nodes(famc1, famc0, FALSE, TRUE)) {
		*pmsg = _(qSbadfmc);
		goto bad1;
	}
	if (!iso_nodes(fams1, fams0, FALSE, TRUE)) {
		*pmsg = _(qSbadfms); 
		goto bad1;
	}
	isex = val_to_sex(sex0);
	if (!fams0) isex = SEX_UNKNOWN;
	if (isex != SEX_UNKNOWN && isex != val_to_sex(sex1)) {
		*pmsg = _(qSbadparsex);
		goto bad1;
	}
	ukey = (refn1 ? nval(refn1) : NULL);
	get_refns(ukey, &num, &keys, 'I');
	if (num > 1 || (num == 1 && (!orig ||
	    nestr(keys[0], rmvat(nxref(indi1)))))) {
		*pmsg = _(qSbadirefn);
		goto bad1;
	}
	if (orig)
		join_indi(orig, name0, refn0, sex0, body0, famc0, fams0);
	join_indi(indi1, name1, refn1, sex1, body1, famc1, fams1);
	return TRUE;
bad1:
	if (orig)
		join_indi(orig, name0, refn0, sex0, body0, famc0, fams0);
bad2:
	join_indi(indi1, name1, refn1, sex1, body1, famc1, fams1);
	return FALSE;
}