-/* $Id: man_term.c,v 1.180 2015/04/18 16:06:40 schwarze Exp $ */
+/* $Id: man_term.c,v 1.203 2017/06/07 17:38:26 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017 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
const struct roff_node *, int);
static int pre_B(DECL_ARGS);
+static int pre_DT(DECL_ARGS);
static int pre_HP(DECL_ARGS);
static int pre_I(DECL_ARGS);
static int pre_IP(DECL_ARGS);
static int pre_TP(DECL_ARGS);
static int pre_UR(DECL_ARGS);
static int pre_alternate(DECL_ARGS);
-static int pre_ft(DECL_ARGS);
static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
static int pre_literal(DECL_ARGS);
-static int pre_ll(DECL_ARGS);
-static int pre_sp(DECL_ARGS);
static void post_IP(DECL_ARGS);
static void post_HP(DECL_ARGS);
static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
-static const struct termact termacts[MAN_MAX] = {
- { pre_sp, NULL, MAN_NOTEXT }, /* br */
+static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */
{ pre_SS, post_SS, 0 }, /* SS */
{ pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */
- { pre_sp, NULL, MAN_NOTEXT }, /* sp */
{ pre_literal, NULL, 0 }, /* nf */
{ pre_literal, NULL, 0 }, /* fi */
{ NULL, NULL, 0 }, /* RE */
{ pre_RS, post_RS, 0 }, /* RS */
- { pre_ign, NULL, 0 }, /* DT */
+ { pre_DT, NULL, 0 }, /* DT */
{ pre_ign, NULL, MAN_NOTEXT }, /* UC */
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
- { pre_ft, NULL, MAN_NOTEXT }, /* ft */
{ pre_OP, NULL, 0 }, /* OP */
{ pre_literal, NULL, 0 }, /* EX */
{ pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */
- { pre_ll, NULL, MAN_NOTEXT }, /* ll */
};
+static const struct termact *termacts = __termacts - MAN_TH;
void
terminal_man(void *arg, const struct roff_man *man)
{
struct termp *p;
- const struct roff_meta *meta;
struct roff_node *n;
struct mtermp mt;
+ size_t save_defindent;
p = (struct termp *)arg;
-
- p->overstep = 0;
- p->rmargin = p->maxrmargin = p->defrmargin;
- p->tabwidth = term_len(p, 5);
-
- n = man_node(man)->child;
- meta = man_meta(man);
+ p->tcol->rmargin = p->maxrmargin = p->defrmargin;
+ term_tab_set(p, NULL);
+ term_tab_set(p, "T");
+ term_tab_set(p, ".5i");
memset(&mt, 0, sizeof(struct mtermp));
-
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 &&
!strcmp(n->child->child->string, "SYNOPSIS")) {
if (n->child->next->child != NULL)
print_man_nodelist(p, &mt,
- n->child->next->child, meta);
+ n->child->next->child,
+ &man->meta);
term_newln(p);
break;
}
n = n->next;
}
} else {
+ save_defindent = p->defindent;
if (p->defindent == 0)
p->defindent = 7;
- term_begin(p, print_man_head, print_man_foot, meta);
+ term_begin(p, print_man_head, print_man_foot, &man->meta);
p->flags |= TERMP_NOSPACE;
if (n != NULL)
- print_man_nodelist(p, &mt, n, meta);
+ print_man_nodelist(p, &mt, n, &man->meta);
term_end(p);
+ p->defindent = save_defindent;
}
}
pre_ign(DECL_ARGS)
{
- return(0);
-}
-
-static int
-pre_ll(DECL_ARGS)
-{
-
- term_setwidth(p, n->nchild ? n->child->string : NULL);
- return(0);
+ return 0;
}
static int
{
term_fontrepl(p, TERMFONT_UNDER);
- return(1);
+ return 1;
}
static int
term_newln(p);
- if (MAN_nf == n->tok || MAN_EX == n->tok)
+ if (n->tok == MAN_nf || n->tok == MAN_EX)
mt->fl |= MANT_LITERAL;
else
mt->fl &= ~MANT_LITERAL;
* So in case a second call to term_flushln() is needed,
* indentation has to be set up explicitly.
*/
- if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
- p->offset = p->rmargin;
- p->rmargin = p->maxrmargin;
+ if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) {
+ p->tcol->offset = p->tcol->rmargin;
+ p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
}
- return(0);
+ return 0;
}
static int
n = n->child;
if (n == NULL) {
mt->pardist = 1;
- return(0);
+ return 0;
}
assert(n->type == ROFFT_TEXT);
if (a2roffsu(n->string, &su, SCALE_VS))
mt->pardist = term_vspan(p, &su);
- return(0);
+ return 0;
}
static int
mt->fl |= MANT_LITERAL;
assert(nn->type == ROFFT_TEXT);
term_word(p, nn->string);
- if (nn->flags & MAN_EOS)
+ if (nn->flags & NODE_EOS)
p->flags |= TERMP_SENTENCE;
if (nn->next)
p->flags |= TERMP_NOSPACE;
}
- return(0);
+ return 0;
}
static int
{
term_fontrepl(p, TERMFONT_BOLD);
- return(1);
+ return 1;
}
static int
term_fontrepl(p, TERMFONT_NONE);
p->flags |= TERMP_NOSPACE;
term_word(p, "]");
- return(0);
-}
-
-static int
-pre_ft(DECL_ARGS)
-{
- const char *cp;
-
- if (NULL == n->child) {
- term_fontlast(p);
- return(0);
- }
-
- cp = n->child->string;
- switch (*cp) {
- case '4':
- /* FALLTHROUGH */
- case '3':
- /* FALLTHROUGH */
- case 'B':
- term_fontrepl(p, TERMFONT_BOLD);
- break;
- case '2':
- /* FALLTHROUGH */
- case 'I':
- term_fontrepl(p, TERMFONT_UNDER);
- break;
- case 'P':
- term_fontlast(p);
- break;
- case '1':
- /* FALLTHROUGH */
- case 'C':
- /* FALLTHROUGH */
- case 'R':
- term_fontrepl(p, TERMFONT_NONE);
- break;
- default:
- break;
- }
- return(0);
+ return 0;
}
static int
term_newln(p);
- if (NULL == n->child) {
- p->offset = mt->offset;
- return(0);
+ if (n->child == NULL) {
+ p->tcol->offset = mt->offset;
+ return 0;
}
cp = n->child->string;
cp--;
if ( ! a2roffsu(++cp, &su, SCALE_EN))
- return(0);
+ return 0;
v = (term_hspan(p, &su) + 11) / 24;
if (less < 0)
- p->offset -= p->offset > v ? v : p->offset;
+ p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
else if (less > 0)
- p->offset += v;
+ p->tcol->offset += v;
else
- p->offset = v;
- if (p->offset > SHRT_MAX)
- p->offset = term_len(p, p->defindent);
+ p->tcol->offset = v;
+ if (p->tcol->offset > SHRT_MAX)
+ p->tcol->offset = term_len(p, p->defindent);
- return(0);
+ return 0;
}
static int
-pre_sp(DECL_ARGS)
+pre_DT(DECL_ARGS)
{
- struct roffsu su;
- int i, len;
-
- if ((NULL == n->prev && n->parent)) {
- switch (n->parent->tok) {
- case MAN_SH:
- /* FALLTHROUGH */
- case MAN_SS:
- /* FALLTHROUGH */
- case MAN_PP:
- /* FALLTHROUGH */
- case MAN_LP:
- /* FALLTHROUGH */
- case MAN_P:
- /* FALLTHROUGH */
- return(0);
- default:
- break;
- }
- }
-
- if (n->tok == MAN_br)
- len = 0;
- else if (n->child == NULL)
- len = 1;
- else {
- if ( ! a2roffsu(n->child->string, &su, SCALE_VS))
- su.scale = 1.0;
- len = term_vspan(p, &su);
- }
-
- if (len == 0)
- term_newln(p);
- else if (len < 0)
- p->skipvsp -= len;
- else
- for (i = 0; i < len; i++)
- term_vspace(p);
-
- return(0);
+ term_tab_set(p, NULL);
+ term_tab_set(p, "T");
+ term_tab_set(p, ".5i");
+ return 0;
}
static int
switch (n->type) {
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
- return(1);
+ return 1;
case ROFFT_BODY:
break;
default:
- return(0);
+ return 0;
}
if ( ! (MANT_LITERAL & mt->fl)) {
} else
len = mt->lmargin[mt->lmargincur];
- p->offset = mt->offset;
- p->rmargin = mt->offset + len;
- return(1);
+ p->tcol->offset = mt->offset;
+ p->tcol->rmargin = mt->offset + len;
+ return 1;
}
static void
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->trailspace = 0;
- p->offset = mt->offset;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = mt->offset;
+ p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
print_bvspace(p, n, mt->pardist);
break;
default:
- p->offset = mt->offset;
+ p->tcol->offset = mt->offset;
break;
}
- return(n->type != ROFFT_HEAD);
+ return n->type != ROFFT_HEAD;
}
static int
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
- return(1);
+ return 1;
}
/* Calculate the offset from the optional second argument. */
switch (n->type) {
case ROFFT_HEAD:
- p->offset = mt->offset;
- p->rmargin = mt->offset + len;
+ p->tcol->offset = mt->offset;
+ p->tcol->rmargin = mt->offset + len;
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
if (savelit)
mt->fl |= MANT_LITERAL;
- return(0);
+ return 0;
case ROFFT_BODY:
- p->offset = mt->offset + len;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = mt->offset + len;
+ p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
}
- return(1);
+ return 1;
}
static void
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
- p->rmargin = p->maxrmargin;
+ p->tcol->rmargin = p->maxrmargin;
break;
case ROFFT_BODY:
term_newln(p);
- p->offset = mt->offset;
+ p->tcol->offset = mt->offset;
break;
default:
break;
switch (n->type) {
case ROFFT_HEAD:
- p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
p->trailspace = 1;
break;
case ROFFT_BODY:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
- return(1);
+ return 1;
}
/* Calculate offset. */
if ((nn = n->parent->head->child) != NULL &&
- nn->string != NULL && ! (MAN_LINE & nn->flags) &&
+ nn->string != NULL && ! (NODE_LINE & nn->flags) &&
a2roffsu(nn->string, &su, SCALE_EN)) {
len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset)
switch (n->type) {
case ROFFT_HEAD:
- p->offset = mt->offset;
- p->rmargin = mt->offset + len;
+ 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 == (MAN_LINE & nn->flags))
+ while (NULL != nn && 0 == (NODE_LINE & nn->flags))
nn = nn->next;
while (NULL != nn) {
if (savelit)
mt->fl |= MANT_LITERAL;
- return(0);
+ return 0;
case ROFFT_BODY:
- p->offset = mt->offset + len;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = mt->offset + len;
+ p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
- p->flags &= ~TERMP_NOBREAK;
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break;
default:
break;
}
- return(1);
+ return 1;
}
static void
break;
case ROFFT_BODY:
term_newln(p);
- p->offset = mt->offset;
+ p->tcol->offset = mt->offset;
break;
default:
break;
do {
n = n->prev;
- } while (n != NULL && n->tok != MAN_MAX &&
+ } while (n != NULL && n->tok != TOKEN_NONE &&
termacts[n->tok].flags & MAN_NOTEXT);
if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL))
break;
break;
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
- p->offset = term_len(p, 3);
- p->rmargin = mt->offset;
+ p->tcol->offset = term_len(p, 3);
+ p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
- p->offset = mt->offset;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = mt->offset;
+ p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
break;
}
- return(1);
+ return 1;
}
static void
do {
n = n->prev;
- } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT);
+ } while (n != NULL && n->tok != TOKEN_NONE &&
+ termacts[n->tok].flags & MAN_NOTEXT);
if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL))
break;
break;
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
- p->offset = 0;
- p->rmargin = mt->offset;
+ p->tcol->offset = 0;
+ p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
- p->offset = mt->offset;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = mt->offset;
+ p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
break;
}
- return(1);
+ return 1;
}
static void
switch (n->type) {
case ROFFT_BLOCK:
term_newln(p);
- return(1);
+ return 1;
case ROFFT_HEAD:
- return(0);
+ return 0;
default:
break;
}
n->aux = term_len(p, p->defindent);
mt->offset += n->aux;
- p->offset = mt->offset;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = mt->offset;
+ p->tcol->rmargin = p->maxrmargin;
if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
- return(1);
+ return 1;
}
static void
}
mt->offset -= n->parent->head->aux;
- p->offset = mt->offset;
+ p->tcol->offset = mt->offset;
if (--mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
pre_UR(DECL_ARGS)
{
- return (n->type != ROFFT_HEAD);
+ return n->type != ROFFT_HEAD;
}
static void
static void
print_man_node(DECL_ARGS)
{
- size_t rm, rmax;
int c;
switch (n->type) {
* If we have a space as the first character, break
* before printing the line's data.
*/
- if ('\0' == *n->string) {
+ if (*n->string == '\0') {
term_vspace(p);
return;
- } else if (' ' == *n->string && MAN_LINE & n->flags)
+ } else if (*n->string == ' ' && n->flags & NODE_LINE &&
+ (p->flags & TERMP_NONEWLINE) == 0)
term_newln(p);
term_word(p, n->string);
goto out;
case ROFFT_EQN:
- if ( ! (n->flags & MAN_LINE))
+ if ( ! (n->flags & NODE_LINE))
p->flags |= TERMP_NOSPACE;
term_eqn(p, n->eqn);
- if (n->next != NULL && ! (n->next->flags & MAN_LINE))
+ if (n->next != NULL && ! (n->next->flags & NODE_LINE))
p->flags |= TERMP_NOSPACE;
return;
case ROFFT_TBL:
break;
}
+ if (n->tok < ROFF_MAX) {
+ roff_term_pre(p, n);
+ return;
+ }
+
+ assert(n->tok >= MAN_TH && n->tok <= MAN_MAX);
if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
term_fontrepl(p, TERMFONT_NONE);
*/
if (mt->fl & MANT_LITERAL &&
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
- (n->next == NULL || n->next->flags & MAN_LINE)) {
- rm = p->rmargin;
- rmax = p->maxrmargin;
- p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
- p->flags |= TERMP_NOSPACE;
+ (n->next == NULL || n->next->flags & NODE_LINE)) {
+ p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
if (n->string != NULL && *n->string != '\0')
term_flushln(p);
else
term_newln(p);
- if (rm < rmax && n->parent->tok == MAN_HP) {
- p->offset = rm;
- p->rmargin = rmax;
- } else
- p->rmargin = rm;
- p->maxrmargin = rmax;
+ p->flags &= ~TERMP_BRNEVER;
+ if (p->tcol->rmargin < p->maxrmargin &&
+ n->parent->tok == MAN_HP) {
+ p->tcol->offset = p->tcol->rmargin;
+ p->tcol->rmargin = p->maxrmargin;
+ }
}
- if (MAN_EOS & n->flags)
+ if (NODE_EOS & n->flags)
p->flags |= TERMP_SENTENCE;
}
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
- p->offset = 0;
- p->rmargin = p->maxrmargin > datelen ?
+ p->tcol->offset = 0;
+ p->tcol->rmargin = p->maxrmargin > datelen ?
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
if (meta->os)
/* At the bottom in the middle: manual date. */
- p->offset = p->rmargin;
+ p->tcol->offset = p->tcol->rmargin;
titlen = term_strlen(p, title);
- p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0;
+ p->tcol->rmargin = p->maxrmargin > titlen ?
+ p->maxrmargin - titlen : 0;
p->flags |= TERMP_NOSPACE;
term_word(p, meta->date);
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
p->trailspace = 0;
- p->offset = p->rmargin;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = p->tcol->rmargin;
+ p->tcol->rmargin = p->maxrmargin;
term_word(p, title);
term_flushln(p);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
- p->offset = 0;
- p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
+ p->tcol->offset = 0;
+ p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
/* At the top in the middle: manual volume. */
p->flags |= TERMP_NOSPACE;
- p->offset = p->rmargin;
- p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
- p->maxrmargin - titlen : p->maxrmargin;
+ p->tcol->offset = p->tcol->rmargin;
+ p->tcol->rmargin = p->tcol->offset + vollen + titlen <
+ p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
term_word(p, volume);
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
- if (p->rmargin + titlen <= p->maxrmargin) {
+ if (p->tcol->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE;
- p->offset = p->rmargin;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = p->tcol->rmargin;
+ p->tcol->rmargin = p->maxrmargin;
term_word(p, title);
term_flushln(p);
}
p->flags &= ~TERMP_NOSPACE;
- p->offset = 0;
- p->rmargin = p->maxrmargin;
+ p->tcol->offset = 0;
+ p->tcol->rmargin = p->maxrmargin;
/*
* Groff prints three blank lines before the content.