Revamp of the Halibut error handling mechanism.
[sgt/halibut] / bk_man.c
index 204d145..44f159f 100644 (file)
--- a/bk_man.c
+++ b/bk_man.c
@@ -217,7 +217,7 @@ paragraph *man_config_filename(char *filename)
 
 #define QUOTE_INITCTRL    1 /* quote initial . and ' on a line */
 #define QUOTE_QUOTES      2 /* quote double quotes by doubling them */
-#define QUOTE_LITHYPHENS  4 /* don't convert hyphens into \(hy */
+#define QUOTE_LITERAL     4 /* defeat special meaning of `, ', - in troff */
 
 void man_backend(paragraph *sourceform, keywordlist *keywords,
                 indexdata *idx, void *unused) {
@@ -235,9 +235,12 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
     /*
      * Open the output file.
      */
-    fp = fopen(conf.filename, "w");
+    if (!strcmp(conf.filename, "-"))
+       fp = stdout;
+    else
+       fp = fopen(conf.filename, "w");
     if (!fp) {
-       error(err_cantopenw, conf.filename);
+       err_cantopenw(conf.filename);
        return;
     }
 
@@ -248,6 +251,12 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
            man_text(fp, p->words, TRUE, 0, &conf);
        }
 
+    /* Standard preamble */
+    /* Dodge to try to get literal U+0027 in output when required,
+     * bypassing groff's Unicode transform; pinched from pod2man */
+    fprintf(fp, ".ie \\n(.g .ds Aq \\(aq\n"
+               ".el       .ds Aq '\n");
+
     /* .TH name-of-program manual-section */
     fprintf(fp, ".TH");
     if (conf.th && *conf.th) {
@@ -419,7 +428,8 @@ void man_backend(paragraph *sourceform, keywordlist *keywords,
     /*
      * Tidy up.
      */
-    fclose(fp);
+    if (fp != stdout)
+       fclose(fp);
     man_conf_cleanup(conf);
 }
 
@@ -476,16 +486,35 @@ static int man_convert(wchar_t const *s, int maxlen,
                 */
                rdaddc(&out, '\\');
                rdaddc(&out, '&');
-           } else if (*q == '`' || *q == ' ') {
+           }
+           if (*q == '`' || *q == ' ') {
                /* Quote backticks and nonbreakable spaces always. */
                rdaddc(&out, '\\');
            } else if (*q == '\\') {
                /* Turn backslashes into \e. */
                rdaddsc(&out, "\\e");
                continue;
-           } else if (*q == '-' && !(quote_props & QUOTE_LITHYPHENS)) {
-               /* Turn nonbreakable hyphens into \(hy. */
-               rdaddsc(&out, "\\(hy");
+           } else if (*q == '-') {
+               if (quote_props & QUOTE_LITERAL) {
+                   /*
+                    * Try to preserve literal U+002D.
+                    * This is quite awkward. Debian hacks groff so that
+                    * \- and - both produce it; elsewhere it's not necessarily
+                    * possible to get it.
+                    * Apparently \- is the preferred compromise despite
+                    * having minus-sign semantics, as it is non-breaking.
+                    * (pod2man uses it, anyway.)
+                    */
+                   rdaddc(&out, '\\');
+               } else {
+                   /* Turn nonbreakable hyphens into \(hy. */
+                   rdaddsc(&out, "\\(hy");
+                   continue;
+               }
+           } else if (*q == '\'' && (quote_props & QUOTE_LITERAL)) {
+               /* Try to preserve literal U+0027 (using string defined
+                * in preamble) */
+               rdaddsc(&out, "\\*(Aq"); /* "apostrophe quote" */
                continue;
            } else if (*q == '"' && (quote_props & QUOTE_QUOTES)) {
                /*
@@ -587,7 +616,7 @@ static int man_rdaddwc(rdstringc *rs, word *text, word *end,
 
        if (towordstyle(text->type) == word_Code ||
            towordstyle(text->type) == word_WeakCode)
-           quote_props |= QUOTE_LITHYPHENS;
+           quote_props |= QUOTE_LITERAL;
 
        if (removeattr(text->type) == word_Normal) {
            charset_state s2 = *state;
@@ -659,7 +688,7 @@ static void man_codepara(FILE *fp, word *text, int charset) {
     for (; text; text = text->next) if (text->type == word_WeakCode) {
        char *c;
        wchar_t *t, *e;
-       int quote_props = QUOTE_INITCTRL | QUOTE_LITHYPHENS;
+       int quote_props = QUOTE_INITCTRL | QUOTE_LITERAL;
 
        t = text->text;
        if (text->next && text->next->type == word_Emph) {