[net.sources] geneal- a family tree program

tlr@umcp-cs.UUCP (Terry L. Ridder) (09/01/85)

	
	I have been using this family tree package which was posted
	to the net a long time ago. The software was originally
	written to run on a VAX, and required alot of changes to
	port it to smaller machines. I have it running on two
	68000 based Unix machines. I have received permission from 
	the author to post my version of the program.

	The original author, is Jim McBeath of Silicon Compilers Inc..
	The program is named 'geneal'.

	Enjoy the program, and trace your roots.

	Those of you how pull this off and use it, please let me
	know. I have various improvements in the works and as 
	soon as they are finished and tested I will send you them.
	
	Any comments, complaints, gripes, and etc. send to me.
	Any suggestions for improvements send to both myself
	and Jim McBeath. Jim's email address is below.

	UUCP:seismo!turtlevax!sci!jimmc

	Terry L. Ridder
	(The Dutchman)

  =====================don't=cut=me=i=am=just=a=signature=file===============
  | 									    |
  |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	    |
  |									    |
  ===========================================================================

=======cut-here====no=cut-here=======no-cut-here=======no-cut-there==========
#! /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:
#	CHANGES
#	Makefile
#	README
#	dataman.c
#	errorman.c
#	famgetdat.c
#	family.1003
#	family.c
#	famtree.c
#	famtree.h
#	gbrowse.c
#	geneal.c
#	geneal.h
#	geneal.l
#	geneal.man
#	genealogy.dat
#	index.c
#	index.h
#	indivs.c
#	pagemap.c
#	pagemap.h
#	pgmr.doc
#	pgmr.man
#	strsav.c
#	tprintf.c
#	vsprintf.c
#	xalloc.c
# This archive created: Sat Aug 31 14:44:43 1985
# By:	Terry L. Ridder (The Terry L. Ridder family)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'CHANGES'" '(3283 characters)'
if test -f 'CHANGES'
then
	echo shar: will not over-write existing file "'CHANGES'"
else
sed 's/^	X//' << \SHAR_EOF > 'CHANGES'
	X	Changes made by Terry L. Ridder
	X
	X	The original file GENEAL.DOC was rewritten into a manual page
	X	, which is now called geneal.l (l = local). The file geneal.man
	X	is the result of the cmd 'nroff -man geneal.l > geneal.man'
	X
	X	The original file PGMR.DOC was rewritten into a nroff file using
	X	ms macros. The file is now called pgmr.doc. The file pgmr.man
	X	is the result of the cmd 'nroff -ms pgmr.doc > pgmr.man'.
	X	
	X	All files are now in the style that I normally use in C programs.
	X
	X	i.e. if (expression)	for (expression)	while (expression)
	X	     {			{			{
	X		....		    .....		    ....
	X	     }			}			}
	X 
	X
	X	     if (expression)
	X	     {
	X		....
	X	     }
	X	     else		where '....' is any number of statements.
	X	     {
	X		....
	X	     }
	X
	X	Changes made by Terry L. Ridder 
	X
	X	Original Variable Name			Changed to
	X	======================			==========
	X	ac					argc
	X	ar					argv
	X
	X	chusbandnum				chisnum
	X	cwifenum				chernum
	X
	X	husbandlname				hislname
	X	husbandname				hisname
	X	husbandnum				hisnum
	X
	X	marriagenum				marnum
	X
	X	wifelname				herlname
	X	wifename				hername
	X	wifenum					hernum
	X
	X	spousenum				sonum 
	X	spousestr				sostr
	X
	X	famgetbirth()				fgbirth()
	X	famgetbirthdeath()			fgbegend()
	X	famgetbname()				bname()
	X	famgetbstr()				bstr()
	X	famgetclist()				fgclist()
	X	famgetfname()				fname()
	X	famgetmarriage()			fgmar()
	X	famgetnum()				fgnum()
	X	famgetstr(0				fgstr()
	X	famgettname()				tname()
	X	
	X	Files Changed				What Changed
	X	=============			==================================
	X	famgetdat.c			famgetbstr()       ->   bstr()
	X	famgetdat.c			famgetbirth()	   ->	fgbirth()
	X	famgetdat.c			famgetbirthdeath() ->	fgbegend()
	X	famgetdat.c			famgetbname()	   ->	bname()
	X	famgetdat.c			famgetbstr()	   ->	bstr()
	X	famgetdat.c			famgetclist()	   ->	fgclist()
	X	famgetdat.c			famgetfname()	   ->	fname()
	X	famgetdat.c			famgetmarriage()   ->	fgmar()
	X	famgetdat.c			famgetnum()	   ->	fgnum()
	X	famgetdat.c			famgetstr(0	   ->	fgstr()
	X	famgetdat.c			famgettname()	   ->	tname()
	X
	X	family.c			famgetbstr()       ->   bstr()
	X	family.c			famgetbirth()	   ->	fgbirth()
	X	family.c			famgetbname()	   ->	bname()
	X	family.c			famgetclist()	   ->	fgclist()
	X	family.c			famgetmarriage()   ->	fgmar()
	X	family.c			famgetnum()	   ->	fgnum()
	X	family.c			famgetstr(0	   ->	fgstr()
	X	family.c			chusbandnum	   ->	chisnum
	X	family.c			cwifenum	   ->	chernum
	X	family.c			husbandlname	   ->	hislname
	X	family.c			husbandname	   ->	hisname
	X	family.c			husbandnum	   ->	hisnum
	X	family.c			marriagenum	   ->	marnum
	X	family.c			wifelname	   ->	herlname
	X	family.c			wifename	   ->	hername
	X	family.c			wifenum		   ->	hernum
	X	family.c			spousenum	   ->	sonum 
	X	family.c			spousestr	   ->	sostr
	X
	X
	X	famtree.c			famgetbirthdeath() ->	fgbegend()
	X	famtree.c			famgetnum()	   ->	fgnum()
	X	famtree.c			famgetstr(0	   ->	fgstr()
	X	famtree.c			famgettname()	   ->	tname()
	X
	X	geneal.c			ac		   ->   argc
	X 	geneal.c		        ar		   ->   argv
	X
	X	gbrowse.c			famgetbstr()       ->   bstr()
	X
	X	indivs.c			famgetbstr()       ->   bstr()
	X	indivs.c			famgetbirth()	   ->	fgbirth()
	X	indivs.c			famgetbirthdeath() ->	fgbegend()
	X	indivs.c			famgetbname()	   ->	bname()
	X	indivs.c			famgetclist()	   ->	fgclist()
	X	indivs.c			famgetfname()	   ->	fname()
	X	indivs.c			famgetmarriage()   ->	fgmar()
	X	indivs.c			famgetnum()	   ->	fgnum()
	X	indivs.c			famgettname()	   ->	tname()
	X
SHAR_EOF
if test 3283 -ne "`wc -c < 'CHANGES'`"
then
	echo shar: error transmitting "'CHANGES'" '(should have been 3283 characters)'
fi
chmod +x 'CHANGES'
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(1837 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'Makefile'
	XCFLAGS	=	-v
	X
	XLINTFLAGS =	
	X
	XDEST	      = .
	X
	XEXTHDRS	      = /usr/include/ctype.h \
	X		/usr/include/stdio.h
	X
	XHDRS	      = famtree.h \
	X		geneal.h \
	X		pagemap.h
	X
	XLDFLAGS	      = 
	X
	XLINKER	      = cc
	X
	XMAKEFILE      = Makefile
	X
	XOBJS	      = dataman.o \
	X		errorman.o \
	X		famgetdat.o \
	X		family.o \
	X		famtree.o \
	X		gbrowse.o \
	X		geneal.o \
	X		index.o \
	X		indivs.o \
	X		pagemap.o \
	X		strsav.o \
	X		tprintf.o \
	X		vsprintf.o \
	X		xalloc.o
	X
	XLIBS          =	
	X
	XPRINT	      = pr
	X
	XPROGRAM	      = geneal
	X
	XSRCS	      = dataman.c \
	X		errorman.c \
	X		famgetdat.c \
	X		family.c \
	X		famtree.c \
	X		gbrowse.c \
	X		geneal.c \
	X		index.c \
	X		indivs.c \
	X		pagemap.c \
	X		strsav.c \
	X		tprintf.c \
	X		vsprintf.c \
	X		xalloc.c
	X
	Xall:		$(PROGRAM)
	X
	X$(PROGRAM):     $(OBJS) $(LIBS)
	X		@echo -n "Loading $(PROGRAM) ... "
	X		@$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
	X		@echo "done"
	X
	Xclean:;		@rm -f $(OBJS)
	X
	Xdepend:;	@echo Updating makefile
	X		@mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
	X
	Xindex:;		@ctags -wx $(HDRS) $(SRCS)
	X
	Xlint:;		lint $(LINTFLAGS) $(SRCS) $(LINTLIBS)
	X
	Xinstall:	$(PROGRAM)
	X		@echo Installing $(PROGRAM) in $(DEST)
	X		@install -s $(PROGRAM) $(DEST)
	X
	Xprint:;		@$(PRINT) $(SRCS) $(HDRS)
	X
	Xprogram:        $(PROGRAM)
	X
	Xtags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
	X
	Xupdate:		$(DEST)/$(PROGRAM)
	X
	X$(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
	X		@make -f $(MAKEFILE) DEST=$(DEST) install
	X
	X###
	Xdataman.o: /usr/include/stdio.h
	Xerrorman.o: /usr/include/stdio.h
	Xfamgetdat.o: /usr/include/stdio.h geneal.h famtree.h
	Xfamily.o: /usr/include/stdio.h /usr/include/ctype.h geneal.h pagemap.h
	Xfamtree.o: /usr/include/stdio.h geneal.h famtree.h pagemap.h
	Xgbrowse.o: geneal.h
	Xgeneal.o: /usr/include/stdio.h /usr/include/ctype.h
	Xindivs.o: geneal.h
	Xpagemap.o: pagemap.h /usr/include/stdio.h
	Xvsprintf.o: /usr/include/stdio.h
	Xxalloc.o: /usr/include/stdio.h
SHAR_EOF
if test 1837 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 1837 characters)'
fi
chmod +x 'Makefile'
fi # end of overwriting check
echo shar: extracting "'README'" '(1887 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	XThe GENEAL Program
	XWritten by Jim McBeath (jimmc) at SCI
	XModified by Terry L. Ridder (tlr) at The Terry L. Ridder Family
	X
	Xlast edit 20-Jan-85 16:55:25 by jimmc (Jim McBeath)
	Xlast edit 30-Aug-85 01:29:00 by tlr   (Terry L. Ridder)
	X
	XThis file describes what other files exist and what you will have to
	Xdo in order to make geneal useful to you.
	X
	XFiles of interest:
	X    *.[ch]	The source files for geneal.
	X
	X    Makefile	Exactly that.
	X
	X    README	What you are looking at right now.
	X
	X    geneal.l	Manual page for geneal. nroff -man geneal.l to
	X	   	generate geneal.man.
	X
	X    geneal.man	Manual page for geneal. Describes (briefly) what
	X		geneal is all about.  Gives list of options.
	X
	X    pgmr.doc    nroff file for prog.man. nroff -ms pgmr.doc > pgmr.man
	X
	X    pgmr.man	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
	X    genealogy.dat    The data file.  This is a sample file for you to use
	X		as a template for creating your own data file.
	X
	X    family.1003	Sample output file produced by "geneal -f 1003".
	X
	XWhat to do (after unpacking):
	X1. Read geneal.man.
	X2. 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.
	X3. 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.
	X4. Run the program.  There are numerous checks for data consistency, so
	X   you should get error messages if things do not point to each other
	X   properly.  These are typically easy to fix.
	X5. If you want to make changes, read pgmr.man first.
	X6. Send us your comments and improvements.
	X
	X
	X				-Jim McBeath
	X				 15-Jan-1985
	X				-Terry L. Ridder
	X				 30-Aug-1985
SHAR_EOF
if test 1887 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1887 characters)'
fi
chmod +x 'README'
fi # end of overwriting check
echo shar: extracting "'dataman.c'" '(5502 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 31-Aug-85 13:00: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 <stdio.h>
	X#include "index.h"
	X
	Xstruct dpoint {
	X    FILE *ff;				/* which data file to read */
	X    struct toplevel *xx;		/* pointer for index routine */
	X    };
	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(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 5502 -ne "`wc -c < 'dataman.c'`"
then
	echo shar: error transmitting "'dataman.c'" '(should have been 5502 characters)'
fi
chmod +x 'dataman.c'
fi # end of overwriting check
echo shar: extracting "'errorman.c'" '(1052 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 31-Aug-85 13:00: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 vsprintf, so that must be included
	X * in the load list. */
	X
	X#include <stdio.h>
	X
	X#define ERROR_EXIT 1
	X#define BSIZE 200
	X
	Xextern char *Progname;		/* user must set up the progname to use */
	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
	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 */
	Xerrormsg(s, args)
	Xchar *s;
	X{
	Xchar buf[BSIZE];
	X
	X    vsprintf(buf, s, &args);
	X    fprintf(stderr, "%s: error: %s\n", Progname, buf);
	X}
	X
	X/* end */
SHAR_EOF
if test 1052 -ne "`wc -c < 'errorman.c'`"
then
	echo shar: error transmitting "'errorman.c'" '(should have been 1052 characters)'
fi
chmod +x 'errorman.c'
fi # end of overwriting check
echo shar: extracting "'famgetdat.c'" '(8434 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 31-Aug-85 13:00: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 <stdio.h>
	X#include "geneal.h"
	X#include "famtree.h"
	X
	X#define TRUE 1
	X#define FALSE 0
	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 8434 -ne "`wc -c < 'famgetdat.c'`"
then
	echo shar: error transmitting "'famgetdat.c'" '(should have been 8434 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'" '(8253 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 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#include <stdio.h>
	X#include <ctype.h>
	X#include "geneal.h"
	X#include "pagemap.h"
	X
	X#define PGWD 80
	X#define LTMAR 4
	X#define RTMAR 4
	X#define CTRMAR 2
	X#define LTCOL ((PGWD-LTMAR-RTMAR-CTRMAR)/2)
	X#define RTCOL (PGWD-LTMAR-RTMAR-CTRMAR-LTCOL)
	X#define SO 10
	X
	X#define TBLOCKSIZE 1000
	X#define NOTEMAX 500
	X
	Xstruct tblock {				/* a text block */
	X    int width;				/* length of longest line */
	X    int lines;				/* number of lines */
	X    char *text[TBLOCKSIZE];		/* the text pointers */
	X    };
	X
	Xextern int gendp;			/* datafile index number */
	Xextern int dataStatus;
	Xextern char *dataErrStrs[];
	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 8253 -ne "`wc -c < 'family.c'`"
then
	echo shar: error transmitting "'family.c'" '(should have been 8253 characters)'
fi
chmod +x 'family.c'
fi # end of overwriting check
echo shar: extracting "'famtree.c'" '(7204 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 31-Aug-85 13:00: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 <stdio.h>
	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 int 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 7204 -ne "`wc -c < 'famtree.c'`"
then
	echo shar: error transmitting "'famtree.c'" '(should have been 7204 characters)'
fi
chmod +x 'famtree.c'
fi # end of overwriting check
echo shar: extracting "'famtree.h'" '(1385 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 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	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 1385 -ne "`wc -c < 'famtree.h'`"
then
	echo shar: error transmitting "'famtree.h'" '(should have been 1385 characters)'
fi
chmod +x 'famtree.h'
fi # end of overwriting check
echo shar: extracting "'gbrowse.c'" '(1260 characters)'
if test -f 'gbrowse.c'
then
	echo shar: will not over-write existing file "'gbrowse.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'gbrowse.c'
	X/* gbrowse.c - browse through the genealogy file */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 09:08:30 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#include "geneal.h"
	X
	Xextern char *gets();
	X
	Xint		/* 0 if OK */
	Xgbrowse()	/* browse the database */
	X{
	Xchar *ss;
	Xchar lbuf[1000];
	Xchar tbuf[1000];
	Xint n;
	Xint t;
	X
	X    indexes++;		/* note we want to see all the index numbers */
	X    while (1)		/* until a break takes us out */
	X    {
	X	printf(">");		/* give the browse prompt */
	X	ss = gets(lbuf);		/* read in a line */
	X	if (ss == 0)
	X	{
	X	    break;		/* quit on eof */
	X	}
	X	if (lbuf[0] == 0)
	X	{
	X	    continue;	/* ignore blank lines */
	X	}
	X	t = sscanf(lbuf, "%d", &n);	/* read his number */
	X	if (t != 1)
	X	{
	X	    printf("numbers only, please\n");
	X	    continue;		/* read another line */
	X	}
	X	if (n <= 0)
	X	{
	X	    continue;
	X	}
	X	t = bstr(n, "T", tbuf);	/* see what the record type is */
	X	if (t == 0)		/* if not there */
	X	{
	X	    printf("bad record %d\n", n);
	X	    continue;
	X	}
	X	if (strcmp(tbuf, "I") == 0)
	X	{
	X	    indivs(n);
	X	}
	X	else if (strcmp(tbuf, "F") == 0)
	X	{
	X	    family(n);
	X	}
	X	else
	X	{
	X	    printf("unknown type code %s in record %d\n", tbuf, n);
	X	}
	X/* continue the loop */
	X    }
	X    return 0;
	X}
	X
	X/* end */
SHAR_EOF
if test 1260 -ne "`wc -c < 'gbrowse.c'`"
then
	echo shar: error transmitting "'gbrowse.c'" '(should have been 1260 characters)'
fi
chmod +x 'gbrowse.c'
fi # end of overwriting check
echo shar: extracting "'geneal.c'" '(4521 characters)'
if test -f 'geneal.c'
then
	echo shar: will not over-write existing file "'geneal.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'geneal.c'
	X/* geneal - manipulate family trees, etc. */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 08:17:08 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#include <stdio.h>
	X#include <ctype.h>
	X
	X#define HELP_EXIT 2
	X
	Xchar *getData(), *rindex();
	X
	Xchar *Progname;				/* name of the program 		     */
	Xextern int dataDebug;			/* flag for debugging data routines  */
	Xextern int indexDebug;			/* flag for debugging index routines */
	X
	Xint gendp;				/* data pointer for file 	     */
	Xchar *gendatfile="genealogy.dat";	/* filename for data file 	     */
	Xint indexes=0;				/* set means output index numbers    */
	X
	Xmain(argc, argv)
	Xint 	argc;
	Xchar 	*argv[];
	X{
	Xint i, j;
	Xint nval = 1;
	Xint nsac = 0;		/* non-switch argument count */
	Xint fampage = 0;	/* set means user wants a family info page */
	Xint sflag = 0;		/* set means use short form */
	Xint iflag = 0;		/* set means produce individual data page */
	Xint tflag = 0;		/* set means produce a tree */
	Xint t;			/* for status values */
	X
	X    Progname = rindex(argv[0], '/');	/* program name */
	X    if (Progname == 0)
	X    {
	X  	 Progname = argv[0];
	X    }
	X    else
	X    {
	X   	 Progname++;
	X    }
	X    nval = 0;		/* stays 0 if the user never asks for a number */
	X    for (i = 1; i < argc; i++)		/* scan switches and args */
	X    {
	X	if (argv[i][0] == '-') for (j = 1; j > 0 && argv[i][j]; j++)
	X		/* check switches */
	X	switch (argv[i][j])
	X	{
	X	case 'f':			/* produce family info page */
	X	    fampage++;
	X	    break;
	X	case 'h':			/* give help */
	X	    genhelp();
	X	    exit(HELP_EXIT);		/* don't continue */
	X	case 'i':			/* individual information page */
	X	    iflag++;
	X	    break;
	X	case 's':			/* short form */
	X	    sflag++;
	X	    break;
	X	case 't':			/* produce a tree */
	X	    tflag++;
	X	    break;
	X	case 'D':			/* debug data routines */
	X	    dataDebug++;
	X	    break;
	X	case 'F':
	X	    if (argv[i][j+1])
	X	    {
	X		 gendatfile = argv[i]+(j+1);
	X	    }
	X	    else if (argv[++i])
	X	    {
	X		 gendatfile = argv[i];
	X	    } 
	X	    else
	X	    {
	X		 fatalerr("no argument for -F switch");
	X	    }
	X	    j = -2;			/* flag this string is used up */
	X	    break;
	X	case 'I':			/* debug index routines */
	X	    indexDebug++;
	X	    break;
	X	case 'N':			/* output index numbers */
	X	    indexes++;
	X	    break;
	X	default:
	X	    fatalerr("unknown switch %c in %s", argv[i][j], argv[i]);
	X	}
	X	else				/* non-switch args */
	X	{
	X	    switch (nsac++)		/* non-switch arg count */
	X	    {
	X	    case 0:			/* first arg is number to use */
	X		if (isdigit(argv[i][0]))
	X		{
	X		    nval = atoi(argv[i]);
	X		}
	X		else
	X		{
	X		    fatalerr("bad format for arg0 (must be a number)");
	X		}
	X		break;
	X	    default:			/* too many */
	X		fatalerr("unknown argument %s", argv[i]);
	X	    }
	X	}
	X    }
	X    if (fampage + iflag + tflag > 1)
	X    {
	X	fatalerr("only one of -f, -i or -t may be selected");
	X    }
	X    gendp = initDataFile(gendatfile);	/* get data file */
	X    if (gendp == 0) 
	X    {
	X        fatalerr("can't open data file %s", gendatfile);
	X    }
	X/* check for combinations which are not yet implemented */
	X    if (fampage && sflag) 
	X    {
	X        warning("short form for family is not implemented");
	X    }
	X    if (iflag && !sflag) 
	X    {
	X        warning("only short form available for individuals");
	X    }
	X    if (fampage)                    	/* produce a family page if requested */
	X    {
	X	t = family(nval);
	X    }
	X    else if (iflag)                    	/* produce info about individual */
	X    {
	X	t = indivs(nval);
	X    }
	X    else if (tflag)                   	/* produce a family tree */
	X    {
	X	t = famtree(nval);
	X    }
	X/* if no specific action was requested, do the default */
	X    else               			/* go browsing */
	X    {
	X	t = gbrowse();
	X    }
	X    if (t == 0)				/* if no errors, exit w/o errors */
	X    {
	X	exit(0);
	X    }
	X    else
	X    {
	X	exit(1);			/* errors */
	X    }
	X}
	X
	X/*........../
	X
	X/* the help table */
	Xchar *helptab[] = {
	X"arg0 is the ID number of interest",
	X"Switches:",
	X"-f   produce a family information page",
	X"-h   give this help message",
	X"-i   produce an individual (person) information page",
	X"-s   use a short form for the specified information",
	X"-t   produce a tree (this function is quite incomplete!)",
	X"-D   debug data routines",
	X"-F file   use the specified file as datafile",
	X"-I   debug index routines",
	X"-N   output internal index numbers with all names",
	X"If no switches are given, the program enters browse mode.",
	X0
	X};
	X
	Xgenhelp()		/* give help */
	X{
	Xint i;
	X
	X    for (i = 0; helptab[i]; i++)
	X    {
	X	printf("%s\n", helptab[i]);		/* print out the help table */
	X    }
	X    return;
	X}
	X
	X/* end */
SHAR_EOF
if test 4521 -ne "`wc -c < 'geneal.c'`"
then
	echo shar: error transmitting "'geneal.c'" '(should have been 4521 characters)'
fi
chmod +x 'geneal.c'
fi # end of overwriting check
echo shar: extracting "'geneal.h'" '(911 characters)'
if test -f 'geneal.h'
then
	echo shar: will not over-write existing file "'geneal.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'geneal.h'
	X/* geneal.h - general include stuff for geneal modules */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 05:07:41 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X/* global variables */
	Xextern int gendp;		/* data file index number */
	Xextern int indexes;		/* set means output index numbers w names */
	X
	X/* declare functions */
	Xchar *index();
	X
	Xchar *getData();
	Xchar *strsav();
	Xchar *tprintf();
	X
	Xchar *fgstr();			/* originally char *famgetstr()		*/
	Xchar *tname();			/* originally char *famgettname() 	*/
	Xchar *bname();			/* originally char *famgetbname() 	*/
	Xchar *fname();			/* originally char *famgetfname() 	*/
	Xchar *fgbirth();		/* originally char *famgetbirth() 	*/
	Xchar *fgdeath();		/* originally char *famgetdeath() 	*/
	Xchar *fgbegend();		/* originally char *famgetbirthdeath() 	*/
	Xchar *fgmar();			/* originally char *famgetmarriage() 	*/
	X
	X/* end */
SHAR_EOF
if test 911 -ne "`wc -c < 'geneal.h'`"
then
	echo shar: error transmitting "'geneal.h'" '(should have been 911 characters)'
fi
chmod +x 'geneal.h'
fi # end of overwriting check
echo shar: extracting "'geneal.l'" '(3143 characters)'
if test -f 'geneal.l'
then
	echo shar: will not over-write existing file "'geneal.l'"
else
sed 's/^	X//' << \SHAR_EOF > 'geneal.l'
	X.TH GENEAL LOCAL 8/28/85
	X.SH NAME
	Xgeneal \- genealogy program
	X.SH SYNOPSIS
	X.B Geneal
	X[ option ] ...
	X[ file ] 
	X.SH DESCRIPTION
	X.I Geneal
	Xis a program to read a database of family relations in the named
	X.I file
	Xand print the information out in various formats.  
	X.PP
	XIf no
	X.I file
	Xargument is present, the default file,
	X.I genealogy.dat
	X, is read.
	X.PP
	XIt deals with
	Xfamilies and individuals, each identified by a unique integer.
	XThe database contains information such as 
	X.I birth
	X, 
	X.I death 
	Xand
	X.I marriage 
	Xdates and places (if you know them!), relations between
	Xpeople (i.e. what children belong to X, are you my mother),
	Xand miscellaneous information of general interest.
	XThe program can read the information for a specified individual
	Xand output it in a specified format.  At the moment there are two
	Xformats (only one of which is "real"): the tree, and the family
	Xpage.  The tree format is only a tiny bit implemented, so it's
	Xnot very useful yet.  The family page gives information about
	Xan entire family (one generation), i.e. parents, children, and
	Xchildrens's spouses.  More formats can easily be added (and will
	Xbe in the future!).
	X
	XGeneal expects one argument on the command line, which is the index
	Xnumber of the person or family to center the data search/output on.
	X.PP
	XThe options available are:
	X.TP "w'\f3\-F\f1name 'u"
	X.BI \-f   
	Xproduce a family information page
	X.TP
	X.BI \-h   
	Xgive this help message (try this in case this man page is wrong!)
	X.TP
	X.BI \-i   
	Xproduce information about an individual
	X.TP
	X.BI \-s   
	Xuse a short form of output
	X.TP
	X.BI \-t   
	Xproduce a tree (not implemented very far!)
	X.TP
	X.BI \-D   
	Xdebug data routines
	X.TP
	X.BI \-F file   
	Xuse the specified file as datafile
	X.TP
	X.BI \-I   
	Xdebug index routines
	X.TP
	X.BI \-N   
	Xoutput internal index numbers with all names
	X.PP
	XIf no format switches (-f, -i, -t) are given, browse mode is entered.
	XThe two debug switches (-D and -I) will probably not be useful to you
	Xunless you are familiar with the dataman and index routines which they
	Xapply to.
	X
	X.SH EXAMPLE
	XIndividuals or families are specified by index number.  Thus the
	Xcommand to output the family data page for a particular family
	Xwould be
	X.IP
	X.nf
	X    geneal -f 1025
	X.fi
	Xwhere 1025 is the index number for that family.
	X.SH NOTES
	XThere is some flexibility in the data file as to what numbers you
	Xuse as index numbers.  The authors have adopted the convention that individuals
	Xare numbered starting at 1 and families starting at 1000 (when I get
	X1000 individuals, I will start the next group at 10000).  You may
	Xwant to use different conventions, e.g. odd numbers for males, even
	Xfor females; families starting at a higher number; or whatever.
	X.SH FILES
	X.nf
	X   genealogy.dat 	The database file. This is a sample 
	X			file for you to use as a template
	X			for creating your own data file.
	X
	X   family.1003 		Sample output file produced by 
	X			"geneal -f 1003".
	X
	X   pgmr.doc 		Programmer's documentation. Gives 
	X			more details about some of the source 
	X			files. Read this if you need to look 
	X			for bugs.
	X.fi
	X.SH AUTHOR
	XJim McBeath (original author)
	X.br
	XTerry L. Ridder (ported geneal to Version 7 and SYS V)
SHAR_EOF
if test 3143 -ne "`wc -c < 'geneal.l'`"
then
	echo shar: error transmitting "'geneal.l'" '(should have been 3143 characters)'
fi
chmod +x 'geneal.l'
fi # end of overwriting check
echo shar: extracting "'geneal.man'" '(3740 characters)'
if test -f 'geneal.man'
then
	echo shar: will not over-write existing file "'geneal.man'"
else
sed 's/^	X//' << \SHAR_EOF > 'geneal.man'
	X
	X
	X
	XGENEAL(LOCAL)       UNIX Programmer's Manual        GENEAL(LOCAL)
	X
	X
	X
	XNAME
	X     geneal - genealogy program
	X
	XSYNOPSIS
	X     Geneal [ option ] ...  [ file ]
	X
	XDESCRIPTION
	X     _G_e_n_e_a_l is a program to read a database of family relations
	X     in the named _f_i_l_e and print the information out in various
	X     formats.
	X
	X     If no _f_i_l_e argument is present, the default file,
	X     _g_e_n_e_a_l_o_g_y._d_a_t , is read.
	X
	X     It deals with families and individuals, each identified by a
	X     unique integer.  The database contains information such as
	X     _b_i_r_t_h , _d_e_a_t_h and _m_a_r_r_i_a_g_e dates and places (if you know
	X     them!), relations between people (i.e. what children belong
	X     to X, are you my mother), and miscellaneous information of
	X     general interest.  The program can read the information for
	X     a specified individual and output it in a specified format.
	X     At the moment there are two formats (only one of which is
	X     "real"): the tree, and the family page.  The tree format is
	X     only a tiny bit implemented, so it's not very useful yet.
	X     The family page gives information about an entire family
	X     (one generation), i.e. parents, children, and childrens's
	X     spouses.  More formats can easily be added (and will be in
	X     the future!).
	X
	X     Geneal expects one argument on the command line, which is
	X     the index number of the person or family to center the data
	X     search/output on.
	X
	X     The options available are:
	X
	X     -f   produce a family information page
	X
	X     -h   give this help message (try this in case this man page
	X          is wrong!)
	X
	X     -i   produce information about an individual
	X
	X     -s   use a short form of output
	X
	X     -t   produce a tree (not implemented very far!)
	X
	X     -D   debug data routines
	X
	X     -F_f_i_l_e
	X          use the specified file as datafile
	X
	X     -I   debug index routines
	X
	X
	X
	XPrinted 8/29/85              8/28/85                            1
	X
	X
	X
	X
	X
	X
	XGENEAL(LOCAL)       UNIX Programmer's Manual        GENEAL(LOCAL)
	X
	X
	X
	X     -N   output internal index numbers with all names
	X
	X     If no format switches (-f, -i, -t) are given, browse mode is
	X     entered.  The two debug switches (-D and -I) will probably
	X     not be useful to you unless you are familiar with the data-
	X     man and index routines which they apply to.
	X
	X
	XEXAMPLE
	X     Individuals or families are specified by index number.  Thus
	X     the command to output the family data page for a particular
	X     family would be
	X
	X
	X              geneal -f 1025
	X          where 1025 is the index number for that family.
	X
	XNOTES
	X     There is some flexibility in the data file as to what
	X     numbers you use as index numbers.  The authors have adopted
	X     the convention that individuals are numbered starting at 1
	X     and families starting at 1000 (when I get 1000 individuals,
	X     I will start the next group at 10000).  You may want to use
	X     different conventions, e.g. odd numbers for males, even for
	X     females; families starting at a higher number; or whatever.
	X
	XFILES
	X        genealogy.dat    The database file. This is a sample
	X                    file for you to use as a template
	X                    for creating your own data file.
	X
	X        family.1003           Sample output file produced by
	X                    "geneal -f 1003".
	X
	X        pgmr.doc         Programmer's documentation. Gives
	X                    more details about some of the source
	X                    files. Read this if you need to look
	X                    for bugs.
	X
	XAUTHOR
	X     Jim McBeath (original author)
	X     Terry L. Ridder (ported geneal to Version 7 and SYS V)
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	XPrinted 8/29/85              8/28/85                            2
	X
	X
	X
SHAR_EOF
echo shar: 48 control characters may be missing from "'geneal.man'"
if test 3740 -ne "`wc -c < 'geneal.man'`"
then
	echo shar: error transmitting "'geneal.man'" '(should have been 3740 characters)'
fi
chmod +x 'geneal.man'
fi # end of overwriting check
echo shar: extracting "'genealogy.dat'" '(2829 characters)'
if test -f 'genealogy.dat'
then
	echo shar: will not over-write existing file "'genealogy.dat'"
else
sed 's/^	X//' << \SHAR_EOF > 'genealogy.dat'
	X0	Description of data format
	X:Sample Data file for genealogy records.
	X:All the information has been changed to protect the innocent.
	X:last edit 20-Jan-85 16:41:45 by jimmc (Jim McBeath)
	X:
	X:File format:
	X:Each record specifies either an individual or a family.
	X:Each record has a unique index number.
	X:Each record is separated by a blank line.
	X:Each line within a record is an item of data.
	X:Each item of data consists of a key, a colon, and a payload string.
	X:Lines which start with a colon are comment lines.
	X:The first line of each record starts with an integer which is
	X:the index number for that record.  The rest of that line is ignored.
	X:
	X:The fields used in this file are described in this record.
	XT:Type of record: I for individual, F for family
	X:fields in an individual record:
	XLN:Last name (family name)
	XLNM:Maiden name
	XFN:First name
	XMN:Middle names
	XNN:Nickname
	XB:Birthdate in the format dd-mmm-yyyy
	XBP:Place of birth
	XD:Date of death in the same format
	XDP:Place of death
	XP:Index number of parent's marriage
	XS0:Index number of first marriage
	XS1:Index number of second marriage
	X:A family record contains information about a marriage and its offsprings.
	X:fields in a family record:
	XN:family name
	XH:Index number of husband
	XW:Index number of wife
	XM:Date of marriage
	XMD:Date of end of marriage
	XMP:Place of marriage
	XMDP:Place of end of marriage
	XC:Index number list of children from this marriage
	X:general fields:
	XGEN0:General information of interest about that person.
	XGEN1: etc.
	XCOM0:Comments.
	XCOM1: etc.
	X:
	X:first real record follows
	X
	X1	John Doe (1952)
	XT:I
	XLN:Doe
	XFN:John
	XMN:Michael
	XNN:Norm
	XB:10-Feb-1952
	XBP:Anytown, USA
	XP:1003
	XS0:1001
	X
	X2	Andrew Doe (1921)
	XT:I
	XLN:Doe
	XFN:Andrew
	XMN:Q.
	XB:3-Feb-1921
	XBP:New York, NY
	XS0:1003
	XP:1004
	X
	X3	Elizabeth Smith Doe (1925)
	XT:I
	XLN:Doe
	XLNM:Smith
	XFN:Elizabeth
	XMN:Nancy
	XNN:Beth
	XB:4-Mar-1925
	XBP:Hauppauge, NY
	XS0:1003
	X
	X4	Jane Jones Doe (1953)
	XT:I
	XLN:Doe
	XLNM:Jones
	XFN:Jane
	XMN:Jill
	XB:12-Dec-1953
	XBP:Los Angeles, CA
	XS0:1001
	X
	X5	Dave Doe (1949)
	XT:I
	XLN:Doe
	XFN:David
	XNN:Dave
	XB:3-Jun-1949
	XBP:Midville, USA
	XP:1003
	XS0:1002
	X
	X6	Kim Doe (1975)
	XT:I
	XLN:Doe
	XFN:Kimberly
	XMN:Janice
	XNN:Kim
	XB:5-Apr-1975
	XBP:Oakland, CA
	XP:1001
	X
	X8	Nancy Walker Doe (1950)
	XT:I
	XLN:Doe
	XLNM:Walker
	XFN:Nancy
	XMN:M.
	XB:Jul-1950
	XS0:1002
	X
	X9	Hans Doe (ca 1900?)
	XT:I
	XLN:Doe
	XFN:Hans
	XB:ca. 1900?
	XBP:Sweden
	XS0:1004
	X
	X10	Lita ?? Doe (ca 1900?)
	XT:I
	XLN:Doe
	XFN:Lita
	XB:ca. 1900?
	XS0:1004
	X
	XCOM0:Try to find maiden name in Oslo marriage records
	X
	X1001	John Doe and Jane Jones (1973)
	XT:F
	XN:Doe
	XH:1
	XW:4
	XM:15-Jun-1973
	XMP:San Franciso, CA
	XC:6
	X
	X1002	Dave Doe and Nancy Walker (1975)
	XT:F
	XN:Doe
	XH:5
	XW:8
	XM:6-Sep-1975
	X
	X1003	Andrew Doe and Elizabeth Simth (1948)
	XT:F
	XN:Doe
	XH:2
	XW:3
	XM:3-Aug-1948
	XMP:San Francisco, CA
	XC:5,1
	X
	X1004	Hans Doe and Lita ?? (1919)
	XT:F
	XN:Doe
	XH:9
	XW:10
	XM:1915
	XMP:Oslo, Sweden?
	XC:2
	XGEN0:Stowed away on a ship in 1917 to come to America.
	X
	X:end of file
SHAR_EOF
if test 2829 -ne "`wc -c < 'genealogy.dat'`"
then
	echo shar: error transmitting "'genealogy.dat'" '(should have been 2829 characters)'
fi
chmod +x 'genealogy.dat'
fi # end of overwriting check
echo shar: extracting "'index.c'" '(5774 characters)'
if test -f 'index.c'
then
	echo shar: will not over-write existing file "'index.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'index.c'
	X/* index - index handler for large pseudo-arrays */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 10-Jan-85 07:59:39 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X/* This module implements a very large pseudo-array.  There are three
	X   entry points, to initialize a pseudo-array, to insert an item, and
	X   to read an item.  The array contains integers (which can of course
	X   be used for another purpose, such as pointers to something else).
	X
	X   Structure of a table:
	X   A table is a recursive structure which contains 2 words of size
	X   information and n words of pointers.  The first word of size
	X   information tells how many entries are represented by this and
	X   all lower tables; the second word of size information tells how
	X   many entries are actually in this table.  If the two numbers are
	X   the same, then the table is an end node which actually has the
	X   data entries in it.
	X*/
	X
	X/*..........*/
	X
	X#include "index.h"
	X
	Xextern char *malloc();		/* added by tlr */
	X
	Xint indexDebug = 0;		/* a debugging flag */
	X
	X/*..........*/
	X
	Xstruct toplevel *		/* pointer to the structure for future calls */
	XinitIndex()			/* init a new index table */
	X{
	Xstruct toplevel *tt;
	Xstruct tblblock *dd;
	Xint i;
	X
	X    tt = (struct toplevel *)malloc(sizeof(struct toplevel));
	X	/* get space for top level block */
	X    if (!tt)
	X    {
	X	 return 0;
	X    }
	X    dd = (struct tblblock *)malloc(sizeof(struct tblblock));
	X	/* get space for top level table */
	X    if (!dd) 
	X    {
	X        free(tt);
	X        return 0;
	X    }
	X    tt->data = dd;			/* save pointer in our block */
	X    tt->numlevs = 1;		/* we always start with one level */
	X    dd->repnum = TBLSIZ;
	X    dd->count = TBLSIZ;
	X    for (i = 0; i < dd->count; i++)
	X    {
	X	dd->tdata[i] = 0;	/* clear all data */
	X    }
	X    return tt;			/* return pointer to top level block */
	X}
	X
	X/*..........*/
	X
	XsetIndex(tt, ix, num)		/* put index value into table */
	Xstruct toplevel *tt;		/* table to use */
	Xint ix;				/* the index where it goes */
	Xint num;			/* the value to put there */
	X{
	Xstruct tblblock *dd, *dd0;
	Xint i;
	X
	X    if (indexDebug) 
	X    {
	X        printf("setIndex: index=%d, value=%d\n", ix, num);
	X        if (!tt)
	X	{
	X	    printf("setIndex: no table index\n");
	X	}
	X        else if (!(tt->numlevs))
	X	{
	X	    printf("setIndex: no numlevs\n");
	X	}
	X        else if (!(tt->data))
	X	{
	X	    printf("setIndex: no data array\n");
	X	}
	X    }
	X    if (!tt)
	X    {
	X	 return -1;		/* check for errors */
	X    }
	X    if (!(tt->numlevs))
	X    {
	X	 return -1;
	X    }
	X    if (!(tt->data))
	X    {
	X	 return -1;
	X    }
	X    dd = tt->data;			/* get data pointer */
	X    while (ix >= dd->repnum)
	X    {	/* create a higher level */
	X    	if (indexDebug)
	X    	{
	X	 	printf("setIndex: %d(ix) > %d(repnum)\n", ix, dd->repnum);
	X    	}
	X    	dd0 = (struct tblblock *)malloc(sizeof(struct tblblock));
	X		/* get space for a higher level */
	X    	if (!dd0)
	X    	{
	X	 	return -1;		/* error */
	X    	}
	X    	dd0->repnum = dd->repnum*TBLSIZ;
	X    	dd0->count = TBLSIZ;
	X    	for (i = 0; i < TBLSIZ; i++)
	X    	{
	X	 	dd0->tdata[i] = 0;	/* clear table */
	X    	}
	X    	dd0->tdata[0] = (int)dd;	/* put in pointer to next level down */
	X    	tt->data = dd0;		/* put in new top-level pointer */
	X    	tt->numlevs++;
	X    	if (indexDebug)
	X    	{
	X	 	printf("setIndex: numlevs=%d\n", tt->numlevs);
	X    	}
	X    	dd = dd0;
	X    }
	X    while (dd->repnum > dd->count)
	X    {	/* scan down to the last level */
	X        if (indexDebug)
	X        {
	X	    printf("setIndex: %d(repnum) > %d(count)\n",
	X	    dd->repnum, dd->count);
	X        }
	X        dd0 = (struct tblblock *)(dd->tdata[ix/dd->count]);
	X	/* get pointer to next table lower */
	X        if (!dd0)
	X        {			/* if no table there, have to make one */
	X	    dd0 = (struct tblblock *)malloc(sizeof(struct tblblock));
	X	    if (!dd0)
	X	    {
	X	       return -1;		/* error */
	X	    }
	X	    dd0->repnum = dd->repnum/dd->count;
	X	    dd0->count = TBLSIZ;
	X	    for (i = 0; i < TBLSIZ; i++)
	X	    {
	X	        dd0->tdata[i] = 0; /* clear the new table */
	X	    }
	X	    dd->tdata[ix/dd->count] = (int)dd0;	/* save pointer to it */
	X	}
	X        ix %= dd->count;		/* lower the index */
	X        dd = dd0;
	X    }
	X    dd->tdata[ix] = num;		/* put it in */
	X    if (indexDebug)
	X    {
	X	printf("setIndex: table %X, index %d, value %d\n",
	X	dd, ix, num);
	X    }
	X    return ix;
	X}
	X
	X/*..........*/
	X
	Xint				/* return value out of table */
	X				/*  returns 0 if no entry */
	XgetIndex(tt, ix)
	Xstruct toplevel *tt;
	Xint ix;				/* the index to look for */
	X{
	Xstruct tblblock *dd, *dd0;
	X
	X    if (indexDebug) 
	X    {
	X        printf("getIndex: index=%d\n", ix);
	X        if (!tt) 
	X	{
	X	    printf("getIndex: no table\n");
	X	}
	X        else if (!tt->data) 
	X	{
	X	    printf("getIndex: no data array\n");
	X	}
	X        else if (!tt->numlevs) 
	X	{
	X	    printf("genIndex: no numlevs\n");
	X	}
	X    }
	X    if (!tt) 
	X    {
	X	return 0;		/* check for errors */
	X    }
	X    if (!tt->data) 
	X    {
	X	return 0;
	X    }
	X    if (!tt->numlevs)
	X    {
	X 	 return 0;
	X    }
	X    dd = tt->data;
	X    if (ix >= dd->repnum) 
	X    {
	X        if (indexDebug) 
	X	{
	X	    printf("getIndex: index %d > repnum %d\n", ix,dd->repnum);
	X	}
	X        return 0;	/* we don't have them that high */
	X    }
	X    while (dd->repnum > dd->count) 
	X    {	/* scan down to bottom level */
	X        if (indexDebug) 
	X	{
	X	    printf("getIndex: %d(repnum) > %d(count)\n",
	X		dd->repnum, dd->count);
	X	}
	X        dd0 = (struct tblblock *)(dd->tdata[ix/dd->count]);
	X	/* get pointer to next level */
	X        if (!dd0) 
	X	{
	X	    if (indexDebug) 
	X	    {
	X		printf("getIndex: no table\n");
	X	    }
	X	    return 0;		/* nothing there */
	X	}
	X        ix %= dd->count;
	X        dd = dd0;
	X    }
	X    if (indexDebug)
	X    {
	X	printf("getIndex: table %X, index %d, value %d\n",
	X	    dd, ix, dd->tdata[ix]);
	X    }
	X    return dd->tdata[ix];		/* this is the data entry */
	X}
	X    
	X/* end of index */
SHAR_EOF
if test 5774 -ne "`wc -c < 'index.c'`"
then
	echo shar: error transmitting "'index.c'" '(should have been 5774 characters)'
fi
chmod +x 'index.c'
fi # end of overwriting check
echo shar: extracting "'index.h'" '(584 characters)'
if test -f 'index.h'
then
	echo shar: will not over-write existing file "'index.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'index.h'
	X/* index.h - definitions for index */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 08:53:10 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	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    int 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    };
	X
	X/* end */
SHAR_EOF
if test 584 -ne "`wc -c < 'index.h'`"
then
	echo shar: error transmitting "'index.h'" '(should have been 584 characters)'
fi
chmod +x 'index.h'
fi # end of overwriting check
echo shar: extracting "'indivs.c'" '(4199 characters)'
if test -f 'indivs.c'
then
	echo shar: will not over-write existing file "'indivs.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'indivs.c'
	X/* indivs.v - print out short form info about an individual */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 08:05:47 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#include "geneal.h"
	X
	Xint			/* 0 if OK */
	Xindivs(n)
	Xint n;			/* the person's ID number */
	X{
	Xchar lbuf[1000];
	Xchar *ss;
	Xint pnum;		/* parent family number */
	Xint fnum;		/* father's number */
	Xint mnum;		/* mother's number */
	Xint mgnum;		/* marriage number */
	Xint snum;		/* spouse's number */
	Xint mhnum, mwnum;
	Xchar mgstr[20];		/* used for building key string */
	Xint i;			/* loop counter */
	Xint t;			/* random numbers and status */
	Xchar *sostr;
	X
	X    bstr(n, "T", lbuf);
	X    if (lbuf[0] == 0 || strcmp(lbuf, "I") != 0)
	X    {
	X	warning("id %d is not an individual");
	X	return 1;
	X    }
	X    ss = fname(n);
	X    printf("Name: %s\n", ss);
	X    ss = fgbirth(n);
	X    if (ss && *ss) 
	X    {
	X	printf("%s\n", ss);
	X    }
	X    ss = fgdeath(n);
	X    if (ss && *ss) 
	X    {
	X	printf("%s\n", ss);
	X    }
	X    pnum = fgnum(n, "P");	        /* get number of parent family */
	X    if (pnum > 0)			/* if we got a family */
	X    {
	X	if (indexes) 
	X	{
	X	    printf("Parent family: %d\n", pnum);
	X	}
	X	fnum = fgnum(pnum, "H");
	X	if (fnum >= 0)
	X	{
	X	    ss = fname(fnum);
	X	    printf("  Father: %s\n", ss);
	X	    ss = fgbegend(fnum);
	X	    if (ss && *ss) 
	X	    {
	X		printf("  %s\n", ss);
	X	    }
	X	}
	X	mnum = fgnum(pnum, "W");
	X	if (mnum >= 0)
	X	{
	X	    ss = fname(mnum);
	X	    printf("  Mother: %s\n", ss);
	X	    ss = fgbegend(mnum);
	X	    if (ss && *ss) 
	X	    {
	X		printf("  %s\n", ss);
	X	    }
	X	}
	X	ss = fgmar(pnum);
	X	if (ss) 
	X	{
	X	    printf("Parent's marriage: %s\n", ss);
	X	}
	X	doiclist(pnum, "Sibling", "Siblings", n);	/* do the siblings */
	X    }
	X    else	/* no parent in this record */
	X    {
	X	if (indexes) 
	X	{
	X	    printf("No parent family specified\n");
	X	}
	X    }
	X    for (i = 0; ; i++)	/* look at marriages */
	X    {
	X	sprintf(mgstr, "S%d", i);	/* build indicator string */
	X	mgnum = fgnum(n, mgstr);	/* get number of marriage */
	X	if (mgnum <= 0) 
	X	{
	X	    break;		/* stop if no more */
	X	}
	X	if (indexes) 
	X	{
	X	    printf("Marriage S%d: %d\n", i, mgnum);
	X	}
	X	mhnum = fgnum(mgnum, "H");	/* are we the husband? */
	X	mwnum = fgnum(mgnum, "W");	/*  or the wife */
	X	if (n != mhnum && n != mwnum)
	X	    warning("person %d claims marriage %d, but not vice-versa",
	X		n, mgnum);
	X	if (n == mhnum)
	X	{
	X	    snum = mwnum;
	X	    sostr = "Wife";
	X	}
	X	else
	X	{
	X	    snum = mhnum;
	X	    sostr = "Husband";
	X	}
	X	if (snum > 0)
	X	{
	X	    ss = bname(snum);
	X	    printf(" %s: %s\n", sostr, ss);
	X	    ss = fgbegend(snum);
	X	    if (ss && *ss) 
	X	    {
	X		printf(" %s\n", ss);
	X	    }
	X	}
	X	ss = fgmar(mgnum);
	X	if (ss && *ss) 
	X	{
	X	    printf(" %s\n", ss);
	X	}
	X	doiclist(mgnum,"Child","Children",-1);
	X    }
	X    for (i = 0; ; i++)
	X    {
	X	sprintf(mgstr, "GEN%d", i);
	X	t = bstr(n, mgstr, lbuf);
	X	if (t == 0) 
	X	{
	X	    break;		/* no more strings */
	X	}
	X	if (i == 0) 
	X	{
	X	    printf("General:\n");
	X	}
	X	printf("%s\n", lbuf);		/* print each line of GEN */
	X    }
	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{
	Xint i;
	Xint t;
	Xchar *ss;
	Xint *clist;
	Xint cflag = 0;
	X
	X    t = fgclist(pnum, &clist);	/* get list of kids */
	X    if (t == 0)
	X    {
	X	if (indexes) 
	X	{
	X	    printf("No %s specified\n", cm);
	X	}
	X	if (xn > 0) 
	X	{
	X	    warning("person %d claims parents %d but not vice-versa",
	X		xn, pnum);
	X	}
	X    }
	X    else
	X    {
	X	if (t == 1) 
	X	{
	X	    printf("  1 %s:\n", c1);
	X	}
	X	else 
	X	{
	X	    printf("  %d %s:\n", t, cm);
	X	}
	X	for (i = 0; i < t; i++)	/* for each child */
	X	{
	X	    if (clist[i] == xn) 
	X	    {
	X		cflag++;	/* note found special sibling */
	X	    }
	X	    if (indexes) 
	X	    {
	X		printf("  %s %d:", c1, i);
	X	    }
	X	    ss = tname(clist[i]);
	X	    printf("  %s%s\n", (clist[i]==xn?"*":""), ss);
	X	    ss = fgbegend(clist[i]);
	X	    if (ss && *ss) 
	X	    {
	X	   	printf("  %s\n", ss);
	X	    }
	X	}
	X	if (xn > 0 && cflag == 0)
	X	{
	X	    warning("person %d claims parents %d but not vice-versa",
	X		xn, pnum);
	X	}
	X    }
	X}
	X
	X/* end */
SHAR_EOF
if test 4199 -ne "`wc -c < 'indivs.c'`"
then
	echo shar: error transmitting "'indivs.c'" '(should have been 4199 characters)'
fi
chmod +x 'indivs.c'
fi # end of overwriting check
echo shar: extracting "'pagemap.c'" '(1887 characters)'
if test -f 'pagemap.c'
then
	echo shar: will not over-write existing file "'pagemap.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'pagemap.c'
	X/* pagemap - functions to manipulate a page of character data */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 15-Sep-84 22:24:02 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#include "pagemap.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 = XALLOC(Pagem, 1, "pageInit");	/* get the top level structure */
	X    pp->rows = r;
	X    pp->cols = c;		/* put in his numbers */
	X    pp->data = XALLOC(char *, r, "pageInit rowpointers");
	X    for (i = 0; i < r; i++)
	X    {
	X	pp->data[i] = ss = XALLOC(char, c+2, "pageInit data");
	X	for (j = 0; j <= c; j++)
	X	{
	X	    ss[j]=' ';	/* fill with spaces */
	X	}
	X	ss[c+1] = 0;		/* null terminated */
	X    }
	X    return pp;			/* return the pointer to him */
	X}
	X
	X/*..........*/
	X
	XpagePuts(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)
	X    {
	X	 n = pp->cols - c;	/* don't run off page */
	X    }
	X    for ( ; n > 0; n--)
	X    {
	X	 *(dd++) = *(ss++);	/* transfer string */
	X    }
	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{
	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	{
	X	    if (ss[c] > ' ')
	X	    {
	X		 break;	/* strip trailing spaces and nulls */
	X	    }
	X	}
	X	ss[++c] = 0;			/* make it null terminated */
	X	if (c > 0)
	X	{
	X	    lastline = r;		/* remember where the last line is */
	X	}
	X    }
	X    for (r = 0; r <= lastline; r++)		/* now output the lines */
	X    {
	X	fprintf(f, "%s\n", pp->data[r]);
	X    }
	X}
	X
	X/* end */
SHAR_EOF
if test 1887 -ne "`wc -c < 'pagemap.c'`"
then
	echo shar: error transmitting "'pagemap.c'" '(should have been 1887 characters)'
fi
chmod +x 'pagemap.c'
fi # end of overwriting check
echo shar: extracting "'pagemap.h'" '(960 characters)'
if test -f 'pagemap.h'
then
	echo shar: will not over-write existing file "'pagemap.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'pagemap.h'
	X/* pagemap.h - definition for the pagemap functions */
	X/* last edit 15-Sep-84 21:52:47 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#define XALLOC(item, count, msg) (item *)xalloc(sizeof(item)*count,msg)
	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 pagePutc(pp,r,c,ch) ((pp)->data[r][c] = (ch))
	X#define pageGetc(pp,r,c)    ((pp)->data[r][c])
	X
	Xextern Pagemp pageInit();
	X
	X/* end */
SHAR_EOF
if test 960 -ne "`wc -c < 'pagemap.h'`"
then
	echo shar: error transmitting "'pagemap.h'" '(should have been 960 characters)'
fi
chmod +x 'pagemap.h'
fi # end of overwriting check
echo shar: extracting "'pgmr.doc'" '(7963 characters)'
if test -f 'pgmr.doc'
then
	echo shar: will not over-write existing file "'pgmr.doc'"
else
sed 's/^	X//' << \SHAR_EOF > 'pgmr.doc'
	X.DA Aug 29, 1985
	X.RP
	X.TL
	XProgrammer Documentation for geneal
	X.AU
	XJim McBeath (jimmc) at SCI
	XTerry L. Ridder 
	X.AI
	XSilcon Compilers Inc.
	XThe Terry L. Ridder Family
	X.AB
	XThis document describes some of the files used in geneal.  It is
	Xintended to assist someone who may want to fix a bug or improve the
	Xprogram, or perhaps use one of the general modules for another program.
	XIf you do any of the above, we would be interested in hearing about it.
	X.AE
	X.NH
	XBACKGROUND
	X.LP
	XThe geneal program is divided up into a number of general purpose files
	Xand some special files specifically for the geneal program.
	X.DS
	XThe general files include:
	X    dataman.c	Simple reader for formatted data file.
	X    errorman.c	Error message routines.
	X    index.c	Routines to manipulate large virtual 
	X		arrays.
	X    pagemap.c	Build up an image of a page in memory 
	X		and output it.
	X    strsav.c	Save a malloc'ed copy of a string.
	X    tprintf.c	sprintf into a malloc'ed string.
	X    vsprintf.c	sprintf with a vector of arguments.
	X    xalloc.c	allocate memory and die if no more.
	X.DE
	X.DS
	XThe geneal-specific files include:
	X    geneal.c	main program for geneal (switches etc).
	X    famgetdat.c	routines to generate one-line strings 
	X		of data.
	X    family.c	generate a page of info about a family.
	X    famtree.c	generate a family tree (incomplete!).
	X    gbrowse.c	browse through the data.
	X    indivs.c	generate info about an individual.
	X.DE
	X
	X.NH
	XGeneral files
	X.LP
	XMost of the general files are simple, and can be easily understood by
	Xinspection.  The ones which deserve more extensive comment are dataman,
	Xindex, and pagemap.
	X
	X.NH 2 
	XDataman
	X.R
	Xis the interface to the datafile.  The datafile is in a particular
	Xformat (records, lines, keywords/values) which is decsribed at the beginning
	Xof that file.  The routines in this module allow access to those data items,
	Xtypically given a record number and a keyword name. There were two primary
	Xconsiderations behind selecting the format used in the data file and the
	Xtechniques used to read that file: 
	X.IP 1) 
	X.RS
	XIt should be in a text format so that it can be edited by a text editor (I
	Xdidn't want to have to write a special datafile editor) and so that it is
	Xhuman readable (so it could be used even before all the output routines
	Xwere written for any particular program); 
	X.RE
	X.IP 2) 
	X.RS
	XThe program should be able to
	Xhandle extremely large files.
	X.RE
	X.LP
	XThe current implementation of DATAMAN works as follows: during initialization,
	Xit scans through the data file looking for the start of each record.  It
	Xthen reads in the record number (an arbitrary but unique integer) and records
	X(using the INDEX module) the seek location in the file for that record.
	XWhen an access request is processed, it seeks to the location for that record
	Xand then scans until it finds the requested keyword.  While this may not
	Xbe particularly fast, it does satisfy the above two requirements of simple
	Xtext file format and the ability to handle extremely large files.  It is
	Xtrue that the initialization phase would take much longer for a very large
	Xfile, but the access time for any given item should be independent of
	Xfile size.
	X.LP
	XThere are of course some optimizations and improvements which could be
	Xmade here.  The first two on my list are: 
	X.IP 1) 
	X.RS
	XAfter scanning through the
	Xdata file creating the list of indexes and seek positions, write that
	Xinformation out to a file - then the next time the program is run with
	Xthat same file, the dates can be checked, and the index file can be
	Xread in if it is still newer (i.e. the data file has not changed). This
	Xwould greatly improve the initialization time for larger data files.
	X.RE
	X.IP 2) 
	X.RS
	XCache the most recent records in memory (and perhaps sort the fields
	Xin them).  In those cases where a program goes back and forth between a
	Xfew records (as often happens in the genealogy program when following
	Xchild pointers, parent pointers, etc.), this would help to speed up
	Xthe accessing.  However, remember that unix alreadys caches some disk
	Xio, so this may not be as big a win as it seems at first.  (Try running
	Xthe geneal program - actually it's not all that slow, considering the
	Xway it reads the data file!)
	X.RE
	X
	X.NH 2 
	XIndex
	X.R
	Ximplements a large dynamic virtual array.  Each location in the
	Xarray is allowed to contain an integer (or a pointer, if you have more
	Xdata to store).  The routines allow you to set or get that value
	X(integer or pointer) for a specified index (conceptually the index
	Xinto a large table).  Internally, the data are stored in a number of
	Xsmaller tables, so that unused locations in the array need not take
	Xup memory space.  For example, if you needed an array with indexes of
	X1 and 1000000, the amount of storage needed would be something like
	X1K (due to chunk size).  The approach used works well for arrays with
	Xclusters of dense use, e.g. the number 1 to 1000, 1M to 1M+1000, 10M to
	X10M+1000, etc.  It does not work well for sparse but regular distributions,
	Xe.g. 1K, 2K, 3K, etc.
	X
	XThe index table is implemented by a multi-level table.  The bottom level
	Xtable contains N data items; the next level up contains N pointers to
	Xbottom level tables; the next level up contains N pointers to first
	Xlevel pointer tables, etc. as far as needed.  The number N can be selected
	Xin the initialization call for an array.  When the set routine is called,
	Xenough tables are built to access the requested index.  When the get
	Xroutine is called, those tables are then followed to get to the data.
	XThus the size of the table can grow as needed.
	X
	X.NH 2 
	XPagemap
	X.R
	Xis an embryonic module used to generate a page of character
	Xdata when it is desired to place things at particular locations on
	Xthe page.  The caller first initializes a page (giving the size), and
	Xthen calls routines to output strings and characters to particular
	Xlocations (row/column) on the page.  At the end, he calls a function
	Xto output the page.  This function was written in order to do the
	Xfamily tree part of geneal, but so far has not seen that use.
	X
	X
	X.NH 
	XGeneal specific files
	X.LP
	XThe geneal program has a number of non-general files intended only
	Xfor use in this program.  These were mentioned above and will be
	Xdiscussed in a little more detail here.
	X
	X.NH 2 
	XGeneal
	X.R
	Xis the main program.  It scans the command line for arguments
	Xand switches, calls any initialization functions, and dispatches to
	Xthe appropriate function for processing.
	X
	X.NH 2 
	XFamgetdat
	X.R
	Xis the basic interface to dataman.  It is used to read certain
	Xitems of data for a particular person and return a string.  For example,
	Xone of the functions reads the birth date and place, formats them into
	Xa string ("b: 12-Oct-1855, Arlington, VA") and returns a pointer to that
	Xstring.  This type of routine is used to build up a list of information
	Xabout someone, to be output in some particular format.
	X
	X.NH 2 
	XFamily
	X.R
	Xis a function to output information about a family in a particular
	Xformat.  This function is invoked by a switch on the command line.
	XThe family page consists of information about the parents, their children,
	Xand the children's spouses.  This function calls famgetdat a lot to collect
	Xits information, then formats it and outputs it.  Mostly pretty
	Xstraightforward code.
	X
	X.NH 2 
	XFamtree
	X.R
	Xis the routine which eventually will draw family trees.  At the
	Xmoment there is not very much there to that end.  It outputs the information
	Xfor one family in the format in which it will appear in the tree.  It
	Xuses pagemap to build up this picture, so you can take a look at it if
	Xyou want to see an example of its use.
	X
	X.NH 2 
	XGbrowse
	X.R
	Xis the module which controls browsing through the data.  This is
	Xa very simple control module at the moment, but should eventually grow to
	Xhave a much more sophisticated interface to allow searching of the data.
	X
	X.NH 2 
	XIndivs
	X.R
	Xcreates a short form data page for an individual.
	X
	XHave fun and send me your improvements!
	X
	X			-Jim McBeath
	X			 15-Jan-1985
	X			-Terry L. Ridder
	X			 29-Aug-1985
SHAR_EOF
if test 7963 -ne "`wc -c < 'pgmr.doc'`"
then
	echo shar: error transmitting "'pgmr.doc'" '(should have been 7963 characters)'
fi
chmod +x 'pgmr.doc'
fi # end of overwriting check
echo shar: extracting "'pgmr.man'" '(9652 characters)'
if test -f 'pgmr.man'
then
	echo shar: will not over-write existing file "'pgmr.man'"
else
sed 's/^	X//' << \SHAR_EOF > 'pgmr.man'
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X            Programmer Documentation for geneal
	X
	X
	X                 Jim McBeath (jimmc) at SCI
	X                      Terry L. Ridder
	X
	X                   Silcon Compilers Inc.
	X                 The Terry L. Ridder Family
	X
	X
	X
	X                          _A_B_S_T_R_A_C_T
	X
	X          This document describes  some  of  the  files
	X     used  in geneal.  It is intended to assist someone
	X     who may want to fix a bug or improve the  program,
	X     or  perhaps  use  one  of  the general modules for
	X     another program.  If you do any of the  above,  we
	X     would be interested in hearing about it.
	X
	X
	X
	XAug 29, 1985
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X            Programmer Documentation for geneal
	X
	X
	X                 Jim McBeath (jimmc) at SCI
	X                      Terry L. Ridder
	X
	X                   Silcon Compilers Inc.
	X                 The Terry L. Ridder Family
	X
	X
	X
	X_1.  _B_A_C_K_G_R_O_U_N_D
	X
	XThe geneal program is divided up into a  number  of  general
	Xpurpose  files  and  some special files specifically for the
	Xgeneal program.
	X
	X        The general files include:
	X            dataman.c   Simple reader for formatted data file.
	X            errorman.c  Error message routines.
	X            index.c     Routines to manipulate large virtual
	X                        arrays.
	X            pagemap.c   Build up an image of a page in memory
	X                        and output it.
	X            strsav.c    Save a malloc'ed copy of a string.
	X            tprintf.c   sprintf into a malloc'ed string.
	X            vsprintf.c  sprintf with a vector of arguments.
	X            xalloc.c    allocate memory and die if no more.
	X
	X
	X        The geneal-specific files include:
	X            geneal.c    main program for geneal (switches etc).
	X            famgetdat.c routines to generate one-line strings
	X                        of data.
	X            family.c    generate a page of info about a family.
	X            famtree.c   generate a family tree (incomplete!).
	X            gbrowse.c   browse through the data.
	X            indivs.c    generate info about an individual.
	X
	X
	X
	X_2.  _G_e_n_e_r_a_l _f_i_l_e_s
	X
	XMost of the general files are  simple,  and  can  be  easily
	Xunderstood  by  inspection.   The  ones  which  deserve more
	Xextensive comment are dataman, index, and pagemap.
	X
	X
	X
	X
	X
	X
	X
	X
	X                       Aug 29, 1985
	X
	X
	X
	X
	X
	X                           - 2 -
	X
	X
	X_2._1.   _D_a_t_a_m_a_n  is  the  interface  to  the  datafile.   The
	Xdatafile   is   in  a  particular  format  (records,  lines,
	Xkeywords/values) which is decsribed at the beginning of that
	Xfile.   The  routines  in  this module allow access to those
	Xdata items, typically given a record number  and  a  keyword
	Xname. There were two primary considerations behind selecting
	Xthe format used in the data file and the techniques used  to
	Xread that file:
	X
	X1)
	X          It should be in a text format so that  it  can  be
	X          edited  by a text editor (I didn't want to have to
	X          write a special datafile editor) and so that it is
	X          human  readable  (so  it could be used even before
	X          all the output routines were written for any  par-
	X          ticular program);
	X
	X2)
	X          The program should be  able  to  handle  extremely
	X          large files.
	X
	XThe current implementation of DATAMAN works as follows: dur-
	Xing  initialization,  it scans through the data file looking
	Xfor the start of each record.  It then reads in  the  record
	Xnumber  (an arbitrary but unique integer) and records (using
	Xthe INDEX module) the seek location in  the  file  for  that
	Xrecord.   When  an  access request is processed, it seeks to
	Xthe location for that record and then scans until  it  finds
	Xthe  requested  keyword.  While this may not be particularly
	Xfast, it does satisfy the above two requirements  of  simple
	Xtext  file  format and the ability to handle extremely large
	Xfiles.  It is true that the initialization phase would  take
	Xmuch  longer  for a very large file, but the access time for
	Xany given item should be independent of file size.
	X
	XThere are of  course  some  optimizations  and  improvements
	Xwhich could be made here.  The first two on my list are:
	X
	X1)
	X          After scanning through the data file creating  the
	X          list  of  indexes  and  seek positions, write that
	X          information out to a file - then the next time the
	X          program  is run with that same file, the dates can
	X          be checked, and the index file can be read  in  if
	X          it  is  still  newer  (i.e.  the data file has not
	X          changed). This would greatly improve the initiali-
	X          zation time for larger data files.
	X
	X2)
	X          Cache the  most  recent  records  in  memory  (and
	X          perhaps  sort the fields in them).  In those cases
	X          where a program goes back and forth between a  few
	X          records (as often happens in the genealogy program
	X          when following child  pointers,  parent  pointers,
	X
	X
	X
	X                       Aug 29, 1985
	X
	X
	X
	X
	X
	X                           - 3 -
	X
	X
	X          etc.),  this would help to speed up the accessing.
	X          However, remember that unix alreadys  caches  some
	X          disk  io,  so  this  may not be as big a win as it
	X          seems at first.  (Try running the geneal program -
	X          actually  it's  not all that slow, considering the
	X          way it reads the data file!)
	X
	X
	X_2._2.  _I_n_d_e_x implements a large dynamic virtual array.   Each
	Xlocation in the array is allowed to contain an integer (or a
	Xpointer, if you have more  data  to  store).   The  routines
	Xallow  you to set or get that value (integer or pointer) for
	Xa specified index  (conceptually  the  index  into  a  large
	Xtable).   Internally,  the  data  are  stored in a number of
	Xsmaller tables, so that unused locations in the  array  need
	Xnot  take  up  memory  space.  For example, if you needed an
	Xarray with indexes of 1 and 1000000, the amount  of  storage
	Xneeded  would be something like 1K (due to chunk size).  The
	Xapproach used works well for arrays with clusters  of  dense
	Xuse,  e.g.  the  number  1  to  1000,  1M to 1M+1000, 10M to
	X10M+1000, etc.  It does not work well for sparse but regular
	Xdistributions, e.g. 1K, 2K, 3K, etc.
	X
	XThe index table is implemented by a multi-level table.   The
	Xbottom  level table contains N data items; the next level up
	Xcontains N pointers to bottom level tables; the  next  level
	Xup  contains  N pointers to first level pointer tables, etc.
	Xas far as needed.  The number N can be selected in the  ini-
	Xtialization  call  for  an  array.   When the set routine is
	Xcalled, enough tables are  built  to  access  the  requested
	Xindex.   When  the  get  routine is called, those tables are
	Xthen followed to get to the data.   Thus  the  size  of  the
	Xtable can grow as needed.
	X
	X
	X_2._3.  _P_a_g_e_m_a_p is an embryonic module used to generate a page
	Xof character data when it is desired to place things at par-
	Xticular locations on the page.  The caller first initializes
	Xa  page (giving the size), and then calls routines to output
	Xstrings and characters to particular locations  (row/column)
	Xon  the page.  At the end, he calls a function to output the
	Xpage.  This function was written in order to do  the  family
	Xtree part of geneal, but so far has not seen that use.
	X
	X
	X
	X_3.  _G_e_n_e_a_l _s_p_e_c_i_f_i_c _f_i_l_e_s
	X
	XThe  geneal  program  has  a  number  of  non-general  files
	Xintended only for use in this program.  These were mentioned
	Xabove and will be discussed in a little more detail here.
	X
	X
	X
	X
	X
	X
	X                       Aug 29, 1985
	X
	X
	X
	X
	X
	X                           - 4 -
	X
	X
	X_3._1.  _G_e_n_e_a_l is the main program.  It scans the command line
	Xfor  arguments  and switches, calls any initialization func-
	Xtions, and dispatches to the appropriate function  for  pro-
	Xcessing.
	X
	X
	X_3._2.  _F_a_m_g_e_t_d_a_t is the basic interface to  dataman.   It  is
	Xused  to  read certain items of data for a particular person
	Xand return a string.  For  example,  one  of  the  functions
	Xreads  the  birth date and place, formats them into a string
	X("b: 12-Oct-1855, Arlington, VA") and returns a  pointer  to
	Xthat  string.   This  type  of routine is used to build up a
	Xlist of information about someone, to be output in some par-
	Xticular format.
	X
	X
	X_3._3.  _F_a_m_i_l_y is a function to  output  information  about  a
	Xfamily  in a particular format.  This function is invoked by
	Xa switch on the command line.  The family page  consists  of
	Xinformation  about  the  parents,  their  children,  and the
	Xchildren's spouses.  This function calls famgetdat a lot  to
	Xcollect  its  information,  then  formats it and outputs it.
	XMostly pretty straightforward code.
	X
	X
	X_3._4.  _F_a_m_t_r_e_e is the routine which eventually will draw fam-
	Xily  trees.   At  the moment there is not very much there to
	Xthat end.  It outputs the information for one family in  the
	Xformat in which it will appear in the tree.  It uses pagemap
	Xto build up this picture, so you can take a look  at  it  if
	Xyou want to see an example of its use.
	X
	X
	X_3._5.  _G_b_r_o_w_s_e is the module which controls browsing  through
	Xthe  data.   This  is  a  very  simple control module at the
	Xmoment, but should eventually  grow  to  have  a  much  more
	Xsophisticated interface to allow searching of the data.
	X
	X
	X_3._6.  _I_n_d_i_v_s creates a short form data page for  an  indivi-
	Xdual.
	X
	XHave fun and send me your improvements!
	X
	X               -Jim  McBeath                     15-Jan-1985
	X               -Terry L. Ridder                 29-Aug-1985
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X
	X                       Aug 29, 1985
	X
	X
SHAR_EOF
echo shar: 130 control characters may be missing from "'pgmr.man'"
if test 9652 -ne "`wc -c < 'pgmr.man'`"
then
	echo shar: error transmitting "'pgmr.man'" '(should have been 9652 characters)'
fi
chmod +x 'pgmr.man'
fi # end of overwriting check
echo shar: extracting "'strsav.c'" '(426 characters)'
if test -f 'strsav.c'
then
	echo shar: will not over-write existing file "'strsav.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'strsav.c'
	X/* strsav - make a copy of a string and return a pointer to it */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit  6-Jan-85 22:21:20 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	Xchar *
	Xstrsav(ss)
	Xchar *ss;
	X{
	Xchar *dd;
	X
	X    dd = (char *)xalloc(strlen(ss) + 1, "strsav");
	X    strcpy(dd, ss);		/* make a copy of the string */
	X    return dd;			/* return the copy */
	X}
	X
	X/* end */
SHAR_EOF
if test 426 -ne "`wc -c < 'strsav.c'`"
then
	echo shar: error transmitting "'strsav.c'" '(should have been 426 characters)'
fi
chmod +x 'strsav.c'
fi # end of overwriting check
echo shar: extracting "'tprintf.c'" '(509 characters)'
if test -f 'tprintf.c'
then
	echo shar: will not over-write existing file "'tprintf.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'tprintf.c'
	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/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 08:59:43 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#define BUFSIZ 1000
	X
	Xextern char *strsav();
	X
	X/* VARARGS1 */
	Xchar *
	Xtprintf(fmt, args)
	Xchar *fmt;
	X{
	Xchar buf[BUFSIZ];
	X
	X    vsprintf(buf, fmt, &args);	/* printf the string */
	X    return strsav(buf);		/* return a copy */
	X}
	X
	X/* end */
SHAR_EOF
if test 509 -ne "`wc -c < 'tprintf.c'`"
then
	echo shar: error transmitting "'tprintf.c'" '(should have been 509 characters)'
fi
chmod +x 'tprintf.c'
fi # end of overwriting check
echo shar: extracting "'vsprintf.c'" '(745 characters)'
if test -f 'vsprintf.c'
then
	echo shar: will not over-write existing file "'vsprintf.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'vsprintf.c'
	X/* @(#)sprintf.c	4.1 (Berkeley) 12/21/80 */
	X/* vsprintf from sprintf */
	X/* Created from unix sprintf by Jim McBeath (jimmc) at SCI */
	X/* last edit 19-Jan-85 09:00:15 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	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/* VARARGS2 */
	Xchar *vsprintf(str, fmt, argv)
	Xchar *str, *fmt;
	X{
	X	struct _iobuf _strbuf;
	X
	X	_strbuf._flag = _IOWRT + _IOSTRG;
	X	_strbuf._ptr = str;
	X	_strbuf._cnt = 32767;
	X	_doprnt(fmt, argv, &_strbuf);
	X	putc('\0', &_strbuf);
	X	return(str);
	X}
SHAR_EOF
if test 745 -ne "`wc -c < 'vsprintf.c'`"
then
	echo shar: error transmitting "'vsprintf.c'" '(should have been 745 characters)'
fi
chmod +x 'vsprintf.c'
fi # end of overwriting check
echo shar: extracting "'xalloc.c'" '(673 characters)'
if test -f 'xalloc.c'
then
	echo shar: will not over-write existing file "'xalloc.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'xalloc.c'
	X/* xalloc - allocate memory, give error message and die if no more */
	X/* Written by Jim McBeath (jimmc) at SCI */
	X/* last edit 15-Sep-84 16:50:25 by jimmc (Jim McBeath) */
	X/* last edit 31-Aug-85 13:00:00 by tlr (Terry L. Ridder) */
	X
	X#include <stdio.h>
	X
	X#define ERROR_EXIT 1
	X
	Xstatic int totalused = 0;
	X
	Xchar *
	Xxalloc(size, msg)
	Xint size;		/* number of bytes to allocate */
	Xchar *msg;		/* error string */
	X{
	Xchar *x;
	X
	X    x = (char *)malloc(size);
	X    if (x == 0)
	X    {
	X	fprintf(stderr, "\nNo more memory (%s)\n", msg);
	X	fprintf(stderr, "Previously used: %d; this request: %d\n",
	X			totalused, size);
	X	exit(ERROR_EXIT);
	X    }
	X    totalused += size;
	X    return x;
	X}
	X
	X/* end */
SHAR_EOF
if test 673 -ne "`wc -c < 'xalloc.c'`"
then
	echo shar: error transmitting "'xalloc.c'" '(should have been 673 characters)'
fi
chmod +x 'xalloc.c'
fi # end of overwriting check
#	End of shell archive
exit 0