[comp.sources.unix] v18i011: Geneal, a genealogy browsing program, Part01/03

rsalz@uunet.uu.net (Rich Salz) (03/10/89)

Submitted-by: Jim McBeath <voder!sci!gumby!jimmc>
Posting-number: Volume 18, Issue 11
Archive-name: geneal/part01

GENEAL is a genealogy program which can browse data, make individual and
family pages, make birthday and anniversary lists, and (with the help of
the TREEPAR program) make various flavors of family tree plots.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 4)."
# Contents:  History MANIFEST README browse.c dataman.h dates.c
#   datesort.c dlists.c errorman.c famatree.c famdtree.c familyh.c
#   famntree.h geneal.c geneal.h index.h indivs.c pagemap.c pagemap.h
#   strings.c vsprintf.c
# Wrapped by rsalz@fig.bbn.com on Thu Mar  9 15:54:52 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'History' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'History'\"
else
echo shar: Extracting \"'History'\" \(2672 characters\)
sed "s/^X//" >'History' <<'END_OF_FILE'
XSome History of Geneal			 	11.Jan.88
X
XGeneal was originally written in late 1984 and first posted to the net
Xin January, 1985.  It was written on a VAX, and had some problems with
Xportability.  Ian Darwin and Terry Ridder made a number of contributions
Xand suggestions, and a second version was posted in February, 1985.
X
XFor a couple of years after that posting, I spent essentially no time
Xworking with geneal (or on any genealogy research either).  My first
Xson was born that February, and I suddenly had no time for geneal.
X
XIn 1987 I finally found the time to get back to genealogy and my geneal
Xprogram.  During my "absence", I believe Terry Ridder posted some fixes
Xor changes to geneal, but I was not keeping up on things, so I probably
Xdon't have them.  In any case, the present version of geneal has been
Xsubstantially changed, so that point is probably moot.
X
XChanges from version 2.4 of geneal to this version include:
X	The command line interface has been completely changed; it has
X		been replaced by a simple programmable interface implemented
X		with the SPIN package.
X	The memory allocation routines in SPIN are also being used.
X	The dataman file manager now keeps an index file for faster
X		startup.  It also does better error checking when
X		scanning the data file.
X	It is now possible to produce graphical family trees with geneal.
X		There is a command to output a text file in the appropriate
X		format to feed to the treepar program, which does the
X		actual place, route, and plot of the tree.
X	The man page has been completely rewritten.
X	The sample data file is much larger (it contains real data).
X	The use of a counted set of field names for multi-line data
X		(e.g. GEN0, GEN1, etc.) has been replaced by the "+"
X		mechanism for multi-line data.
X	Two new record types have been added (Address and Reference).
X	A number of fields have been added (TNOTE, TGEN, ADDR, BURIED).
X	There are now two formats of family page output.
X	It is now possible to generate sorted birthday and anniversary lists.
X	The output routines now operate on lists of record numbers rather
X		than single record numbers.
X	There is a set of list manipulation routines to assist in generating
X		arbitrarily complex lists for use in generation of family
X		trees, etc.
X	There is a simple set of browsing functions that make it easier
X		to walk around a family tree (although much more could
X		be added here).
X	All files have been linted, and are almost clean (except for
X		'sprintf' and 'end').
X
X
X
XA brief history of geneal:
X20.Jan.85  Version 1 posted to the net.
X15.Feb.85  Version 2.4 posted to the net.
X
XThere are edit histories at the beginning of each individual source file.
END_OF_FILE
if test 2672 -ne `wc -c <'History'`; then
    echo shar: \"'History'\" unpacked with wrong size!
fi
# end of 'History'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1181 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X History                    1	
X MANIFEST                   1	
X Makefile                   2	
X PGMR.DOC                   2	
X README                     1	
X browse.c                   1	
X dataman.c                  3	
X dataman.h                  1	
X dates.c                    1	
X datesort.c                 1	
X dlists.c                   1	
X errorman.c                 1	
X famatree.c                 1	
X famdtree.c                 1	
X family.c                   3	
X familyh.c                  1	
X famlists.c                 2	
X famntree.c                 3	
X famntree.h                 1	
X fgdat.c                    3	
X fgsubs.c                   2	
X gconsist.c                 2	
X geneal.c                   1	
X geneal.h                   1	
X geneal.n                   4	
X index.c                    2	
X index.h                    1	
X indivs.c                   1	
X lists.c                    2	
X misc.c                     2	
X pagemap.c                  1	
X pagemap.h                  1	
X sample.dat                 4	
X strings.c                  1	
X vsprintf.c                 1	
END_OF_FILE
if test 1181 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2621 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThe GENEAL Program				 1.Mar.88
XWritten by Jim McBeath (jimmc) at SCI
X
XThis is version 3.5 of GENEAL.
X
XGENEAL is a genealogy program which can browse data, make individual
Xand family pages, make birthday and anniversary lists, and (with
Xthe help of the TREEPAR program) make various flavors of family tree plots.
X
XThis file describes what other files exist and what you will have to
Xdo in order to make geneal useful to you.
X
XNOTE: Geneal uses the SPIN package (Simple Programmable INterface).  If you
Xdon't have it, you won't be able to build geneal.
X
XFiles of interest:
X    *.[ch]	The source files for geneal.
X    Makefile	Exactly that.
X    README	What you are looking at right now.
X    History	A Brief history of geneal.
X    geneal.n	Source for man page.  Describes (briefly) what
X		geneal is all about.  Gives list of switches.
X		Use "make man" to create geneal man file (geneal.man).
X    PGMR.DOC	Programmer's documentation.  Gives more detail about some
X		of the source files.  Read this if you are going to make
X		any changes to the program or if you need to look for bugs.
X    sample.dat  The data file.  This is a sample file for you to use
X		as a template for creating your own data file.
X
XWhat to do (after unpacking):
X1. Use "make man" to create geneal.man from geneal.n.  Read it.
X2. Edit the Makefile and set SPINDIR to point to the directory containing
X   the spin files (xalloc.h, spin.h, spin.a, llib-lspin.a.ln).
X   By default this is ../spin.
X3. If you are running on something other than sun or bsd, you may have
X   trouble with vsprintf.  You should put -DUSG in the CFLAGS in the
X   Makefile in this case.
X4. Make the program.  You should be able to simply issue a "make" command.
X   If you wish, you can test it out at this point on the sample data file
X   and make sure that it works.  (You will have to do a
X   "setenv GENEALDAT sample.dat" to do this.)
X5. Make your own data file.  Delete all of the supplied data file except
X   record 0 (the description of the data format).  Add your own data in
X   the same format.
X6. Run geneal and execute the GConsist command to check for data consistency
X   errors.  After correcting all errors uncovered here, you should
X   be able to run the other portions of the program without errors.
X7. If you want to make changes, read PGMR.DOC first.
X8. Send me your comments, wishes, and improvements.
X
XGeneal was originally written to run on a VAX under BSD4.2.  It has
Xsince been moved to run on a SUN3 under Sun OS3.4.  If you have
Xproblems running on other systems, please let me know.
X
X		-Jim McBeath  {decwrl|oliveb|weitek|auspyr}!sci!jimmc
X		  1.Mar.1988
END_OF_FILE
if test 2621 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'browse.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'browse.c'\"
else
echo shar: Extracting \"'browse.c'\" \(1954 characters\)
sed "s/^X//" >'browse.c' <<'END_OF_FILE'
X/* browse.c - functions to simplify browsing through the tree
X *
X * 18.Aug.87  jimmc  Initial definition
X *  8.Jan.88  jimmc  Lint cleanup
X */
X
X#include <stdio.h>
X#include "geneal.h"
X
Xint CurrentID;
X
Xstatic
Xprintandfree(s)
Xchar *s;
X{
X	printf("%s\n",s);
X	freestr(s);
X}
X
Xstatic
XprintIndiv(id)
Xint id;
X{
Xint cnt, *slist;
Xint i;
X
X	printandfree(fgbname(id));
X	printandfree(fgbrtdeath(id));
X	cnt = fgslist(id,&slist);
X	if (cnt>0) printf("Marriages:\n");
X	for (i=0; i<cnt; i++) {
X		printf("[%d] ",slist[i]);
X		printandfree(fgmarriage(slist[i]));
X	}
X	if (cnt) free((char *)slist);
X}
X
Xstatic
XprintFamily(id)
Xint id;
X{
Xint hid,wid;
Xint cnt, *clist;
Xint i;
X
X	printf("Family [%d] ",id);
X	printandfree(fgmarriage(id));
X	hid = fgnum(id,"H");
X	if (hid>0) printandfree(fgbname(hid));
X	wid = fgnum(id,"W");
X	if (wid>0) printandfree(fgbname(wid));
X	cnt = fgclist(id,&clist);
X	if (cnt>0) printf("Children:\n");
X	for (i=0; i<cnt; i++) {
X		printf("  ");
X		printandfree(fgbname(clist[i]));
X	}
X	if (cnt) free((char *)clist);
X}
X
Xstatic
XprintCurrent(id)
Xint id;
X{
Xint oldflag;
X
X	CurrentID = id;
X	oldflag = Gflag['n'];
X	Gflag['n'] = 1;
X	switch (fgtype(id)) {
X	case 'I':
X		printIndiv(id);
X		break;
X	case 'F':
X		printFamily(id);
X		break;
X	default:
X		printf("bad type code for record %d\n",id);
X		break;
X	}
X	Gflag['n'] = oldflag;
X}
X
XTCurrent(id)
Xint id;
X{
X	if (id<=0) id=CurrentID;
X	if (id<=0) return 0;
X	printCurrent(id);
X	return id;
X}
X
XTFamily(id)
Xint id;
X{
Xint t;
X
X	if (id<=0) id=CurrentID;
X	t = fgnum(id,"P");	/* get parent record */
X	if (t<=0) return 0;
X	printCurrent(t);
X	return t;
X}
X
XTFather(id)
Xint id;
X{
Xint t;
X
X	if (id<=0) id=CurrentID;
X	if (fgtype(id)=='I') id=fgnum(id,"P");
X	if (id<=0) return 0;
X	t = fgnum(id,"H");
X	if (t<=0) return 0;
X	printCurrent(t);
X	return t;
X}
X
XTMother(id)
Xint id;
X{
Xint t;
X
X	if (id<=0) id=CurrentID;
X	if (fgtype(id)=='I') id=fgnum(id,"P");
X	if (id<=0) return 0;
X	t = fgnum(id,"W");
X	if (t<=0) return 0;
X	printCurrent(t);
X	return t;
X}
X
X/* end */
END_OF_FILE
if test 1954 -ne `wc -c <'browse.c'`; then
    echo shar: \"'browse.c'\" unpacked with wrong size!
fi
# end of 'browse.c'
fi
if test -f 'dataman.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dataman.h'\"
else
echo shar: Extracting \"'dataman.h'\" \(719 characters\)
sed "s/^X//" >'dataman.h' <<'END_OF_FILE'
X/* dataman.h - include file for dataman structures */
X/* Written by Jim McBeath (jimmc) at SCI */
X/* last edit 24-Jan-85 08:02:52 by jimmc (Jim McBeath) */
X/* Revision history:
X * 24-Jan-85	Jim McBeath	remove from dataman.c to create dataman.h
X */
X
X/* stdio must be included before this file is included */
X
X#ifndef DATAMANH	/* safe for double inclusions */
X#define DATAMANH
X
Xstruct dpoint {
X    FILE *ff;		/* which data file to read */
X    struct toplevel *xx;		/* pointer for index routine */
X    };
X
Xstruct drecord {
X    int numfields;	/* number of name/value pairs */
X    char **name;	/* array of pointers to name strings */
X    char **value;	/* array of pointers to value strings */
X};
X
X#endif DATAMANH
X
X/* end */
END_OF_FILE
if test 719 -ne `wc -c <'dataman.h'`; then
    echo shar: \"'dataman.h'\" unpacked with wrong size!
fi
# end of 'dataman.h'
fi
if test -f 'dates.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dates.c'\"
else
echo shar: Extracting \"'dates.c'\" \(3621 characters\)
sed "s/^X//" >'dates.c' <<'END_OF_FILE'
X/* dates.c - some date manipulation routines
X *
X *  4.Jan.88  jimmc  Initial definition
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <strings.h>
X#include "geneal.h"
X
Xstruct {
X	char *sname;
X	char *lname;
X} montab[] = {
X	{ "???", "???" },
X	{ "Jan", "January" },
X	{ "Feb", "February" },
X	{ "Mar", "March" },
X	{ "Apr", "April" },
X	{ "May", "May" },
X	{ "Jun", "June" },
X	{ "Jul", "July" },
X	{ "Aug", "August" },
X	{ "Sep", "September" },
X	{ "Oct", "October" },
X	{ "Nov", "November" },
X	{ "Dec", "December" },
X};
Xint montabsize = sizeof(montab)/sizeof(montab[0]);
X
Xint		/* returns 1 to 12 for a month, 0 if not found */
Xfindmonth(sname)
Xchar *sname;
X{
X	int i;
X
X	for (i=1; i<montabsize; i++) {
X		if (strcmp(sname,montab[i].sname)==0)
X			return i;
X	}
X	return 0;	/* not found */
X}
X
Xint			/* (year*10000) + (month(jan==1)*100 + day(1-based) */
X			/* or -1 if it can't make the conversion */
Xsdatetoint(olddate)	/*    for example, decimal 18760123 */
Xchar *olddate;		/* in format "23-Jan-1876" */
X{
X	char *dash1, *dash2;
X	int day, month, year;
X	int n;
X
X	if (!olddate || !olddate[0]) return -1;	/* nothing to convert */
X	dash1 = index(olddate,'-');
X	if (dash1) {
X		dash2 = index(dash1+1,'-');
X		if (dash2) {	/* all three of day, month, year given */
X			if (strlen(dash2)!=sizeof("-1876")-1 ||
X			    (dash2-dash1)!=sizeof("-Jan")-1 ||
X			    (dash1-olddate>2)) {
X				goto badformat;
X			}
X			day = atoi(olddate);
X			year = atoi(dash2+1);
X			*dash2 = 0;
X			month = findmonth(dash1+1);
X			*dash2 = '-';
X		}
X		else {	/* only two of day, month, year given */
X			if (isdigit(olddate[0])) {	/* day given */
X				if (dash1-olddate>2)
X					goto badformat;
X				day = atoi(olddate);
X				if (isdigit(dash1[1])) { /* year given */
X					if (strlen(dash1)!=sizeof("-1876")-1)
X						goto badformat;
X					year = atoi(dash1+1);
X					month = 0;
X				}
X				else {
X					if (strlen(dash1)!=sizeof("-Jan")-1)
X						goto badformat;
X					year = 0;
X					month = findmonth(dash1+1);
X				}
X			}
X			else {	/* must be month and year */
X				if (strlen(dash1)!=sizeof("-1876")-1
X				    || (dash1-olddate!=sizeof("Jan")-1))
X					goto badformat;
X				day = 0;
X				year = atoi(dash1+1);
X				*dash1 = 0;
X				month = findmonth(olddate);
X				*dash1 = '-';
X			}
X		}
X	}
X	else {		/* only one of day, month, year given */
X		if (isdigit(olddate[0])) {
X			n = atoi(olddate);
X			if (n>=32) {	/* assume no years before 100 */
X				if (strlen(olddate)!=sizeof("1876")-1)
X					goto badformat;
X				year = n;
X				day = 0;
X			}
X			else {
X				if (strlen(olddate)<2)
X					goto badformat;
X				year = n;
X				year = 0;
X				day = n;
X			}
X			month = 0;
X		}
X		else {		/* not a digit, must be a month */
X			if (strlen(olddate)!=sizeof("Jan")-1)
X				goto badformat;
X			month = findmonth(olddate);
X			year = 0;
X			day = 0;
X		}
X	}
X	return year*10000 + month*100 + day;
X
Xbadformat:
X	return -1;	/* don't understand it */
X}
X
Xchar *
Xconvertidate(cnvdate)
Xint cnvdate;
X{
X	int year, month, day;
X	char tbuf[100];
X
X	year = cnvdate/10000;
X	month = cnvdate/100 - year*100;
X	day = cnvdate - month*100 - year*10000;
X
X	tbuf[0] = 0;
X	if (month)
X		sprintf(tbuf,"%s",montab[month].lname);
X	if (day) {
X		if (tbuf[0])
X			strcat(tbuf," ");
X		sprintf(tbuf+strlen(tbuf),"%d",day);
X	}
X	if (year) {
X		if (tbuf[0])
X			strcat(tbuf,", ");
X		sprintf(tbuf+strlen(tbuf),"%d",year);
X	}
X	return strsav(tbuf);
X}
X
Xchar *			/* allocated string in format "January 23, 1876" */
Xconvertsdate(olddate)
Xchar *olddate;		/* in format "23-Jan-1876" */
X{
X	int cnvdate;
X
X	cnvdate = sdatetoint(olddate);
X	if (cnvdate<=0)
X		return strsav(olddate);
X			/* can't figure it out, use what's there */
X	return convertidate(cnvdate);
X}
X
X/* end */
END_OF_FILE
if test 3621 -ne `wc -c <'dates.c'`; then
    echo shar: \"'dates.c'\" unpacked with wrong size!
fi
# end of 'dates.c'
fi
if test -f 'datesort.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'datesort.c'\"
else
echo shar: Extracting \"'datesort.c'\" \(1869 characters\)
sed "s/^X//" >'datesort.c' <<'END_OF_FILE'
X/* datesort.c - routines dealing with sorting of dates
X *
X *  4.Jan.1988  jimmc  Initial definition
X */
X
X#include <stdio.h>
X#include "xalloc.h"
X#include "geneal.h"
X
Xtypedef struct _dsortinfo {
X	char *sdate;
X	int idate;
X	char *pstr;
X} Dsortinfo;
X
XDsortinfo *dsortinf;
Xint dsortalloc;
Xint dsortcount;
X
Xdsortinit()	/* init the sorting routine */
X{
X	Dsortinfo *p;
X	int i;
X
X	for (i=0; i<dsortcount; i++) {
X		p = dsortinf + i;
X		freestr(p->sdate);
X	}
X	dsortcount = 0;
X}
X
Xdsortadd(sdate,pstr)
Xchar *sdate;		/* the date to be sorted, in short format */
Xchar *pstr;		/* the extra pointer to keep with the date */
X{
X	Dsortinfo *p;
X
X	if (dsortcount>=dsortalloc) {	/* need more space */
X		if (dsortalloc) dsortalloc *= 2;
X		else dsortalloc = 15;
X		if (dsortinf)
X			dsortinf = XREALLOC(Dsortinfo,dsortinf,dsortalloc);
X		else
X			dsortinf = XALLOC(Dsortinfo,dsortalloc);
X	}
X	p = dsortinf+dsortcount;
X	p->sdate = sdate;
X	p->idate = sdatetoint(sdate);
X	p->pstr = pstr;
X	dsortcount++;
X}
X
Xdsortadds(sdate,pstr)
Xchar *sdate;
Xchar *pstr;
X{
X	dsortadd(strsav(sdate),strsav(pstr));
X}
X
Xint
Xdsortsort(a,b)
XDsortinfo *a, *b;
X{
X	if (Gflag['y'])		/* include year in date sorts */
X		return a->idate - b->idate;
X	else
X		return (a->idate%10000) - (b->idate%10000);
X}
X
Xint			/* returns 0 if no errors, else value of funcp() */
Xdsortenum(funcp)	/* enumerate the sorted list */
Xint (*funcp)();		/* function to call for each item */
X		/* the function is called as funcp(sdate,pstr,idate) */
X		/* if the function returns non-zero, the enumeration stops */
X{
X	Dsortinfo *p;
X	int i,t;
X
X	if (dsortcount<=0) return 0;
X	qsort((char *)dsortinf,dsortcount,sizeof(Dsortinfo),dsortsort);
X	for (i=0; i<dsortcount; i++) {
X		p = dsortinf+i;
X		t = (*funcp)(p->sdate,p->pstr,p->idate);
X		if (t) break;
X	}
X	for (i=0; i<dsortcount; i++) {
X		p = dsortinf+i;
X		freestr(p->sdate);
X	}
X	dsortcount = 0;
X	return t;
X}
X
X/* end */
END_OF_FILE
if test 1869 -ne `wc -c <'datesort.c'`; then
    echo shar: \"'datesort.c'\" unpacked with wrong size!
fi
# end of 'datesort.c'
fi
if test -f 'dlists.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dlists.c'\"
else
echo shar: Extracting \"'dlists.c'\" \(1202 characters\)
sed "s/^X//" >'dlists.c' <<'END_OF_FILE'
X/* dlists.c - generate date lists for various things
X *
X *  4.Jan.88  jimmc  Initial definition
X */
X
X#include <stdio.h>
X#include "geneal.h"
X
Xextern char *convertidate();
X
Xint
Xbdlist1(sdate,name,idate)
Xchar *sdate;
Xchar *name;
Xint idate;
X{
X	char *cnvdate;
X
X	if (idate>0)
X		cnvdate = convertidate(idate);
X	else
X		cnvdate = sdate;
X	fprintf(outfp,"    %-24s%s\n", cnvdate, name);
X	return 0;
X}
X
Xint
Xbdlist(idcount,idlist)
Xint idcount;		/* number of entries in idlist */
Xint *idlist;		/* array of id numbesr */
X{
X	int i;
X	char *bdate, *name;
X
X	dsortinit();
X	for (i=0; i<idcount; i++) {
X		bdate = fgstr(idlist[i],"B");
X		name = fgfname(idlist[i]);
X		if (bdate&&bdate[0] || name&&name[0])
X			dsortadd(bdate,name);
X	}
X
X	fprintf(outfp,"                     BIRTHDAYS\n\n");
X	dsortenum(bdlist1);
X}
X
Xint
Xannlist(idcount,idlist)
Xint idcount;		/* number of entries in idlist */
Xint *idlist;		/* array of id numbesr */
X{
X	int i;
X	char *bdate, *name;
X
X	dsortinit();
X	for (i=0; i<idcount; i++) {
X		bdate = fgstr(idlist[i],"M");
X		name = fglpname(idlist[i]);
X		if (bdate&&bdate[0] || name&&name[0])
X			dsortadd(bdate,name);
X	}
X
X	fprintf(outfp,"                     ANNIVERSARIES\n\n");
X	dsortenum(bdlist1);
X}
X
X/* end */
END_OF_FILE
if test 1202 -ne `wc -c <'dlists.c'`; then
    echo shar: \"'dlists.c'\" unpacked with wrong size!
fi
# end of 'dlists.c'
fi
if test -f 'errorman.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'errorman.c'\"
else
echo shar: Extracting \"'errorman.c'\" \(1256 characters\)
sed "s/^X//" >'errorman.c' <<'END_OF_FILE'
X/* errorman.c - general error handling routines
X * Written by Jim McBeath (jimmc) at SCI
X *
X * To use these routines, the user must have the variable Progname declared
X * elsewhere; also, these routines call vsprintf, so that must be included
X * in the load list.
X *
X *  8.Jan.88  jimmc  Lint cleanup
X */
X
X#include <stdio.h>
X#include <strings.h>
X
X#define ERROR_EXIT 1
X#define BSIZE 200
X
Xextern char *Progname;		/* user must set up the progname to use */
X
X/*..........*/
X
X/* VARARGS1 */
Xwarning(s,args)
Xchar *s;
X{
Xchar buf[BSIZE];
X
X    vsprintf(buf,s,&args);
X    fprintf(stderr,"%s: warning: %s\n", Progname, buf);
X}
X
X/*..........*/
X/* hack... */
Xfferror(s) char *s; {fatalerr(s);}
X
X/* VARARGS1 */
Xfatalerr(s,args)
Xchar *s;
X{
Xchar buf[BSIZE];
X
X    vsprintf(buf,s,&args);
X    fprintf(stderr,"%s: fatal error: %s\n", Progname, buf);
X    exit(ERROR_EXIT);
X}
X
X/*..........*/
X
X/* VARARGS1 */
Xfatalperr(s,args)
Xchar *s;
X{
Xchar buf[BSIZE];
Xchar buf2[BSIZE];
X
X    vsprintf(buf,s,&args);
X    sprintf(buf2,"%s: fatal error: %s: ", Progname, buf);
X    perror(buf2);
X    exit(ERROR_EXIT);
X}
X
X/*..........*/
X
X/* VARARGS1 */
Xerrormsg(s,args)
Xchar *s;
X{
Xchar buf[BSIZE];
X
X    (void)vsprintf(buf,s,&args);
X    fprintf(stderr,"%s: error: %s\n", Progname, buf);
X}
X
X/* end */
END_OF_FILE
if test 1256 -ne `wc -c <'errorman.c'`; then
    echo shar: \"'errorman.c'\" unpacked with wrong size!
fi
# end of 'errorman.c'
fi
if test -f 'famatree.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'famatree.c'\"
else
echo shar: Extracting \"'famatree.c'\" \(3552 characters\)
sed "s/^X//" >'famatree.c' <<'END_OF_FILE'
X/* famatree.c - simple ancestor tree generator
X * Written by Jim McBeath (jimmc) at SCI
X *
X * Revision history:
X * 27-Jan-85	Jim McBeath	Initial defintion
X *  8-Mar-85	Jim McBeath	add return 0 in famatrr
X * 26.Oct.87  jimmc  A little cleanup
X *  8.Jan.88  jimmc  Direct output to outfp instead of stdout
X */
X
X#include <stdio.h>
X#include "geneal.h"
X
X#define NOLINE 0	/* don't draw any line from this person */
X#define LINEUP 1	/* draw a line up from this person */
X#define LINEDN 2	/* draw a line down from this person */
X#define INDENTOFFSET 3	/* distance each generation is offset */
X#define LINEOFFSET (INDENTOFFSET-2)	/* distance to a line */
X
Xextern char Gflag[];
X
Xint lines[1000];	/* column number to draw lines in */
Xint linecount;		/* number of entries in lines */
X
Xint		/* 0 means OK */
Xfamatree(n)
Xint n;		/* the person to make the tree for */
X{
X	char *ss;
X
X	if (fgtype(n)!='I') {
X		warning("record %d is not an individual", n);
X		return 1;
X	}
X	ss = fgbname(n);
X	strup(ss);
X	fprintf(outfp,"Ancestor tree for %s\n\n", ss);
X	linecount = 0;
X	return famatrr(n,0,NOLINE);		/* use recursive routine */
X}
X
X/*..........*/
X
Xint			/* 0 means OK */
Xfamatrr(n,indent,lineflag)	/* recursive tree printer */
Xint n;			/* the person to print the tree for */
Xint indent;		/* indentation for this person */
Xint lineflag;		/* flag to indicate a line from this person */
X{
X	int pp, ff, mm;
X	int i;
X	int ccount, clist[1000], cflag;
X
X	pp = fgnum(n,"P");	/* get parents */
X	if (pp>0) {
X		ff = fgnum(pp,"H");		/* get father */
X		if (ff>0) {	/* print father and ancestors */
X			if (lineflag==LINEUP)
X				lines[linecount++] = indent+LINEOFFSET;
X			famatrr(ff,indent+INDENTOFFSET,LINEDN);
X			if (lineflag==LINEUP) linecount--;
X		}
X	}
X	if (Gflag['s']>1 && pp>0) {
X			/* if he wants siblings and we have them... */
X		ccount = fgbclist(pp,clist);	/* get a child list */
X		cflag= -1;
X		for (i=0; i<ccount; i++) {
X			if (clist[i]==n) cflag=0;
X			famatrp(clist[i],indent,lineflag,cflag);
X			if (clist[i]==n) cflag=1;
X		}
X	}
X	else {
X		famatrp(n,indent,lineflag,0);
X		/* print up info for this person */
X	}
X	if (pp>0) {
X		mm = fgnum(pp,"W");		/* get mother */
X		if (mm>0) {	/* print mother and ancestors */
X			if (lineflag==LINEDN)
X				lines[linecount++] = indent+LINEOFFSET;
X			famatrr(mm,indent+INDENTOFFSET,LINEUP);
X			if (lineflag==LINEDN) linecount--;
X		}
X	}
X	return 0;	/* we have no error counter, so always return OK */
X}
X
X/*..........*/
X
Xfamatrp(n,indent,lineflag,cflag)
Xint n;			/* the person of interest */
Xint indent;		/* indent level */
Xint lineflag;		/* flags to tell how to draw lines */
Xint cflag;		/* flag to indicate lines for siblings */
X/* -1 means we are above the sibling in the ancestry */
X/* 0 means this is the sibling in the ancestry */
X/* 1 means we are below th sibling in the ancestry */
X{
X	int i;
X	int lastl;
X	char *ss, *bd;
X	char *xstr;
X
X	lastl = 0;	/* adjust the left/right position by changing this */
X	for (i=0; i<linecount; i++) {		/* put in the extra lines */
X		fprintf(outfp,"%*s|", lines[i]-lastl-1, "");
X		lastl = lines[i];
X	}
X	fprintf(outfp,"%*s", indent-lastl, "");
X	ss = fgbname(n);
X	bd = fgbrtdeath(n);
X	if (lineflag==NOLINE) {
X		if (cflag==0) xstr="*-";
X		else if (cflag== 1) xstr = " '";
X		else xstr = " ,";
X	}
X	else if (lineflag==LINEUP) {
X		if (cflag==0) xstr="\\-";
X		else if (cflag== -1) xstr="|,";
X		else xstr=" '";
X	}
X	else {	/* must be lineflag==LINEDN */
X		if (cflag==0) xstr="/-";
X		else if (cflag== 1) xstr="|'";
X		else xstr=" ,";
X	}
X	fprintf(outfp,"%s%s%s\n", xstr, ss, bd);
X		/* print info for this person */
X}
X
X/* end */
END_OF_FILE
if test 3552 -ne `wc -c <'famatree.c'`; then
    echo shar: \"'famatree.c'\" unpacked with wrong size!
fi
# end of 'famatree.c'
fi
if test -f 'famdtree.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'famdtree.c'\"
else
echo shar: Extracting \"'famdtree.c'\" \(2309 characters\)
sed "s/^X//" >'famdtree.c' <<'END_OF_FILE'
X/* famdtree.c - produce descendant trees
X * Written by Jim McBeath (jimmc) at SCI
X *
X * Revision history:
X * 27-Jan-85	Jim McBeath	Initial definition
X * 14-Feb-85	(Ian Darwin)	return error counter e instead of 0
X * 26.Oct.87  jimmc  Just a little cleaning up
X *  8.Jan.88  jimmc  Direct output to outfp instead of stdout
X */
X
X#include <stdio.h>
X#include "geneal.h"
X#include "ctype.h"
X
X#define INDENTOFFSET 4	/* how far each generation is offset */
X
Xint		/* 0 means OK */
Xfamdtree(n)
Xint n;		/* the person to do a tree for */
X{
X	char *ss;
X	char buf[1000];
X	int t;
X
X	switch ((t=fgtype(n))) {
X	case 'I':
X		ss = fgbname(n);
X		strup(ss);		/* make it upper case */
X		fprintf(outfp,"Descendant tree for %s\n\n", ss);
X		break;
X	case 'F':
X		fgbstr(n,"N",buf);
X		strup(buf);
X		fprintf(outfp,"Descendant tree for family %s\n\n", buf);
X		break;
X	default:
X		warning("bad record type %c for dtree\n", t);
X		return 1;	/* error */
X	}
X	return famdtrr(n,0);	/* use recursive routine */
X}
X
X/*..........*/
X
Xint
Xfamdtrr(n,indent)	/* recursive descendant routine */
Xint n;			/* the person or family to do */
Xint indent;		/* the indentation for this level */
X{
X	char buf[200];
X	int ccount, clist[1000];
X	int e;		/* error count */
X	int i;
X	char *ss, *bd, *md;
X	int snum;
X
X	e = 0;
X	fgbstr(n,"T",buf);
X	if (strcmp(buf,"F")==0) {	/* if a family */
X		ccount = fgbclist(n,clist);	/* get list of children */
X		for (i=0; i<ccount; i++)
X			e += famdtrr(clist[i],indent);
X	}
X	else if (strcmp(buf,"I")==0) {	/* if an individual */
X		ss = fgbname(n);	/* get his name */
X		bd = fgbrtdeath(n);	/* and vital dates */
X		fprintf(outfp,"%*s%s%s\n", indent, "", ss, bd );
X		ccount = fgbslist(n,clist);	/* get list of marriages */
X		for (i=0; i<ccount; i++) {	/* for each marriage */
X			snum = fgnum(clist[i],"H");
X			if (snum==n) snum = fgnum(clist[i],"W"); /* spouse */
X			ss = fgbname(snum);	/* name of spouse */
X			if (ss==0 || ss[0]==0) ss = "???";
X			bd = fgbrtdeath(snum);
X			if (bd==0) bd="";
X			md = fgstr(clist[i],"M");	/* date of marriage */
X			if (md==0) md="";
X			fprintf(outfp,"%*s m: %s to %s%s\n",
X				indent, "", md, ss, bd);
X			e += famdtrr(clist[i],indent+INDENTOFFSET);
X				/* do the family */
X		}
X	}
X	else {
X		warning("bad record type \"%s\" in record %d", buf, n);
X		e++;		/* this counts as an error */
X	}
X	return e;
X}
X
X/* end */
END_OF_FILE
if test 2309 -ne `wc -c <'famdtree.c'`; then
    echo shar: \"'famdtree.c'\" unpacked with wrong size!
fi
# end of 'famdtree.c'
fi
if test -f 'familyh.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'familyh.c'\"
else
echo shar: Extracting \"'familyh.c'\" \(3973 characters\)
sed "s/^X//" >'familyh.c' <<'END_OF_FILE'
X/* familyh.c - a more horizontal style of family page
X *
X *  4.Jan.88  jimmc  Initial definition
X *  8.Jan.88  jimmc  Allow lists of families to be printed
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <strings.h>
X#include "geneal.h"
X
X#define TITLECOL 24
X#define NAMECOL 4
X#define COLFMT "    %-30s %-18s %s\n"
X
Xextern char *convertsdate();
X
Xint			/* 0 if OK */
Xfamilyh(ac,av)
Xint ac;
Xint *av;
X{
X	int i,t;
X
X	t = 0;
X	for (i=0; i<ac; i++) {
X		if (i>0) fprintf(outfp,sepstr);
X		t += familyh1(av[i]);
X	}
X	return t;
X}
X
Xint			/* 0 if OK */
Xfamilyh1(famnum)
Xint famnum;			/* the family to give info about */
X{
X	int rtype;
X	char *famname;
X	int addrnum;
X	char *addr, *phone, *gen;
X	char mbuf[200];
X	char *mdate, *mplace;
X	int i, cnum, clist[1000];
X
X	rtype = fgtype(famnum);
X	if (rtype<=0) {
X		warning("no such record number %d", famnum);
X		return 1;
X	}
X	if (rtype!='F') {
X		warning("record %d is not a family", famnum);
X		return 1;
X	}
X
X	famname = fglhname(famnum);
X	strup(famname);
X	printindented(TITLECOL,famname);
X	addrnum = fgnum(famnum,"ADDR");
X	if (Gflag['a'] && addrnum>0) {	/* print address if known */
X		addr = fgstr(addrnum,"ADDR");
X		printindented(TITLECOL,addr);
X		phone = fgstr(addrnum,"PHONE");
X		printindented(TITLECOL,phone);
X	}
X	fprintf(outfp,"\n\n\n");
X
X	fprintf(outfp,COLFMT,"NAME","BIRTHDATE","BIRTHPLACE");
X	fprintf(outfp,COLFMT,"----","---------","----------");
X	fprintf(outfp,"\n");
X
X	famhp(fgnum(famnum,"H"),"");	/* print info about husband */
X
X	mdate = fgstr(famnum,"M");
X	mplace = fgstr(famnum,"MP");
X	strcpy(mbuf,"MARRIED ");
X	if (Gflag['n'])
X		sprintf(mbuf+strlen(mbuf),"[%d] ",famnum);
X	if (mdate && mdate[0])
X		sprintf(mbuf+strlen(mbuf),"%s ",convertsdate(mdate));
X	if (mplace && mplace[0])
X		sprintf(mbuf+strlen(mbuf),"at %s ",mplace);
X	strcat(mbuf,"to\n");
X	printindented(NAMECOL,mbuf);
X
X	famhp(fgnum(famnum,"W"),"N");
X
X	gen = fggen(famnum);
X	if (gen && gen[0]) {
X		printindented(NAMECOL,gen);
X		fprintf(outfp,"\n");
X	}
X
X	fprintf(outfp,"\n");
X
X	cnum = fgbclist(famnum,clist);
X	if (cnum==0) {
X		;	/* do nothing here if no children */
X	}
X	else {
X		printindented(NAMECOL,"Born to this union:\n");
X		for (i=0; i<cnum; i++) {
X			famhp(clist[i],"S");
X			fprintf(outfp,"\n");
X		}
X	}
X	return 0;
X}
X
Xfamhp(n,mflags)
Xint n;			/* individual to print info about */
Xchar *mflags;		/* mode flags */
X{
X	char *name, *bdate, *bplace;
X	char *deathdate, *deathplace, *buried, *gen;
X	int scount, slist[1000];
X	int mnum, mgnum, spnum;
X	char *spname;
X	char *mdate, *mplace;
X	char sbuf[1000];
X
X	if (index(mflags,'N'))	/* include last name */
X		name = fgbname(n);
X	else
X		name = fgtname(n);
X	bdate = fgstr(n,"B");
X	bplace = fgstr(n,"BP");
X	deathdate = fgstr(n,"D");
X	deathplace = fgstr(n,"DP");
X	buried = fgstr(n,"BUR");
X	gen = fggen(n);
X	fprintf(outfp,COLFMT,name,convertsdate(bdate),bplace);
X	if (index(mflags,'S')) {	/* do spouse info */
X		scount = fgbslist(n,slist);
X		for (mnum=0; mnum<scount; mnum++) {
X			mgnum = slist[mnum];
X			spnum = fgspouse(mgnum,n);
X			spname = fgbname(spnum);
X			if (!spname || !spname[0]) spname="??";
X			mdate = fgstr(mgnum,"M");
X			mplace = fgstr(mgnum,"MP");
X			strcpy(sbuf,"Married ");
X			if (Gflag['n'])
X				sprintf(sbuf+strlen(sbuf),"[%d] ",mgnum);
X			if (mdate && mdate[0])
X				sprintf(sbuf+strlen(sbuf),"%s ",
X					convertsdate(mdate));
X			sprintf(sbuf+strlen(sbuf),"to %s",spname);
X			if (mplace && mplace[0])
X				sprintf(sbuf+strlen(sbuf)," at %s",mplace);
X			strcat(sbuf,".");
X			printindented(NAMECOL,sbuf);
X		}
X	}
X	if ((deathdate&&deathdate[0])||(deathplace&&deathplace[0])) {
X		strcpy(sbuf,"Deceased ");
X		if (deathdate&&deathdate[0])
X			sprintf(sbuf+strlen(sbuf),"%s ",
X				convertsdate(deathdate));
X		if (deathplace&&deathplace[0])
X			sprintf(sbuf+strlen(sbuf),"at %s",deathplace);
X		strcat(sbuf,".");
X		printindented(NAMECOL,sbuf);
X	}
X	if (buried && buried[0]) {
X		sprintf(sbuf,"Buried at %s.", buried);
X		printindented(NAMECOL,sbuf);
X	}
X	if (gen && gen[0]) printindented(NAMECOL,gen);
X	fprintf(outfp,"\n");
X}
X
X/* end */
END_OF_FILE
if test 3973 -ne `wc -c <'familyh.c'`; then
    echo shar: \"'familyh.c'\" unpacked with wrong size!
fi
# end of 'familyh.c'
fi
if test -f 'famntree.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'famntree.h'\"
else
echo shar: Extracting \"'famntree.h'\" \(2567 characters\)
sed "s/^X//" >'famntree.h' <<'END_OF_FILE'
X/* famntree.h - header file for famntree.c
X *
X * 12.Aug.87  jimmc  Initial definition
X * 31.Aug.87  jimmc  Add bd2, marr, headerlines
X *  8.Sep.87  jimmc  Add tnote
X * 18.Sep.87  jimmc  Moved XALLOC into xalloc.h; add addr in Famninfo
X * 21.Sep.87  jimmc  Use info[] instead of separate char* fields
X */
X
Xtypedef struct _Fammemspouse {	/* one spouse for an individual */
X	int id;		/* spouse id */
X	int mid;	/* marriage (family) id */
X#define FS_MD 0		/* marriage date/place */
X#define FS_MTNOTE 1	/* a tnote on the marriage */
X#define FS_NAME 2	/* spouse name */
X#define FS_BD 3		/* birthdate */
X#define FS_BD2 4	/* more bd stuff */
X#define FS_BUR 5	/* buried */
X#define FS_TNOTE 6	/* a tnote on the spouse */
X#define FSSIZE 7	/* number of info items for a spouse record */
X	char *info[FSSIZE];	/* info per above defines */
X	int lines;	/* number of lines of text for this spouse */
X	int cols;		/* number of cols in this fs */
X	int connx;	/* position of connector for this spouse */
X} Fammemspouse;
X
Xtypedef struct _Fammember {	/* one individual */
X	int id;		/* member id */
X#define FM_NAME 0	/* member name */
X#define FM_BD 1		/* birthdate/place */
X#define FM_BD2 2	/* more bd stuff */
X#define FM_BUR 3	/* buried */
X#define FM_TNOTE 4	/* a tnote on the member */
X#define FMSIZE 5
X	char *info[FMSIZE];	/* info per above defines */
X	int headerlines;	/* number of lines in the header part */
X	int lines;	/* total number of lines of text for this member */
X	int cols;		/* number of cols in this fm */
X	int connx;	/* x position of connector for this member */
X	int scount;	/* number of spouse entries */
X	Fammemspouse *slist;	/* pointer to array of spouse entries */
X} Fammember;
X
Xtypedef struct _Famninfo {	/* a family or individual in a box */
X	char *boxname;		/* for labeling and for connectors */
X	int famid;		/* family id, even if box for individual */
X	int fatherid;		/* id for father of that family */
X	int motherid;		/* id for mother of that family */
X#define FI_NAME 0	/* family name */
X#define FI_MARR 1	/* marriage info */
X#define FI_TNOTE 2	/* a tnote on the family */
X#define FI_ADDR 3	/* address/phone for the family */
X#define FISIZE 4	/* number of info items for a family info record */
X	char *info[FISIZE];	/* info per above defines */
X	int namelen;		/* length of name */
X	int headerlines;	/* number of lines in the header part */
X	int lines;		/* number of lines in this square */
X	int cols;		/* number of cols in this square */
X	int mcount;		/* number of members in this box */
X	Fammember *mlist;	/* pointer to array of members */
X} Famninfo;
X
X/* end */
END_OF_FILE
if test 2567 -ne `wc -c <'famntree.h'`; then
    echo shar: \"'famntree.h'\" unpacked with wrong size!
fi
# end of 'famntree.h'
fi
if test -f 'geneal.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'geneal.c'\"
else
echo shar: Extracting \"'geneal.c'\" \(4576 characters\)
sed "s/^X//" >'geneal.c' <<'END_OF_FILE'
X/* geneal - manipulate family trees, etc.
X * Written by Jim McBeath (jimmc) at SCI
X *
X * Revision history:
X * 24-Jan-85	Jim McBeath	Use real dpoint instead of int for gendp.
X *				Add -C switch for consistency check.
X * v2.0 27-Jan-85 Jim McBeath	Add -a, -d, -V switches; add version string;
X *				add GENEALDAT environment var. check.
X * v2.1 29-Jan-85 Jim McBeath	7-char-distinct names
X * v2.2  2-Feb-85 Jim McBeath	Adopt the .A convention for adopted items.
X * v2.3 12-Feb-85 Jim McBeath	Include usage line in help message; change
X *				default filename to geneal.dat (suggestions
X *				of Ian Darwin)
X * v2.4  8-Mar-85 Jim McBeath	minor fixes in other modules
X * v2.5  2.Aug.87  jimmc  Modify -t switch to be suitable for famtree program
X * v2.6 13.Aug.87  jimmc  Add -T switch
X * v3.0 17.Aug.87  jimmc  Convert to genie interface
X * v3.1 28.Aug.87  jimmc  Add GENEALLABEL check
X * v3.2 17.Oct.87  jimmc  Convert to spin interface
X *      27.Oct.87  jimmc  Add outfp
X * v3.3  4.Jan.88  jimmc  Add Pfamilyh, PBDlist, PAnnlist, LRange, LAll,
X *				LFieldMatch, LRefs
X * v3.4  8.Jan.88  jimmc  Add GSetOutput, GGetOutput, GFlushOutput; modify
X *				remaining P output routines to output to outfp;
X *				add GSetSep, GGetSep; modify fampage output
X *				routines to accept list of id numbers;
X *				lint cleanup
X *      18.Jan.88  jimmc  Make LAnc, LDesc take input list args, plus limit
X *      19.Jan.88  jimmc  Clean up data file access stuff
X * v3.5  1.Mar.88  jimmc  Make GVersion return a string instead of printing it
X */
Xchar *genealVersion="geneal v3.5 1-Mar-88";
X
X#define MAIN
X
X#include <stdio.h>
X#include <ctype.h>
X#include "spin.h"
X#include "geneal.h"
X
Xextern char *rindex(), *getenv();
Xextern char *getData();
X
Xextern char *Label;
X
Xchar *Progname;		/* name of the program */
Xchar *defdatfile="geneal.dat";	/* default datafile name */
Xchar *gendatfile=0;	/* filename for data file */
XFILE *outfp=stdout;	/* stream to output to */
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
Xchar *estr;
Xchar *s;
Xint i,j;
Xchar *execval=NULL;
X
X	Progname = rindex(argv[0],'/');
X	if (Progname) Progname++; else Progname=argv[0];
X
X	if (!gendatfile)	/* if he didn't specify a file... */
X	{
X		estr = getenv("GENEALDAT"); /* look for data file */
X		if (estr && *estr) gendatfile=estr;
X		else gendatfile=defdatfile;
X	}
X	fgsetfn(gendatfile);
X
X	s = getenv("GENEALLABEL");
X	if (s) Label = strsav(s);
X
X	sepstr = strsav("\f");	/* default separator string */
X	GSetOutput("stdout");
X
X	applinit();
X	SPinitsubs();
X
X	for (i=1; i<argc; i++) {
X		if (argv[i][0]=='-') for (j=1; j>0 && argv[i][j]; j++) {
X			switch (argv[i][j]) {
X			case 'e':	/* execute */
X				if (argv[i][++j]) execval = argv[i]+j;
X				else if (++i<argc) execval = argv[i];
X				else fatalerr("not enough args for -e");
X				j = -1;
X				break;
X			default:
X				fatalerr("unknown switch %c", argv[i][j]);
X			}
X		}
X		else {	/* not a switch */
X			fatalerr("unknown argument %s", argv[i]);
X		}
X	}
X
X	if (execval) { SPmainstring(execval); }
X	SPmainfile(stdin);
X	exit(0);
X}
X
X/*
X * arg types are:
X * i - integer
X * s - string
X * f - float (double)
X * L - application list
X */
X
X#define BB(name,func,args) { \
X	extern func(); \
X	SPdeffunc("name",args,func); \
X}
X
X#define B(name,args) BB(name,name,args)
X
X#define BBS(name,func,args) { \
X	extern char *func(); \
X	SPdeffunc("name",args,func); \
X}
X
X#define BS(name,args) BBS(name,name,args)
X
X#define BBL(name,func,args) { \
X	extern SPtoken *func(); \
X	SPdeffunc("name",args,func); \
X}
X
X#define BL(name,args) BBL(name,name,args)
X
Xapplinit()
X{
X/* routines to output data pages */
XBB(PFamily,gfamily,"iV");
XBB(PFamilyh,gfamilyh,"iV");	/* alternate format family page */
XBB(PF,gfamily,"iV");	/* an alias */
XBB(PIndiv,gindivs,"iV");
XBB(PI,gindivs,"iV");	/* an alias */
XBB(P,GPfi,"iV");		/* useful for browsing */
XBB(PAtree,famatree,"ii");
XBB(PDtree,famdtree,"ii");
XBB(PFamtree,gfamntree,"iV");
XBB(PBDlist,gbdlist,"iV");
XBB(PAnnlist,gannlist,"iV");
X
X/* DB dependent list generation and manipulation routines */
XBL(LAll,"L");
XBL(LAnc,"LVI-1");
XBL(LDesc,"LVI-1");
XBL(LRefs,"LVs");
XBL(LFieldMatch,"LVss");
X
X/* DB independent list manipulation routines */
XBL(LRange,"Lii");
XBL(LUnion,"LVV");
XBL(LIntersect,"LVV");
XBL(LAndNot,"LVV");
X
X/* browsing commands */
XB(TCurrent,"iI0");
XB(TFamily,"iI0");
XB(TFather,"iI0");
XB(TMother,"iI0");
X
X/* miscellaneous routines */
XBS(GFlags,"ss");
XB(GSetLabel,"vs");
XBS(GGetLabel,"s");
XBS(GVersion,"s");
XB(GSetOutput,"is");
XBS(GGetOutput,"s");
XB(GFlushOutput,"v");
XB(GSetSep,"vs");
XBS(GGetSep,"s");
XBB(GConsist,gconsist,"i");
X
X/* for debugging */
XBBS(fgstr,fgstr,"sis");
X}
X
X/* end */
END_OF_FILE
if test 4576 -ne `wc -c <'geneal.c'`; then
    echo shar: \"'geneal.c'\" unpacked with wrong size!
fi
# end of 'geneal.c'
fi
if test -f 'geneal.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'geneal.h'\"
else
echo shar: Extracting \"'geneal.h'\" \(1330 characters\)
sed "s/^X//" >'geneal.h' <<'END_OF_FILE'
X/* geneal.h - general include stuff for geneal modules
X * Written by Jim McBeath (jimmc) at SCI
X *
X * Revision history:
X * 24-Jan-85	Jim McBeath	use dpoint instead of int for gendp
X * 17.Aug.87  jimmc  Add reference to fglname
X * 18.Aug.87  jimmc  Add Group structure
X *  8.Sep.87  jimmc  Add fgtnote
X * 18.Sep.87  jimmc  Add fgaddrphn
X * 27.Oct.87  jimmc  Add fggen, outfp
X *  1.Jan.88  jimmc  Add fglpname
X *  4.Jan.88  jimmc  Add fglhname
X *  8.Jan.88  jimmc  Add sepstr
X * 19.Jan.88  jimmc  Remove dpoint/gendp stuff
X */
X
X/* global variables */
Xextern char Gflag[];		/* various mode and debug flags */
Xextern FILE *outfp;	/* the stream to outputo */
Xextern char *sepstr;	/* separator string between info pages */
X
X/* declare functions */
Xchar *index();
X
Xchar *getData();
Xchar *strsav();
Xchar *tprintf();
X
Xchar *fgstr();
Xchar *fgtname();
Xchar *fglname();
Xchar *fglpname();
Xchar *fglhname();
Xchar *fgbname();
Xchar *fgfname();
Xchar *fgbirth();
Xchar *fgdeath();
Xchar *fgburied();
Xchar *fgbrtdeath();
Xchar *fgmarriage();
Xchar *fgnmarriage();
Xchar *fgtnote();
Xchar *fggen();
Xchar *fgaddrphn();
X
X/* a structure for lists of id numbers */
Xtypedef struct _group {
X	int count;	/* number of used entries in the array */
X	int alloc;	/* size of the array (number of entries) */
X	int *n;		/* pointer to array of ints */
X} Group;
X
X/* end */
END_OF_FILE
if test 1330 -ne `wc -c <'geneal.h'`; then
    echo shar: \"'geneal.h'\" unpacked with wrong size!
fi
# end of 'geneal.h'
fi
if test -f 'index.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'index.h'\"
else
echo shar: Extracting \"'index.h'\" \(698 characters\)
sed "s/^X//" >'index.h' <<'END_OF_FILE'
X/* index.h - definitions for index
X * Written by Jim McBeath (jimmc) at SCI
X *
X * 19.Jan.85  jimmc  previous last edit
X *  8.Jan.88  jimmc  Use a union for tdata
X */
X
X#define TBLSIZ 100
X
Xstruct tblblock {
X	int repnum;		/* number of indexes represented by this blk */
X	int count;		/* count of entries in this level */
X	union {
X		long n;		/* integer values at the leaves */
X		struct tblblock *p;	/* or else pointers to more blocks */
X	} tdata[TBLSIZ];	/* the actual data for this level */
X};
X
Xstruct toplevel {
X	int numlevs;		/* how deep the table is at it's deepest */
X	struct tblblock *data;	/* pointer to the top level */
X	int nzcount;		/* number of non-zero entries in the table */
X};
X
X/* end */
END_OF_FILE
if test 698 -ne `wc -c <'index.h'`; then
    echo shar: \"'index.h'\" unpacked with wrong size!
fi
# end of 'index.h'
fi
if test -f 'indivs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'indivs.c'\"
else
echo shar: Extracting \"'indivs.c'\" \(4098 characters\)
sed "s/^X//" >'indivs.c' <<'END_OF_FILE'
X/* indivs.v - print out short form info about an individual
X * Written by Jim McBeath (jimmc) at SCI
X *
X * Revision history:
X * 24-Jan-85	Jim McBeath	add include stdio
X * 27-Jan-85	Jim McBeath	use fgbslist
X * 18.Aug.87  jimmc  Use Gflag instead in indexes flag
X * 25.Aug.87  jimmc  Add buried info
X * 27.Oct.87  jimmc  General cleanup; call fggen to get GEN
X *  8.Jan.88  jimmc  Lint cleanup
X */
X
X#include <stdio.h>
X#include "geneal.h"
X#include "xalloc.h"
X
Xint			/* 0 if OK */
Xindivs(ac,av)
Xint ac;
Xint *av;
X{
X	int i,t;
X
X	t = 0;
X	for (i=0; i<ac; i++) {
X		if (i>0) fprintf(outfp,sepstr);
X		t += indivs1(av[i]);
X	}
X	return t;
X}
X
Xint			/* 0 if OK */
Xindivs1(n)
Xint n;			/* the person's ID number */
X{
X	char *ss;
X	int pnum;	/* parent family number */
X	int fnum;	/* father's number */
X	int mnum;	/* mother's number */
X	int mgnum;	/* marriage number */
X	int snum;	/* spouse's number */
X	int mhnum, mwnum;
X	int i;		/* loop counter */
X	int t;		/* random numbers and status */
X	char *spousestr;
X	int scount, slist[1000];
X	char *gen;
X
X	t = fgtype(n);
X	if (t!='I') {
X		warning("id %d is not an individual");
X		return 1;
X	}
X	ss = fgfname(n);
X	fprintf(outfp,"Name: %s\n", ss);
X	ss = fgbirth(n);
X	if (ss && *ss) fprintf(outfp,"%s\n", ss);
X	ss = fgdeath(n);
X	if (ss && *ss) fprintf(outfp,"%s\n", ss);
X	ss = fgburied(n);
X	if (ss && *ss) fprintf(outfp,"%s\n", ss);
X	pnum = fgnum(n,"P");	/* get number of parent family */
X	if (pnum>0) {			/* if we got a family */
X		if (Gflag['n']) fprintf(outfp,"Parent family: %d\n", pnum);
X		fnum = fgnum(pnum,"H");
X		if (fnum>=0) {
X			ss = fgfname(fnum);
X			fprintf(outfp,"  Father: %s\n", ss);
X			ss = fgbrtdeath(fnum);
X			if (ss && *ss) fprintf(outfp,"  %s\n", ss);
X		}
X		mnum = fgnum(pnum,"W");
X		if (mnum>=0) {
X			ss = fgfname(mnum);
X			fprintf(outfp,"  Mother: %s\n", ss);
X			ss = fgbrtdeath(mnum);
X			if (ss && *ss) fprintf(outfp,"  %s\n", ss);
X		}
X		ss = fgmarriage(pnum);
X		if (ss) fprintf(outfp,"Parent's marriage: %s\n", ss);
X		doiclist(pnum,"Sibling","Siblings",n);	/* do the siblings */
X	}
X	else {	/* no parent in this record */
X		if (Gflag['n']) fprintf(outfp,"No parent family specified\n");
X	}
X	scount = fgbslist(n,slist);
X	for (i=0; i<scount; i++) {	/* look at marriages */
X		mgnum = slist[i];
X		if (Gflag['n']) fprintf(outfp,"Marriage %d: %d\n", i, mgnum);
X		mhnum = fgnum(mgnum,"H");	/* are we the husband? */
X		mwnum = fgnum(mgnum,"W");	/*  or the wife */
X		if (n!=mhnum && n!= mwnum)
Xwarning("person %d claims marriage %d, but not vice-versa",
X			    n, mgnum);
X		if (n==mhnum) {
X			snum = mwnum;
X			spousestr = "Wife";
X		}
X		else {
X			snum = mhnum;
X			spousestr = "Husband";
X		}
X		if (snum>0) {
X			ss = fgbname(snum);
X			fprintf(outfp," %s: %s\n", spousestr, ss);
X			ss = fgbrtdeath(snum);
X			if (ss && *ss) fprintf(outfp," %s\n", ss);
X		}
X		ss = fgmarriage(mgnum);
X		if (ss && *ss) fprintf(outfp," %s\n", ss);
X		doiclist(mgnum,"Child","Children",-1);
X	}
X	gen = fggen(mgnum);
X	if (gen && *gen) fprintf(outfp,"General:\n%s\n",gen);
X	if (gen) XFREE(gen);
X	return 0;			/* finished it all OK */
X}
X
X/*..........*/
X
Xdoiclist(pnum,c1,cm,xn)		/* print out info about children */
Xint pnum;			/* the family to deal with */
Xchar *c1;			/* string to use if one child */
Xchar *cm;			/* string to use if more than one child */
Xint xn;		/* number of special sibling, or -1 if none */
X{
X	int i;
X	int t;
X	char *ss;
X	int *clist;
X	int cflag=0;
X
X	t = fgclist(pnum,&clist);	/* get list of kids */
X	if (t==0) {
X		if (Gflag['n']) fprintf(outfp,"No %s specified\n", cm);
X		if (xn>0)
Xwarning("person %d claims parents %d but not vice-versa", xn, pnum);
X	}
X	else {
X		if (t==1) fprintf(outfp,"  1 %s:\n",c1);
X		else fprintf(outfp,"  %d %s:\n",t,cm);
X		for (i=0; i<t; i++) {	/* for each child */
X			if (clist[i]==xn) cflag++;
X				/* note found special sibling */
X			if (Gflag['n']) fprintf(outfp,"  %s %d:", c1, i);
X			ss = fgtname(clist[i]);
X			fprintf(outfp,"  %s%s\n",(clist[i]==xn?"*":""),ss);
X			ss = fgbrtdeath(clist[i]);
X			if (ss&&*ss) fprintf(outfp,"  %s\n", ss);
X		}
X		if (xn>0 && cflag==0)
Xwarning("person %d claims parents %d but not vice-versa", xn, pnum);
X	}
X}
X
X/* end */
END_OF_FILE
if test 4098 -ne `wc -c <'indivs.c'`; then
    echo shar: \"'indivs.c'\" unpacked with wrong size!
fi
# end of 'indivs.c'
fi
if test -f 'pagemap.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pagemap.c'\"
else
echo shar: Extracting \"'pagemap.c'\" \(2321 characters\)
sed "s/^X//" >'pagemap.c' <<'END_OF_FILE'
X/* pagemap - functions to manipulate a page of character data
X * Written by Jim McBeath (jimmc) at SCI
X * last edit 29-Jan-85 07:17:11 by jimmc (Jim McBeath)
X * Revision history:
X * 29-Jan-85	Jim McBeath	convert to 7-char-distinct names
X *  2.Aug.87  jimmc  Add pageQPrint()
X * 18.Sep.87  jimmc  add #include xalloc.h
X */
X
X#include "pagemap.h"
X#include "xalloc.h"
X#include <stdio.h>
X
XPagemp
XpageInit(r,c)		/* make a new page of data */
Xint r,c;		/* rows an columns desired in the page */
X{
XPagemp pp;
Xint i, j;
Xchar *ss;
X
X    pp = XALLOCM(Pagem,1,"pageInit");	/* get the top level structure */
X    pp->rows = r;
X    pp->cols = c;		/* put in his numbers */
X    pp->data = XALLOCM(char *,r,"pageInit rowpointers");
X    for (i=0; i<r; i++)
X    {
X	pp->data[i] = ss = XALLOCM(char,c+2,"pageInit data");
X	for (j=0; j<=c; j++) ss[j]=' ';		/* fill with spaces */
X	ss[c+1] = 0;		/* null terminated */
X    }
X    return pp;			/* return the pointer to him */
X}
X
X/*..........*/
X
XpagPuts(pp,r,c,ss)
XPagemp pp;
Xint r,c;
Xchar *ss;
X{
Xchar *dd;
Xint n;
X
X    dd = &pp->data[r][c];		/* where to put it */
X    n = strlen(ss);			/* number of chars to move */
X    if (pp->cols - c < n) n = pp->cols - c;	/* don't run off page */
X    for ( ; n>0; n--) *(dd++) = *(ss++);	/* transfer string */
X}
X
X/*..........*/
X
XpagePrint(pp,f)		/* output the page */
XPagemp pp;		/* pointer to the page to output */
XFILE *f;		/* stream to output to */
X{
X	pageLPrint(pp,f,"\n");
X	fputc('\n',f);
X}
X
XpageQPrint(pp,f)		/* output the page as a quoted string */
XPagemp pp;		/* pointer to the page to output */
XFILE *f;		/* stream to output to */
X{
X	fputc('"',f);
X	pageLPrint(pp,f,"\\n\\\n");
X	fputc('"',f);
X}
X
XpageLPrint(pp,f,linesep)		/* output the page */
XPagemp pp;		/* pointer to the page to output */
XFILE *f;		/* stream to output to */
Xchar *linesep;		/* what to print between each line */
X{
Xint r,c;
Xint lastline;
Xchar *ss;
X
X    lastline = -1;
X    for (r=0; r<pp->rows; r++)	/* for each row */
X    {
X	ss = pp->data[r];		/* faster access */
X	for (c=pp->cols+1; c>=0; c--)
X	    if (ss[c]>' ') break;	/* strip trailing spaces and nulls */
X	ss[++c] = 0;			/* make it null terminated */
X	if (c>0) lastline=r;		/* remember where the last line is */
X    }
X    for (r=0; r<=lastline; r++)		/* now output the lines */
X	fprintf(f,"%s%s",pp->data[r],linesep);
X}
X
X/* end */
END_OF_FILE
if test 2321 -ne `wc -c <'pagemap.c'`; then
    echo shar: \"'pagemap.c'\" unpacked with wrong size!
fi
# end of 'pagemap.c'
fi
if test -f 'pagemap.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pagemap.h'\"
else
echo shar: Extracting \"'pagemap.h'\" \(918 characters\)
sed "s/^X//" >'pagemap.h' <<'END_OF_FILE'
X/* pagemap.h - definition for the pagemap functions
X * last edit 29-Jan-85 07:18:22 by jimmc (Jim McBeath)
X *
X * 29-Jan-85	Jim McBeath	convert to 7-char-distinct names
X * 18.Sep.87  jimmc  Move XALLOC into xalloc.h
X */
X
Xstruct pagem {
X	int rows;		/* number of rows (lines) on the page */
X	int cols;		/* number of columns on the page */
X	char **data;	/* pointer to an array of char pointers */
X};
X
Xtypedef struct pagem Pagem, *Pagemp;
X
X/* data is stored in row major order; given the data pointer from the
X * above structure, data[x] points to row x, and data[x][y] points to
X * character y in row x.
X *
X * The number of columns is actually greater by two than the number
X * x->cols indicates; this is to leave space for a newline and a null
X * at the end.
X */
X
X/* access macros */
X#define pagPutc(pp,r,c,ch) ((pp)->data[r][c] = (ch))
X#define pagGetc(pp,r,c)    ((pp)->data[r][c])
X
Xextern Pagemp pageInit();
X
X/* end */
END_OF_FILE
if test 918 -ne `wc -c <'pagemap.h'`; then
    echo shar: \"'pagemap.h'\" unpacked with wrong size!
fi
# end of 'pagemap.h'
fi
if test -f 'strings.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strings.c'\"
else
echo shar: Extracting \"'strings.c'\" \(1806 characters\)
sed "s/^X//" >'strings.c' <<'END_OF_FILE'
X/* strings.c - some string manipulation routines
X *
X *  3.Feb.85  jimmc  Previous last edit
X * 26.Oct.87  jimmc  Collect numerous small routines into strings.c
X *  1.Jan.88  jimmc  Add freestr
X *  8.Jan.88  jimmc  Lint cleanup
X */
X
X#include <ctype.h>
X#include <strings.h>
X#include "xalloc.h"
X
Xextern char end[];	/* for freestr */
X
X/* Since index and rindex appear to be only in bsd4.2, these functions
X * will have to be distributed to assure portability.
X */
Xchar *
Xindex(str,ch)
Xchar *str;		/* string to look through */
Xchar ch;		/* char to look for */
X{
X	for ( ; *str; str++)
X		if (*str==ch) return str;
X	return 0;		/* not found */
X}
X
Xchar *
Xrindex(str,ch)
Xchar *str;
Xchar ch;
X{
X	char *ss;
X
X	for (ss = str+strlen(str)-1; ss>=str; ss--)
X		if (*str==ch) return ss;
X	return 0;
X}
X
Xchar *
Xstrcrep(str,cs,cd)	/* replace specified chars in a string */
Xchar *str;
Xchar cs;		/* char to look for */
Xchar cd;		/* char to replace it with */
X{
X	char *ss;
X
X	for (ss=str; *ss; ss++)
X		if (*ss == cs) *ss = cd;
X	return str;
X}
X
X/* strsav - make a copy of a string and return a pointer to it */
Xchar *
Xstrsav(ss)
Xchar *ss;
X{
X	char *dd;
X
X	dd = XALLOCM(char,strlen(ss)+1,"strsav");
X	strcpy(dd,ss);		/* make a copy of the string */
X	return dd;			/* return the copy */
X}
X
Xstrup(ss)		/* make a string all upper case */
Xchar *ss;
X{
X	for ( ; *ss; ss++)
X		if (islower(*ss)) *ss = toupper(*ss);
X}
X
X/* tprintf - do a printf into a temp buffer, then make a copy of the
X * string and return a pointer to the copy */
X/* VARARGS1 */
Xchar *
Xtprintf(fmt,args)
Xchar *fmt;
X{
X	char buf[2050];
X
X	vsprintf(buf,fmt,&args);	/* printf the string */
X	return strsav(buf);		/* return a copy */
X}
X
X/* freestr - free up a string, but not if it's in program space or stack */
Xfreestr(s)
Xchar *s;
X{
X	if (s>=end && s<(char *)&s)
X		free(s);
X}
X
X/* end */
END_OF_FILE
if test 1806 -ne `wc -c <'strings.c'`; then
    echo shar: \"'strings.c'\" unpacked with wrong size!
fi
# end of 'strings.c'
fi
if test -f 'vsprintf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vsprintf.c'\"
else
echo shar: Extracting \"'vsprintf.c'\" \(1732 characters\)
sed "s/^X//" >'vsprintf.c' <<'END_OF_FILE'
X/* @(#)sprintf.c	4.1 (Berkeley) 12/21/80 */
X/* vsprintf from sprintf */
X/* Created from bsd4.1 unix sprintf by Jim McBeath (jimmc) at SCI */
X/* last edit 8-Jan-1988 16:31:45 by jimmc () */
X
X#ifndef sun	/* sun now provides vsprintf as a standard function */
X
X#include	<stdio.h>
X
X/* vsprintf is like sprintf, but instead of passing a list of arguments,
X * the address of the list is passed.  This is typically used to implement
X * a function which accepts a format string and list of arguments of
X * its own.
X */
X
X#ifndef USG
X/* This ifdef should really be #ifdef BSD4_2, but that symbol doesn't exist!
X * If you are using USG, you should add -DUSG to the makefile.  If you are
X * using some other system in which _doprnt does not quite work like the one
X * in BSD4.2, you should change this line to #if 0.
X */
X
X/* VARARGS2 */
Xchar *vsprintf(str, fmt, argv)
Xchar *str, *fmt;
X{
X	struct _iobuf _strbuf;
X
X	_strbuf._flag = _IOWRT+_IOSTRG;
X#ifdef sun
X	_strbuf._ptr = (unsigned char *)str;
X#else
X	_strbuf._ptr = str;
X#endif
X	_strbuf._cnt = 32767;
X	_doprnt(fmt, argv, &_strbuf);
X	putc('\0', &_strbuf);
X	return(str);
X}
X
X#else USG
X
X/* this version of vsprintf is limited to a certain number of arguments,
X * and is still machine-dependant. (There is also an extermely slight
X * possibility of accessing non-existant memory on machines that grow the stack
X * upwards. (comments from Jim McBeath; routine by Ian Darwin.)
X
X/* VARARGS2 */
Xchar *vsprintf(str, fmt, argv)
Xchar *str, *fmt;
Xchar	**argv;
X{
X	sprintf(str, fmt,
X	    argv[0], argv[1], argv[2], argv[3], argv[4]); /* up to 5 args */
X		/* quasi-portable?? */
X	return(str);
X}
X
X#endif USG
X
X#else sun
X#ifndef lint
Xstatic char dummy;	/* prevent "empty file" error messages */
X#endif
X#endif sun
END_OF_FILE
if test 1732 -ne `wc -c <'vsprintf.c'`; then
    echo shar: \"'vsprintf.c'\" unpacked with wrong size!
fi
# end of 'vsprintf.c'
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.