diff options
Diffstat (limited to 'src/info2html/html.c')
-rw-r--r-- | src/info2html/html.c | 835 |
1 files changed, 835 insertions, 0 deletions
diff --git a/src/info2html/html.c b/src/info2html/html.c new file mode 100644 index 00000000..6e12b8ff --- /dev/null +++ b/src/info2html/html.c @@ -0,0 +1,835 @@ +/* handles all html operations */ + +#include <stdio.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> + +#include <glib.h> + +#include "data.h" +#include "html.h" +#include "parse.h" +#include "utils.h" + +#define USE_FILE_URLS + +/* print out the url for a info file */ +char *form_info_tag_href( char *nodefile, char *nodename ) +{ + char tmp[1024]; + char *escaped_nodename; + + escaped_nodename = escape_html_chars( nodename ); + +#if 0 +#ifdef USE_FILE_URLS + snprintf(tmp,sizeof(tmp), + "HREF=\"../%s/%s.html\"", nodefile, escaped_nodename ); +#else + snprintf(tmp,sizeof(tmp), + "HREF=\"/cgi-bin/grab-info-file?doctype=info&" + "docname=%s&doctag=%s\"", nodefile, escaped_nodename ); +#endif +#endif +/* snprintf(tmp,sizeof(tmp),"HREF=\"info:%s#%s\"", nodefile, escaped_nodename ); */ + + snprintf(tmp,sizeof(tmp),"HREF=\"info:%s#%s\"", nodefile, 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,"<A %s>%s%s</A>\n", href, refname, ref); + g_free(href); +#if 0 + fprintf(f,"<A HREF=\"../%s/%s.html\">%s%s</A>\n", + nodefile, converted_nodename, refname, ref); +#endif + g_free(converted_nodename); + } + else + { +#if 0 + fprintf(f,"<A HREF=\"../dir/Top.html\">%s(dir)</A>\n",refname); +#endif + href = form_info_tag_href("dir", "Top"); + fprintf(f,"<A %s>%s(dir)</A>\n", href, refname); + g_free(href); + + } + } +} + +/* write out top of a new html file */ +void write_html_header( FILE *f, char *filename, char *nodename) +{ + fprintf(f,"<!DOCTYPE HTML PUBLIC \"-//W3C/DTD HTML 3.2//EN\">\n"); + fprintf(f,"<HTML>\n"); + fprintf(f,"<HEAD>\n"); + fprintf(f,"<TITLE>Info Node: (%s)%s</TITLE>\n",filename,nodename); + fprintf(f,"<META NAME=\"GENERATOR\" CONTENT=\"info2html\">\n"); + fprintf(f,"</HEAD>\n"); + fprintf(f,"<!-- conversion of file \"%s\", node \"%s\" -->\n",work_filename, work_node); +} + +/* start of everything after html header */ +void start_html_content( FILE *f ) +{ + fprintf(f,"<BODY>\n"); +} + +/* we want to put links to next, prev, and up nodes */ +void make_nav_links( FILE *f, NODE *node ) +{ + fprintf(f,"<PRE>\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,"</PRE>\n"); +} + +/* 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 <H2> </H2> for now. + * + * body text: Format this between <PRE> </PRE> 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 + + 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 + + /* do the html header first */ + write_html_header( f, node->filename, node->nodename ); + + /* now for the body */ + start_html_content( f ); + + /* make an anchor */ + escaped_nodename = escape_html_chars( node->nodename ); + map_spaces_to_underscores( escaped_nodename ); + fprintf(f, "<A name=\"%s\">\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,"<H1> Main Info File Directory </H1>\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 ); + + fprintf(f,"</BODY>\n</HTML>\n"); + + /* 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, "<PRE>\n"); +} + +void close_body_text_html( FILE *f ) +{ + fprintf(f, "</PRE>\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 *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); + + /* write out stuff up to Note */ + fwrite(p, 1, note_ptr - p, f); + fprintf(f, "<STRONG>"); + fwrite(note_ptr, 1, match1 - note_ptr, f); + fprintf(f, " </STRONG>"); + + /* 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,"<A HREF=\"../%s/%s.html\">", reffile, converted_nodename); +#endif + href = form_info_tag_href(reffile, converted_nodename); + fprintf(f,"<A %s>", href); + for (ptr=escaped_refname; *ptr; ptr++) + if (*ptr == '\n') + { + fprintf(f,"</A>\n"); + fprintf(f,"<A %s>", href); + } + else + fprintf(f,"%c", *ptr); + + if (strcmp(refname, refnode)) + { + fprintf(f,": "); + for (ptr=escaped_refnode; *ptr; ptr++) + if (*ptr == '\n') + { + fprintf(f,"</A>\n"); + fprintf(f,"<A %s>", href); + } + else + fprintf(f,"%c", *ptr); + + fprintf(f,"</A>"); + if (end > q && !(strchr(refnode, '\n'))) + fprintf(f,"\n"); + } + else + fprintf(f,"</A>"); + + 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(refname); + g_free(reffile); + g_free(refnode); + + /* write out stuff at end */ + if (end < q) + { + fwrite(end+1, 1, q - end, f); + return NULL; + } + else + return end+1; + } + else + { + fwrite(p, 1, q-p+1, f); + /* not needed any more */ + g_free(tmp); + return NULL; + } +} + +void open_menu_html( FILE *f, char *p ) +{ + if (*p != '\000') + fprintf(f, "<H2>%s</H2>\n",p); + /* fprintf(f, "<UL>\n"); */ + fprintf(f, "<dl>\n"); +} + +void close_menu_html( FILE *f ) +{ + /* fprintf(f, "</UL>\n"); */ + fprintf(f, "</dl>\n"); +} + +/* 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 (!isblank(*(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,"<dt><A HREF=\"../%s/%s.html\">%s</A>\n", + reffile, converted_nodename, escaped_refname); +#endif + href = form_info_tag_href( reffile, converted_nodename ); + fprintf(f,"<dt><A %s>%s</A>\n", href, escaped_refname ); + fprintf(f,"<dd>"); + if (*end == '.' && *(end+1) == '\n') + fprintf(f,"%s.\n",escaped_refnode); + else + fwrite(end+1, 1, *menu_end - end - 1, f); + + 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, "<HR>\n"); +} + |