-/* $Id: term.c,v 1.150 2010/06/26 15:36:37 kristaps Exp $ */
+/* $Id: term.c,v 1.167 2010/08/20 01:02:07 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 "term.h"
#include "main.h"
-static void spec(struct termp *, const char *, size_t);
+static void spec(struct termp *, enum roffdeco,
+ const char *, size_t);
static void res(struct termp *, const char *, size_t);
-static void buffera(struct termp *, const char *, size_t);
static void bufferc(struct termp *, char);
static void adjbuf(struct termp *p, size_t);
static void encode(struct termp *, const char *, size_t);
p = calloc(1, sizeof(struct termp));
if (NULL == p) {
perror(NULL);
- exit(EXIT_FAILURE);
+ exit(MANDOCLEVEL_SYSERR);
}
p->enc = enc;
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 */
- int j; /* temporary loop index */
- int jhy; /* last hyphen before line overflow */
- size_t maxvis, mmax;
+ int j; /* temporary loop index for p->buf */
+ int 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.
*/
vbl = p->flags & TERMP_NOLPAD ? 0 : p->offset;
- /*
- * FIXME: if bp is zero, we still output the first word before
- * breaking the line.
- */
-
vis = vend = i = 0;
- while (i < (int)p->col) {
+ while (i < (int)p->col) {
/*
- * Handle literal tab characters.
+ * Handle literal tab characters: collapse all
+ * subsequent tabs into a single huge set of spaces.
*/
for (j = i; j < (int)p->col; j++) {
if ('\t' != p->buf[j])
break;
- vend = (vis/p->tabwidth+1)*p->tabwidth;
+ vend = (vis / p->tabwidth + 1) * p->tabwidth;
vbl += vend - vis;
vis = vend;
}
for (jhy = 0; j < (int)p->col; j++) {
if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j])
break;
- if (8 != p->buf[j]) {
- if (vend > vis && vend < bp &&
- ASCII_HYPH == p->buf[j])
- jhy = j;
- vend++;
- } else
- vend--;
+
+ /* Back over the the last printed character. */
+ if (8 == p->buf[j]) {
+ assert(j);
+ vend -= (*p->width)(p, p->buf[j - 1]);
+ continue;
+ }
+
+ /* Regular word. */
+ /* Break at the hyphen point if we overrun. */
+ if (vend > vis && vend < bp &&
+ ASCII_HYPH == p->buf[j])
+ jhy = j;
+
+ vend += (*p->width)(p, p->buf[j]);
}
/*
if ('\t' == p->buf[i])
break;
if (' ' == p->buf[i]) {
- while (' ' == p->buf[i]) {
- vbl++;
+ j = i;
+ while (' ' == p->buf[i])
i++;
- }
+ vbl += (i - j) * (*p->width)(p, ' ');
break;
}
if (ASCII_NBRSP == p->buf[i]) {
- vbl++;
+ vbl += (*p->width)(p, ' ');
continue;
}
vbl = 0;
}
- if (ASCII_HYPH == p->buf[i])
+ if (ASCII_HYPH == p->buf[i]) {
(*p->letter)(p, '-');
- else
+ p->viscol += (*p->width)(p, '-');
+ } else {
(*p->letter)(p, p->buf[i]);
-
- p->viscol += 1;
+ p->viscol += (*p->width)(p, p->buf[i]);
+ }
}
vend += vbl;
vis = vend;
if (TERMP_HANG & p->flags) {
/* We need one blank after the tag. */
p->overstep = /* LINTED */
- vis - maxvis + 1;
+ vis - maxvis + (*p->width)(p, ' ');
/*
* Behave exactly the same way as groff:
/* Right-pad. */
if (maxvis > vis + /* LINTED */
- ((TERMP_TWOSPACE & p->flags) ? 1 : 0)) {
+ ((TERMP_TWOSPACE & p->flags) ?
+ (*p->width)(p, ' ') : 0)) {
p->viscol += maxvis - vis;
(*p->advance)(p, maxvis - vis);
vis += (maxvis - vis);
static void
-spec(struct termp *p, const char *word, size_t len)
+spec(struct termp *p, enum roffdeco d, const char *word, size_t len)
{
const char *rhs;
size_t sz;
- rhs = chars_a2ascii(p->symtab, word, len, &sz);
+ rhs = chars_spec2str(p->symtab, word, len, &sz);
if (rhs)
encode(p, rhs, sz);
+ else if (DECO_SSPECIAL == d)
+ encode(p, word, len);
}
const char *rhs;
size_t sz;
- rhs = chars_a2res(p->symtab, word, len, &sz);
+ rhs = chars_res2str(p->symtab, word, len, &sz);
if (rhs)
encode(p, rhs, sz);
}
}
if ( ! (TERMP_NOSPACE & p->flags)) {
- bufferc(p, ' ');
- if (TERMP_SENTENCE & p->flags)
+ if ( ! (TERMP_KEEP & p->flags)) {
+ if (TERMP_PREKEEP & p->flags)
+ p->flags |= TERMP_KEEP;
bufferc(p, ' ');
+ if (TERMP_SENTENCE & p->flags)
+ bufferc(p, ' ');
+ } else
+ bufferc(p, ASCII_NBRSP);
}
if ( ! (p->flags & TERMP_NONOSPACE))
p->flags &= ~TERMP_NOSPACE;
+ else
+ p->flags |= TERMP_NOSPACE;
p->flags &= ~TERMP_SENTENCE;
- /* FIXME: use strcspn. */
-
while (*word) {
- if ('\\' != *word) {
- encode(p, word, 1);
- word++;
+ if ((ssz = strcspn(word, "\\")) > 0)
+ encode(p, word, ssz);
+
+ word += ssz;
+ if ('\\' != *word)
continue;
- }
seq = ++word;
sz = a2roffdeco(&deco, &seq, &ssz);
res(p, seq, ssz);
break;
case (DECO_SPECIAL):
- spec(p, seq, ssz);
+ /* FALLTHROUGH */
+ case (DECO_SSPECIAL):
+ spec(p, deco, seq, ssz);
break;
case (DECO_BOLD):
term_fontrepl(p, TERMFONT_BOLD);
* Note that we don't process the pipe: the parser sees it as
* punctuation, but we don't in terms of typography.
*/
- if (sv[0] && 0 == sv[1])
+ if (sv[0] && '\0' == sv[1])
switch (sv[0]) {
case('('):
/* FALLTHROUGH */
p->buf = realloc(p->buf, p->maxcols);
if (NULL == p->buf) {
perror(NULL);
- exit(EXIT_FAILURE);
+ exit(MANDOCLEVEL_SYSERR);
}
}
-static void
-buffera(struct termp *p, const char *word, size_t sz)
-{
-
- if (p->col + sz >= p->maxcols)
- adjbuf(p, p->col + sz);
-
- memcpy(&p->buf[(int)p->col], word, sz);
- p->col += sz;
-}
-
-
static void
bufferc(struct termp *p, char c)
{
*/
if (TERMFONT_NONE == (f = term_fonttop(p))) {
- buffera(p, word, sz);
+ if (p->col + sz >= p->maxcols)
+ adjbuf(p, p->col + sz);
+ memcpy(&p->buf[(int)p->col], word, sz);
+ p->col += sz;
return;
}
+ /* Pre-buffer, assuming worst-case. */
+
+ if (p->col + 1 + (sz * 3) >= p->maxcols)
+ adjbuf(p, p->col + 1 + (sz * 3));
+
for (i = 0; i < (int)sz; i++) {
if ( ! isgraph((u_char)word[i])) {
- bufferc(p, word[i]);
+ p->buf[(int)p->col++] = word[i];
continue;
}
if (TERMFONT_UNDER == f)
- bufferc(p, '_');
+ p->buf[(int)p->col++] = '_';
else
- bufferc(p, word[i]);
+ p->buf[(int)p->col++] = word[i];
- bufferc(p, 8);
- bufferc(p, word[i]);
+ p->buf[(int)p->col++] = 8;
+ p->buf[(int)p->col++] = word[i];
}
}
}
+/* ARGSUSED */
size_t
term_vspan(const struct termp *p, const struct roffsu *su)
{
size_t
term_hspan(const struct termp *p, const struct roffsu *su)
{
- double r;
-
- /* XXX: CM, IN, and PT are approximations. */
-
- switch (su->unit) {
- case (SCALE_CM):
- r = 4 * su->scale;
- break;
- case (SCALE_IN):
- /* XXX: this is an approximation. */
- r = 10 * su->scale;
- break;
- case (SCALE_PC):
- r = (10 * su->scale) / 6;
- break;
- case (SCALE_PT):
- r = (10 * su->scale) / 72;
- break;
- case (SCALE_MM):
- r = su->scale / 1000; /* FIXME: double-check. */
- break;
- case (SCALE_VS):
- r = su->scale * 2 - 1; /* FIXME: double-check. */
- break;
- default:
- r = su->scale;
- break;
- }
+ double v;
- if (r < 0.0)
- r = 0.0;
- return((size_t)/* LINTED */
- r);
+ v = ((*p->hspan)(p, su));
+ if (v < 0.0)
+ v = 0.0;
+ return((size_t) /* LINTED */
+ v);
}
-
-