home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best Internet Programs
/
BESTINTERNET.bin
/
latest
/
ged2ht20
/
output.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-08
|
26KB
|
1,074 lines
/*
* HTML Output Routines
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tags.h"
#include "node.h"
#include "database.h"
#include "output.h"
#ifndef FILENAME_MAX
#define FILENAME_MAX 1024
#endif
char *url_template="%s.html";
char *file_template="%s.html";
#ifdef MSDOS
int max_per_directory = 100;
#else
int max_per_directory = 0;
#endif
/*
* I don't like repeating these two templates, which are the same
* except for "INDEX" versus "../INDEX", but I am tired of working on this
* right now and I want to get something out that works right.
*/
char *individual_template_subdir =
"<HTML>\n" \
"<HEAD>\n" \
"<TITLE>${@.XREF}: ${@.NAME}</TITLE>\n" \
"</HEAD>\n" \
"<BODY>\n"
"<H1>${@.NAME}</H1>\n" \
"!INCLUDE @.img\n" \
"!IF @.EVENT\n" \
"<UL>\n" \
"!RESET i\n" \
"!WHILE @.EVENT[i]\n" \
"<LI><EM>${@.EVENT[i].TAG}</EM>: ${@.EVENT[i].DATE}, ${@.EVENT[i].PLACE.NAME}\n" \
"!INCREMENT i\n" \
"!END\n" \
"</UL>\n" \
"!ENDIF\n" \
"!IF @.FATHER\n" \
"<EM>Father:</EM> <A HREF=\"${@.FATHER.&}\">${@.FATHER.NAME}</A><BR>\n" \
"!ENDIF\n" \
"!IF @.MOTHER\n" \
"<EM>Mother:</EM> <A HREF=\"${@.MOTHER.&}\">${@.MOTHER.NAME}</A><BR>\n" \
"!ENDIF\n" \
"<BR>\n" \
"!RESET i\n" \
"!WHILE @.FAMS[i]\n" \
"</EM>Family ${i}</EM>:\n" \
"!IF @.ISMALE\n" \
"!IF @.FAMS[i].FAMILY.WIFE\n" \
"<A HREF=\"${@.FAMS[i].FAMILY.WIFE.&}\">${@.FAMS[i].FAMILY.WIFE.NAME}</A>\n" \
"!ENDIF\n" \
"!ENDIF\n"
"!IF @.ISFEMALE\n" \
"!IF @.FAMS[i].FAMILY.HUSBAND\n" \
"<A HREF=\"${@.FAMS[i].FAMILY.HUSBAND.&}\">${@.FAMS[i].FAMILY.HUSBAND.NAME}</A>\n" \
"!ENDIF\n" \
"!ENDIF\n" \
"!IF @.FAMS[i].FAMILY.EVENT\n" \
"<UL>\n" \
"!RESET j\n" \
"!WHILE @.FAMS[i].FAMILY.EVENT[j]\n" \
"<LI><EM>${@.FAMS[i].FAMILY.EVENT[j].TAG}</EM>: " \
"${@.FAMS[i].FAMILY.EVENT[j].DATE}, ${@.FAMS[i].FAMILY.EVENT[j].PLACE.NAME}\n" \
"!INCREMENT j\n" \
"!END\n" \
"</UL>\n" \
"!ELSE\n" \
"<BR>\n" \
"!ENDIF\n" \
"!IF @.FAMS[i].FAMILY.CHILDREN\n" \
"<OL>\n" \
"!RESET j\n" \
"!WHILE @.FAMS[i].FAMILY.CHILDREN[j]\n" \
"<LI><A HREF=\"${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.&}\">" \
"${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.NAME}</A>\n" \
"!INCREMENT j\n" \
"!END\n" \
"</OL>\n" \
"!ENDIF\n" \
"!INCREMENT i\n" \
"!END\n" \
"<A HREF=\"../INDEX.html\">INDEX</A><BR><BR>\n" \
"!IF @.NOTE\n" \
"<H2>Notes</H2>\n" \
"!RESET i\n" \
"!WHILE @.NOTE[i]\n" \
"${@.NOTE[i].TEXT}\n" \
"!RESET j\n" \
"!WHILE @.NOTE[i].CONT[j]\n" \
"${@.NOTE[i].CONT[j].TEXT}\n" \
"<BR>\n" \
"!INCREMENT j\n" \
"!END\n" \
"<BR>\n" \
"!INCREMENT i\n" \
"!END\n" \
"!ENDIF\n" \
"<BR>\n" \
"!IF @.SOURCE\n" \
"<H2>Sources</H2>\n" \
"!RESET i\n" \
"!WHILE @.SOURCE[i]\n" \
"${@.SOURCE[i].SOURCE.TEXT}\n" \
"!RESET j\n" \
"!WHILE @.SOURCE[i].SOURCE.CONT[j]\n" \
"${@.SOURCE[i].SOURCE.CONT[j].TEXT}\n" \
"<BR>\n" \
"!INCREMENT j\n" \
"!END\n" \
"<BR>\n" \
"!INCREMENT i\n" \
"!END\n" \
"!ENDIF\n" \
"!INCLUDE @.inc\n" \
"</BODY>\n" \
"</HTML>\n";
char *individual_template_nosubdir =
"<HTML>\n" \
"<HEAD>\n" \
"<TITLE>${@.XREF}: ${@.NAME}</TITLE>\n" \
"</HEAD>\n" \
"<BODY>\n"
"<H1>${@.NAME}</H1>\n" \
"!INCLUDE @.img\n" \
"!IF @.EVENT\n" \
"<UL>\n" \
"!RESET i\n" \
"!WHILE @.EVENT[i]\n" \
"<LI><EM>${@.EVENT[i].TAG}</EM>: ${@.EVENT[i].DATE}, ${@.EVENT[i].PLACE.NAME}\n" \
"!INCREMENT i\n" \
"!END\n" \
"</UL>\n" \
"!ENDIF\n" \
"!IF @.FATHER\n" \
"<EM>Father:</EM> <A HREF=\"${@.FATHER.&}\">${@.FATHER.NAME}</A><BR>\n" \
"!ENDIF\n" \
"!IF @.MOTHER\n" \
"<EM>Mother:</EM> <A HREF=\"${@.MOTHER.&}\">${@.MOTHER.NAME}</A><BR>\n" \
"!ENDIF\n" \
"<BR>\n" \
"!RESET i\n" \
"!WHILE @.FAMS[i]\n" \
"</EM>Family ${i}</EM>:\n" \
"!IF @.ISMALE\n" \
"!IF @.FAMS[i].FAMILY.WIFE\n" \
"<A HREF=\"${@.FAMS[i].FAMILY.WIFE.&}\">${@.FAMS[i].FAMILY.WIFE.NAME}</A>\n" \
"!ENDIF\n" \
"!ENDIF\n"
"!IF @.ISFEMALE\n" \
"!IF @.FAMS[i].FAMILY.HUSBAND\n" \
"<A HREF=\"${@.FAMS[i].FAMILY.HUSBAND.&}\">${@.FAMS[i].FAMILY.HUSBAND.NAME}</A>\n" \
"!ENDIF\n" \
"!ENDIF\n" \
"!IF @.FAMS[i].FAMILY.EVENT\n" \
"<UL>\n" \
"!RESET j\n" \
"!WHILE @.FAMS[i].FAMILY.EVENT[j]\n" \
"<LI><EM>${@.FAMS[i].FAMILY.EVENT[j].TAG}</EM>: " \
"${@.FAMS[i].FAMILY.EVENT[j].DATE}, ${@.FAMS[i].FAMILY.EVENT[j].PLACE.NAME}\n" \
"!INCREMENT j\n" \
"!END\n" \
"</UL>\n" \
"!ELSE\n" \
"<BR>\n" \
"!ENDIF\n" \
"!IF @.FAMS[i].FAMILY.CHILDREN\n" \
"<OL>\n" \
"!RESET j\n" \
"!WHILE @.FAMS[i].FAMILY.CHILDREN[j]\n" \
"<LI><A HREF=\"${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.&}\">" \
"${@.FAMS[i].FAMILY.CHILDREN[j].INDIV.NAME}</A>\n" \
"!INCREMENT j\n" \
"!END\n" \
"</OL>\n" \
"!ENDIF\n" \
"!INCREMENT i\n" \
"!END\n" \
"<A HREF=\"INDEX.html\">INDEX</A><BR><BR>\n" \
"!IF @.NOTE\n" \
"<H2>Notes</H2>\n" \
"!RESET i\n" \
"!WHILE @.NOTE[i]\n" \
"${@.NOTE[i].TEXT}\n" \
"!RESET j\n" \
"!WHILE @.NOTE[i].CONT[j]\n" \
"${@.NOTE[i].CONT[j].TEXT}\n" \
"<BR>\n" \
"!INCREMENT j\n" \
"!END\n" \
"<BR>\n" \
"!INCREMENT i\n" \
"!END\n" \
"!ENDIF\n" \
"<BR>\n" \
"!IF @.SOURCE\n" \
"<H2>Sources</H2>\n" \
"!RESET i\n" \
"!WHILE @.SOURCE[i]\n" \
"${@.SOURCE[i].SOURCE.TEXT}\n" \
"!RESET j\n" \
"!WHILE @.SOURCE[i].SOURCE.CONT[j]\n" \
"${@.SOURCE[i].SOURCE.CONT[j].TEXT}\n" \
"<BR>\n" \
"!INCREMENT j\n" \
"!END\n" \
"<BR>\n" \
"!INCREMENT i\n" \
"!END\n" \
"!ENDIF\n" \
"!INCLUDE @.inc\n" \
"</BODY>\n" \
"</HTML>\n";
char *individual_template = NULL;
char *index_template =
"<HTML>\n<HEAD>\n<TITLE>Index of Persons</TITLE>\n</HEAD>\n" \
"<BODY>\n<H1>Index of Persons</H1>\n<P>\n" \
"!WHILE @\n" \
"!IF @.TITLE\n" \
"<A HREF=\"${@.&}\">${@.NAME} (${@.TITLE})</A>\n" \
"!ELSE\n" \
"<A HREF=\"${@.&}\">${@.NAME}</A>\n" \
"!ENDIF\n" \
" (${@.BIRTH.DATE} - ${@.DEATH.DATE})<BR>\n" \
"!NEXT\n" \
"!END\n" \
"</P>\n</BODY>\n</HTML>\n";
/*
* Record types
*/
typedef enum {
T_INTEGER, T_STRING, T_PLACE, T_NOTE, T_XREF, T_SOURCE,
T_FAMEVENT, T_EVENT, T_INDIV, T_FAMILY, T_CONT, T_URL
} record_type;
/*
* Interpreter state
*/
int skipping;
#define CONTROL_STACK_SIZE 100
char *while_stack[CONTROL_STACK_SIZE];
int while_stack_top;
int if_stack[CONTROL_STACK_SIZE];
int if_stack_top;
struct individual_record *root;
char *template;
char *template_start;
int current_index;
record_type current_type = T_INTEGER;
union value {
int integer;
char *string;
struct place_structure *place;
struct note_structure *note;
struct xref *xref;
struct event_structure *event;
struct individual_record *indiv;
struct family_record *family;
struct continuation *cont;
struct source_record *source;
char *url;
} current_value;
char current_url[FILENAME_MAX+1];
int doing_index;
void interpret(FILE *ofile);
void variable(FILE *ofile);
void command(FILE *ofile);
void collect_identifier(char **ret);
void skip_white_space();
void output_error(char *msg);
void set_variable(char *name, int value);
int get_variable(char *name);
void family_select(char *field);
void indiv_select(char *field);
void event_select(char *field);
void note_select(char *field);
void source_select(char *field);
void cont_select(char *field);
void place_select(char *field);
void xref_select(char *field);
void construct_url(char *dest, struct individual_record *indiv);
void output_individual(struct individual_record *rt)
{
FILE *ofile;
char path[FILENAME_MAX+1];
char url[FILENAME_MAX+1];
if(max_per_directory) {
sprintf(path, "D%07d",
rt->serial / max_per_directory);
mkdir(path, 0777);
str