home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume18
/
geneal
/
part03
/
famntree.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-03-08
|
10KB
|
482 lines
/* famntree.c - produce output suitable for treepar
*
* 13.Aug.87 jimmc Initial definition
* 14.Aug.87 jimmc Add globals, textsize
* 18.Aug.87 jimmc Add spouse stuff
* 24.Aug.87 jimmc Add label
* 31.Aug.87 jimmc Add bd2
* 14.Sep.87 jimmc Allow multiple line tnotes
* 16.Sep.87 jimmc Fix bug in fam1fs when id==-1
* 18.Sep.87 jimmc Add #include xalloc.h; use XCALLOC instead of XALLOC;
* add 'addr' field.
* 21.Sep.87 jimmc Use info arrays instead of separate structure members
* add 'buried' field.
* 27.Oct.87 jimmc Make countlines() and linewidth() global
* 1.Jan.88 jimmc Use fglpname instead of fglname
* 8.Jan.88 jimmc Direct output to outfp instead of stdout; lint cleanup
*/
#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include "geneal.h"
#include "famntree.h"
#include "xalloc.h"
#define SX 6
#define SY 10
#define YOFF (SY/3)
#define ROWSPACE 20
#define TRACKSPACE 20
#define IROWSPACE 30
#define NOTNULL(str) ((str)&&(str[0]))
extern char *strsave(), *strsave2();
extern char *Label;
static int ypos;
static
char *
pad(padstr,str)
char *padstr;
char *str;
{
char *new;
new = strsave2(padstr,str);
free(str);
return new;
}
static
char *
cpad(padstr,str)
char *padstr;
char *str;
{
if (!str || !*str) return 0;
return pad(padstr,str);
}
static
printsbody(f,s)
FILE *f;
char *s;
{
if (!s) return;
for (;*s;s++) {
if (isprint(*s)) {
if (*s=='"') fputc('\\',f);
fputc(*s,f);
}
else if (*s=='\n') fputs("\\n\\\n",f);
else fprintf(f,"\\%03o",*s);
}
}
static
printmbody(f,s) /* like printsbody, but indents all lines based on first */
FILE *f;
char *s;
{
int i,n;
if (!s) return;
for (n=0; s[n]==' ';n++) ; /* EMPTY - count spaces */
for (;*s;s++) {
if (isprint(*s)) {
if (*s=='"') fputc('\\',f);
fputc(*s,f);
}
else if (*s=='\n') {
fputs("\\n\\\n",f);
if (s[1]) for(i=0; i<n; i++) fputc(' ',f);
/* indent following lines by same amount */
}
else fprintf(f,"\\%03o",*s);
}
}
static
printstring(f,s)
FILE *f;
char *s;
{
fputc('"',f);
printsbody(f,s);
fputc('"',f);
}
static
printsline(f,s)
FILE *f;
char *s;
{
if (NOTNULL(s)) {
printmbody(f,s);
printsbody(f,"\n");
}
}
int
countlines(s)
char *s;
{
int n;
if (!s || !s[0]) return 0;
n=1;
while (s) {
s = index(s,'\n');
if (s) {
n++;
s++;
}
}
return n;
}
int
linewidth(s)
char *s;
{
int l,newl;
char *p;
if (!s || !s[0]) return 0;
l = 0;
while (s) {
p = index(s,'\n');
if (p) {
newl = p-s;
s = p+1;
}
else {
newl = strlen(s);
s = p;
}
if (newl>l) l=newl;
}
return l;
}
static
famschema()
{
fprintf(outfp,"globals schema (\"textsizex.i\" \"textsizey.i\" \
\"rowposspace.i\" \"rowdir.s\" \"trackspace.i\" \
\"interrowspace.i\" \"label.s\")\n");
fprintf(outfp,"globals (%d %d %d \"V\" %d %d ",
SX, SY, ROWSPACE, TRACKSPACE, IROWSPACE);
printstring(outfp,Label?Label:"");
fprintf(outfp,")\n\n");
fprintf(outfp,"box schema (\"name.s\" \"sizex.i\" \"sizey.i\" \
\"orgx.i\" \"orgy.i\"\n\t\"text.s\" \"textx.i\" \"texty.i\" \"textpos.s\")\n");
fprintf(outfp,"conn schema (\"boxname.s\" \"name.s\" \
\"x.i\" \"y.i\" \"side.s\" \"netname.s\")\n\n");
}
static
fam1out(fi)
Famninfo *fi;
{
int i,j,n;
Fammember *fm;
Fammemspouse *fs;
int linecount,slinecount;
fprintf(outfp,"box (\"%s\" %d %d %d %d \"",
fi->boxname, SX*(fi->cols+2), SY*(fi->lines+2),
SX*0, SY*(ypos+=30,ypos-30));
for (n=0; n<FISIZE; n++)
printsline(outfp,fi->info[n]);
for (i=0; i<fi->namelen; i++)
fputc('=',outfp);
fprintf(outfp,"\\n\\\n");
for (i=0; i<fi->mcount; i++) {
fm = fi->mlist+i;
for (n=0; n<FMSIZE; n++)
printsline(outfp,fm->info[n]);
if (Gflag['m']) {
for (j=0; j<fm->scount; j++) {
fs = fm->slist+j;
for (n=0; n<FSSIZE; n++)
printsline(outfp,fs->info[n]);
}
}
}
fprintf(outfp,"\" %d %d \"NW\")\n", SX*1, SY*(fi->lines+1));
/* output connectors for the box */
if (Gflag['m']) {
/* output connectors for parents */
if (fi->famid>0) {
fprintf(outfp,
"conn (\"%s\" \"f%d\" %d %d \"W\" \"f%d\")\n",
fi->boxname, fi->famid,
SX*0, SY*((fi->lines+2)/2), fi->famid);
}
/* output connectors for member marriages */
linecount = fi->headerlines;
for (i=0; i<fi->mcount; i++) {
fm = fi->mlist+i;
slinecount = linecount+fm->headerlines;
if (fm->id>0) for (j=0; j<fm->scount; j++) {
fs = fm->slist+j;
if (fs->mid>0) {
fprintf(outfp,
"conn (\"%s\" \"f%d\" %d %d \"E\" \"f%d\")\n",
fi->boxname, fs->mid,
SX*(fs->connx+1),
SY*(fi->lines-slinecount)+YOFF,
fs->mid);
}
slinecount += fs->lines;
}
linecount += fm->lines;
}
}
else {
/* output connectors for parents */
if (fi->fatherid>0) {
fprintf(outfp,
"conn (\"%s\" \"i%d\" %d %d \"W\" \"i%d\")\n",
fi->boxname, fi->fatherid,
SX*0, SY*(fi->lines+1), fi->fatherid);
}
if (fi->motherid>0) {
fprintf(outfp,
"conn (\"%s\" \"i%d\" %d %d \"W\" \"i%d\")\n",
fi->boxname, fi->motherid,
SX*0, SY*1, fi->motherid);
}
/* output connectors for members */
linecount = fi->headerlines;
for (i=0; i<fi->mcount; i++) {
fm = fi->mlist+i;
if (fm->id>0) {
fprintf(outfp,
"conn (\"%s\" \"i%d\" %d %d \"E\" \"i%d\")\n",
fi->boxname, fm->id,
SX*(fm->connx+1),
SY*(fi->lines-linecount)+YOFF,
fm->id);
}
linecount += fm->lines;
}
}
}
static
fam1fs(fs,mid,fmid)
Fammemspouse *fs;
int mid;
int fmid;
{
int lines, cols;
int tt;
char *marr;
int i;
fs->mid = mid,fmid;
fs->id = fgspouse(fs->mid,fmid);
marr = fgnmarriage(fs->mid);
if (NOTNULL(marr)) fs->info[FS_MD] = pad(" ",marr);
else fs->info[FS_MD] = strsave(" m: ");
if (Gflag['t']) {
fs->info[FS_MTNOTE] = cpad(" ",fgtnote(fs->mid));
}
if (fs->id>0) {
fs->info[FS_NAME] = cpad(" ",fgbname(fs->id));
if (Gflag['b']) {
fs->info[FS_BD] = cpad(" ",fgbirth(fs->id));
fs->info[FS_BD2] = cpad(" ",fgdeath(fs->id));
fs->info[FS_BUR] = cpad(" ",fgburied(fs->id));
} else {
fs->info[FS_BD] = cpad(" ",fgbrtdeath(fs->id));
}
if (Gflag['t']) {
fs->info[FS_TNOTE] = cpad(" ",fgtnote(fs->id));
}
}
lines = 0;
cols = fs->connx = strlen(fs->info[FS_MD]);
for (i=0; i<FSSIZE; i++) {
lines += countlines(fs->info[i]);
if ((tt=linewidth(fs->info[i])) > cols) cols=tt;
}
fs->lines = lines;
fs->cols = cols;
}
static
fam1fm(fm)
Fammember *fm;
{
int lines, cols;
Fammemspouse *fs;
int *mlist;
int tt;
int i, n;
fm->info[FM_NAME] = fgtname(fm->id);
if (Gflag['b']) { /* extended birth/death info */
fm->info[FM_BD] = cpad(" ",fgbirth(fm->id));
fm->info[FM_BD2] = cpad(" ",fgdeath(fm->id));
fm->info[FM_BUR] = cpad(" ",fgburied(fm->id));
}
else {
fm->info[FM_BD] = fgbrtdeath(fm->id);
}
if (Gflag['t']) {
fm->info[FM_TNOTE] = cpad(" ",fgtnote(fm->id));
}
lines = 0;
cols = fm->connx = strlen(fm->info[FM_NAME]);
for (i=0; i<FMSIZE; i++) {
lines += countlines(fm->info[i]);
if ((tt=linewidth(fm->info[i])) > cols) cols=tt;
}
fm->lines = fm->headerlines = lines;
fm->cols = cols;
if (Gflag['m']) { /* include spouse info if set */
fm->scount = fglist(fm->id,"S",&mlist);
fm->slist = XCALLOCM(Fammemspouse,fm->scount,"fam1fi spouse");
for (n=0; n<fm->scount; n++) {
fs = fm->slist+n;
fam1fs(fs,mlist[n],fm->id);
if (fs->cols > fm->cols) fm->cols=fs->cols;
fm->lines += fs->lines;
}
}
}
static int
fam1fi(fi) /* stuff common to ind and fam */
Famninfo *fi; /* the family box to fill out */
{
int lines, cols;
int tt;
int i;
Fammember *fm;
int addrnum;
if (!fi->info[FI_NAME]) fi->info[FI_NAME] = strsave("****");
if (Gflag['b'] && !Gflag['m'] && fi->famid>0) {
fi->info[FI_MARR] = fgmarriage(fi->famid);
}
if (Gflag['t'] && fi->famid>0) {
fi->info[FI_TNOTE] = fgtnote(fi->famid);
}
if (Gflag['a'] && fi->famid>0) {
addrnum = fgnum(fi->famid,"ADDR");
if (addrnum>0) fi->info[FI_ADDR] = fgaddrphn(addrnum);
}
lines = 1; /* account for the line of "====" */
cols = 0;
for (i=0; i<FISIZE; i++) {
lines += countlines(fi->info[i]);
if ((tt=linewidth(fi->info[i])) > cols) cols=tt;
}
fi->lines = fi->headerlines = lines;
fi->cols = fi->namelen = cols;
for (i=0; i<fi->mcount; i++) {
fm = fi->mlist+i;
fam1fm(fm); /* fill out info for each member */
if (fm->cols > fi->cols) fi->cols=fm->cols;
fi->lines += fm->lines;
}
fi->fatherid = fgnum(fi->famid,"H");
fi->motherid = fgnum(fi->famid,"W");
fam1out(fi); /* write out what we have so far */
return 0;
}
static int
fam1ind(id)
int id; /* id of family or individual to output for */
{
Famninfo *fi;
Fammember *fm;
char buf[500];
fi = XCALLOCM(Famninfo,1,"fam1ind fi");
fi->famid = fgnum(id,"P");
fi->info[FI_NAME] = fgstr(id,"LN");
sprintf(buf,"I%d",id);
fi->boxname = strsave(buf);
fi->mcount = 1;
fi->mlist = XCALLOCM(Fammember,1,"fam1ind members");
fm = fi->mlist+0; /* point to first entry */
fm->id = id;
return fam1fi(fi);
}
static int
fam1fam(id)
int id; /* id of family or individual to output for */
{
Famninfo *fi;
Fammember *fm;
int i;
int *clist;
char buf[500];
fi = XCALLOCM(Famninfo,1,"fam1fam fi");
fi->famid = id;
/*** used to use fglname instead of fglpname - should we have a switch? */
fi->info[FI_NAME] = fglpname(id);
sprintf(buf,"F%d",id);
fi->boxname = strsave(buf);
fi->mcount = fglist(id,"C",&clist);
fi->mlist = XCALLOCM(Fammember,fi->mcount,"fam1fam members");
for (i=0; i<fi->mcount; i++) {
fm = fi->mlist+i;
fm->id = clist[i];
}
if (clist) free((char *)clist);
return fam1fi(fi);
}
static int /* returns 0 if OK */
fam1tree(id)
int id; /* id of family or individual to output for */
{
switch (fgtype(id)) {
case 'I':
return fam1ind(id);
case 'F':
return fam1fam(id);
default:
return 0;
}
}
int /* returns 0 if OK */
famntree(idcount,idlist)
int idcount; /* number of entries in idlist */
int *idlist; /* array of id numbers in the group to be output */
{
int i;
int t=0;
ypos=0;
famschema(); /* write out the schema */
for (i=0; i<idcount; i++) {
t += fam1tree(idlist[i]);
}
return t;
}
/* end */