v18i013: Geneal, a genealogy browsing program, Part03/03
Rich Salz
rsalz at uunet.uu.net
Fri Mar 10 08:57:15 AEST 1989
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 at 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 at uunet.uu.net.
More information about the Comp.sources.unix
mailing list