/*
- * info backend for Halibut
+ * Info backend for Halibut
+ *
+ * The Info file format isn't well-specified, and what specification
+ * there is is scattered all over the place. Sources include:
+ * (info), from GNU Texinfo.
+ * (texinfo), also from GNU Texinfo.
+ * (Emacs)Misc Help, and (emacs)Info Lookup, from GNU Emacs.
+ * info.el, from GNU Emacs.
*
* Possible future work:
*
*
* - might be helpful to diagnose duplicate node names!
*
- * - more flexibility in heading underlines, like text backend.
- * + Given info.el's fontifier, we'd want the following defaults:
- * \cfg{info-title-underline}{*}
- * \cfg{info-chapter-underline}{=}
- * \cfg{info-section-underline}{0}{-}
- * \cfg{info-section-underline}{1}{.}
- *
* - Indices generated by makeinfo use a menu rather than a bunch of
* cross-references, which reduces visual clutter rather. For
* singly-referenced items, it looks like:
* make things slightly less ugly by using the lower-case version
* when the user asks for \k. Unfortunately, standalone Info seems
* to match node names case-sensitively, so we can't downcase that.
+ *
+ * - The character encoding used in an Info file can be configured using
+ * an Emacs local variables block at the end, like this:
+ * Local Variables:
+ * coding: iso-8859-1
+ * End:
*/
#include <stdio.h>
#include "halibut.h"
typedef struct {
+ wchar_t *underline;
+} alignstruct;
+
+typedef struct {
char *filename;
int maxfilesize;
int charset;
int listindentbefore, listindentafter;
int indent_code, width, index_width;
+ alignstruct atitle, achapter, *asect;
+ int nasect;
wchar_t *bullet, *listsuffix;
wchar_t *startemph, *endemph;
wchar_t *lquote, *rquote;
- wchar_t *sectsuffix, *underline;
+ wchar_t *sectsuffix;
wchar_t *rule;
wchar_t *index_text;
} infoconfig;
static int info_rdaddc(info_data *, char);
static int info_rdaddsc(info_data *, char const *);
-static void info_heading(info_data *, word *, word *, int, infoconfig *);
+static void info_heading(info_data *, word *, word *, alignstruct, int,
+ infoconfig *);
static void info_rule(info_data *, int, int, infoconfig *);
static void info_para(info_data *, word *, wchar_t *, word *, keywordlist *,
int, int, int, infoconfig *);
static infoconfig info_configure(paragraph *source) {
infoconfig ret;
paragraph *p;
+ int n;
/*
* Defaults.
ret.lquote = L"\x2018\0\x2019\0`\0'\0\0";
ret.rquote = uadv(ret.lquote);
ret.sectsuffix = L": ";
- ret.underline = L"\x203E\0-\0\0";
+ /*
+ * Default underline characters are chosen to match those recognised by
+ * Info-fontify-node.
+ */
+ ret.atitle.underline = L"*\0\0";
+ ret.achapter.underline = L"=\0\0";
+ ret.nasect = 2;
+ ret.asect = snewn(ret.nasect, alignstruct);
+ ret.asect[0].underline = L"-\0\0";
+ ret.asect[1].underline = L".\0\0";
ret.index_text = L"Index";
/*
} else if (!ustricmp(p->keyword, L"info-section-suffix")) {
ret.sectsuffix = uadv(p->keyword);
} else if (!ustricmp(p->keyword, L"info-underline")) {
- ret.underline = uadv(p->keyword);
+ ret.atitle.underline = ret.achapter.underline =
+ uadv(p->keyword);
+ for (n = 0; n < ret.nasect; n++)
+ ret.asect[n].underline = ret.atitle.underline;
+ } else if (!ustricmp(p->keyword, L"info-chapter-underline")) {
+ ret.achapter.underline = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"info-section-underline")) {
+ wchar_t *q = uadv(p->keyword);
+ int n = 0;
+ if (uisdigit(*q)) {
+ n = utoi(q);
+ q = uadv(q);
+ }
+ if (n >= ret.nasect) {
+ int i;
+ ret.asect = sresize(ret.asect, n+1, alignstruct);
+ for (i = ret.nasect; i <= n; i++)
+ ret.asect[i] = ret.asect[ret.nasect-1];
+ ret.nasect = n+1;
+ }
+ ret.asect[n].underline = q;
+ } else if (!ustricmp(p->keyword, L"text-title-underline")) {
+ ret.atitle.underline = uadv(p->keyword);
} else if (!ustricmp(p->keyword, L"info-bullet")) {
ret.bullet = uadv(p->keyword);
} else if (!ustricmp(p->keyword, L"info-rule")) {
ret.endemph = uadv(ret.startemph);
}
- while (*ret.underline && *uadv(ret.underline) &&
- !cvt_ok(ret.charset, ret.underline))
- ret.underline = uadv(ret.underline);
-
+ while (*ret.atitle.underline && *uadv(ret.atitle.underline) &&
+ !cvt_ok(ret.charset, ret.atitle.underline))
+ ret.atitle.underline = uadv(ret.atitle.underline);
+
+ while (*ret.achapter.underline && *uadv(ret.achapter.underline) &&
+ !cvt_ok(ret.charset, ret.achapter.underline))
+ ret.achapter.underline = uadv(ret.achapter.underline);
+
+ for (n = 0; n < ret.nasect; n++) {
+ while (*ret.asect[n].underline && *uadv(ret.asect[n].underline) &&
+ !cvt_ok(ret.charset, ret.asect[n].underline))
+ ret.asect[n].underline = uadv(ret.asect[n].underline);
+ }
+
while (*ret.bullet && *uadv(ret.bullet) &&
!cvt_ok(ret.charset, ret.bullet))
ret.bullet = uadv(ret.bullet);
/* Do the title */
for (p = sourceform; p; p = p->next)
if (p->type == para_Title)
- info_heading(&topnode->text, NULL, p->words, conf.width, &conf);
+ info_heading(&topnode->text, NULL, p->words,
+ conf.atitle, conf.width, &conf);
nestindent = conf.listindentbefore + conf.listindentafter;
nesting = 0;
info_menu_item(&currnode->up->text, currnode, p, &conf);
has_index |= info_check_index(p->words, currnode, idx);
- info_heading(&currnode->text, p->kwtext, p->words, conf.width, &conf);
+ if (p->type == para_Chapter || p->type == para_Appendix ||
+ p->type == para_UnnumberedChapter)
+ info_heading(&currnode->text, p->kwtext, p->words,
+ conf.achapter, conf.width, &conf);
+ else
+ info_heading(&currnode->text, p->kwtext, p->words,
+ conf.asect[p->aux>=conf.nasect?conf.nasect-1:p->aux],
+ conf.width, &conf);
nesting = 0;
break;
k = info_rdadds(&newnode->text, conf.index_text);
info_rdaddsc(&newnode->text, "\n");
while (k > 0) {
- info_rdadds(&newnode->text, conf.underline);
- k -= ustrwid(conf.underline, conf.charset);
+ info_rdadds(&newnode->text, conf.achapter.underline);
+ k -= ustrwid(conf.achapter.underline, conf.charset);
}
info_rdaddsc(&newnode->text, "\n\n");
}
static void info_heading(info_data *text, word *tprefix,
- word *words, int width, infoconfig *cfg) {
+ word *words, alignstruct align,
+ int width, infoconfig *cfg) {
int length;
int firstlinewidth, wrapwidth;
wrappedline *wrapping, *p;
for (p = wrapping; p; p = p->next) {
length += info_rdaddwc(text, p->begin, p->end, FALSE, cfg);
info_rdadd(text, L'\n');
- while (length > 0) {
- info_rdadds(text, cfg->underline);
- length -= ustrwid(cfg->underline, cfg->charset);
+ if (*align.underline) {
+ while (length > 0) {
+ info_rdadds(text, align.underline);
+ length -= ustrwid(align.underline, cfg->charset);
+ }
+ info_rdadd(text, L'\n');
}
- info_rdadd(text, L'\n');
length = 0;
}
wrap_free(wrapping);