summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2014-12-24 23:32:42 +0000
committerIngo Schwarze <schwarze@openbsd.org>2014-12-24 23:32:42 +0000
commit4039dc9d2363717732db9e312b0dcc38973d1a54 (patch)
treee0732e3c42b57f0a92079aacdde4967354c83e24
parent87b33207281eab1594f4681af9e74ecdc86df0ba (diff)
downloadmandoc-4039dc9d2363717732db9e312b0dcc38973d1a54.tar.gz
Support negative indentations for mdoc(7) displays and lists.
Not exactly recommended for use, rather for groff compatibility. While here, introduce similar SHRT_MAX limits as in man(7), fixing a few cases of infinite output found by jsg@ with afl.
-rw-r--r--mdoc_man.c55
-rw-r--r--mdoc_term.c105
-rw-r--r--term.c2
3 files changed, 84 insertions, 78 deletions
diff --git a/mdoc_man.c b/mdoc_man.c
index f6ee541d..bbf7c99b 100644
--- a/mdoc_man.c
+++ b/mdoc_man.c
@@ -116,8 +116,8 @@ static void print_word(const char *);
static void print_line(const char *, int);
static void print_block(const char *, int);
static void print_offs(const char *, int);
-static void print_width(const char *,
- const struct mdoc_node *, size_t);
+static void print_width(const struct mdoc_bl *,
+ const struct mdoc_node *);
static void print_count(int *);
static void print_node(DECL_ARGS);
@@ -265,7 +265,7 @@ static int outflags;
#define BL_STACK_MAX 32
-static size_t Bl_stack[BL_STACK_MAX]; /* offsets [chars] */
+static int Bl_stack[BL_STACK_MAX]; /* offsets [chars] */
static int Bl_stack_post[BL_STACK_MAX]; /* add final .RE */
static int Bl_stack_len; /* number of nested Bl blocks */
static int TPremain; /* characters before tag is full */
@@ -423,7 +423,7 @@ print_offs(const char *v, int keywords)
{
char buf[24];
struct roffsu su;
- size_t sz;
+ int sz;
print_line(".RS", MMAN_Bk_susp);
@@ -435,8 +435,6 @@ print_offs(const char *v, int keywords)
else if (keywords && !strcmp(v, "indent-two"))
sz = 12;
else if (a2roffsu(v, &su, SCALE_EN) > 1) {
- if (su.scale < 0.0)
- su.scale = 0.0;
if (SCALE_EN == su.unit)
sz = su.scale;
else {
@@ -461,7 +459,7 @@ print_offs(const char *v, int keywords)
if (Bl_stack_len)
sz += Bl_stack[Bl_stack_len - 1];
- (void)snprintf(buf, sizeof(buf), "%zun", sz);
+ (void)snprintf(buf, sizeof(buf), "%dn", sz);
print_word(buf);
outflags |= MMAN_nl;
}
@@ -470,22 +468,19 @@ print_offs(const char *v, int keywords)
* Set up the indentation for a list item; used from pre_it().
*/
static void
-print_width(const char *v, const struct mdoc_node *child, size_t defsz)
+print_width(const struct mdoc_bl *bl, const struct mdoc_node *child)
{
char buf[24];
struct roffsu su;
- size_t sz, chsz;
- int numeric, remain;
+ int numeric, remain, sz, chsz;
numeric = 1;
remain = 0;
- /* Convert v into a number (of characters). */
- if (NULL == v)
- sz = defsz;
- else if (a2roffsu(v, &su, SCALE_MAX) > 1) {
- if (su.scale < 0.0)
- su.scale = 0.0;
+ /* Convert the width into a number (of characters). */
+ if (bl->width == NULL)
+ sz = (bl->type == LIST_hang) ? 6 : 0;
+ else if (a2roffsu(bl->width, &su, SCALE_MAX) > 1) {
if (SCALE_EN == su.unit)
sz = su.scale;
else {
@@ -493,11 +488,15 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
numeric = 0;
}
} else
- sz = strlen(v);
+ sz = strlen(bl->width);
/* XXX Rough estimation, might have multiple parts. */
- chsz = (NULL != child && MDOC_TEXT == child->type) ?
- strlen(child->string) : 0;
+ if (bl->type == LIST_enum)
+ chsz = (bl->count > 8) + 1;
+ else if (child != NULL && child->type == MDOC_TEXT)
+ chsz = strlen(child->string);
+ else
+ chsz = 0;
/* Maybe we are inside an enclosing list? */
mid_it();
@@ -509,17 +508,17 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
Bl_stack[Bl_stack_len++] = sz + 2;
/* Set up the current list. */
- if (defsz && chsz > sz)
+ if (chsz > sz && bl->type != LIST_tag)
print_block(".HP", 0);
else {
print_block(".TP", 0);
remain = sz + 2;
}
if (numeric) {
- (void)snprintf(buf, sizeof(buf), "%zun", sz + 2);
+ (void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
print_word(buf);
} else
- print_word(v);
+ print_word(bl->width);
TPremain = remain;
}
@@ -528,7 +527,7 @@ print_count(int *count)
{
char buf[24];
- (void)snprintf(buf, sizeof(buf), "%d.", ++*count);
+ (void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
print_word(buf);
}
@@ -1366,7 +1365,7 @@ pre_it(DECL_ARGS)
case LIST_dash:
/* FALLTHROUGH */
case LIST_hyphen:
- print_width(bln->norm->Bl.width, NULL, 0);
+ print_width(&bln->norm->Bl, NULL);
TPremain = 0;
outflags |= MMAN_nl;
font_push('B');
@@ -1378,19 +1377,19 @@ pre_it(DECL_ARGS)
outflags |= MMAN_nl;
return(0);
case LIST_enum:
- print_width(bln->norm->Bl.width, NULL, 0);
+ print_width(&bln->norm->Bl, NULL);
TPremain = 0;
outflags |= MMAN_nl;
print_count(&bln->norm->Bl.count);
outflags |= MMAN_nl;
return(0);
case LIST_hang:
- print_width(bln->norm->Bl.width, n->child, 6);
+ print_width(&bln->norm->Bl, n->child);
TPremain = 0;
outflags |= MMAN_nl;
return(1);
case LIST_tag:
- print_width(bln->norm->Bl.width, n->child, 0);
+ print_width(&bln->norm->Bl, n->child);
putchar('\n');
outflags &= ~MMAN_spc;
return(1);
@@ -1422,7 +1421,7 @@ mid_it(void)
/* Restore the indentation of the enclosing list. */
print_line(".RS", MMAN_Bk_susp);
- (void)snprintf(buf, sizeof(buf), "%zun",
+ (void)snprintf(buf, sizeof(buf), "%dn",
Bl_stack[Bl_stack_len - 1]);
print_word(buf);
diff --git a/mdoc_term.c b/mdoc_term.c
index d8004b9a..0cdec271 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -49,7 +50,7 @@ struct termact {
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 *,
@@ -525,7 +526,7 @@ print_mdoc_head(struct termp *p, const void *arg)
free(volume);
}
-static size_t
+static int
a2width(const struct termp *p, const char *v)
{
struct roffsu su;
@@ -533,9 +534,7 @@ a2width(const struct termp *p, const char *v)
if (a2roffsu(v, &su, SCALE_MAX) < 2) {
SCALE_HS_INIT(&su, term_strlen(p, v));
su.scale /= term_strlen(p, "0");
- } else if (su.scale < 0.0)
- su.scale = 0.0;
-
+ }
return(term_hspan(p, &su));
}
@@ -606,10 +605,10 @@ termp_ll_pre(DECL_ARGS)
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) {
@@ -621,15 +620,46 @@ termp_it_pre(DECL_ARGS)
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:
@@ -684,39 +714,11 @@ termp_it_pre(DECL_ARGS)
* 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;
}
@@ -762,16 +764,16 @@ termp_it_pre(DECL_ARGS)
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;
@@ -860,7 +862,6 @@ termp_it_pre(DECL_ARGS)
case LIST_hyphen:
/* FALLTHROUGH */
case LIST_tag:
- assert(width);
if (MDOC_HEAD == n->type)
p->rmargin = p->offset + width;
else
@@ -1540,6 +1541,7 @@ termp_bd_pre(DECL_ARGS)
{
size_t tabwidth, lm, len, rm, rmax;
struct mdoc_node *nn;
+ int offset;
if (MDOC_BLOCK == n->type) {
print_bvspace(p, n, n);
@@ -1556,8 +1558,13 @@ termp_bd_pre(DECL_ARGS)
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
diff --git a/term.c b/term.c
index 3efc2709..61fe0c3b 100644
--- a/term.c
+++ b/term.c
@@ -273,7 +273,7 @@ term_flushln(struct termp *p)
}
if (TERMP_HANG & p->flags) {
- p->overstep = (int)(vis - maxvis +
+ p->overstep += (int)(p->offset + vis - p->rmargin +
p->trailspace * (*p->width)(p, ' '));
/*