summaryrefslogtreecommitdiffstats
path: root/man_html.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2017-01-26 18:28:18 +0000
committerIngo Schwarze <schwarze@openbsd.org>2017-01-26 18:28:18 +0000
commit235ae1a6a0c472285b2c9310fe2e27c03a80393d (patch)
treeb17150962d8d551f194058cfd460dfe4b358985b /man_html.c
parent596fca22f9c5c89fa592c0edf80c10f94529b3a6 (diff)
downloadmandoc-235ae1a6a0c472285b2c9310fe2e27c03a80393d.tar.gz
Fix -man -Thtml formatting after .nf (which has nothing to do
with "literal", by the way, it means "no fill"): * Use <pre> such that whitespace is preserved. * Preserve lines breaks. * For font alternating macros, avoid node recursion which required scary juggling with the fill state. Instead, simply print the text children directly. Missing feature first noticed by kristaps@ in 2011, the again reported by afresh1@ in 2016, and finally reported here: https://github.com/Debian/debiman/issues/21 , which i only found because of Shane Kerr's comment here: https://plus.google.com/110314300533310775053/posts/H1eaw9Yskoc
Diffstat (limited to 'man_html.c')
-rw-r--r--man_html.c103
1 files changed, 46 insertions, 57 deletions
diff --git a/man_html.c b/man_html.c
index 54d26320..a5147e06 100644
--- a/man_html.c
+++ b/man_html.c
@@ -32,7 +32,6 @@
#include "html.h"
#include "main.h"
-/* TODO: preserve ident widths. */
/* FIXME: have PD set the default vspace width. */
#define INDENT 5
@@ -43,8 +42,7 @@
struct html *h
struct mhtml {
- int fl;
-#define MANH_LITERAL (1 << 0) /* literal context */
+ struct tag *nofill;
};
struct htmlman {
@@ -72,9 +70,9 @@ static int man_SS_pre(MAN_ARGS);
static int man_UR_pre(MAN_ARGS);
static int man_alt_pre(MAN_ARGS);
static int man_br_pre(MAN_ARGS);
+static int man_fill_pre(MAN_ARGS);
static int man_ign_pre(MAN_ARGS);
static int man_in_pre(MAN_ARGS);
-static int man_literal_pre(MAN_ARGS);
static void man_root_post(MAN_ARGS);
static void man_root_pre(MAN_ARGS);
@@ -101,8 +99,8 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_alt_pre, NULL }, /* IR */
{ man_alt_pre, NULL }, /* RI */
{ man_br_pre, NULL }, /* sp */
- { man_literal_pre, NULL }, /* nf */
- { man_literal_pre, NULL }, /* fi */
+ { man_fill_pre, NULL }, /* nf */
+ { man_fill_pre, NULL }, /* fi */
{ NULL, NULL }, /* RE */
{ man_RS_pre, NULL }, /* RS */
{ man_ign_pre, NULL }, /* DT */
@@ -112,8 +110,8 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_in_pre, NULL }, /* in */
{ man_ign_pre, NULL }, /* ft */
{ man_OP_pre, NULL }, /* OP */
- { man_literal_pre, NULL }, /* EX */
- { man_literal_pre, NULL }, /* EE */
+ { man_fill_pre, NULL }, /* EX */
+ { man_fill_pre, NULL }, /* EE */
{ man_UR_pre, NULL }, /* UR */
{ NULL, NULL }, /* UE */
{ man_ign_pre, NULL }, /* ll */
@@ -150,7 +148,7 @@ html_man(void *arg, const struct roff_man *man)
struct html *h;
struct tag *t;
- memset(&mh, 0, sizeof(mh));
+ mh.nofill = NULL;
h = (struct html *)arg;
if ((h->oflags & HTML_FRAGMENT) == 0) {
@@ -200,6 +198,8 @@ print_man_node(MAN_ARGS)
child = 1;
t = h->tags.head;
+ if (t == mh->nofill)
+ t = t->next;
switch (n->type) {
case ROFFT_TEXT:
@@ -207,12 +207,11 @@ print_man_node(MAN_ARGS)
print_paragraph(h);
return;
}
- if (n->flags & NODE_LINE && (*n->string == ' ' ||
- (n->prev != NULL && mh->fl & MANH_LITERAL &&
- ! (h->flags & HTML_NONEWLINE))))
+ if (mh->nofill == NULL &&
+ n->flags & NODE_LINE && *n->string == ' ')
print_otag(h, TAG_BR, "");
print_text(h, n->string);
- return;
+ break;
case ROFFT_EQN:
print_eqn(h, n->eqn);
break;
@@ -252,16 +251,15 @@ print_man_node(MAN_ARGS)
print_man_nodelist(man, n->child, mh, h);
/* This will automatically close out any font scope. */
- print_stagq(h, t);
+ print_stagq(h, mh->nofill == NULL ? t : mh->nofill);
- switch (n->type) {
- case ROFFT_EQN:
- break;
- default:
- if (mans[n->tok].post)
- (*mans[n->tok].post)(man, n, mh, h);
- break;
- }
+ if (n->type != ROFFT_TEXT && n->type != ROFFT_EQN &&
+ mans[n->tok].post != NULL)
+ (*mans[n->tok].post)(man, n, mh, h);
+
+ if (mh->nofill != NULL &&
+ (n->next == NULL || n->next->flags & NODE_LINE))
+ print_endline(h);
}
static int
@@ -349,13 +347,11 @@ man_br_pre(MAN_ARGS)
static int
man_SH_pre(MAN_ARGS)
{
- if (n->type == ROFFT_BLOCK) {
- mh->fl &= ~MANH_LITERAL;
- return 1;
- } else if (n->type == ROFFT_BODY)
- return 1;
-
- print_otag(h, TAG_H1, "c", "Sh");
+ if (n->type == ROFFT_BLOCK && mh->nofill != NULL) {
+ print_tagq(h, mh->nofill);
+ mh->nofill = NULL;
+ } else if (n->type == ROFFT_HEAD)
+ print_otag(h, TAG_H1, "c", "Sh");
return 1;
}
@@ -363,17 +359,11 @@ static int
man_alt_pre(MAN_ARGS)
{
const struct roff_node *nn;
- int i, savelit;
+ int i;
enum htmltag fp;
struct tag *t;
- if ((savelit = mh->fl & MANH_LITERAL))
- print_otag(h, TAG_BR, "");
-
- mh->fl &= ~MANH_LITERAL;
-
for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
- t = NULL;
switch (n->tok) {
case MAN_BI:
fp = i % 2 ? TAG_I : TAG_B;
@@ -400,18 +390,14 @@ man_alt_pre(MAN_ARGS)
if (i)
h->flags |= HTML_NOSPACE;
- if (TAG_MAX != fp)
+ if (fp != TAG_MAX)
t = print_otag(h, fp, "");
- print_man_node(man, nn, mh, h);
+ print_text(h, nn->string);
- if (t)
+ if (fp != TAG_MAX)
print_tagq(h, t);
}
-
- if (savelit)
- mh->fl |= MANH_LITERAL;
-
return 0;
}
@@ -427,13 +413,11 @@ man_SM_pre(MAN_ARGS)
static int
man_SS_pre(MAN_ARGS)
{
- if (n->type == ROFFT_BLOCK) {
- mh->fl &= ~MANH_LITERAL;
- return 1;
- } else if (n->type == ROFFT_BODY)
- return 1;
-
- print_otag(h, TAG_H2, "c", "Ss");
+ if (n->type == ROFFT_BLOCK && mh->nofill != NULL) {
+ print_tagq(h, mh->nofill);
+ mh->nofill = NULL;
+ } else if (n->type == ROFFT_HEAD)
+ print_otag(h, TAG_H2, "c", "Ss");
return 1;
}
@@ -552,15 +536,20 @@ man_I_pre(MAN_ARGS)
}
static int
-man_literal_pre(MAN_ARGS)
+man_fill_pre(MAN_ARGS)
{
-
if (MAN_fi == n->tok || MAN_EE == n->tok) {
- print_otag(h, TAG_BR, "");
- mh->fl &= ~MANH_LITERAL;
- } else
- mh->fl |= MANH_LITERAL;
-
+ if (mh->nofill != NULL) {
+ print_tagq(h, mh->nofill);
+ mh->nofill = NULL;
+ } else
+ print_otag(h, TAG_BR, "");
+ } else {
+ if (mh->nofill == NULL)
+ mh->nofill = print_otag(h, TAG_PRE, "");
+ else
+ print_otag(h, TAG_BR, "");
+ }
return 0;
}