rsalz@uunet.uu.net (Rich Salz) (03/10/89)
Submitted-by: Jim McBeath <voder!sci!gumby!jimmc> Posting-number: Volume 18, Issue 13 Archive-name: geneal/part03 #! /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 3 (of 4)." # Contents: dataman.c family.c famntree.c fgdat.c # Wrapped by rsalz@fig.bbn.com on Thu Mar 9 15:55:05 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'dataman.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dataman.c'\" else echo shar: Extracting \"'dataman.c'\" \(16428 characters\) sed "s/^X//" >'dataman.c' <<'END_OF_FILE' X/* dataman - simple data manager for reading data from text files X * Written by Jim McBeath (jimmc) at SCI X * X * Revision history: X * 24-Jan-85 Jim McBeath Put structure description into include file X * 14-Mar-86 J. McBeath Add getRecord() X * 9-May-86 J. McBeath Add unnumbered index mode X * 13-May-68 J. McBeath Bug fix for unnumbered record at start of file; X * add check for duplicate record numbers; X * modify error message scheme; add multi-line X * data value capability. X * 18-Sep-86 J. McBeath make strsave and strsave2 not static X * v1.5 jimmc 8.jan.87 Add checks for trailing spaces X * v1.6 jimmc 19.jan.87 Output error messages to error file also, X * add closeDataFile X * 8.Jan.88 jimmc Lint cleanup X */ 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 Alternatively, the records can all be unnumbered. In this case, X index numbers are automatically generated. The only allowable X record number in this mode is 0, which specifies that that record X is a comment record and is to be ignored. The record numbers in X this mode start at 1 and increase sequentially. 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 alphanumeric characters or '_' or '.' followed immediately X by 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 X#include <stdio.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <ctype.h> X#include <strings.h> X#include "index.h" X#include "dataman.h" X Xstruct dline { X int ltype; /* what kind of data line we found */ X#define LBLANK 0 /* nothing at all on the line */ X#define LCOMMENT 1 /* line starts with a colon */ X#define LKEY 2 /* normal key:value line */ X#define LNOKEY 3 /* line with text but no key, no leading colon */ X char *key; /* malloc'ed key string */ X char *value; /* malloc'ed value string, including \n */ X}; X Xextern char *malloc(), *realloc(); Xextern int errno; Xextern int sys_nerr; Xextern char *sys_errlist[]; Xextern long getIndex(); X Xstruct toplevel *initIndex(); XFILE *indexfp; /* used by writeoneindex */ XFILE *errorfp; /* used to write out errors when making index */ 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 *dataErrMsg=""; /* the error message */ Xchar dataErrBuf[1000]; /* where we put our error messages */ 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 "mixed records with and without indexes", /* 9 */ X "unnumbered records must not start on first line of file", /* 10 */ X "can't open index file", /* 11 */ X "error creating new index file", /* 12 */ X}; X#define ERET(n) { dataStatus = n; dataErrMsg = dataErrStrs[n]; return 0; } X#define EMSGRET { dataStatus = -1; dataErrMsg = dataErrBuf; return 0; } X#define EPRET(n) { sprintf(dataErrBuf, "%s: %s", dataErrStrs[n], \ X (errno<sys_nerr?sys_errlist[errno]:"Unknown unix error")); \ X dataStatus = n; dataErrMsg = dataErrBuf; return 0; } X X/*..........*/ X Xlong /* return the last-modification date of a file, or 0 */ Xfdate(fn) Xchar *fn; /* name of the file to get the date for */ X{ X struct stat sbuf; X int t; X X t = stat(fn,&sbuf); X if (t) return 0; X return sbuf.st_mtime; X} X X/*..........*/ X Xlong /* return the last-modification date of a file, or 0 */ Xfddate(fp) XFILE *fp; /* the file to get the date for */ X{ X struct stat sbuf; X int t; X X t = fstat(fileno(fp),&sbuf); X if (t) return 0; X return sbuf.st_mtime; X} X X/*..........*/ X Xchar *strsave(ss) Xchar *ss; X{ X char *dd; X dd = malloc((unsigned)(strlen(ss)+1)); X if (dd==0) fferror("no more memory"); X strcpy(dd,ss); X return dd; X} X X/*..........*/ X Xchar *strsave2(s1,s2) Xchar *s1,*s2; X{ X char *dd; X int l1,l2; X l1 = strlen(s1); X l2 = strlen(s2); X dd = malloc((unsigned)(l1+l2+1)); X if (dd==0) fferror("no more memory"); X strcpy(dd,s1); X strcpy(dd+l1,s2); X return dd; X} X X/*..........*/ X Xint Xwriteoneindex(n,l) Xint n; /* index number */ Xint l; /* seek offset */ X{ X if (n<=0) return 0; X putw(n,indexfp); /* write out the index number */ X putw(l,indexfp); /* write out the seek offset */ X return 0; X} X X/*..........*/ X Xchar *dlinebuf=0; Xint dlinebufsize=0; Xint dlineno; Xchar *dfilename; X Xgetdline(fp) XFILE *fp; X{ X int t; X X if (dlinebufsize==0) { X dlinebufsize = 100; /* a starting point */ X dlinebuf = malloc((unsigned)dlinebufsize); X if (dlinebuf==0) fferror("no more memory"); X } X dlinebuf[dlinebufsize-1]=0; /* set to null so we can check it */ X dlinebuf[dlinebufsize-2]=0; X dlinebuf[0]=0; X fgets(dlinebuf,dlinebufsize,fp); X while (dlinebuf[dlinebufsize-2]!=0 && dlinebuf[dlinebufsize-2]!='\n') { X t = dlinebufsize-1; /* this is where new piece should start */ X dlinebufsize *=2; /* try twice the size */ X dlinebuf = realloc(dlinebuf,(unsigned)dlinebufsize); X if (dlinebuf==0) fferror("no more memory"); X dlinebuf[t]=0; X dlinebuf[dlinebufsize-1]=0; X dlinebuf[dlinebufsize-2]=0; X fgets(dlinebuf+t,dlinebufsize-t,fp); X /* pick up next part of line */ X } X/* We now have the complete line in dlinebuf, no matter how long it was! */ X dlineno++; X} X X/*..........*/ X Xstruct dline * /* reads and parses one line */ Xreaddline(fp,dlp) XFILE *fp; /* File to read from */ Xstruct dline *dlp; /* structure to fill in; if nul, allocates one */ X{ X int c; X char *cp; X X if (dlp==0) { X dlp = (struct dline *)malloc(sizeof(struct dline)); X if (dlp==0) fferror("no more memory"); X dlp->key=0; X dlp->value=0; X } X getdline(fp); /* read data line into dlinebuf */ X for (cp=dlinebuf; (c= *cp)!=0; cp++) { X if (!(isalnum(c)||c=='_'||c=='.')) break; X } X if (c=='\n' || c==0) { X if (cp==dlinebuf) dlp->ltype=LBLANK; X else dlp->ltype=LNOKEY; X dlp->key = 0; X dlp->value = strsave(dlinebuf); X } X else if (c==':') { X if (cp==dlinebuf) { X dlp->ltype=LCOMMENT; X dlp->key=0; X } X else { X dlp->ltype=LKEY; X *cp = 0; /* null terminate the key */ X dlp->key = strsave(dlinebuf); X } X dlp->value = strsave(cp+1); X } X else { X dlp->ltype=LNOKEY; X dlp->key = 0; X dlp->value = strsave(dlinebuf); X } X return dlp; X} 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{ X FILE *fp, *ifp; X struct dpoint *pp; X struct toplevel *qq; X int iflag,n; X int lastindex=0; X int indexedmode=0; /* 0 means mode is not yet set */ X#define INDEXMODEYES 1 X#define INDEXMODENO 2 X long lastftell=0; X char *indexfn; X char *errorfn; X#define INDEXSUFF ".index" X#define ERRORSUFF ".error" X int l,c; X int t; X long lt; X char *msg; X X dfilename = fn; /* for error messages during init */ X dlineno = 0; X fp = fopen(fn,"r"); /* get his data file */ X if (!fp) EPRET(1) /* can't do anything if no file */ X pp = (struct dpoint *)malloc(sizeof(struct dpoint)); X if (!pp) { /* if no memory for us */ X fclose(fp); /* dump the file */ X EPRET(2) /* error return */ X } X pp->ff = fp; /* put file pointer into our data block */ X qq = initIndex(); /* start up an index table */ X if (qq==0) { /* if can't start up an index table */ X fclose(fp); X free((char *)pp); X ERET(3) X } X pp->xx = qq; /* save pointer to index table */ X if (dataDebug) printf("initDataFile: index table is at %X\n", qq); X X l = strlen(fn)+sizeof(INDEXSUFF)+1; X indexfn = malloc((unsigned)l); X if (indexfn==0) ERET(2) /* no more memory */ X sprintf(indexfn,"%s%s", fn, INDEXSUFF); X if (fdate(indexfn)>fddate(fp)) { X /* if we have an up-to-date index */ X ifp = fopen(indexfn,"r"); X if (ifp==0) EPRET(11) X while (!feof(ifp)) { X n = getw(ifp); /* read the index number */ X lastftell = getw(ifp); X /* read the seek offset */ X if (n>0) setIndex(qq,n,lastftell); X /* set the table */ X } X dataStatus=0; X return pp; /* done */ X } X X l = strlen(fn)+sizeof(ERRORSUFF)+1; X errorfn = malloc((unsigned)l); X if (errorfn==0) ERET(2) /* no more memory */ X sprintf(errorfn,"%s%s", fn, ERRORSUFF); X errorfp = fopen(errorfn,"w"); /* the error file */ X iflag = 1; /* note we are looking for start of record */ X while (!feof(fp)) { /* scan through the file */ X getdline(fp); /* read line into dlinebuf */ X l = strlen(dlinebuf); X if (l>0 && dlinebuf[l-1]=='\n') --l; X if (l>0 && ((c=dlinebuf[l-1])==' ' || c=='\t')) { X msg="trailing spaces or tabs"; X fprintf(stderr, X "warning: %s in data file %s on line %d\n", X msg, dfilename, dlineno); X if (errorfp) fprintf(errorfp, X "warning: %s in data file %s on line %d\n", X msg, dfilename, dlineno); X } X if (iflag) { /* looking for start of next record */ X if (dlinebuf[0]==0) break; /* EOF */ X if (dlinebuf[0]=='\n') { /* another blank line */ X if (indexedmode!=INDEXMODEYES) X lastftell = ftell(fp); X } X else if (sscanf(dlinebuf,"%d",&n)==1) { X /* if index number */ X if (n>0) { /* ignore records numbered 0 */ X switch(indexedmode) { X case 0: X indexedmode=INDEXMODEYES; X break; X case INDEXMODENO: X ERET(9) /* NOTREACHED */ X } X if (dataDebug) Xprintf("initDataFile: index %d at loc %d\n", n,ftell(fp)); X lastftell = ftell(fp); X lt = getIndex(qq,n); X if (lt!=0) { X sprintf(dataErrBuf, X"duplicate record index %d (seek offsets %d and %d)", X n, lt, lastftell); X EMSGRET X } X setIndex(qq,n,lastftell); X /* remember start of next line */ X } X iflag=0; X /* no longer looking for start of record */ X } X else { /* start of a record without an index */ X switch (indexedmode) { X case 0: X indexedmode=INDEXMODENO; X break; X case INDEXMODEYES: X ERET(9) /* NOTREACHED */ X } X if (dataDebug) Xprintf("initDataFile: index %d at loc %d\n", lastindex+1,lastftell); X if (lastftell==0) X ERET(10) /* can't start right at 0! */ X setIndex(qq,++lastindex,lastftell); X /* remember start of this line */ X iflag=0; X } X } X else { /* in the middle of a record */ X if (dlinebuf[0]=='\n') { X /* see if this is a blank line */ X if (indexedmode!=INDEXMODEYES) X lastftell = ftell(fp); X iflag++; /* note blank line - */ X /* start looking for next record */ X } X } X } X if (errorfp) fclose(errorfp); X /* Now create an index file to use for future runs */ X indexfp = fopen(indexfn,"w"); X if (indexfp) { /* if we got it, make the file */ X enumIndex(pp->xx,writeoneindex); /* write out the index info */ X t = fclose(indexfp); X if (t) { EPRET(12) } X } X dataStatus=0; X return pp; /* return pointer to our structure */ X} X X/*..........*/ X XcloseDataFile(pp) Xstruct dpoint *pp; X{ X if (!pp) ERET(4) /* check for valid pointer */ X if (!(pp->ff)) ERET(5) /* error return if no file open */ X if (!(pp->xx)) ERET(6) /* error if no index table pointer */ X freeIndex(pp->xx); /* dump the index */ X fclose(pp->ff); /* free up the file pointer */ X free((char *)pp); X dataStatus=0; X return 0; X} X X/*..........*/ X Xchar *getdatalastp=0; 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{ X long l; X int len; X char *index(); X struct dline dl, dl2; X struct dline *dlp, *dlp2; X int unnamedok; X char *oldv, *addv; X X if (!pp) ERET(4) /* check for valid pointer */ X if (!(pp->ff)) ERET(5) /* error return if no file open */ X if (!(pp->xx)) ERET(6) /* error if no index table pointer */ X l = getIndex(pp->xx,indexn); /* get the lseek value for that index */ X if (l==0) ERET(7) /* error if no lseek value for that index */ X fseek(pp->ff,l,0); /* seek to the start of that line */ X if (strcmp(key,"unnamed")==0) unnamedok=1; X else unnamedok=0; X while (!feof(pp->ff)) { /* read lines until eof (or blank) */ X dlp = readdline(pp->ff,&dl); X if (dlp->ltype==LBLANK) break; /* blank line */ X else if (dlp->ltype==LCOMMENT) continue; X else if (dlp->ltype==LKEY) unnamedok=0; X if ((dlp->ltype==LNOKEY && unnamedok) || X (dlp->ltype==LKEY && strcmp(key,dlp->key)==0)) { X /* we've got a hot one */ X dlp2 = readdline(pp->ff,&dl2); X while (dlp2->ltype==LNOKEY) { X oldv = dlp->value; X addv = dlp2->value; X if (*addv == '+') X addv++; X /* skip over leading plus mark */ X dlp->value = strsave2(dlp->value,addv); X free(oldv); X free(dlp2->value); X dlp2 = readdline(pp->ff,&dl2); X } X len = strlen(dlp->value); X if (dlp->value[len-1]=='\n') dlp->value[len-1]=0; X free(dlp2->key); X free(dlp2->value); X free(dlp->key); X if (getdatalastp) free(getdatalastp); X getdatalastp = dlp->value; X dataStatus=0; X return dlp->value; X } X } /* continue - read next line and compare */ X ERET(8) /* eof or blank line, key not found */ X} X X/*..........*/ X Xstruct drecord * /* returns a pointer to a record struct */ X/* return NULL if no data or error */ XgetRecord(pp,indexn,rp) /* get a complete record */ Xstruct dpoint *pp; /* pointer to our structure */ Xint indexn; /* the index of the record of interest */ Xstruct drecord *rp; /* structure to fill in; if NULL, allocs one */ X{ X int i; X int len; X long l; X char *index(); X int numfields; X#define MAXRECNUM 1000 X char *names[MAXRECNUM]; /* make number of fields */ X char *values[MAXRECNUM]; X struct dline dl, dl2; X struct dline *dlp, *dlp2; X char *oldv, *addv; X X if (!pp) ERET(4) /* check for valid pointer */ X if (!(pp->ff)) ERET(5) /* error return if no file open */ X if (!(pp->xx)) ERET(6) /* error if no index table pointer */ X if (rp==0) { X rp = (struct drecord *)malloc(sizeof(struct drecord)); X if (rp==0) return 0; X rp->numfields = 0; X rp->name = 0; X rp->value = 0; X } X for (i=0; i<rp->numfields; i++) { X free(rp->name[i]); X free(rp->value[i]); X }; X if (rp->name) free((char *)rp->name); X if (rp->value) free((char *)rp->value); X l = getIndex(pp->xx,indexn); /* get the lseek value for that index */ X if (l==0) ERET(7) /* error if no lseek value for that index */ X fseek(pp->ff,l,0); /* seek to the start of that line */ X numfields = 0; X dlp = readdline(pp->ff,&dl); X while (dlp->ltype!=LBLANK) { X while (dlp->ltype==LCOMMENT) { X free(dlp->value); X dlp = readdline(pp->ff,&dl); X } X if (dlp->ltype==LBLANK) break; X dlp2 = readdline(pp->ff,&dl2); X while (dlp2->ltype==LNOKEY) { X oldv = dlp->value; X addv = dlp2->value; X if (*addv == '+') X addv++; /* skip over leading plus mark */ X dlp->value = strsave2(dlp->value,addv); X free(oldv); X free(dlp2->value); X dlp2 = readdline(pp->ff,&dl2); X } X len = strlen(dlp->value); X if (dlp->value[len-1]=='\n') dlp->value[len-1]=0; X if (dlp->ltype==LNOKEY) X names[numfields] = strsave("unnamed"); X else names[numfields] = dlp->key; X values[numfields] = dlp->value; X numfields++; X dl = dl2; X } X if (dlp->ltype==LBLANK) free(dlp->value); X dataStatus=0; X rp->numfields = numfields; X rp->name = (char **)malloc((unsigned)(numfields*sizeof(char *))); X if (rp->name==0) return 0; X rp->value = (char **)malloc((unsigned)(numfields*sizeof(char *))); X if (rp->value==0) return 0; X for (i=0; i<numfields; i++) { X rp->name[i] = names[i]; X rp->value[i] = values[i]; X } X return rp; X} X X/* end */ END_OF_FILE if test 16428 -ne `wc -c <'dataman.c'`; then echo shar: \"'dataman.c'\" unpacked with wrong size! fi # end of 'dataman.c' fi if test -f 'family.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'family.c'\" else echo shar: Extracting \"'family.c'\" \(8659 characters\) sed "s/^X//" >'family.c' <<'END_OF_FILE' X/* family.c - produce a family information page X * Written by Jim McBeath (jimmc) at SCI X * X * Revision history: X * 24-Jan-85 Jim McBeath Remove redundant declaration of gendp X * 27-Jan-85 Jim McBeath Use fgbslist; change fgclist to bclist X * 29-Jan-85 Jim McBeath convert to 7-char-distinct names X * 14-Feb-85 (Ian Darwin) remove mnumstr (unused variable) X * 24.Aug.87 jimmc Add Label stuff, add BUR info X * 14.Sep.87 jimmc Add addr stuff X * 27.Oct.87 jimmc General cleanup; call fggen to get GEN info X * 4.Jan.88 jimmc Make printindented not static X * 8.Jan.88 jimmc Allow lists of families to be printed X */ X X#include <stdio.h> X#include <ctype.h> X#include "geneal.h" X#include "pagemap.h" X X#define PAGEWID 80 X#define LEFTMARGIN 4 X#define RIGHTMARGIN 4 X#define CENTERMARGIN 2 X#define LEFTCOL ((PAGEWID-LEFTMARGIN-RIGHTMARGIN-CENTERMARGIN)/2) X#define RIGHTCOL (PAGEWID-LEFTMARGIN-RIGHTMARGIN-CENTERMARGIN-LEFTCOL) X#define ADDRCOL (LEFTMARGIN+20) X#define SPOUSEOFFSET 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 dataStatus; Xextern char *dataErrStrs[]; Xextern char *Label; X Xint notenum; Xint notecount; /* for storing the footnotes */ Xchar *notes[NOTEMAX]; X Xprintindented(indent,str) Xint indent; Xchar *str; X{ X if (!str || !str[0]) return; X fprintf(outfp,"%*s", indent, ""); X for (; *str; str++) { X if (*str == '\n') { X fprintf(outfp,"\n%*s", indent, ""); X } X else putc(*str,outfp); X } X putc('\n',outfp); X} X X/*..........*/ X Xint /* 0 if all OK */ Xfamily(ac,av) Xint ac; /* number of families */ Xint *av; /* list of family id numbers */ X{ X int i,t; X X t = 0; X for (i=0; i<ac; i++) { X if (i>0) fprintf(outfp,sepstr); X t += family1(av[i]); X } X return t; X} X X/*..........*/ X Xint /* 0 if OK */ Xfamily1(famnum) Xint famnum; /* the family to give info about */ X{ X int rtype; X char *famname, *husname, *wifename; X char *huslname, *wifelname; X int husnum, wifenum; X char *headerline; X int i, cnum, clist[1000]; X char *ss; X int addrnum; X char *addr; X char *phone; X X notecount=notenum=0; X rtype = fgtype(famnum); X if (rtype<=0) { X warning("no such record number %d", famnum); X return 1; X } X if (rtype!='F') { X warning("record %d is not a family", famnum); X return 1; X } X famname = fgstr(famnum,"N"); /* get the family name */ X husnum = fgnum(famnum,"H"); /* get husband and wife index nums */ X wifenum = fgnum(famnum,"W"); X husname = fgbname(husnum); X wifename = fgbname(wifenum); X huslname = fgstr(husnum,"LN"); X wifelname = fgstr(wifenum,"LNM"); X X if (wifelname==0 || wifelname[0]==0) wifelname = fgstr(wifenum,"LN"); X X if (huslname && huslname[0]==0) huslname=0; X if (wifelname && wifelname[0]==0) wifelname=0; X if (famname && famname[0]==0) famname=0; X if (husname==0 || husname[0]==0) husname = "???"; X if (wifename==0 || wifename[0]==0) wifename = "???"; X if (famname && (huslname==0 || strcmp(famname,huslname)!=0)) X headerline = X tprintf("%s - %s & %s", famname, husname, wifename); X else X headerline = tprintf("%s & %s", husname, wifename); X strup(headerline); X if (Gflag['N'] && Gflag['n']) { X ss = tprintf("[%d]: %s",famnum,headerline); X free(headerline); X headerline = ss; X } X printindented(LEFTMARGIN,Label); X printindented(LEFTMARGIN,headerline); X fprintf(outfp,"\n"); X printpair(0,famnum,husnum, wifenum); /* print data about parents */ X X addrnum = fgnum(famnum,"ADDR"); X if (Gflag['a'] && addrnum>0) { /* print address if known */ X addr = fgstr(addrnum,"ADDR"); X printindented(ADDRCOL,addr); X phone = fgstr(addrnum,"PHONE"); X printindented(ADDRCOL,phone); X fprintf(outfp,"\n"); X } X X cnum = fgbclist(famnum,clist); X if (cnum==0) { X#if 0 /* be silent about no children... */ X printindented(LEFTMARGIN,"NO CHILDREN"); X#endif X } X else { X fprintf(outfp,"%*s%*s%*s%s\n\n", X LEFTMARGIN, "", -LEFTCOL, "CHILDREN", X CENTERMARGIN, "", "SPOUSES OF CHILDREN"); X for (i=0; i<cnum; i++) { X int childnum, mgnum, spousenum, chusnum, cwifenum; X int scount,slist[1000],mnum; X X childnum = clist[i]; X scount = fgbslist(childnum,slist); X for (mnum=0; mnum<scount; mnum++) { X /* until we run out of marriages */ X mgnum = slist[mnum]; X chusnum = fgnum(mgnum, "H"); X cwifenum = fgnum(mgnum, "W"); X if (childnum==chusnum) spousenum=cwifenum; X else if (childnum==cwifenum) spousenum=chusnum; X else { Xwarning("person %d claims marriage %d, but not vice-versa!", X childnum, mgnum); X spousenum= -1; X } X printpair(mnum,mgnum,childnum,spousenum); X } X if (scount==0) printpair(0,-1,childnum,-1); X /* print the individual if no marriage */ X } X } X if (notecount>0) { /* if we accumulated any notes */ X printindented(LEFTMARGIN, "-----------------------"); X for (i=0; i<notecount; i++) X printindented(LEFTMARGIN, notes[i]); 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{ X struct tblock cntb, sntb; /* where to store data */ X int 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>LEFTCOL || sntb.width>RIGHTCOL) { /* separate */ X printtb(&cntb,LEFTMARGIN); /* output the first one */ X printtb(&sntb,LEFTMARGIN+SPOUSEOFFSET); /* output spouse */ X } X else { /* both on the same line */ X if (cntb.lines > sntb.lines) max = cntb.lines; X else max = sntb.lines; X for (i=0; i<max; i++) { X if (i>=cntb.lines) X printindented( X -(LEFTMARGIN+CENTERMARGIN+LEFTCOL), X sntb.text[i]); X else if (i>=sntb.lines) X printindented(LEFTMARGIN, cntb.text[i]); X else X/*** Problems here if field in database was > 1 line */ X fprintf(outfp,"%*s%*s%*s%s\n", LEFTMARGIN, "", X -LEFTCOL, cntb.text[i], CENTERMARGIN, X "", sntb.text[i]); X } X fprintf(outfp,"\n"); X } X} X X/*..........*/ X Xprinttb(b,offset) /* print a text block */ Xstruct tblock *b; Xint offset; /* left margin offset */ X{ X int i; X X for (i=0; i<b->lines; i++) X printindented(offset, b->text[i]); X if (b->lines!=0) fprintf(outfp,"\n"); 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{ X char *name, *birth, *death, *buried, *marriage; X X b->lines = b->width = 0; /* clear it out first */ X if (n<=0) return; X name = fgbname(n); X birth = fgbirth(n); X death = fgdeath(n); X buried = fgburied(n); X marriage = fgnmarriage(m); X if (i<=0) { X addtline(name,b); X if (birth && *birth) addtline(birth,b); X if (death && *death) addtline(death,b); X if (buried && *buried) addtline(buried,b); X if (i==0) { X if (marriage && *marriage) addtline(marriage,b); X addnots(n,m,b); /* add general comment notes */ X } X else /* i== -1 */ X addnots(n,-1,b); /* don't add marriage notes */ X } X else { X if (marriage && *marriage) X marriage = tprintf("re-%s", marriage); X else marriage = "remarried:"; X addtline(marriage,b); X addnots(-1,m,b); X } X} X X/*..........*/ X Xaddnots(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 addnote(n,b,""); X addnote(m,b," (m)"); X} X X/*..........*/ X Xaddnote(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{ X char *gencom; X int lcount; X int hlen; X int t; X X lcount = 0; X hlen = strlen(ss)+sizeof("Note")+2; X gencom = fggen(n); X lcount += countlines(gencom); X if (lcount==1 && ((t=strlen(gencom)+hlen)<=b->width||t<LEFTCOL)) { X /* if we have one relatively short string, do it in-line */ X addtline(tprintf("[Note%s: %s]", ss, gencom),b); X } X else if (lcount>0) { X addtline(tprintf("[Note %d%s]", 1+notenum, ss),b); X notes[notecount++] = tprintf("Note %d%s:", 1+notenum++, ss); X notes[notecount++] = gencom; /* add string to notes */ 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{ X int l; X X if (b->lines >= TBLOCKSIZE) { 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) b->width=l; /* keep track of width */ X} X X/* end */ END_OF_FILE if test 8659 -ne `wc -c <'family.c'`; then echo shar: \"'family.c'\" unpacked with wrong size! fi # end of 'family.c' fi if test -f 'famntree.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'famntree.c'\" else echo shar: Extracting \"'famntree.c'\" \(10181 characters\) sed "s/^X//" >'famntree.c' <<'END_OF_FILE' X/* famntree.c - produce output suitable for treepar X * X * 13.Aug.87 jimmc Initial definition X * 14.Aug.87 jimmc Add globals, textsize X * 18.Aug.87 jimmc Add spouse stuff X * 24.Aug.87 jimmc Add label X * 31.Aug.87 jimmc Add bd2 X * 14.Sep.87 jimmc Allow multiple line tnotes X * 16.Sep.87 jimmc Fix bug in fam1fs when id==-1 X * 18.Sep.87 jimmc Add #include xalloc.h; use XCALLOC instead of XALLOC; X * add 'addr' field. X * 21.Sep.87 jimmc Use info arrays instead of separate structure members X * add 'buried' field. X * 27.Oct.87 jimmc Make countlines() and linewidth() global X * 1.Jan.88 jimmc Use fglpname instead of fglname X * 8.Jan.88 jimmc Direct output to outfp instead of stdout; lint cleanup X */ X X#include <stdio.h> X#include <ctype.h> X#include <strings.h> X#include "geneal.h" X#include "famntree.h" X#include "xalloc.h" X X#define SX 6 X#define SY 10 X#define YOFF (SY/3) X#define ROWSPACE 20 X#define TRACKSPACE 20 X#define IROWSPACE 30 X X#define NOTNULL(str) ((str)&&(str[0])) X Xextern char *strsave(), *strsave2(); X Xextern char *Label; X Xstatic int ypos; X Xstatic Xchar * Xpad(padstr,str) Xchar *padstr; Xchar *str; X{ X char *new; X X new = strsave2(padstr,str); X free(str); X return new; X} X Xstatic Xchar * Xcpad(padstr,str) Xchar *padstr; Xchar *str; X{ X X if (!str || !*str) return 0; X return pad(padstr,str); X} X Xstatic Xprintsbody(f,s) XFILE *f; Xchar *s; X{ X if (!s) return; X for (;*s;s++) { X if (isprint(*s)) { X if (*s=='"') fputc('\\',f); X fputc(*s,f); X } X else if (*s=='\n') fputs("\\n\\\n",f); X else fprintf(f,"\\%03o",*s); X } X} X Xstatic Xprintmbody(f,s) /* like printsbody, but indents all lines based on first */ XFILE *f; Xchar *s; X{ X int i,n; X X if (!s) return; X for (n=0; s[n]==' ';n++) ; /* EMPTY - count spaces */ X for (;*s;s++) { X if (isprint(*s)) { X if (*s=='"') fputc('\\',f); X fputc(*s,f); X } X else if (*s=='\n') { X fputs("\\n\\\n",f); X if (s[1]) for(i=0; i<n; i++) fputc(' ',f); X /* indent following lines by same amount */ X } X else fprintf(f,"\\%03o",*s); X } X} X Xstatic Xprintstring(f,s) XFILE *f; Xchar *s; X{ X fputc('"',f); X printsbody(f,s); X fputc('"',f); X} X Xstatic Xprintsline(f,s) XFILE *f; Xchar *s; X{ X if (NOTNULL(s)) { X printmbody(f,s); X printsbody(f,"\n"); X } X} X Xint Xcountlines(s) Xchar *s; X{ X int n; X X if (!s || !s[0]) return 0; X n=1; X while (s) { X s = index(s,'\n'); X if (s) { X n++; X s++; X } X } X return n; X} X Xint Xlinewidth(s) Xchar *s; X{ X int l,newl; X char *p; X X if (!s || !s[0]) return 0; X l = 0; X while (s) { X p = index(s,'\n'); X if (p) { X newl = p-s; X s = p+1; X } X else { X newl = strlen(s); X s = p; X } X if (newl>l) l=newl; X } X return l; X} X Xstatic Xfamschema() X{ X fprintf(outfp,"globals schema (\"textsizex.i\" \"textsizey.i\" \ X\"rowposspace.i\" \"rowdir.s\" \"trackspace.i\" \ X\"interrowspace.i\" \"label.s\")\n"); X fprintf(outfp,"globals (%d %d %d \"V\" %d %d ", X SX, SY, ROWSPACE, TRACKSPACE, IROWSPACE); X printstring(outfp,Label?Label:""); X fprintf(outfp,")\n\n"); X X fprintf(outfp,"box schema (\"name.s\" \"sizex.i\" \"sizey.i\" \ X\"orgx.i\" \"orgy.i\"\n\t\"text.s\" \"textx.i\" \"texty.i\" \"textpos.s\")\n"); X fprintf(outfp,"conn schema (\"boxname.s\" \"name.s\" \ X\"x.i\" \"y.i\" \"side.s\" \"netname.s\")\n\n"); X} X Xstatic Xfam1out(fi) XFamninfo *fi; X{ X int i,j,n; X Fammember *fm; X Fammemspouse *fs; X int linecount,slinecount; X X fprintf(outfp,"box (\"%s\" %d %d %d %d \"", X fi->boxname, SX*(fi->cols+2), SY*(fi->lines+2), X SX*0, SY*(ypos+=30,ypos-30)); X for (n=0; n<FISIZE; n++) X printsline(outfp,fi->info[n]); X for (i=0; i<fi->namelen; i++) X fputc('=',outfp); X fprintf(outfp,"\\n\\\n"); X for (i=0; i<fi->mcount; i++) { X fm = fi->mlist+i; X for (n=0; n<FMSIZE; n++) X printsline(outfp,fm->info[n]); X if (Gflag['m']) { X for (j=0; j<fm->scount; j++) { X fs = fm->slist+j; X for (n=0; n<FSSIZE; n++) X printsline(outfp,fs->info[n]); X } X } X } X fprintf(outfp,"\" %d %d \"NW\")\n", SX*1, SY*(fi->lines+1)); X X /* output connectors for the box */ X if (Gflag['m']) { X /* output connectors for parents */ X if (fi->famid>0) { X fprintf(outfp, X "conn (\"%s\" \"f%d\" %d %d \"W\" \"f%d\")\n", X fi->boxname, fi->famid, X SX*0, SY*((fi->lines+2)/2), fi->famid); X } X /* output connectors for member marriages */ X linecount = fi->headerlines; X for (i=0; i<fi->mcount; i++) { X fm = fi->mlist+i; X slinecount = linecount+fm->headerlines; X if (fm->id>0) for (j=0; j<fm->scount; j++) { X fs = fm->slist+j; X if (fs->mid>0) { X fprintf(outfp, X "conn (\"%s\" \"f%d\" %d %d \"E\" \"f%d\")\n", X fi->boxname, fs->mid, X SX*(fs->connx+1), X SY*(fi->lines-slinecount)+YOFF, X fs->mid); X } X slinecount += fs->lines; X } X linecount += fm->lines; X } X } X else { X /* output connectors for parents */ X if (fi->fatherid>0) { X fprintf(outfp, X "conn (\"%s\" \"i%d\" %d %d \"W\" \"i%d\")\n", X fi->boxname, fi->fatherid, X SX*0, SY*(fi->lines+1), fi->fatherid); X } X if (fi->motherid>0) { X fprintf(outfp, X "conn (\"%s\" \"i%d\" %d %d \"W\" \"i%d\")\n", X fi->boxname, fi->motherid, X SX*0, SY*1, fi->motherid); X } X /* output connectors for members */ X linecount = fi->headerlines; X for (i=0; i<fi->mcount; i++) { X fm = fi->mlist+i; X if (fm->id>0) { X fprintf(outfp, X "conn (\"%s\" \"i%d\" %d %d \"E\" \"i%d\")\n", X fi->boxname, fm->id, X SX*(fm->connx+1), X SY*(fi->lines-linecount)+YOFF, X fm->id); X } X linecount += fm->lines; X } X } X} X Xstatic Xfam1fs(fs,mid,fmid) XFammemspouse *fs; Xint mid; Xint fmid; X{ X int lines, cols; X int tt; X char *marr; X int i; X X fs->mid = mid,fmid; X fs->id = fgspouse(fs->mid,fmid); X marr = fgnmarriage(fs->mid); X if (NOTNULL(marr)) fs->info[FS_MD] = pad(" ",marr); X else fs->info[FS_MD] = strsave(" m: "); X if (Gflag['t']) { X fs->info[FS_MTNOTE] = cpad(" ",fgtnote(fs->mid)); X } X if (fs->id>0) { X fs->info[FS_NAME] = cpad(" ",fgbname(fs->id)); X if (Gflag['b']) { X fs->info[FS_BD] = cpad(" ",fgbirth(fs->id)); X fs->info[FS_BD2] = cpad(" ",fgdeath(fs->id)); X fs->info[FS_BUR] = cpad(" ",fgburied(fs->id)); X } else { X fs->info[FS_BD] = cpad(" ",fgbrtdeath(fs->id)); X } X if (Gflag['t']) { X fs->info[FS_TNOTE] = cpad(" ",fgtnote(fs->id)); X } X } X X lines = 0; X cols = fs->connx = strlen(fs->info[FS_MD]); X for (i=0; i<FSSIZE; i++) { X lines += countlines(fs->info[i]); X if ((tt=linewidth(fs->info[i])) > cols) cols=tt; X } X fs->lines = lines; X fs->cols = cols; X} X Xstatic Xfam1fm(fm) XFammember *fm; X{ X int lines, cols; X Fammemspouse *fs; X int *mlist; X int tt; X int i, n; X X fm->info[FM_NAME] = fgtname(fm->id); X if (Gflag['b']) { /* extended birth/death info */ X fm->info[FM_BD] = cpad(" ",fgbirth(fm->id)); X fm->info[FM_BD2] = cpad(" ",fgdeath(fm->id)); X fm->info[FM_BUR] = cpad(" ",fgburied(fm->id)); X } X else { X fm->info[FM_BD] = fgbrtdeath(fm->id); X } X if (Gflag['t']) { X fm->info[FM_TNOTE] = cpad(" ",fgtnote(fm->id)); X } X X lines = 0; X cols = fm->connx = strlen(fm->info[FM_NAME]); X for (i=0; i<FMSIZE; i++) { X lines += countlines(fm->info[i]); X if ((tt=linewidth(fm->info[i])) > cols) cols=tt; X } X fm->lines = fm->headerlines = lines; X fm->cols = cols; X X if (Gflag['m']) { /* include spouse info if set */ X fm->scount = fglist(fm->id,"S",&mlist); X fm->slist = XCALLOCM(Fammemspouse,fm->scount,"fam1fi spouse"); X for (n=0; n<fm->scount; n++) { X fs = fm->slist+n; X fam1fs(fs,mlist[n],fm->id); X if (fs->cols > fm->cols) fm->cols=fs->cols; X fm->lines += fs->lines; X } X } X} X Xstatic int Xfam1fi(fi) /* stuff common to ind and fam */ XFamninfo *fi; /* the family box to fill out */ X{ X int lines, cols; X int tt; X int i; X Fammember *fm; X int addrnum; X X if (!fi->info[FI_NAME]) fi->info[FI_NAME] = strsave("****"); X if (Gflag['b'] && !Gflag['m'] && fi->famid>0) { X fi->info[FI_MARR] = fgmarriage(fi->famid); X } X if (Gflag['t'] && fi->famid>0) { X fi->info[FI_TNOTE] = fgtnote(fi->famid); X } X if (Gflag['a'] && fi->famid>0) { X addrnum = fgnum(fi->famid,"ADDR"); X if (addrnum>0) fi->info[FI_ADDR] = fgaddrphn(addrnum); X } X X lines = 1; /* account for the line of "====" */ X cols = 0; X for (i=0; i<FISIZE; i++) { X lines += countlines(fi->info[i]); X if ((tt=linewidth(fi->info[i])) > cols) cols=tt; X } X fi->lines = fi->headerlines = lines; X fi->cols = fi->namelen = cols; X X for (i=0; i<fi->mcount; i++) { X fm = fi->mlist+i; X fam1fm(fm); /* fill out info for each member */ X if (fm->cols > fi->cols) fi->cols=fm->cols; X fi->lines += fm->lines; X } X fi->fatherid = fgnum(fi->famid,"H"); X fi->motherid = fgnum(fi->famid,"W"); X fam1out(fi); /* write out what we have so far */ X return 0; X} X Xstatic int Xfam1ind(id) Xint id; /* id of family or individual to output for */ X{ X Famninfo *fi; X Fammember *fm; X char buf[500]; X X fi = XCALLOCM(Famninfo,1,"fam1ind fi"); X fi->famid = fgnum(id,"P"); X fi->info[FI_NAME] = fgstr(id,"LN"); X sprintf(buf,"I%d",id); X fi->boxname = strsave(buf); X fi->mcount = 1; X fi->mlist = XCALLOCM(Fammember,1,"fam1ind members"); X fm = fi->mlist+0; /* point to first entry */ X fm->id = id; X return fam1fi(fi); X} X Xstatic int Xfam1fam(id) Xint id; /* id of family or individual to output for */ X{ X Famninfo *fi; X Fammember *fm; X int i; X int *clist; X char buf[500]; X X fi = XCALLOCM(Famninfo,1,"fam1fam fi"); X fi->famid = id; X/*** used to use fglname instead of fglpname - should we have a switch? */ X fi->info[FI_NAME] = fglpname(id); X sprintf(buf,"F%d",id); X fi->boxname = strsave(buf); X fi->mcount = fglist(id,"C",&clist); X fi->mlist = XCALLOCM(Fammember,fi->mcount,"fam1fam members"); X for (i=0; i<fi->mcount; i++) { X fm = fi->mlist+i; X fm->id = clist[i]; X } X if (clist) free((char *)clist); X return fam1fi(fi); X} X Xstatic int /* returns 0 if OK */ Xfam1tree(id) Xint id; /* id of family or individual to output for */ X{ X switch (fgtype(id)) { X case 'I': X return fam1ind(id); X case 'F': X return fam1fam(id); X default: X return 0; X } X} X Xint /* returns 0 if OK */ Xfamntree(idcount,idlist) Xint idcount; /* number of entries in idlist */ Xint *idlist; /* array of id numbers in the group to be output */ X{ X int i; X int t=0; X X ypos=0; X famschema(); /* write out the schema */ X for (i=0; i<idcount; i++) { X t += fam1tree(idlist[i]); X } X return t; X} X X/* end */ END_OF_FILE if test 10181 -ne `wc -c <'famntree.c'`; then echo shar: \"'famntree.c'\" unpacked with wrong size! fi # end of 'famntree.c' fi if test -f 'fgdat.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'fgdat.c'\" else echo shar: Extracting \"'fgdat.c'\" \(11824 characters\) sed "s/^X//" >'fgdat.c' <<'END_OF_FILE' X/* fgdat.c - routines to get pieces of info records X * Written by Jim McBeath (jimmc) at SCI X * X * Revision history: X * 27-Jan-85 Jim McBeath convert fgclist to fg*list functions X * add addn[cp]list functions X * 29-Jan-85 Jim McBeath add family index in names if index>1 X * convert to 7-char-distinct names X * 2-Feb-85 Jim McBeath Convert to LN.A instead of LNM. X * 13-Feb-85 (Ian Darwin) use NULL and \0 instead of 0 for cstr X * 17.Aug.87 jimmc Add fglname X * 18.Aug.87 jimmc Add fgtype, fgspouse X * 24.Aug.87 jimmc Add fgburied X * 25.Aug.87 jimmc Add fgnmarriage X * 18.Sep.87 jimmc Add #include xalloc.h; add fgaddrphn X * 26.Oct.87 jimmc Remove basic routines into fgdatsubs.c X * 27.Oct.87 jimmc Add fggen X * 1.Jan.88 jimmc Make fgtnote and fggen also pick up TGEN; add fglpname X * 4.Jan.88 jimmc Add fglhname X * 8.Jan.88 jimmc Lint cleanup X */ 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 freestr() function. X * The functions in this file in general refer to and format specific X * fields; the functions in fgdatsubs are more general, without references X * to specific fields. X * In the arguments, i is an ID for an individual's record; f is an ID for X * a family record, and n is an ID for either (or sometimes any record kind). X * Functions which return an allocated string are: X * fgsname(i) just the nickname; else first name; else middle name; else "?" X * fgtname(i) all of name but last name X * fglname(f) last name of a family only X * fglpname(f) last name of a family plus names of parents X * fgbname(i) full born (maiden) name X * fgfname(i) full name (including maiden and married last names) X * fgbirth(i) birth date and place X * fgdeath(i) death date and place X * fgburied(i) burial location X * fgbrtdeath(i) birth and death dates X * fgmarriage(f) marriage date and place X * fgnmarriage(f) marriage date and place, and number if +n switch X * fgtnote(n) TNOTE plus TGEN X * fggen(n) GEN plus TGEN X * Functions which return an integer are: X * fgspouse(f_m,i_n) returns the spouse for marriage f_m who is not i_n X * fgbclist(f,av) get child list; return valus is ac, fills array av X * fgclist(f,avp) get child list; return value is ac, fills pointer avp X * fgbslist(i,av) get spouse list; return valus is ac, fills array av X * fgslist(i,avp) get spouse list; return value is ac, fills pointer avp X * Other functions: X * fgtype(n) returns single character which is type code (e.g. 'I') X */ X X#include <stdio.h> X#include <strings.h> X#include "geneal.h" X#include "xalloc.h" X Xextern char *strcrep(); X X/* for forward references */ Xchar *fgdateplace(); X X/*..........*/ X Xint Xfgtype(n) /* get a type character from the file */ Xint n; X{ X return fgchar(n,"T"); X} X X/*..........*/ X Xint Xfgspouse(m,n) Xint m; /* id of the marriage */ Xint n; /* id of the spouse we DONT want */ X{ X int t; X X t = fgnum(m,"H"); X if (t>0 && t!=n) return t; X t = fgnum(m,"W"); X if (t>0 && t!=n) return t; X return -1; X} X X/*..........*/ X Xchar * Xfgsname(n) /* short name (first name or whatever) */ Xint n; X{ X char xname[200]; X int l; X X xname[0] = 0; X addindex(xname,n); X addncstr(xname,n,"PN"); X l = strlen(xname); X addncstr(xname,n,"NN"); /* use nickname if there */ X if (!xname[l]) addncstr(xname,n,"FN"); X if (!xname[l]) addncstr(xname,n,"MN"); X if (!xname[l]) addcstr(xname,"??"); X addncstr(xname,n,"SN"); X return strsav(xname); X} X X/*..........*/ X Xchar * Xfgtname(n) /* get the full name (except last name) */ Xint n; /* person to get data item for */ X{ X char xname[200]; X X xname[0] = 0; /* start with null */ X addindex(xname,n); /* put in id number if requested */ X addncstr(xname,n,"PN"); /* prefix name */ X addncstr(xname,n,"FN"); /* add first name */ X addncstr(xname,n,"MN"); /* add middle name */ X addnpstr(xname,n,"NN"); /* add nickname in parens */ X addncstr(xname,n,"SN"); /* suffix name */ X return strsav(xname); X} X X/*..........*/ X Xchar * Xfglname(f) Xint f; /* family id number */ X{ X char xname[200]; X X xname[0] = 0; /* start with null */ X addindex(xname,f); /* put in id number if requested */ X addncstr(xname,f,"N"); /* the name */ X return strsav(xname); X} X X/*..........*/ X Xchar * Xfglpname(f) Xint f; /* family id number */ X{ X char xname[200]; X int h,w; X char *fn, *hln, *wln, *hfn, *wfn, *fpn; X X xname[0] = 0; X addindex(xname,f); X fn = fgstr(f,"N"); /* get family last name */ X h = fgnum(f,"H"); /* husband and wife ID numbers */ X w = fgnum(f,"W"); X if (h<=0 && w<=0) { X addcstr(xname,fn); X freestr(fn); X return strsav(xname); X } X hln = fgstr(h,"LN"); X wln = fgstr(w,"LN.A"); /*** sex-biased assumptions about names... */ X hfn = fgsname(h); X wfn = fgsname(w); X if (strcmp(fn,hln)==0 && strcmp(fn,wln)==0) { X fpn = tprintf("%s and %s %s", hfn, wfn, fn); X } X else if (strcmp(fn,hln)==0) { X if (wln && wln[0]) X fpn = tprintf("%s %s and %s %s", hfn, hln, wfn, wln); X else X fpn = tprintf("%s %s and %s", hfn, hln, wfn); X } X else { X fpn = tprintf("%s: %s %s and %s %s", fn, hfn, hln, wfn, wln); X } X addcstr(xname,fpn); X freestr(hln); X freestr(wln); X freestr(hfn); X freestr(wfn); X freestr(fn); X freestr(fpn); X return strsav(xname); X} X X/*..........*/ X Xchar * Xfglhname(f) Xint f; /* family id number */ X{ X char xname[200]; X int h,w; X char *hpn, *wpn, *fn; X X xname[0] = 0; X addindex(xname,f); X h = fgnum(f,"H"); /* husband and wife ID numbers */ X w = fgnum(f,"W"); X hpn = fgstr(h,"PN"); X if (!hpn || !hpn[0]) hpn="Mr."; X wpn = fgstr(w,"PN"); X if (!wpn || !wpn[0]) wpn="Mrs."; X addcstr(xname,hpn); X addcstr(xname,"and"); X addcstr(xname,wpn); X freestr(hpn); X freestr(wpn); X if (h>0) { X addncstr(xname,h,"FN"); X addncstr(xname,h,"MN"); X addnpstr(xname,h,"NN"); X addncstr(xname,h,"LN"); X addncstr(xname,h,"SN"); X } X else { X fn = fgstr(f,"N"); /* get family last name */ X addcstr(xname,fn); X freestr(fn); X } X return strsav(xname); X} X X/*..........*/ X Xchar * Xfgbname(n) /* get the full born name */ Xint n; /* person to get data item for */ X{ X char xname[200]; X X xname[0] = 0; /* start with null */ X addindex(xname,n); /* put in id number if requested */ X addncstr(xname,n,"PN"); X addncstr(xname,n,"FN"); X addncstr(xname,n,"MN"); X addnpstr(xname,n,"NN"); X addncstr(xname,n,"LN"); X addncstr(xname,n,"SN"); X return strsav(xname); X} X X/*..........*/ X Xchar * Xfgfname(n) /* get the full name */ Xint n; /* person to get data item for */ X{ X char xname[200]; X char lnaname[200]; X X fgbstr(n,"LN.A",lnaname); X strcrep(lnaname, ';', ' '); /* convert semicolons to space */ X xname[0] = 0; /* start with null */ X addindex(xname,n); /* put in id number if requested */ X addncstr(xname,n,"PN"); X addncstr(xname,n,"FN"); X addncstr(xname,n,"MN"); X addnpstr(xname,n,"NN"); X addncstr(xname,n,"LN"); X addcstr(xname,lnaname); X addncstr(xname,n,"SN"); 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 * Xfgburied(n) /* get burail place */ Xint n; /* person to get data item for */ X{ X char b[1000]; X X fgbstr(n,"BUR",b); X if (*b) return tprintf("bur: %s",b); X else return strsav(""); X} X X/*..........*/ X Xchar * Xfgbrtdeath(n) /* get birth/death date info */ Xint n; /* person to get data item for */ X{ X char bdate[100], ddate[100], dates[200]; X X fgbstr(n,"B",bdate); /* get birth date */ X fgbstr(n,"D",ddate); /* get death date */ X if (*bdate==0 && *ddate==0) return ""; X if (*ddate==0) sprintf(dates," ( b: %s )", bdate); X else if (*bdate==0) sprintf(dates," ( d: %s )", ddate); X else sprintf(dates," ( b: %s, d: %s )", bdate, ddate); X return strsav(dates); X} X X/*..........*/ X Xchar * Xfgmarriage(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 * Xfgnmarriage(n) /* get marriage date info and optionally number */ Xint n; /* person to get data item for */ X{ X char *s, *t; X X s = fgdateplace(n,"M","MP","m"); X if (!Gflag['n']) return s; X t = tprintf("%s [%d]",s,n); X freestr(s); X return t; X} X X/*..........*/ X Xchar *fgt2gen(n,item) Xint n; Xchar *item; X{ Xchar *tgen; Xchar *istr; Xchar *rstr; X X tgen = fgstr(n,"TGEN"); X istr = fgstr(n,item); X if (tgen && tgen[0] && istr && istr[0]) { X rstr = tprintf("%s\n%s",tgen,istr); X freestr(tgen); X freestr(istr); X return rstr; X } X if (tgen && tgen[0]) return tgen; X return istr; X} X Xchar * fgtnote(n) int n; { return fgt2gen(n,"TNOTE"); } Xchar * fggen(n) int n; { return fgt2gen(n,"GEN"); } X X/*..........*/ X Xchar * Xfgaddrphn(n) Xint n; X{ X char addr[1000]; X char phone[1000]; X char *t; X X fgbstr(n,"ADDR",addr); X fgbstr(n,"PHONE",phone); X if (*addr && *phone) X t = tprintf("%s\n%s",addr,phone); X else if (*addr) X t = strsav(addr); X else if (*phone) X t = strsav(phone); X else X t = strsav(""); X return t; X} X X/*..........*/ X Xint Xfgclist(n,avp) /* get child list into allocated array */ Xint n; /* family to get list for */ Xint **avp; /* where we should put the pointer to the array */ X{ X return fglist(n,"C",avp); X} X X/*..........*/ X Xint Xfgbclist(n,av) /* get child list into specified array */ Xint n; /* family to get list for */ Xint *av; /* where we should put the data */ X{ X return fgblist(n,"C",av); X} X X/*..........*/ X Xint Xfgslist(n,avp) /* get spouse list into allocated array */ Xint n; /* person to get list for */ Xint **avp; /* where we should put the pointer to the array */ X{ X return fglist(n,"S",avp); X} X X/*..........*/ X Xint Xfgbslist(n,av) /* get spouse list into specified array */ Xint n; /* person to get list for */ Xint *av; /* where we should put the data */ X{ X return fgblist(n,"S",av); 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{ X char date[100], place[100]; X X fgbstr(n,dk,date); /* get date */ X fgbstr(n,pk,place); /* get place */ X if (*date==0 && *place==0) return ""; X if (*date && *place) return tprintf("%s: %s, %s", cc, date, place); X if (*date) return tprintf("%s: %s", cc, date); X return tprintf("%s: %s", cc, place); X} X X/*..........*/ X Xaddncstr(dd,n,ff) /* add a field value onto a string */ Xchar *dd; /* the string being built */ Xint n; /* record number */ Xchar *ff; /* name of field to get from that record */ X{ X char buf[1000]; X X fgbstr(n,ff,buf); X addcstr(dd,buf); X} X X/*..........*/ X Xaddnpstr(dd,n,ff) /* add a field value onto a string in parens */ Xchar *dd; /* the string being built */ Xint n; /* record number */ Xchar *ff; /* name of field to get from that record */ X{ X char buf[1000]; X X fgbstr(n,ff,buf); X addpstr(dd,buf); 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 if (dd[0]) strcat(dd," "); 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 if (dd[0]) strcat(dd," "); X strcat(dd,"("); X strcat(dd,ss); /* add the string in parens */ X strcat(dd,")"); X } X} X X/*..........*/ X Xaddindex(ss,n) Xchar *ss; /* the string to add to */ Xint n; /* id number of person */ X{ X if (Gflag['N']) X sprintf(ss,"[%d/%d]", n, fgnum(n,"P")); X /* put in both individual and family if requested */ X else if (Gflag['n']) X sprintf(ss, "[%d]", n); /* put in the id number */ X /* if neither flag set, put in nothing */ X} X X/* end */ END_OF_FILE if test 11824 -ne `wc -c <'fgdat.c'`; then echo shar: \"'fgdat.c'\" unpacked with wrong size! fi # end of 'fgdat.c' fi echo shar: End of archive 3 \(of 4\). cp /dev/null ark3isdone 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.