home *** CD-ROM | disk | FTP | other *** search
/ The Best Internet Programs / BESTINTERNET.bin / latest / ged2ht20 / output.c < prev    next >
C/C++ Source or Header  |  1995-04-08  |  26KB  |  1,074 lines

  1. /*
  2.  * HTML Output Routines
  3.  */
  4.  
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8.  
  9. #include "tags.h"
  10. #include "node.h"
  11. #include "database.h"
  12. #include "output.h"
  13.  
  14. #ifndef FILENAME_MAX
  15. #define FILENAME_MAX 1024
  16. #endif
  17.  
  18. char *url_template="%s.html";
  19. char *file_template="%s.html";
  20.  
  21. #ifdef MSDOS
  22. int max_per_directory = 100;
  23. #else
  24. int max_per_directory = 0;
  25. #endif
  26.  
  27. /*
  28.  * I don't like repeating these two templates, which are the same
  29.  * except for "INDEX" versus "../INDEX", but I am tired of working on this
  30.  * right now and I want to get something out that works right.
  31.  */
  32.  
  33. char *individual_template_subdir =
  34.   "<HTML>\n" \
  35.   "<HEAD>\n" \
  36.   "<TITLE>${@.XREF}: ${@.NAME}</TITLE>\n" \
  37.   "</HEAD>\n" \
  38.   "<BODY>\n"
  39.   "<H1>${@.NAME}</H1>\n" \
  40.   "!INCLUDE @.img\n" \
  41.   "!IF @.EVENT\n" \
  42.     "<UL>\n" \
  43.     "!RESET i\n" \
  44.     "!WHILE @.EVENT[i]\n" \
  45.       "<LI><EM>${@.EVENT[i].TAG}</EM>: ${@.EVENT[i].DATE}, ${@.EVENT[i].PLACE.NAME}\n" \
  46.       "!INCREMENT i\n" \
  47.     "!END\n" \
  48.     "</UL>\n" \
  49.    "!ENDIF\n" \
  50.    "!IF @.FATHER\n" \
  51.      "<EM>Father:</EM> <A HREF=\"${@.FATHER.&}\">${@.FATHER.NAME}</A><BR>\n" \
  52.   "!ENDIF\n" \
  53.   "!IF @.MOTHER\n" \
  54.     "<EM>Mother:</EM> <A HREF=\"${@.MOTHER.&}\">${@.MOTHER.NAME}</A><BR>\n" \
  55.   "!ENDIF\n" \
  56.   "<BR>\n" \
  57.   "!RESET i\n" \
  58.   "!WHILE @.FAMS[i]\n" \
  59.     "</EM>Family ${i}</EM>:\n" \
  60.     "!IF @.ISMALE\n" \
  61.       "!IF @.FAMS[i].FAMILY.WIFE\n" \
  62.         "<A HREF=\"${@.FAMS[i].FAMILY.WIFE.&}\">${@.FAMS[i].FAMILY.WIFE.NAME}</A>\n" \
  63.       "!ENDIF\n" \
  64.     "!ENDIF\n"
  65.     "!IF @.ISFEMALE\n" \
  66.       "!IF @.FAMS[i].FAMILY.HUSBAND\n" \
  67.         "<A HREF=\"${@.FAMS[i].FAMILY.HUSBAND.&}\">${@.FAMS[i].FAMILY.HUSBAND.NAME}</A>\n" \
  68.       "!ENDIF\n" \
  69.     "!ENDIF\n" \
  70.     "!IF @.FAMS[i].FAMILY.EVENT\n" \
  71.       "<UL>\n" \
  72.       "!RESET j\n" \
  73.       "!WHILE @.FAMS[i].FAMILY.EVENT[j]\n" \
  74.         "<LI><EM>${@.FAMS[i].FAMILY.EVENT[j].TAG}</EM>: " \
  75.         "${@.FAMS[i].FAMILY.EVENT[j].DATE}, ${@.FAMS[i].FAMILY.EVENT[j].PLACE.NAME}\n" \
  76.         "!INCREMENT j\n" \
  77.       "!END\n" \
  78.       "</UL>\n" \
  79.     "!ELSE\n" \
  80.       "<BR>\n" \
  81.     "!ENDIF\n" \
  82.     "!IF @.FAMS[i].FAMILY.CHILDREN\n" \
  83.       "<OL>\n" \
  84.       "!RESET j\n" \
  85.       "!WHILE @.FAMS[i].FAMILY.CHILDREN[j]\n" \
  86.         "<LI><A HREF=\"${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.&}\">" \
  87.         "${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.NAME}</A>\n" \
  88.         "!INCREMENT j\n" \
  89.       "!END\n" \
  90.       "</OL>\n" \
  91.     "!ENDIF\n" \
  92.     "!INCREMENT i\n" \
  93.   "!END\n" \
  94.   "<A HREF=\"../INDEX.html\">INDEX</A><BR><BR>\n" \
  95.   "!IF @.NOTE\n" \
  96.     "<H2>Notes</H2>\n" \
  97.     "!RESET i\n" \
  98.     "!WHILE @.NOTE[i]\n" \
  99.       "${@.NOTE[i].TEXT}\n" \
  100.       "!RESET j\n" \
  101.       "!WHILE @.NOTE[i].CONT[j]\n" \
  102.         "${@.NOTE[i].CONT[j].TEXT}\n" \
  103.         "<BR>\n" \
  104.         "!INCREMENT j\n" \
  105.       "!END\n" \
  106.       "<BR>\n" \
  107.       "!INCREMENT i\n" \
  108.     "!END\n" \
  109.   "!ENDIF\n" \
  110.   "<BR>\n" \
  111.   "!IF @.SOURCE\n" \
  112.     "<H2>Sources</H2>\n" \
  113.     "!RESET i\n" \
  114.     "!WHILE @.SOURCE[i]\n" \
  115.       "${@.SOURCE[i].SOURCE.TEXT}\n" \
  116.       "!RESET j\n" \
  117.       "!WHILE @.SOURCE[i].SOURCE.CONT[j]\n" \
  118.         "${@.SOURCE[i].SOURCE.CONT[j].TEXT}\n" \
  119.         "<BR>\n" \
  120.         "!INCREMENT j\n" \
  121.       "!END\n" \
  122.       "<BR>\n" \
  123.       "!INCREMENT i\n" \
  124.     "!END\n" \
  125.   "!ENDIF\n" \
  126.   "!INCLUDE @.inc\n" \
  127.   "</BODY>\n" \
  128.   "</HTML>\n";
  129.  
  130. char *individual_template_nosubdir =
  131.   "<HTML>\n" \
  132.   "<HEAD>\n" \
  133.   "<TITLE>${@.XREF}: ${@.NAME}</TITLE>\n" \
  134.   "</HEAD>\n" \
  135.   "<BODY>\n"
  136.   "<H1>${@.NAME}</H1>\n" \
  137.   "!INCLUDE @.img\n" \
  138.   "!IF @.EVENT\n" \
  139.     "<UL>\n" \
  140.     "!RESET i\n" \
  141.     "!WHILE @.EVENT[i]\n" \
  142.       "<LI><EM>${@.EVENT[i].TAG}</EM>: ${@.EVENT[i].DATE}, ${@.EVENT[i].PLACE.NAME}\n" \
  143.       "!INCREMENT i\n" \
  144.     "!END\n" \
  145.     "</UL>\n" \
  146.    "!ENDIF\n" \
  147.    "!IF @.FATHER\n" \
  148.      "<EM>Father:</EM> <A HREF=\"${@.FATHER.&}\">${@.FATHER.NAME}</A><BR>\n" \
  149.   "!ENDIF\n" \
  150.   "!IF @.MOTHER\n" \
  151.     "<EM>Mother:</EM> <A HREF=\"${@.MOTHER.&}\">${@.MOTHER.NAME}</A><BR>\n" \
  152.   "!ENDIF\n" \
  153.   "<BR>\n" \
  154.   "!RESET i\n" \
  155.   "!WHILE @.FAMS[i]\n" \
  156.     "</EM>Family ${i}</EM>:\n" \
  157.     "!IF @.ISMALE\n" \
  158.       "!IF @.FAMS[i].FAMILY.WIFE\n" \
  159.         "<A HREF=\"${@.FAMS[i].FAMILY.WIFE.&}\">${@.FAMS[i].FAMILY.WIFE.NAME}</A>\n" \
  160.       "!ENDIF\n" \
  161.     "!ENDIF\n"
  162.     "!IF @.ISFEMALE\n" \
  163.       "!IF @.FAMS[i].FAMILY.HUSBAND\n" \
  164.         "<A HREF=\"${@.FAMS[i].FAMILY.HUSBAND.&}\">${@.FAMS[i].FAMILY.HUSBAND.NAME}</A>\n" \
  165.       "!ENDIF\n" \
  166.     "!ENDIF\n" \
  167.     "!IF @.FAMS[i].FAMILY.EVENT\n" \
  168.       "<UL>\n" \
  169.       "!RESET j\n" \
  170.       "!WHILE @.FAMS[i].FAMILY.EVENT[j]\n" \
  171.         "<LI><EM>${@.FAMS[i].FAMILY.EVENT[j].TAG}</EM>: " \
  172.         "${@.FAMS[i].FAMILY.EVENT[j].DATE}, ${@.FAMS[i].FAMILY.EVENT[j].PLACE.NAME}\n" \
  173.         "!INCREMENT j\n" \
  174.       "!END\n" \
  175.       "</UL>\n" \
  176.     "!ELSE\n" \
  177.       "<BR>\n" \
  178.     "!ENDIF\n" \
  179.     "!IF @.FAMS[i].FAMILY.CHILDREN\n" \
  180.       "<OL>\n" \
  181.       "!RESET j\n" \
  182.       "!WHILE @.FAMS[i].FAMILY.CHILDREN[j]\n" \
  183.         "<LI><A HREF=\"${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.&}\">" \
  184.         "${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.NAME}</A>\n" \
  185.         "!INCREMENT j\n" \
  186.       "!END\n" \
  187.       "</OL>\n" \
  188.     "!ENDIF\n" \
  189.     "!INCREMENT i\n" \
  190.   "!END\n" \
  191.   "<A HREF=\"INDEX.html\">INDEX</A><BR><BR>\n" \
  192.   "!IF @.NOTE\n" \
  193.     "<H2>Notes</H2>\n" \
  194.     "!RESET i\n" \
  195.     "!WHILE @.NOTE[i]\n" \
  196.       "${@.NOTE[i].TEXT}\n" \
  197.       "!RESET j\n" \
  198.       "!WHILE @.NOTE[i].CONT[j]\n" \
  199.         "${@.NOTE[i].CONT[j].TEXT}\n" \
  200.         "<BR>\n" \
  201.         "!INCREMENT j\n" \
  202.       "!END\n" \
  203.       "<BR>\n" \
  204.       "!INCREMENT i\n" \
  205.     "!END\n" \
  206.   "!ENDIF\n" \
  207.   "<BR>\n" \
  208.   "!IF @.SOURCE\n" \
  209.     "<H2>Sources</H2>\n" \
  210.     "!RESET i\n" \
  211.     "!WHILE @.SOURCE[i]\n" \
  212.       "${@.SOURCE[i].SOURCE.TEXT}\n" \
  213.       "!RESET j\n" \
  214.       "!WHILE @.SOURCE[i].SOURCE.CONT[j]\n" \
  215.         "${@.SOURCE[i].SOURCE.CONT[j].TEXT}\n" \
  216.         "<BR>\n" \
  217.         "!INCREMENT j\n" \
  218.       "!END\n" \
  219.       "<BR>\n" \
  220.       "!INCREMENT i\n" \
  221.     "!END\n" \
  222.   "!ENDIF\n" \
  223.   "!INCLUDE @.inc\n" \
  224.   "</BODY>\n" \
  225.   "</HTML>\n";
  226.  
  227. char *individual_template = NULL;
  228.  
  229. char *index_template =
  230.   "<HTML>\n<HEAD>\n<TITLE>Index of Persons</TITLE>\n</HEAD>\n" \
  231.   "<BODY>\n<H1>Index of Persons</H1>\n<P>\n" \
  232.   "!WHILE @\n" \
  233.     "!IF @.TITLE\n" \
  234.       "<A HREF=\"${@.&}\">${@.NAME} (${@.TITLE})</A>\n" \
  235.     "!ELSE\n" \
  236.       "<A HREF=\"${@.&}\">${@.NAME}</A>\n" \
  237.     "!ENDIF\n" \
  238.     " (${@.BIRTH.DATE} - ${@.DEATH.DATE})<BR>\n" \
  239.     "!NEXT\n" \
  240.   "!END\n" \
  241.   "</P>\n</BODY>\n</HTML>\n";
  242.  
  243. /*
  244.  * Record types
  245.  */
  246.  
  247. typedef enum {
  248.   T_INTEGER, T_STRING, T_PLACE, T_NOTE, T_XREF, T_SOURCE,
  249.   T_FAMEVENT, T_EVENT, T_INDIV, T_FAMILY, T_CONT, T_URL
  250. } record_type;
  251.  
  252. /*
  253.  * Interpreter state
  254.  */
  255.  
  256. int skipping;
  257.  
  258. #define CONTROL_STACK_SIZE 100
  259. char *while_stack[CONTROL_STACK_SIZE];
  260. int while_stack_top;
  261. int if_stack[CONTROL_STACK_SIZE];
  262. int if_stack_top;
  263.  
  264. struct individual_record *root;
  265.  
  266. char *template;
  267. char *template_start;
  268. int current_index;
  269. record_type current_type = T_INTEGER;
  270. union value {
  271.   int integer;
  272.   char *string;
  273.   struct place_structure *place;
  274.   struct note_structure *note;
  275.   struct xref *xref;
  276.   struct event_structure *event;
  277.   struct individual_record *indiv;
  278.   struct family_record *family;
  279.   struct continuation *cont;
  280.   struct source_record *source;
  281.   char *url;
  282. } current_value;
  283.  
  284. char current_url[FILENAME_MAX+1];
  285. int doing_index;
  286.  
  287. void interpret(FILE *ofile);
  288. void variable(FILE *ofile);
  289. void command(FILE *ofile);
  290. void collect_identifier(char **ret);
  291. void skip_white_space();
  292. void output_error(char *msg);
  293.  
  294. void set_variable(char *name, int value);
  295. int get_variable(char *name);
  296.  
  297. void family_select(char *field);
  298. void indiv_select(char *field);
  299. void event_select(char *field);
  300. void note_select(char *field);
  301. void source_select(char *field);
  302. void cont_select(char *field);
  303. void place_select(char *field);
  304. void xref_select(char *field);
  305.  
  306. void construct_url(char *dest, struct individual_record *indiv);
  307.  
  308. void output_individual(struct individual_record *rt)
  309. {
  310.   FILE *ofile;
  311.   char path[FILENAME_MAX+1];
  312.   char url[FILENAME_MAX+1];
  313.  
  314.   if(max_per_directory) {
  315.     sprintf(path, "D%07d",
  316.         rt->serial / max_per_directory);
  317.     mkdir(path, 0777);
  318.     str