-/* $Id: term.c,v 1.94 2009/07/27 12:02:49 kristaps Exp $ */
+/* $Id: term.c,v 1.111 2009/10/26 07:18:23 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
*
#include <stdlib.h>
#include <string.h>
+#include "chars.h"
+#include "out.h"
#include "term.h"
#include "man.h"
#include "mdoc.h"
+#include "main.h"
-extern int man_run(struct termp *,
- const struct man *);
-extern int mdoc_run(struct termp *,
- const struct mdoc *);
+/* FIXME: accomodate non-breaking, non-collapsing white-space. */
+/* FIXME: accomodate non-breaking, collapsing white-space. */
static struct termp *term_alloc(enum termenc);
static void term_free(struct termp *);
-static void term_pescape(struct termp *, const char **);
-static void term_nescape(struct termp *,
+
+static void do_escaped(struct termp *, const char **);
+static void do_special(struct termp *,
const char *, size_t);
-static void term_sescape(struct termp *,
+static void do_reserved(struct termp *,
const char *, size_t);
-static void term_chara(struct termp *, char);
-static void term_encodea(struct termp *, char);
-static int term_isopendelim(const char *);
-static int term_isclosedelim(const char *);
+static void buffer(struct termp *, char);
+static void encode(struct termp *, char);
void *
}
-int
-terminal_man(void *arg, const struct man *man)
-{
- struct termp *p;
-
- p = (struct termp *)arg;
- if (NULL == p->symtab)
- p->symtab = term_ascii2htab();
-
- return(man_run(p, man));
-}
-
-
-int
-terminal_mdoc(void *arg, const struct mdoc *mdoc)
-{
- struct termp *p;
-
- p = (struct termp *)arg;
- if (NULL == p->symtab)
- p->symtab = term_ascii2htab();
-
- return(mdoc_run(p, mdoc));
-}
-
-
void
terminal_free(void *arg)
{
if (p->buf)
free(p->buf);
- if (TERMENC_ASCII == p->enc && p->symtab)
- term_asciifree(p->symtab);
+ if (p->symtab)
+ chars_free(p->symtab);
free(p);
}
struct termp *p;
if (NULL == (p = malloc(sizeof(struct termp))))
- err(1, "malloc");
+ return(NULL);
bzero(p, sizeof(struct termp));
p->maxrmargin = 78;
p->enc = enc;
}
-static int
-term_isclosedelim(const char *p)
-{
-
- if ( ! (*p && 0 == *(p + 1)))
- return(0);
-
- switch (*p) {
- case('.'):
- /* FALLTHROUGH */
- case(','):
- /* FALLTHROUGH */
- case(';'):
- /* FALLTHROUGH */
- case(':'):
- /* FALLTHROUGH */
- case('?'):
- /* FALLTHROUGH */
- case('!'):
- /* FALLTHROUGH */
- case(')'):
- /* FALLTHROUGH */
- case(']'):
- /* FALLTHROUGH */
- case('}'):
- return(1);
- default:
- break;
- }
-
- return(0);
-}
-
-
-static int
-term_isopendelim(const char *p)
-{
-
- if ( ! (*p && 0 == *(p + 1)))
- return(0);
-
- switch (*p) {
- case('('):
- /* FALLTHROUGH */
- case('['):
- /* FALLTHROUGH */
- case('{'):
- return(1);
- default:
- break;
- }
-
- return(0);
-}
-
-
/*
* Flush a line of text. A "line" is loosely defined as being something
* that should be followed by a newline, regardless of whether it's
* Otherwise, the line will break at the right margin. Extremely long
* lines will cause the system to emit a warning (TODO: hyphenate, if
* possible).
- *
- * FIXME: newline breaks occur (in groff) also occur when a single
- * space follows a NOBREAK (try `Bl -tag')
- *
- * FIXME: there's a newline error where a `Bl -diag' will have a
- * trailing newline if the line is exactly 73 chars long.
*/
void
term_flushln(struct termp *p)
bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
vis = 0;
- overstep = 0;
/*
* If in the standard case (left-justified), then begin with our
putchar(' ');
vis = 0;
}
+ /* Remove the overstep width. */
+ bp += overstep;
+ overstep = 0;
} else {
for (j = 0; j < (int)vbl; j++)
putchar(' ');
}
vis += vsz;
}
+
p->col = 0;
+ overstep = 0;
if ( ! (TERMP_NOBREAK & p->flags)) {
putchar('\n');
}
-/*
- * Determine the symbol indicated by an escape sequences, that is, one
- * starting with a backslash. Once done, we pass this value into the
- * output buffer by way of the symbol table.
- */
static void
-term_nescape(struct termp *p, const char *word, size_t len)
+do_special(struct termp *p, const char *word, size_t len)
{
const char *rhs;
size_t sz;
int i;
- rhs = term_a2ascii(p->symtab, word, len, &sz);
+ rhs = chars_a2ascii(p->symtab, word, len, &sz);
- if (NULL == rhs)
+ if (NULL == rhs) {
+#if 0
+ fputs("Unknown special character: ", stderr);
+ for (i = 0; i < (int)len; i++)
+ fputc(word[i], stderr);
+ fputc('\n', stderr);
+#endif
return;
+ }
for (i = 0; i < (int)sz; i++)
- term_encodea(p, rhs[i]);
+ encode(p, rhs[i]);
}
static void
-term_sescape(struct termp *p, const char *word, size_t len)
+do_reserved(struct termp *p, const char *word, size_t len)
{
const char *rhs;
size_t sz;
int i;
- rhs = term_a2res(p->symtab, word, len, &sz);
+ rhs = chars_a2res(p->symtab, word, len, &sz);
- if (NULL == rhs)
+ if (NULL == rhs) {
+#if 0
+ fputs("Unknown reserved word: ", stderr);
+ for (i = 0; i < (int)len; i++)
+ fputc(word[i], stderr);
+ fputc('\n', stderr);
+#endif
return;
+ }
for (i = 0; i < (int)sz; i++)
- term_encodea(p, rhs[i]);
+ encode(p, rhs[i]);
}
* the escape sequence (we assert upon badly-formed escape sequences).
*/
static void
-term_pescape(struct termp *p, const char **word)
+do_escaped(struct termp *p, const char **word)
{
- int j;
+ int j, type;
const char *wp;
wp = *word;
+ type = 1;
if (0 == *(++wp)) {
*word = wp;
return;
}
- term_nescape(p, wp, 2);
+ do_special(p, wp, 2);
*word = ++wp;
return;
return;
}
- term_sescape(p, wp, 2);
+ do_reserved(p, wp, 2);
*word = ++wp;
return;
case ('['):
+ type = 0;
break;
default:
- term_sescape(p, wp, 1);
+ do_reserved(p, wp, 1);
*word = wp;
return;
}
switch (*wp) {
case ('B'):
- p->flags |= TERMP_BOLD;
+ p->bold++;
break;
case ('I'):
- p->flags |= TERMP_UNDER;
+ p->under++;
break;
case ('P'):
/* FALLTHROUGH */
case ('R'):
- p->flags &= ~TERMP_STYLE;
+ p->bold = p->under = 0;
break;
default:
break;
return;
} else if ('[' != *wp) {
- term_nescape(p, wp, 1);
+ do_special(p, wp, 1);
*word = wp;
return;
}
return;
}
- term_nescape(p, wp - j, (size_t)j);
+ if (type)
+ do_special(p, wp - j, (size_t)j);
+ else
+ do_reserved(p, wp - j, (size_t)j);
*word = wp;
}
{
const char *sv;
- if (term_isclosedelim(word))
- if ( ! (TERMP_IGNDELIM & p->flags))
- p->flags |= TERMP_NOSPACE;
+ sv = word;
+
+ if (word[0] && 0 == word[1])
+ switch (word[0]) {
+ case('.'):
+ /* FALLTHROUGH */
+ case(','):
+ /* FALLTHROUGH */
+ case(';'):
+ /* FALLTHROUGH */
+ case(':'):
+ /* FALLTHROUGH */
+ case('?'):
+ /* FALLTHROUGH */
+ case('!'):
+ /* FALLTHROUGH */
+ case(')'):
+ /* FALLTHROUGH */
+ case(']'):
+ /* FALLTHROUGH */
+ case('}'):
+ if ( ! (TERMP_IGNDELIM & p->flags))
+ p->flags |= TERMP_NOSPACE;
+ break;
+ default:
+ break;
+ }
if ( ! (TERMP_NOSPACE & p->flags))
- term_chara(p, ' ');
+ buffer(p, ' ');
if ( ! (p->flags & TERMP_NONOSPACE))
p->flags &= ~TERMP_NOSPACE;
- /*
- * If ANSI (word-length styling), then apply our style now,
- * before the word.
- */
-
- for (sv = word; *word; word++)
+ for ( ; *word; word++)
if ('\\' != *word)
- term_encodea(p, *word);
+ encode(p, *word);
else
- term_pescape(p, &word);
+ do_escaped(p, &word);
- if (term_isopendelim(sv))
- p->flags |= TERMP_NOSPACE;
+ if (sv[0] && 0 == sv[1])
+ switch (sv[0]) {
+ case('('):
+ /* FALLTHROUGH */
+ case('['):
+ /* FALLTHROUGH */
+ case('{'):
+ p->flags |= TERMP_NOSPACE;
+ break;
+ default:
+ break;
+ }
}
* size.
*/
static void
-term_chara(struct termp *p, char c)
+buffer(struct termp *p, char c)
{
size_t s;
s = p->maxcols * 2;
p->buf = realloc(p->buf, s);
if (NULL == p->buf)
- err(1, "realloc");
+ err(1, "realloc"); /* FIXME: shouldn't be here! */
p->maxcols = s;
}
p->buf[(int)(p->col)++] = c;
static void
-term_encodea(struct termp *p, char c)
+encode(struct termp *p, char c)
{
- if (' ' != c && TERMP_STYLE & p->flags) {
- if (TERMP_BOLD & p->flags) {
- term_chara(p, c);
- term_chara(p, 8);
+ if (' ' != c) {
+ if (p->under) {
+ buffer(p, '_');
+ buffer(p, 8);
}
- if (TERMP_UNDER & p->flags) {
- term_chara(p, '_');
- term_chara(p, 8);
+ if (p->bold) {
+ buffer(p, c);
+ buffer(p, 8);
}
}
- term_chara(p, c);
+ buffer(p, c);
}
+
+
+size_t
+term_vspan(const struct roffsu *su)
+{
+ double r;
+
+ switch (su->unit) {
+ case (SCALE_CM):
+ r = su->scale * 2;
+ break;
+ case (SCALE_IN):
+ r = su->scale * 6;
+ break;
+ case (SCALE_PC):
+ r = su->scale;
+ break;
+ case (SCALE_PT):
+ r = su->scale / 8;
+ break;
+ case (SCALE_MM):
+ r = su->scale / 1000;
+ break;
+ case (SCALE_VS):
+ r = su->scale;
+ break;
+ default:
+ r = su->scale - 1;
+ break;
+ }
+
+ if (r < 0.0)
+ r = 0.0;
+ return(/* LINTED */(size_t)
+ r);
+}
+
+
+size_t
+term_hspan(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;
+ }
+
+ if (r < 0.0)
+ r = 0.0;
+ return((size_t)/* LINTED */
+ r);
+}
+
+