#include "data.h"
#include "html.h"
#include "parse.h"
#include "utils.h"
#define USE_FILE_URLS
int inTable=0;
char *BaseFilename=NULL;
char *OverrideBaseFilename=NULL;
/* prototypes */
char *form_info_tag_href( char *nodefile, char *nodename );
int make_Top_link( char *destdir, char *destfile );
int make_info_dir( char *destdir );
void write_node_link_html( FILE *f, char *nodefile, char *refname, char *ref );
void start_html_content( FILE *f );
void make_nav_links( FILE *f, NODE *node );
void html_error( char *s, char *p, char *q );
/* print out the url for a info file */
char *form_info_tag_href( char *nodefile, char *nodename )
{
char tmp[1024];
char *escaped_nodename;
char *filename;
escaped_nodename = escape_html_chars( nodename );
if (!strcmp(BaseFilename, nodefile))
{
if (OverrideBaseFilename)
filename = OverrideBaseFilename;
else
filename = BaseFilename;
}
else
filename = nodefile;
g_snprintf(tmp,sizeof(tmp),"HREF=\"info:%s#%s\"", filename, escaped_nodename );
if (escaped_nodename)
g_free(escaped_nodename);
return g_strdup(tmp);
}
/* returns zero if success making link from destfile -> index.html in */
/* specified directory. If it already exists, just returns with success */
int make_Top_link( char *destdir, char *destfile )
{
struct stat filestat;
char *indexlink;
indexlink = (char *) g_malloc( strlen(destdir) + 20);
strcpy(indexlink, destdir);
strcat(indexlink, "/index.html");
if (lstat(indexlink, &filestat))
{
if (errno == ENOENT)
{
if (symlink(destfile, indexlink))
{
fprintf(stderr,"Error creating link to %s\n",indexlink);
perror("Error was");
exit(1);
}
}
else
{
fprintf(stderr,"Error stat'ing file %s\n",indexlink);
perror("Error was");
exit(1);
}
}
else if (!S_ISLNK(filestat.st_mode))
{
fprintf(stderr, "file %s exists and isnt a link\n",indexlink);
fprintf(stderr, "FIX ME!!!\n");
g_free(indexlink);
return -1;
}
return 0;
}
/* return non-zero if error with making directory */
int make_info_dir( char *destdir )
{
struct stat filestat;
if (stat(destdir, &filestat))
{
if (errno == ENOENT)
{
if (mkdir(destdir, 01777))
{
fprintf(stderr,"Error creating directory %s\n",destdir);
perror("Error was");
exit(1);
}
}
else
{
fprintf(stderr,"Error stat'ing directory %s\n",destdir);
perror("Error was");
exit(1);
}
}
else if (!S_ISDIR(filestat.st_mode))
{
fprintf(stderr, "Info dir %s exists and isnt a directory!\n",destdir);
fprintf(stderr, "FIX ME!!!\n");
return -1;
}
return 0;
}
/* write a link to another document */
void write_node_link_html( FILE *f, char *nodefile, char *refname, char *ref )
{
char *converted_nodename;
char *href;
if (ref) {
if (strcasecmp(ref, "(dir)")) {
converted_nodename = g_strdup( ref );
map_spaces_to_underscores( converted_nodename );
href = form_info_tag_href(nodefile, converted_nodename);
fprintf(f,"%s%s\n", href, refname, ref);
g_free(href);
g_free(converted_nodename);
} else {
href = form_info_tag_href("dir", "Top");
fprintf(f,"%s(dir)\n",href, refname);
g_free(href);
}
}
}
/* write out top of a new html file */
#if 0
void write_html_header( FILE *f, char *filename, char *nodename)
{
fprintf(f,"\n");
fprintf(f,"\n");
fprintf(f,"\n");
fprintf(f,"Info Node: (%s)%s\n",filename,nodename);
fprintf(f,"\n");
fprintf(f,"\n");
fprintf(f,"\n",work_filename, work_node);
}
#endif
/* start of everything after html header */
void start_html_content( FILE *f )
{
fprintf(f,"\n");
}
/* we want to put links to next, prev, and up nodes */
void make_nav_links( FILE *f, NODE *node )
{
#if 0
fprintf(f,"\n");
write_node_link_html( f, node->filename, "Next:", node->next );
write_node_link_html( f, node->filename, "Prev:", node->prev );
write_node_link_html( f, node->filename, "Up:", node->up );
fprintf(f,"
\n");
#else
fprintf(f,"\n");
fprintf(f,"\n");
fprintf(f,"\t\n\t");
write_node_link_html( f, node->filename, "Next:", node->next );
fprintf(f,"\t | \n");
fprintf(f,"\t\n\t");
write_node_link_html( f, node->filename, "Prev:", node->prev );
fprintf(f,"\t | \n");
fprintf(f,"\t\n\t");
write_node_link_html( f, node->filename, "Up:", node->up );
fprintf(f,"\t | \n");
fprintf(f,"
\n
\n");
#endif
}
/* s is error message */
/* p is start of offending line */
/* q is end of offending line */
void html_error( char *s, char *p, char *q )
{
fprintf(stderr, "%s:%s\n",work_filename, work_node);
fprintf(stderr, "\t%s\n",s);
fprintf(stderr, "\tOffending line is:\n\t|");
fwrite(p, 1, q-p, stderr);
fprintf(stderr, "|\n");
}
/********************************************************************
* here is what we expect in contents of a node:
*
* headers: These are identified as a line of text
* followed by a row of '---' or '###' normally.
* These get mapped to
for now.
*
* body text: Format this between
statements.
* Catch any *Note and *note and make into
* links to other documents. Also try to catch
* URLs as well.
*
* menus: Starts with a '* Menu' line. Goes until the
* end of the node, or until the next line which
* starts with something other than a '* ' or '\n'.
*
* end of node: The INFO_FF and INFO_COOKIE mark the end of a node.
* Hitting EOF also marks the end of a node.
********************************************************************/
void dump_html_for_node( NODE *node )
{
/* char *destdir; */
/* char *destfile; */
char *escaped_nodename;
/* char *converted_nodename; */
char *contents_start, *contents_end;
char *header_name;
char *p, *q, *r, *skippnt;
char *end_menu_entry;
int menu_open, body_open;
int seen_menu;
int prev_was_blank, next_is_blank, current_is_blank;
int seen_first_header;
int last_output_was_header;
int nskip;
int we_are_in_dir_node;
int i;
FILE *f;
/* msf - used to write each node to a separate file - now we're going */
/* to just output HTML to stdout. */
/* Each node will just be concantentated to previous */
#if 0
destdir = (char *) g_malloc ( strlen(node->filename) +
strlen(HTML_ROOT) +
strlen(node->filename) + 2);
strcpy(destdir, HTML_ROOT);
strcat(destdir, "/");
strcat(destdir, node->filename);
strcat(destdir, "/");
/* check that the dir for info file exists */
make_info_dir( destdir );
/* ok, we made the dir, lets go */
destfile = (char *) g_malloc( strlen(destdir) + strlen(node->nodename) + 10);
strcpy(destfile, destdir);
converted_nodename = g_strdup( node->nodename );
map_spaces_to_underscores( converted_nodename );
strcat(destfile, converted_nodename);
strcat(destfile, ".html");
g_free(converted_nodename);
if (!(f=fopen(destfile, "w")))
{
fprintf(f,"Couldnt create node html file %s\n",destfile);
perror("Error was");
exit(1);
}
#endif
/* hack - just dump to stdout for now */
f = stdout;
/* see if this is THE dir node */
we_are_in_dir_node = !strcmp("Top", node->nodename) && !strcmp("dir", node->filename);
#if 0
/* try and make a link between 'index.html' and 'Top.html' */
if (!strcmp("Top", node->nodename))
make_Top_link( destdir, destfile );
#endif
#if 0
/* do the html header first */
write_html_header( f, node->filename, node->nodename );
#endif
#if 0
/* now for the body */
start_html_content( f );
#endif
/* make an anchor */
escaped_nodename = escape_html_chars( node->nodename );
map_spaces_to_underscores( escaped_nodename );
fprintf(f, "\n",escaped_nodename);
g_free(escaped_nodename);
/* links to other immediate nodes */
make_nav_links( f, node );
/* setup pointers to textual content of current node */
contents_start = node->contents;
contents_end = node->contents+node->contlen;
/* scan through all of contents and generate html on the fly */
/* p points at start of current line */
/* q points at the end of current line (at '\n' actually) */
/* r points at the start of next line */
/* we do this to catch headers */
/* scan for a header at the top of the contents */
/* if we see a '\n***'3 '*' in a row i */
/* then take previous line as a header */
header_name = NULL;
p = contents_start = node->contents;
q = memchr(p, '\n', contents_end - p);
r=q+1;
/* we have several states we could be in */
next_is_blank = 0;
prev_was_blank = 0;
current_is_blank = 0;
seen_first_header = 0;
seen_menu = 0;
menu_open = 0;
body_open = 0;
last_output_was_header = 0;
for (; q && r <= contents_end; )
{
nskip = 1;
skippnt = NULL;
next_is_blank = (*r == '\n');
current_is_blank = (*p == '\n');
/* test some easy things first */
if (!strncmp(p, MENU_START, strlen(MENU_START)))
{
if (we_are_in_dir_node && !seen_menu)
{
if (body_open)
{
close_body_text_html(f);
body_open = 0;
}
fprintf(f," Main Info File Directory
\n");
open_body_text_html(f);
body_open = 1;
fprintf(f,"This is the main directory of available info files.\n");
}
if (body_open)
{
close_body_text_html(f);
body_open = 0;
}
else if (seen_menu)
html_error("Warning:saw new menu start and already in menu!", p, q);
if (menu_open)
close_menu_html( f );
if (last_output_was_header)
open_menu_html( f, "" );
else
open_menu_html( f, "Contents" );
seen_menu = 1;
menu_open = 1;
last_output_was_header = 0;
}
else if (we_are_in_dir_node && !seen_menu)
{
/* do nothing */
}
else if (seen_menu)
{
/* if current line is blank ignore it */
if (current_is_blank)
{
/* do nothing */
}
/* first see if its a menu line */
else if (!strncmp(p, MENU_ENTRY, strlen(MENU_ENTRY)))
{
if (!seen_menu)
html_error("Have seen menu start and hit a menu line!", p, q);
else
{
if (body_open)
{
if (menu_open)
html_error("Hit a menu line, and body and menu are opened!", p, q);
close_body_text_html( f );
body_open = 0;
open_menu_html( f, "" );
menu_open = 1;
}
if (!menu_open)
{
open_menu_html( f, "" );
menu_open = 1;
}
write_menu_entry_html( f, p, node->filename, &end_menu_entry );
if (end_menu_entry != NULL)
skippnt = end_menu_entry;
last_output_was_header = 0;
}
}
/* maybe its a header line */
/* man this is getting ridiculous, its like teaching a child */
/* to read! */
else if (is_a_hdr_line(r) ||
(*p != '*' && *r == '*' && *(r+1) == ' ') ||
(*p != '*' && seen_menu && (*p != ' ' && *(p+1) != ' ') &&
!current_is_blank && prev_was_blank && next_is_blank))
{
header_name = (char *) g_malloc( q-p+2 );
memcpy(header_name, p, q-p);
*(header_name + (q - p) ) = '\000';
/* if we were writing a particular component, close it */
if (menu_open)
{
close_menu_html( f );
menu_open = 0;
}
if (body_open)
{
close_body_text_html( f );
body_open = 0;
}
if (seen_first_header)
write_header_html( f, header_name, HEADER_SIZE_2 );
else
{
seen_first_header = 1;
write_header_html( f, header_name, HEADER_SIZE_1 );
}
g_free(header_name);
/* jump ahead another line */
if (!(*r == '*' && *(r+1) == ' ') && !next_is_blank)
nskip++;
last_output_was_header = 1;
}
/* well, has to be body text then */
else
{
if (menu_open)
{
close_menu_html( f );
menu_open = 0;
write_html_horiz_rule ( f );
}
if (!body_open)
{
open_body_text_html( f );
body_open = 1;
}
if (*p != '\n' && !last_output_was_header)
{
skippnt=write_body_text_html( f, p, q, node->filename );
last_output_was_header = 0;
}
}
}
/* otherwise, no menu seen so things are easier */
else
{
if (is_a_hdr_line(r))
{
header_name = (char *) g_malloc( q-p+2 );
memcpy(header_name, p, q-p);
*(header_name + (q - p) ) = '\000';
/* if we were writing a particular component, close it */
if (body_open)
{
close_body_text_html( f );
body_open = 0;
}
if (seen_first_header)
write_header_html( f, header_name, HEADER_SIZE_2 );
else
{
seen_first_header = 1;
write_header_html( f, header_name, HEADER_SIZE_1 );
}
g_free(header_name);
/* jump ahead another line */
if (!(*r == '*' && *(r+1) == ' ') && !next_is_blank)
nskip++;
last_output_was_header = 1;
}
/* well, has to be body text then */
else
{
if (!body_open)
{
open_body_text_html( f );
body_open = 1;
}
if (!(*p == '\n' && last_output_was_header))
{
skippnt=write_body_text_html( f, p, q, node->filename );
last_output_was_header = 0;
}
}
}
/* end of cases, move to next line in contents */
prev_was_blank = (*p == '\n');
if (skippnt)
{
p = skippnt;
q = memchr(p, '\n', contents_end - p);
r = q+1;
skippnt = NULL;
}
else
for (i=0; i< nskip; i++)
{
p = r;
q = memchr(p, '\n', contents_end - p);
r = q+1;
}
}
/* thats all folks */
if (menu_open)
close_menu_html( f );
else if (body_open)
close_body_text_html( f );
/* put nav links at the bottom */
make_nav_links(f, node);
#if 0
fprintf(f,"\n\n");
#endif
/* clean up */
#if 0
g_free(destdir);
g_free(destfile);
#endif
}
void write_header_html( FILE *f, char *p, char *hdr )
{
fprintf(f,"<%s> %s %s>\n",hdr,p,hdr);
}
void open_body_text_html( FILE *f )
{
fprintf(f, "\n");
}
void close_body_text_html( FILE *f )
{
fprintf(f, "
\n");
}
/* we have to handle '*note' and '*Note' links in body text */
/* p is ptr to start of current line */
/* q is ptr to '\n' at end of current line */
char *write_body_text_html( FILE *f, char *p, char *q, char *nodefile )
{
int curlen;
int ref_exists;
char *tmp;
char *ptr;
char *match1;
char *note_ptr;
char *converted_nodename;
char *escaped_refname;
char *escaped_refnode;
char *escaped_seg;
char *refname, *reffile, *refnode, *end;
char *href;
curlen = q - p;
tmp = (char *) g_malloc( curlen + 1 );
memcpy( tmp, p, curlen );
*(tmp+curlen) = '\000';
/* see if there is a reference in current line */
/* and make sure this isnt a '*Note*' instead ! */
ref_exists = 0;
if ((note_ptr=strstr(tmp, "*Note")) || (note_ptr=strstr(tmp, "*note")))
if (*(note_ptr+6) != '*')
ref_exists = 1;
if (ref_exists)
{
/* find the start of the link */
note_ptr = (note_ptr - tmp) + p;
match1 = note_ptr + 4;
/* not needed any more */
g_free(tmp);
for (; 1; )
if (*(match1+1) == ' ' || *(match1+1) == '\n')
match1++;
else
break;
/* find end of the link */
if (parse_note_ref( match1, &refname, &reffile, &refnode, &end, 1))
{
html_error( "Corrupt *Note link found!", p, q );
return NULL;
}
/* now we assume that parse_note_ref left control chars in ref* */
/* if both null, we had a '::' and have to set both */
if (reffile == NULL && refnode == NULL)
{
reffile = g_strdup(nodefile);
refnode = g_strdup(refname);
}
/* otherwise we had (file)., and we set node to 'Top' */
else if (refnode == NULL)
refnode = g_strdup("Top");
/* otherwise we had :nodename., and we set node to 'Top' */
else if (reffile == NULL)
reffile = g_strdup(nodefile);
/* Here we need to escape everything up to Note.
* One caveat: The "*Note*" itself isn't escaped. Currently we know this is
* okay ("*Note" has no characters needing escapes.) but....
*/
curlen = note_ptr - p;
tmp = (char *) g_malloc (curlen + 1);
memcpy (tmp, p, curlen);
*(tmp + curlen) = '\000';
escaped_seg = escape_html_chars (tmp);
g_free (tmp);
/* write out stuff up to Note */
fprintf(f, "%s", escaped_seg);
fprintf(f, "");
fwrite(note_ptr, 1, match1 - note_ptr, f);
fprintf(f, " ");
/* we need a nice nodename -> filename translation */
/* so we convert newlines to spaces */
converted_nodename = g_strdup( refnode );
convert_newlines_to_spaces( converted_nodename );
/* we don't want two spaces in a row */
strip_dupspaces( converted_nodename );
map_spaces_to_underscores( converted_nodename );
/* escape HTML chars */
escaped_refname = escape_html_chars( refname );
escaped_refnode = escape_html_chars( refnode );
/* now output the link to html doc */
#if 0
fprintf(f,"", reffile, converted_nodename);
#endif
href = form_info_tag_href(reffile, converted_nodename);
fprintf(f,"", href);
for (ptr=escaped_refname; *ptr; ptr++)
if (*ptr == '\n')
{
fprintf(f,"\n");
fprintf(f,"", href);
}
else
fprintf(f,"%c", *ptr);
if (strcmp(refname, refnode))
{
fprintf(f,": ");
for (ptr=escaped_refnode; *ptr; ptr++)
if (*ptr == '\n')
{
fprintf(f,"\n");
fprintf(f,"", href);
}
else
fprintf(f,"%c", *ptr);
fprintf(f,"");
if (end > q && !(strchr(refnode, '\n')))
fprintf(f,"\n");
}
else
fprintf(f,"");
if (href)
g_free(href);
if (escaped_refnode)
g_free(escaped_refnode);
if (escaped_refname)
g_free(escaped_refname);
if (converted_nodename)
g_free(converted_nodename);
g_free(escaped_seg);
g_free(refname);
g_free(reffile);
g_free(refnode);
/* write out stuff at end */
if (end < q)
{
/* Escape up to the end of line. */
curlen = q - (end+1);
tmp = (char *) g_malloc (curlen + 1);
memcpy (tmp, end+1, curlen);
*(tmp+curlen) = '\000';
escaped_seg = escape_html_chars (tmp);
g_free (tmp);
fprintf (f, "%s", escaped_seg);
fprintf (f, "\n");
g_free (escaped_seg);
return NULL;
}
else
return end+1;
}
else
{
/* Escape the whole thing. */
escaped_seg = escape_html_chars (tmp);
fprintf (f, "%s", escaped_seg);
fprintf (f, "\n");
/* not needed any more */
g_free(tmp);
g_free (escaped_seg);
return NULL;
}
}
void open_menu_html( FILE *f, char *p )
{
if (*p != '\000')
fprintf(f, "%s
\n",p);
/* fprintf(f, "\n"); */
#if 0
fprintf(f, "\n");
#else
if (inTable)
fprintf(stderr, "In a table and starting new one!\n");
inTable = 1;
fprintf(f, " |
\n");
#endif
}
void close_menu_html( FILE *f )
{
/* fprintf(f, "\n"); */
#if 0
fprintf(f, "\n");
#else
if (!inTable)
fprintf(stderr, "Not in a table and closing one!\n");
inTable = 0;
fprintf(f, "
\n");
#endif
}
/* writes menu entry contained in string p */
/* nodename and nodefile apply to the node which menu entry is in */
void write_menu_entry_html( FILE *f, char *p, char *nodefile, char **menu_end )
{
char *refname;
char *reffile;
char *refnode;
char *end;
char *realend;
char *converted_nodename;
char *escaped_refnode;
char *escaped_refname;
char *href;
int i, done;
/* skip over the '* ' at the start of the line */
if (parse_menu_line( p+2, &refname, &reffile, &refnode, &end, 0 ))
{
html_error("Error parsing menu", p, memchr(p, '\n', 80));
return;
}
/* if both null, we had a '::' and have to set both */
if (reffile == NULL && refnode == NULL)
{
reffile = g_strdup(nodefile);
refnode = g_strdup(refname);
}
/* otherwise we had (file)., and we set node to 'Top' */
else if (refnode == NULL)
refnode = g_strdup("Top");
else if (reffile == NULL)
reffile = g_strdup(nodefile);
/* now find the end of the right hand text for this menu line */
/* it can continue for several lines */
done = 0;
for (realend = end+1; !done; realend++)
{
if (*realend == '\n')
{
if (*(realend+1) == '\n')
{
done = 1;
continue;
}
for (i=1; i<4; i++)
if (!isspace(*(realend+i)) && *(realend+i) != '\n')
{
done = 1;
break;
}
}
}
*menu_end = realend;
converted_nodename = g_strdup( refnode );
map_spaces_to_underscores( converted_nodename );
escaped_refnode = escape_html_chars( refnode );
escaped_refname = escape_html_chars( refname );
#if 0
fprintf(f,"- %s\n",
reffile, converted_nodename, escaped_refname);
#endif
href = form_info_tag_href( reffile, converted_nodename );
#if 0
fprintf(f,"
- %s\n", href, escaped_refname );
fprintf(f,"
- ");
if (*end == '.' && *(end+1) == '\n')
fprintf(f,"%s.\n",escaped_refnode);
else
fwrite(end+1, 1, *menu_end - end - 1, f);
#else
fprintf(f,"
\n\t\n\t\t%s\n\t | \n"
"\t\n\t\t",
href, escaped_refname );
if (*end == '.' && *(end+1) == '\n')
fprintf(f,"%s.\n",escaped_refnode);
else
fwrite(end+1, 1, *menu_end - end - 1, f);
fprintf(f,"\n\t | \n
\n");
#endif
if (href)
g_free(href);
if (escaped_refname)
g_free(escaped_refname);
if (escaped_refnode)
g_free(escaped_refnode);
if (converted_nodename)
g_free(converted_nodename);
g_free(refname);
g_free(reffile);
g_free(refnode);
}
void write_html_horiz_rule( FILE *f )
{
fprintf(f, "
\n");
}