home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / FTREE0.3.LHA / ftree / src / RCS / main.c,v < prev    next >
Encoding:
Text File  |  1994-04-29  |  42.3 KB  |  2,213 lines

  1. head    1.12;
  2. access;
  3. symbols
  4.     stage1:1.8;
  5. locks; strict;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.12
  10. date    94.04.30.00.29.27;    author peteric;    state Exp;
  11. branches;
  12. next    1.11;
  13.  
  14. 1.11
  15. date    94.04.29.23.46.46;    author peteric;    state Exp;
  16. branches;
  17. next    1.10;
  18.  
  19. 1.10
  20. date    94.04.27.11.37.54;    author peteric;    state Exp;
  21. branches;
  22. next    1.9;
  23.  
  24. 1.9
  25. date    94.03.26.11.28.03;    author peteric;    state Exp;
  26. branches;
  27. next    1.8;
  28.  
  29. 1.8
  30. date    94.03.10.21.28.26;    author peteric;    state Exp;
  31. branches;
  32. next    1.7;
  33.  
  34. 1.7
  35. date    94.03.07.12.44.14;    author peteric;    state Exp;
  36. branches;
  37. next    1.6;
  38.  
  39. 1.6
  40. date    94.03.01.23.18.45;    author peteric;    state Exp;
  41. branches;
  42. next    1.5;
  43.  
  44. 1.5
  45. date    94.02.27.19.34.47;    author peteric;    state Exp;
  46. branches;
  47. next    1.4;
  48.  
  49. 1.4
  50. date    94.02.13.16.44.05;    author peteric;    state Exp;
  51. branches;
  52. next    1.3;
  53.  
  54. 1.3
  55. date    94.02.12.20.32.53;    author peteric;    state Exp;
  56. branches;
  57. next    1.2;
  58.  
  59. 1.2
  60. date    94.02.12.20.00.20;    author peteric;    state Exp;
  61. branches;
  62. next    1.1;
  63.  
  64. 1.1
  65. date    94.02.12.19.51.34;    author peteric;    state Exp;
  66. branches;
  67. next    ;
  68.  
  69.  
  70. desc
  71. @main routine for ftree family tree formatter.
  72. @
  73.  
  74.  
  75. 1.12
  76. log
  77. @Included Amiga Version string.
  78. @
  79. text
  80. @/*************************************************************************
  81.  *
  82.  *     $RCSFile$
  83.  *
  84.  *    $Author: peteric $
  85.  *
  86.  *    $Date: 1994/04/29 23:46:46 $
  87.  *
  88.  *    $Revision: 1.11 $
  89.  *
  90.  *    Purpose:    Main routine for ftree family tree formatter.
  91.  *            
  92.  *    $Log: main.c,v $
  93.  * Revision 1.11  1994/04/29  23:46:46  peteric
  94.  * Added 'datewidth' initialisation.
  95.  *
  96.  * Revision 1.10  1994/04/27  11:37:54  peteric
  97.  * New options added (-M - multipage, -q - quick). Sorted out
  98.  * a couple of uninitialised variables in the person & marriage
  99.  * structures & reorganised into structure order. Added option
  100.  * to specify size of page in inches. Deleted 'mparent' and
  101.  * 'fparent' links - these can be got from the 'parents' links.
  102.  * Set up 'married flag from makemarried & ensure it is set for
  103.  * both parents (previously only set for parent who was a child
  104.  * of someone on the tree!).
  105.  * Changed 'con' name to more standard '-' name when output to stdout
  106.  * wanted. Added macro 'dbprintf_note' for messages wanted on-screen
  107.  * and in the log file. Changed the log file name to ram:debug.ftree
  108.  * for Amiga use.
  109.  * Moved some code for setting person & marriage widths into layout.c
  110.  * Adjusted the code which determined the vertical space to do it
  111.  * properly - i.e. not assume the 'person' font size is close enough for
  112.  * all the other fonts.
  113.  * Made the program exit if an input file not found.
  114.  * Modified some default options settings - reduced margin for paper area
  115.  * mainly.
  116.  *
  117.  * Revision 1.9  1994/03/26  11:28:03  peteric
  118.  * Minor changes to include loadfont() calls.
  119.  *
  120.  * Revision 1.8  1994/03/10  21:28:26  peteric
  121.  * Multiple pages working!
  122.  *
  123.  * Revision 1.7  1994/03/07  12:44:14  peteric
  124.  * Passed on as first Version.
  125.  *
  126.  * Revision 1.6  1994/03/01  23:18:45  peteric
  127.  * added landscape version of a4 paper size.
  128.  *
  129.  * Revision 1.5  94/02/27  19:34:47  19:34:47  peteric (Peter Ivimey-Cook)
  130.  * added initialisations for extended structures, added new font handling code
  131.  * and new font types, improved error message system
  132.  * 
  133.  * Revision 1.4  1994/02/13  16:44:05  peteric
  134.  * Various changes; include new nextmarriage() to support multiple
  135.  * marriages & corrected some of the setup code; now -sX works!
  136.  *
  137.  * Revision 1.3  1994/02/12  20:32:53  peteric
  138.  * added function comments.
  139.  *
  140.  * Revision 1.2  94/02/12  20:00:20  20:00:20  peteric (Peter Ivimey-Cook)
  141.  * added in comments etc.
  142.  * 
  143.  *    
  144.  *
  145.  *************************************************************************/
  146.  
  147. #include <stdlib.h>
  148. #include <stdarg.h>
  149. #include <string.h>
  150.  
  151. #ifdef amiga
  152. #define DEBUGFILE "ram:debug.ftree"
  153. #else
  154. #define DEBUGFILE "debug.ftree"
  155. #endif
  156.  
  157. /*
  158.  * this forces the global definitions in ftree.h
  159.  * to be declarations.
  160.  */
  161. #define EXTERN
  162.  
  163. #include "ftree.h"
  164.  
  165. /*
  166.  * Amiga style revision code for the ';version' command.
  167.  */
  168. static char amiga_revision[] = "$VER: ftree 0.3 (29.04.94) $";
  169.  
  170. papersize_t papersizes[] =
  171. {
  172.     /* Name        X pts    Y pts    (1 pts = 1/72") */
  173.     { "11x17",    792,    1224  },
  174.     { "a0",        2380,    3368  },
  175.     { "a1",        1684,    2380  },
  176.     { "a2",        1190,    1684  },
  177.     { "a3",        842,    1190  },
  178.     { "a4",        595,    842  },
  179.     { "a4l",    842 ,    595 },
  180.     { "a5",        421,    595  },
  181.     { "a6",        297,    421  },
  182.     { "a7",        210,    297  },
  183.     { "a8",        148,    210  },
  184.     { "a9",        105,    148  },
  185.     { "a10",    74,    105  },
  186.     { "archA",    648,    864  },
  187.     { "archB",    864,    1296  },
  188.     { "archC",    1296,    1728  },
  189.     { "archD",    1728,    2592  },
  190.     { "archE",    2592,    3456  },
  191.     { "b0",        2836,    4008  },
  192.     { "b1",        2004,    2836  },
  193.     { "b2",        1418,    2004  },
  194.     { "b3",        1002,    1418  },
  195.     { "b4",        709,    1002  },
  196.     { "b5",        501,    709  },
  197.     { "flsa",    612,    936  },
  198.     { "flse",    612,    936  },
  199.     { "halfletter",    396,    612  },
  200.     { "ledger",    1224,    792  },
  201.     { "legal",    612,    1008  },
  202.     { "letter",    612,    792  },
  203.     { "note",    540,    720  }
  204. };
  205.  
  206. int numpapersizes = sizeof(papersizes) / sizeof(papersize_t);
  207.  
  208. /*(
  209.  ************************************************************* 
  210.  *
  211.  *    Function:    main
  212.  *
  213.  *
  214.  *    Inputs:
  215.  *        argc - arg count
  216.  *        argv - arg strings
  217.  *
  218.  *    Outputs:
  219.  *        int - return code - 0 if OK, <>0 if error
  220.  *
  221.  *    Error Handling:
  222.  *        
  223.  *
  224.  *    Description:
  225.  *        
  226.  *        Main routine. Sets up initial settings, scans
  227.  * argv array and defaults file for option settings, calls parse
  228.  * routine to read input file & print routine to print out the
  229.  * result.
  230.  *
  231.  ************************************************************* 
  232. )*/
  233. int main(int argc, char **argv)
  234. {
  235.     options_t opts;
  236.     int ch, quick;
  237.     double vspace;
  238.     FILE *f;
  239.     extern char *optarg;
  240.     extern int optind;
  241. #ifdef DEBUG
  242. #ifdef YYDEBUG
  243.     extern int yydebug;
  244. #endif
  245. #ifdef FLEXDEBUG
  246.     extern int yy_flex_debug;
  247.     yy_flex_debug = 0;
  248. #endif
  249. #ifdef YYDEBUG
  250.     yydebug = 0;
  251. #endif
  252.     debug = 0;
  253. #endif
  254.     
  255.     verbose = FALSE;
  256.     quick = FALSE;
  257.     reading_file = FALSE;
  258.     if ((psfontpath = getenv("PSFONTPATH")) == NULL)
  259.         psfontpath = "";
  260.     
  261.     opts.startperson = NULL;
  262.     opts.printoccupation = TRUE;
  263.     opts.printids = FALSE;
  264.     opts.outputfile = "tree.ps";
  265.     opts.rmargin = INCH * 0.3;
  266.     opts.lmargin = INCH * 0.3;
  267.     opts.bmargin = INCH * 0.3;
  268.     opts.tmargin = INCH * 0.3;
  269.     opts.multipage = FALSE;
  270.     opts.titlefont.size = 17.0;        /* drawing title */
  271.     opts.titlefont.linespc = 18;
  272.     opts.titlefont.font = "ZapfChancery";
  273.     opts.titlegreylevel = 0.9;
  274.     opts.personfont.size = 8.0;        /* names */
  275.     opts.personfont.linespc = 9;
  276.     opts.personfont.font = "Times-Roman";
  277.     opts.datefont.size = 6.0;        /* dates */
  278.     opts.datefont.linespc = 7;
  279.     opts.datefont.font = "Times-Roman";
  280.     opts.symfont.size = 8.0;        /* extra-ordinary symbols */
  281.     opts.symfont.linespc = 9;
  282.     opts.symfont.font = "Helvetica";
  283.     opts.identfont.size = 7.0;        /* ID codes */
  284.     opts.identfont.linespc = 7;
  285.     opts.identfont.font = "Times-Italic";
  286.     opts.titlestr = "Family Tree";
  287.     opts.maxlevel = 10;
  288.     opts.vspace = 1.00 * INCH;
  289.     opts.pagewidth = 0;
  290.     opts.pageheight = 0;
  291.     opts.papertype = "a4";
  292.     opts.landscape = FALSE;
  293.     opts.marrlines = 4;
  294.     opts.bblx = opts.bbly = 0;
  295.     opts.bbux = opts.bbuy = 0;
  296.     opts.ticklen = 0.1*INCH;
  297.     opts.tree_gap = (int)(0.1*INCH);
  298.     opts.afmconst = 0.6;
  299.     proot = NULL;
  300.     mroot = NULL;
  301.     glob_opts = &opts;
  302.  
  303.     /*
  304.      * set up the default options.
  305.      */
  306.     f = fopen("ftree.options", "r");
  307.     if (f)
  308.     {
  309.         parse(f, "ftree.options");
  310.         fclose(f);
  311.     }
  312.     
  313.     while((ch = getopt(argc, argv, "MP:F:hldDp:t:o:s:vL:q")) != EOF)
  314.     {
  315.         switch(ch)
  316.         {
  317.             case 'd':
  318. #ifdef DEBUG
  319.                 debug = 1;
  320. #else
  321.                 fprintf(stderr, "Debugging option not available.\n");
  322. #endif
  323.                 break;
  324.  
  325.             case 'D':
  326. #ifdef DEBUG
  327.                 debug = 1;
  328. #if YYDEBUG
  329.                 yy_flex_debug = 1;
  330. #endif
  331. #if YYDEBUG
  332.                 yydebug = 1;
  333. #endif
  334. #else
  335.                 fprintf(stderr, "Debugging option not available.\n");
  336. #endif
  337.                 break;
  338.  
  339.             case 's':
  340.                 opts.startperson = cvid(optarg);
  341.                 break;
  342.  
  343.             case 'q':
  344.                 quick = TRUE;
  345.                 break;
  346.                 
  347.             case 'P':
  348.                 opts.papertype = optarg;
  349.                 break;
  350.                 
  351.             case 'F':
  352.                 opts.personfont.font = optarg;
  353.                 break;
  354.                 
  355.             case 'x':
  356.                 opts.printoccupation = FALSE;
  357.                 break;
  358.             
  359.             case 'M':
  360.                 opts.multipage = TRUE;
  361.                 break;
  362.             
  363.             case 'v':
  364.                 verbose = TRUE;
  365.                 break;
  366.             
  367.             case 'L':
  368.                 opts.maxlevel = atoi(optarg);
  369.                 break;
  370.             
  371.             case 'l':
  372.                 opts.landscape = TRUE;
  373.                 break;
  374.             
  375.             case 'o':
  376.                 opts.outputfile = optarg;
  377.                 break;
  378.                 
  379.             case 'p':
  380.                 sscanf(optarg, "%f", &opts.personfont.size);
  381.                 break;
  382.                 
  383.             case 't':
  384.                 opts.titlestr = optarg;
  385.                 break;
  386.  
  387.             case 'h':
  388.             default:
  389.                 usage();
  390.                 exit(1);
  391.         }
  392.     }
  393.     
  394.     setpapertype(&opts);
  395.  
  396.     dbprintf_note(("main: loading source files\n"));
  397.     
  398.     if (optind == argc)
  399.         parse(stdin, "stdin");
  400.     else
  401.     {
  402.         for (; optind < argc; optind++)
  403.         {
  404.             f = fopen(argv[optind], "r");
  405.             if (f != NULL)
  406.             {
  407.                 parse(f, argv[optind]);
  408.                 fclose(f);
  409.             }
  410.             else
  411.             {
  412.                 perror("opening file");
  413.                 exit(1);
  414.             }
  415.         }
  416.     }
  417.  
  418.     dbprintf_note(("main: setting up line spacing\n"));
  419.  
  420.     /*
  421.      * set up the line spacing given a point size. For small
  422.      * sizes p+1 is good enough. For larger sizes the usual is
  423.      * p * 1.1, which at small sizes is too close when l is
  424.      * an integer.
  425.      *
  426.      * Use p+1 for now; most point sizes will be small (or very
  427.      * small).
  428.      */
  429.     opts.personfont.linespc = (int)(opts.personfont.size + 1);
  430.     opts.titlefont.linespc = (int)(opts.titlefont.size + 1);
  431.     opts.identfont.linespc = (int)(opts.identfont.size + 1);
  432.     opts.datefont.linespc = (int)(opts.datefont.size + 1);
  433.     opts.symfont.linespc = (int)(opts.symfont.size + 1);
  434.  
  435.     /*
  436.      * check vertical space OK. We lie about marrlines (should start at 6)
  437.      * because the [no issue] message never appears with a marriage spike,
  438.      * and not including it makes it look better...
  439.      */
  440.     opts.marrlines = 5;    /* basic - two names, two dates, "no issue", x in middle, */
  441.     vspace = 4;        /* a bit of a gap... */
  442.     vspace += opts.personfont.linespc * 3;
  443.     vspace += opts.datefont.linespc * 2;
  444.     vspace += opts.symfont.linespc;
  445.  
  446.     if (opts.printoccupation)
  447.     {
  448.         opts.marrlines++;
  449.         vspace += opts.personfont.linespc;
  450.     }
  451.     if (opts.printids)
  452.     {
  453.         opts.marrlines += 2;
  454.         vspace += opts.identfont.linespc * 2;
  455.     }
  456.     if (vspace > opts.vspace)
  457.     {
  458.         opts.vspace = vspace;
  459.         warnmsg("vertical space btw. generations insufficient, adjusting to %.2gi.\n",
  460.                     (double)vspace / (double)INCH);
  461.     }
  462.     
  463.     dbprintf_note(("main: loading fonts\n"));
  464.  
  465.     if (!quick)
  466.     {
  467.         /*
  468.          * load the fonts we wish to use.
  469.          */
  470.         loadfont(&opts.personfont);
  471.         loadfont(&opts.titlefont);
  472.         loadfont(&opts.identfont);
  473.         loadfont(&opts.datefont);
  474.         loadfont(&opts.symfont);
  475.     }
  476.     
  477.     dbprintf_note(("main: determining root\n"));
  478.  
  479.     if (opts.startperson == NULL)
  480.     {
  481.         if (mroot != NULL)
  482.         {
  483.             person_t *p;
  484.             if (mroot->husband != NULL)
  485.                 opts.startperson = mroot->husband->id;
  486.             else
  487.                 opts.startperson = mroot->wife->id;
  488.             p = findperson(opts.startperson);
  489.             warnmsg("no start person selected, selecting last defined -- %s %s (%lx)\n",
  490.                     p->firstname, p->family, opts.startperson);
  491.         }
  492.         else
  493.         {
  494.             warnmsg("no marriages found, exiting\n");
  495.             exit(0);
  496.         }
  497.     }
  498.  
  499.     dbprintf_note(("main: determining person/marriage widths\n"));
  500.  
  501.     setpersonwidths(&opts, proot);
  502.     setmarriagewidths(&opts, mroot);
  503.  
  504.     dbprintf_note(("main: printing tree\n"));
  505.  
  506.     if (proot || mroot)
  507.     {
  508.         print(&opts);
  509.     }
  510.     dbprintf_note(("main: finished.\n"));
  511.     return (0);
  512. }
  513.  
  514.  
  515. /*(
  516.  ************************************************************* 
  517.  *
  518.  *    Function:    usage
  519.  *
  520.  *
  521.  *    Inputs:
  522.  *        none.
  523.  *
  524.  *    Outputs:
  525.  *        none (text).
  526.  *
  527.  *    Error Handling:
  528.  *        none.
  529.  *
  530.  *    Description:
  531.  *        
  532.  *        Prints out a message describing the valid options
  533.  * to the program and the version number and date the program
  534.  * was compiled.
  535.  *
  536.  ************************************************************* 
  537. )*/
  538.  
  539. void usage(void)
  540. {
  541.     int i, w;
  542.     printf("ftree version " VERSION " (" __DATE__ ")\n");
  543.     printf("Usage: ftree [-hlMqvx] [-P psize] [-L maxl] [-t ttl] [-s pers] [-o psfile] [-F font] [infile ...]\n");
  544.     printf("Where:\n");
  545.     printf("    -F font    - select font 'font' to write with\n");
  546.     printf("    -L <size>  - set maximum # generations to print\n");
  547.     printf("    -M         - print out multipage plot chart\n");
  548.     printf("    -P psize   - set the paper size to 'psize'\n");
  549.     printf("    -h         - print this help message\n");
  550.     printf("    -l         - print in landscape mode\n");
  551.     printf("    -o psfile  - specify output file name ('-' == stdout)\n");
  552.     printf("    -p <size>  - standard font point size\n");
  553.     printf("    -q         - quick mode; approximate font sizes\n");
  554.     printf("    -s pers    - specify 'root' person of tree\n");
  555.     printf("    -t ttl     - title string of tree\n");
  556.     printf("    -v         - comment more verbosely.\n");
  557.     printf("    -x         - do not print occupations\n");
  558.     printf(" psfile is the name of a PostScript output file.\n");
  559.     printf(" infile is the name of the tree file.\n");
  560.     printf("Allowable paper types are:\n  ");
  561.     w = 2;
  562.     for(i = 0; i < numpapersizes; i++)
  563.     {
  564.         printf("%s,", papersizes[i].str);
  565.         w += strlen(papersizes[i].str) + 2;
  566.         if (w > 72)
  567.         {
  568.             w = 2;
  569.             printf("\n  ");
  570.         }
  571.     }
  572.     printf(" or <w>x<h>\n");
  573.     printf("where <w> and <h> are the width and height in inches\n");
  574.     printf("Example font names are: (case is important)\n");
  575.     printf("  Times-Roman, Helvetica, Courier, Utopia, ZapfChancery\n");
  576. }
  577.  
  578. /*(
  579.  ************************************************************* 
  580.  *
  581.  *    Function:    parse
  582.  *
  583.  *
  584.  *    Inputs:
  585.  *        fp - pointer to the text file to read
  586.  *        filename - the name of the file referenced by fp.
  587.  *
  588.  *    Outputs:
  589.  *        none.
  590.  *
  591.  *    Error Handling:
  592.  *        handles by yyerror - generally a message
  593.  * is written to the standard error file.
  594.  *
  595.  *    Description:
  596.  *        
  597.  *        calls the lex/yacc functions to parse the input
  598.  * file for people, options and marriage definitions. The data
  599.  * is accumulated as parsing proceeds into a pair of linked lists
  600.  * and the options structure.
  601.  *
  602.  *        This routine is not reentrant, but it may be
  603.  * called more than once.
  604.  *
  605.  ************************************************************* 
  606. )*/
  607.  
  608. void parse(FILE *fp, char *filename)
  609. {
  610.     static int first_call = 1;
  611.     extern FILE *yyin;
  612.     
  613.     current_filename = filename;
  614.     yyin = fp;
  615.     lineno = 1;
  616.     
  617.     if (first_call)
  618.         first_call = 0;
  619.     else
  620.         yyrestart(yyin);
  621.     
  622.     reading_file = TRUE;
  623.     yyparse();
  624.     reading_file = FALSE;
  625. }
  626.  
  627. /*(
  628.  ************************************************************* 
  629.  *
  630.  *    Function:    yyerror
  631.  *
  632.  *
  633.  *    Inputs:
  634.  *        str - a string describing the error.
  635.  *
  636.  *    Outputs:
  637.  *        none.
  638.  *
  639.  *    Description:
  640.  *        
  641.  *        Prints out an error message on the standard
  642.  * error stream, containing the file, line number and message
  643.  * passed.
  644.  *
  645.  ************************************************************* 
  646. )*/
  647.  
  648. void yyerror(char *str)
  649. {
  650.     errmsg("%s\n",str);
  651. }
  652.  
  653. /*(
  654.  ************************************************************* 
  655.  *
  656.  *    Function:    makemarriage
  657.  *
  658.  *
  659.  *    Inputs:
  660.  *        prev_marr - pointer to previous marriage struct, or NULL
  661.  *        husb - ID code of husband for this marriage
  662.  *        wife - ID code of wife for this marriage
  663.  *        when - date (if known) of marriage
  664.  *        state - state (div, sep etc) of marriage
  665.  *        hint - left/right ness of children - may be (is) ignored
  666.  *        first_child - pointer to person rec for first (oldest) child
  667.  *        last_child - pointer to person rec for last (youngest) child
  668.  *
  669.  *    Outputs:
  670.  *        marriage_t * - pointer to new marriage record.
  671.  *
  672.  *    Error Handling:
  673.  *        
  674.  *
  675.  *    Description:
  676.  *        
  677.  *        Constructs & checks the marriage record constructed during
  678.  * the parse and if OK adds it to the list of marriages. Also if
  679.  * prev_marr is non-NULL adds this marriage onto the end of the list
  680.  * of marriages.
  681.  *
  682.  ************************************************************* 
  683. )*/
  684.  
  685. marriage_t *makemarriage(marriage_t *prev_marr, id_t husb, id_t wife, date_t when,
  686.         enum mstate_t state, enum mhint_t hint, person_t *first_child,
  687.         person_t *last_child)
  688. {
  689.     person_t *p;
  690.     marriage_t *m;
  691.  
  692.     dbprintf(("ENTER: makemarriage\n"));
  693.     m = malloc(sizeof *m);
  694.     if (!m)
  695.     {
  696.         errmsg("ran out of memory in makemarriage\n");
  697.         return NULL;
  698.     }
  699.     m->h.left = NULL;
  700.     m->h.right = NULL;
  701.     m->h.type = HT_MARRIAGE;
  702.     m->h.level = 0;
  703.     m->h.xpos = 0;
  704.     m->h.ypos = 0;
  705.     m->h.width = 0;
  706.  
  707.     m->nextmarriage = NULL;
  708.     m->next = NULL;
  709.     m->prev = NULL;
  710.     m->husband = findperson(husb);
  711.     m->wife = findperson(wife);
  712.     m->backlink = NULL;
  713.     m->firstchild = first_child;
  714.     m->lastchild = last_child;
  715.     m->when = when;
  716.     m->state = state;
  717.     m->hint = hint;
  718.     m->chartref = NULL;
  719.     m->children = 0;
  720.     m->legal = TRUE;
  721.     m->datewidth = 0;
  722.  
  723.     if (m->husband == NULL)
  724.     {
  725.         warnmsg("no father known for marriage (%lx) (%lx)\n", husb, wife);
  726.     }
  727.     else
  728.     {
  729.         switch (m->husband->sex)
  730.         {
  731.  
  732.             case S_FEMALE:
  733.                 warnmsg("'father' in marriage (%lx) to (%lx) is female!\n", husb, wife);
  734.                 break;
  735.             case S_UNKNOWN:
  736.                 warnmsg("in marriage (%lx) to (%lx) the father is of unknown sex\n", husb, wife);
  737.                 break;
  738.             default:
  739.                 break;
  740.         }
  741.         dbprintf(("makemarriage: set married flag for %s %s\n", m->husband->firstname, m->husband->family));
  742.         m->husband->married = TRUE;
  743.         m->husband->fullname = TRUE;
  744.     }
  745.     if (m->wife == NULL)
  746.     {
  747.         warnmsg("no mother known for marriage (%lx) (%lx)\n", husb, wife);
  748.     }
  749.     else
  750.     {
  751.         switch (m->wife->sex)
  752.         {
  753.             case S_MALE:
  754.                 warnmsg("'mother' in marriage (%lx) to (%lx) is male!\n", husb, wife);
  755.                 break;
  756.             case S_UNKNOWN:
  757.                 warnmsg("in marriage (%lx) to (%lx) the mother is of unknown sex\n", husb, wife);
  758.                 break;
  759.             default:
  760.                 break;
  761.         }
  762.         dbprintf(("makemarriage: set married flag for %s %s\n", m->wife->firstname, m->husband->family));
  763.         m->wife->married = TRUE;
  764.         m->wife->fullname = TRUE;
  765.     }
  766.  
  767.     /*
  768.      * link in previous marriage, if any
  769.      */
  770.     if (prev_marr)
  771.     {
  772.         prev_marr->next = m;
  773.         m->prev = prev_marr;
  774.     }
  775.  
  776.     /*
  777.      * link into global list
  778.      */
  779.     m->nextmarriage = mroot;
  780.     mroot = m;
  781.  
  782.     p = first_child;
  783.     while(p)
  784.     {
  785.         if (p->parents != NULL)
  786.         {
  787.             warnmsg("%s %s already has a mother or father\n", p->firstname, p->family);
  788.             if (p->parents->husband)
  789.                 warnmsg("  father was: '%s %s'\n", p->parents->husband->firstname, p->parents->husband->family);
  790.             if (p->parents->wife)
  791.                 warnmsg("  mother was: '%s %s'\n", p->parents->wife->firstname, p->parents->wife->family);
  792.             warnmsg("now:\n");
  793.             if (m->husband)
  794.                 warnmsg("  father is : '%s %s'\n", m->husband->firstname, m->husband->family);
  795.             if (m->wife)
  796.                 warnmsg("  mother is : '%s %s'\n", m->wife->firstname, m->wife->family);
  797.         }
  798.  
  799.         p->parents = m;
  800.         p = p->nextchild;
  801.     }
  802.     dbprintf(("LEAVE: makemarriage\n"));
  803.     
  804.     return m;
  805. }
  806.  
  807. /*(
  808.  ************************************************************* 
  809.  *
  810.  *    Function:    makeperson
  811.  *
  812.  *
  813.  *    Inputs:
  814.  *        person - pointer to template person data
  815.  *
  816.  *    Outputs:
  817.  *        none.
  818.  *
  819.  *    Error Handling:
  820.  *        none.
  821.  *
  822.  *    Description:
  823.  *        
  824.  *        Copies and validates the data pointed to by
  825.  * person into a new record, which is added to the list of
  826.  * known people.
  827.  *
  828.  ************************************************************* 
  829. )*/
  830.  
  831. void makeperson(person_t *person)
  832. {
  833.     person_t *p;
  834.  
  835.     dbprintf(("ENTER: makeperson\n"));
  836.     p = malloc(sizeof *p);
  837.     if (!p)
  838.     {
  839.         errmsg("ran out of memory in makeperson\n");
  840.         return;
  841.     }
  842.     p->h.left = NULL;
  843.     p->h.right = NULL;
  844.     p->h.type = HT_PERSON;
  845.     p->h.level = 0;
  846.     p->h.width = 0;
  847.     p->h.xpos = p->h.ypos = 0;
  848.  
  849.     p->nextperson = NULL;
  850.     p->parents = NULL;
  851.     p->nextchild = NULL;
  852.     p->lastchild = NULL;
  853.     strcpy(p->firstname, person->firstname);
  854.     strcpy(p->family, person->family);
  855.     strcpy(p->occupation, person->occupation);
  856.     p->living = person->living;
  857.     p->sex = person->sex;
  858.     p->married = FALSE;
  859.     p->firstmarriage = NULL;
  860.     p->lastmarriage = NULL;
  861.     p->fullname = FALSE;
  862.     p->born = person->born;
  863.     p->bapt = person->bapt;
  864.     p->died = person->died;
  865.  
  866.     if (idcmp(person->id, NOID))
  867.     {
  868.         if (p->family[0] != '\0' && p->firstname[0] != '\0')
  869.             p->id = makeid(p);
  870.         else
  871.             errmsg("you must provide both names if no specific ID is given\n");
  872.     }
  873.     else
  874.     {
  875.         p->id = person->id;
  876.     }
  877.     if (findperson(p->id))
  878.     {
  879.         errmsg("ID '%lx' not unique; please specify an ID code for %s %s.\n",
  880.                 p->id,
  881.                 p->firstname[0] ? p->firstname : "(noname)",
  882.                 p->family[0] ? p->family : "(noname)");
  883.         return;
  884.     }
  885.     
  886.     /*
  887.      * link in this person to the people list.
  888.      */
  889.     p->nextperson = proot;
  890.     proot = p;
  891.     dbprintf(("LEAVE: makeperson\n"));
  892.  
  893.     return;
  894. }
  895.  
  896. /*(
  897.  ************************************************************* 
  898.  *
  899.  *    Function:    setpapertype
  900.  *
  901.  *
  902.  *    Inputs:
  903.  *        opts - current options settings, esp:
  904.  *            opts->papertype
  905.  *
  906.  *    Outputs:
  907.  *        none.
  908.  *
  909.  *    Error Handling:
  910.  *        
  911.  *
  912.  *    Description:
  913.  *        
  914.  *        Uses opts->papertype to define the page size,
  915.  * and thus set up the pageheight & pagewidth settings. If
  916.  * landscape mode has been requested, also swaps width & height
  917.  * to the 'orthogonal' view.
  918.  *
  919.  ************************************************************* 
  920. )*/
  921.  
  922. void setpapertype(options_t *opts)
  923. {
  924.     int i;
  925.     
  926.     for (i = 0; i < numpapersizes; i++)
  927.     {
  928.         if (stricmp(opts->papertype, papersizes[i].str) == 0)
  929.         {
  930.             opts->pagewidth = (int)(papersizes[i].xsz);
  931.             opts->pageheight = (int)(papersizes[i].ysz);
  932.             opts->papertype = papersizes[i].str;
  933.             break;
  934.         }
  935.     }
  936.     if (i == numpapersizes)
  937.     {
  938.         float x, y;
  939.         if (sscanf(opts->papertype, "%fx%f", &x, &y) == 2)
  940.         {
  941.             opts->pagewidth = x * INCH;
  942.             opts->pageheight = y * INCH;
  943.         }
  944.         else
  945.         {
  946.             errmsg("paper type/size not understood: '%s'\n", opts->papertype);
  947.             exit(1);
  948.         }
  949.     }
  950.     if (opts->landscape)
  951.     {
  952.         int t;
  953.         t = opts->pagewidth;
  954.         opts->pagewidth = opts->pageheight;
  955.         opts->pageheight = t;
  956.     }
  957. }
  958.  
  959. /*(
  960.  ***********************************************************************
  961.  *
  962.  *    Function:    makeid
  963.  *
  964.  *
  965.  *    Inputs:
  966.  *        p - pointer to a person structure
  967.  *
  968.  *    Outputs:
  969.  *        id_t - id code generated from the data in *p
  970.  *
  971.  *    Error Handling:
  972.  *        family & firstname can be empty.
  973.  *
  974.  *    Description:
  975.  *        
  976.  *        Uses a simple checksum to generate an ID code for the person
  977.  * pointed to by p. Shifts are used to spread out the number. across the
  978.  * 32 bit code.
  979.  *
  980.  ***********************************************************************
  981. )*/
  982.  
  983. id_t makeid(person_t *p)
  984. {
  985.     id_t id;
  986.     char *q;
  987.     
  988.     id = 0;
  989.     q = p->family;
  990.     if (q)
  991.     {
  992.         while(*q)
  993.             id += (long)(*q++);
  994.     }
  995.     dbprintf(("after family id = %lx\n", id));
  996.     id <<= 4;
  997.     q = p->firstname;
  998.     if (q)
  999.     {
  1000.         while(*q)
  1001.             id += (long)(*q++);
  1002.     }
  1003.     dbprintf(("after first id = %lx\n", id));
  1004.     id <<= 4;
  1005.     id += p->born.day;
  1006.     id += p->born.month;
  1007.     id += p->born.year;
  1008.     dbprintf(("after born id = %lx\n", id));
  1009.     id <<= 4;
  1010.     id += p->died.day;
  1011.     id += p->died.month;
  1012.     id += p->died.year;
  1013.     dbprintf(("after died id = %lx\n", id));
  1014.     id <<= 4;
  1015.     id += p->bapt.day;
  1016.     id += p->bapt.month;
  1017.     id += p->bapt.year;
  1018.     dbprintf(("after bapt id = %lx\n", id));
  1019.     
  1020.     id <<= 4;
  1021.     id += p->sex;
  1022.     id += p->living;
  1023.     
  1024.     id |= 0xC0000000L;        /* this segments 'generated' from 'assigned' ID's */
  1025.     
  1026.     dbprintf(("makeid: return id %lx for %s %s\n", id,
  1027.         p->firstname[0] ? p->firstname : "(none)",
  1028.         p->family[0]  ? p->family : "(none)"));
  1029.     return id;
  1030. }
  1031.  
  1032. /*(
  1033.  ***********************************************************************
  1034.  *
  1035.  *    Function:    cvid
  1036.  *
  1037.  *
  1038.  *    Inputs:
  1039.  *        str - an id string [A-Z][0-9]
  1040.  *
  1041.  *    Outputs:
  1042.  *        id_t - id code number
  1043.  *
  1044.  *    Error Handling:
  1045.  *        
  1046.  *
  1047.  *    Description:
  1048.  *        
  1049.  *        Converts an id string into a number, making for easier
  1050.  * comparison etc.
  1051.  *
  1052.  ***********************************************************************
  1053. )*/
  1054.  
  1055. id_t cvid(const char *str)
  1056. {
  1057.     id_t code = 0;
  1058.     
  1059.     code |= (*str++) - 'A' + 10;
  1060.     while(*str)
  1061.     {
  1062.         code <<= 4;
  1063.         code |= (*str++) - '0';
  1064.     }
  1065.     /* dbprintf(("cvid(%s): id = %lx\n", str, code)); */
  1066.     
  1067.     return code;
  1068. }
  1069.  
  1070. /*(
  1071.  ************************************************************* 
  1072.  *
  1073.  *    Function:    _dprintf
  1074.  *
  1075.  *
  1076.  *    Inputs:
  1077.  *        str - printf() style format string
  1078.  *        ... - args as required by str
  1079.  *
  1080.  *    Outputs:
  1081.  *        none.
  1082.  *
  1083.  *    Error Handling:
  1084.  *        none.
  1085.  *
  1086.  *    Description:
  1087.  *        
  1088.  *        if debug mode is active, prints out the
  1089.  * string as fprintf(stderr, str) would. If not active,
  1090.  * does nothing.
  1091.  *
  1092.  ************************************************************* 
  1093. )*/
  1094. #ifdef DEBUG
  1095. #include <stdarg.h>
  1096.  
  1097. static FILE *debugfile = 0;
  1098.  
  1099. void _dprintf(char *str, ...)
  1100. {
  1101.     va_list ap;
  1102.  
  1103.     va_start(ap, str);
  1104.     if (debug)
  1105.     {
  1106.         if (debugfile == 0)
  1107.             debugfile = fopen(DEBUGFILE, "w");
  1108.         
  1109.         vfprintf(debugfile, str, ap);
  1110.         fflush(debugfile);
  1111.     }
  1112.     va_end(ap);
  1113. }
  1114.  
  1115. #endif
  1116.  
  1117. @
  1118.  
  1119.  
  1120. 1.11
  1121. log
  1122. @Added 'datewidth' initialisation.
  1123. @
  1124. text
  1125. @d7 1
  1126. a7 1
  1127.  *    $Date: 1994/04/27 11:37:54 $
  1128. d9 1
  1129. a9 1
  1130.  *    $Revision: 1.10 $
  1131. d14 3
  1132. d85 5
  1133. @
  1134.  
  1135.  
  1136. 1.10
  1137. log
  1138. @New options added (-M - multipage, -q - quick). Sorted out
  1139. a couple of uninitialised variables in the person & marriage
  1140. structures & reorganised into structure order. Added option
  1141. to specify size of page in inches. Deleted 'mparent' and
  1142. 'fparent' links - these can be got from the 'parents' links.
  1143. Set up 'married flag from makemarried & ensure it is set for
  1144. both parents (previously only set for parent who was a child
  1145. of someone on the tree!).
  1146. Changed 'con' name to more standard '-' name when output to stdout
  1147. wanted. Added macro 'dbprintf_note' for messages wanted on-screen
  1148. and in the log file. Changed the log file name to ram:debug.ftree
  1149. for Amiga use.
  1150. Moved some code for setting person & marriage widths into layout.c
  1151. Adjusted the code which determined the vertical space to do it
  1152. properly - i.e. not assume the 'person' font size is close enough for
  1153. all the other fonts.
  1154. Made the program exit if an input file not found.
  1155. Modified some default options settings - reduced margin for paper area
  1156. mainly.
  1157. @
  1158. text
  1159. @d7 1
  1160. a7 1
  1161.  *    $Date: 1994/03/26 11:28:03 $
  1162. d9 1
  1163. a9 1
  1164.  *    $Revision: 1.9 $
  1165. d14 21
  1166. d634 1
  1167. @
  1168.  
  1169.  
  1170. 1.9
  1171. log
  1172. @Minor changes to include loadfont() calls.
  1173. @
  1174. text
  1175. @d7 1
  1176. a7 1
  1177.  *    $Date: 1994/03/10 21:28:26 $
  1178. d9 1
  1179. a9 1
  1180.  *    $Revision: 1.8 $
  1181. d14 3
  1182. d48 6
  1183. d128 2
  1184. a129 1
  1185.     int ch;
  1186. d148 1
  1187. d150 3
  1188. d157 4
  1189. a160 4
  1190.     opts.rmargin = INCH * 0.4;
  1191.     opts.lmargin = INCH * 0.4;
  1192.     opts.bmargin = INCH * 0.4;
  1193.     opts.tmargin = INCH * 0.4;
  1194. d164 1
  1195. a164 1
  1196.     opts.titlefont.font = "Zapf-Chancery";
  1197. d190 1
  1198. a190 1
  1199.     opts.afmconst = 0.45;
  1200. d205 1
  1201. a205 1
  1202.     while((ch = getopt(argc, argv, "MP:F:hldDp:t:o:s:vL:")) != EOF)
  1203. d234 4
  1204. a285 9
  1205.     /*
  1206.      * calculate the number of lines needed to print a marriage.
  1207.      */
  1208.     opts.marrlines = 5;    /* basic - two names, two dates, x in middle */
  1209.     if (opts.printoccupation)
  1210.         opts.marrlines++;
  1211.     if (opts.printids)
  1212.         opts.marrlines += 2;
  1213.     
  1214. d287 2
  1215. d303 1
  1216. d305 2
  1217. d310 2
  1218. d328 3
  1219. a330 2
  1220.      * check vertical space OK. Note this isn't strictly correct, as the
  1221.      * dates are printed a point size smaller...
  1222. d332 12
  1223. a343 1
  1224.     if ((opts.personfont.linespc * opts.marrlines) >= opts.vspace)
  1225. d345 8
  1226. a352 2
  1227.         warnmsg("vertical space btw. generations insufficient, adjusting.\n");
  1228.         opts.vspace = (opts.personfont.linespc * opts.marrlines) + 1;
  1229. d355 13
  1230. a367 8
  1231.     /*
  1232.      * load the fonts we wish to use.
  1233.      */
  1234.     loadfont(&opts.personfont);
  1235.     loadfont(&opts.titlefont);
  1236.     loadfont(&opts.identfont);
  1237.     loadfont(&opts.datefont);
  1238.     loadfont(&opts.symfont);
  1239. d369 2
  1240. d391 6
  1241. a396 8
  1242.     {
  1243.         marriage_t *m = mroot;
  1244.         while(m)
  1245.         {
  1246.             m->width = widthofmarriage(&opts, m);
  1247.             m = m->nextmarriage;
  1248.         }
  1249.     }
  1250. d402 1
  1251. d435 1
  1252. a435 1
  1253.     printf("Usage: ftree [-vlhx] [-P psize] [-L maxl] [-t ttl] [-s pers] [-o psfile] [-F font] [infile ...]\n");
  1254. d439 1
  1255. d443 1
  1256. a443 1
  1257.     printf("    -o psfile  - specify output file name ('con' == stdout)\n");
  1258. d445 1
  1259. d456 1
  1260. a456 1
  1261.         printf("%s%s", papersizes[i].str, i < (numpapersizes-1) ? ", " : "\n");
  1262. d458 1
  1263. a458 1
  1264.         if (w > 76)
  1265. d464 2
  1266. d584 1
  1267. d591 8
  1268. a598 2
  1269.     m->firstchild = NULL;
  1270.     m->lastchild = NULL;
  1271. d600 4
  1272. d605 3
  1273. a607 2
  1274.     m->chartref = NULL;
  1275.     m->level = 0;
  1276. d610 4
  1277. a613 2
  1278.     m->husband = findperson(husb);
  1279.     m->wife = findperson(wife);
  1280. d622 1
  1281. d632 3
  1282. d653 3
  1283. d657 1
  1284. a657 6
  1285.     m->firstchild = first_child;
  1286.     m->lastchild = last_child;
  1287.     m->xpos = 0;
  1288.     m->ypos = 0;
  1289.     m->width = 0;
  1290.     m->when = when;
  1291. a660 2
  1292.     m->next = NULL;
  1293.     m->prev = NULL;
  1294. d676 1
  1295. a676 1
  1296.         if ((p->mparent != NULL) || (p->fparent != NULL))
  1297. d678 5
  1298. a682 5
  1299.             warnmsg("%s %s (%lx) already has a mother or father\n", p->firstname, p->family, p->id);
  1300.             if (p->mparent)
  1301.                 warnmsg("  father was: '%s %s' (%lx)\n", p->mparent->firstname, p->mparent->family, p->mparent->id);
  1302.             if (p->fparent)
  1303.                 warnmsg("  mother was: '%s %s' (%lx)\n", p->fparent->firstname, p->fparent->family, p->fparent->id);
  1304. d685 1
  1305. a685 1
  1306.                 warnmsg("  father is : '%s %s' (%lx)\n", m->husband->firstname, m->husband->family, m->husband->id);
  1307. d687 1
  1308. a687 1
  1309.                 warnmsg("  mother is : '%s %s' (%lx)\n", m->wife->firstname, m->wife->family, m->wife->id);
  1310. a689 2
  1311.         p->mparent = m->husband;
  1312.         p->fparent = m->wife;
  1313. d693 1
  1314. d726 1
  1315. d733 7
  1316. d741 1
  1317. a741 2
  1318.     p->mparent = NULL;
  1319.     p->fparent = NULL;
  1320. d744 4
  1321. a747 3
  1322.     p->parents = NULL;
  1323.     p->left = NULL;
  1324.     p->right = NULL;
  1325. d749 4
  1326. d754 1
  1327. d756 1
  1328. a756 8
  1329.     p->living = person->living;
  1330.     p->fullname = FALSE;
  1331.     p->level = 0;
  1332.     p->width = 0;
  1333.     p->xpos = p->ypos = 0;
  1334.     strcpy(p->occupation, person->occupation);
  1335.     strcpy(p->family, person->family);
  1336.     strcpy(p->firstname, person->firstname);
  1337. d782 3
  1338. d829 2
  1339. a830 2
  1340.         int x, y;
  1341.         if (sscanf(opts->papertype, "%dx%d", &x, &y) == 2)
  1342. d832 2
  1343. a833 3
  1344.             opts->pagewidth = x;
  1345.             opts->pageheight = y;
  1346.             opts->papertype = "special";
  1347. d956 1
  1348. a956 1
  1349.     dbprintf(("cvid(%s): id = %lx\n", str, code));
  1350. d998 1
  1351. a998 1
  1352.             debugfile = fopen("debug.ftree", "w");
  1353. @
  1354.  
  1355.  
  1356. 1.8
  1357. log
  1358. @Multiple pages working!
  1359. @
  1360. text
  1361. @d3 1
  1362. a3 1
  1363.  *     $Name$
  1364. d7 1
  1365. a7 1
  1366.  *    $Date: 1994/03/07 12:44:14 $
  1367. d9 1
  1368. a9 1
  1369.  *    $Revision: 1.7 $
  1370. d14 3
  1371. a268 15
  1372.      * set up the line spacing given a point size. For small
  1373.      * sizes p+1 is good enough. For larger sizes the usual is
  1374.      * p * 1.1, which at small sizes is too close when l is
  1375.      * an integer.
  1376.      *
  1377.      * Use p+1 for now; most point sizes will be small (or very
  1378.      * small).
  1379.      */
  1380.     opts.personfont.linespc = (int)(opts.personfont.size + 1);
  1381.     opts.titlefont.linespc = (int)(opts.titlefont.size + 1);
  1382.     opts.identfont.linespc = (int)(opts.identfont.size + 1);
  1383.     opts.datefont.linespc = (int)(opts.datefont.size + 1);
  1384.     opts.symfont.linespc = (int)(opts.symfont.size + 1);
  1385.     
  1386.     /*
  1387. a276 10
  1388.     /*
  1389.      * check vertical space OK. Note this isn't strictly correct, as the
  1390.      * dates are printed a point size smaller...
  1391.      */
  1392.     if ((opts.personfont.linespc * opts.marrlines) >= opts.vspace)
  1393.     {
  1394.         warnmsg("vertical space btw. generations insufficient, adjusting.\n");
  1395.         opts.vspace = (opts.personfont.linespc * opts.marrlines) + 1;
  1396.     }
  1397.     
  1398. d296 34
  1399. d350 9
  1400. a500 30
  1401. void errmsg(const char *str, ...)
  1402. {
  1403.     va_list ap;
  1404.  
  1405.     va_start(ap, str);
  1406.     if (reading_file)
  1407.         fprintf(stderr, "%s: %d: ", current_filename, lineno);
  1408.     fprintf(stderr, "error: ");
  1409.     vfprintf(stderr, str, ap);
  1410.     va_end(ap);
  1411.     
  1412.     if (++errors > 5)
  1413.     {
  1414.         fprintf(stderr, "ftree: error: too many errors; exiting.\n");
  1415.         exit(1);
  1416.     }
  1417. }
  1418.  
  1419. void warnmsg(const char *str, ...)
  1420. {
  1421.     va_list ap;
  1422.  
  1423.     va_start(ap, str);
  1424.     if (reading_file)
  1425.         fprintf(stderr, "%s: %d: ", current_filename, lineno);
  1426.     fprintf(stderr, "warning: ");
  1427.     vfprintf(stderr, str, ap);
  1428.     va_end(ap);
  1429. }
  1430.  
  1431. d504 1
  1432. a504 1
  1433.  *    Function:    
  1434. d508 8
  1435. a515 1
  1436.  *        
  1437. d518 1
  1438. a518 1
  1439.  *        
  1440. d525 4
  1441. a528 1
  1442.  *        
  1443. a596 1
  1444.     m->height = 0;
  1445. d602 1
  1446. d604 1
  1447. d606 2
  1448. a682 1
  1449.     p->width = 0;
  1450. d689 1
  1451. a723 185
  1452.  *    Function:    findmarriage1
  1453.  *
  1454.  *
  1455.  *    Inputs:
  1456.  *        id - the ID to look for
  1457.  *
  1458.  *    Outputs:
  1459.  *        marriage_t * - pointer to a marriage struct or NULL
  1460.  *
  1461.  *    Error Handling:
  1462.  *        
  1463.  *
  1464.  *    Description:
  1465.  *        
  1466.  *        Finds the marriage in which one person has the
  1467.  * ID code 'id'.
  1468.  *
  1469.  ************************************************************* 
  1470. )*/
  1471.  
  1472. marriage_t *findmarriage1(id_t id)
  1473. {
  1474.     marriage_t *m;
  1475.  
  1476.     if (id == NOID)
  1477.     {
  1478.         dbprintf(( "findmarriage1: no id\n"));
  1479.         return NULL;
  1480.     }
  1481.     m = mroot;
  1482.     while(m)
  1483.     {
  1484.         if (((m->husband != NULL) && idcmp(id, m->husband->id)) ||
  1485.             ((m->wife    != NULL) && idcmp(id, m->wife->id)))
  1486.         {
  1487.             dbprintf(( "findmarriage1: found match %lx\n", id));
  1488.             break;
  1489.         }
  1490.         m = m->nextmarriage;
  1491.     }
  1492.     return m;
  1493. }
  1494.  
  1495. /*(
  1496.  ************************************************************* 
  1497.  *
  1498.  *    Function:    findmarriage2
  1499.  *
  1500.  *
  1501.  *    Inputs:
  1502.  *        id - the ID to look for
  1503.  *
  1504.  *    Outputs:
  1505.  *        marriage_t * - pointer to a marriage struct or NULL
  1506.  *
  1507.  *    Error Handling:
  1508.  *        
  1509.  *
  1510.  *    Description:
  1511.  *        
  1512.  *        Finds the marriage in which one person has the
  1513.  * ID code 'id'.
  1514.  *
  1515.  ************************************************************* 
  1516. )*/
  1517.  
  1518. marriage_t *findmarriage2(id_t hid, id_t wid)
  1519. {
  1520.     marriage_t *m;
  1521.  
  1522.     if (hid == NOID || wid == NOID)
  1523.     {
  1524.         dbprintf(( "findmarriage2: no id\n"));
  1525.         return NULL;
  1526.     }
  1527.     m = mroot;
  1528.     while(m)
  1529.     {
  1530.         if (((m->husband != NULL) && idcmp(hid, m->husband->id)) ||
  1531.             ((m->wife    != NULL) && idcmp(wid, m->wife->id)))
  1532.         {
  1533.             dbprintf(( "findmarriage2: found match h%lx/w%lx\n", hid, wid));
  1534.             break;
  1535.         }
  1536.         m = m->nextmarriage;
  1537.     }
  1538.     return m;
  1539. }
  1540.  
  1541. /*(
  1542.  ************************************************************* 
  1543.  *
  1544.  *    Function:    nextmarriage
  1545.  *
  1546.  *
  1547.  *    Inputs:
  1548.  *        m - pointer to previously found marriage
  1549.  *
  1550.  *    Outputs:
  1551.  *        marriage_t * - pointer to next marriage, or NULL
  1552.  *
  1553.  *    Error Handling:
  1554.  *        Returns NULL if no marriage, or ID is unset.
  1555.  *
  1556.  *    Description:
  1557.  *        
  1558.  *        
  1559.  *
  1560.  ************************************************************* 
  1561. )*/
  1562.  
  1563. marriage_t *nextmarriage(marriage_t *m, id_t id)
  1564. {
  1565.     if (id == NOID)
  1566.     {
  1567.         dbprintf(( "nextmarriage: ERROR no id\n"));
  1568.         return NULL;
  1569.     }
  1570.  
  1571.     /*
  1572.      * starting at the current (assumed) match, find the next one...
  1573.      */
  1574.     m = m->nextmarriage;
  1575.     while(m)
  1576.     {
  1577.         if (((m->husband != NULL) && idcmp(id, m->husband->id)) ||
  1578.             ((m->wife    != NULL) && idcmp(id, m->wife->id)))
  1579.         {
  1580.             dbprintf(( "nextmarriage: found match %lx\n", id));
  1581.             break;
  1582.         }
  1583.         m = m->nextmarriage;
  1584.     }
  1585.     return m;
  1586. }
  1587.  
  1588. /*(
  1589.  ************************************************************* 
  1590.  *
  1591.  *    Function:    findperson
  1592.  *
  1593.  *
  1594.  *    Inputs:
  1595.  *        id - person id code
  1596.  *
  1597.  *    Outputs:
  1598.  *        person_t * - pointer to a person record
  1599.  *
  1600.  *    Error Handling:
  1601.  *        Checks that id is non-null. returns NULL if
  1602.  * person not found.
  1603.  *
  1604.  *    Description:
  1605.  *        
  1606.  *        Returns (a pointer to) the person record for
  1607.  * the person who matches the id code. 
  1608.  *
  1609.  ************************************************************* 
  1610. )*/
  1611.  
  1612. person_t *findperson(id_t id)
  1613. {
  1614.     person_t *p;
  1615.     p = proot;
  1616.  
  1617.     if (id == NULL)
  1618.     {
  1619.         dbprintf(( "findperson: no id\n"));
  1620.         return NULL;
  1621.     }
  1622.     while(p)
  1623.     {
  1624.         if (idcmp(id, p->id))
  1625.         {
  1626.             dbprintf(( "findperson: found match %lx\n", p->id));
  1627.             break;
  1628.         }
  1629.         p = p->nextperson;
  1630.     }
  1631.     return p;
  1632. }
  1633.  
  1634. /*(
  1635.  ************************************************************* 
  1636.  *
  1637. d755 2
  1638. a756 2
  1639.             opts->pagewidth = (int)(papersizes[i].xsz * 0.96);
  1640.             opts->pageheight = (int)(papersizes[i].ysz * 0.96);
  1641. d759 15
  1642. @
  1643.  
  1644.  
  1645. 1.7
  1646. log
  1647. @Passed on as first Version.
  1648. @
  1649. text
  1650. @d7 1
  1651. a7 1
  1652.  *    $Date: 1994/03/01 23:18:45 $
  1653. d9 1
  1654. a9 1
  1655.  *    $Revision: 1.6 $
  1656. d14 3
  1657. d140 5
  1658. a144 4
  1659.     opts.rmargin = INCH * 0.5;
  1660.     opts.lmargin = INCH * 0.5;
  1661.     opts.bmargin = INCH * 0.5;
  1662.     opts.tmargin = INCH * 0.5;
  1663. d172 2
  1664. d188 1
  1665. a188 1
  1666.     while((ch = getopt(argc, argv, "P:F:hldDp:t:o:s:vL:")) != EOF)
  1667. d230 4
  1668. d549 1
  1669. a1094 3
  1670.     if (debugfile == 0)
  1671.         debugfile = fopen("debug.ftree", "w");
  1672.     
  1673. d1098 3
  1674. @
  1675.  
  1676.  
  1677. 1.6
  1678. log
  1679. @added landscape version of a4 paper size.
  1680. @
  1681. text
  1682. @d7 1
  1683. a7 1
  1684.  *    $Date: 94/02/27 19:34:47 $
  1685. d9 1
  1686. a9 1
  1687.  *    $Revision: 1.5 $
  1688. d13 4
  1689. a16 1
  1690.  *    $Log:    main.c,v $
  1691. d522 1
  1692. a522 1
  1693. void makemarriage(marriage_t *prev_marr, id_t husb, id_t wife, date_t when,
  1694. d533 1
  1695. a533 1
  1696.         return;
  1697. d622 2
  1698. @
  1699.  
  1700.  
  1701. 1.5
  1702. log
  1703. @added initialisations for extended structures, added new font handling code
  1704. and new font types, improved error message system
  1705. @
  1706. text
  1707. @d7 1
  1708. a7 1
  1709.  *    $Date: 1994/02/13 16:44:05 $
  1710. d9 1
  1711. a9 1
  1712.  *    $Revision: 1.4 $
  1713. d13 5
  1714. a17 1
  1715.  *    $Log: main.c,v $
  1716. d53 1
  1717. @
  1718.  
  1719.  
  1720. 1.4
  1721. log
  1722. @Various changes; include new nextmarriage() to support multiple
  1723. marriages & corrected some of the setup code; now -sX works!
  1724. @
  1725. text
  1726. @d7 1
  1727. a7 1
  1728.  *    $Date: 1994/02/12 20:32:53 $
  1729. d9 1
  1730. a9 1
  1731.  *    $Revision: 1.3 $
  1732. d14 4
  1733. a27 1
  1734. #include <stdio.h>
  1735. d29 2
  1736. d32 4
  1737. d42 1
  1738. d80 1
  1739. a80 1
  1740.  *    Function:    
  1741. d84 2
  1742. a85 1
  1743.  *        
  1744. d88 1
  1745. a88 1
  1746.  *        
  1747. d95 4
  1748. a98 1
  1749.  *        
  1750. d124 1
  1751. d133 16
  1752. a148 10
  1753.     opts.title.size = 17.0;
  1754.     opts.title.linespc = 18;
  1755.     opts.title.font = "Zapf-Chancery";
  1756.     opts.titlegreylevel = 0.80;
  1757.     opts.person.size = 9.0;
  1758.     opts.person.linespc = 10;
  1759.     opts.person.font = "Times-Roman";
  1760.     opts.ident.size = 8.0;
  1761.     opts.ident.linespc = 9;
  1762.     opts.ident.font = "Times-Italic";
  1763. d201 1
  1764. a201 1
  1765.                 opts.startperson = optarg;
  1766. d209 1
  1767. a209 1
  1768.                 opts.person.font = optarg;
  1769. d233 1
  1770. a233 1
  1771.                 opts.person.size = atof(optarg);
  1772. d247 14
  1773. a260 3
  1774.     opts.person.linespc = (int)(opts.person.size + 1);
  1775.     opts.title.linespc = (int)(opts.title.size + 1);
  1776.     opts.ident.linespc = (int)(opts.ident.size + 1);
  1777. d265 1
  1778. a265 1
  1779.     opts.marrlines = 5;        /* basic - two names, two dates, x in middle */
  1780. d275 1
  1781. a275 1
  1782.     if (opts.person.linespc * opts.marrlines >= opts.vspace)
  1783. d277 2
  1784. a278 2
  1785.         fprintf(stderr, "warning: vertical space btw. generations insufficient, adjusting.\n");
  1786.         opts.vspace = (opts.person.linespc * opts.marrlines) + 1;
  1787. d310 1
  1788. a310 1
  1789.             fprintf(stderr, "warning: no start person selected, selecting last defined -- %s %s (%s)\n",
  1790. d315 1
  1791. a315 1
  1792.             fprintf(stderr, "warning: no marriages found, exiting\n");
  1793. a319 1
  1794.  
  1795. d351 1
  1796. d384 1
  1797. a384 1
  1798.     printf("  Times-Roman, Helvetica, Courier, Utopia\n");
  1799. d431 1
  1800. d433 1
  1801. d459 2
  1802. a460 2
  1803.     extern int lineno;
  1804.     extern char *current_filename;
  1805. d462 16
  1806. a477 1
  1807.     fprintf(stderr, "%s: %d: %s\n", current_filename, lineno, str);
  1808. d480 12
  1809. d514 3
  1810. a516 2
  1811. void makemarriage(char *husb, char *wife, date_t when, enum mstate_t state,
  1812.         person_t *first_child, person_t *last_child)
  1813. d524 1
  1814. a524 1
  1815.         yyerror("ran out of memory in makemarriage");
  1816. d529 3
  1817. a531 1
  1818.     m->next = NULL;
  1819. d533 1
  1820. d538 1
  1821. a538 2
  1822.         if (verbose)
  1823.             fprintf(stderr, "warning: no father known for marriage (%s) (%s)\n", husb, wife);
  1824. d545 1
  1825. a545 1
  1826.                 fprintf(stderr, "warning: 'father' in marriage (%s) to (%s) is female!\n", husb, wife);
  1827. d548 1
  1828. a548 1
  1829.                 fprintf(stderr, "warning: in marriage (%s) to (%s) the father is of unknown sex\n", husb, wife);
  1830. d556 1
  1831. a556 2
  1832.         if (verbose)
  1833.             fprintf(stderr, "warning: no mother known for marriage (%s) (%s)\n", husb, wife);
  1834. d563 1
  1835. a563 1
  1836.                 fprintf(stderr, "warning: 'mother' in marriage (%s) to (%s) is male!\n", husb, wife);
  1837. d566 1
  1838. a566 1
  1839.                 fprintf(stderr, "warning: in marriage (%s) to (%s) the mother is of unknown sex\n", husb, wife);
  1840. d579 11
  1841. a589 1
  1842.     m->next = mroot;
  1843. d597 1
  1844. a597 1
  1845.             fprintf(stderr, "ftree: warning: %s %s (%s) already has a mother or father\n", p->firstname, p->family, p->id);
  1846. d599 1
  1847. a599 1
  1848.                 fprintf(stderr, "  father was: '%s %s' (%s)\n", p->mparent->firstname, p->mparent->family, p->mparent->id);
  1849. d601 2
  1850. a602 2
  1851.                 fprintf(stderr, "  mother was: '%s %s' (%s)\n", p->fparent->firstname, p->fparent->family, p->fparent->id);
  1852.             fprintf(stderr, "now:\n");
  1853. d604 1
  1854. a604 1
  1855.                 fprintf(stderr, "  father is : '%s %s' (%s)\n", m->husband->firstname, m->husband->family, m->husband->id);
  1856. d606 1
  1857. a606 1
  1858.                 fprintf(stderr, "  mother is : '%s %s' (%s)\n", m->wife->firstname, m->wife->family, m->wife->id);
  1859. d611 1
  1860. d619 1
  1861. a619 1
  1862.  *    Function:    
  1863. d623 1
  1864. a623 1
  1865.  *        
  1866. d626 1
  1867. a626 1
  1868.  *        
  1869. d629 1
  1870. a629 1
  1871.  *        
  1872. d633 3
  1873. a635 1
  1874.  *        
  1875. d639 1
  1876. d647 1
  1877. a647 1
  1878.         yyerror("ran out of memory in makeperson");
  1879. d654 4
  1880. d664 1
  1881. d669 1
  1882. a669 1
  1883.     if (strcmp(person->id, "(blank)") == 0)
  1884. d672 1
  1885. a672 9
  1886.         {
  1887.             sprintf(p->id, "%s %s", p->firstname, p->family);
  1888.             if (findperson(p->id))
  1889.             {
  1890.                 fprintf(stderr,"%s: %d: generated ID '%s' not unique; please specify an ID code.\n",
  1891.                     current_filename, lineno, p->id);
  1892.                 return;
  1893.             }
  1894.         }
  1895. d674 1
  1896. a674 1
  1897.             yyerror("you must provide both names if no specific ID is given");
  1898. d678 1
  1899. a678 1
  1900.         strcpy(p->id, person->id);
  1901. d680 9
  1902. d699 1
  1903. a699 1
  1904.  *    Function:    
  1905. d703 1
  1906. a703 1
  1907.  *        
  1908. d706 1
  1909. a706 1
  1910.  *        
  1911. d713 2
  1912. a714 1
  1913.  *        
  1914. d719 1
  1915. a719 1
  1916. marriage_t *findmarriage(char*id)
  1917. d723 1
  1918. a723 1
  1919.     if (id == NULL)
  1920. d725 1
  1921. a725 1
  1922.         dbprintf(( "findmarriage: no id\n"));
  1923. d731 2
  1924. a732 2
  1925.         if (((m->husband != NULL) && (strcmp(id, m->husband->id) == 0)) ||
  1926.             ((m->wife    != NULL) && (strcmp(id, m->wife->id)    == 0)))
  1927. d734 1
  1928. a734 1
  1929.             dbprintf(( "findmarriage: found match %s\n", id));
  1930. d737 1
  1931. a737 1
  1932.         m = m->next;
  1933. d745 1
  1934. a745 1
  1935.  *    Function:    
  1936. d749 1
  1937. a749 1
  1938.  *        
  1939. d752 1
  1940. a752 1
  1941.  *        
  1942. d759 45
  1943. d805 1
  1944. d809 2
  1945. a810 1
  1946. marriage_t *nextmarriage(marriage_t *m, char *id)
  1947. d812 1
  1948. a812 1
  1949.     if (id == NULL || m == NULL)
  1950. d821 1
  1951. a821 1
  1952.     m = m->next;
  1953. d824 2
  1954. a825 2
  1955.         if (((m->husband != NULL) && (strcmp(id, m->husband->id) == 0)) ||
  1956.             ((m->wife    != NULL) && (strcmp(id, m->wife->id)    == 0)))
  1957. d827 1
  1958. a827 1
  1959.             dbprintf(( "nextmarriage: found match %s\n", id));
  1960. d830 1
  1961. a830 1
  1962.         m = m->next;
  1963. d838 1
  1964. a838 1
  1965.  *    Function:    
  1966. d842 1
  1967. a842 1
  1968.  *        
  1969. d845 1
  1970. a845 1
  1971.  *        
  1972. d848 2
  1973. a849 1
  1974.  *        
  1975. d853 2
  1976. a854 1
  1977.  *        
  1978. d858 2
  1979. a859 1
  1980. person_t *findperson(char*id)
  1981. d871 1
  1982. a871 1
  1983.         if (strcmp(id, p->id) == 0)
  1984. d873 1
  1985. a873 1
  1986.             dbprintf(( "findperson: found match %s\n", p->id));
  1987. d884 1
  1988. a884 1
  1989.  *    Function:    
  1990. d888 2
  1991. a889 1
  1992.  *        
  1993. d892 1
  1994. a892 1
  1995.  *        
  1996. d899 4
  1997. a902 1
  1998.  *        
  1999. d906 1
  2000. d931 1
  2001. a931 1
  2002.  ************************************************************* 
  2003. d933 1
  2004. a933 1
  2005.  *    Function:    
  2006. d937 1
  2007. a937 1
  2008.  *        
  2009. d940 6
  2010. d947 3
  2011. d951 64
  2012. d1020 38
  2013. d1059 3
  2014. d1068 2
  2015. d1074 3
  2016. d1080 2
  2017. a1081 1
  2018.         vfprintf(stderr, str, ap);
  2019. d1087 1
  2020. @
  2021.  
  2022.  
  2023. 1.3
  2024. log
  2025. @added function comments.
  2026. @
  2027. text
  2028. @d7 1
  2029. a7 1
  2030.  *    $Date: 94/02/12 20:00:20 $
  2031. d9 1
  2032. a9 1
  2033.  *    $Revision: 1.2 $
  2034. d13 4
  2035. a16 1
  2036.  *    $Log:    main.c,v $
  2037. d33 30
  2038. a62 30
  2039.     { "11x17", 792, 1224  },
  2040.     { "a0", 2380, 3368  },
  2041.     { "a1", 1684, 2380  },
  2042.     { "a2", 1190, 1684  },
  2043.     { "a3", 842, 1190  },
  2044.     { "a4", 595, 842  },
  2045.     { "a5", 421, 595  },
  2046.     { "a6", 297, 421  },
  2047.     { "a7", 210, 297  },
  2048.     { "a8", 148, 210  },
  2049.     { "a9", 105, 148  },
  2050.     { "a10", 74, 105  },
  2051.     { "archA", 648, 864  },
  2052.     { "archB", 864, 1296  },
  2053.     { "archC", 1296, 1728  },
  2054.     { "archD", 1728, 2592  },
  2055.     { "archE", 2592, 3456  },
  2056.     { "b0", 2836, 4008  },
  2057.     { "b1", 2004, 2836  },
  2058.     { "b2", 1418, 2004  },
  2059.     { "b3", 1002, 1418  },
  2060.     { "b4", 709, 1002  },
  2061.     { "b5", 501, 709  },
  2062.     { "flsa", 612, 936  },
  2063.     { "flse", 612, 936  },
  2064.     { "halfletter", 396, 612  },
  2065.     { "ledger", 1224, 792  },
  2066.     { "legal", 612, 1008  },
  2067.     { "letter", 612, 792  },
  2068.     { "note", 540, 720  }
  2069. d95 2
  2070. a96 1
  2071. #if YYDEBUG
  2072. d99 7
  2073. d107 1
  2074. d121 1
  2075. d135 1
  2076. d153 1
  2077. a153 1
  2078.     while((ch = getopt(argc, argv, "P:F:hldp:t:o:s:vL:")) != EOF)
  2079. d160 11
  2080. d227 22
  2081. d268 1
  2082. a268 1
  2083.     if (opts.startperson == NULL && mroot != NULL)
  2084. d270 11
  2085. a280 3
  2086.         person_t *p;
  2087.         if (mroot->husband != NULL)
  2088.             opts.startperson = mroot->husband->id;
  2089. d282 4
  2090. a285 9
  2091.             opts.startperson = mroot->wife->id;
  2092.         p = findperson(opts.startperson);
  2093.         fprintf(stderr, "warning: no start person selected, selecting last defined -- %s %s (%s)\n",
  2094.                 p->firstname, p->family, opts.startperson);
  2095.     }
  2096.     else
  2097.     {
  2098.         fprintf(stderr, "warning: no start person selected and no marriages, exiting\n");
  2099.         exit(0);
  2100. d300 1
  2101. a300 1
  2102.  *    Function:    
  2103. d304 1
  2104. a304 1
  2105.  *        
  2106. d307 1
  2107. a307 1
  2108.  *        
  2109. d310 1
  2110. a310 1
  2111.  *        
  2112. d314 3
  2113. a316 1
  2114.  *        
  2115. d323 2
  2116. a324 2
  2117.     printf("ftree version 1.0 (" __DATE__ ")\n");
  2118.     printf("Usage: ftree [-hx] [-t ttl] [-s pers] [-o psfile] [-F font] [infile ...]\n");
  2119. a325 1
  2120.     printf("    -h         - print this help message\n");
  2121. d327 1
  2122. d329 2
  2123. a330 3
  2124.     printf("    -H hspace  - set horizontal space to 'hspc'\n");
  2125.     printf("    -V vspace  - set vertical space to 'vspc'\n");
  2126.     printf("    -s pers    - specify 'root' person of tree\n");
  2127. a331 2
  2128.     printf("    -x         - do not print occupations\n");
  2129.     printf("    -l         - print in landscape mode\n");
  2130. d333 1
  2131. d335 2
  2132. d358 1
  2133. a358 1
  2134.  *    Function:    
  2135. d362 2
  2136. a363 1
  2137.  *        
  2138. d366 1
  2139. a366 1
  2140.  *        
  2141. d369 2
  2142. a370 1
  2143.  *        
  2144. d374 7
  2145. a380 1
  2146.  *        
  2147. d405 1
  2148. a405 1
  2149.  *    Function:    
  2150. d409 1
  2151. a409 1
  2152.  *        
  2153. d412 1
  2154. a412 4
  2155.  *        
  2156.  *
  2157.  *    Error Handling:
  2158.  *        
  2159. d416 3
  2160. a418 1
  2161.  *        
  2162. d584 1
  2163. a608 1
  2164.     strcpy(p->occupation, person->occupation);
  2165. @
  2166.  
  2167.  
  2168. 1.2
  2169. log
  2170. @added in comments etc.
  2171. @
  2172. text
  2173. @d5 1
  2174. a5 1
  2175.  *    $Author$
  2176. d7 1
  2177. a7 1
  2178.  *    $Date$
  2179. d9 1
  2180. a9 1
  2181.  *    $Revision$
  2182. d13 4
  2183. a16 1
  2184.  *    $Log$
  2185. d64 21
  2186. d247 21
  2187. d303 21
  2188. a335 1
  2189. #if 0
  2190. a337 1
  2191. #endif
  2192. d342 21
  2193. d372 22
  2194. d483 21
  2195. d554 21
  2196. d599 67
  2197. d688 21
  2198. d732 21
  2199. @
  2200.  
  2201.  
  2202. 1.1
  2203. log
  2204. @Initial revision
  2205. @
  2206. text
  2207. @d1 16
  2208. a16 3
  2209. /*
  2210.  * main.c
  2211.  */
  2212. @
  2213.