Ben Hutchings points out that `.UC', which I think I must have
[sgt/halibut] / bk_man.c
index b2db5bb..553b2dd 100644 (file)
--- a/bk_man.c
+++ b/bk_man.c
@@ -42,7 +42,7 @@ static manconfig man_configure(paragraph *source) {
     /*
      * Two-pass configuration so that we can pick up global config
      * (e.g. `quotes') before having it overridden by specific
-     * config (`text-quotes'), irrespective of the order in which
+     * config (`man-quotes'), irrespective of the order in which
      * they occur.
      */
     for (p = source; p; p = p->next) {
@@ -69,9 +69,7 @@ static manconfig man_configure(paragraph *source) {
                ret.th = snewn(ep - wp + 1, wchar_t);
                memcpy(ret.th, wp, (ep - wp + 1) * sizeof(wchar_t));
            } else if (!ustricmp(p->keyword, L"man-charset")) {
-               char *csname = utoa_dup(uadv(p->keyword), CS_ASCII);
-               ret.charset = charset_from_localenc(csname);
-               sfree(csname);
+               ret.charset = charset_from_ustr(&p->fpos, uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"man-headnumbers")) {
                ret.headnumbers = utob(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"man-mindepth")) {
@@ -81,7 +79,7 @@ static manconfig man_configure(paragraph *source) {
                ret.filename = dupstr(adv(p->origkeyword));
            } else if (!ustricmp(p->keyword, L"man-bullet")) {
                ret.bullet = uadv(p->keyword);
-           } else if (!ustricmp(p->keyword, L"text-quotes")) {
+           } else if (!ustricmp(p->keyword, L"man-quotes")) {
                if (*uadv(p->keyword) && *uadv(uadv(p->keyword))) {
                    ret.lquote = uadv(p->keyword);
                    ret.rquote = uadv(ret.lquote);
@@ -126,6 +124,7 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
     paragraph *p;
     FILE *fp;
     manconfig conf;
+    int had_described_thing;
 
     IGNORE(unused);
     IGNORE(keywords);
@@ -165,7 +164,12 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
     }
     fputc('\n', fp);
 
-    fprintf(fp, ".UC\n");
+    had_described_thing = FALSE;
+#define cleanup_described_thing do { \
+    if (had_described_thing) \
+       fprintf(fp, "\n"); \
+    had_described_thing = FALSE; \
+} while (0)
 
     for (p = sourceform; p; p = p->next) switch (p->type) {
        /*
@@ -189,16 +193,20 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
       case para_Heading:
       case para_Subsect:
 
+       cleanup_described_thing;
        {
            int depth;
            if (p->type == para_Subsect)
-               depth = p->aux + 2;
+               depth = p->aux + 1;
            else if (p->type == para_Heading)
                depth = 1;
            else
                depth = 0;
            if (depth >= conf.mindepth) {
-               fprintf(fp, ".SH \"");
+               if (depth > conf.mindepth)
+                   fprintf(fp, ".SS \"");
+               else
+                   fprintf(fp, ".SH \"");
                if (conf.headnumbers && p->kwtext) {
                    man_text(fp, p->kwtext, FALSE, QUOTE_QUOTES, &conf);
                    fprintf(fp, " ");
@@ -213,6 +221,7 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
         * Code paragraphs.
         */
       case para_Code:
+       cleanup_described_thing;
        fprintf(fp, ".PP\n");
        man_codepara(fp, p->words, conf.charset);
        break;
@@ -222,6 +231,7 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
         */
       case para_Normal:
       case para_Copyright:
+       cleanup_described_thing;
        fprintf(fp, ".PP\n");
        man_text(fp, p->words, TRUE, 0, &conf);
        break;
@@ -233,6 +243,9 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
       case para_BiblioCited:
       case para_Bullet:
       case para_NumberedList:
+       if (p->type != para_Description)
+           cleanup_described_thing;
+
        if (p->type == para_Bullet) {
            char *bullettext;
            man_convert(conf.bullet, -1, &bullettext, QUOTE_QUOTES,
@@ -244,22 +257,34 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
            man_text(fp, p->kwtext, FALSE, QUOTE_QUOTES, &conf);
            fprintf(fp, "\"\n");
        } else if (p->type == para_Description) {
-           /*
-            * Do nothing; the .xP for this paragraph is the .IP
-            * which has come before it in the DescribedThing.
-            */
+           if (had_described_thing) {
+               /*
+                * Do nothing; the .xP for this paragraph is the
+                * .IP which has come before it in the
+                * DescribedThing.
+                */
+           } else {
+               /*
+                * A \dd without a preceding \dt is given a blank
+                * one.
+                */
+               fprintf(fp, ".IP \"\"\n");
+           }
        } else if (p->type == para_BiblioCited) {
            fprintf(fp, ".IP \"");
            man_text(fp, p->kwtext, FALSE, QUOTE_QUOTES, &conf);
            fprintf(fp, "\"\n");
        }
        man_text(fp, p->words, TRUE, 0, &conf);
+       had_described_thing = FALSE;
        break;
 
       case para_DescribedThing:
+       cleanup_described_thing;
        fprintf(fp, ".IP \"");
        man_text(fp, p->words, FALSE, QUOTE_QUOTES, &conf);
        fprintf(fp, "\"\n");
+       had_described_thing = TRUE;
        break;
 
       case para_Rule:
@@ -267,18 +292,22 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
         * This isn't terribly good. Anyone who wants to do better
         * should feel free!
         */
+       cleanup_described_thing;
        fprintf(fp, ".PP\n----------------------------------------\n");
        break;
 
       case para_LcontPush:
       case para_QuotePush:
+       cleanup_described_thing;
        fprintf(fp, ".RS\n");
        break;
       case para_LcontPop:
       case para_QuotePop:
+       cleanup_described_thing;
        fprintf(fp, ".RE\n");
        break;
     }
+    cleanup_described_thing;
 
     /*
      * Tidy up.
@@ -378,9 +407,9 @@ static int man_convert(wchar_t const *s, int maxlen,
     return !err;
 }
 
-static void man_rdaddwc(rdstringc *rs, word *text, word *end,
-                       int quote_props, manconfig *conf,
-                       charset_state *state) {
+static int man_rdaddwc(rdstringc *rs, word *text, word *end,
+                      int quote_props, manconfig *conf,
+                      charset_state *state) {
     char *c;
 
     for (; text && text != end; text = text->next) switch (text->type) {
@@ -410,10 +439,10 @@ static void man_rdaddwc(rdstringc *rs, word *text, word *end,
        if (towordstyle(text->type) == word_Emph &&
            (attraux(text->aux) == attr_First ||
             attraux(text->aux) == attr_Only)) {
-           if (rs->pos > 0)
-               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            man_convert(NULL, 0, &c, quote_props, conf->charset, state);
            rdaddsc(rs, c);
+           if (*c)
+               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            sfree(c);
            *state = charset_init_state;
            rdaddsc(rs, "\\fI");
@@ -421,10 +450,10 @@ static void man_rdaddwc(rdstringc *rs, word *text, word *end,
                    towordstyle(text->type) == word_WeakCode) &&
                   (attraux(text->aux) == attr_First ||
                    attraux(text->aux) == attr_Only)) {
-           if (rs->pos > 0)
-               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            man_convert(NULL, 0, &c, quote_props, conf->charset, state);
            rdaddsc(rs, c);
+           if (*c)
+               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            sfree(c);
            *state = charset_init_state;
            rdaddsc(rs, "\\fB");
@@ -433,38 +462,39 @@ static void man_rdaddwc(rdstringc *rs, word *text, word *end,
        if (removeattr(text->type) == word_Normal) {
            charset_state s2 = *state;
 
-           if (rs->pos > 0)
-               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            if (man_convert(text->text, 0, &c, quote_props, conf->charset, &s2) ||
                !text->alt) {
                rdaddsc(rs, c);
+               if (*c)
+                   quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
                *state = s2;
            } else {
-               man_rdaddwc(rs, text->alt, NULL, quote_props, conf, state);
+               quote_props = man_rdaddwc(rs, text->alt, NULL,
+                                         quote_props, conf, state);
            }
            sfree(c);
        } else if (removeattr(text->type) == word_WhiteSpace) {
-           if (rs->pos > 0)
-               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            man_convert(L" ", 1, &c, quote_props, conf->charset, state);
            rdaddsc(rs, c);
+           if (*c)
+               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            sfree(c);
        } else if (removeattr(text->type) == word_Quote) {
-           if (rs->pos > 0)
-               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            man_convert(quoteaux(text->aux) == quote_Open ?
                        conf->lquote : conf->rquote, 0,
                        &c, quote_props, conf->charset, state);
            rdaddsc(rs, c);
+           if (*c)
+               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            sfree(c);
        }
        if (towordstyle(text->type) != word_Normal &&
            (attraux(text->aux) == attr_Last ||
             attraux(text->aux) == attr_Only)) {
-           if (rs->pos > 0)
-               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            man_convert(NULL, 0, &c, quote_props, conf->charset, state);
            rdaddsc(rs, c);
+           if (*c)
+               quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
            sfree(c);
            *state = charset_init_state;
            rdaddsc(rs, "\\fP");
@@ -473,7 +503,11 @@ static void man_rdaddwc(rdstringc *rs, word *text, word *end,
     }
     man_convert(NULL, 0, &c, quote_props, conf->charset, state);
     rdaddsc(rs, c);
+    if (*c)
+       quote_props &= ~QUOTE_INITCTRL;   /* not at start any more */
     sfree(c);
+
+    return quote_props;
 }
 
 static void man_text(FILE *fp, word *text, int newline,