Initial work on PS and PDF output. Because these two backends share
[sgt/halibut] / bk_whlp.c
index 91b07c1..9655b1f 100644 (file)
--- a/bk_whlp.c
+++ b/bk_whlp.c
@@ -1,12 +1,10 @@
 /*
  * Windows Help backend for Halibut
- * 
- * TODO:
- *  - allow user to specify section contexts.
  */
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <ctype.h>
 #include <assert.h>
 
 #include "halibut.h"
@@ -45,8 +43,36 @@ static void whlp_navmenu(struct bk_whlp_state *state, paragraph *p);
 static void whlp_contents_write(struct bk_whlp_state *state,
                                int level, char *text, WHLP_TOPIC topic);
     
+paragraph *whlp_config_filename(char *filename)
+{
+    paragraph *p;
+    wchar_t *ufilename, *up;
+    int len;
+
+    p = mknew(paragraph);
+    memset(p, 0, sizeof(*p));
+    p->type = para_Config;
+    p->next = NULL;
+    p->fpos.filename = "<command line>";
+    p->fpos.line = p->fpos.col = -1;
+
+    ufilename = ufroma_dup(filename);
+    len = ustrlen(ufilename) + 2 + lenof(L"winhelp-filename");
+    p->keyword = mknewa(wchar_t, len);
+    up = p->keyword;
+    ustrcpy(up, L"winhelp-filename");
+    up = uadv(up);
+    ustrcpy(up, ufilename);
+    up = uadv(up);
+    *up = L'\0';
+    assert(up - p->keyword < len);
+    sfree(ufilename);
+
+    return p;
+}
+
 void whlp_backend(paragraph *sourceform, keywordlist *keywords,
-                 indexdata *idx) {
+                 indexdata *idx, void *unused) {
     WHLP h;
     char *filename, *cntname;
     paragraph *p, *lastsect;
@@ -55,12 +81,9 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
     int i;
     int nesting;
     indexentry *ie;
+    int done_contents_topic = FALSE;
 
-    filename = "output.hlp";          /* FIXME: configurability */
-    cntname = "output.cnt";           /* corresponding contents file */
-
-    state.cntfp = fopen(cntname, "wb");
-    state.cnt_last_level = -1; state.cnt_workaround = 0;
+    IGNORE(unused);
 
     h = state.h = whlp_new();
     state.keywords = keywords;
@@ -91,8 +114,10 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
 
     /*
      * Loop over the source form finding out whether the user has
-     * specified particular help topic names for anything.
+     * specified particular help topic names for anything. Also
+     * pick out the output file name at this stage.
      */
+    filename = dupstr("output.hlp");
     for (p = sourceform; p; p = p->next) {
        p->private_data = NULL;
        if (p->type == para_Config && p->parent) {
@@ -102,11 +127,39 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
                /* Store the topic name in the private_data field of the
                 * containing section. */
                p->parent->private_data = topicname;
+           } else if (!ustricmp(p->keyword, L"winhelp-filename")) {
+               sfree(filename);
+               filename = utoa_dup(uadv(p->keyword));
            }
        }
     }
 
     /*
+     * Ensure the output file name has a .hlp extension. This is
+     * required since we must create the .cnt file in parallel with
+     * it.
+     */
+    {
+       int len = strlen(filename);
+       if (len < 4 || filename[len-4] != '.' ||
+           tolower(filename[len-3] != 'h') ||
+           tolower(filename[len-2] != 'l') ||
+           tolower(filename[len-1] != 'p')) {
+           char *newf;
+           newf = mknewa(char, len + 5);
+           sprintf(newf, "%s.hlp", filename);
+           sfree(filename);
+           filename = newf;
+           len = strlen(newf);
+       }
+       cntname = mknewa(char, len);
+       sprintf(cntname, "%.*s.cnt", len-4, filename);
+    }
+
+    state.cntfp = fopen(cntname, "wb");
+    state.cnt_last_level = -1; state.cnt_workaround = 0;
+
+    /*
      * Loop over the source form registering WHLP_TOPICs for
      * everything.
      */
@@ -144,8 +197,7 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
     whlp_prepare(h);
 
     /* ------------------------------------------------------------------
-     * Do the contents page, containing title, preamble and
-     * copyright.
+     * Begin the contents page.
      */
 
     whlp_begin_topic(h, contents_topic, "Contents", "DB(\"btn_up\")", NULL);
@@ -174,32 +226,13 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
     }
 
     /*
-     * Next comes the preamble, which just goes into the ordinary
-     * scrolling region.
-     */
-    for (p = sourceform; p; p = p->next) {
-       if (p->type == para_Preamble) {
-           whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12);
-           whlp_begin_para(h, WHLP_PARA_SCROLL);
-           whlp_mkparagraph(&state, FONT_NORMAL, p->words, FALSE);
-           whlp_end_para(h);
-       }
-    }
-
-    /*
-     * The copyright goes to two places, again: into the contents
-     * page and also into the system section.
+     * Put the copyright into the system section.
      */
     {
        rdstringc rs = {0, 0, NULL};
        for (p = sourceform; p; p = p->next) {
-           if (p->type == para_Copyright) {
-               whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12);
-               whlp_begin_para(h, WHLP_PARA_SCROLL);
-               whlp_mkparagraph(&state, FONT_NORMAL, p->words, FALSE);
-               whlp_end_para(h);
+           if (p->type == para_Copyright)
                whlp_rdaddwc(&rs, p->words);
-           }
        }
        if (rs.text) {
            whlp_copyright(h, rs.text);
@@ -207,17 +240,6 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
        }
     }
 
-    /*
-     * Now do the primary navigation menu.
-     */
-    for (p = sourceform; p; p = p->next) {
-       if (p->type == para_Chapter ||
-           p->type == para_Appendix ||
-           p->type == para_UnnumberedChapter)
-           whlp_navmenu(&state, p);
-    }
-
-    state.curr_topic = contents_topic;
     lastsect = NULL;
 
     /* ------------------------------------------------------------------
@@ -234,8 +256,6 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
       case para_BR:
       case para_Biblio:                       /* only touch BiblioCited */
       case para_VersionID:
-      case para_Copyright:
-      case para_Preamble:
       case para_NoCite:
       case para_Title:
        break;
@@ -258,6 +278,28 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
       case para_UnnumberedChapter:
       case para_Heading:
       case para_Subsect:
+
+       if (!done_contents_topic) {
+           paragraph *p;
+
+           /*
+            * If this is the first section title we've seen, then
+            * we're currently still in the contents topic. We
+            * should therefore finish up the contents page by
+            * writing a nav menu.
+            */
+           for (p = sourceform; p; p = p->next) {
+               if (p->type == para_Chapter ||
+                   p->type == para_Appendix ||
+                   p->type == para_UnnumberedChapter)
+                   whlp_navmenu(&state, p);
+           }
+
+           state.curr_topic = contents_topic;
+
+           done_contents_topic = TRUE;
+       }
+
        if (lastsect && lastsect->child) {
            paragraph *q;
            /*
@@ -362,6 +404,7 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
        break;
 
       case para_Normal:
+      case para_Copyright:
       case para_DescribedThing:
       case para_Description:
       case para_BiblioCited:
@@ -458,6 +501,9 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords,
     for (i = 0; (ie = index234(idx->entries, i)) != NULL; i++) {
        sfree(ie->backend_data);
     }
+
+    sfree(filename);
+    sfree(cntname);
 }
 
 static void whlp_contents_write(struct bk_whlp_state *state,