home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / geneal / part03 / famntree.c < prev    next >
C/C++ Source or Header  |  1989-03-08  |  10KB  |  482 lines

  1. /* famntree.c - produce output suitable for treepar
  2.  *
  3.  * 13.Aug.87  jimmc  Initial definition
  4.  * 14.Aug.87  jimmc  Add globals, textsize
  5.  * 18.Aug.87  jimmc  Add spouse stuff
  6.  * 24.Aug.87  jimmc  Add label
  7.  * 31.Aug.87  jimmc  Add bd2
  8.  * 14.Sep.87  jimmc  Allow multiple line tnotes
  9.  * 16.Sep.87  jimmc  Fix bug in fam1fs when id==-1
  10.  * 18.Sep.87  jimmc  Add #include xalloc.h; use XCALLOC instead of XALLOC;
  11.  *            add 'addr' field.
  12.  * 21.Sep.87  jimmc  Use info arrays instead of separate structure members
  13.  *            add 'buried' field.
  14.  * 27.Oct.87  jimmc  Make countlines() and linewidth() global
  15.  *  1.Jan.88  jimmc  Use fglpname instead of fglname
  16.  *  8.Jan.88  jimmc  Direct output to outfp instead of stdout; lint cleanup
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <strings.h>
  22. #include "geneal.h"
  23. #include "famntree.h"
  24. #include "xalloc.h"
  25.  
  26. #define SX 6
  27. #define SY 10
  28. #define YOFF (SY/3)
  29. #define ROWSPACE 20
  30. #define TRACKSPACE 20
  31. #define IROWSPACE 30
  32.  
  33. #define NOTNULL(str) ((str)&&(str[0]))
  34.  
  35. extern char *strsave(), *strsave2();
  36.  
  37. extern char *Label;
  38.  
  39. static int ypos;
  40.  
  41. static
  42. char *
  43. pad(padstr,str)
  44. char *padstr;
  45. char *str;
  46. {
  47.     char *new;
  48.  
  49.     new = strsave2(padstr,str);
  50.     free(str);
  51.     return new;
  52. }
  53.  
  54. static
  55. char *
  56. cpad(padstr,str)
  57. char *padstr;
  58. char *str;
  59. {
  60.  
  61.     if (!str || !*str) return 0;
  62.     return pad(padstr,str);
  63. }
  64.  
  65. static
  66. printsbody(f,s)
  67. FILE *f;
  68. char *s;
  69. {
  70.     if (!s) return;
  71.     for (;*s;s++) {
  72.         if (isprint(*s)) {
  73.             if (*s=='"') fputc('\\',f);
  74.             fputc(*s,f);
  75.         }
  76.         else if (*s=='\n') fputs("\\n\\\n",f);
  77.         else fprintf(f,"\\%03o",*s);
  78.     }
  79. }
  80.  
  81. static
  82. printmbody(f,s)    /* like printsbody, but indents all lines based on first */
  83. FILE *f;
  84. char *s;
  85. {
  86.     int i,n;
  87.  
  88.     if (!s) return;
  89.     for (n=0; s[n]==' ';n++) ;    /* EMPTY - count spaces */
  90.     for (;*s;s++) {
  91.         if (isprint(*s)) {
  92.             if (*s=='"') fputc('\\',f);
  93.             fputc(*s,f);
  94.         }
  95.         else if (*s=='\n') {
  96.             fputs("\\n\\\n",f);
  97.             if (s[1]) for(i=0; i<n; i++) fputc(' ',f);
  98.             /* indent following lines by same amount */
  99.         }
  100.         else fprintf(f,"\\%03o",*s);
  101.     }
  102. }
  103.  
  104. static
  105. printstring(f,s)
  106. FILE *f;
  107. char *s;
  108. {
  109.     fputc('"',f);
  110.     printsbody(f,s);
  111.     fputc('"',f);
  112. }
  113.  
  114. static
  115. printsline(f,s)
  116. FILE *f;
  117. char *s;
  118. {
  119.     if (NOTNULL(s)) {
  120.         printmbody(f,s);
  121.         printsbody(f,"\n");
  122.     }
  123. }
  124.  
  125. int 
  126. countlines(s)
  127. char *s;
  128. {
  129.     int n;
  130.  
  131.     if (!s || !s[0]) return 0;
  132.     n=1;
  133.     while (s) {
  134.         s = index(s,'\n');
  135.         if (s) {
  136.             n++;
  137.             s++;
  138.         }
  139.     }
  140.     return n;
  141. }
  142.  
  143. int
  144. linewidth(s)
  145. char *s;
  146. {
  147.     int l,newl;
  148.     char *p;
  149.  
  150.     if (!s || !s[0]) return 0;
  151.     l = 0;
  152.     while (s) {
  153.         p = index(s,'\n');
  154.         if (p) {
  155.             newl = p-s;
  156.             s = p+1;
  157.         }
  158.         else {
  159.             newl = strlen(s);
  160.             s = p;
  161.         }
  162.         if (newl>l) l=newl;
  163.     }
  164.     return l;
  165. }
  166.  
  167. static
  168. famschema()
  169. {
  170.     fprintf(outfp,"globals schema (\"textsizex.i\" \"textsizey.i\" \
  171. \"rowposspace.i\" \"rowdir.s\" \"trackspace.i\" \
  172. \"interrowspace.i\" \"label.s\")\n");
  173.     fprintf(outfp,"globals (%d %d %d \"V\" %d %d ",
  174.         SX, SY, ROWSPACE, TRACKSPACE, IROWSPACE);
  175.     printstring(outfp,Label?Label:"");
  176.     fprintf(outfp,")\n\n");
  177.  
  178.     fprintf(outfp,"box schema (\"name.s\" \"sizex.i\" \"sizey.i\" \
  179. \"orgx.i\" \"orgy.i\"\n\t\"text.s\" \"textx.i\" \"texty.i\" \"textpos.s\")\n");
  180.     fprintf(outfp,"conn schema (\"boxname.s\" \"name.s\" \
  181. \"x.i\" \"y.i\" \"side.s\" \"netname.s\")\n\n");
  182. }
  183.  
  184. static
  185. fam1out(fi)
  186. Famninfo *fi;
  187. {
  188.     int i,j,n;
  189.     Fammember *fm;
  190.     Fammemspouse *fs;
  191.     int linecount,slinecount;
  192.  
  193.     fprintf(outfp,"box (\"%s\" %d %d %d %d \"",
  194.         fi->boxname, SX*(fi->cols+2), SY*(fi->lines+2),
  195.         SX*0, SY*(ypos+=30,ypos-30));
  196.     for (n=0; n<FISIZE; n++)
  197.         printsline(outfp,fi->info[n]);
  198.     for (i=0; i<fi->namelen; i++)
  199.         fputc('=',outfp);
  200.     fprintf(outfp,"\\n\\\n");
  201.     for (i=0; i<fi->mcount; i++) {
  202.         fm = fi->mlist+i;
  203.         for (n=0; n<FMSIZE; n++)
  204.             printsline(outfp,fm->info[n]);
  205.         if (Gflag['m']) {
  206.             for (j=0; j<fm->scount; j++) {
  207.                 fs = fm->slist+j;
  208.                 for (n=0; n<FSSIZE; n++)
  209.                     printsline(outfp,fs->info[n]);
  210.             }
  211.         }
  212.     }
  213.     fprintf(outfp,"\" %d %d \"NW\")\n", SX*1, SY*(fi->lines+1));
  214.  
  215.     /* output connectors for the box */
  216.     if (Gflag['m']) {
  217.         /* output connectors for parents */
  218.         if (fi->famid>0) {
  219.             fprintf(outfp,
  220.                 "conn (\"%s\" \"f%d\" %d  %d \"W\" \"f%d\")\n",
  221.                 fi->boxname, fi->famid,
  222.                 SX*0, SY*((fi->lines+2)/2), fi->famid);
  223.         }
  224.         /* output connectors for member marriages */
  225.         linecount = fi->headerlines;
  226.         for (i=0; i<fi->mcount; i++) {
  227.             fm = fi->mlist+i;
  228.             slinecount = linecount+fm->headerlines;
  229.             if (fm->id>0) for (j=0; j<fm->scount; j++) {
  230.                 fs = fm->slist+j;
  231.                 if (fs->mid>0) {
  232.                     fprintf(outfp,
  233.                         "conn (\"%s\" \"f%d\" %d %d \"E\" \"f%d\")\n",
  234.                         fi->boxname, fs->mid,
  235.                         SX*(fs->connx+1),
  236.                         SY*(fi->lines-slinecount)+YOFF,
  237.                         fs->mid);
  238.                 }
  239.                 slinecount += fs->lines;
  240.             }
  241.             linecount += fm->lines;
  242.         }
  243.     }
  244.     else {
  245.         /* output connectors for parents */
  246.         if (fi->fatherid>0) {
  247.             fprintf(outfp,
  248.                 "conn (\"%s\" \"i%d\" %d  %d \"W\" \"i%d\")\n",
  249.                 fi->boxname, fi->fatherid,
  250.                 SX*0, SY*(fi->lines+1), fi->fatherid);
  251.         }
  252.         if (fi->motherid>0) {
  253.             fprintf(outfp,
  254.                 "conn (\"%s\" \"i%d\" %d  %d \"W\" \"i%d\")\n",
  255.                 fi->boxname, fi->motherid,
  256.                 SX*0, SY*1, fi->motherid);
  257.         }
  258.         /* output connectors for members */
  259.         linecount = fi->headerlines;
  260.         for (i=0; i<fi->mcount; i++) {
  261.             fm = fi->mlist+i;
  262.             if (fm->id>0) {
  263.                 fprintf(outfp,
  264.                     "conn (\"%s\" \"i%d\" %d %d \"E\" \"i%d\")\n",
  265.                     fi->boxname, fm->id,
  266.                     SX*(fm->connx+1),
  267.                     SY*(fi->lines-linecount)+YOFF,
  268.                     fm->id);
  269.             }
  270.             linecount += fm->lines;
  271.         }
  272.     }
  273. }
  274.  
  275. static
  276. fam1fs(fs,mid,fmid)
  277. Fammemspouse *fs;
  278. int mid;
  279. int fmid;
  280. {
  281.     int lines, cols;
  282.     int tt;
  283.     char *marr;
  284.     int i;
  285.  
  286.     fs->mid = mid,fmid;
  287.     fs->id = fgspouse(fs->mid,fmid);
  288.     marr = fgnmarriage(fs->mid);
  289.     if (NOTNULL(marr)) fs->info[FS_MD] = pad(" ",marr);
  290.     else fs->info[FS_MD] = strsave(" m: ");
  291.     if (Gflag['t']) {
  292.         fs->info[FS_MTNOTE] = cpad("  ",fgtnote(fs->mid));
  293.     }
  294.     if (fs->id>0) {
  295.         fs->info[FS_NAME] = cpad("  ",fgbname(fs->id));
  296.         if (Gflag['b']) {
  297.             fs->info[FS_BD] = cpad("   ",fgbirth(fs->id));
  298.             fs->info[FS_BD2] = cpad("   ",fgdeath(fs->id));
  299.             fs->info[FS_BUR] = cpad("   ",fgburied(fs->id));
  300.         } else {
  301.             fs->info[FS_BD] = cpad("  ",fgbrtdeath(fs->id));
  302.         }
  303.         if (Gflag['t']) {
  304.             fs->info[FS_TNOTE] = cpad("   ",fgtnote(fs->id));
  305.         }
  306.     }
  307.  
  308.     lines = 0;
  309.     cols = fs->connx = strlen(fs->info[FS_MD]);
  310.     for (i=0; i<FSSIZE; i++) {
  311.         lines += countlines(fs->info[i]);
  312.         if ((tt=linewidth(fs->info[i])) > cols) cols=tt;
  313.     }
  314.     fs->lines = lines;
  315.     fs->cols = cols;
  316. }
  317.  
  318. static
  319. fam1fm(fm)
  320. Fammember *fm;
  321. {
  322.     int lines, cols;
  323.     Fammemspouse *fs;
  324.     int *mlist;
  325.     int tt;
  326.     int i, n;
  327.  
  328.     fm->info[FM_NAME] = fgtname(fm->id);
  329.     if (Gflag['b']) {    /* extended birth/death info */
  330.         fm->info[FM_BD] = cpad(" ",fgbirth(fm->id));
  331.         fm->info[FM_BD2] = cpad(" ",fgdeath(fm->id));
  332.         fm->info[FM_BUR] = cpad(" ",fgburied(fm->id));
  333.     }
  334.     else {
  335.         fm->info[FM_BD] = fgbrtdeath(fm->id);
  336.     }
  337.     if (Gflag['t']) {
  338.         fm->info[FM_TNOTE] = cpad(" ",fgtnote(fm->id));
  339.     }
  340.  
  341.     lines = 0;
  342.     cols = fm->connx = strlen(fm->info[FM_NAME]);
  343.     for (i=0; i<FMSIZE; i++) {
  344.         lines += countlines(fm->info[i]);
  345.         if ((tt=linewidth(fm->info[i])) > cols) cols=tt;
  346.     }
  347.     fm->lines = fm->headerlines = lines;
  348.     fm->cols = cols;
  349.  
  350.     if (Gflag['m']) {    /* include spouse info if set */
  351.         fm->scount = fglist(fm->id,"S",&mlist);
  352.         fm->slist = XCALLOCM(Fammemspouse,fm->scount,"fam1fi spouse");
  353.         for (n=0; n<fm->scount; n++) {
  354.             fs = fm->slist+n;
  355.             fam1fs(fs,mlist[n],fm->id);
  356.             if (fs->cols > fm->cols) fm->cols=fs->cols;
  357.             fm->lines += fs->lines;
  358.         }
  359.     }
  360. }
  361.  
  362. static int
  363. fam1fi(fi)        /* stuff common to ind and fam */
  364. Famninfo *fi;        /* the family box to fill out */
  365. {
  366.     int lines, cols;
  367.     int tt;
  368.     int i;
  369.     Fammember *fm;
  370.     int addrnum;
  371.  
  372.     if (!fi->info[FI_NAME]) fi->info[FI_NAME] = strsave("****");
  373.     if (Gflag['b'] && !Gflag['m'] && fi->famid>0) {
  374.         fi->info[FI_MARR] = fgmarriage(fi->famid);
  375.     }
  376.     if (Gflag['t'] && fi->famid>0) {
  377.         fi->info[FI_TNOTE] = fgtnote(fi->famid);
  378.     }
  379.     if (Gflag['a'] && fi->famid>0) {
  380.         addrnum = fgnum(fi->famid,"ADDR");
  381.         if (addrnum>0) fi->info[FI_ADDR] = fgaddrphn(addrnum);
  382.     }
  383.  
  384.     lines = 1;    /* account for the line of "====" */
  385.     cols = 0;
  386.     for (i=0; i<FISIZE; i++) {
  387.         lines += countlines(fi->info[i]);
  388.         if ((tt=linewidth(fi->info[i])) > cols) cols=tt;
  389.     }
  390.     fi->lines = fi->headerlines = lines;
  391.     fi->cols = fi->namelen = cols;
  392.  
  393.     for (i=0; i<fi->mcount; i++) {
  394.         fm = fi->mlist+i;
  395.         fam1fm(fm);        /* fill out info for each member */
  396.         if (fm->cols > fi->cols) fi->cols=fm->cols;
  397.         fi->lines += fm->lines;
  398.     }
  399.     fi->fatherid = fgnum(fi->famid,"H");
  400.     fi->motherid = fgnum(fi->famid,"W");
  401.     fam1out(fi);    /* write out what we have so far */
  402.     return 0;
  403. }
  404.  
  405. static int
  406. fam1ind(id)
  407. int id;            /* id of family or individual to output for */
  408. {
  409.     Famninfo *fi;
  410.     Fammember *fm;
  411.     char buf[500];
  412.  
  413.     fi = XCALLOCM(Famninfo,1,"fam1ind fi");
  414.     fi->famid = fgnum(id,"P");
  415.     fi->info[FI_NAME] = fgstr(id,"LN");
  416.     sprintf(buf,"I%d",id);
  417.     fi->boxname = strsave(buf);
  418.     fi->mcount = 1;
  419.     fi->mlist = XCALLOCM(Fammember,1,"fam1ind members");
  420.     fm = fi->mlist+0;    /* point to first entry */
  421.     fm->id = id;
  422.     return fam1fi(fi);
  423. }
  424.  
  425. static int
  426. fam1fam(id)
  427. int id;            /* id of family or individual to output for */
  428. {
  429.     Famninfo *fi;
  430.     Fammember *fm;
  431.     int i;
  432.     int *clist;
  433.     char buf[500];
  434.  
  435.     fi = XCALLOCM(Famninfo,1,"fam1fam fi");
  436.     fi->famid = id;
  437. /*** used to use fglname instead of fglpname - should we have a switch? */
  438.     fi->info[FI_NAME] = fglpname(id);
  439.     sprintf(buf,"F%d",id);
  440.     fi->boxname = strsave(buf);
  441.     fi->mcount = fglist(id,"C",&clist);
  442.     fi->mlist = XCALLOCM(Fammember,fi->mcount,"fam1fam members");
  443.     for (i=0; i<fi->mcount; i++) {
  444.         fm = fi->mlist+i;
  445.         fm->id = clist[i];
  446.     }
  447.     if (clist) free((char *)clist);
  448.     return fam1fi(fi);
  449. }
  450.  
  451. static int            /* returns 0 if OK */
  452. fam1tree(id)
  453. int id;            /* id of family or individual to output for */
  454. {
  455.     switch (fgtype(id)) {
  456.     case 'I':
  457.         return fam1ind(id);
  458.     case 'F':
  459.         return fam1fam(id);
  460.     default:
  461.         return 0;
  462.     }
  463. }
  464.  
  465. int            /* returns 0 if OK */
  466. famntree(idcount,idlist)
  467. int idcount;        /* number of entries in idlist */
  468. int *idlist;        /* array of id numbers in the group to be output */
  469. {
  470.     int i;
  471.     int t=0;
  472.  
  473.     ypos=0;
  474.     famschema();        /* write out the schema */
  475.     for (i=0; i<idcount; i++) {
  476.         t += fam1tree(idlist[i]);
  477.     }
  478.     return t;
  479. }
  480.  
  481. /* end */
  482.