-/* $Id: mdoc_term.c,v 1.300 2014/12/23 09:31:46 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.308 2015/02/05 01:46:56 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
void (*post)(DECL_ARGS);
};
-static size_t a2width(const struct termp *, const char *);
+static int a2width(const struct termp *, const char *);
static void print_bvspace(struct termp *,
const struct mdoc_node *,
static void termp_bd_post(DECL_ARGS);
static void termp_bk_post(DECL_ARGS);
static void termp_bl_post(DECL_ARGS);
+static void termp_eo_post(DECL_ARGS);
static void termp_fd_post(DECL_ARGS);
static void termp_fo_post(DECL_ARGS);
static void termp_in_post(DECL_ARGS);
static int termp_bx_pre(DECL_ARGS);
static int termp_cd_pre(DECL_ARGS);
static int termp_d1_pre(DECL_ARGS);
+static int termp_eo_pre(DECL_ARGS);
static int termp_ex_pre(DECL_ARGS);
static int termp_fa_pre(DECL_ARGS);
static int termp_fd_pre(DECL_ARGS);
{ NULL, NULL }, /* Ec */ /* FIXME: no space */
{ NULL, NULL }, /* Ef */
{ termp_under_pre, NULL }, /* Em */
- { termp_quote_pre, termp_quote_post }, /* Eo */
+ { termp_eo_pre, termp_eo_post }, /* Eo */
{ termp_xx_pre, NULL }, /* Fx */
{ termp_bold_pre, NULL }, /* Ms */
{ termp_li_pre, NULL }, /* No */
print_mdoc_nodelist(DECL_ARGS)
{
- print_mdoc_node(p, pair, meta, n);
- if (n->next)
- print_mdoc_nodelist(p, pair, meta, n->next);
+ while (n != NULL) {
+ print_mdoc_node(p, pair, meta, n);
+ n = n->next;
+ }
}
static void
chld = 1;
offset = p->offset;
rmargin = p->rmargin;
- n->prev_font = term_fontq(p);
+ n->prev_font = p->fonti;
memset(&npair, 0, sizeof(struct termpair));
npair.ppair = pair;
* invoked in a prior line, revert it to PREKEEP.
*/
- if (TERMP_KEEP & p->flags) {
- if (n->prev ? (n->prev->lastline != n->line) :
- (n->parent && n->parent->line != n->line)) {
- p->flags &= ~TERMP_KEEP;
- p->flags |= TERMP_PREKEEP;
- }
+ if (p->flags & TERMP_KEEP && n->flags & MDOC_LINE) {
+ p->flags &= ~TERMP_KEEP;
+ p->flags |= TERMP_PREKEEP;
}
/*
free(volume);
}
-static size_t
+static int
a2width(const struct termp *p, const char *v)
{
struct roffsu su;
SCALE_HS_INIT(&su, term_strlen(p, v));
su.scale /= term_strlen(p, "0");
}
-
return(term_hspan(p, &su));
}
static int
termp_it_pre(DECL_ARGS)
{
- const struct mdoc_node *bl, *nn;
char buf[24];
- int i;
- size_t width, offset, ncols, dcol;
+ const struct mdoc_node *bl, *nn;
+ size_t ncols, dcol;
+ int i, offset, width;
enum mdoc_list type;
if (MDOC_BLOCK == n->type) {
bl = n->parent->parent->parent;
type = bl->norm->Bl.type;
+ /*
+ * Defaults for specific list types.
+ */
+
+ switch (type) {
+ case LIST_bullet:
+ /* FALLTHROUGH */
+ case LIST_dash:
+ /* FALLTHROUGH */
+ case LIST_hyphen:
+ /* FALLTHROUGH */
+ case LIST_enum:
+ width = term_len(p, 2);
+ break;
+ case LIST_hang:
+ width = term_len(p, 8);
+ break;
+ case LIST_column:
+ /* FALLTHROUGH */
+ case LIST_tag:
+ width = term_len(p, 10);
+ break;
+ default:
+ width = 0;
+ break;
+ }
+ offset = 0;
+
/*
* First calculate width and offset. This is pretty easy unless
* we're a -column list, in which case all prior columns must
* be accounted for.
*/
- width = offset = 0;
-
- if (bl->norm->Bl.offs)
+ if (bl->norm->Bl.offs != NULL) {
offset = a2width(p, bl->norm->Bl.offs);
+ if (offset < 0 && (size_t)(-offset) > p->offset)
+ offset = -p->offset;
+ else if (offset > SHRT_MAX)
+ offset = 0;
+ }
switch (type) {
case LIST_column:
* number for buffering single arguments. See the above
* handling for column for how this changes.
*/
- assert(bl->norm->Bl.width);
width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
- break;
- }
-
- /*
- * List-type can override the width in the case of fixed-head
- * values (bullet, dash/hyphen, enum). Tags need a non-zero
- * offset.
- */
-
- switch (type) {
- case LIST_bullet:
- /* FALLTHROUGH */
- case LIST_dash:
- /* FALLTHROUGH */
- case LIST_hyphen:
- /* FALLTHROUGH */
- case LIST_enum:
- if (width < term_len(p, 2))
- width = term_len(p, 2);
- break;
- case LIST_hang:
- if (0 == width)
- width = term_len(p, 8);
- break;
- case LIST_column:
- /* FALLTHROUGH */
- case LIST_tag:
- if (0 == width)
- width = term_len(p, 10);
- break;
- default:
+ if (width < 0 && (size_t)(-width) > p->offset)
+ width = -p->offset;
+ else if (width > SHRT_MAX)
+ width = 0;
break;
}
case LIST_enum:
/*
* Weird special case.
- * Very narrow enum lists actually hang.
+ * Some very narrow lists actually hang.
*/
- if (width == term_len(p, 2))
- p->flags |= TERMP_HANG;
/* FALLTHROUGH */
case LIST_bullet:
/* FALLTHROUGH */
case LIST_dash:
/* FALLTHROUGH */
case LIST_hyphen:
+ if (width <= (int)term_len(p, 2))
+ p->flags |= TERMP_HANG;
if (MDOC_HEAD != n->type)
break;
p->flags |= TERMP_NOBREAK;
case LIST_hyphen:
/* FALLTHROUGH */
case LIST_tag:
- assert(width);
if (MDOC_HEAD == n->type)
p->rmargin = p->offset + width;
else
return(0);
}
- if (n->child == NULL)
- return(0);
-
if (p->flags & TERMP_SPLIT)
term_newln(p);
{
size_t tabwidth, lm, len, rm, rmax;
struct mdoc_node *nn;
+ int offset;
if (MDOC_BLOCK == n->type) {
print_bvspace(p, n, n);
p->offset += term_len(p, p->defindent + 1);
else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
p->offset += term_len(p, (p->defindent + 1) * 2);
- else
- p->offset += a2width(p, n->norm->Bd.offs);
+ else {
+ offset = a2width(p, n->norm->Bd.offs);
+ if (offset < 0 && (size_t)(-offset) > p->offset)
+ p->offset = 0;
+ else if (offset < SHRT_MAX)
+ p->offset += offset;
+ }
/*
* If -ragged or -filled are specified, the block does nothing
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- term_word(p, n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? "<" : "\\(la");
+ term_word(p, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
break;
case MDOC_Bro:
/* FALLTHROUGH */
return(1);
term_word(p, n->norm->Es->child->string);
break;
- case MDOC_Eo:
- break;
case MDOC_Po:
/* FALLTHROUGH */
case MDOC_Pq:
if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
return;
- if ( ! (n->tok == MDOC_En ||
- (n->tok == MDOC_Eo && n->end == ENDBODY_SPACE)))
- p->flags |= TERMP_NOSPACE;
+ p->flags |= TERMP_NOSPACE;
switch (n->tok) {
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- term_word(p, n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? ">" : "\\(ra");
+ term_word(p, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
break;
case MDOC_Bro:
/* FALLTHROUGH */
term_word(p, "\\(rq");
break;
case MDOC_En:
- if (NULL != n->norm->Es &&
- NULL != n->norm->Es->child &&
- NULL != n->norm->Es->child->next) {
- p->flags |= TERMP_NOSPACE;
+ if (n->norm->Es == NULL ||
+ n->norm->Es->child == NULL ||
+ n->norm->Es->child->next == NULL)
+ p->flags &= ~TERMP_NOSPACE;
+ else
term_word(p, n->norm->Es->child->next->string);
- }
- break;
- case MDOC_Eo:
break;
case MDOC_Po:
/* FALLTHROUGH */
}
}
+static int
+termp_eo_pre(DECL_ARGS)
+{
+
+ if (n->type != MDOC_BODY)
+ return(1);
+
+ if (n->end == ENDBODY_NOT &&
+ n->parent->head->child == NULL &&
+ n->child != NULL &&
+ n->child->end != ENDBODY_NOT)
+ term_word(p, "\\&");
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
+ n->parent->head->child != NULL &&
+ (n->parent->body->child != NULL ||
+ n->parent->tail->child != NULL))
+ p->flags |= TERMP_NOSPACE;
+
+ return(1);
+}
+
+static void
+termp_eo_post(DECL_ARGS)
+{
+ int body, tail;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->end != ENDBODY_NOT) {
+ p->flags &= ~TERMP_NOSPACE;
+ return;
+ }
+
+ body = n->child != NULL || n->parent->head->child != NULL;
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+
+ if (body && tail)
+ p->flags |= TERMP_NOSPACE;
+ else if ( ! (body || tail))
+ term_word(p, "\\&");
+ else if ( ! tail)
+ p->flags &= ~TERMP_NOSPACE;
+}
+
static int
termp_fo_pre(DECL_ARGS)
{