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