Geneal (part 2 of 3) (debugged version)

Terry L. Ridder tlr at umcp-cs.UUCP
Sat Sep 14 09:09:49 AEST 1985


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	dataman.c
#	errorman.c
#	famgetdat.c
#	family.1003
#	family.c
#	famtree.c
#	famtree.h
# This archive created: Thu Sep 12 22:19:03 1985
# By:	Terry L. Ridder (The Terry L. Ridder family)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'dataman.c'" '(5361 characters)'
if test -f 'dataman.c'
then
	echo shar: will not over-write existing file "'dataman.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'dataman.c'
	X/* dataman - simple data manager for reading data from text files */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 09:14:15 by jimmc (Jim McBeath) */
	X/* last edit 11-Sept-85 22:31:00 by tlr (Terry L. Ridder) */
	X
	X/* This module is a very simple data manager which allows a simple
	X   interface to a text file.  The text file is the database.  This
	X   module has routines to read that database (it is assumed that
	X   the writing is done by another program, e.g. a text editor).
	X   The format of the data file is as follows:
	X
	X   A file consists of a sequence of records.  All records are ascii
	X   text.  Records are separated by blank lines.  Lines within each
	X   record contain the data for that record.  The first line of a
	X   record must begin with an integer.  This integer is the index
	X   number of that record, and is used to reference the record.  All
	X   other text on the line with the index number is ignored, so
	X   can be used as a comment line.
	X
	X   The remaining lines in a record are data items for that record.
	X   A data item consists of a key and a payload.  The key is any
	X   string of printing characters followed by a colon (i.e. the
	X   key can't contain a colon!).  All remaining text on the line,
	X   after the colon, is the payload for that data item.
	X
	X   Both index numbers and key strings must be unique; non-unique
	X   items will not be referenceable.  Index numbers need not be in
	X   any order.  Key strings should be short to increase speed.
	X   (Note that this is not designed to be a particularly fast
	X   system anyway!)
	X*/
	X
	Xextern char *malloc();
	X
	X/*..........*/
	X
	X#include "geneal.h"
	X
	Xstruct toplevel *initIndex();
	X
	X#ifdef vms
	X#define index strchr
	X#endif
	X
	Xint dataDebug  = 0;			/* set this flag to give debug output */
	Xint dataStatus = 0;			/* status after most recent operation */
	Xchar *dataErrStrs[] = {
	X    "successful data operation",	/* 0 */
	X    "can't open data file",		/* 1 */
	X    "no more memory",			/* 2 */
	X    "can't start an index table",	/* 3 */
	X    "invalid pointer to getData",	/* 4 */
	X    "no file open in getData",		/* 5 */
	X    "no index table in getData",	/* 6 */
	X    "no such index number",		/* 7 */
	X    "key not found",			/* 8 */
	X    };
	X#define ERET(n) { dataStatus = n; return 0; }
	X
	X/*..........*/
	X
	Xstruct dpoint *				/* a pointer to our internal struct */
	X					/* returns 0 on error */
	XinitDataFile(fn)			/* init the data file to be used */
	Xchar *fn;				/* the filename to look up */
	X{
	XFILE *fp;
	Xstruct dpoint *pp;
	Xstruct toplevel *qq;
	Xint iflag,n;
	Xchar linebuf[256];
	X
	Xfp = fopen(fn, "r");			/* get his data file */
	Xif (!fp) 
	X{
	X    ERET(1)				/* can't do anything if no file */
	X}
	Xpp = (struct dpoint *)malloc(sizeof(struct dpoint));
	Xif (!pp) 
	X{					/* if no memory for us */
	X    fclose(fp);				/* dump the file */
	X    ERET(2)				/* error return */
	X}
	Xpp->ff = fp;			/* put file pointer into our data block */
	Xqq = initIndex();			/* start up an index table */
	Xif (qq == 0) 
	X{					/* if can't start up an index table */
	X    fclose(fp);
	X    free((char *)pp);
	X    ERET(3)
	X}
	Xpp->xx = qq;				/* save pointer to index table */
	Xif (dataDebug) 
	X{
	X    printf("initDataFile: index table is at %X\n", qq);
	X}
	Xiflag = 1;				/* note next line can be index line */
	Xwhile (!feof(fp)) 
	X{					/* scan through the file */
	X    fgets(linebuf, 255, fp);		/* read a line */
	X    if (iflag) 
	X    {					/* if we can look for an index line */
	X	if (sscanf(linebuf, "%d", &n) == 1) 
	X	{				/* and if we got a number */
	X	    if (dataDebug) 
	X	    {
	X		printf("initDataFile: index %d at loc %d\n",
	X				n, ftell(fp));
	X	    }
	X	    setIndex(qq, n, (int)ftell(fp)); /* remember start of next line */
	X	    iflag = 0;			/* have to get a blank line now */
	X	}
	X    }
	X    else 
	X    {					/* see if this is a blank line */
	X	if (linebuf[0] != '\n') 
	X	{
	X	    iflag++;			/* note blank line */
	X	}
	X    }
	X}
	XdataStatus = 0;
	Xreturn pp;				/* return pointer to our structure */
	X}
	X
	X/*..........*/
	X
	Xchar *				/* returns a pointer to the data string */
	X				/*  return NULL if no data */
	XgetData(pp, indexn, key)	/* get a data item */
	Xstruct dpoint *pp;		/* pointer to our structure */
	Xint indexn;			/* the index of the record of interest */
	Xchar *key;				/* the key string */
	X{
	Xint l;
	Xchar *cc,*index();
	Xstatic char linebuf[256];
	X
	Xif (!pp) 
	X{
	X    ERET(4)				/* check for valid pointer */
	X}
	Xif (!(pp->ff)) 
	X{
	X    ERET(5)				/* error return if no file open */
	X}
	Xif (!(pp->xx)) 
	X{
	X    ERET(6)				/* error if no index table pointer */
	X}
	Xl = getIndex(pp->xx, indexn);		/* get the lseek value for that index */
	Xif (l == 0) 
	X{
	X    ERET(7)			/* error if no lseek value for that index */
	X}
	Xfseek(pp->ff, (long)l, 0);		/* seek to the start of that line */
	Xwhile (!feof(pp->ff)) 
	X{					/* read lines until eof (or blank) */
	X    fgets(linebuf, 255, pp->ff);	/* read in a line */
	X    if (linebuf[0] == '\n') 
	X    {
	X	break;				/* stop on a blank line */
	X    }
	X    cc = index(linebuf, ':');		/* search for the colon */
	X    if (!cc) 
	X    {
	X	continue;		/* if no colon, take it as a comment line */
	X    }
	X    *cc = 0;				/* replace colon with null */
	X    if (strcmp(linebuf, key) == 0) 
	X    {
	X	cc++;				/* point to start of payload */
	X	*(cc + strlen(cc) - 1) = 0;	/* remove \n from the end */
	X	dataStatus = 0;
	X	return cc;			/* return pointer to payload */
	X    }
	X}				/* continue - read next line and compare */
	XERET(8)					/* eof or blank line, key not found */
	X}
	X
	X/* end */
SHAR_EOF
if test 5361 -ne "`wc -c < 'dataman.c'`"
then
	echo shar: error transmitting "'dataman.c'" '(should have been 5361 characters)'
fi
chmod +x 'dataman.c'
fi # end of overwriting check
echo shar: extracting "'errorman.c'" '(1113 characters)'
if test -f 'errorman.c'
then
	echo shar: will not over-write existing file "'errorman.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'errorman.c'
	X/* errorman.c - general error handling routines */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 09:01:20 by jimmc (Jim McBeath) */
	X/* last edit 11-Sept-85 22:07:00 by tlr (Terry L. Ridder) */
	X
	X/* To use these routines, the user must have the variable Progname declared
	X * elsewhere; also, these routines call sprintf. 
	X */
	X
	X#include <stdio.h>
	X
	X#define ERROR_EXIT 1
	X#define BSIZE 200
	X
	Xextern char *Progname;		/* user must set up the progname to use */
	Xextern char *sprintf();
	X
	X/*..........*/
	X
	X/* VARARGS1 */
	Xwarning(s, arg1, arg2)
	Xchar *s;
	Xint  arg1, arg2;
	X{
	Xchar buf[BSIZE];
	X
	X    sprintf(buf, s, arg1, arg2);
	X    fprintf(stderr, "%s: warning: %s\n", Progname, buf);
	X}
	X
	X/*..........*/
	X
	X/* VARARGS1 */
	Xfatalerr(s, arg1, arg2)
	Xchar *s;
	Xint  arg1, arg2;
	X{
	Xchar buf[BSIZE];
	X
	X    sprintf(buf, s, arg1, arg2);
	X    fprintf(stderr, "%s: fatal error: %s\n", Progname, buf);
	X    exit(ERROR_EXIT);
	X}
	X
	X/*..........*/
	X
	X/* VARARGS1 */
	Xerrormsg(s, arg1, arg2)
	Xchar *s;
	Xint  arg1, arg2;
	X{
	Xchar buf[BSIZE];
	X
	X    sprintf(buf, s, arg1, arg2);
	X    fprintf(stderr, "%s: error: %s\n", Progname, buf);
	X}
	X
	X/* end */
SHAR_EOF
if test 1113 -ne "`wc -c < 'errorman.c'`"
then
	echo shar: error transmitting "'errorman.c'" '(should have been 1113 characters)'
fi
chmod +x 'errorman.c'
fi # end of overwriting check
echo shar: extracting "'famgetdat.c'" '(8463 characters)'
if test -f 'famgetdat.c'
then
	echo shar: will not over-write existing file "'famgetdat.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'famgetdat.c'
	X/* famgdat.c - routines to get pieces of info records */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 08:45:48 by jimmc (Jim McBeath) */
	X/* last edit 10-Sept-85 00:04:00 by tlr (Terry L. Ridder) */
	X
	X/* These routines all package up various pieces of information
	X * from specified records.  They each take as arguments a record
	X * ID number; some take a field name as well.  Most return a pointer
	X * to a string allocated from dynamic memory, which can be freed
	X * by passing the pointer to the free() function.  Exceptions are
	X * noted (e.g. fgnum returns an int).
	X * Functions are:
	X * fgnum(n,s)		returns the integer value of field s
	X * fgstr(n,s)		the basic string routine which returns field s
	X * bstr(n,s,b)		like fgstr, but returns string in buffer b
	X * tname(n)		all of name but last name
	X * bname(n)		full born (maiden) name
	X * fname(n)		full name (including maiden and married last names)
	X * fgbirth(n)		birth date and place
	X * fgdeath(n)		death date and place
	X * fgbegend(n)		birth and death dates
	X * fgmar(n)		marriage date and place
	X * fgclist(n,av)	get child list; return value is ac, fills pointer av
	X */
	X
	X#include "famtree.h"
	X#include "geneal.h"
	X
	X#define TRUE 1
	X#define FALSE 0
	X
	Xextern char *strcat();
	Xextern char *strcpy();
	X
	X/* for forward references */
	Xchar *fgdateplace();
	X
	X/*..........*/
	X
	Xint
	Xfgnum(n,s)		/* get an item number from the data file */
	Xint n;			/* person to get data item for */
	Xchar *s;		/* name of data item */
	X{
	Xint tt, dd;
	Xchar *str;
	X
	X    if (gendp == 0) 
	X    {
	X	fatalerr("no data file opened");
	X    }
	X    if (n <= 0) 
	X    {
	X	return -1;
	X    }
	X    str = getData(gendp, n, s);		/* get pointer to data item */
	X    if (str == 0) 
	X    {
	X	return -1;			/* -1 if no such item */
	X    }
	X    tt = sscanf(str, "%d", &dd);	/* get the number */
	X    if (tt != 1) 
	X    {
	X	return -1;			/* if no succesful scan */
	X    }
	X    return dd;			/* return the number we found */
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xfgstr(n, s)		/* get an item string from the data file */
	Xint n;			/* person to get data item for */
	Xchar *s;		/* name of data item */
	X{
	Xchar *str;
	X
	X    if (gendp == 0) 
	X    {
	X	fatalerr("no data file opened");
	X    }
	X    if (n <= 0) 
	X    {
	X	return "";
	X    }
	X    str = getData(gendp, n, s);	/* get pointer to data item */
	X    if (str == 0) 		/* null string if no such item */
	X    {
	X	return "";	
	X    }
	X    return strsav(str);
	X}
	X
	X/*..........*/
	X
	Xint			/* returns 1 if found, 0 if not */
	Xbstr(n, s, b)		/* get an item string from the data file */
	Xint n;			/* person to get data item for */
	Xchar *s;		/* name of data item */
	Xchar *b;		/* the buffer to put it into */
	X{
	X    char *str;
	X
	X    if (gendp == 0) 
	X    {
	X	fatalerr("no data file opened");
	X    }
	X    if (n <= 0) 			/* make string null */
	X    { 
	X	*b = 0; 
	X	return 0; 
	X    }					
	X    str = getData(gendp, n, s);	        /* get pointer to data item */
	X    if (str == 0) 			/* null string if no such item */
	X    { 
	X	*b = 0; 
	X	return 0; 
	X    }					/* null string if no such item */
	X    strcpy(b, str);		        /* copy the string to his buffer */
	X    return 1;
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xtname(n)			/* get the full name (except last name) */
	Xint n;				/* person to get data item for */
	X{
	Xchar xname[200];
	Xchar Fname[100], mname[100], nname[100];
	X
	X    bstr(n, "FN", Fname);	/* get first name */
	X    bstr(n, "MN", mname);	/* get middle name */
	X    bstr(n, "NN", nname);	/* get nick-name */
	X    xname[0] = 0;		/* start with null */
	X    if (indexes) 
	X    {
	X	sprintf(xname, "[%d]", n);	/* put in the id number */
	X    }
	X    addcstr(xname, Fname);	/* add first name */
	X    addcstr(xname, mname);	/* add middle name */
	X    addpstr(xname, nname);	/* add nickname in parens */
	X    return strsav(xname);
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xbname(n)		/* get the full born name */
	Xint n;			/* person to get data item for */
	X{
	Xchar xname[200];
	Xchar Fname[100], mname[100], nname[100], lname[100], oname[100];
	X
	X    bstr(n, "FN", Fname);	/* get first name */
	X    bstr(n, "MN", mname);	/* get middle name */
	X    bstr(n, "NN", nname);	/* get nick-name */
	X    bstr(n, "LN", lname);	/* get last name */
	X    bstr(n, "LNM", oname);	/* original last name */
	X    xname[0] = 0;		/* start with null */
	X    if (indexes) 
	X    {
	X	sprintf(xname, "[%d]", n);	/* put in the id number */
	X    }
	X    addcstr(xname, Fname);
	X    addcstr(xname, mname);
	X    addpstr(xname, nname);
	X    addcstr(xname, oname);
	X    if (oname[0] == 0) 
	X    {
	X	addcstr(xname, lname); /* use last name of no maiden */
	X    }
	X    return strsav(xname);
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xfname(n)		/* get the full name */
	Xint n;			/* person to get data item for */
	X{
	Xchar xname[200];
	Xchar Fname[100], mname[100], nname[100], lname[100], oname[100];
	X
	X    bstr(n, "FN", Fname);	/* get first name */
	X    bstr(n, "MN", mname);	/* get middle name */
	X    bstr(n, "NN", nname);	/* get nick-name */
	X    bstr(n, "LN", lname);	/* get last name */
	X    bstr(n, "LNM", oname);	/* original last name */
	X    xname[0] = 0;		/* start with null */
	X    if (indexes) 
	X    {
	X	sprintf(xname,"[%d]", n);	/* put in the id number */
	X    }
	X    addcstr(xname, Fname);
	X    addcstr(xname, mname);
	X    addpstr(xname, nname);
	X    addcstr(xname, oname);
	X    addcstr(xname, lname);
	X    return strsav(xname);
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xfgbirth(n)			/* get birth date info */
	Xint n;				/* person to get data item for */
	X{
	X    return fgdateplace(n, "B", "BP", "b");
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xfgdeath(n)			/* get death date info */
	Xint n;				/* person to get data item for */
	X{
	X    return fgdateplace(n, "D", "DP", "d");
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xfgbegend(n)			/* get birth/death date info */
	Xint n;				/* person to get data item for */
	X{
	Xchar bdate[100], ddate[100], dates[200];
	X
	X    bstr(n, "B", bdate);	/* get birth date */
	X    bstr(n, "D", ddate);	/* get death date */
	X    if (*bdate == 0 && *ddate == 0) 
	X    {
	X	return "";
	X    }
	X    if (*ddate == 0) 
	X    {
	X	sprintf(dates, "( b: %s )", bdate);
	X    }
	X    else if (*bdate == 0) 
	X    {
	X	sprintf(dates, "( d: %s )", ddate);
	X    }
	X    else 
	X    {
	X	sprintf(dates, "( b: %s, d: %s )", bdate, ddate);
	X    }
	X    return strsav(dates);
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xfgmar(n)			/* get marriage date info */
	Xint n;				/* person to get data item for */
	X{
	X    return fgdateplace(n, "M", "MP", "m");
	X}
	X
	X/*..........*/
	X
	Xchar *
	Xfgdateplace(n, dk, pk, cc)	/* get date/place info */
	Xint n;				/* person to get data item for */
	Xchar *dk;			/* date keyword */
	Xchar *pk;			/* place keyword */
	Xchar *cc;			/* string to use as output key */
	X{
	Xchar date[100], place[100];
	X
	X    bstr(n, dk, date);		/* get date */
	X    bstr(n, pk, place);		/* get place */
	X    if (*date == 0 && *place == 0) 
	X    {
	X	return "";
	X    }
	X    if (*date && *place) 
	X    {
	X	return tprintf("%s: %s, %s", cc, date, place);
	X    }
	X    if (*date) 
	X    {
	X	return tprintf("%s: %s", cc, date);
	X    }
	X    return tprintf("%s: %s", cc, place);
	X}
	X
	X/*..........*/
	X
	Xint			/* returns count */
	Xfgclist(n, av)
	Xint n;			/* id of family */
	Xint **av;		/* ADDRESS of where to put the av we return */
	X{
	X    char cstr[200];
	X    char *cstrp;
	X    int *clist;
	X    int i, ac, tt, dd;
	X
	X    bstr(n, "C", cstr);	/* get list of kids */
	X    cstrp = cstr;
	X
	X    for (ac = 0; (cstrp && *cstrp); ac++)
	X    {
	X	cstrp = index(cstrp + 1, ',');	/* count separators */
	X    }
	X    if (ac == 0) 
	X    {
	X	return 0;
	X    }
	X    clist = XALLOC(int, ac, "fgclist");
	X    for(cstrp = cstr, i = 0; (cstrp && *cstrp); i++)
	X    {
	X	if (i >= ac) 
	X	{
	X	    fatalerr("loop too far on child list in fgclist");
	X	}
	X	tt = sscanf(cstrp, "%d", &dd);	/* read child number */
	X	if (tt == 1) 
	X	{
	X	    clist[i] = dd;
	X	}
	X	else
	X	{
	X	    warning("bad child list format in family %d", n);
	X	    clist[i] = dd = -1;
	X	}
	X	cstrp = index(cstrp, ',');
	X	if (cstrp != 0) 
	X	{
	X	    cstrp++;
	X	}
	X    }
	X    if (i != ac)
	X    {
	X	warning("bad child list format in family %d", n);
	X	for (; i < ac; i++)
	X	{
	X	    clist[i] = -1;	/* fill with -1 */
	X	}
	X    }
	X    *av = clist;		/* fill in pointer */
	X    return ac;			/* return count */
	X}
	X
	X/*..........*/
	X
	Xaddcstr(dd, ss)			/* add a string to another */
	Xchar *dd;			/* the string being built */
	Xchar *ss;			/* the string to add if not null */
	X{
	X    if (ss && *ss)
	X    {
	X	if (dd[0]) 
	X	{
	X	    strcat(dd," ");
	X	}
	X	strcat(dd, ss);
	X    }
	X}
	X
	X/*..........*/
	X
	Xaddpstr(dd, ss)			/* add a string in parens */
	Xchar *dd;			/* the string to add to */
	Xchar *ss;			/* the string to add in parens if not null */
	X{
	X    if (ss[0])
	X    {
	X	if (dd[0]) 
	X	{
	X	    strcat(dd, " ");
	X	}
	X	strcat(dd, "(");
	X	strcat(dd, ss);		/* add the string in parens */
	X	strcat(dd, ")");
	X    }
	X}
	X
	X/* end */
SHAR_EOF
if test 8463 -ne "`wc -c < 'famgetdat.c'`"
then
	echo shar: error transmitting "'famgetdat.c'" '(should have been 8463 characters)'
fi
chmod +x 'famgetdat.c'
fi # end of overwriting check
echo shar: extracting "'family.1003'" '(587 characters)'
if test -f 'family.1003'
then
	echo shar: will not over-write existing file "'family.1003'"
else
sed 's/^	X//' << \SHAR_EOF > 'family.1003'
	X    ANDREW Q. DOE & ELIZABETH NANCY (BETH) SMITH
	X
	X    Andrew Q. Doe                        Elizabeth Nancy (Beth) Smith
	X    b: 3-Feb-1921, New York, NY          b: 4-Mar-1925, Hauppauge, NY
	X    m: 3-Aug-1948, San Francisco, CA
	X
	X    CHILDREN                             SPOUSES OF CHILDREN
	X
	X    David (Dave) Doe                     Nancy M. Walker
	X    b: 3-Jun-1949, Midville, USA         b: Jul-1950
	X    m: 6-Sep-1975
	X
	X    John Michael (Norm) Doe              Jane Jill Jones
	X    b: 10-Feb-1952, Anytown, USA         b: 12-Dec-1953, Los Angeles, CA
	X    m: 15-Jun-1973, San Franciso, CA
	X
SHAR_EOF
if test 587 -ne "`wc -c < 'family.1003'`"
then
	echo shar: error transmitting "'family.1003'" '(should have been 587 characters)'
fi
chmod +x 'family.1003'
fi # end of overwriting check
echo shar: extracting "'family.c'" '(8136 characters)'
if test -f 'family.c'
then
	echo shar: will not over-write existing file "'family.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'family.c'
	X/* family.c - produce a family information page */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 08:47:46 by jimmc (Jim McBeath) */
	X/* last edit 11-Sept-85 22:29:00 by tlr (Terry L. Ridder) */
	X
	X#include "geneal.h"
	X#include <ctype.h>
	X#include "pagemap.h"
	X
	X#define PGWD 80
	X#define LTMAR 4
	X#define RTMAR 4
	X#define CTRMAR 2
	X#define LTCOL ((PGWD-LTMAR-RTMAR-CTRMAR)/2)
	X#define RTCOL (PGWD-LTMAR-RTMAR-CTRMAR-LTCOL)
	X#define SO 10
	X
	X#define TBLOCKSIZE 1000
	X#define NOTEMAX 500
	X
	Xstruct tblock {				/* a text block */
	X    int width;				/* length of longest line */
	X    int lines;				/* number of lines */
	X    char *text[TBLOCKSIZE];		/* the text pointers */
	X    };
	X
	X
	Xint notenum;
	Xint notecount;				/* for storing the footnotes */
	Xchar *notes[NOTEMAX];
	X
	X/*..........*/
	X
	Xint					/* 0 if OK */
	Xfamily(famnum)
	Xint famnum;				/* the family to give info about */
	X{
	Xchar *rtype;
	Xchar *famname, *hisname, *hername;
	Xchar *hislname, *herlname;
	Xint hisnum, hernum;
	Xchar *headerline;
	Xint i, cnum, *clist;
	Xchar *ss;
	X
	X    notecount = notenum = 0;
	X    rtype = fgstr(famnum, "T");		/* get record type */
	X    if (rtype == 0 || *rtype == 0)
	X    {
	X	warning("no such record number %d", famnum);
	X	return 1;
	X    }
	X    if (rtype[0] != 'F')
	X    {
	X	warning("record %d is not a family", famnum);
	X	return 1;
	X    }
	X    famname  = fgstr(famnum, "N");	/* get the family name */
	X    hisnum   = fgnum(famnum, "H");	/* get husband and wife index nums */
	X    hernum   = fgnum(famnum, "W");
	X    hisname  = bname(hisnum);
	X    hername  = bname(hernum);
	X    hislname = fgstr(hisnum, "LN");
	X    herlname = fgstr(hernum, "LNM");
	X    if (herlname == 0 || herlname[0] == 0) 
	X    {
	X	herlname = fgstr(hernum, "LN");
	X    }
	X
	X    if (hislname && hislname[0] == 0) 
	X    {
	X	hislname = 0;
	X    }
	X    if (herlname && herlname[0] == 0) 
	X    {
	X	herlname = 0;
	X    }
	X    if (famname && famname[0] == 0) 
	X    {
	X	famname = 0;
	X    }
	X    if (hisname == 0 || hisname[0] == 0) 
	X    {
	X	hisname = "???";
	X    }
	X    if (hername == 0 || hername[0] == 0) 
	X    {
	X	hername = "???";
	X    }
	X    if (famname && (hislname == 0 || strcmp(famname, hislname) != 0))
	X    {
	X	headerline = tprintf("%s - %s & %s", famname, hisname, hername);
	X    }
	X    else
	X    {
	X	headerline = tprintf("%s & %s", hisname, hername);
	X    }
	X    for (ss = headerline; *ss; ss++)
	X    {
	X	if (islower(*ss)) 
	X	{
	X	    *ss = toupper(*ss);		/* convert to upper case */
	X	
	X	}
	X    }
	X    printf("%*s%s\n\n", LTMAR, " ", headerline);
	X    printpair(0, famnum, hisnum, hernum);	/* print data about parents */
	X    cnum = fgclist(famnum, &clist);
	X    if (cnum == 0)
	X    {
	X/* be silent about no children...
	X	printf("%*s%s\n", LTMAR, " ", "NO CHILDREN");
	X */
	X    }
	X    else
	X    {
	X	printf("%*s%-*s%*s%s\n\n", LTMAR, " ", LTCOL, "CHILDREN",
	X	    CTRMAR, " ", "SPOUSES OF CHILDREN");
	X	for (i = 0; i < cnum; i++)
	X	{
	X	 int childnum, marnum, sonum, chisnum, chernum;
	X	 int mnum;
	X	 char mnumstr[5];
	X    
	X	    childnum = clist[i];
	X	    for (mnum = 0, marnum = 1; marnum > 0; mnum++)
	X			    /* until we run out of marriages */
	X	    {
	X		sprintf(mnumstr,"S%d", mnum);
	X		marnum = fgnum(childnum, mnumstr);	/* get marriage */
	X		if (marnum > 0)
	X		{
	X		    chisnum = fgnum(marnum, "H");
	X		    chernum = fgnum(marnum, "W");
	X		    if (childnum == chisnum) 
	X		    {
	X			sonum = chernum;
	X		    }
	X		    else if (childnum == chernum) 
	X		    {
	X			sonum = chisnum;
	X		    }
	X		    else
	X		    {
	X			warning(
	X			    "person %d claims marraige %d, but not vice-versa!",
	X			    childnum, marnum);
	X			sonum= -1;
	X		    }
	X		}
	X		else sonum = -1;
	X		if (mnum == 0 || marnum > 0) 
	X		{
	X		    printpair(mnum, marnum, childnum, sonum);
	X		}
	X	    }
	X	}
	X    }
	X    if (notecount > 0)		/* if we accumulated any notes */
	X    {
	X	printf("%*s%s\n\n", LTMAR, " ", "-----------------------");
	X	for (i = 0; i < notecount; i++)
	X	{
	X	    printf("%*s%s\n", LTMAR, " ",  notes[i]);
	X	}
	X    }
	X    return 0;
	X}
	X
	X/*..........*/
	X
	Xprintpair(n, mn, cn, sn)	/* print info about a couple */
	Xint n;			/* which marriage in the list this is; -1=only one */
	Xint mn;			/* marriage number */
	Xint cn;			/* primary person number */
	Xint sn;			/* spouse number */
	X{
	Xstruct tblock cntb, sntb;	/* where to store data */
	Xint i, max;
	X
	X    fampdat(n, mn, cn, &cntb);		/* get the data */
	X    fampdat(-1, mn, sn, &sntb);
	X/* decide if they should both be on the same lines or not */
	X    if (cntb.width > LTCOL || sntb.width > RTCOL) /* separate */
	X    {
	X	printtb(&cntb, LTMAR);	/* output the first one */
	X	printtb(&sntb, LTMAR + SO);	/* output spouse */
	X    }
	X    else		/* both on the same line */
	X    {
	X	if (cntb.lines > sntb.lines) 
	X	{
	X	    max = cntb.lines;
	X	}
	X	else 
	X	{
	X	    max = sntb.lines;
	X	}
	X	for (i = 0; i < max; i++)
	X	{
	X	    if (i >= cntb.lines)
	X	    {
	X		printf("%-*s%s\n",
	X		    (LTMAR + CTRMAR + LTCOL), " ", sntb.text[i]);
	X	    }
	X	    else if (i >= sntb.lines)
	X	    {
	X		printf("%*s%s\n",
	X		    LTMAR, " ", cntb.text[i]);
	X	    }
	X	    else
	X	    {
	X		printf("%*s%-*s%*s%s\n", LTMAR, " ",
	X		    LTCOL, cntb.text[i], CTRMAR, " ", sntb.text[i]);
	X	    }
	X	}
	X	printf("\n");
	X    }
	X}
	X
	X/*..........*/
	X
	Xprinttb(b, offset)		/* print a text block */
	Xstruct tblock *b;
	Xint offset;			/* left margin offset */
	X{
	Xint i;
	X
	X    for (i = 0; i < b->lines; i++)
	X    {
	X	printf("%*s%s\n", offset, " ", b->text[i]);
	X    }
	X    if (b->lines != 0) 
	X    {
	X	printf("\n");
	X    }
	X}
	X
	X/*..........*/
	X
	Xfampdat(i, m, n, b)		/* get a tblock about a person */
	Xint i;			/* iteration number to determine how to format */
	Xint m;			/* marriage number */
	Xint n;			/* the person to get info about */
	Xstruct tblock *b;	/* where to put the data */
	X{
	Xchar *name, *birth, *death, *mar;
	X
	X    b->lines = b->width = 0;	/* clear it out first */
	X    if (n <= 0) 
	X    {
	X	return;
	X    }
	X    name = bname(n);
	X    birth = fgbirth(n);
	X    death = fgdeath(n);
	X    mar = fgmar(m);
	X    if (i <= 0)
	X    {
	X	addtline(name, b);
	X	if (birth && *birth) 
	X	{
	X	    addtline(birth, b);
	X	}
	X	if (death && *death) 
	X	{
	X	    addtline(death, b);
	X	}
	X	if (i == 0)
	X	{
	X	    if (mar && *mar) 
	X	    {
	X		addtline(mar, b);
	X	    }
	X	    adnotes(n, m, b);		/* add general comment notes */
	X	}
	X	else	/* i== -1 */
	X	{
	X	    adnotes(n, -1, b);		/* don't add marriage notes */
	X	}
	X    }
	X    else
	X    {
	X	if (mar && *mar) 
	X	{
	X	    mar = tprintf("re-%s", mar);
	X	}
	X	else 
	X	{
	X	    mar = "remarried:";
	X	}
	X	addtline(mar, b);
	X	adnotes(-1, m, b);
	X    }
	X}
	X
	X/*..........*/
	X
	Xadnotes(n, m, b)	/* add general comment notes to a block */
	Xint n;			/* index of person */
	Xint m;			/* index of marriage */
	Xstruct tblock *b;	/* text block to add to */
	X{
	X    adnote(n, b, " ");
	X    adnote(m, b, " (m)");
	X}
	X
	X/*..........*/
	X
	Xadnote(n, b, ss)	/* add general comment notes to a block */
	Xint n;			/* index of person */
	Xstruct tblock *b;	/* text block to add to */
	Xchar *ss;		/* note indicator string */
	X{
	Xint i;
	Xchar comnum[10];
	Xchar gencom[1000];
	Xchar *lnotes[1000];
	Xint lcount;
	Xint hlen;
	Xint t;
	X
	X    gencom[0] = 0;		/* clear to start */
	X    lcount = 0;
	X    hlen = strlen(ss) + sizeof("Note") + 2;
	X    for (i = 0; i == 0 || gencom[0]; i++)	/* read each comment */
	X    {
	X	sprintf(comnum,"GEN%d", i);
	X	bstr(n, comnum, gencom);	/* read comment line */
	X	if (gencom[0] == 0) 
	X	{
	X	    break;
	X	}
	X	lnotes[lcount++] = strsav(gencom);
	X    }
	X    if (lcount == 1 && ((t = strlen(lnotes[0]) + hlen) <= b->width || t < LTCOL))
	X    {		/* if we have one relatively short string, do it in-line */
	X	addtline(tprintf("[Note%s: %s]", ss, lnotes[0]), b);
	X    }
	X    else if (lcount > 0)
	X    {
	X	addtline(tprintf("[Note %d%s]", 1 + notenum, ss), b);
	X	notes[notecount++] = tprintf("Note %d%s:", 1 + notenum++, ss);
	X	for (i = 0; i < lcount; i++)
	X	{
	X	    notes[notecount++] = lnotes[i];	/* add string to notes */
	X	    if (notecount >= NOTEMAX -1)
	X	    {
	X		warning("notelist overflow!");
	X		notecount--;
	X	    }
	X	}
	X	notes[notecount++] = "";
	X    }
	X}
	X
	X/*..........*/
	X
	Xaddtline(ss, b)			/* add a line to a tblock */
	Xchar *ss;			/* the string to add */
	Xstruct tblock *b;		/* the block to add to */
	X{
	Xint l;
	X
	X    if (b->lines >= TBLOCKSIZE)
	X    {
	X	warning("tblock overflow!");
	X	return;			/* ignore the addition */
	X    }
	X    b->text[b->lines++] = ss;	/* add in the string */
	X    l = strlen(ss);
	X    if (l > b->width) 
	X    {
	X	b->width = l;	/* keep track of width */
	X    }
	X}
	X
	X/* end */
SHAR_EOF
if test 8136 -ne "`wc -c < 'family.c'`"
then
	echo shar: error transmitting "'family.c'" '(should have been 8136 characters)'
fi
chmod +x 'family.c'
fi # end of overwriting check
echo shar: extracting "'famtree.c'" '(7197 characters)'
if test -f 'famtree.c'
then
	echo shar: will not over-write existing file "'famtree.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'famtree.c'
	X/* famtree - make a family tree */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 08:49:00 by jimmc (Jim McBeath) */
	X/* last edit 10-Sept-85 07:58:00 by tlr (Terry L. Ridder) */
	X
	X/* A family tree is composed of a number of family blocks
	X * connected by lines.  Each family block is a rectangle, with
	X * lines coming out the top and bottom for the father and mother
	X * families, respectively, and one line coming out the right
	X * for the child families.  The family blocks are then placed
	X * in the appropriate positions and connected by extending the
	X * lines.
	X */
	X
	X#include "geneal.h"
	X#include "famtree.h"
	X#include "pagemap.h"
	X
	X#define TRUE 1
	X#define FALSE 0
	X
	XFsqp famgen();
	X
	Xextern struct dpoint *gendp;		/* the datafile index number */
	Xextern int dataStatus;
	Xextern char *dataErrStrs[];
	X
	X/*..........*/
	X
	Xint				/* 0 if OK */
	Xfamtree(n)
	Xint n;				/* index number of the person or family
	X				 to do the tree for */
	X{
	XFsqp fm;
	X
	X    fm = famgen(n);	/* generate this family block and all ancestors */
	X/*    famdump(fm);	/*** dump the info we created */
	X    famgtmp(fm);	/*** output a portion of the tree */
	X    return 0;		/* assume it all went OK! */
	X}
	X
	X/*..........*/
	X
	XFsqp
	Xfamgen(n)		/* generate a family block for person or family n */
	Xint n;
	X{
	XFsqp fm;
	Xchar *rtype;
	Xchar *cstr, *cstr0;
	Xint i;
	Xint individual;		/* set if it is an individual; not set if family */
	Xint nochildren;
	Xint childfound;
	Xint tt, dd;
	X
	X    if (n <= 0) 
	X    {
	X	return 0;
	X    }
	X    fm = XALLOC(Fsq, 1, "famgen");
	X    rtype = fgstr(n, "T");		/* get record type */
	X    if (rtype == 0 || *rtype == 0) 
	X    {
	X	return 0;	/* must have this record! */
	X    }
	X    if (rtype[0] == 'I')		/* if an individual's record */
	X    {
	X	individual = 1;
	X	fm->cnum = n;
	X	fm->pnum = fgnum(n, "P");
	X    }
	X    else
	X    {
	X	individual = 0;		/* not an individual */
	X	fm->cnum = -1;
	X	fm->pnum = n;
	X    }
	X    fm->pname = fgstr(fm->pnum, "N");
	X    fm->fnum = fgnum(fm->pnum, "H");
	X    fm->mnum = fgnum(fm->pnum, "W");
	X    fm->ffamily = famgen(fm->fnum);
	X    fm->mfamily = famgen(fm->mnum);
	X    if (fm->pnum > 0)
	X    {
	X	cstr = getData(gendp, fm->pnum, "C");	/* get child info */
	X	if (cstr == 0 || *cstr == 0 )
	X	{		/*** check for individual here? */
	X	    if (dataStatus == 7)
	X	    {
	X		warning("inconsistent data: person %d claims family %d,\n\
	X		which does not exist!", n, fm->pnum);
	X	    }
	X	    else if (dataStatus == 8)
	X	    {
	X		warning("inconsistent data: person %d claims family %d,\n\
	X		which has no child list!", n, fm->pnum);
	X	    }
	X	    else if (dataStatus == 0)	/* must be strlen(cstr)==0 */
	X	    {
	X		warning("inconsistent data: person %d claims family %d,\n\
	X		which has an empty child list!", n, fm->pnum);
	X	    }
	X	    else
	X	    {
	X		warning("error in getData for family %d: %s",
	X			fm->pnum, dataErrStrs[dataStatus]);
	X	    }
	X	    nochildren = TRUE;
	X	}
	X	else	/* we have a cstr */
	X	{
	X	    for (i = 0, cstr0 = cstr; (cstr0 && *cstr0); i++)
	X	    {
	X		cstr0 = index(cstr0 + 1, ',');
	X		    /* count separators to determine number in list */
	X	    }
	X	    fm->ccount = i;
	X	    fm->clist = XALLOC(int, i, "famgen clist");
	X	    childfound = FALSE;
	X	    for(cstr0 = cstr, i = 0; (cstr0 && *cstr0); i++)
	X	    {
	X		if (i >= fm->ccount) 
	X		{
	X		    fatalerr("loop too far on child list");
	X		}
	X		tt = sscanf(cstr0, "%d", &dd);	/* read child number */
	X		if (tt == 1) 
	X		{
	X		    fm->clist[i] = dd;
	X		}
	X		else
	X		{
	X		    warning("bad child list format in family %d", fm->pnum);
	X		    fm->clist[i] = dd = -1;
	X		}
	X		if (dd == n)
	X		{
	X		    childfound = TRUE;
	X		    fm->chloc = i;	/* remember his position in list */
	X		}
	X		cstr0 = index(cstr0, ',');
	X		if (cstr0 != 0) 
	X		{
	X		    cstr0++;
	X		}
	X	    }
	X	    if (individual && !childfound)
	X	    {
	X		warning("inconsistent data: person %d claims family %d,\n\
	X		but family does not claim child!", n, fm->pnum);
	X	    }
	X	    nochildren = FALSE;
	X	}
	X    }
	X    else nochildren = TRUE;
	X    if (nochildren)
	X    {
	X	fm->ccount = individual? 1 : 0;
	X	fm->clist = XALLOC(int, 1, "famgen clist");
	X	fm->clist[0] = individual? n : 0;
	X	fm->chloc = 0;
	X    }
	X    fm->cnlist = XALLOC(char *, fm->ccount, "famtree cnlist");
	X    fm->cblist = XALLOC(char *, fm->ccount, "famtree cblist");
	X    fm->cols = 0;
	X    for (i = 0; i < fm->ccount; i++)	/* fill in child info */
	X    {
	X	fm->cnlist[i] = tname(fm->clist[i]); /* get names */
	X	fm->cblist[i] = fgbegend(fm->clist[i]); /* get date info */
	X	if ((tt = strlen(fm->cnlist[i])) > fm->cols) 
	X	{
	X	    fm->cols = tt;
	X	}
	X	if ((tt = strlen(fm->cblist[i])) > fm->cols) 
	X	{
	X	    fm->cols = tt;
	X	}
	X		/* keep track of longest name */
	X    }
	X    if (strlen(fm->pname) > 2*fm->ccount) 
	X    {
	X	fm->lines = strlen(fm->pname);
	X    }
	X    else 
	X    {
	X	fm->lines = 2*fm->ccount;
	X	/* there must be enough lines for both the vertical family name
	X		and the list of children (2 lines per child) */
	X    }
	X    fm->acolmax = fm->cols;
	X    fm->alines = 0;
	X    fm->agens = 0;
	X    if (fm->ffamily)
	X    {
	X	if (fm->ffamily->acolmax > fm->acolmax)
	X	{
	X	    fm->acolmax = fm->ffamily->acolmax;
	X	}
	X	if (fm->ffamily->agens+1 > fm->agens)
	X	{
	X	    fm->agens = fm->ffamily->agens + 1;
	X	}
	X	fm->alines += fm->ffamily->alines;
	X    }
	X    if (fm->mfamily)
	X    {
	X	if (fm->mfamily->acolmax > fm->acolmax)
	X	{
	X	    fm->acolmax = fm->mfamily->acolmax;
	X 	}
	X	if (fm->mfamily->agens + 1 > fm->agens)
	X	{
	X	    fm->agens = fm->mfamily->agens + 1;
	X	}
	X	fm->alines += fm->mfamily->alines;
	X    }
	X    if (fm->lines > fm->alines) 
	X    {
	X	fm->alines = fm->lines;
	X    }
	X/*** still need to calculate chline */
	X    fm->chline = 0;	/***/
	X    return fm;
	X}
	X
	X/*..........*/
	X
	Xfamdump(fm)		/* dump tree info */
	XFsqp fm;
	X{
	Xint i;
	X
	X    if (fm == 0) 
	X    {
	X	return;
	X    }
	X    printf("Family at %X: \"%s\", ", fm, fm->pname);
	X    printf("P=%d, F=%d, M=%d, C=%d, ",
	X	fm->pnum, fm->fnum, fm->mnum, fm->cnum);
	X    printf("ccount=%d, clist=%X:\n", fm->ccount, fm->clist);
	X    for (i = 0; i < fm->ccount; i++) printf("%2d \"%s\" %s\n",
	X	fm->clist[i], fm->cnlist[i], fm->cblist[i]);
	X    {
	X    	printf("lines=%d, cols=%d, chloc=%d, agens=%d, \
	X	alines=%d, acolmax=%d, chline=%d;\n",
	X	fm->lines, fm->cols, fm->chloc, fm->agens,
	X	fm->alines, fm->acolmax, fm->chline);
	X    }
	X    printf("ffamily=%X, mfamily=%X\n\n", fm->ffamily, fm->mfamily);
	X    famdump(fm->ffamily);
	X    famdump(fm->mfamily);
	X}
	X
	X/*..........*/
	X
	Xfamgtmp(fm)		/* for debugging - output one family in tree form */
	XFsqp fm;
	X{
	XPagemp pp;
	Xint lines, cols;
	Xint i, j, x;
	Xchar *ss;
	X
	X    lines = fm->lines; cols=fm->cols;
	X    pp = pageInit(lines, cols+5);
	X    for (i = 0; i < lines; i++)		/* put in the vertical line */
	X    {
	X	pagePutc(pp, i, 2, '|');
	X    }
	X    x = (lines-strlen(fm->pname))/2;	/* calculate starting position */
	X    for (i = x, ss = fm->pname; *ss; i++, ss++)
	X    {
	X	pagePutc(pp, i, 0, *ss);	/* put family name in vertically */
	X    }
	X    x = (lines - (2*fm->ccount))/2;	/* starting line for children */
	X    for (i = 0; i < fm->ccount; i++)
	X    {
	X	if (i == fm->chloc)		/* if this is the child of interest */
	X	{
	X	    for (j = 4; j < pp->cols; j++)
	X	    {
	X		pagePutc(pp, 2 * i + x, j, '-');
	X		    			/* put in a row of dashes first */
	X	    }
	X	}
	X	pagePuts(pp, 2 * i + x, 4, fm->cnlist[i]);
	X	pagePuts(pp, 2 * i + x + 1, 4, fm->cblist[i]);
	X    }
	X    pagePrint(pp, stdout);		/* output it */
	X}
	X
	X/* end */
SHAR_EOF
if test 7197 -ne "`wc -c < 'famtree.c'`"
then
	echo shar: error transmitting "'famtree.c'" '(should have been 7197 characters)'
fi
chmod +x 'famtree.c'
fi # end of overwriting check
echo shar: extracting "'famtree.h'" '(1410 characters)'
if test -f 'famtree.h'
then
	echo shar: will not over-write existing file "'famtree.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'famtree.h'
	X/* famtree.h - header file for family tree stuff */
	X/* last edit 15-Sep-84 21:05:02 by jimmc (Jim McBeath) */
	X/* last edit 10-Sept-85 08:09:00 by tlr (Terry L. Ridder) */
	X
	Xextern char *xalloc();
	X
	X#define XALLOC(item, count, msg) (item *)xalloc(sizeof(item)*count,msg)
	X
	Xstruct fsq {		/* a family square */
	X    char *pname;	/* name of the family */
	X    int pnum;		/* index number of the parents (marriage) */
	X    int fnum;		/* index number of the father of the family */
	X    int mnum;		/* index number of the mother of the family */
	X    int chloc;		/* where the child of interest lies in child list */
	X    int ccount;		/* number of children in the family */
	X    int *clist;		/* list of child indexes for the family */
	X    char **cnlist;	/* list of names for children */
	X    char **cblist;	/* list of birthdates for children */
	X    int cnum;		/* number of the child with desc. tree */
	X    struct fsq *ffamily;	/* pointer to father's familysq */
	X    struct fsq *mfamily;	/* pointer to mother's familysq */
	X    int lines;		/* number of lines in this square */
	X    int cols;		/* number of cols in this square */
	X    int agens;		/* number of generations previous to this one */
	X    int alines;		/* number of lines for all ancestor families */
	X    int acolmax;	/* max columns for all ancestor families */
	X    int chline;		/* the line where the child tree comes out */
	X    };
	X
	Xtypedef struct fsq Fsq, *Fsqp;
	X
	X/* end */
SHAR_EOF
if test 1410 -ne "`wc -c < 'famtree.h'`"
then
	echo shar: error transmitting "'famtree.h'" '(should have been 1410 characters)'
fi
chmod +x 'famtree.h'
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
	
  ===========================================================================
  | 									    |
  |UUCP:         /--- !neurad--\             /---!wiretap!{root, tlr}	    |
  |UUCP: seismo-<               >---!bilbo--<            		    |
  |UUCP:         \--- !umcp-cs-<     	     \---!{root, tlr}		    |
  | 			        \---!tlr				    |
  | 									    |
  |ARPA: tlr at maryland							    |
  | 									    |
  |U.S.SNAIL: Terry L. Ridder, 401 Cherry Lane E301, Laurel, Maryland 20707 |
  |									    |
  |Ma Bell: Home: 301-490-2248 Work: 301-859-6271 Work: 301-859-6642	    |
  |									    |
  ===========================================================================



More information about the Comp.sources.unix mailing list