Include libcharset into both the Timber and Halibut checkouts.
[sgt/halibut] / bk_info.c
index 088c72d..0d7c032 100644 (file)
--- a/bk_info.c
+++ b/bk_info.c
@@ -1,17 +1,28 @@
 /*
  * info backend for Halibut
  * 
- * TODO:
+ * Possible future work:
  * 
- *  - basic vital configuration: Info dir entries in heading, and
- *    how to allocate node names
- *  - escape, warn or simply remove commas and colons in node
- *    names; also test colons in index terms.
- *  - test everything in info(1), and probably jed too
+ *  - configurable indentation, bullets, emphasis, quotes etc?
  * 
- * Later:
+ *  - configurable choice of how to allocate node names?
+ *     + possibly a template-like approach, choosing node names to
+ *      be the full section title or perhaps the internal keyword?
+ *     + neither of those seems quite right. Perhaps instead a
+ *      Windows Help-like mechanism, where a magic config
+ *      directive allows user choice of name for every node.
+ *     + Only trouble with that is, now what happens to the section
+ *      numbers? Do they become completely vestigial and just sit
+ *      in the title text of each node? Or do we keep them in the
+ *      menus somehow? I think people might occasionally want to
+ *      go to a section by number, if only because all the _other_
+ *      formats of the same document will reference the numbers
+ *      all the time. So our menu lines could look like one of
+ *      these:
+ *        * Nodename: Section 1.2. Title of section.
+ *        * Section 1.2: Nodename. Title of section.
  * 
- *  - configurable indentation, bullets, emphasis, quotes etc?
+ *  - might be helpful to diagnose duplicate node names!
  */
 
 #include <stdio.h>
@@ -108,7 +119,7 @@ paragraph *info_config_filename(char *filename)
 }
 
 void info_backend(paragraph *sourceform, keywordlist *keywords,
-                 indexdata *idx) {
+                 indexdata *idx, void *unused) {
     paragraph *p;
     infoconfig conf;
     word *prefix, *body, *wp;
@@ -129,8 +140,7 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
     int width = 70, listindentbefore = 1, listindentafter = 3;
     int indent_code = 2, index_width = 40;
 
-    IGNORE(keywords);                 /* we don't happen to need this */
-    IGNORE(idx);                      /* or this */
+    IGNORE(unused);
 
     conf = info_configure(sourceform);
 
@@ -189,9 +199,7 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
            ii->nodes = NULL;
 
            info_rdaddwc(&rs, entry->text, NULL, FALSE);
-           /*
-            * FIXME: splatter colons.
-            */
+
            ii->text = rs.text;
 
            entry->backend_data = ii;
@@ -201,10 +209,8 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
     /*
      * An Info file begins with a piece of introductory text which
      * is apparently never shown anywhere. This seems to me to be a
-     * good place to put the copyright notice and the version IDs.
-     * 
-     * FIXME: also Info directory entries are expected to go here.
-     * This will need to be a configurable thing of some sort.
+     * good place to put the copyright notice and the version IDs. 
+     * Also, Info directory entries are expected to go here.
      */
 
     rdaddsc(&intro_text,
@@ -213,6 +219,51 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
     rdaddsc(&intro_text, "\n\n");
 
     for (p = sourceform; p; p = p->next)
+       if (p->type == para_Config &&
+           !ustricmp(p->keyword, L"info-dir-entry")) {
+           wchar_t *section, *shortname, *longname, *kw;
+           char *s;
+
+           section = uadv(p->keyword);
+           shortname = *section ? uadv(section) : NULL;
+           longname = *shortname ? uadv(shortname) : NULL;
+           kw = *longname ? uadv(longname) : NULL;
+
+           if (!*longname) {
+               error(err_infodirentry, &p->fpos);
+               continue;
+           }
+
+           rdaddsc(&intro_text, "INFO-DIR-SECTION ");
+           s = utoa_dup(section);
+           rdaddsc(&intro_text, s);
+           sfree(s);
+           rdaddsc(&intro_text, "\nSTART-INFO-DIR-ENTRY\n* ");
+           s = utoa_dup(shortname);
+           rdaddsc(&intro_text, s);
+           sfree(s);
+           rdaddsc(&intro_text, ": (");
+           s = dupstr(conf.filename);
+           if (strlen(s) > 5 && !strcmp(s+strlen(s)-5, ".info"))
+               s[strlen(s)-5] = '\0';
+           rdaddsc(&intro_text, s);
+           sfree(s);
+           rdaddsc(&intro_text, ")");
+           if (*kw) {
+               keyword *kwl = kw_lookup(keywords, kw);
+               if (kwl && kwl->para->private_data) {
+                   node *n = (node *)kwl->para->private_data;
+                   rdaddsc(&intro_text, n->name);
+               }
+           }
+           rdaddsc(&intro_text, ".   ");
+           s = utoa_dup(longname);
+           rdaddsc(&intro_text, s);
+           sfree(s);
+           rdaddsc(&intro_text, "\nEND-INFO-DIR-ENTRY\n\n");
+       }
+
+    for (p = sourceform; p; p = p->next)
        if (p->type == para_Copyright)
            info_para(&intro_text, NULL, NULL, p->words, keywords,
                      0, 0, width);
@@ -367,7 +418,7 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
        newnode->prev = currnode;
        currnode->listnext = newnode;
 
-       rdaddsc(&newnode->text, "Index\n-----\n\n* Menu:\n\n");
+       rdaddsc(&newnode->text, "Index\n-----\n\n");
 
        info_menu_item(&topnode->text, newnode, NULL);
 
@@ -376,7 +427,6 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
 
            for (j = 0; j < ii->nnodes; j++) {
                int pos0 = newnode->text.pos;
-               rdaddsc(&newnode->text, "* ");
                /*
                 * When we have multiple references for a single
                 * index term, we only display the actual term on
@@ -387,9 +437,9 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
                    rdaddsc(&newnode->text, ii->text);
                for (k = newnode->text.pos - pos0; k < index_width; k++)
                    rdaddc(&newnode->text, ' ');
-               rdaddsc(&newnode->text, ": ");
+               rdaddsc(&newnode->text, "   *Note ");
                rdaddsc(&newnode->text, ii->nodes[j]->name);
-               rdaddsc(&newnode->text, ".\n");
+               rdaddsc(&newnode->text, "::\n");
            }
        }
     }
@@ -788,12 +838,14 @@ static int info_width_internal(word *words, int xrefs) {
     return 0;                         /* should never happen */
 }
 
-static int info_width_noxrefs(word *words)
+static int info_width_noxrefs(void *ctx, word *words)
 {
+    IGNORE(ctx);
     return info_width_internal(words, FALSE);
 }
-static int info_width_xrefs(word *words)
+static int info_width_xrefs(void *ctx, word *words)
 {
+    IGNORE(ctx);
     return info_width_internal(words, TRUE);
 }
 
@@ -815,7 +867,8 @@ static void info_heading(rdstringc *text, word *tprefix,
     firstlinewidth = width - length;
     wrapwidth = width;
 
-    wrapping = wrap_para(words, firstlinewidth, wrapwidth, info_width_noxrefs);
+    wrapping = wrap_para(words, firstlinewidth, wrapwidth,
+                        info_width_noxrefs, NULL, 0);
     for (p = wrapping; p; p = p->next) {
        info_rdaddwc(&t, p->begin, p->end, FALSE);
        length = (t.text ? strlen(t.text) : 0);
@@ -879,7 +932,8 @@ static void info_para(rdstringc *text, word *prefix, char *prefixextra,
     } else
        e = indent + extraindent;
 
-    wrapping = wrap_para(words, firstlinewidth, width, info_width_xrefs);
+    wrapping = wrap_para(words, firstlinewidth, width, info_width_xrefs,
+                        NULL, 0);
     for (p = wrapping; p; p = p->next) {
        for (i = 0; i < e; i++)
            rdaddc(text, ' ');
@@ -933,10 +987,27 @@ static node *info_node_new(char *name)
     return n;
 }
 
-static char *info_node_name(paragraph *p)
+static char *info_node_name(paragraph *par)
 {
     rdstringc rsc = { 0, 0, NULL };
-    info_rdaddwc(&rsc, p->kwtext ? p->kwtext : p->words, NULL, FALSE);
+    char *p, *q;
+    info_rdaddwc(&rsc, par->kwtext ? par->kwtext : par->words, NULL, FALSE);
+
+    /*
+     * We cannot have commas or colons in a node name. Remove any
+     * that we find, with a warning.
+     */
+    p = q = rsc.text;
+    while (*p) {
+       if (*p == ':' || *p == ',') {
+           error(err_infonodechar, &par->fpos, *p);
+       } else {
+           *q++ = *p;
+       }
+       p++;
+    }
+    *p = '\0';
+
     return rsc.text;
 }