-/* $Id: mdoc_term.c,v 1.163 2010/07/01 14:34:03 kristaps Exp $ */
+/* $Id: mdoc_term.c,v 1.183 2010/08/21 14:04:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010 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
#include "mandoc.h"
#include "out.h"
#include "term.h"
-#include "regs.h"
#include "mdoc.h"
#include "chars.h"
#include "main.h"
static size_t a2height(const struct termp *, const char *);
static size_t a2offs(const struct termp *, const char *);
-static int arg_hasattr(int, const struct mdoc_node *);
-static int arg_getattr(int, const struct mdoc_node *);
static void print_bvspace(struct termp *,
const struct mdoc_node *,
const struct mdoc_node *);
static void termp_in_post(DECL_ARGS);
static void termp_it_post(DECL_ARGS);
static void termp_lb_post(DECL_ARGS);
+static void termp_nm_post(DECL_ARGS);
static void termp_op_post(DECL_ARGS);
static void termp_pf_post(DECL_ARGS);
static void termp_pq_post(DECL_ARGS);
{ termp_bl_pre, termp_bl_post }, /* Bl */
{ NULL, NULL }, /* El */
{ termp_it_pre, termp_it_post }, /* It */
- { NULL, NULL }, /* Ad */
+ { termp_under_pre, NULL }, /* Ad */
{ termp_an_pre, termp_an_post }, /* An */
{ termp_under_pre, NULL }, /* Ar */
{ termp_cd_pre, NULL }, /* Cd */
{ termp_in_pre, termp_in_post }, /* In */
{ termp_li_pre, NULL }, /* Li */
{ termp_nd_pre, NULL }, /* Nd */
- { termp_nm_pre, NULL }, /* Nm */
+ { termp_nm_pre, termp_nm_post }, /* Nm */
{ termp_op_pre, termp_op_post }, /* Op */
{ NULL, NULL }, /* Ot */
{ termp_under_pre, NULL }, /* Pa */
{ termp_under_pre, NULL }, /* Em */
{ NULL, NULL }, /* Eo */
{ termp_xx_pre, NULL }, /* Fx */
- { termp_bold_pre, NULL }, /* Ms */ /* FIXME: convert to symbol? */
+ { termp_bold_pre, NULL }, /* Ms */
{ NULL, NULL }, /* No */
{ termp_ns_pre, NULL }, /* Ns */
{ termp_xx_pre, NULL }, /* Nx */
else if (termacts[n->tok].pre && ENDBODY_NOT == n->end)
chld = (*termacts[n->tok].pre)(p, &npair, m, n);
+ /*
+ * Keeps only work until the end of a line. If a keep was
+ * invoked in a prior line, revert it to PREKEEP.
+ */
+
+ if (TERMP_KEEP & p->flags) {
+ if (n->prev && n->prev->line != n->line) {
+ p->flags &= ~TERMP_KEEP;
+ p->flags |= TERMP_PREKEEP;
+ } else if (NULL == n->prev) {
+ if (n->parent && n->parent->line != n->line) {
+ p->flags &= ~TERMP_KEEP;
+ p->flags |= TERMP_PREKEEP;
+ }
+ }
+ }
+
if (chld && n->child)
print_mdoc_nodelist(p, &npair, m, n->child);
term_fontpopq(p, font);
- if (MDOC_TEXT != n->type &&
- termacts[n->tok].post &&
- ! (MDOC_ENDED & n->flags)) {
- (*termacts[n->tok].post)(p, &npair, m, n);
+ if (MDOC_TEXT != n->type && termacts[n->tok].post &&
+ ! (MDOC_ENDED & n->flags)) {
+ (void)(*termacts[n->tok].post)(p, &npair, m, n);
/*
* Explicit end tokens not only call the post
* handler, but also tell the respective block
* that it must not call the post handler again.
*/
- if (n->end)
+ if (ENDBODY_NOT != n->end)
n->pending->flags |= MDOC_ENDED;
/*
}
-/*
- * Return 1 if an argument has a particular argument value or 0 if it
- * does not. See arg_getattr().
- */
-static int
-arg_hasattr(int arg, const struct mdoc_node *n)
-{
-
- return(-1 != arg_getattr(arg, n));
-}
-
-
-/*
- * Get the index of an argument in a node's argument list or -1 if it
- * does not exist.
- */
-static int
-arg_getattr(int v, const struct mdoc_node *n)
-{
- int i;
-
- if (NULL == n->args)
- return(0);
-
- for (i = 0; i < (int)n->args->argc; i++)
- if (n->args->argv[i].arg == v)
- return(i);
-
- return(-1);
-}
-
-
/*
* Determine how much space to print out before block elements of `It'
* (and thus `Bl') and `Bd'. And then go ahead and print that space,
term_newln(p);
- if (MDOC_Bd == bl->tok && bl->data.Bd.comp)
+ if (MDOC_Bd == bl->tok && bl->data.Bd->comp)
return;
- if (MDOC_Bl == bl->tok && bl->data.Bl.comp)
+ if (MDOC_Bl == bl->tok && bl->data.Bl->comp)
return;
/* Do not vspace directly after Ss/Sh. */
/* A `-column' does not assert vspace within the list. */
- if (MDOC_Bl == bl->tok && LIST_column == bl->data.Bl.type)
+ if (MDOC_Bl == bl->tok && LIST_column == bl->data.Bl->type)
if (n->prev && MDOC_It == n->prev->tok)
return;
/* A `-diag' without body does not vspace. */
- if (MDOC_Bl == bl->tok && LIST_diag == bl->data.Bl.type)
+ if (MDOC_Bl == bl->tok && LIST_diag == bl->data.Bl->type)
if (n->prev && MDOC_It == n->prev->tok) {
assert(n->prev->body);
if (NULL == n->prev->body->child)
{
const struct mdoc_node *bl, *nn;
char buf[7];
- int i, col;
+ int i;
size_t width, offset, ncols, dcol;
enum mdoc_list type;
}
bl = n->parent->parent->parent;
- type = bl->data.Bl.type;
+ assert(bl->data.Bl);
+ type = bl->data.Bl->type;
/*
* First calculate width and offset. This is pretty easy unless
width = offset = 0;
- if (bl->data.Bl.offs)
- offset = a2offs(p, bl->data.Bl.offs);
+ if (bl->data.Bl->offs)
+ offset = a2offs(p, bl->data.Bl->offs);
switch (type) {
case (LIST_column):
if (MDOC_HEAD == n->type)
break;
- col = arg_getattr(MDOC_Column, bl);
-
/*
* Imitate groff's column handling:
* - For each earlier column, add its width.
* column.
* - For more than 5 columns, add only one column.
*/
- ncols = bl->args->argv[col].sz;
+ ncols = bl->data.Bl->ncols;
+
/* LINTED */
dcol = ncols < 5 ? term_len(p, 4) :
ncols == 5 ? term_len(p, 3) : term_len(p, 1);
nn->prev && i < (int)ncols;
nn = nn->prev, i++)
offset += dcol + a2width
- (p, bl->args->argv[col].value[i]);
+ (p, bl->data.Bl->cols[i]);
/*
* When exceeding the declared number of columns, leave
* Use the declared column widths, extended as explained
* in the preceding paragraph.
*/
- width = a2width(p, bl->args->argv[col].value[i]) + dcol;
+ width = a2width(p, bl->data.Bl->cols[i]) + dcol;
break;
default:
- if (NULL == bl->data.Bl.width)
+ if (NULL == bl->data.Bl->width)
break;
/*
* number for buffering single arguments. See the above
* handling for column for how this changes.
*/
- assert(bl->data.Bl.width);
- width = a2width(p, bl->data.Bl.width) + term_len(p, 2);
+ assert(bl->data.Bl->width);
+ width = a2width(p, bl->data.Bl->width) + term_len(p, 2);
break;
}
if (MDOC_BLOCK == n->type)
return;
- type = n->parent->parent->parent->data.Bl.type;
+ type = n->parent->parent->parent->data.Bl->type;
switch (type) {
case (LIST_item):
termp_nm_pre(DECL_ARGS)
{
- if (NULL == n->child && NULL == m->name)
+ if (MDOC_BLOCK == n->type)
return(1);
- synopsis_pre(p, n);
+ if (MDOC_BODY == n->type) {
+ if (NULL == n->child)
+ return(0);
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+ p->offset += term_len(p, 1) +
+ (NULL == n->prev->child ? term_strlen(p, m->name) :
+ MDOC_TEXT == n->prev->child->type ?
+ term_strlen(p, n->prev->child->string) :
+ term_len(p, 5));
+ return(1);
+ }
+
+ if (NULL == n->child && NULL == m->name)
+ return(0);
+
+ if (MDOC_HEAD == n->type)
+ synopsis_pre(p, n->parent);
+
+ if (MDOC_HEAD == n->type && n->next->child) {
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_HANG;
+ p->rmargin = p->offset + term_len(p, 1) +
+ (NULL == n->child ? term_strlen(p, m->name) :
+ MDOC_TEXT == n->child->type ?
+ term_strlen(p, n->child->string) :
+ term_len(p, 5));
+ }
term_fontpush(p, TERMFONT_BOLD);
if (NULL == n->child)
}
+/* ARGSUSED */
+static void
+termp_nm_post(DECL_ARGS)
+{
+
+ if (MDOC_HEAD == n->type && n->next->child) {
+ term_flushln(p);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ } else if (MDOC_BODY == n->type && n->child) {
+ term_flushln(p);
+ p->flags &= ~TERMP_NOLPAD;
+ }
+}
+
+
/* ARGSUSED */
static int
termp_fl_pre(DECL_ARGS)
return;
}
- if (arg_hasattr(MDOC_Split, n)) {
+ if (AUTH_split == n->data.An.auth) {
p->flags &= ~TERMP_NOSPLIT;
p->flags |= TERMP_SPLIT;
- } else {
+ } else if (AUTH_nosplit == n->data.An.auth) {
p->flags &= ~TERMP_SPLIT;
p->flags |= TERMP_NOSPLIT;
}
static int
termp_bd_pre(DECL_ARGS)
{
- size_t tabwidth;
- size_t rm, rmax;
+ size_t tabwidth, rm, rmax;
const struct mdoc_node *nn;
if (MDOC_BLOCK == n->type) {
} else if (MDOC_HEAD == n->type)
return(0);
- if (n->data.Bd.offs)
- p->offset += a2offs(p, n->data.Bd.offs);
+ assert(n->data.Bd);
+ if (n->data.Bd->offs)
+ p->offset += a2offs(p, n->data.Bd->offs);
/*
* If -ragged or -filled are specified, the block does nothing
* lines are allowed.
*/
- if (DISP_literal != n->data.Bd.type &&
- DISP_unfilled != n->data.Bd.type)
+ if (DISP_literal != n->data.Bd->type &&
+ DISP_unfilled != n->data.Bd->type)
return(1);
tabwidth = p->tabwidth;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
for (nn = n->child; nn; nn = nn->next) {
- p->flags |= TERMP_NOSPACE;
print_mdoc_node(p, pair, m, nn);
- if (NULL == nn->prev ||
- nn->prev->line < nn->line ||
- NULL == nn->next)
- term_flushln(p);
+ if (nn->next && nn->next->line == nn->line)
+ continue;
+ term_flushln(p);
+ p->flags |= TERMP_NOSPACE;
}
p->tabwidth = tabwidth;
rm = p->rmargin;
rmax = p->maxrmargin;
- if (DISP_literal == n->data.Bd.type ||
- DISP_unfilled == n->data.Bd.type)
+ assert(n->data.Bd);
+ if (DISP_literal == n->data.Bd->type ||
+ DISP_unfilled == n->data.Bd->type)
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
len = 0;
break;
default:
+ assert(n->parent);
+ if ((NULL == n->next || NULL == n->prev) &&
+ (MDOC_Ss == n->parent->tok ||
+ MDOC_Sh == n->parent->tok))
+ return(0);
len = 1;
break;
}
return(1);
}
+ if (NULL == n->child)
+ return(0);
+
/* XXX: we drop non-initial arguments as per groff. */
- assert(n->child);
assert(n->child->string);
term_fontpush(p, TERMFONT_BOLD);
term_word(p, n->child->string);
static int
termp_bf_pre(DECL_ARGS)
{
- const struct mdoc_node *nn;
if (MDOC_HEAD == n->type)
return(0);
else if (MDOC_BLOCK != n->type)
return(1);
- if (NULL == (nn = n->head->child)) {
- if (arg_hasattr(MDOC_Emphasis, n))
- term_fontpush(p, TERMFONT_UNDER);
- else if (arg_hasattr(MDOC_Symbolic, n))
- term_fontpush(p, TERMFONT_BOLD);
- else
- term_fontpush(p, TERMFONT_NONE);
+ assert(n->data.Bf);
- return(1);
- }
-
- assert(MDOC_TEXT == nn->type);
- if (0 == strcmp("Em", nn->string))
+ if (FONT_Em == n->data.Bf->font)
term_fontpush(p, TERMFONT_UNDER);
- else if (0 == strcmp("Sy", nn->string))
+ else if (FONT_Sy == n->data.Bf->font)
term_fontpush(p, TERMFONT_BOLD);
- else
+ else
term_fontpush(p, TERMFONT_NONE);
return(1);
{
assert(n->child && MDOC_TEXT == n->child->type);
- if (0 == strcmp("on", n->child->string))
+ if (0 == strcmp("on", n->child->string)) {
+ if (p->col)
+ p->flags &= ~TERMP_NOSPACE;
p->flags &= ~TERMP_NONOSPACE;
- else
+ } else
p->flags |= TERMP_NONOSPACE;
return(0);
static int
termp_lk_pre(DECL_ARGS)
{
- const struct mdoc_node *nn;
+ const struct mdoc_node *nn, *sv;
term_fontpush(p, TERMFONT_UNDER);
- nn = n->child;
+
+ nn = sv = n->child;
if (NULL == nn->next)
return(1);
- term_word(p, nn->string);
+ for (nn = nn->next; nn; nn = nn->next)
+ term_word(p, nn->string);
+
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
term_word(p, ":");
term_fontpush(p, TERMFONT_BOLD);
- for (nn = nn->next; nn; nn = nn->next)
- term_word(p, nn->string);
+ term_word(p, sv->string);
term_fontpop(p);
return(0);
switch (n->type) {
case (MDOC_BLOCK):
- return(1);
+ break;
case (MDOC_HEAD):
return(0);
case (MDOC_BODY):
p->flags |= TERMP_PREKEEP;
- return(1);
+ break;
default:
abort();
+ /* NOTREACHED */
}
+
+ return(1);
}