-/* $Id: term.c,v 1.209 2013/08/08 20:07:47 schwarze Exp $ */
+/* $Id: term.c,v 1.217 2014/03/13 19:23:50 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 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 "main.h"
static size_t cond_width(const struct termp *, int, int *);
-static void adjbuf(struct termp *p, int);
+static void adjbuf(struct termp *p, size_t);
static void bufferc(struct termp *, char);
static void encode(struct termp *, const char *, size_t);
static void encode1(struct termp *, int);
* - TERMP_NOBREAK: this is the most important and is used when making
* columns. In short: don't print a newline and instead expect the
* next call to do the padding up to the start of the next column.
- *
- * - TERMP_TWOSPACE: make sure there is room for at least two space
- * characters of padding. Otherwise, rather break the line.
+ * p->trailspace may be set to 0, 1, or 2, depending on how many
+ * space characters are required at the end of the column.
*
* - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
* the line is overrun, and don't pad-right if it's underrun.
void
term_flushln(struct termp *p)
{
- int i; /* current input position in p->buf */
+ size_t i; /* current input position in p->buf */
int ntab; /* number of tabs to prepend */
size_t vis; /* current visual position on output */
size_t vbl; /* number of blanks to prepend to output */
size_t vend; /* end of word visual position on output */
size_t bp; /* visual right border position */
size_t dv; /* temporary for visual pos calculations */
- int j; /* temporary loop index for p->buf */
- int jhy; /* last hyph before overflow w/r/t j */
+ size_t j; /* temporary loop index for p->buf */
+ size_t jhy; /* last hyph before overflow w/r/t j */
size_t maxvis; /* output position of visible boundary */
size_t mmax; /* used in calculating bp */
* First, establish the maximum columns of "visible" content.
* This is usually the difference between the right-margin and
* an indentation, but can be, for tagged lists or columns, a
- * small set of values.
+ * small set of values.
+ *
+ * The following unsigned-signed subtractions look strange,
+ * but they are actually correct. If the int p->overstep
+ * is negative, it gets sign extended. Subtracting that
+ * very large size_t effectively adds a small number to dv.
*/
assert (p->rmargin >= p->offset);
dv = p->rmargin - p->offset;
/* Regular word. */
/* Break at the hyphen point if we overrun. */
if (vend > vis && vend < bp &&
- ASCII_HYPH == p->buf[j])
+ (ASCII_HYPH == p->buf[j] ||
+ ASCII_BREAK == p->buf[j]))
jhy = j;
+ /*
+ * Hyphenation now decided, put back a real
+ * hyphen such that we get the correct width.
+ */
+ if (ASCII_HYPH == p->buf[j])
+ p->buf[j] = '-';
+
vend += (*p->width)(p, p->buf[j]);
}
if (0 < ntab)
vbl += ntab * p->tabwidth;
- /* Remove the p->overstep width. */
+ /*
+ * Remove the p->overstep width.
+ * Again, if p->overstep is negative,
+ * sign extension does the right thing.
+ */
bp += (size_t)p->overstep;
p->overstep = 0;
j = i;
while (' ' == p->buf[i])
i++;
- dv = (size_t)(i - j) * (*p->width)(p, ' ');
+ dv = (i - j) * (*p->width)(p, ' ');
vbl += dv;
vend += dv;
break;
vbl += (*p->width)(p, ' ');
continue;
}
+ if (ASCII_BREAK == p->buf[i])
+ continue;
/*
* Now we definitely know there will be
vbl = 0;
}
- if (ASCII_HYPH == p->buf[i]) {
- (*p->letter)(p, '-');
- p->viscol += (*p->width)(p, '-');
- continue;
- }
-
(*p->letter)(p, p->buf[i]);
if (8 == p->buf[i])
p->viscol -= (*p->width)(p, p->buf[i-1]);
}
if (TERMP_HANG & p->flags) {
- /* We need one blank after the tag. */
- p->overstep = (int)(vis - maxvis + (*p->width)(p, ' '));
+ p->overstep = (int)(vis - maxvis +
+ p->trailspace * (*p->width)(p, ' '));
/*
* If we have overstepped the margin, temporarily move
* it to the right and flag the rest of the line to be
* shorter.
+ * If there is a request to keep the columns together,
+ * allow negative overstep when the column is not full.
*/
- if (p->overstep < 0)
+ if (p->trailspace && p->overstep < 0)
p->overstep = 0;
return;
return;
/* If the column was overrun, break the line. */
- if (maxvis <= vis +
- ((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) {
+ if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) {
(*p->endline)(p);
p->viscol = 0;
}
void
term_word(struct termp *p, const char *word)
{
+ const char nbrsp[2] = { ASCII_NBRSP, 0 };
const char *seq, *cp;
char c;
int sz, uc;
else
p->flags |= TERMP_NOSPACE;
- p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM);
+ p->flags &= ~TERMP_SENTENCE;
while ('\0' != *word) {
if ('\\' != *word) {
word++;
continue;
}
- ssz = strcspn(word, "\\");
+ if (TERMP_NBRWORD & p->flags) {
+ if (' ' == *word) {
+ encode(p, nbrsp, 1);
+ word++;
+ continue;
+ }
+ ssz = strcspn(word, "\\ ");
+ } else
+ ssz = strcspn(word, "\\");
encode(p, word, ssz);
word += (int)ssz;
continue;
break;
}
}
+ p->flags &= ~TERMP_NBRWORD;
}
static void
-adjbuf(struct termp *p, int sz)
+adjbuf(struct termp *p, size_t sz)
{
if (0 == p->maxcols)
while (sz >= p->maxcols)
p->maxcols <<= 2;
- p->buf = mandoc_realloc
- (p->buf, sizeof(int) * (size_t)p->maxcols);
+ p->buf = mandoc_realloc(p->buf, sizeof(int) * p->maxcols);
}
static void
static void
encode(struct termp *p, const char *word, size_t sz)
{
- int i, len;
+ size_t i;
if (TERMP_SKIPCHAR & p->flags) {
p->flags &= ~TERMP_SKIPCHAR;
return;
}
- /* LINTED */
- len = sz;
-
/*
* Encode and buffer a string of characters. If the current
* font mode is unset, buffer directly, else encode then buffer
*/
if (TERMFONT_NONE == term_fonttop(p)) {
- if (p->col + len >= p->maxcols)
- adjbuf(p, p->col + len);
- for (i = 0; i < len; i++)
+ if (p->col + sz >= p->maxcols)
+ adjbuf(p, p->col + sz);
+ for (i = 0; i < sz; i++)
p->buf[p->col++] = word[i];
return;
}
/* Pre-buffer, assuming worst-case. */
- if (p->col + 1 + (len * 5) >= p->maxcols)
- adjbuf(p, p->col + 1 + (len * 5));
+ if (p->col + 1 + (sz * 5) >= p->maxcols)
+ adjbuf(p, p->col + 1 + (sz * 5));
- for (i = 0; i < len; i++) {
+ for (i = 0; i < sz; i++) {
if (ASCII_HYPH == word[i] ||
isgraph((unsigned char)word[i]))
encode1(p, word[i]);
int ssz, skip, c;
const char *seq, *rhs;
enum mandoc_esc esc;
- static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
+ static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH,
+ ASCII_BREAK, '\0' };
/*
* Account for escaped sequences within string length
for (i = 0; i < rsz; i++)
sz += cond_width(p, *cp++, &skip);
- c = 0;
switch (*cp) {
case ('\\'):
cp++;
case (ASCII_HYPH):
sz += cond_width(p, '-', &skip);
cp++;
+ /* FALLTHROUGH */
+ case (ASCII_BREAK):
break;
default:
break;