-/* $Id: term.c,v 1.198 2011/09/18 14:14:15 schwarze Exp $ */
+/* $Id: term.c,v 1.205 2012/07/16 21:30:42 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2012 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 "term.h"
#include "main.h"
+static size_t cond_width(const struct termp *, int, int *);
static void adjbuf(struct termp *p, int);
static void bufferc(struct termp *, char);
static void encode(struct termp *, const char *, size_t);
*
* The following flags may be specified:
*
- * - TERMP_NOLPAD: when beginning to write the line, don't left-pad the
- * offset value. This is useful when doing columnar lists where the
- * prior column has right-padded.
- *
* - TERMP_NOBREAK: this is the most important and is used when making
- * columns. In short: don't print a newline and instead pad to the
- * right margin. Used in conjunction with TERMP_NOLPAD.
+ * 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: when padding, make sure there are at least two
- * space characters of padding. Otherwise, rather break the line.
+ * - TERMP_TWOSPACE: make sure there is room for at least two space
+ * characters of padding. Otherwise, rather break the line.
*
* - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
* the line is overrun, and don't pad-right if it's underrun.
*
* - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
- * overruning, instead save the position and continue at that point
+ * overrunning, instead save the position and continue at that point
* when the next invocation.
*
* In-line line breaking:
term_flushln(struct termp *p)
{
int 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 */
bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
/*
- * Indent the first line of a paragraph.
+ * Calculate the required amount of padding.
*/
- vbl = p->flags & TERMP_NOLPAD ? (size_t)0 : p->offset;
+ vbl = p->offset + p->overstep > p->viscol ?
+ p->offset + p->overstep - p->viscol : 0;
vis = vend = 0;
i = 0;
* Handle literal tab characters: collapse all
* subsequent tabs into a single huge set of spaces.
*/
+ ntab = 0;
while (i < p->col && '\t' == p->buf[i]) {
vend = (vis / p->tabwidth + 1) * p->tabwidth;
vbl += vend - vis;
vis = vend;
+ ntab++;
i++;
}
if (vend > bp && 0 == jhy && vis > 0) {
vend -= vis;
(*p->endline)(p);
+ p->viscol = 0;
if (TERMP_NOBREAK & p->flags) {
- p->viscol = p->rmargin;
- (*p->advance)(p, p->rmargin);
+ vbl = p->rmargin;
vend += p->rmargin - p->offset;
- } else {
- p->viscol = 0;
+ } else
vbl = p->offset;
- }
+
+ /* use pending tabs on the new line */
+
+ if (0 < ntab)
+ vbl += ntab * p->tabwidth;
/* Remove the p->overstep width. */
if (ASCII_HYPH == p->buf[i]) {
(*p->letter)(p, '-');
p->viscol += (*p->width)(p, '-');
- } else {
- (*p->letter)(p, p->buf[i]);
- p->viscol += (*p->width)(p, p->buf[i]);
+ continue;
}
+
+ (*p->letter)(p, p->buf[i]);
+ if (8 == p->buf[i])
+ p->viscol -= (*p->width)(p, p->buf[i-1]);
+ else
+ p->viscol += (*p->width)(p, p->buf[i]);
}
vis = vend;
}
* If there was trailing white space, it was not printed;
* so reset the cursor position accordingly.
*/
- vis -= vbl;
+ if (vis)
+ vis -= vbl;
p->col = 0;
p->overstep = 0;
p->overstep = (int)(vis - maxvis + (*p->width)(p, ' '));
/*
- * Behave exactly the same way as groff:
* If we have overstepped the margin, temporarily move
* it to the right and flag the rest of the line to be
* shorter.
- * If we landed right at the margin, be happy.
- * If we are one step before the margin, temporarily
- * move it one step LEFT and flag the rest of the line
- * to be longer.
*/
- if (p->overstep >= -1) {
- assert((int)maxvis + p->overstep >= 0);
- maxvis += (size_t)p->overstep;
- } else
+ if (p->overstep < 0)
p->overstep = 0;
+ return;
} else if (TERMP_DANGLE & p->flags)
return;
- /* Right-pad. */
- if (maxvis > vis +
+ /* If the column was overrun, break the line. */
+ if (maxvis <= vis +
((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) {
- p->viscol += maxvis - vis;
- (*p->advance)(p, maxvis - vis);
- vis += (maxvis - vis);
- } else { /* ...or newline break. */
(*p->endline)(p);
- p->viscol = p->rmargin;
- (*p->advance)(p, p->rmargin);
+ p->viscol = 0;
}
}
{
p->flags |= TERMP_NOSPACE;
- if (0 == p->col && 0 == p->viscol) {
- p->flags &= ~TERMP_NOLPAD;
- return;
- }
- term_flushln(p);
- p->flags &= ~TERMP_NOLPAD;
+ if (p->col || p->viscol)
+ term_flushln(p);
}
term_newln(p);
p->viscol = 0;
- (*p->endline)(p);
+ if (0 < p->skipvsp)
+ p->skipvsp--;
+ else
+ (*p->endline)(p);
}
void
p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM);
while ('\0' != *word) {
- if ((ssz = strcspn(word, "\\")) > 0)
+ if ('\\' != *word) {
+ if (TERMP_SKIPCHAR & p->flags) {
+ p->flags &= ~TERMP_SKIPCHAR;
+ word++;
+ continue;
+ }
+ ssz = strcspn(word, "\\");
encode(p, word, ssz);
-
- word += (int)ssz;
- if ('\\' != *word)
+ word += (int)ssz;
continue;
+ }
word++;
esc = mandoc_escape(&word, &seq, &sz);
term_fontlast(p);
break;
case (ESCAPE_NOSPACE):
- if ('\0' == *word)
+ if (TERMP_SKIPCHAR & p->flags)
+ p->flags &= ~TERMP_SKIPCHAR;
+ else if ('\0' == *word)
p->flags |= TERMP_NOSPACE;
break;
+ case (ESCAPE_SKIPCHAR):
+ p->flags |= TERMP_SKIPCHAR;
+ break;
default:
break;
}
{
enum termfont f;
+ if (TERMP_SKIPCHAR & p->flags) {
+ p->flags &= ~TERMP_SKIPCHAR;
+ return;
+ }
+
if (p->col + 4 >= p->maxcols)
adjbuf(p, p->col + 4);
enum termfont f;
int i, len;
+ if (TERMP_SKIPCHAR & p->flags) {
+ p->flags &= ~TERMP_SKIPCHAR;
+ return;
+ }
+
/* LINTED */
len = sz;
adjbuf(p, p->col + 1 + (len * 3));
for (i = 0; i < len; i++) {
- if ( ! isgraph((unsigned char)word[i])) {
+ if (ASCII_HYPH != word[i] &&
+ ! isgraph((unsigned char)word[i])) {
p->buf[p->col++] = word[i];
continue;
}
if (TERMFONT_UNDER == f)
p->buf[p->col++] = '_';
+ else if (ASCII_HYPH == word[i])
+ p->buf[p->col++] = '-';
else
p->buf[p->col++] = word[i];
return((*p->width)(p, ' ') * sz);
}
+static size_t
+cond_width(const struct termp *p, int c, int *skip)
+{
+
+ if (*skip) {
+ (*skip) = 0;
+ return(0);
+ } else
+ return((*p->width)(p, c));
+}
size_t
term_strlen(const struct termp *p, const char *cp)
{
size_t sz, rsz, i;
- int ssz, c;
+ int ssz, skip, c;
const char *seq, *rhs;
enum mandoc_esc esc;
static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
*/
sz = 0;
+ skip = 0;
while ('\0' != *cp) {
rsz = strcspn(cp, rej);
for (i = 0; i < rsz; i++)
- sz += (*p->width)(p, *cp++);
+ sz += cond_width(p, *cp++, &skip);
c = 0;
switch (*cp) {
(seq + 1, ssz - 1);
if ('\0' == c)
break;
- sz += (*p->width)(p, c);
+ sz += cond_width(p, c, &skip);
continue;
case (ESCAPE_SPECIAL):
c = mchars_spec2cp
(p->symtab, seq, ssz);
if (c <= 0)
break;
- sz += (*p->width)(p, c);
+ sz += cond_width(p, c, &skip);
continue;
default:
break;
switch (esc) {
case (ESCAPE_UNICODE):
- sz += (*p->width)(p, '?');
+ sz += cond_width(p, '?', &skip);
break;
case (ESCAPE_NUMBERED):
c = mchars_num2char(seq, ssz);
if ('\0' != c)
- sz += (*p->width)(p, c);
+ sz += cond_width(p, c, &skip);
break;
case (ESCAPE_SPECIAL):
rhs = mchars_spec2str
rhs = seq;
rsz = ssz;
break;
+ case (ESCAPE_SKIPCHAR):
+ skip = 1;
+ break;
default:
break;
}
if (NULL == rhs)
break;
+ if (skip) {
+ skip = 0;
+ break;
+ }
+
for (i = 0; i < rsz; i++)
sz += (*p->width)(p, *rhs++);
break;
case (ASCII_NBRSP):
- sz += (*p->width)(p, ' ');
+ sz += cond_width(p, ' ', &skip);
cp++;
break;
case (ASCII_HYPH):
- sz += (*p->width)(p, '-');
+ sz += cond_width(p, '-', &skip);
cp++;
break;
default: