Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site umcp-cs.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!umcp-cs!tlr From: tlr@umcp-cs.UUCP (Terry L. Ridder) Newsgroups: net.sources Subject: Geneal (part 2 of 3) (debugged version) Message-ID: <1576@umcp-cs.UUCP> Date: Fri, 13-Sep-85 19:09:49 EDT Article-I.D.: umcp-cs.1576 Posted: Fri Sep 13 19:09:49 1985 Date-Received: Sat, 14-Sep-85 17:24:47 EDT Distribution: net Organization: The Ridder Family Zoo Lines: 1463 #! /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 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 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@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 | | | ===========================================================================