Info backend now takes care to avoid magic characters in node names
[sgt/halibut] / bk_info.c
index 088c72d..d4179f2 100644 (file)
--- a/bk_info.c
+++ b/bk_info.c
@@ -3,10 +3,8 @@
  * 
  * TODO:
  * 
- *  - 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.
+ *  - configurable choice of how to allocate node names
+ *  - might be helpful to diagnose duplicate node names!
  *  - test everything in info(1), and probably jed too
  * 
  * Later:
@@ -184,14 +182,28 @@ void info_backend(paragraph *sourceform, keywordlist *keywords,
        for (i = 0; (entry = index234(idx->entries, i)) != NULL; i++) {
            info_idx *ii = mknew(info_idx);
            rdstringc rs = { 0, 0, NULL };
+           char *p, *q;
 
            ii->nnodes = ii->nodesize = 0;
            ii->nodes = NULL;
 
            info_rdaddwc(&rs, entry->text, NULL, FALSE);
+
            /*
-            * FIXME: splatter colons.
+            * We cannot have colons in index terms, since they
+            * disrupt the structure of the index menu. Remove any
+            * that we find, with a warning.
             */
+           p = q = rs.text;
+           while (*p) {
+               if (*p == ':') {
+                   error(err_infoindexcolon, &entry->fpos);
+               } else {
+                   *q++ = *p;
+               }
+               p++;
+           }
+
            ii->text = rs.text;
 
            entry->backend_data = ii;
@@ -201,10 +213,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 +223,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);
@@ -933,10 +988,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;
 }