summaryrefslogtreecommitdiffstats
path: root/term.c
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2009-02-21 14:56:57 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2009-02-21 14:56:57 +0000
commit3f750ebfbcf6d91d72265ebaf5febeeb85e41eaf (patch)
tree7255261bafe6c53c25207137d3385112ec8d13de /term.c
parentab7f2d17f8d8e211aab2a91883bc0f5358f306ac (diff)
downloadmandoc-3f750ebfbcf6d91d72265ebaf5febeeb85e41eaf.tar.gz
Initial list support (not nested, yet).
Diffstat (limited to 'term.c')
-rw-r--r--term.c369
1 files changed, 282 insertions, 87 deletions
diff --git a/term.c b/term.c
index 9b97736e..6852b4b6 100644
--- a/term.c
+++ b/term.c
@@ -28,7 +28,6 @@
#include "private.h"
-
enum termesc {
ESC_CLEAR,
ESC_BOLD,
@@ -36,14 +35,17 @@ enum termesc {
};
struct termp {
- size_t maxvisible;
+ size_t rmargin;
+ size_t maxrmargin;
size_t maxcols;
- size_t indent;
+ size_t offset;
size_t col;
int flags;
-#define TERMP_BOLD (1 << 0)
-#define TERMP_UNDERLINE (1 << 1)
-#define TERMP_NOSPACE (1 << 2)
+#define TERMP_BOLD (1 << 0) /* Embolden words. */
+#define TERMP_UNDERLINE (1 << 1) /* Underline words. */
+#define TERMP_NOSPACE (1 << 2) /* No space before words. */
+#define TERMP_NOLPAD (1 << 3) /* No left-padding. */
+#define TERMP_NOBREAK (1 << 4) /* No break after line */
char *buf;
};
@@ -64,53 +66,42 @@ static void termprint_header(struct termp *,
static void termprint_footer(struct termp *,
const struct mdoc_meta *);
+static int arg_hasattr(int, size_t,
+ const struct mdoc_arg *);
+static int arg_getattr(int, size_t,
+ const struct mdoc_arg *);
+
static void newln(struct termp *);
static void vspace(struct termp *);
static void pword(struct termp *, const char *, size_t);
static void word(struct termp *, const char *);
-static int termp_it_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_ns_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_pp_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_fl_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_op_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_op_post(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_bl_post(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_sh_post(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_sh_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_nd_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_bold_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_under_pre(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_bold_post(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static int termp_under_post(struct termp *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
+#define decl_prepost(name, suffix) \
+static int name##_##suffix(struct termp *, \
+ const struct mdoc_meta *, \
+ const struct mdoc_node *)
+
+#define decl_pre(name) decl_prepost(name, pre)
+#define decl_post(name) decl_prepost(name, post)
+
+decl_pre(termp_fl);
+decl_pre(termp_it);
+decl_pre(termp_nd);
+decl_pre(termp_ns);
+decl_pre(termp_op);
+decl_pre(termp_pp);
+decl_pre(termp_sh);
+
+decl_post(termp_bl);
+decl_post(termp_it);
+decl_post(termp_op);
+decl_post(termp_sh);
+
+decl_pre(termp_bold);
+decl_pre(termp_under);
+
+decl_post(termp_bold);
+decl_post(termp_under);
const struct termact termacts[MDOC_MAX] = {
{ NULL, NULL }, /* \" */
@@ -126,7 +117,7 @@ const struct termact termacts[MDOC_MAX] = {
{ NULL, NULL }, /* Ed */
{ NULL, termp_bl_post }, /* Bl */
{ NULL, NULL }, /* El */
- { termp_it_pre, NULL }, /* It */
+ { termp_it_pre, termp_it_post }, /* It */
{ NULL, NULL }, /* Ad */
{ NULL, NULL }, /* An */
{ termp_under_pre, termp_under_post }, /* Ar */
@@ -222,18 +213,61 @@ const struct termact termacts[MDOC_MAX] = {
};
+static int
+arg_hasattr(int arg, size_t argc, const struct mdoc_arg *argv)
+{
+
+ return(-1 != arg_getattr(arg, argc, argv));
+}
+
+
+static int
+arg_getattr(int arg, size_t argc, const struct mdoc_arg *argv)
+{
+ int i;
+
+ for (i = 0; i < (int)argc; i++)
+ if (argv[i].arg == arg)
+ return(i);
+ return(-1);
+}
+
+
static void
-flush(struct termp *p)
+flushln(struct termp *p)
{
size_t i, j, vsz, vis, maxvis;
- maxvis = p->maxvisible - (p->indent * 4);
+ /*
+ * 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.
+ */
+
+ assert(p->offset < p->rmargin);
+ maxvis = p->rmargin - p->offset;
vis = 0;
- for (j = 0; j < (p->indent * 4); j++)
- putchar(' ');
+ /*
+ * If in the standard case (left-justified), then begin with our
+ * indentation, otherwise (columns, etc.) just start spitting
+ * out text.
+ */
+
+ if ( ! (p->flags & TERMP_NOLPAD))
+ /* LINTED */
+ for (j = 0; j < p->offset; j++)
+ putchar(' ');
for (i = 0; i < p->col; i++) {
+ /*
+ * Count up visible word characters. Control sequences
+ * (starting with the CSI) aren't counted.
+ */
+ assert( ! isspace(p->buf[i]));
+
+ /* LINTED */
for (j = i, vsz = 0; j < p->col; j++) {
if (isspace(p->buf[j]))
break;
@@ -245,12 +279,31 @@ flush(struct termp *p)
}
assert(vsz > 0);
+ /*
+ * If a word is too long and we're within a line, put it
+ * on the next line. Puke if we're being asked to write
+ * something that will exceed the right margin (i.e.,
+ * from a fresh line or when we're not allowed to break
+ * the line with TERMP_NOBREAK).
+ */
+
if (vis && vis + vsz >= maxvis) {
+ /* FIXME */
+ if (p->flags & TERMP_NOBREAK)
+ errx(1, "word breaks right margin");
putchar('\n');
- for (j = 0; j < (p->indent * 4); j++)
+ for (j = 0; j < p->offset; j++)
putchar(' ');
vis = 0;
- }
+ } else if (vis + vsz >= maxvis) {
+ /* FIXME */
+ errx(1, "word breaks right margin");
+ }
+
+ /*
+ * Write out the word and a trailing space. Omit the
+ * space if we're the last word in the line.
+ */
for ( ; i < p->col; i++) {
if (isspace(p->buf[i]))
@@ -264,7 +317,17 @@ flush(struct termp *p)
}
}
- putchar('\n');
+ /*
+ * If we're not to right-marginalise it (newline), then instead
+ * pad to the right margin and stay off.
+ */
+
+ if (p->flags & TERMP_NOBREAK) {
+ for ( ; vis <= maxvis; vis++)
+ putchar(' ');
+ } else
+ putchar('\n');
+
p->col = 0;
}
@@ -273,10 +336,14 @@ static void
newln(struct termp *p)
{
+ /*
+ * A newline only breaks an existing line; it won't assert
+ * vertical space.
+ */
p->flags |= TERMP_NOSPACE;
if (0 == p->col)
return;
- flush(p);
+ flushln(p);
}
@@ -284,6 +351,10 @@ static void
vspace(struct termp *p)
{
+ /*
+ * Asserts a vertical space (a full, empty line-break between
+ * lines).
+ */
newln(p);
putchar('\n');
}
@@ -293,9 +364,9 @@ static void
chara(struct termp *p, char c)
{
+ /* TODO: dynamically expand the buffer. */
if (p->col + 1 >= p->maxcols)
errx(1, "line overrun");
-
p->buf[(p->col)++] = c;
}
@@ -344,6 +415,8 @@ pword(struct termp *p, const char *word, size_t len)
if (p->flags & TERMP_UNDERLINE)
escape(p, ESC_UNDERLINE);
+ /* TODO: escape patterns. */
+
for (i = 0; i < len; i++)
chara(p, word[i]);
@@ -358,11 +431,13 @@ word(struct termp *p, const char *word)
{
size_t i, j, len;
- /* TODO: delimiters? */
+ if (mdoc_isdelim(word))
+ p->flags |= TERMP_NOSPACE;
len = strlen(word);
assert(len > 0);
+ /* LINTED */
for (j = i = 0; i < len; i++) {
if ( ! isspace(word[i])) {
j++;
@@ -381,23 +456,130 @@ word(struct termp *p, const char *word)
}
+/* ARGSUSED */
static int
-termp_it_pre(struct termp *p, const struct mdoc_meta *meta,
+termp_it_post(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
{
+ const struct mdoc_node *n, *it;
+ const struct mdoc_block *bl;
+ int i;
+ size_t width;
switch (node->type) {
+ case (MDOC_BODY):
+ /* FALLTHROUGH */
case (MDOC_HEAD):
- /* TODO: only print one, if compat. */
- vspace(p);
break;
default:
+ return(1);
+ }
+
+ it = node->parent;
+ assert(MDOC_BLOCK == it->type);
+ assert(MDOC_It == it->tok);
+
+ n = it->parent;
+ assert(MDOC_BODY == n->type);
+ assert(MDOC_Bl == n->tok);
+ n = n->parent;
+ bl = &n->data.block;
+
+ /* If `-tag', adjust our margins accordingly. */
+
+ if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
+ i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
+ assert(i >= 0);
+ assert(1 == bl->argv[i].sz);
+ width = strlen(*bl->argv[i].value); /* XXX */
+
+ if (MDOC_HEAD == node->type) {
+ flushln(p);
+ /* FIXME: nested lists. */
+ p->rmargin = p->maxrmargin;
+ p->flags &= ~TERMP_NOBREAK;
+ } else {
+ flushln(p);
+ p->offset -= width + 1;
+ p->flags &= ~TERMP_NOLPAD;
+ }
+ }
+
+ return(1);
+}
+
+
+/* ARGSUSED */
+static int
+termp_it_pre(struct termp *p, const struct mdoc_meta *meta,
+ const struct mdoc_node *node)
+{
+ const struct mdoc_node *n, *it;
+ const struct mdoc_block *bl;
+ int i;
+ size_t width;
+
+ switch (node->type) {
+ case (MDOC_BODY):
+ /* FALLTHROUGH */
+ case (MDOC_HEAD):
+ it = node->parent;
+ break;
+ case (MDOC_BLOCK):
+ it = node;
break;
+ default:
+ return(1);
+ }
+
+ assert(MDOC_BLOCK == it->type);
+ assert(MDOC_It == it->tok);
+
+ n = it->parent;
+ assert(MDOC_BODY == n->type);
+ assert(MDOC_Bl == n->tok);
+ n = n->parent;
+ bl = &n->data.block;
+
+ /* If `-compact', don't assert vertical space. */
+
+ if (MDOC_BLOCK == node->type) {
+ if (arg_hasattr(MDOC_Compact, bl->argc, bl->argv))
+ newln(p);
+ else
+ vspace(p);
+ return(1);
+ }
+
+ assert(MDOC_HEAD == node->type
+ || MDOC_BODY == node->type);
+
+ /* If `-tag', adjust our margins accordingly. */
+
+ if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
+ i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
+ assert(i >= 0); /* XXX */
+ assert(1 == bl->argv[i].sz);
+ width = strlen(*bl->argv[i].value); /* XXX */
+
+ /* FIXME: nested lists. */
+
+ if (MDOC_HEAD == node->type) {
+ p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOSPACE;
+ p->rmargin = p->offset + width;
+ } else {
+ p->flags |= TERMP_NOSPACE;
+ p->flags |= TERMP_NOLPAD;
+ p->offset += width + 1;
+ }
}
+
return(1);
}
+/* ARGSUSED */
static int
termp_bold_post(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -408,6 +590,7 @@ termp_bold_post(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_under_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -418,6 +601,7 @@ termp_under_pre(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_bold_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -428,6 +612,7 @@ termp_bold_pre(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_ns_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -438,6 +623,7 @@ termp_ns_pre(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_pp_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -448,6 +634,7 @@ termp_pp_pre(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_under_post(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -458,6 +645,7 @@ termp_under_post(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_nd_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -468,6 +656,7 @@ termp_nd_pre(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_bl_post(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -484,6 +673,7 @@ termp_bl_post(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_op_post(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -501,6 +691,7 @@ termp_op_post(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_sh_post(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -513,7 +704,7 @@ termp_sh_post(struct termp *p, const struct mdoc_meta *meta,
break;
case (MDOC_BODY):
newln(p);
- (p->indent)--;
+ p->offset -= 4;
break;
default:
break;
@@ -522,6 +713,7 @@ termp_sh_post(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_sh_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -533,7 +725,7 @@ termp_sh_pre(struct termp *p, const struct mdoc_meta *meta,
p->flags |= TERMP_BOLD;
break;
case (MDOC_BODY):
- (p->indent)++;
+ p->offset += 4;
break;
default:
break;
@@ -542,6 +734,7 @@ termp_sh_pre(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_op_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -559,6 +752,7 @@ termp_op_pre(struct termp *p, const struct mdoc_meta *meta,
}
+/* ARGSUSED */
static int
termp_fl_pre(struct termp *p, const struct mdoc_meta *meta,
const struct mdoc_node *node)
@@ -630,27 +824,27 @@ termprint_footer(struct termp *p, const struct mdoc_meta *meta)
char *buf, *os;
size_t sz, osz, ssz, i;
- if (NULL == (buf = malloc(p->maxvisible)))
+ if (NULL == (buf = malloc(p->rmargin)))
err(1, "malloc");
- if (NULL == (os = malloc(p->maxvisible)))
+ if (NULL == (os = malloc(p->rmargin)))
err(1, "malloc");
tm = localtime(&meta->date);
- if (NULL == strftime(buf, p->maxvisible, "%B %d, %Y", tm))
+ if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
err(1, "strftime");
- osz = strlcpy(os, meta->os, p->maxvisible);
+ osz = strlcpy(os, meta->os, p->rmargin);
sz = strlen(buf);
ssz = sz + osz + 1;
- if (ssz > p->maxvisible) {
- ssz -= p->maxvisible;
+ if (ssz > p->rmargin) {
+ ssz -= p->rmargin;
assert(ssz <= osz);
os[osz - ssz] = 0;
ssz = 1;
} else
- ssz = p->maxvisible - ssz + 1;
+ ssz = p->rmargin - ssz + 1;
printf("\n");
printf("%s", os);
@@ -671,9 +865,9 @@ termprint_header(struct termp *p, const struct mdoc_meta *meta)
char *msec, *buf, *title, *pp;
size_t ssz, tsz, ttsz, i;;
- if (NULL == (buf = malloc(p->maxvisible)))
+ if (NULL == (buf = malloc(p->rmargin)))
err(1, "malloc");
- if (NULL == (title = malloc(p->maxvisible)))
+ if (NULL == (title = malloc(p->rmargin)))
err(1, "malloc");
if (NULL == (pp = mdoc_vol2a(meta->vol)))
@@ -708,27 +902,27 @@ termprint_header(struct termp *p, const struct mdoc_meta *meta)
}
assert(pp);
- tsz = strlcpy(buf, pp, p->maxvisible);
- assert(tsz < p->maxvisible);
+ tsz = strlcpy(buf, pp, p->rmargin);
+ assert(tsz < p->rmargin);
if ((pp = mdoc_arch2a(meta->arch))) {
- tsz = strlcat(buf, " (", p->maxvisible);
- assert(tsz < p->maxvisible);
- tsz = strlcat(buf, pp, p->maxvisible);
- assert(tsz < p->maxvisible);
- tsz = strlcat(buf, ")", p->maxvisible);
- assert(tsz < p->maxvisible);
+ tsz = strlcat(buf, " (", p->rmargin);
+ assert(tsz < p->rmargin);
+ tsz = strlcat(buf, pp, p->rmargin);
+ assert(tsz < p->rmargin);
+ tsz = strlcat(buf, ")", p->rmargin);
+ assert(tsz < p->rmargin);
}
- ttsz = strlcpy(title, meta->title, p->maxvisible);
+ ttsz = strlcpy(title, meta->title, p->rmargin);
if (NULL == (msec = mdoc_msec2a(meta->msec)))
msec = "";
ssz = (2 * (ttsz + 2 + strlen(msec))) + tsz + 2;
- if (ssz > p->maxvisible) {
- if ((ssz -= p->maxvisible) % 2)
+ if (ssz > p->rmargin) {
+ if ((ssz -= p->rmargin) % 2)
ssz++;
ssz /= 2;
@@ -736,7 +930,7 @@ termprint_header(struct termp *p, const struct mdoc_meta *meta)
title[ttsz - ssz] = 0;
ssz = 1;
} else
- ssz = ((p->maxvisible - ssz) / 2) + 1;
+ ssz = ((p->rmargin - ssz) / 2) + 1;
printf("%s(%s)", title, msec);
@@ -765,9 +959,10 @@ termprint(const struct mdoc_node *node,
if (ERR == setupterm(NULL, STDOUT_FILENO, NULL))
return(0);
- p.maxvisible = columns < 60 ? 60 : (size_t)columns;
+ p.maxrmargin = columns < 60 ? 60 : (size_t)columns;
+ p.rmargin = p.maxrmargin;
p.maxcols = 1024;
- p.indent = p.col = 0;
+ p.offset = p.col = 0;
p.flags = TERMP_NOSPACE;
if (NULL == (p.buf = malloc(p.maxcols)))