rsalz@uunet.uu.net (Rich Salz) (03/10/89)
Submitted-by: Jim McBeath <voder!sci!gumby!jimmc> Posting-number: Volume 18, Issue 12 Archive-name: geneal/part02 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 2 (of 4)." # Contents: Makefile PGMR.DOC famlists.c fgsubs.c gconsist.c index.c # lists.c misc.c # Wrapped by rsalz@fig.bbn.com on Thu Mar 9 15:55:00 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(4743 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X#Makefile for geneal X#last edit 11-Jan-1988 09:29:05 by jimmc () X XPROGRAM = geneal XDEST = /tmp X X#Program to pack file into shell archive XSHAR = shar X X#Program to check for symbol name clashes XCLASH = clash X XMKMF = mkmf X XMAKE = make $(MFLAGS) XMAKEFILE = Makefile X XSPINDIR = ../spin X XBKPMACH = wheel XBKPDIR = geneal/geneal.bak X XINCLUDE = -I$(SPINDIR) XCCOPTS = -g X X# careful with this variable. it is really set down in target "depend:" XCFLAGS = $(CCOPTS) -I../spin X XLINTFLAGS = -bauz $(INCLUDE) XLINTLIBS = $(SPINDIR)/llib-lspin.a.ln X XEXTHDRS = ../spin/spin.h \ X ../spin/xalloc.h \ X /usr/include/ctype.h \ X /usr/include/ctype.h \ X /usr/include/stdio.h \ X /usr/include/strings.h \ X /usr/include/sys/stat.h \ X /usr/include/sys/types.h X XHDRS = dataman.h \ X famntree.h \ X geneal.h \ X index.h \ X pagemap.h X XLDFLAGS = -g X XLINKER = cc X XMAKEFILE = Makefile X XOBJS = browse.o \ X dataman.o \ X dates.o \ X datesort.o \ X dlists.o \ X errorman.o \ X famatree.o \ X famdtree.o \ X family.o \ X familyh.o \ X famlists.o \ X famntree.o \ X fgdat.o \ X fgsubs.o \ X gconsist.o \ X geneal.o \ X index.o \ X indivs.o \ X lists.o \ X misc.o \ X pagemap.o \ X strings.o \ X vsprintf.o X XSRCS = browse.c \ X dataman.c \ X dates.c \ X datesort.c \ X dlists.c \ X errorman.c \ X famatree.c \ X famdtree.c \ X family.c \ X familyh.c \ X famlists.c \ X famntree.c \ X fgdat.c \ X fgsubs.c \ X gconsist.c \ X geneal.c \ X index.c \ X indivs.c \ X lists.c \ X misc.c \ X pagemap.c \ X strings.c \ X vsprintf.c X XLIBS = $(SPINDIR)/spin.a X XPRINT = pr X XDOCFILES = README History PGMR.DOC geneal.n XSHARFILES1 = $(DOCFILES) $(MAKEFILE) $(HDRS) sample.dat XSHARFILES2 = [a-eh-zA-Z]*.c XSHARFILES3 = [fg]*.c XSHAROUT1 = $(PROGRAM).1.sh XSHAROUT2 = $(PROGRAM).2.sh XSHAROUT3 = $(PROGRAM).3.sh X Xall: $(PROGRAM) X Xshar: $(SHAROUT1) $(SHAROUT2) $(SHAROUT3) X Xclash:; $(CLASH) $(HDRS) $(SRCS) X Xman: $(PROGRAM).n X nroff -man $(PROGRAM).n > $(PROGRAM).man.new X mv $(PROGRAM).man.new $(PROGRAM).man X X$(SHAROUT1): $(SHARFILES1) X $(SHAR) -n 1 -e 3 $(SHARFILES1) > $(SHAROUT1) X X$(SHAROUT2): $(SHARFILES2) X $(SHAR) -n 2 -e 3 $(SHARFILES2) > $(SHAROUT2) X X$(SHAROUT3): $(SHARFILES3) X $(SHAR) -n 3 -e 3 $(SHARFILES3) > $(SHAROUT3) X X$(PROGRAM): $(OBJS) $(LIBS) X @echo -n "Loading $(PROGRAM) ... " X @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -lm -o $(PROGRAM).new X @mv -f $(PROGRAM).new $(PROGRAM) X @echo "done" X Xclean: tidy X @rm -f $(PROGRAM) X Xtidy:; @rm -f $(OBJS) X Xdepend: $(XDEP) X @echo Updating $(MAKEFILE) ... X @$(MKMF) -f $(MAKEFILE) \ X CFLAGS='$$(CCOPTS) $(INCLUDE)' X# PROGRAM makes mkmf use p.Makefile template X# PROGRAM=$(PROGRAM) 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 Xbackup:; tar chf - $(HDRS) $(SRCS) $(MAKEFILE) | \ X rsh $(BKPMACH) 'cd $(BKPDIR); tar xBf -' X### Xbrowse.o: /usr/include/stdio.h geneal.h Xdataman.o: /usr/include/stdio.h /usr/include/sys/types.h \ X /usr/include/sys/stat.h \ X /usr/include/ctype.h /usr/include/strings.h index.h dataman.h Xdates.o: /usr/include/stdio.h /usr/include/ctype.h /usr/include/strings.h \ X geneal.h Xdatesort.o: /usr/include/stdio.h ../spin/xalloc.h geneal.h Xdlists.o: /usr/include/stdio.h geneal.h Xerrorman.o: /usr/include/stdio.h /usr/include/strings.h Xfamatree.o: /usr/include/stdio.h geneal.h Xfamdtree.o: /usr/include/stdio.h geneal.h /usr/include/ctype.h Xfamily.o: /usr/include/stdio.h /usr/include/ctype.h geneal.h pagemap.h Xfamilyh.o: /usr/include/stdio.h /usr/include/ctype.h /usr/include/strings.h \ X geneal.h Xfamlists.o: /usr/include/stdio.h geneal.h Xfamntree.o: /usr/include/stdio.h /usr/include/ctype.h \ X /usr/include/strings.h geneal.h famntree.h ../spin/xalloc.h Xfgdat.o: /usr/include/stdio.h /usr/include/strings.h geneal.h \ X ../spin/xalloc.h Xfgsubs.o: /usr/include/stdio.h /usr/include/strings.h dataman.h geneal.h \ X ../spin/xalloc.h Xgconsist.o: /usr/include/stdio.h geneal.h Xgeneal.o: /usr/include/stdio.h /usr/include/ctype.h ../spin/spin.h geneal.h Xindex.o: index.h Xindivs.o: /usr/include/stdio.h geneal.h ../spin/xalloc.h Xlists.o: /usr/include/stdio.h ../spin/xalloc.h geneal.h ../spin/spin.h Xmisc.o: /usr/include/stdio.h /usr/include/strings.h ../spin/spin.h geneal.h Xpagemap.o: pagemap.h ../spin/xalloc.h /usr/include/stdio.h Xstrings.o: /usr/include/ctype.h /usr/include/strings.h ../spin/xalloc.h Xvsprintf.o: /usr/include/stdio.h END_OF_FILE if test 4743 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'PGMR.DOC' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'PGMR.DOC'\" else echo shar: Extracting \"'PGMR.DOC'\" \(7887 characters\) sed "s/^X//" >'PGMR.DOC' <<'END_OF_FILE' XProgrammer Documentation for geneal 8.Jan.88 XWritten by Jim McBeath (jimmc) at SCI X 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, I would be interested in hearing about it. X XGeneal uses the spin library and some include files from that directory; Xthis document does not describe those file. X XThe geneal program is divided up into a number of general purpose files Xand some special files specifically for the geneal program. XThe general files include: X dataman.c Simple reader for formatted data file X errorman.c Error message routines X fgdatsubs.c Routines to simply getting info from the data file X index.c Routines to manipulate large virtual arrays X pagemap.c Build up an image of a page in memory and output it X strings.c string manipulation routines X vsprintf.c sprintf with a vector of arguments XThe geneal-specific files include: X browse.c the browse routines (T*) X dates.c routines to reformat dates (used for BD and Ann lists) X datesort.c routines to sort dates (for BD and Ann lists) X dlists.c more routines to manipulate dates X fgdat.c routines to generate one-line strings of data X family.c generate a page of info about a family X familyh.c generate alternate format page of info about a family X famatree.c generate simple text ancestor trees X famdtree.c generate simple text descendant trees X famlists.c routines to deal with id lists X famntree.c generate treepar format output for family trees X gconsist.c check consistency of data X geneal.c main program for geneal (includes spin function defs) X indivs.c generate info about an individual X lists.c id list manipulation routines X misc.c miscellaneous routines X 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 XDATAMAN is the interface to the datafile. The datafile is in a particular Xformat (records, lines, keywords/values) which is described 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: 1) It Xshould 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); 2) The program should be able to Xhandle extremely large files. X XThe current implementation of DATAMAN works as follows: during initialization, Xif there is not already an existing index file, it creates one by Xscanning 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. X XINDEX implements 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 XPAGEMAP is 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 originally written in order to Xdo the family tree part of geneal, but that was eventually done in Xa different manner. X X 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 XBROWSE is the module which controls browsing through the data. This is Xwhere all the T* routines are. X XDATES, DATESORT, and DLIST are all routines which deal with dates. X XFGDAT is 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 XFAMILY and FAMILYH are functions to output information about a family in Xa particular format. The family page consists of information about the Xparents, their children, and the children's spouses. These functions Xcall fgdat a lot to collect information, then format and outputs it. XMostly pretty straightforward code. X XFAMATREE is a function to produce simple ancestor trees. These trees Xare produced using normal ascii characters on a printing terminal. X XFAMDTREE is a function to produce simple descendant trees. As in famatree, Xthey are produced with normal ascii characters. X XFAMLISTS contains the data-dependent list generation and manipulation Xroutines (some of the L* routines). See also LISTS. X XFAMNTREE is the routine which outputs treepar files which can be fed into Xthe treepar program to draw trees. X XGCONSIST is the data consistency checker. It looks for such things as Xreferences which are not bi-directional (e.g. between parent and child), Xetc. X XGENEAL is the main program. It scans the command line for arguments Xand switches, calls any initialization functions, initializes the spin Xparser and defines all the functions available to the user. XIf you are looking to make modifications to a specific command, you Xshould look at the table of functions at the end of this file to see Xwhat C function gets called for each user-visible function. X XINDIVS creates a short form data page for an individual. X XLISTS contains the data-independent list manipulation routines X(some of the L* commands). See also FAMLISTS. X XMISC contains a bunch of random stuff. Much of this has to do with Xinterfacing to the spin interpreter, doing such things as converting Xfrom lists to arrays and back. All of the G* commands are in this file. X XHave fun and send me your improvements! X X -Jim McBeath X 8.Jan.1988 END_OF_FILE if test 7887 -ne `wc -c <'PGMR.DOC'`; then echo shar: \"'PGMR.DOC'\" unpacked with wrong size! fi # end of 'PGMR.DOC' fi if test -f 'famlists.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'famlists.c'\" else echo shar: Extracting \"'famlists.c'\" \(4714 characters\) sed "s/^X//" >'famlists.c' <<'END_OF_FILE' X/* famlists.c - routines to generate or modify lists of id numbers X * X * 18.Aug.87 jimmc Initial defintion X * 8.Jan.88 jimmc Lint cleanup X * 18.Jan.88 jimmc Add limit to famalist, famdlist, make them take input list X * 19.Jan.88 jimmc Call fgenum instead of enumIndex X */ X X#include <stdio.h> X#include "geneal.h" X Xstatic Xfamafsub(clist,famid,n) /* add an individual */ XGroup *clist; Xint famid; Xint n; X{ Xint hid,wid; X X GroupSortedAdd(clist,famid); X if (n==1) return; /* return if this was the last one */ X hid = fgnum(famid,"H"); X wid = fgnum(famid,"W"); X if (hid>0) famaisub(clist,hid,n-1); X if (wid>0) famaisub(clist,wid,n-1); X} X Xstatic Xfamaisub(clist,id,n) /* add an individual */ XGroup *clist; Xint id; Xint n; X{ Xint famid; X X famid = fgnum(id,"P"); X if (famid<=0) { X GroupSortedAdd(clist,id); X return; X } X famafsub(clist,famid,n); X} X Xint Xfamalist(ac,av,pav,n) Xint ac; Xint *av; Xint **pav; Xint n; X{ Xint i; Xint tac,rac,nac; Xint *tav,*rav,*nav; X X rac = 0; X rav = 0; X for (i=0; i<ac; i++) { X nac = famaidlist(av[i],&nav,n); X tac = llunion(rac,rav,nac,nav,&tav); X if (nav) free((char *)nav); X rac = tac; X rav = tav; X } X *pav = rav; X return rac; X} X Xstatic Xint /* returns count of entries in list */ Xfamaidlist(id,pav,n) /* list of ancestors */ Xint id; /* id to get list for */ Xint **pav; /* where to return list pointer */ Xint n; /* number of generations to do (-1 means no limit) */ X{ XGroup clist; X X if (n>=0) n++; /* total number of generations to include in list */ X clist.count = clist.alloc = 0; X clist.n = 0; X switch (fgtype(id)) { X case 'I': X famaisub(&clist,id,n); /* enter recursive search */ X break; X case 'F': X famafsub(&clist,id,n); /* enter recursive search */ X break; X default: X printf("bad type code for id %d\n",id); X break; X } X if (clist.count) *pav = clist.n; X return clist.count; X} X Xstatic Xfamdfsub(clist,famid,n) /* add an individual */ XGroup *clist; Xint famid; Xint n; X{ Xint cnt, *ll; Xint i; X X GroupSortedAdd(clist,famid); X if (n==1) return; X cnt = fglist(famid,"C",&ll); X for (i=0; i<cnt; i++) { X famdisub(clist,ll[i],n-1); X } X free((char *)ll); X} X Xstatic Xfamdisub(clist,id,n) /* add an individual */ XGroup *clist; Xint id; Xint n; X{ Xint cnt, *ll; Xint i; X X cnt = fglist(id,"S",&ll); X for (i=0; i<cnt; i++) { X famdfsub(clist,ll[i],n); X } X free((char *)ll); X} X Xint Xfamdlist(ac,av,pav,n) Xint ac; Xint *av; Xint **pav; Xint n; X{ Xint i; Xint tac,rac,nac; Xint *tav,*rav,*nav; X X rac = 0; X rav = 0; X for (i=0; i<ac; i++) { X nac = famdidlist(av[i],&nav,n); X tac = llunion(rac,rav,nac,nav,&tav); X if (nav) free((char *)nav); X rac = tac; X rav = tav; X } X *pav = rav; X return rac; X} X Xstatic Xint /* returns count of entries in list */ Xfamdidlist(id,pav,n) /* list of descendants */ Xint id; /* id to get list for */ Xint **pav; /* where to return list pointer */ Xint n; /* number of generations to add */ X{ XGroup clist; X X if (n>=0) n++; /* total number of generations to include in list */ X clist.count = clist.alloc = 0; X clist.n = 0; X switch (fgtype(id)) { X case 'I': X GroupSortedAdd(&clist,id); X famdisub(&clist,id,n); /* enter recursive search */ X break; X case 'F': X famdfsub(&clist,id,n); /* enter recursive search */ X break; X default: X printf("bad type code for id %d\n",id); X break; X } X if (clist.count) *pav = clist.n; X return clist.count; X} X Xstatic Group allclist; X X/* ARGSUSED */ Xint Xalladdone(id,v) Xint id; /* index number */ Xint v; /* value (seek offset) */ X{ X GroupSortedAdd(&allclist,id); X return 0; X} X Xint /* returns count of entries in list */ Xalllist(pav) /* list of all indexes in the entire database */ Xint **pav; /* where to return list pointer */ X{ X allclist.count = 0; X fgenum(alladdone); X if (allclist.count) *pav = allclist.n; X return allclist.count; X} X Xint Xlfieldmatch(ac,av,fname,fvalue,pav) Xint ac; /* input list */ Xint *av; Xchar *fname; /* name of field to check */ Xchar *fvalue; /* value to look for */ Xint **pav; /* where to return list pointer */ X{ X int i; X Group clist; X int id; X char *dvalue; X X clist.count = clist.alloc = 0; X clist.n = 0; X for (i=0; i<ac; i++) { X id = av[i]; X dvalue = fgstr(id,fname); X if (strcmp(dvalue,fvalue)==0) { X GroupSortedAdd(&clist,id); X } X freestr(dvalue); X } X if (clist.count) *pav = clist.n; X return clist.count; X} X Xint Xlrefs(ac,av,fname,pav) Xint ac; /* input list */ Xint *av; Xchar *fname; /* name of field to follow references of */ Xint **pav; /* where to return list pointer */ X{ X int i,j; X Group clist; X int id; X int n; X int flist[1000]; X X clist.count = clist.alloc = 0; X clist.n = 0; X for (i=0; i<ac; i++) { X id = av[i]; X n = fgblist(id,fname,flist); X for (j=0; j<n; j++) X GroupSortedAdd(&clist,flist[j]); X } X if (clist.count) *pav = clist.n; X return clist.count; X} X X/* end */ END_OF_FILE if test 4714 -ne `wc -c <'famlists.c'`; then echo shar: \"'famlists.c'\" unpacked with wrong size! fi # end of 'famlists.c' fi if test -f 'fgsubs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'fgsubs.c'\" else echo shar: Extracting \"'fgsubs.c'\" \(5179 characters\) sed "s/^X//" >'fgsubs.c' <<'END_OF_FILE' X/* fgsubs.c - underlying subroutines used from fgdat X * X * All access to the data file should go through this module, so that X * we can properly change over to another data file when needed. X * X * Basically, this file contains routines which do not specifically X * name the fields, whereas routines in fgdat do specifically name fields. X * X * 26.Oct.87 jimmc Extracted from fgdat X * 8.Jan.88 jimmc Lint cleanup X * 19.Jan.88 jimmc Add fgenum, fginit X */ X X/* Functions which return an allocated string are: X * fgstr(n,s) the basic string routine which returns field s X * X * Functions which return an integer are: X * fgnum(n,s) returns the integer value of field s X * fgblist(n,s,av) get a list; return valus is ac, fills array av X * fglist(n,s,avp) get a list; return value is ac, fills pointer avp X * X * Other functions: X * fgbstr(n,s,b) like fgstr, but returns string in buffer b X * fgchar(n) returns single character (first char of data word) X * fgenum(funcp) enumerates all entries in the data file X */ X X#include <stdio.h> X#include <strings.h> X#include "dataman.h" X#include "geneal.h" X#include "xalloc.h" X Xextern struct dpoint *initDataFile(); X Xextern char *dataErrMsg; X Xstatic struct dpoint *gendp; /* data file handle */ Xstatic char *datfilename; Xstatic char *opendatfilename; X X/*..........*/ X Xfgopenfn(fn) Xchar *fn; X{ X fgsetfn(fn); X fgopen(); X} X Xfgsetfn(fn) Xchar *fn; X{ X if (datfilename) freestr(datfilename); X datfilename = strsav(fn); X} X Xfgopen() X{ X if (!datfilename) X fatalerr("No data filename specified"); X gendp = initDataFile(datfilename); X if (!gendp) X fatalerr("error opening data file %s: %s", X datfilename,dataErrMsg); X if (opendatfilename) freestr(opendatfilename); X opendatfilename = datfilename; X datfilename = 0; X} X Xfgclose() X{ X if (gendp) { X closeDataFile(gendp); X gendp = 0; X if (opendatfilename) freestr(opendatfilename); X } X} X X/*..........*/ X Xstatic Xcheckdp() X{ X if (gendp==0) { X fgopen(); X if (gendp==0) fatalerr("no data file open"); X } X /* return and continue */ X} X X/*..........*/ X Xint Xfgenum(funcp) Xint (*funcp)(); X{ X int t; X X checkdp(); X t = enumIndex(gendp->xx,funcp); X return t; X} 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{ X int tt, dd; X char *str; X X checkdp(); X if (n<=0) return -1; X str = getData(gendp,n,s); /* get pointer to data item */ X if (str==0) return -1; /* -1 if no such item */ X tt = sscanf(str,"%d", &dd); /* get the number */ X if (tt!=1) return -1; /* if no succesful scan */ X return dd; /* return the number we found */ X} X X/*..........*/ X Xint Xfgchar(n,s) /* get the first character from a field */ Xint n; /* record to get data from */ Xchar *s; /* name of data item */ X{ X char *word; X X checkdp(); X if (n<=0) return 0; X word = getData(gendp,n,s); X if (!word) return 0; X return word[0]; 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{ X char *str; X X checkdp(); X if (n<=0) return ""; X str = getData(gendp,n,s); /* get pointer to data item */ X if (str==0) return ""; /* null string if no such item */ X return strsav(str); X} X X/*..........*/ X Xint /* returns 1 if found, 0 if not */ Xfgbstr(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 checkdp(); X if (n<=0) { X *b=0; X return 0; X } /* make string null */ X str = getData(gendp,n,s); /* get pointer to data item */ X if (str==0) { 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 Xint /* returns count */ Xfgblist(n,t,av) Xint n; /* id of family */ Xchar *t; /* the keyword tag for the field to read */ Xint *av; /* array to put data into */ X{ X char cstr[200]; X char *cstrp; X int *clist; X int i, ac, tt, dd; X X fgbstr(n,t,cstr); /* get list of kids */ X for (ac=0, cstrp=cstr; cstrp!=NULL && *cstrp!='\0'; ac++) X cstrp=index(cstrp+1,','); /* count separators */ X if (ac==0) return 0; X clist = av; /* put data into his array */ X for(cstrp=cstr, i=0; cstrp!=NULL && *cstrp!='\0'; i++) { X if (i>=ac) fatalerr("loop too far on %s list in fgblist", t); X tt = sscanf(cstrp,"%d",&dd); /* read number */ X if (tt==1) clist[i]=dd; X else { X warning("bad %s list format in family %d", t, n); X clist[i] = dd = -1; X } X cstrp = index(cstrp,','); X if (cstrp!=NULL) cstrp++; X } X if (i!=ac) { X warning("bad %s list format in family %d", t, n); X for (; i<ac; i++) clist[i] = -1; /* fill with -1 */ X } X return ac; /* return count */ X} X X/*..........*/ X Xint /* returns count */ Xfglist(n,t,avp) Xint n; /* id of family */ Xchar *t; /* the keyword of the list to get */ Xint **avp; /* ADDRESS of where to put the av we return */ X{ X int *clist; X int cbuf[1000]; X int i, ac; X X ac = fgblist(n,t,cbuf); X i = (ac==0)? 1 : ac; X clist = XALLOCM(int, i, "fglist"); X for (i=0; i<ac; i++) clist[i] = cbuf[i]; /* copy the list */ X *avp = clist; /* fill in his pointer */ X return ac; /* return count */ X} X X/* end */ END_OF_FILE if test 5179 -ne `wc -c <'fgsubs.c'`; then echo shar: \"'fgsubs.c'\" unpacked with wrong size! fi # end of 'fgsubs.c' fi if test -f 'gconsist.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'gconsist.c'\" else echo shar: Extracting \"'gconsist.c'\" \(6217 characters\) sed "s/^X//" >'gconsist.c' <<'END_OF_FILE' X/* gconsist.c - consistency checker for geneal X * Written by Jim McBeath (jimmc) at SCI X * X * Revision history: X * 24-Jan-85 Jim McBeath Initial definition X * 8-Mar-85 Jim McBeath minor cleanups for lint X * 14.Sep.87 jimmc Add address stuff X * 12.Dec.87 jimmc Allow reference record type ('R') X * 19.Jan.88 jimmc Use fgenum instead of enumIndex X */ X X#include <stdio.h> X#include "geneal.h" X Xstatic int gconerrcount; /* count of errors detected */ Xstatic int gicount; /* number of individuals */ Xstatic int gfcount; /* number of families */ Xstatic int gacount; /* number of addresses */ Xstatic int gmcount; /* number of males */ Xstatic int gfmcount; /* number of females */ X X/*..........*/ X X/* VARARGS1 */ Xstatic Xdataerr(fmt,args) /* print out a data error message */ Xchar *fmt; /* printf style format list */ Xint args; X{ Xchar buf[1000]; X X vsprintf(buf,fmt,&args); X printf("data error: %s\n", buf); X gconerrcount++; /* count the error */ X} X X/*..........*/ X Xstatic int Xicmp(a,b) /* compare two integers for qsort */ Xint *a, *b; X{ X return (*a - *b); X} X X/*..........*/ X Xstatic Xgenumi(x) Xint x; X{ Xchar sbuf[1000]; Xint nlist[1000]; Xint scount, ccount; Xint i; Xint pp; Xint addr; X X gicount++; /* count the individual */ X fgbstr(x,"SX",sbuf); /* look at the sex */ X if (strcmp(sbuf,"M")==0) gmcount++; X else if (strcmp(sbuf,"F")==0) gfmcount++; X pp = fgnum(x,"P"); /* see if parents */ X if (pp>0) X { X ccount = fgbclist(pp,nlist); X if (ccount==0) dataerr( X "person %d claims family %d, which claims no children", X x, pp); X else X { X for (i=0; i<ccount; i++) if (nlist[i]==x) break; X if (i==ccount) dataerr( X "person %d claims family %d, but not vice-versa", X x, pp); X } X } X else ccount=0; X scount = fgbslist(x,nlist); /* add spouse numbers */ X if (scount>0) X { X for (i=0; i<scount; i++) /* check each marriage/union */ X { X if (x!=fgnum(nlist[i],"H") && x!=fgnum(nlist[i],"W")) X dataerr("person %d claims marriage %d but not vice-versa", X x, nlist[i]); X } X qsort((char*)nlist,scount,sizeof(nlist[0]),icmp); /* sort list */ X for (i=0; i<scount-1; i++) if (nlist[i]==nlist[i+1]) X dataerr("duplicate marriage number %d in person %d", X nlist[i], x); X } X addr = fgnum(x,"ADDR"); X if (addr>0) { X if (fgnum(addr,"WHO")!=x) X dataerr("person %d points to address %d, but not vice-versa", X x, addr); X } X} X Xstatic Xgenumf(x) Xint x; X{ Xchar sbuf[1000]; Xint nlist[1000]; Xint scount, ccount; Xint i; Xint hh, ww; Xint addr; X X gfcount++; /* count the family */ X ccount = fgbclist(x,nlist); X if (ccount>0) X { X for (i=0; i<ccount; i++) /* check children */ X { X if (fgnum(nlist[i],"P")!=x) X dataerr("family %d claims child %d, but not vice-versa", X x, nlist[i]); X } X qsort((char*)nlist,ccount,sizeof(nlist[0]),icmp); X for (i=0; i<ccount-1; i++) if (nlist[i]==nlist[i+1]) X dataerr("duplicate child %d in family %d", nlist[i], x); X } X hh = fgnum(x,"H"); /* check out the husband */ X ww = fgnum(x,"W"); /* check out the wife */ X for (i=0; i<ccount; i++) X { X if (hh>0 && nlist[i]==hh) X dataerr("person %d is both husband and child in family %d", X hh, x); X if (ww>0 && nlist[i]==ww) X dataerr("person %d is both wife and child in family %d", X ww, x); X } X if (hh>0) X { X if (ww==hh) X dataerr("family %d claims %d as both husband and wife", X x, hh); /* not likely to happen, but what the heck */ X fgbstr(hh,"SX",sbuf); /* look at his sex */ X if (strcmp(sbuf,"M")!=0) X dataerr( X"family %d claims husband %d, who is not designated as a male", x, hh); X scount = fgbslist(hh,nlist); X for (i=0; i<scount; i++) if (nlist[i]==x) break; X if (i==scount) X dataerr("family %d claims husband %d, but not vice-versa", X x, hh); X } X if (ww>0) X { X fgbstr(ww,"SX",sbuf); /* look at her sex */ X if (strcmp(sbuf,"F")!=0) X dataerr( X"family %d claims wife %d, who is not designated as a female", x, ww); X scount = fgbslist(ww,nlist); X for (i=0; i<scount; i++) if (nlist[i]==x) break; X if (i==scount) X dataerr("family %d claims wife %d, but not vice-versa", X x, ww); X } X addr = fgnum(x,"ADDR"); X if (addr>0) { X if (fgnum(addr,"WHO")!=x) X dataerr("family %d points to address %d, but not vice-versa", X x, addr); X } X} X Xstatic Xgenuma(x) Xint x; X{ Xint who; X X gacount++; X who = fgnum(x,"WHO"); X if (who<=0) dataerr("address %d has no WHO reference",x); X else if (fgnum(who,"ADDR")!=x) X dataerr("address %d points to %d, but not vice-versa",x,who); X} X X/* genum is the function which is called for each record. It is what X * does the consistency checking. X */ X X/* ARGSUSED */ Xint /* returns 0 if OK */ Xgenum(x,d) /* our enumeration function for enumIndex */ Xint x; /* the index number */ Xint d; /* its value */ X{ X X if (x==0) return 0; /* ignore record 0, it's just for comments */ X X switch (fgtype(x)) { X case 'I': /* individual */ X genumi(x); X break; X case 'F': /* family */ X genumf(x); X break; X case 'A': /* address */ X genuma(x); X break; X case 'R': /* reference */ X /* nothing to check in this record type at the moment */ X break; X default: X dataerr("bad type in record %d", x); X break; X } X return 0; /* always continue */ X} X X/*..........*/ X X/* gconsist is the top level consistency checker. */ X Xint /* returns 0 if OK */ Xgconsist() /* check the consistecny of the data */ X{ Xint n; X X gfcount = gicount = gacount = gconerrcount = 0; /* clear data */ X printf("Checking data consistency...\n"); X n = fgenum(genum); X if (n<0) printf("error enumerating indexes\n"); X else /* no errors, give report */ X { X if (gconerrcount>0) X printf("%d data consistency error%s detected\n", X gconerrcount, (gconerrcount==1?"":"s") ); X else printf("No data consistency errors detected\n"); X printf("%d individual%s, %d famil%s, %d address%s\n", X gicount, (gicount==1?"":"s"), X gfcount, (gfcount==1?"y":"ies"), X gacount, (gacount==1?"":"es") ); X gicount -= (gmcount+gfmcount); X /* convert to count of unspeced */ X printf("%d male%s, %d female%s, %d not indicated\n", X gmcount, (gmcount==1?"":"s"), X gfmcount, (gfmcount==1?"":"s"), X gicount, (gicount==1?"":"s") ); X } X if (gconerrcount==0) return 0; /* all OK */ X else return 1; /* error */ X} X X/* end */ END_OF_FILE if test 6217 -ne `wc -c <'gconsist.c'`; then echo shar: \"'gconsist.c'\" unpacked with wrong size! fi # end of 'gconsist.c' fi if test -f 'index.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'index.c'\" else echo shar: Extracting \"'index.c'\" \(7152 characters\) sed "s/^X//" >'index.c' <<'END_OF_FILE' X/* index - index handler for large pseudo-arrays X * Written by Jim McBeath (jimmc) at SCI X * X * Revision history: X * 24-Jan-85 Jim McBeath Add enumIndex function X * 8-Mar-85 Jim McBeath remove unused var numentries from enumIndex X * 17-Apr-86 Jim McBeath Add field nzcount X * 19.Jan.87 J. McBeath Add freeIndex X * 13.Feb.87 J. McBeath Set nzcount to 0 on init X * 8.Jan.99 jimmc Lint cleanup X */ X X/* This module implements a very large pseudo-array. There are four X entry points: to initialize a pseudo-array, to insert an item, X to read an item, and to enumerate the entries in an array. The X array contains integers (which could of course be used for another X 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(), *calloc(); 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{ X struct toplevel *tt; X struct tblblock *dd; X X tt = (struct toplevel *)calloc((unsigned)sizeof(struct toplevel),1); X /* get space for top level block */ X if (!tt) return 0; X dd = (struct tblblock *)calloc((unsigned)sizeof(struct tblblock),1); X /* get space for top level table */ X if (!dd) { X free((char *)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 tt->nzcount = 0; X dd->repnum = TBLSIZ; X dd->count = TBLSIZ; X return tt; /* return pointer to top level block */ X} X X/*..........*/ X XfreeIndex(tt) Xstruct toplevel *tt; X{ X freeBlock(tt->data); X free((char *)tt); X} X Xstatic freeBlock(dd) Xstruct tblblock *dd; X{ X int i; X if (dd->repnum > dd->count) { /* not at lowest level */ X for (i=0; i<dd->count; i++) X if (dd->tdata[i].p) X freeBlock(dd->tdata[i].p); X /* free lower level tables */ X } X free((char *)dd); 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 */ Xlong num; /* the value to put there */ X{ X struct tblblock *dd, *dd0; X X if (indexDebug) { X printf("setIndex: index=%d, value=%d\n", ix, num); X if (!tt) printf("setIndex: no table index\n"); X else if (!(tt->numlevs)) printf("setIndex: no numlevs\n"); X else if (!(tt->data)) printf("setIndex: no data array\n"); X } X if (!tt) return -1; /* check for errors */ X if (!(tt->numlevs)) return -1; X if (!(tt->data)) return -1; X dd = tt->data; /* get data pointer */ X while (ix >= dd->repnum) { /* create a higher level */ X if (indexDebug) X printf("setIndex: %d(ix) > %d(repnum)\n", X ix, dd->repnum); X dd0 = (struct tblblock *)calloc( X (unsigned)sizeof(struct tblblock),1); X /* get space for a higher level */ X if (!dd0) return -1; /* error */ X dd0->repnum = dd->repnum*TBLSIZ; X dd0->count = TBLSIZ; X dd0->tdata[0].p = dd; X /* put in pointer to next level down */ X tt->data = dd0; /* put in new top-level pointer */ X tt->numlevs++; X if (indexDebug) X printf("setIndex: numlevs=%d\n", tt->numlevs); X dd = dd0; X } X while (dd->repnum > dd->count) { X /* scan down to the last level */ X if (indexDebug) printf("setIndex: %d(repnum) > %d(count)\n", X dd->repnum, dd->count); X dd0 = dd->tdata[ix/dd->count].p; X /* get pointer to next table lower */ X if (!dd0) { X /* if no table there, have to make one */ X dd0 = (struct tblblock *)calloc( X (unsigned)sizeof(struct tblblock),1); X if (!dd0) return -1; /* error */ X dd0->repnum = dd->repnum/dd->count; X dd0->count = TBLSIZ; X dd->tdata[ix/dd->count].p = dd0; X /* save pointer to it */ X } X ix %= dd->count; /* lower the index */ X dd = dd0; X } X if (dd->tdata[ix].n) tt->nzcount--; X dd->tdata[ix].n = num; /* put it in */ X if (num) tt->nzcount++; X if (indexDebug) X printf("setIndex: table %X, index %d, value %d\n", dd,ix,num); X return ix; X} X X/*..........*/ X Xlong /* 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{ X struct tblblock *dd, *dd0; X X if (indexDebug) { X printf("getIndex: index=%d\n", ix); X if (!tt) printf("getIndex: no table\n"); X else if (!tt->data) printf("getIndex: no data array\n"); X else if (!tt->numlevs) printf("genIndex: no numlevs\n"); X } X if (!tt) return 0; /* check for errors */ X if (!tt->data) return 0; X if (!tt->numlevs) return 0; X dd = tt->data; X if (ix >= dd->repnum) { X if (indexDebug) X printf("getIndex: index %d > repnum %d\n", X ix,dd->repnum); X return 0; /* we don't have them that high */ X } X while (dd->repnum > dd->count) { /* scan down to bottom level */ X if (indexDebug) printf("getIndex: %d(repnum) > %d(count)\n", X dd->repnum, dd->count); X dd0 = dd->tdata[ix/dd->count].p; X /* get pointer to next level */ X if (!dd0) { X if (indexDebug) printf("getIndex: no table\n"); X return 0; /* nothing there */ X } X ix %= dd->count; X dd = dd0; X } X if (indexDebug) X printf("getIndex: table %X, index %d, value %d\n", X dd, ix, dd->tdata[ix].n); X return dd->tdata[ix].n; /* this is the data entry */ X} X X/*..........*/ X X/* the enumerate function scans throught the table and calls (*f)(x,d) for X * each non-zero entry n in the table. If f returns <>0, the enum routine X * stops scanning and returns an error. (x is the index number, d is its X * value.) X */ Xint /* returns number of entries or <0 on error */ XenumIndex(tt,f) /* enumerate the table */ Xstruct toplevel *tt; /* the table to enumerate */ Xint (*f)(); /* the function to call for each item */ X{ X X if (indexDebug) { X if (!tt) printf("enumIndex: no table index\n"); X else if (!(tt->numlevs)) printf("enumIndex: no numlevs\n"); X else if (!(tt->data)) printf("enumIndex: no data array\n"); X } X if (!tt) return -1; /* check for errors */ X if (!(tt->numlevs)) return -1; X if (!(tt->data)) return -1; X return enum1(tt->data,tt->numlevs,0,f); X /* do the enumeration recursively */ X} X Xstatic int Xenum1(dd,levs,b,f) Xstruct tblblock *dd; /* the datablock to enumerate */ Xint levs; /* the number of levels left to descend */ Xint b; /* the base number for this segment */ Xint (*f)(); /* the function to call */ X{ X int count=0; X int i, n; X int binc; X X if (levs<=1) { X for (i=0; i<TBLSIZ; i++) { /* scan through the table */ X if (dd->tdata[i].n) { X n = (*f)(b+i,dd->tdata[i].n); X if (n!=0) return -1; /* error */ X count++; X } X } X return count; X /* return the number of entries processed */ X } X else { /* not yet at the bottom, keep descending */ X binc = dd->repnum/TBLSIZ; X for (i=0; i<TBLSIZ; i++, b+=binc) { X if (dd->tdata[i].p) { X n = enum1(dd->tdata[i].p,levs-1,b,f); X if (n<0) return n; X count += n; X } X } X } X return count; X} X X/* end */ END_OF_FILE if test 7152 -ne `wc -c <'index.c'`; then echo shar: \"'index.c'\" unpacked with wrong size! fi # end of 'index.c' fi if test -f 'lists.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'lists.c'\" else echo shar: Extracting \"'lists.c'\" \(5191 characters\) sed "s/^X//" >'lists.c' <<'END_OF_FILE' X/* lists.c - list manipulation routines for geneal X * X * 18.Aug.87 jimmc Initial definition X * 28.Sep.87 jimmc Add LAndNot function X * 17.Oct.87 jimmc Convert to spin interface X * 6.Nov.87 jimmc Name change: xalloc to xallocm, xrealloc to xreallom X * 4.Jan.88 jimmc Add LRange X * 8.Jan.88 jimmc Add olisttoiarr; lint cleanup X */ X X#include <stdio.h> X#include "xalloc.h" X#include "geneal.h" X#include "spin.h" X Xextern SPtoken *SPiarrtolist(); X XGroupAppend(group,item) XGroup *group; Xint item; X{ Xstatic char *mm="GroupAppend"; X X if (group->count >= group->alloc) { X if (group->alloc==0) group->alloc=15; X else group->alloc *= 2; X if (group->n) group->n = (int *)xreallocm((char *)group->n, X group->alloc*sizeof(group->n[0]),mm); X else group->n = (int *)xallocm( X group->alloc*sizeof(group->n[0]),mm); X } X group->n[group->count++] = item; X} X X/* Assumes the list is sorted; inserts the new item in sorted order if X * it does not already exist */ XGroupSortedAdd(group,item) XGroup *group; Xint item; X{ Xint i,j; X X /* The following linear search could be replaced X * by something more intelligent, like a binary search. */ X for (i=0; i<group->count; i++) { X if (group->n[i]==item) return; /* already there */ X if (group->n[i]>item) break; X } X GroupAppend(group,item); /* make space for it */ X if (i<group->count-1) { X for (j=group->count-1; j>i; j--) X group->n[j] = group->n[j-1]; X group->n[i] = item; /* insert in sorted order */ X } X} X Xstatic int icmp(a,b) int *a,*b; { return *a - *b; } X Xint Xllunion(ac1,av1,ac2,av2,pav3) Xint ac1, *av1; Xint ac2, *av2; Xint **pav3; /* return value - we malloc an array and return pointer */ X{ XGroup clist; Xint i1,i2; Xint n1,n2; X X qsort((char *)av1,ac1,sizeof(av1[0]),icmp); X qsort((char *)av2,ac2,sizeof(av2[0]),icmp); X clist.count = clist.alloc = 0; X clist.n = 0; X i1 = i2 = 0; X while (i1<ac1 && i2<ac2) { X n1 = av1[i1]; X n2 = av2[i2]; X if (n1<n2) { X if (clist.count==0 || n1>clist.n[clist.count-1]) { X GroupAppend(&clist,n1); X } X i1++; X } X else { /* n1>=n2 */ X if (clist.count==0 || n2>clist.n[clist.count-1]) { X GroupAppend(&clist,n2); X } X i2++; X if (n1==n2) i1++; X } X } X while (i1<ac1) { X n1 = av1[i1]; X if (clist.count==0 || n1>clist.n[clist.count-1]) { X GroupAppend(&clist,n1); X } X i1++; X } X while (i2<ac2) { X n2 = av2[i2]; X if (clist.count==0 || n2>clist.n[clist.count-1]) { X GroupAppend(&clist,n2); X } X i2++; X } X *pav3 = clist.n; X return clist.count; X} X Xstatic int Xllintersect(ac1,av1,ac2,av2,pav3) Xint ac1, *av1; Xint ac2, *av2; Xint **pav3; /* return value - we malloc an array and return pointer */ X{ XGroup clist; Xint i1,i2; Xint n1,n2; X X qsort((char *)av1,ac1,sizeof(av1[0]),icmp); X qsort((char *)av2,ac2,sizeof(av2[0]),icmp); X clist.count = clist.alloc = 0; X clist.n = 0; X i1 = i2 = 0; X while (i1<ac1 && i2<ac2) { X n1 = av1[i1]; X n2 = av2[i2]; X if (n1<n2) i1++; X else if (n1>n2) i2++; X else { /* n1==n2 */ X if (clist.count==0 || n2>clist.n[clist.count-1]) { X GroupAppend(&clist,n2); X } X i1++; i2++; X } X } X *pav3 = clist.n; X return clist.count; X} X Xstatic int Xllandnot(ac1,av1,ac2,av2,pav3) Xint ac1, *av1; Xint ac2, *av2; Xint **pav3; /* return value - we malloc an array and return pointer */ X{ XGroup clist; Xint i1,i2; Xint n1,n2; X X qsort((char *)av1,ac1,sizeof(av1[0]),icmp); X qsort((char *)av2,ac2,sizeof(av2[0]),icmp); X clist.count = clist.alloc = 0; X clist.n = 0; X i2 = 0; X for (i1=0; i1<ac1; i1++) { X n1 = av1[i1]; X for ( ; i2<ac2; i2++) { X n2 = av2[i2]; X if (n1==n2) goto no_insert; X if (n2>n1) break; X } X if (clist.count==0 || n1>clist.n[clist.count-1]) { X GroupAppend(&clist,n1); X } Xno_insert: ; X } X *pav3 = clist.n; X return clist.count; X} X Xstatic int Xllrange(from,to,pav3) Xint from, to; /* range, inclusive */ Xint **pav3; /* return value - we malloc an array and return pointer */ X{ Xint r,i; Xint *v; X X r = to - from + 1; /* number of items in the range */ X if (r<=0) return 0; /* no range */ X v = XALLOC(int,r); X for (i=0; i<r; i++) { X v[i] = from+i; X } X *pav3 = v; X return r; X} X XSPtoken * XLibin2(i1,i2,opfunc) Xint i1, i2; Xint (*opfunc)(); X{ Xint ac3, *av3; XSPtoken *l; X X ac3 = (*opfunc)(i1,i2,&av3); X l = SPiarrtolist(ac3,av3); X free((char *)av3); X return l; X} X XSPtoken * XLRange(i1,i2) Xint i1,i2; X{ X return Libin2(i1,i2,llrange); X} X XSPtoken * XLbinop(l1,l2,opfunc) XSPtoken *l1, *l2; Xint (*opfunc)(); X{ Xint ac1, *av1; Xint ac2, *av2; Xint ac3, *av3; XSPtoken *l; X X ac1 = olisttoiarr(l1,&av1); X ac2 = olisttoiarr(l2,&av2); X ac3 = (*opfunc)(ac1,av1,ac2,av2,&av3); X l = SPiarrtolist(ac3,av3); X free((char *)av3); X return l; X} X XSPtoken * XLIntersect(l1,l2) XSPtoken *l1, *l2; X{ X return Lbinop(l1,l2,llintersect); X} X XSPtoken * XLUnion(l1,l2) XSPtoken *l1, *l2; X{ X return Lbinop(l1,l2,llunion); X} X XSPtoken * XLAndNot(l1,l2) XSPtoken *l1, *l2; X{ X return Lbinop(l1,l2,llandnot); X} X Xint /* returns number of entries in list */ Xolisttoiarr(l,pav) XSPtoken *l; /* list of ints or single int */ Xint **pav; /* where to put the return pointer to array of ints */ X{ Xint ac; Xint *av; X X if (l->type==SPTokInt) { /* special case for single int */ X ac = 1; X av = XALLOC(int,1); X av[0] = l->value.n; X *pav = av; X } X else { X ac = SPlisttoiarr(l,pav); X } X return ac; X} X/* end */ END_OF_FILE if test 5191 -ne `wc -c <'lists.c'`; then echo shar: \"'lists.c'\" unpacked with wrong size! fi # end of 'lists.c' fi if test -f 'misc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'misc.c'\" else echo shar: Extracting \"'misc.c'\" \(5963 characters\) sed "s/^X//" >'misc.c' <<'END_OF_FILE' X/* misc.c - miscellaneous routines for geneal X * X * 17.Aug.87 jimmc Initial definition X * 4.Jan.88 jimmc Add gdblist, annlist, LAll, LFieldMatch, LRefs X * 8.Jan.88 jimmc Add GSetOutput, GGetOutput, GFlushOutput, GSetSep, GGetSep X * gfamily, gfamilyh, gindivs; lint cleanup X * 1.Mar.88 jimmc Make GVersion return a string intead of printing it X */ X X#include <stdio.h> X#include <strings.h> X#include "spin.h" X#include "geneal.h" X Xextern SPtoken *SPiarrtolist(); X Xextern char *genealVersion; Xextern int dataDebug; Xextern int indexDebug; X Xextern char *strsave(); Xextern int olisttoiarr(); X Xchar outfpname[1024+1]; Xchar *sepstr; X Xchar Gflag[256]; Xint Gflagcount = sizeof(Gflag)/sizeof(Gflag[0]); X Xchar Gflagr[256+1]; Xchar *Label; X Xchar * XGFlags(flags) Xchar *flags; X{ Xint i; Xchar *cp, *np; X X if (!flags) flags=""; X switch (flags[0]) { X case '=': X for (i=0; i<Gflagcount; i++) Gflag[i]=0; X /* FALL THROUGH */ X case '+': X for (cp=flags+1; *cp; cp++) { X Gflag[*cp] = 1; X switch (*cp) { /* some special flags */ X case 'D': dataDebug=1; break; X case 'I': indexDebug=1; break; X default: break; /* do nothing */ X } X } X break; X case '-': X for (cp=flags+1; *cp; cp++) { X Gflag[*cp] = 0; X switch (*cp) { /* some special flags */ X case 'D': dataDebug=0; break; X case 'I': indexDebug=0; break; X default: break; /* do nothing */ X } X } X break; X case '?': X case '\0': X break; /* just return the value */ X case 'h': X GFlagsHelp(); X break; X default: X break; /*** should output error message */ X } X for (np=Gflagr, i=0; i<Gflagcount; i++) X if (Gflag[i]) *np++ = i; X *np = '\0'; X return Gflagr; X} X XGFlagsHelp() X{ X printf("GFlags [+-=?][flagchars]\n"); X printf("a enables output of addresses in family pages\n"); X printf("b enables additional birth/death info in famtree\n"); X printf("m includes spouses in famtrees\n"); Xprintf("N enables additional printing of index numbers (only if +n)\n"); X printf("n enables printing of index numbers\n"); X printf("s enables printing of sibling info in atrees\n"); X printf("t include TNOTEs in famtree\n"); X printf("y makes date sorts include year (by default they do not)\n"); X printf("D debug data routines\n"); X printf("I debug index routines\n"); X} X Xchar * XGVersion() X{ X return genealVersion; X} X Xint XGSetOutput(name) Xchar *name; X{ XFILE *f; Xint t; Xchar *mode; Xchar m[4]; X X if (outfp!=stdout && outfp!=stderr) { X t = ferror(outfp) || fclose(outfp); X if (t) { X warning("error closing previous output file %s", X outfpname); X } X } X t = 0; /* assume no errors */ X if (strcmp(name,"stdout")==0) X f = stdout; X else if (strcmp(name,"stderr")==0) X f = stderr; X else { X if (name[0]=='+') { X name++; X mode = "append"; X } X else { X mode = "write"; X } X m[0] = mode[0]; X m[1] = 0; X f = fopen(name,m); X if (!f) { X warning("can't open file %s for %s",name,mode); X f = stdout; X name = "stdout"; X t = 1; /* error */ X } X } X strcpy(outfpname,name); /* save for later messages */ X outfp = f; X return t; /* non-zero is error */ X} X Xchar * XGGetOutput() X{ X return outfpname; X} X XGFlushOutput() X{ X fflush(outfp); X} X XGSetSep(s) Xchar *s; /* page separator string */ X{ X if (sepstr) freestr(sepstr); X sepstr = strsav(s); X} X Xchar * XGGetSep() X{ X return sepstr; X} X XGSetLabel(s) Xchar *s; X{ X if (Label) free(Label); X Label = strsave(s); X} X Xchar * XGGetLabel() X{ X return Label; X} X Xint Xgfamily(list) XSPtoken *list; X{ Xint ac; Xint *av; Xint t; X X ac = olisttoiarr(list,&av); X t = family(ac,av); X free((char *)av); X return t; X} X Xint Xgfamilyh(list) XSPtoken *list; X{ Xint ac; Xint *av; Xint t; X X ac = olisttoiarr(list,&av); X t = familyh(ac,av); X free((char *)av); X return t; X} X Xint Xgindivs(list) XSPtoken *list; X{ Xint ac; Xint *av; Xint t; X X ac = olisttoiarr(list,&av); X t = indivs(ac,av); X free((char *)av); X return t; X} X Xint Xgfamntree(list) XSPtoken *list; X{ Xint ac; Xint *av; Xint t; X X ac = olisttoiarr(list,&av); X t = famntree(ac,av); X free((char *)av); X return t; X} X Xint Xgannlist(list) XSPtoken *list; X{ Xint ac; Xint *av; Xint t; X X ac = olisttoiarr(list,&av); X t = annlist(ac,av); X free((char *)av); X return t; X} X Xint Xgbdlist(list) XSPtoken *list; X{ Xint ac; Xint *av; Xint t; X X ac = olisttoiarr(list,&av); X t = bdlist(ac,av); X free((char *)av); X return t; X} X XSPtoken * XLAnc(list,n) /* ancestor list */ XSPtoken *list; Xint n; X{ Xint iac, *iav; Xint ac, *av; XSPtoken *l; X X iac = olisttoiarr(list,&iav); X ac = famalist(iac,iav,&av,n); X l = SPiarrtolist(ac,av); X free((char *)av); X free((char *)iav); X return l; X} X XSPtoken * XLDesc(list,n) /* descendant list */ XSPtoken *list; Xint n; X{ Xint iac, *iav; Xint ac, *av; XSPtoken *l; X X iac = olisttoiarr(list,&iav); X ac = famdlist(iac,iav,&av,n); X l = SPiarrtolist(ac,av); X free((char *)av); X free((char *)iav); X return l; X} X XSPtoken * XLAll() /* all entries in the database */ X{ Xint ac, *av; XSPtoken *l; X X ac = alllist(&av); X l = SPiarrtolist(ac,av); X free((char *)av); X return l; X} X XSPtoken * XLFieldMatch(il,fname,fvalue) /* match value of a field */ XSPtoken *il; /* the list of entry id's to check */ Xchar *fname; /* field name */ Xchar *fvalue; /* field value to look for */ X{ Xint iac, *iav; Xint ac, *av; XSPtoken *l; X X iac = olisttoiarr(il,&iav); X ac = lfieldmatch(iac,iav,fname,fvalue,&av); X l = SPiarrtolist(ac,av); X free((char *)av); X return l; X} X XSPtoken * XLRefs(il,refname) /* follow field references */ XSPtoken *il; /* the list of entry id's to check */ Xchar *refname; /* field name */ X{ Xint iac, *iav; Xint ac, *av; XSPtoken *l; X X iac = olisttoiarr(il,&iav); X ac = lrefs(iac,iav,refname,&av); X l = SPiarrtolist(ac,av); X free((char *)av); X return l; X} X Xint XGPfi(il) /*print family or individual pages */ XSPtoken *il; X{ Xint ac; Xint *av; Xint n; Xint i,t; X X t = 0; X ac = olisttoiarr(il,&av); X for (i=0; i<ac; i++) { X if (i>0) fprintf(outfp,sepstr); X n = av[i]; X switch (fgtype(n)) { X case 'I': X t += indivs1(n); X break; X case 'F': X t += family1(n); X break; X default: X warning("bad record %d\n", n); X break; X } X } X return t; X} X X/* end */ END_OF_FILE if test 5963 -ne `wc -c <'misc.c'`; then echo shar: \"'misc.c'\" unpacked with wrong size! fi # end of 'misc.c' fi echo shar: End of archive 2 \(of 4\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.