home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 24 / CD_ASCQ_24_0995.iso / vrac / ged2ht23.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1995-07-14  |  12KB  |  387 lines

  1. /*
  2.  * Copyright (c) 1995 Eugene W. Stark
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by Eugene W. Stark.
  16.  * 4. The name of the author may not be used to endorse or promote products
  17.  *    derived from this software without specific prior written permission.
  18.  * 5. No copying or redistribution in any form for commercial purposes is
  19.  *    permitted without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  25.  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  26.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  27.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include "node.h"
  38. #include "read.h"
  39. #include "database.h"
  40. #include "output.h"
  41. #include "tags.h"
  42.  
  43. #define VERSION "GEDCOM to HTML translator, version 2.3a (July 14 1995)\n" \
  44.                 "by Gene Stark (stark@cs.sunysb.edu).\n"
  45. #define COPYRIGHT "Copyright (c) 1995 Eugene W. Stark.  All rights reserved.\n" \
  46.                 "See file COPYRIGHT for copying information.\n"
  47. #define USAGE "Usage: %s [-Hcgiv][-d <files-per-directory>][-n <indivs-per-file>][-s <individual> ...][-f <file-template>][-S <surname-template>][-t <individual-template>][-T <index-template>][-w <index-width>] [[--] <gedcom-file> ...]\n", argv[0]
  48. #define OPTIONS " -H\t\t\tPrint a brief message listing the available options.\n" \
  49. " -v\t\t\tPrint version number of program and copyright info.\n" \
  50. " -c\t\t\tDisable automatic capitalization of surnames.\n" \
  51. " -d files_per_directory\tSpecify number of files per subdirectory\n" \
  52. "\t\t\t(0 means don't use subdirectories).\n" \
  53. " -f file_template\tSpecify a template string for the names of the\n" \
  54. "\t\t\tHTML files (default '%%s.html' or '%%s.htm').\n" \
  55. " -g\t\t\tForce production of the textual index file (for use by\n" \
  56. "\t\t\tautomatic indexers).\n" \
  57. " -i\t\t\tDo not generate index files containing entries\n" \
  58. "\t\t\tfor all the individuals and surnames in the input.\n" \
  59. " -n indivs_per_file\tOutput files contain specified number of individuals\n" \
  60. "\t\t\t(0 means don't put multiple individuals per file).\n" \
  61. " -p depth\t\tInclude pedigree charts of the specified depth.\n" \
  62. "\t\t\t(0 means don't include any pedigree charts).\n" \
  63. " -s individuals ...\tLimit the production of output files to a specified\n" \
  64. "\t\t\tlist of zero or more selected individuals.\n" \
  65. " -S surname_template\tSpecify a template file for surname index.\n" \
  66. " -t individual_template\tSpecify a template file for individuals.\n" \
  67. " -T index_template\tSpecify a template file for individual index.\n" \
  68. " -w index_width\t\tCreate hierarchical index of specified width\n" \
  69. "\t\t\t(0 means put all individuals in one index file)\n"
  70.  
  71. int generate_index = 1;
  72. int generate_gendex;
  73. char print_template;
  74. char **selected_individuals;
  75. struct node head;
  76.  
  77. void must_be_number(char c, char *a);
  78.  
  79. main(int argc, char *argv[])
  80. {
  81.   struct node *np;
  82.   int i, optc;
  83.   extern char *optarg;
  84.   extern int optind;
  85.   FILE *gedcom_file;
  86.   int serial = 0;
  87. #ifdef MSDOS
  88.   int getopt(int argc, char *const *argv, const char *optstring);
  89.   extern char *optarg;
  90.   extern int optind;
  91. #endif
  92.  
  93.   validate_tags_tables();
  94. #ifdef MSDOS
  95.   printf("%s\n", VERSION);
  96.   printf("%s\n", COPYRIGHT);
  97.   if(argc <= 1) {
  98. #ifdef MSWINDOWS
  99.     fprintf(stderr, "Launch this program from the File Manager, using the\n");
  100.     fprintf(stderr, "'Run' item under the 'File' menu to specify command-line\n");
  101.     fprintf(stderr, "arguments.\n");
  102. #endif
  103.     fprintf(stderr, USAGE);
  104.     exit(1);
  105.   }
  106. #endif
  107.   while((optc = getopt(argc, argv, "Hvgiscd:f:S:t:T:n:p:w:")) != -1) {
  108.     FILE *tempf;
  109.     long size;
  110.     char *temps, *tempe, c;
  111.  
  112.     switch(optc) {
  113.     case 'v':    /* Version */
  114.       printf("%s\n", VERSION);
  115.       printf("%s", COPYRIGHT);
  116.       exit(0);
  117.     case 'c':   /* Disable automatic capitalization of surnames */
  118.       capitalization = 0;
  119.       break;
  120.     case 'g':   /* Generate limited-information GEDCOM file */
  121.       generate_gendex = 1;
  122.       break;
  123.     case 'i':    /* Do not generate index */
  124.       generate_index = 0;
  125.       break;
  126.     case 's':    /* Generate record(s) for selected individual(s) */
  127.       {
  128.     int i = 0;
  129.     int j;
  130.     while(argv[optind+i] && argv[optind+i][0] != '-')
  131.       i++;
  132.     if(!(selected_individuals = malloc((i+1) * sizeof(char *))))
  133.       out_of_memory();
  134.     for (j = 0; j < i; j++)
  135.       selected_individuals[j] = argv[optind+j];
  136.     selected_individuals[j]=NULL;
  137.     optind += i;
  138.       }
  139.       break;
  140.     case 't':    /* Template file for individuals */
  141.     case 'T':    /* Template file for the individual index */
  142.     case 'S':   /* Template file for the surname index */
  143.       /*
  144.        * If filename starts with '-', print the internal template
  145.        * on the standard output.  I got tired of trying to keep the
  146.        * sample templates in sync with the internal ones.
  147.        */
  148.       if(*optarg == '-') {
  149.       print_template = optc;
  150.       break;
  151.       }
  152.       if((tempf = fopen(optarg, "r")) == NULL) {
  153.     fprintf(stderr, "Can't open template file '%s'\n", optarg);
  154.     break;
  155.       }
  156.       if(fseek(tempf, 0L, SEEK_END) == -1 || (size = ftell(tempf)) == -1){
  157.     fprintf(stderr, "Can't determine length of template file '%s'\n",
  158.         optarg);
  159.     fclose(tempf);
  160.     break;
  161.       }
  162.       rewind(tempf);
  163.       if((temps = malloc((size_t) size+1)) == NULL) {
  164.     fprintf(stderr, "Can't allocate memory for template string\n");
  165.     fclose(tempf);
  166.     break;
  167.       }
  168.       tempe = temps;
  169.       while((c = fgetc(tempf)) != EOF && tempe-temps <= size)
  170.     *tempe++ = c;
  171.       *tempe = '\0';
  172.       if(optc == 't')
  173.     individual_template = temps;
  174.       else if(optc == 'T')
  175.     index_template = temps;
  176.       else if(optc == 'S')
  177.     surname_template = temps;
  178.       break;
  179.     case 'd':    /* Specify files per directory */
  180.       must_be_number('d', optarg);
  181.       if((files_per_directory = atoi(optarg)) < 0) {
  182.       fprintf(stderr,
  183.           "Number of individuals per directory must be nonnegative\n");
  184.       exit(1);
  185.       }
  186.       break;
  187.     case 'n':   /* Specify number of individuals per output file */
  188.       must_be_number('n', optarg);
  189.       if((indivs_per_file = atoi(optarg)) < 0) {
  190.       fprintf(stderr,
  191.           "Number of individuals per file must be nonnegative\n");
  192.       exit(1);
  193.       }
  194.       break;
  195.     case 'p':    /* Create pedigree files */
  196.       must_be_number('p', optarg);
  197.       if((pedigree_depth = atoi(optarg)) < 0 || pedigree_depth > 15) {
  198.       fprintf(stderr, "Pedigree chart depth must be between 0 and 15\n");
  199.       exit(1);
  200.       }
  201.       break;
  202.     case 'w':   /* Specify width of hierarchical index */
  203.       must_be_number('w', optarg);
  204.       if((index_width = atoi(optarg)) < 0 || index_width == 1) {
  205.       fprintf(stderr, "Index width must be either 0 or greater than 1\n");
  206.       exit(1);
  207.       }
  208.       break;
  209.     case 'f':    /* Template for file names */
  210.       file_template = optarg;
  211.       break;
  212.     case 'H':
  213.       printf(USAGE);
  214.       printf(OPTIONS);
  215.       exit(0);
  216.     case '?':
  217.     default:
  218.       fprintf(stderr, USAGE);
  219.       exit(1);
  220.     }
  221.   }
  222.   if(indivs_per_file)
  223.       indivs_per_directory = files_per_directory * indivs_per_file;
  224.   else
  225.       indivs_per_directory = files_per_directory;
  226.   if(individual_template == NULL) {
  227.     int size = 1;
  228.     if(indivs_per_directory)
  229.       individual_template_base[INDEX_ANCHOR_POS] = INDEX_ANCHOR_SUBDIR;
  230.     for(i = 0; i < individual_template_base_size; i++)
  231.       size += strlen(individual_template_base[i]);
  232.     if((individual_template = malloc(size)) == NULL)
  233.       out_of_memory();
  234.     *individual_template = '\0';
  235.     for(i = 0; i < individual_template_base_size; i++)
  236.       strcat(individual_template, individual_template_base[i]);
  237.   }
  238.   if(print_template != '\0') {
  239.       switch(print_template) {
  240.       case 't':
  241.       printf(individual_template);
  242.       break;
  243.       case 'T':
  244.       printf(index_template);
  245.       break;
  246.       case 'S':
  247.       printf(surname_template);
  248.       break;
  249.       default:
  250.       break;
  251.       }
  252.       exit(0);
  253.   }
  254.   if(optind == argc) {
  255.     current_gedcom = "stdin";
  256.     current_lineno = 0;
  257.     read_gedcom(stdin, &head, 0);
  258.   } else {
  259.     for(np = &head ; optind < argc; optind++) {
  260.       current_gedcom = argv[optind];
  261.       current_lineno = 0;
  262.       if((gedcom_file = fopen(argv[optind], "r")) == NULL) {
  263.     fprintf(stderr, "Can't open GEDCOM file '%s'.\n", argv[optind]);
  264.     continue;
  265.       }
  266.       read_gedcom(gedcom_file, np, 0);
  267.       fclose(gedcom_file);
  268.       while(np->siblings)
  269.     np = np->siblings;
  270.     }
  271.   }
  272.   if(head.siblings == NULL) {
  273.     fprintf(stderr, "No valid GEDCOM lines found\n");
  274.     exit(1);
  275.   }
  276.   process_records(head.siblings);
  277.   link_records(head.siblings);
  278.   fprintf(stderr, "Processed %ld GEDCOM lines", gedcom_lines);
  279.   if(total_individuals)
  280.     fprintf(stderr, ", %d individuals", total_individuals);
  281.   if(total_families)
  282.     fprintf(stderr, ", %d families", total_families);
  283.   if(total_events)
  284.     fprintf(stderr, ", %d events", total_events);
  285.   if(total_sources)
  286.     fprintf(stderr, ", %d sources", total_sources);
  287.   if(total_notes)
  288.     fprintf(stderr, ", %d notes", total_notes);
  289.   fprintf(stderr, "\n");
  290.   /*
  291.    * Determine individuals to be output, and assign them serial numbers.
  292.    */
  293.   for(i = 0; i < total_individuals; i++) {
  294.     char **av;
  295.  
  296.     if(selected_individuals != NULL) {
  297.       for(av = selected_individuals; *av != NULL; av++)
  298.     if(!strcmp(*av, all_individuals[i]->xref)) {
  299.       all_individuals[i]->serial = ++serial;
  300.     }
  301.     } else {
  302.       all_individuals[i]->serial = ++serial;
  303.     }
  304.   }
  305.   /*
  306.    * Generate index files
  307.    */
  308.   if(index_width == 0)
  309.       index_depth = 1;
  310.   else {
  311.       for(index_depth = 1, i = total_individuals;
  312.       i > index_width;
  313.       index_depth++, i /= index_width);
  314.   }
  315.   if(generate_index) {
  316.       index_individuals();
  317.       index_surnames(index_root);
  318.       output_index(index_root);
  319.       output_surnames(surname_head);
  320.   }
  321.   if(generate_index || generate_gendex)
  322.       output_gendex(all_individuals[0]);
  323.   /*
  324.    * Output individuals
  325.    */
  326.   for(i = 0; i < total_individuals; i++) {
  327.       if(all_individuals[i]->serial)
  328.       output_individual(all_individuals[i]);
  329.   }
  330.   exit(0);
  331. }
  332.  
  333. /*
  334.  * This is probably easier than writing a decent getopt for MSDOS...
  335.  */
  336.  
  337. void must_be_number(char c, char *a)
  338. {
  339.     while(*a != '\0') {
  340.     if(*a < '0' || *a > '9') {
  341.         fprintf(stderr, "Option '-%c' requires a numeric argument "
  342.             "('%s' supplied)\n", c, a);
  343.         exit(1);
  344.     }
  345.     a++;
  346.     }
  347. }
  348.  
  349. #ifdef MSDOS
  350. char *optarg;
  351. int optind = 1;
  352.  
  353. int getopt(int argc, char *const *argv, const char *optstring)
  354. {
  355.   char c;
  356.   if(optind >= argc || *argv[optind] != '-')
  357.     return(-1);
  358.   if(argv[optind][1] == '-') {
  359.     optind++;
  360.     return(-1);
  361.   }
  362.   for( ; *optstring != '\0'; optstring++) {
  363.     c = *optstring;
  364.     if(c == argv[optind][1]) {
  365.       optstring++;
  366.       optind++;
  367.       if(*optstring == ':') {
  368.     if(optind >= argc) {
  369.       fprintf(stderr, "Option '%c' requires an argument.\n", c);
  370.       return(':');
  371.     } else {
  372.       optarg = argv[optind];
  373.       optind++;
  374.       return(c);
  375.     }
  376.       } else {
  377.     return(c);
  378.       }
  379.     }
  380.   }
  381.   fprintf(stderr, "Unrecognized option: '%c'.\n", argv[optind][1]);
  382.   optind++;
  383.   return('?');
  384. }
  385. #endif
  386.  
  387.