-/* $Id: man_term.c,v 1.218 2018/08/18 14:26:12 schwarze Exp $ */
+/* $Id: man_term.c,v 1.236 2021/06/28 19:50:15 schwarze Exp $ */
/*
+ * Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Plain text formatter for man(7), used by mandoc(1)
+ * for ASCII, UTF-8, PostScript, and PDF output.
*/
#include "config.h"
#include "man.h"
#include "out.h"
#include "term.h"
+#include "term_tag.h"
#include "main.h"
#define MAXMARGINS 64 /* maximum number of indented scopes */
struct mtermp {
- int fl;
-#define MANT_LITERAL (1 << 0)
int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
int lmargincur; /* index of current margin */
int lmarginsz; /* actual number of nested margins */
static void print_man_foot(struct termp *,
const struct roff_meta *);
static void print_bvspace(struct termp *,
- const struct roff_node *, int);
+ struct roff_node *, int);
static int pre_B(DECL_ARGS);
static int pre_DT(DECL_ARGS);
static int pre_SY(DECL_ARGS);
static int pre_TP(DECL_ARGS);
static int pre_UR(DECL_ARGS);
+static int pre_abort(DECL_ARGS);
static int pre_alternate(DECL_ARGS);
static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
static void post_HP(DECL_ARGS);
static void post_RS(DECL_ARGS);
static void post_SH(DECL_ARGS);
-static void post_SS(DECL_ARGS);
static void post_SY(DECL_ARGS);
static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
{ NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */
- { pre_SS, post_SS, 0 }, /* SS */
+ { pre_SS, post_SH, 0 }, /* SS */
{ pre_TP, post_TP, 0 }, /* TP */
{ pre_TP, post_TP, 0 }, /* TQ */
- { pre_PP, NULL, 0 }, /* LP */
+ { pre_abort, NULL, 0 }, /* LP */
{ pre_PP, NULL, 0 }, /* PP */
- { pre_PP, NULL, 0 }, /* P */
+ { pre_abort, NULL, 0 }, /* P */
{ pre_IP, post_IP, 0 }, /* IP */
{ pre_HP, post_HP, 0 }, /* HP */
{ NULL, NULL, 0 }, /* SM */
{ pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */
- { pre_literal, NULL, MAN_NOTEXT }, /* nf */
- { pre_literal, NULL, MAN_NOTEXT }, /* fi */
{ NULL, NULL, 0 }, /* RE */
{ pre_RS, post_RS, 0 }, /* RS */
{ pre_DT, NULL, 0 }, /* DT */
}
void
-terminal_man(void *arg, const struct roff_man *man)
+terminal_man(void *arg, const struct roff_meta *man)
{
- struct termp *p;
- struct roff_node *n;
struct mtermp mt;
+ struct termp *p;
+ struct roff_node *n, *nc, *nn;
size_t save_defindent;
p = (struct termp *)arg;
term_tab_set(p, "T");
term_tab_set(p, ".5i");
- memset(&mt, 0, sizeof(struct mtermp));
+ memset(&mt, 0, sizeof(mt));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
mt.offset = term_len(p, p->defindent);
mt.pardist = 1;
n = man->first->child;
if (p->synopsisonly) {
- while (n != NULL) {
- if (n->tok == MAN_SH &&
- n->child->child->type == ROFFT_TEXT &&
- !strcmp(n->child->child->string, "SYNOPSIS")) {
- if (n->child->next->child != NULL)
- print_man_nodelist(p, &mt,
- n->child->next->child,
- &man->meta);
- term_newln(p);
+ for (nn = NULL; n != NULL; n = n->next) {
+ if (n->tok != MAN_SH)
+ continue;
+ nc = n->child->child;
+ if (nc->type != ROFFT_TEXT)
+ continue;
+ if (strcmp(nc->string, "SYNOPSIS") == 0)
break;
- }
- n = n->next;
+ if (nn == NULL && strcmp(nc->string, "NAME") == 0)
+ nn = n;
}
+ if (n == NULL)
+ n = nn;
+ p->flags |= TERMP_NOSPACE;
+ if (n != NULL && (n = n->child->next->child) != NULL)
+ print_man_nodelist(p, &mt, n, man);
+ term_newln(p);
} else {
- term_begin(p, print_man_head, print_man_foot, &man->meta);
+ term_begin(p, print_man_head, print_man_foot, man);
p->flags |= TERMP_NOSPACE;
if (n != NULL)
- print_man_nodelist(p, &mt, n, &man->meta);
+ print_man_nodelist(p, &mt, n, man);
term_end(p);
}
p->defindent = save_defindent;
* first, print it.
*/
static void
-print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
+print_bvspace(struct termp *p, struct roff_node *n, int pardist)
{
- int i;
+ struct roff_node *nch;
+ int i;
term_newln(p);
- if (n->body && n->body->child)
- if (n->body->child->type == ROFFT_TBL)
- return;
+ if (n->body != NULL &&
+ (nch = roff_node_child(n->body)) != NULL &&
+ nch->type == ROFFT_TBL)
+ return;
- if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
- if (NULL == n->prev)
- return;
+ if (n->parent->tok != MAN_RS && roff_node_prev(n) == NULL)
+ return;
for (i = 0; i < pardist; i++)
term_vspace(p);
static int
-pre_ign(DECL_ARGS)
+pre_abort(DECL_ARGS)
{
+ abort();
+}
+static int
+pre_ign(DECL_ARGS)
+{
return 0;
}
static int
pre_I(DECL_ARGS)
{
-
term_fontrepl(p, TERMFONT_UNDER);
return 1;
}
static int
pre_literal(DECL_ARGS)
{
-
term_newln(p);
- if (n->tok == MAN_nf || n->tok == MAN_EX)
- mt->fl |= MANT_LITERAL;
- else
- mt->fl &= ~MANT_LITERAL;
-
/*
* Unlike .IP and .TP, .HP does not have a HEAD.
* So in case a second call to term_flushln() is needed,
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
}
-
return 0;
}
{
enum termfont font[2];
struct roff_node *nn;
- int savelit, i;
+ int i;
switch (n->tok) {
case MAN_RB:
default:
abort();
}
-
- savelit = MANT_LITERAL & mt->fl;
- mt->fl &= ~MANT_LITERAL;
-
- for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
+ for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) {
term_fontrepl(p, font[i]);
- if (savelit && NULL == nn->next)
- mt->fl |= MANT_LITERAL;
assert(nn->type == ROFFT_TEXT);
term_word(p, nn->string);
if (nn->flags & NODE_EOS)
- p->flags |= TERMP_SENTENCE;
- if (nn->next)
+ p->flags |= TERMP_SENTENCE;
+ if (nn->next != NULL)
p->flags |= TERMP_NOSPACE;
}
-
return 0;
}
static int
pre_B(DECL_ARGS)
{
-
term_fontrepl(p, TERMFONT_BOLD);
return 1;
}
static int
pre_OP(DECL_ARGS)
{
-
term_word(p, "[");
p->flags |= TERMP_KEEP | TERMP_NOSPACE;
- if (NULL != (n = n->child)) {
+ if ((n = n->child) != NULL) {
term_fontrepl(p, TERMFONT_BOLD);
term_word(p, n->string);
}
- if (NULL != n && NULL != n->next) {
+ if (n != NULL && n->next != NULL) {
term_fontrepl(p, TERMFONT_UNDER);
term_word(p, n->next->string);
}
-
term_fontrepl(p, TERMFONT_NONE);
p->flags &= ~TERMP_KEEP;
p->flags |= TERMP_NOSPACE;
cp = n->child->string;
less = 0;
- if ('-' == *cp)
+ if (*cp == '-')
less = -1;
- else if ('+' == *cp)
+ else if (*cp == '+')
less = 1;
else
cp--;
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
return 1;
+ case ROFFT_HEAD:
+ return 0;
case ROFFT_BODY:
break;
default:
- return 0;
+ abort();
}
- if ( ! (MANT_LITERAL & mt->fl)) {
+ if (n->child == NULL)
+ return 0;
+
+ if ((n->child->flags & NODE_NOFILL) == 0) {
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
}
static void
post_HP(DECL_ARGS)
{
-
switch (n->type) {
+ case ROFFT_BLOCK:
+ case ROFFT_HEAD:
+ break;
case ROFFT_BODY:
term_newln(p);
p->tcol->rmargin = p->maxrmargin;
break;
default:
- break;
+ abort();
}
}
static int
pre_PP(DECL_ARGS)
{
-
switch (n->type) {
case ROFFT_BLOCK:
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
print_bvspace(p, n, mt->pardist);
break;
- default:
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
p->tcol->offset = mt->offset;
break;
+ default:
+ abort();
}
-
- return n->type != ROFFT_HEAD;
+ return 1;
}
static int
{
struct roffsu su;
const struct roff_node *nn;
- int len, savelit;
+ int len;
switch (n->type) {
- case ROFFT_BODY:
- p->flags |= TERMP_NOSPACE;
- break;
+ case ROFFT_BLOCK:
+ print_bvspace(p, n, mt->pardist);
+ return 1;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case ROFFT_BLOCK:
- print_bvspace(p, n, mt->pardist);
- /* FALLTHROUGH */
+ case ROFFT_BODY:
+ p->flags |= TERMP_NOSPACE;
+ break;
default:
- return 1;
+ abort();
}
/* Calculate the offset from the optional second argument. */
case ROFFT_HEAD:
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
-
- savelit = MANT_LITERAL & mt->fl;
- mt->fl &= ~MANT_LITERAL;
-
- if (n->child)
+ if (n->child != NULL)
print_man_node(p, mt, n->child, meta);
-
- if (savelit)
- mt->fl |= MANT_LITERAL;
-
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset + len;
p->tcol->rmargin = p->maxrmargin;
break;
default:
- break;
+ abort();
}
-
return 1;
}
static void
post_IP(DECL_ARGS)
{
-
switch (n->type) {
+ case ROFFT_BLOCK:
+ break;
case ROFFT_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->tcol->offset = mt->offset;
break;
default:
- break;
+ abort();
}
}
{
struct roffsu su;
struct roff_node *nn;
- int len, savelit;
+ int len;
switch (n->type) {
+ case ROFFT_BLOCK:
+ if (n->tok == MAN_TP)
+ print_bvspace(p, n, mt->pardist);
+ return 1;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
p->trailspace = 1;
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
- case ROFFT_BLOCK:
- if (n->tok == MAN_TP)
- print_bvspace(p, n, mt->pardist);
- /* FALLTHROUGH */
default:
- return 1;
+ abort();
}
/* Calculate offset. */
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
- savelit = MANT_LITERAL & mt->fl;
- mt->fl &= ~MANT_LITERAL;
-
/* Don't print same-line elements. */
nn = n->child;
- while (NULL != nn && 0 == (NODE_LINE & nn->flags))
+ while (nn != NULL && (nn->flags & NODE_LINE) == 0)
nn = nn->next;
- while (NULL != nn) {
+ while (nn != NULL) {
print_man_node(p, mt, nn, meta);
nn = nn->next;
}
-
- if (savelit)
- mt->fl |= MANT_LITERAL;
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset + len;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break;
default:
- break;
+ abort();
}
-
return 1;
}
static void
post_TP(DECL_ARGS)
{
-
switch (n->type) {
+ case ROFFT_BLOCK:
+ break;
case ROFFT_HEAD:
term_flushln(p);
break;
p->tcol->offset = mt->offset;
break;
default:
- break;
+ abort();
}
}
switch (n->type) {
case ROFFT_BLOCK:
- mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
* and after an empty subsection.
*/
- do {
- n = n->prev;
- } while (n != NULL && n->tok >= MAN_TH &&
- man_term_act(n->tok)->flags & MAN_NOTEXT);
- if (n == NULL || n->type == ROFFT_COMMENT ||
- (n->tok == MAN_SS && n->body->child == NULL))
+ if ((n = roff_node_prev(n)) == NULL ||
+ (n->tok == MAN_SS && roff_node_child(n->body) == NULL))
break;
for (i = 0; i < mt->pardist; i++)
default:
break;
}
-
return 1;
}
-static void
-post_SS(DECL_ARGS)
-{
-
- switch (n->type) {
- case ROFFT_HEAD:
- term_newln(p);
- break;
- case ROFFT_BODY:
- term_newln(p);
- break;
- default:
- break;
- }
-}
-
static int
pre_SH(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
- mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
* and after an empty section.
*/
- do {
- n = n->prev;
- } while (n != NULL && n->tok >= MAN_TH &&
- man_term_act(n->tok)->flags & MAN_NOTEXT);
- if (n == NULL || n->type == ROFFT_COMMENT ||
- (n->tok == MAN_SH && n->body->child == NULL))
+ if ((n = roff_node_prev(n)) == NULL ||
+ (n->tok == MAN_SH && roff_node_child(n->body) == NULL))
break;
for (i = 0; i < mt->pardist; i++)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
default:
- break;
+ abort();
}
-
return 1;
}
static void
post_SH(DECL_ARGS)
{
-
switch (n->type) {
- case ROFFT_HEAD:
- term_newln(p);
+ case ROFFT_BLOCK:
break;
+ case ROFFT_HEAD:
case ROFFT_BODY:
term_newln(p);
break;
default:
- break;
+ abort();
}
}
return 1;
case ROFFT_HEAD:
return 0;
- default:
+ case ROFFT_BODY:
break;
+ default:
+ abort();
}
n = n->parent->head;
static void
post_RS(DECL_ARGS)
{
-
switch (n->type) {
case ROFFT_BLOCK:
- return;
case ROFFT_HEAD:
return;
- default:
- term_newln(p);
+ case ROFFT_BODY:
break;
+ default:
+ abort();
}
-
+ term_newln(p);
mt->offset -= n->parent->head->aux;
p->tcol->offset = mt->offset;
-
if (--mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
}
switch (n->type) {
case ROFFT_BLOCK:
- if (n->prev == NULL || n->prev->tok != MAN_SY)
+ if ((nn = roff_node_prev(n)) == NULL || nn->tok != MAN_SY)
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_HEAD:
}
nn = n->parent->head->child;
- len = nn == NULL ? 0 : term_strlen(p, nn->string) + 1;
+ len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
switch (n->type) {
case ROFFT_HEAD:
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
- p->flags |= TERMP_NOBREAK;
+ if (n->next->child == NULL ||
+ (n->next->child->flags & NODE_NOFILL) == 0)
+ p->flags |= TERMP_NOBREAK;
term_fontrepl(p, TERMFONT_BOLD);
break;
case ROFFT_BODY:
post_SY(DECL_ARGS)
{
switch (n->type) {
+ case ROFFT_BLOCK:
+ break;
case ROFFT_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->tcol->offset = mt->offset;
break;
default:
- break;
+ abort();
}
}
static int
pre_UR(DECL_ARGS)
{
-
return n->type != ROFFT_HEAD;
}
static void
post_UR(DECL_ARGS)
{
-
if (n->type != ROFFT_BLOCK)
return;
term_word(p, "<");
p->flags |= TERMP_NOSPACE;
- if (NULL != n->child->child)
+ if (n->child->child != NULL)
print_man_node(p, mt, n->child->child, meta);
p->flags |= TERMP_NOSPACE;
const struct man_term_act *act;
int c;
+ if (n->flags & NODE_ID)
+ term_tag_write(n, p->line);
+
switch (n->type) {
case ROFFT_TEXT:
/*
}
act = man_term_act(n->tok);
- if ((act->flags & MAN_NOTEXT) == 0)
+ if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
term_fontrepl(p, TERMFONT_NONE);
c = 1;
if (act->pre != NULL)
c = (*act->pre)(p, mt, n, meta);
- if (c && n->child)
+ if (c && n->child != NULL)
print_man_nodelist(p, mt, n->child, meta);
if (act->post != NULL)
(*act->post)(p, mt, n, meta);
- if ((act->flags & MAN_NOTEXT) == 0)
+ if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
term_fontrepl(p, TERMFONT_NONE);
out:
* -man doesn't have nested macros, we don't need to be
* more specific than this.
*/
- if (mt->fl & MANT_LITERAL &&
+ if (n->flags & NODE_NOFILL &&
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
(n->next == NULL || n->next->flags & NODE_LINE)) {
p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
p->tcol->rmargin = p->maxrmargin;
}
}
- if (NODE_EOS & n->flags)
+ if (n->flags & NODE_EOS)
p->flags |= TERMP_SENTENCE;
}
-
static void
print_man_nodelist(DECL_ARGS)
{
-
while (n != NULL) {
print_man_node(p, mt, n, meta);
n = n->next;
*/
if ( ! p->mdocstyle) {
- if (meta->hasbody) {
- term_vspace(p);
- term_vspace(p);
- }
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
- } else if (meta->os) {
+ } else if (meta->os != NULL) {
title = mandoc_strdup(meta->os);
} else {
title = mandoc_strdup("");
*/
term_vspace(p);
- if ( ! p->mdocstyle) {
- term_vspace(p);
- term_vspace(p);
- }
free(title);
}