* integrate tbl into mandoc
@ 2010-10-13 0:46 Ingo Schwarze
2010-10-14 21:18 ` Ingo Schwarze
0 siblings, 1 reply; 7+ messages in thread
From: Ingo Schwarze @ 2010-10-13 0:46 UTC (permalink / raw)
To: tech
Hi,
i should like to remove groff out of the OpenBSD tree as soon as
possible. I was slacking: we should not wait until the 4.9 release
comes close.
The last holdup is that we still need groff to format about one or
two dozens of manuals using tbl(1) syntax. Thus, i am trying to get
mandoc to deal with tbl(1) as quickly as possible.
During EuroBSDCon last weekend, i discussed various approaches to get
this done with Joerg Sonnenberger and Marc Espie.
With Joerg, i came to the conclusion that it would be most rigorous
to do tbl parsing before roff parsing, because when using groff,
tbl output is piped into nroff, so that's the proper order.
On the other hand, i now looked at Kristaps' actual tbl code and it
turns out that a clean solution portable to various frontends will
rather be to put the tbl parser alongside the outher parsers, adding
its AST output to the other ASTs, and to put the tbl output frontend
alongside the other frontends. Unfortunately, that is hard to do
when parsing tbl before roff: It would mean to have the tbl ASTs
before having the man AST ready to hook it into.
Thus, for now, here is a proposal to implement the .TS/.TE macros
in libman and call the tbl parser and frontend from the man code.
The same can of course be done for mdoc.
The files are completely unchanged with respect to Kristaps'
latest published version, tbl-0.1.5.
Here, i'm just showing the glue.
Note that this patch applies to OpenBSD, not to bsd.lv.
As i said, i hope to get it in quickly, even if we do not merge
the same to mdocml.bsd.lv, and even if we have to do more cleanup
later.
One thing to do before commit is probably to replace the printfs
in the output frontend by calls into term.c, such that indentation
is respected and escape sequences get resolved. There may be more
i need to do.
The following already look semi-useful with this:
/usr/src/lib/libcurses/curs_attr.3tbl
/usr/src/lib/libcurses/curs_getch.3tbl
/usr/src/lib/libcurses/curses.3tbl
/usr/src/usr.bin/infocmp/infocmp.1tbl
The following still crash:
/usr/src/lib/libcurses/curs_addch.3tbl
/usr/src/lib/libcurses/curs_inch.3tbl
/usr/src/lib/libcurses/curs_mouse.3tbl
/usr/src/lib/libform/form.3tbl
/usr/src/lib/libmenu/menu.3tbl
/usr/src/usr.bin/tic/captoinfo.1tbl
/usr/src/gnu/usr.sbin/mkhybrid/src/mkhybrid.8tbl
The following have a tbl extension, but no .TS:
/usr/src/lib/libcurses/term.5tbl
The following are mdoc(7) with tbl:
/usr/src/share/man/man4/wi.4tbl
/usr/src/share/man/man4/man4.hppa/cpu.4tbl
/usr/src/games/phantasia/phantasia.6tbl
Thoughts?
Ingo
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/Makefile,v
retrieving revision 1.45
diff -u -p -r1.45 Makefile
--- Makefile 27 Sep 2010 21:25:28 -0000 1.45
+++ Makefile 12 Oct 2010 23:37:36 -0000
@@ -20,6 +20,8 @@ SRCS+= main.c mdoc_term.c chars.c term.c
SRCS+= html.c mdoc_html.c man_html.c out.c
SRCS+= term_ps.c term_ascii.c
+SRCS+= tbl_data.c tbl_layout.c tbl_option.c tbl.c tbl_term.c tbl_tree.c
+
PROG= mandoc
.include <bsd.prog.mk>
Index: man.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man.c,v
retrieving revision 1.40
diff -u -p -r1.40 man.c
--- man.c 20 Aug 2010 00:53:35 -0000 1.40
+++ man.c 12 Oct 2010 23:37:36 -0000
@@ -25,6 +25,7 @@
#include "mandoc.h"
#include "libman.h"
#include "libmandoc.h"
+#include "tbl.h"
const char *const __man_macronames[MAN_MAX] = {
"br", "TH", "SH", "SS",
@@ -36,7 +37,7 @@ const char *const __man_macronames[MAN_M
"nf", "fi", "r", "RE",
"RS", "DT", "UC", "PD",
"Sp", "Vb", "Ve", "AT",
- "in"
+ "in", "TS", "TE"
};
const char * const *man_macronames = __man_macronames;
@@ -121,10 +122,19 @@ man_endparse(struct man *m)
int
man_parseln(struct man *m, int ln, char *buf, int offs)
{
+ struct man_node *n;
if (MAN_HALT & m->flags)
return(0);
+ n = m->last;
+
+ if (n && MAN_TS == n->tok && MAN_BODY == n->type &&
+ strncmp(buf+offs, ".TE", 3)) {
+ n = n->parent;
+ return(tbl_read(n->data.TS, "<man>", ln, buf, offs) ? 1 : 0);
+ }
+
return(('.' == buf[offs] || '\'' == buf[offs]) ?
man_pmacro(m, ln, buf, offs) :
man_ptext(m, ln, buf, offs));
@@ -322,6 +332,8 @@ man_node_free(struct man_node *p)
if (p->string)
free(p->string);
+ if (p->data.TS)
+ tbl_free(p->data.TS);
free(p);
}
Index: man.h
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man.h,v
retrieving revision 1.26
diff -u -p -r1.26 man.h
--- man.h 20 Aug 2010 00:53:35 -0000 1.26
+++ man.h 12 Oct 2010 23:37:36 -0000
@@ -57,6 +57,8 @@ enum mant {
MAN_Ve,
MAN_AT,
MAN_in,
+ MAN_TS,
+ MAN_TE,
MAN_MAX
};
@@ -95,6 +97,9 @@ struct man_node {
char *string;
struct man_node *head;
struct man_node *body;
+ union {
+ struct tbl *TS;
+ } data;
};
extern const char *const *man_macronames;
Index: man_action.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_action.c,v
retrieving revision 1.24
diff -u -p -r1.24 man_action.c
--- man_action.c 25 Jul 2010 18:05:54 -0000 1.24
+++ man_action.c 12 Oct 2010 23:37:36 -0000
@@ -22,6 +22,7 @@
#include "mandoc.h"
#include "libman.h"
#include "libmandoc.h"
+#include "tbl.h"
struct actions {
int (*post)(struct man *);
@@ -32,6 +33,7 @@ static int post_fi(struct man *);
static int post_nf(struct man *);
static int post_AT(struct man *);
static int post_UC(struct man *);
+static int post_TS(struct man *);
const struct actions man_actions[MAN_MAX] = {
{ NULL }, /* br */
@@ -71,6 +73,8 @@ const struct actions man_actions[MAN_MAX
{ post_fi }, /* Ve */
{ post_AT }, /* AT */
{ NULL }, /* in */
+ { post_TS }, /* TS */
+ { NULL }, /* TE */
};
@@ -273,6 +277,29 @@ post_UC(struct man *m)
free(m->meta.source);
m->meta.source = mandoc_strdup(p);
+
+ return(1);
+}
+
+
+static int
+post_TS(struct man *m)
+{
+ struct man_node *n;
+
+ n = m->last;
+
+ switch (n->type) {
+ case (MAN_HEAD):
+ n->parent->data.TS = tbl_alloc();
+ break;
+ case (MAN_BODY):
+ if ( ! tbl_close(n->parent->data.TS, "<man>", n->line))
+ return(0);
+ break;
+ default:
+ break;
+ }
return(1);
}
Index: man_html.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_html.c,v
retrieving revision 1.18
diff -u -p -r1.18 man_html.c
--- man_html.c 25 Jul 2010 18:05:54 -0000 1.18
+++ man_html.c 12 Oct 2010 23:37:37 -0000
@@ -113,6 +113,8 @@ static const struct htmlman mans[MAN_MAX
{ man_literal_pre, NULL }, /* Ve */
{ man_ign_pre, NULL }, /* AT */
{ man_in_pre, NULL }, /* in */
+ { NULL, NULL }, /* TS */
+ { NULL, NULL }, /* TE */
};
Index: man_macro.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_macro.c,v
retrieving revision 1.20
diff -u -p -r1.20 man_macro.c
--- man_macro.c 25 Jul 2010 18:05:54 -0000 1.20
+++ man_macro.c 12 Oct 2010 23:37:37 -0000
@@ -80,6 +80,8 @@ const struct man_macro __man_macros[MAN_
{ in_line_eoln, 0 }, /* Ve */
{ in_line_eoln, 0 }, /* AT */
{ in_line_eoln, 0 }, /* in */
+ { blk_exp, MAN_EXPLICIT }, /* TS */
+ { blk_close, 0 }, /* TE */
};
const struct man_macro * const man_macros = __man_macros;
@@ -264,6 +266,9 @@ blk_close(MACRO_PROT_ARGS)
switch (tok) {
case (MAN_RE):
ntok = MAN_RS;
+ break;
+ case (MAN_TE):
+ ntok = MAN_TS;
break;
default:
abort();
Index: man_term.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_term.c,v
retrieving revision 1.46
diff -u -p -r1.46 man_term.c
--- man_term.c 21 Sep 2010 22:33:41 -0000 1.46
+++ man_term.c 12 Oct 2010 23:37:37 -0000
@@ -28,6 +28,7 @@
#include "term.h"
#include "chars.h"
#include "main.h"
+#include "tbl.h"
#define INDENT 7
#define HALFINDENT 3
@@ -92,6 +93,7 @@ static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
static int pre_literal(DECL_ARGS);
static int pre_sp(DECL_ARGS);
+static int pre_TS(DECL_ARGS);
static void post_IP(DECL_ARGS);
static void post_HP(DECL_ARGS);
@@ -138,6 +140,8 @@ static const struct termact termacts[MAN
{ pre_literal, NULL, 0 }, /* Ve */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
+ { pre_TS, NULL, 0 }, /* TS */
+ { NULL, NULL, 0 }, /* TE */
};
@@ -823,6 +827,18 @@ post_RS(DECL_ARGS)
p->offset = term_len(p, INDENT);
break;
}
+}
+
+
+/* ARGSUSED */
+static int
+pre_TS(DECL_ARGS)
+{
+
+ if (MAN_BLOCK == n->type)
+ tbl_write(n->data.TS);
+
+ return(0);
}
Index: man_validate.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_validate.c,v
retrieving revision 1.29
diff -u -p -r1.29 man_validate.c
--- man_validate.c 20 Aug 2010 00:53:35 -0000 1.29
+++ man_validate.c 12 Oct 2010 23:37:37 -0000
@@ -95,6 +95,8 @@ static const struct man_valid man_valids
{ pres_bline, posts_eq0 }, /* Ve */
{ NULL, NULL }, /* AT */
{ NULL, NULL }, /* in */
+ { NULL, NULL }, /* TS */
+ { NULL, NULL }, /* RE */
};
Index: tbl.c
===================================================================
RCS file: tbl.c
diff -N tbl.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl.c 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,544 @@
+/* $Id: tbl.c,v 1.14 2009/09/12 16:05:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tbl.h"
+#include "tbl_extern.h"
+
+
+const char *const errnames[ERR_MAX] = {
+ "bad syntax", /* ERR_SYNTAX */
+ "bad option" /* ERR_OPTION */
+};
+
+static char buf[1024]; /* XXX */
+
+static enum tbl_tok tbl_next_char(char);
+static void tbl_init(struct tbl *);
+static void tbl_clear(struct tbl *);
+static struct tbl_head *tbl_head_alloc(struct tbl *);
+static void tbl_span_free(struct tbl_span *);
+static void tbl_data_free(struct tbl_data *);
+static void tbl_row_free(struct tbl_row *);
+
+static void headadj(const struct tbl_cell *,
+ struct tbl_head *);
+
+static void
+tbl_init(struct tbl *tbl)
+{
+
+ bzero(tbl, sizeof(struct tbl));
+
+ tbl->part = TBL_PART_OPTS;
+ tbl->tab = '\t';
+ tbl->linesize = 12;
+ tbl->decimal = '.';
+
+ TAILQ_INIT(&tbl->span);
+ TAILQ_INIT(&tbl->row);
+ TAILQ_INIT(&tbl->head);
+}
+
+
+int
+tbl_read(struct tbl *tbl, const char *f, int ln, const char *p, int len)
+{
+
+ if (len && TBL_PART_OPTS == tbl->part)
+ if (';' != p[len - 1])
+ tbl->part = TBL_PART_LAYOUT;
+
+ switch (tbl->part) {
+ case (TBL_PART_OPTS):
+ return(tbl_option(tbl, f, ln, p));
+ case (TBL_PART_CLAYOUT):
+ /* FALLTHROUGH */
+ case (TBL_PART_LAYOUT):
+ return(tbl_layout(tbl, f, ln, p));
+ case (TBL_PART_DATA):
+ return(tbl_data(tbl, f, ln, p));
+ case (TBL_PART_ERROR):
+ break;
+ }
+
+ return(0);
+}
+
+
+int
+tbl_close(struct tbl *tbl, const char *f, int ln)
+{
+
+ if (TBL_PART_DATA != tbl->part)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+ if ( ! tbl_data_close(tbl, f, ln))
+ return(0);
+#if 1
+ return(tbl_calc_term(tbl));
+#else
+ return(tbl_calc_tree(tbl));
+#endif
+}
+
+
+int
+tbl_write(const struct tbl *tbl)
+{
+
+#if 1
+ return(tbl_write_term(tbl));
+#else
+ return(tbl_write_tree(tbl));
+#endif
+}
+
+
+static enum tbl_tok
+tbl_next_char(char c)
+{
+
+ /*
+ * These are delimiting tokens. They separate out words in the
+ * token stream.
+ */
+
+ switch (c) {
+ case ('('):
+ return(TBL_TOK_OPENPAREN);
+ case (')'):
+ return(TBL_TOK_CLOSEPAREN);
+ case (' '):
+ return(TBL_TOK_SPACE);
+ case ('\t'):
+ return(TBL_TOK_TAB);
+ case (';'):
+ return(TBL_TOK_SEMICOLON);
+ case ('.'):
+ return(TBL_TOK_PERIOD);
+ case (','):
+ return(TBL_TOK_COMMA);
+ case (0):
+ return(TBL_TOK_NIL);
+ default:
+ break;
+ }
+
+ return(TBL_TOK_WORD);
+}
+
+
+const char *
+tbl_last(void)
+{
+
+ return(buf);
+}
+
+
+int
+tbl_last_uint(void)
+{
+ char *ep;
+ long lval;
+
+ /* From OpenBSD's strtol(3). Gross. */
+
+ errno = 0;
+ lval = strtol(buf, &ep, 10);
+ if (buf[0] == 0 || *ep != 0)
+ return(-1);
+ if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
+ return(-1);
+ if (lval < 0 || lval > INT_MAX)
+ return(-1);
+
+ return((int)lval);
+}
+
+
+enum tbl_tok
+tbl_next(const char *p, int *pos)
+{
+ int i;
+ enum tbl_tok c;
+
+ buf[0] = 0;
+
+ if (TBL_TOK_WORD != (c = tbl_next_char(p[*pos]))) {
+ if (TBL_TOK_NIL != c) {
+ buf[0] = p[*pos];
+ buf[1] = 0;
+ (*pos)++;
+ }
+ return(c);
+ }
+
+ /*
+ * Copy words into a nil-terminated buffer. For now, we use a
+ * static buffer. Eventually this should be made into a dynamic
+ * one living in struct tbl.
+ */
+
+ for (i = 0; i < 1023; i++, (*pos)++)
+ if (TBL_TOK_WORD == tbl_next_char(p[*pos]))
+ buf[i] = p[*pos];
+ else
+ break;
+
+ assert(i < 1023);
+ buf[i] = 0;
+
+ return(TBL_TOK_WORD);
+}
+
+
+int
+tbl_err(struct tbl *tbl)
+{
+
+ (void)fprintf(stderr, "%s\n", strerror(errno));
+ tbl->part = TBL_PART_ERROR;
+ return(0);
+}
+
+
+/* ARGSUSED */
+int
+tbl_warnx(struct tbl *tbl, enum tbl_err tok,
+ const char *f, int line, int pos)
+{
+
+ (void)fprintf(stderr, "%s:%d:%d: %s\n",
+ f, line, pos + 1, errnames[tok]);
+
+ /* TODO: -Werror */
+ return(1);
+}
+
+
+int
+tbl_errx(struct tbl *tbl, enum tbl_err tok,
+ const char *f, int line, int pos)
+{
+
+ (void)fprintf(stderr, "%s:%d:%d: %s\n",
+ f, line, pos + 1, errnames[tok]);
+
+ tbl->part = TBL_PART_ERROR;
+ return(0);
+}
+
+
+struct tbl *
+tbl_alloc(void)
+{
+ struct tbl *p;
+
+ if (NULL == (p = malloc(sizeof(struct tbl))))
+ return(NULL);
+
+ tbl_init(p);
+ return(p);
+}
+
+
+void
+tbl_free(struct tbl *p)
+{
+
+ tbl_clear(p);
+ free(p);
+}
+
+
+void
+tbl_reset(struct tbl *tbl)
+{
+
+ tbl_clear(tbl);
+ tbl_init(tbl);
+}
+
+
+struct tbl_span *
+tbl_span_alloc(struct tbl *tbl)
+{
+ struct tbl_span *p, *pp;
+ struct tbl_row *row;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_span)))) {
+ (void)tbl_err(tbl);
+ return(NULL);
+ }
+
+ TAILQ_INIT(&p->data);
+ TAILQ_INSERT_TAIL(&tbl->span, p, entries);
+
+ /* LINTED */
+ pp = TAILQ_PREV(p, tbl_spanh, entries);
+
+ if (pp) {
+ row = TAILQ_NEXT(pp->row, entries);
+ if (NULL == row)
+ row = pp->row;
+ } else {
+ row = TAILQ_FIRST(&tbl->row);
+ }
+
+ assert(row);
+ p->row = row;
+ p->tbl = tbl;
+ return(p);
+}
+
+
+struct tbl_row *
+tbl_row_alloc(struct tbl *tbl)
+{
+ struct tbl_row *p;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_row)))) {
+ (void)tbl_err(tbl);
+ return(NULL);
+ }
+
+ TAILQ_INIT(&p->cell);
+ TAILQ_INSERT_TAIL(&tbl->row, p, entries);
+ p->tbl = tbl;
+ return(p);
+}
+
+
+static void
+headadj(const struct tbl_cell *cell, struct tbl_head *head)
+{
+ if (TBL_CELL_VERT != cell->pos &&
+ TBL_CELL_DVERT != cell->pos) {
+ head->pos = TBL_HEAD_DATA;
+ return;
+ }
+ if (TBL_CELL_VERT == cell->pos)
+ if (TBL_HEAD_DVERT != head->pos)
+ head->pos = TBL_HEAD_VERT;
+ if (TBL_CELL_DVERT == cell->pos)
+ head->pos = TBL_HEAD_DVERT;
+}
+
+
+static struct tbl_head *
+tbl_head_alloc(struct tbl *tbl)
+{
+ struct tbl_head *p;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_head)))) {
+ (void)tbl_err(tbl);
+ return(NULL);
+ }
+ p->tbl = tbl;
+ return(p);
+}
+
+
+struct tbl_cell *
+tbl_cell_alloc(struct tbl_row *rp, enum tbl_cellt pos)
+{
+ struct tbl_cell *p, *pp;
+ struct tbl_head *h, *hp;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_cell)))) {
+ (void)tbl_err(rp->tbl);
+ return(NULL);
+ }
+
+ TAILQ_INSERT_TAIL(&rp->cell, p, entries);
+ p->pos = pos;
+ p->row = rp;
+
+ /*
+ * This is a little bit complicated. Here we determine the
+ * header the corresponds to a cell. We add headers dynamically
+ * when need be or re-use them, otherwise. As an example, given
+ * the following:
+ *
+ * 1 c || l
+ * 2 | c | l
+ * 3 l l
+ * 3 || c | l |.
+ *
+ * We first add the new headers (as there are none) in (1); then
+ * in (2) we insert the first spanner (as it doesn't match up
+ * with the header); then we re-use the prior data headers,
+ * skipping over the spanners; then we re-use everything and add
+ * a last spanner. Note that VERT headers are made into DVERT
+ * ones.
+ */
+
+ /* LINTED */
+ pp = TAILQ_PREV(p, tbl_cellh, entries);
+
+ h = pp ? TAILQ_NEXT(pp->head, entries) :
+ TAILQ_FIRST(&rp->tbl->head);
+
+ if (h) {
+ /* Re-use data header. */
+ if (TBL_HEAD_DATA == h->pos &&
+ (TBL_CELL_VERT != p->pos &&
+ TBL_CELL_DVERT != p->pos)) {
+ p->head = h;
+ return(p);
+ }
+
+ /* Re-use spanner header. */
+ if (TBL_HEAD_DATA != h->pos &&
+ (TBL_CELL_VERT == p->pos ||
+ TBL_CELL_DVERT == p->pos)) {
+ headadj(p, h);
+ p->head = h;
+ return(p);
+ }
+
+ /* Right-shift headers with a new spanner. */
+ if (TBL_HEAD_DATA == h->pos &&
+ (TBL_CELL_VERT == p->pos ||
+ TBL_CELL_DVERT == p->pos)) {
+ if (NULL == (hp = tbl_head_alloc(rp->tbl)))
+ return(NULL);
+ TAILQ_INSERT_BEFORE(h, hp, entries);
+ headadj(p, hp);
+ p->head = hp;
+ return(p);
+ }
+
+ h = TAILQ_NEXT(h, entries);
+ if (h) {
+ headadj(p, h);
+ p->head = h;
+ return(p);
+ }
+
+ /* Fall through to default case... */
+ }
+
+ if (NULL == (hp = tbl_head_alloc(rp->tbl)))
+ return(NULL);
+ TAILQ_INSERT_TAIL(&rp->tbl->head, hp, entries);
+ headadj(p, hp);
+ p->head = hp;
+ return(p);
+}
+
+
+struct tbl_data *
+tbl_data_alloc(struct tbl_span *sp)
+{
+ struct tbl_data *p;
+ struct tbl_cell *cp;
+ struct tbl_data *dp;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_data)))) {
+ (void)tbl_err(sp->row->tbl);
+ return(NULL);
+ }
+
+ cp = NULL;
+ /* LINTED */
+ if (NULL == (dp = TAILQ_LAST(&sp->data, tbl_datah)))
+ cp = TAILQ_FIRST(&sp->row->cell);
+ else if (dp->cell)
+ cp = TAILQ_NEXT(dp->cell, entries);
+
+ TAILQ_INSERT_TAIL(&sp->data, p, entries);
+
+ if (cp && (TBL_CELL_VERT == cp->pos ||
+ TBL_CELL_DVERT == cp->pos))
+ cp = TAILQ_NEXT(cp, entries);
+
+ p->span = sp;
+ p->cell = cp;
+ return(p);
+}
+
+
+static void
+tbl_clear(struct tbl *p)
+{
+ struct tbl_span *span;
+ struct tbl_head *head;
+ struct tbl_row *row;
+
+ /* LINTED */
+ while ((span = TAILQ_FIRST(&p->span))) {
+ TAILQ_REMOVE(&p->span, span, entries);
+ tbl_span_free(span);
+ }
+ /* LINTED */
+ while ((row = TAILQ_FIRST(&p->row))) {
+ TAILQ_REMOVE(&p->row, row, entries);
+ tbl_row_free(row);
+ }
+ /* LINTED */
+ while ((head = TAILQ_FIRST(&p->head))) {
+ TAILQ_REMOVE(&p->head, head, entries);
+ free(head);
+ }
+}
+
+
+static void
+tbl_span_free(struct tbl_span *p)
+{
+ struct tbl_data *data;
+
+ /* LINTED */
+ while ((data = TAILQ_FIRST(&p->data))) {
+ TAILQ_REMOVE(&p->data, data, entries);
+ tbl_data_free(data);
+ }
+ free(p);
+}
+
+
+static void
+tbl_data_free(struct tbl_data *p)
+{
+
+ if (p->string)
+ free(p->string);
+ free(p);
+}
+
+
+static void
+tbl_row_free(struct tbl_row *p)
+{
+ struct tbl_cell *cell;
+
+ /* LINTED */
+ while ((cell = TAILQ_FIRST(&p->cell))) {
+ TAILQ_REMOVE(&p->cell, cell, entries);
+ free(cell);
+ }
+ free(p);
+}
Index: tbl.h
===================================================================
RCS file: tbl.h
diff -N tbl.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl.h 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,34 @@
+/* $Id: tbl.h,v 1.3 2009/09/11 15:01:24 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef TBL_H
+#define TBL_H
+
+__BEGIN_DECLS
+
+struct tbl;
+
+struct tbl *tbl_alloc(void);
+void tbl_free(struct tbl *);
+void tbl_reset(struct tbl *);
+
+int tbl_read(struct tbl *, const char *, int, const char *, int);
+int tbl_close(struct tbl *, const char *, int);
+int tbl_write(const struct tbl *);
+
+__END_DECLS
+
+#endif /*TBL_H*/
Index: tbl_data.c
===================================================================
RCS file: tbl_data.c
diff -N tbl_data.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_data.c 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,130 @@
+/* $Id: data.c,v 1.11 2009/09/12 16:05:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tbl_extern.h"
+
+/* FIXME: warn about losing data contents if cell is HORIZ. */
+
+static int data(struct tbl *, struct tbl_span *,
+ const char *, int, int,
+ const char *, int, int);
+
+
+int
+data(struct tbl *tbl, struct tbl_span *dp,
+ const char *f, int ln, int pos,
+ const char *p, int start, int end)
+{
+ struct tbl_data *dat;
+
+ if (NULL == (dat = tbl_data_alloc(dp)))
+ return(0);
+
+ if (NULL == dat->cell)
+ if ( ! tbl_warnx(tbl, ERR_SYNTAX, f, ln, pos))
+ return(0);
+
+ assert(end >= start);
+ if (NULL == (dat->string = malloc((size_t)(end - start + 1))))
+ return(tbl_err(tbl));
+
+ (void)memcpy(dat->string, &p[start], (size_t)(end - start));
+ dat->string[end - start] = 0;
+
+ /* XXX: do the strcmps, then malloc(). */
+
+ if ( ! strcmp(dat->string, "_"))
+ dat->flags |= TBL_DATA_HORIZ;
+ else if ( ! strcmp(dat->string, "="))
+ dat->flags |= TBL_DATA_DHORIZ;
+ else if ( ! strcmp(dat->string, "\\_"))
+ dat->flags |= TBL_DATA_NHORIZ;
+ else if ( ! strcmp(dat->string, "\\="))
+ dat->flags |= TBL_DATA_NDHORIZ;
+ else
+ return(1);
+
+ free(dat->string);
+ dat->string = NULL;
+ return(1);
+}
+
+
+int
+tbl_data(struct tbl *tbl, const char *f, int ln, const char *p)
+{
+ struct tbl_span *dp;
+ int i, j;
+
+ if (0 == p[0])
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+
+ if ('.' == p[0] && ! isdigit((u_char)p[1])) {
+ /*
+ * XXX: departs from tbl convention in that we disallow
+ * macros in the data body.
+ */
+ if (strncasecmp(p, ".T&", 3))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+ return(tbl_data_close(tbl, f, ln));
+ }
+
+ if (NULL == (dp = tbl_span_alloc(tbl)))
+ return(0);
+
+ if ( ! strcmp(p, "_")) {
+ dp->flags |= TBL_SPAN_HORIZ;
+ return(1);
+ } else if ( ! strcmp(p, "=")) {
+ dp->flags |= TBL_SPAN_DHORIZ;
+ return(1);
+ }
+
+ for (j = i = 0; p[i]; i++) {
+ if (p[i] != tbl->tab)
+ continue;
+ if ( ! data(tbl, dp, f, ln, i, p, j, i))
+ return(0);
+ j = i + 1;
+ }
+
+ return(data(tbl, dp, f, ln, i, p, j, i));
+}
+
+
+int
+tbl_data_close(struct tbl *tbl, const char *f, int ln)
+{
+ struct tbl_span *span;
+
+ /* LINTED */
+ span = TAILQ_LAST(&tbl->span, tbl_spanh);
+ if (NULL == span)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+ if (TAILQ_NEXT(span->row, entries))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+
+ tbl->part = TBL_PART_LAYOUT;
+ return(1);
+}
Index: tbl_extern.h
===================================================================
RCS file: tbl_extern.h
diff -N tbl_extern.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_extern.h 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,183 @@
+/* $Id: extern.h,v 1.10 2009/09/13 12:37:28 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef TBL_EXTERN_H
+#define TBL_EXTERN_H
+
+enum tbl_err {
+ ERR_SYNTAX,
+ ERR_OPTION,
+ ERR_MAX
+};
+
+enum tbl_tok {
+ TBL_TOK_WORD,
+ TBL_TOK_OPENPAREN,
+ TBL_TOK_CLOSEPAREN,
+ TBL_TOK_COMMA,
+ TBL_TOK_SEMICOLON,
+ TBL_TOK_PERIOD,
+ TBL_TOK_SPACE,
+ TBL_TOK_TAB,
+ TBL_TOK_NIL
+};
+
+enum tbl_part {
+ TBL_PART_OPTS,
+ TBL_PART_LAYOUT,
+ TBL_PART_CLAYOUT,
+ TBL_PART_DATA,
+ TBL_PART_ERROR
+};
+
+struct tbl;
+struct tbl_head;
+struct tbl_row;
+struct tbl_cell;
+struct tbl_span;
+struct tbl_data;
+
+TAILQ_HEAD(tbl_rowh, tbl_row);
+TAILQ_HEAD(tbl_cellh, tbl_cell);
+TAILQ_HEAD(tbl_headh, tbl_head);
+TAILQ_HEAD(tbl_spanh, tbl_span);
+TAILQ_HEAD(tbl_datah, tbl_data);
+
+struct tbl {
+ enum tbl_part part;
+ int opts;
+#define TBL_OPT_CENTRE (1 << 0)
+#define TBL_OPT_EXPAND (1 << 1)
+#define TBL_OPT_BOX (1 << 2)
+#define TBL_OPT_DBOX (1 << 3)
+#define TBL_OPT_ALLBOX (1 << 4)
+#define TBL_OPT_NOKEEP (1 << 5)
+#define TBL_OPT_NOSPACE (1 << 6)
+ char tab;
+ char decimal;
+ int linesize;
+ char delims[2];
+ struct tbl_spanh span;
+ struct tbl_headh head;
+ struct tbl_rowh row;
+};
+
+enum tbl_headt {
+ TBL_HEAD_DATA,
+ TBL_HEAD_VERT,
+ TBL_HEAD_DVERT,
+ TBL_HEAD_MAX
+};
+
+struct tbl_head {
+ struct tbl *tbl;
+ enum tbl_headt pos;
+ int width;
+ int decimal;
+ TAILQ_ENTRY(tbl_head) entries;
+};
+
+struct tbl_row {
+ struct tbl *tbl;
+ struct tbl_cellh cell;
+ TAILQ_ENTRY(tbl_row) entries;
+};
+
+enum tbl_cellt {
+ TBL_CELL_CENTRE, /* c, C */
+ TBL_CELL_RIGHT, /* r, R */
+ TBL_CELL_LEFT, /* l, L */
+ TBL_CELL_NUMBER, /* n, N */
+ TBL_CELL_SPAN, /* s, S */
+ TBL_CELL_LONG, /* a, A */
+ TBL_CELL_DOWN, /* ^ */
+ TBL_CELL_HORIZ, /* _, - */
+ TBL_CELL_DHORIZ, /* = */
+ TBL_CELL_VERT, /* | */
+ TBL_CELL_DVERT, /* || */
+ TBL_CELL_MAX
+};
+
+struct tbl_cell {
+ struct tbl_row *row;
+ struct tbl_head *head;
+ enum tbl_cellt pos;
+ int spacing;
+ int flags;
+#define TBL_CELL_TALIGN (1 << 0) /* t, T */
+#define TBL_CELL_BALIGN (1 << 1) /* d, D */
+#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */
+#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */
+#define TBL_CELL_EQUAL (1 << 4) /* e, E */
+#define TBL_CELL_UP (1 << 5) /* u, U */
+#define TBL_CELL_WIGN (1 << 6) /* z, Z */
+ TAILQ_ENTRY(tbl_cell) entries;
+};
+
+struct tbl_data {
+ struct tbl_span *span;
+ struct tbl_cell *cell;
+ int flags;
+#define TBL_DATA_HORIZ (1 << 0)
+#define TBL_DATA_DHORIZ (1 << 1)
+#define TBL_DATA_NHORIZ (1 << 2)
+#define TBL_DATA_NDHORIZ (1 << 3)
+ char *string;
+ TAILQ_ENTRY(tbl_data) entries;
+};
+
+struct tbl_span {
+ struct tbl_row *row;
+ struct tbl *tbl;
+ int flags;
+#define TBL_SPAN_HORIZ (1 << 0)
+#define TBL_SPAN_DHORIZ (1 << 1)
+ struct tbl_datah data;
+ TAILQ_ENTRY(tbl_span) entries;
+};
+
+__BEGIN_DECLS
+
+int tbl_option(struct tbl *,
+ const char *, int, const char *);
+int tbl_layout(struct tbl *,
+ const char *, int, const char *);
+int tbl_data(struct tbl *,
+ const char *, int, const char *);
+int tbl_data_close(struct tbl *, const char *, int);
+
+enum tbl_tok tbl_next(const char *, int *);
+const char *tbl_last(void);
+int tbl_last_uint(void);
+int tbl_errx(struct tbl *, enum tbl_err,
+ const char *, int, int);
+int tbl_warnx(struct tbl *, enum tbl_err,
+ const char *, int, int);
+int tbl_err(struct tbl *);
+
+struct tbl_row *tbl_row_alloc(struct tbl *);
+struct tbl_cell *tbl_cell_alloc(struct tbl_row *, enum tbl_cellt);
+struct tbl_span *tbl_span_alloc(struct tbl *);
+struct tbl_data *tbl_data_alloc(struct tbl_span *);
+
+int tbl_write_term(const struct tbl *);
+int tbl_calc_term(struct tbl *);
+int tbl_write_tree(const struct tbl *);
+int tbl_calc_tree(struct tbl *);
+
+__END_DECLS
+
+#endif /*TBL_EXTERN_H*/
Index: tbl_layout.c
===================================================================
RCS file: tbl_layout.c
diff -N tbl_layout.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_layout.c 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,280 @@
+/* $Id: layout.c,v 1.7 2009/09/11 13:24:04 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tbl_extern.h"
+
+struct tbl_phrase {
+ char name;
+ enum tbl_cellt key;
+};
+
+#define KEYS_MAX 17
+
+static const struct tbl_phrase keys[KEYS_MAX] = {
+ { 'c', TBL_CELL_CENTRE },
+ { 'C', TBL_CELL_CENTRE },
+ { 'r', TBL_CELL_RIGHT },
+ { 'R', TBL_CELL_RIGHT },
+ { 'l', TBL_CELL_LEFT },
+ { 'L', TBL_CELL_LEFT },
+ { 'n', TBL_CELL_NUMBER },
+ { 'N', TBL_CELL_NUMBER },
+ { 's', TBL_CELL_SPAN },
+ { 'S', TBL_CELL_SPAN },
+ { 'a', TBL_CELL_LONG },
+ { 'A', TBL_CELL_LONG },
+ { '^', TBL_CELL_DOWN },
+ { '-', TBL_CELL_HORIZ },
+ { '_', TBL_CELL_HORIZ },
+ { '=', TBL_CELL_DHORIZ },
+ { '|', TBL_CELL_VERT }
+};
+
+static int mods(struct tbl *, struct tbl_cell *,
+ const char *, int,
+ const char *, int, int);
+static int cell(struct tbl *, struct tbl_row *,
+ const char *, int, int);
+static int row(struct tbl *, const char *,
+ int, const char *, int *);
+
+
+static int
+mods(struct tbl *tbl, struct tbl_cell *cp, const char *p,
+ int pp, const char *f, int ln, int pos)
+{
+ char buf[5];
+ int i;
+
+ /*
+ * XXX: since, at least for now, modifiers are non-conflicting
+ * (are separable by value, regardless of position), we let
+ * modifiers come in any order. The existing tbl doesn't let
+ * this happen.
+ */
+
+ if (0 == p[pp])
+ return(1);
+
+ /* Parse numerical spacing from modifier string. */
+
+ if (isdigit((u_char)p[pp])) {
+ for (i = 0; i < 4; i++) {
+ if ( ! isdigit((u_char)p[pp + i]))
+ break;
+ buf[i] = p[pp + i];
+ }
+ buf[i] = 0;
+
+ /* No greater than 4 digits. */
+
+ if (4 == i)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp));
+
+ /*
+ * We can't change the spacing in any subsequent layout
+ * definitions. FIXME: I don't think we can change the
+ * spacing for a column at all, after it's already been
+ * initialised.
+ */
+
+ if (TBL_PART_CLAYOUT != tbl->part)
+ cp->spacing = atoi(buf);
+ else if ( ! tbl_warnx(tbl, ERR_SYNTAX, f, ln, pos + pp))
+ return(0);
+
+ /* Continue parsing modifiers. */
+
+ return(mods(tbl, cp, p, pp + i, f, ln, pos));
+ }
+
+ /* TODO: GNU has many more extensions. */
+
+ switch (p[pp]) {
+ case ('z'):
+ /* FALLTHROUGH */
+ case ('Z'):
+ cp->flags |= TBL_CELL_WIGN;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('u'):
+ /* FALLTHROUGH */
+ case ('U'):
+ cp->flags |= TBL_CELL_UP;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('e'):
+ /* FALLTHROUGH */
+ case ('E'):
+ cp->flags |= TBL_CELL_EQUAL;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('t'):
+ /* FALLTHROUGH */
+ case ('T'):
+ cp->flags |= TBL_CELL_TALIGN;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('d'):
+ /* FALLTHROUGH */
+ case ('D'):
+ cp->flags |= TBL_CELL_BALIGN;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('f'):
+ pp++;
+ /* FALLTHROUGH */
+ case ('B'):
+ /* FALLTHROUGH */
+ case ('I'):
+ /* FALLTHROUGH */
+ case ('b'):
+ /* FALLTHROUGH */
+ case ('i'):
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp));
+ }
+
+ switch (p[pp]) {
+ case ('b'):
+ /* FALLTHROUGH */
+ case ('B'):
+ cp->flags |= TBL_CELL_BOLD;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('i'):
+ /* FALLTHROUGH */
+ case ('I'):
+ cp->flags |= TBL_CELL_ITALIC;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ default:
+ break;
+ }
+
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp));
+}
+
+
+static int
+cell(struct tbl *tbl, struct tbl_row *rp,
+ const char *f, int ln, int pos)
+{
+ struct tbl_cell *cp;
+ const char *p;
+ int j, i;
+ enum tbl_cellt c;
+
+ /* Parse the column position (`r', `R', `|', ...). */
+
+ c = TBL_CELL_MAX;
+ for (p = tbl_last(), i = 0; i < KEYS_MAX; i++) {
+ if (keys[i].name != p[0])
+ continue;
+ c = keys[i].key;
+ break;
+ }
+
+ if (i == KEYS_MAX)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos));
+
+ /* Extra check for the double-vertical. */
+
+ if (TBL_CELL_VERT == c && '|' == p[1]) {
+ j = 2;
+ c = TBL_CELL_DVERT;
+ } else
+ j = 1;
+
+ /* Disallow subsequent spacers. */
+
+ /* LINTED */
+ cp = TAILQ_LAST(&rp->cell, tbl_cellh);
+
+ if (cp && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) &&
+ (TBL_CELL_VERT == cp->pos ||
+ TBL_CELL_DVERT == cp->pos))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos));
+
+ /* Allocate cell then parse its modifiers. */
+
+ if (NULL == (cp = tbl_cell_alloc(rp, c)))
+ return(0);
+ return(mods(tbl, cp, p, j, f, ln, pos));
+}
+
+
+static int
+row(struct tbl *tbl, const char *f, int ln,
+ const char *p, int *pos)
+{
+ struct tbl_row *rp;
+ int sv;
+
+ rp = tbl_row_alloc(tbl);
+again:
+ sv = *pos;
+
+ /*
+ * EBNF describing this section:
+ *
+ * row ::= row_list [:space:]* [.]?[\n]
+ * row_list ::= [:space:]* row_elem row_tail
+ * row_tail ::= [:space:]*[,] row_list |
+ * epsilon
+ * row_elem ::= [\t\ ]*[:alpha:]+
+ */
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_TAB):
+ /* FALLTHROUGH */
+ case (TBL_TOK_SPACE):
+ goto again;
+ case (TBL_TOK_WORD):
+ if ( ! cell(tbl, rp, f, ln, sv))
+ return(0);
+ goto again;
+ case (TBL_TOK_COMMA):
+ if (NULL == TAILQ_FIRST(&rp->cell))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ return(row(tbl, f, ln, p, pos));
+ case (TBL_TOK_PERIOD):
+ if (NULL == TAILQ_FIRST(&rp->cell))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->part = TBL_PART_DATA;
+ break;
+ case (TBL_TOK_NIL):
+ if (NULL == TAILQ_FIRST(&rp->cell))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ return(1);
+}
+
+
+int
+tbl_layout(struct tbl *tbl, const char *f, int ln, const char *p)
+{
+ int pos;
+
+ pos = 0;
+ return(row(tbl, f, ln, p, &pos));
+}
Index: tbl_option.c
===================================================================
RCS file: tbl_option.c
diff -N tbl_option.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_option.c 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,195 @@
+/* $Id: option.c,v 1.5 2009/09/09 12:51:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tbl_extern.h"
+
+struct tbl_phrase {
+ char *name;
+ int key;
+ int ident;
+#define KEY_CENTRE 0
+#define KEY_DELIM 1
+#define KEY_EXPAND 2
+#define KEY_BOX 3
+#define KEY_DBOX 4
+#define KEY_ALLBOX 5
+#define KEY_TAB 6
+#define KEY_LINESIZE 7
+#define KEY_NOKEEP 8
+#define KEY_DPOINT 9
+#define KEY_NOSPACE 10
+#define KEY_FRAME 11
+#define KEY_DFRAME 12
+};
+
+#define KEY_MAXKEYS 14
+
+static const struct tbl_phrase keys[KEY_MAXKEYS] = {
+ { "center", TBL_OPT_CENTRE, KEY_CENTRE},
+ { "centre", TBL_OPT_CENTRE, KEY_CENTRE},
+ { "delim", 0, KEY_DELIM},
+ { "expand", TBL_OPT_EXPAND, KEY_EXPAND},
+ { "box", TBL_OPT_BOX, KEY_BOX},
+ { "doublebox", TBL_OPT_DBOX, KEY_DBOX},
+ { "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX},
+ { "frame", TBL_OPT_BOX, KEY_FRAME},
+ { "doubleframe", TBL_OPT_DBOX, KEY_DFRAME},
+ { "tab", 0, KEY_TAB},
+ { "linesize", 0, KEY_LINESIZE},
+ { "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP},
+ { "decimalpoint", 0, KEY_DPOINT},
+ { "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE},
+};
+
+static int arg(struct tbl *, const char *,
+ int, const char *, int *, int);
+static int opt(struct tbl *, const char *,
+ int, const char *, int *);
+
+static int
+arg(struct tbl *tbl, const char *f, int ln,
+ const char *p, int *pos, int key)
+{
+ const char *buf;
+ int sv;
+
+again:
+ sv = *pos;
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_OPENPAREN):
+ break;
+ case (TBL_TOK_SPACE):
+ /* FALLTHROUGH */
+ case (TBL_TOK_TAB):
+ goto again;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ sv = *pos;
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_WORD):
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ buf = tbl_last();
+
+ switch (key) {
+ case (KEY_DELIM):
+ if (2 != strlen(buf))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->delims[0] = buf[0];
+ tbl->delims[1] = buf[1];
+ break;
+ case (KEY_TAB):
+ if (1 != strlen(buf))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->tab = buf[0];
+ break;
+ case (KEY_LINESIZE):
+ if (-1 == (tbl->linesize = tbl_last_uint()))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ break;
+ case (KEY_DPOINT):
+ if (1 != strlen(buf))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->decimal = buf[0];
+ break;
+ default:
+ abort();
+ }
+
+ sv = *pos;
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_CLOSEPAREN):
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ return(1);
+}
+
+
+static int
+opt(struct tbl *tbl, const char *f, int ln, const char *p, int *pos)
+{
+ int i, sv;
+
+again:
+ sv = *pos;
+
+ /*
+ * EBNF describing this section:
+ *
+ * options ::= option_list [:space:]* [;][\n]
+ * option_list ::= option option_tail
+ * option_tail ::= [:space:]+ option_list |
+ * ::= epsilon
+ * option ::= [:alpha:]+ args
+ * args ::= [:space:]* [(] [:alpha:]+ [)]
+ */
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_WORD):
+ break;
+ case (TBL_TOK_SPACE):
+ /* FALLTHROUGH */
+ case (TBL_TOK_TAB):
+ goto again;
+ case (TBL_TOK_SEMICOLON):
+ tbl->part = TBL_PART_LAYOUT;
+ return(1);
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ for (i = 0; i < KEY_MAXKEYS; i++) {
+ if (strcasecmp(tbl_last(), keys[i].name))
+ continue;
+ if (keys[i].key)
+ tbl->opts |= keys[i].key;
+ else if ( ! arg(tbl, f, ln, p, pos, keys[i].ident))
+ return(0);
+
+ break;
+ }
+
+ if (KEY_MAXKEYS == i)
+ return(tbl_errx(tbl, ERR_OPTION, f, ln, sv));
+
+ return(opt(tbl, f, ln, p, pos));
+}
+
+
+int
+tbl_option(struct tbl *tbl, const char *f, int ln, const char *p)
+{
+ int pos;
+
+ pos = 0;
+ return(opt(tbl, f, ln, p, &pos));
+}
Index: tbl_term.c
===================================================================
RCS file: tbl_term.c
diff -N tbl_term.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_term.c 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,504 @@
+/* $Id: term.c,v 1.13 2009/09/14 09:06:40 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tbl_extern.h"
+
+/* FIXME: `n' modifier doesn't always do the right thing. */
+/* FIXME: `n' modifier doesn't use the cell-spacing buffer. */
+
+static void calc_data(struct tbl_data *);
+static void calc_data_literal(struct tbl_data *);
+static void calc_data_number(struct tbl_data *);
+static void calc_data_spanner(struct tbl_data *);
+static inline void write_char(char, int);
+static void write_data(const struct tbl_data *, int);
+static void write_data_literal(const struct tbl_data *, int);
+static void write_data_number(const struct tbl_data *, int);
+static void write_data_spanner(const struct tbl_data *, int);
+static void write_hframe(const struct tbl *);
+static void write_hrule(const struct tbl_span *);
+static void write_spanner(const struct tbl_head *);
+static void write_vframe(const struct tbl *);
+
+
+int
+tbl_write_term(const struct tbl *tbl)
+{
+ const struct tbl_span *span;
+ const struct tbl_data *data;
+ const struct tbl_head *head;
+
+ /*
+ * Note that the absolute widths and decimal places for headers
+ * were set when tbl_calc_term was called.
+ */
+
+ /* First, write out our head horizontal frame. */
+
+ write_hframe(tbl);
+
+ /*
+ * Iterate through each span, and inside, through the global
+ * headers. If the global header's a spanner, print it
+ * directly; if it's data, use the corresponding data in the
+ * span as the object to print.
+ */
+
+ TAILQ_FOREACH(span, &tbl->span, entries) {
+ write_vframe(tbl);
+
+ /* Accomodate for the horizontal rule. */
+ if (TBL_DATA_DHORIZ & span->flags ||
+ TBL_DATA_HORIZ & span->flags) {
+ write_hrule(span);
+ write_vframe(tbl);
+ printf("\n");
+ continue;
+ }
+
+ data = TAILQ_FIRST(&span->data);
+ TAILQ_FOREACH(head, &tbl->head, entries) {
+ switch (head->pos) {
+ case (TBL_HEAD_VERT):
+ /* FALLTHROUGH */
+ case (TBL_HEAD_DVERT):
+ write_spanner(head);
+ break;
+ case (TBL_HEAD_DATA):
+ write_data(data, head->width);
+ if (data)
+ data = TAILQ_NEXT(data, entries);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ }
+ write_vframe(tbl);
+ printf("\n");
+ }
+
+ /* Last, write out our tail horizontal frame. */
+
+ write_hframe(tbl);
+
+ return(1);
+}
+
+
+int
+tbl_calc_term(struct tbl *tbl)
+{
+ struct tbl_span *span;
+ struct tbl_data *data;
+ struct tbl_head *head;
+
+ /* Calculate width as the max of column cells' widths. */
+
+ TAILQ_FOREACH(span, &tbl->span, entries) {
+ if (TBL_DATA_HORIZ & span->flags)
+ continue;
+ if (TBL_DATA_DHORIZ & span->flags)
+ continue;
+ if (TBL_DATA_NHORIZ & span->flags)
+ continue;
+ if (TBL_DATA_NDHORIZ & span->flags)
+ continue;
+ TAILQ_FOREACH(data, &span->data, entries)
+ calc_data(data);
+ }
+
+ /* Calculate width as the simple spanner value. */
+
+ TAILQ_FOREACH(head, &tbl->head, entries)
+ switch (head->pos) {
+ case (TBL_HEAD_VERT):
+ head->width = 1;
+ break;
+ case (TBL_HEAD_DVERT):
+ head->width = 2;
+ break;
+ default:
+ break;
+ }
+
+ return(1);
+}
+
+
+static void
+write_hrule(const struct tbl_span *span)
+{
+ const struct tbl_head *head;
+ char c;
+
+ /*
+ * An hrule extends across the entire table and is demarked by a
+ * standalone `_' or whatnot in lieu of a table row. Spanning
+ * headers are marked by a `+', as are table boundaries.
+ */
+
+ c = '-';
+ if (TBL_SPAN_DHORIZ & span->flags)
+ c = '=';
+
+ /* FIXME: don't use `+' between data and a spanner! */
+
+ TAILQ_FOREACH(head, &span->tbl->head, entries) {
+ switch (head->pos) {
+ case (TBL_HEAD_DATA):
+ write_char(c, head->width);
+ break;
+ case (TBL_HEAD_DVERT):
+ write_char('+', head->width);
+ /* FALLTHROUGH */
+ case (TBL_HEAD_VERT):
+ write_char('+', head->width);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ }
+}
+
+
+static void
+write_hframe(const struct tbl *tbl)
+{
+ const struct tbl_head *head;
+
+ if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts))
+ return;
+
+ /*
+ * Print out the horizontal part of a frame or double frame. A
+ * double frame has an unbroken `-' outer line the width of the
+ * table, bordered by `+'. The frame (or inner frame, in the
+ * case of the double frame) is a `-' bordered by `+' and broken
+ * by `+' whenever a span is encountered.
+ */
+
+ if (TBL_OPT_DBOX & tbl->opts) {
+ printf("+");
+ TAILQ_FOREACH(head, &tbl->head, entries)
+ write_char('-', head->width);
+ printf("+\n");
+ }
+
+ printf("+");
+ TAILQ_FOREACH(head, &tbl->head, entries) {
+ switch (head->pos) {
+ case (TBL_HEAD_DATA):
+ write_char('-', head->width);
+ break;
+ default:
+ write_char('+', head->width);
+ break;
+ }
+ }
+ printf("+\n");
+}
+
+
+static void
+write_vframe(const struct tbl *tbl)
+{
+ /* Always just a single vertical line. */
+
+ if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts))
+ return;
+ printf("|");
+}
+
+
+static void
+calc_data_spanner(struct tbl_data *data)
+{
+
+ /* N.B., these are horiz spanners (not vert) so always 1. */
+ data->cell->head->width = 1;
+}
+
+
+static void
+calc_data_number(struct tbl_data *data)
+{
+ int sz, d;
+ char *dp, pnt;
+
+ /*
+ * First calculate number width and decimal place (last + 1 for
+ * no-decimal numbers). If the stored decimal is subsequent
+ * ours, make our size longer by that difference
+ * (right-"shifting"); similarly, if ours is subsequent the
+ * stored, then extend the stored size by the difference.
+ * Finally, re-assign the stored values.
+ */
+
+ /* TODO: use spacing modifier. */
+
+ assert(data->string);
+ sz = (int)strlen(data->string);
+ pnt = data->span->tbl->decimal;
+
+ if (NULL == (dp = strchr(data->string, pnt)))
+ d = sz + 1;
+ else
+ d = (int)(dp - data->string) + 1;
+
+ sz += 2;
+
+ if (data->cell->head->decimal > d) {
+ sz += data->cell->head->decimal - d;
+ d = data->cell->head->decimal;
+ } else
+ data->cell->head->width +=
+ d - data->cell->head->decimal;
+
+ if (sz > data->cell->head->width)
+ data->cell->head->width = sz;
+ if (d > data->cell->head->decimal)
+ data->cell->head->decimal = d;
+}
+
+
+static void
+calc_data_literal(struct tbl_data *data)
+{
+ int sz, bufsz;
+
+ /*
+ * Calculate our width and use the spacing, with a minimum
+ * spacing dictated by position (centre, e.g,. gets a space on
+ * either side, while right/left get a single adjacent space).
+ */
+
+ assert(data->string);
+ sz = (int)strlen(data->string);
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_LONG):
+ /* FALLTHROUGH */
+ case (TBL_CELL_CENTRE):
+ bufsz = 2;
+ break;
+ default:
+ bufsz = 1;
+ break;
+ }
+
+ if (data->cell->spacing)
+ bufsz = bufsz > data->cell->spacing ?
+ bufsz : data->cell->spacing;
+
+ sz += bufsz;
+ if (data->cell->head->width < sz)
+ data->cell->head->width = sz;
+}
+
+
+static void
+calc_data(struct tbl_data *data)
+{
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_HORIZ):
+ /* FALLTHROUGH */
+ case (TBL_CELL_DHORIZ):
+ calc_data_spanner(data);
+ break;
+ case (TBL_CELL_LONG):
+ /* FALLTHROUGH */
+ case (TBL_CELL_CENTRE):
+ /* FALLTHROUGH */
+ case (TBL_CELL_LEFT):
+ /* FALLTHROUGH */
+ case (TBL_CELL_RIGHT):
+ calc_data_literal(data);
+ break;
+ case (TBL_CELL_NUMBER):
+ calc_data_number(data);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+}
+
+
+static void
+write_data_spanner(const struct tbl_data *data, int width)
+{
+
+ /*
+ * Write spanners dictated by both our cell designation (in the
+ * layout) or as data.
+ */
+ if (TBL_DATA_HORIZ & data->flags)
+ write_char('-', width);
+ else if (TBL_DATA_DHORIZ & data->flags)
+ write_char('=', width);
+ else if (TBL_CELL_HORIZ == data->cell->pos)
+ write_char('-', width);
+ else if (TBL_CELL_DHORIZ == data->cell->pos)
+ write_char('=', width);
+}
+
+
+static void
+write_data_number(const struct tbl_data *data, int width)
+{
+ char *dp, pnt;
+ int d, padl, sz;
+
+ /*
+ * See calc_data_number(). Left-pad by taking the offset of our
+ * and the maximum decimal; right-pad by the remaining amount.
+ */
+
+ sz = (int)strlen(data->string);
+ pnt = data->span->tbl->decimal;
+
+ if (NULL == (dp = strchr(data->string, pnt))) {
+ d = sz + 1;
+ } else {
+ d = (int)(dp - data->string) + 1;
+ }
+
+ assert(d <= data->cell->head->decimal);
+ assert(sz - d <= data->cell->head->width -
+ data->cell->head->decimal);
+
+ padl = data->cell->head->decimal - d + 1;
+ assert(width - sz - padl);
+
+ write_char(' ', padl);
+ (void)printf("%s", data->string);
+ write_char(' ', width - sz - padl);
+}
+
+
+static void
+write_data_literal(const struct tbl_data *data, int width)
+{
+ int padl, padr;
+
+ padl = padr = 0;
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_LONG):
+ padl = 1;
+ padr = width - (int)strlen(data->string) - 1;
+ break;
+ case (TBL_CELL_CENTRE):
+ padl = width - (int)strlen(data->string);
+ if (padl % 2)
+ padr++;
+ padl /= 2;
+ padr += padl;
+ break;
+ case (TBL_CELL_RIGHT):
+ padl = width - (int)strlen(data->string);
+ break;
+ default:
+ padr = width - (int)strlen(data->string);
+ break;
+ }
+
+ write_char(' ', padl);
+ (void)printf("%s", data->string);
+ write_char(' ', padr);
+}
+
+
+static void
+write_data(const struct tbl_data *data, int width)
+{
+
+ if (NULL == data) {
+ write_char(' ', width);
+ return;
+ }
+
+ if (TBL_DATA_HORIZ & data->flags ||
+ TBL_DATA_DHORIZ & data->flags) {
+ write_data_spanner(data, width);
+ return;
+ }
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_HORIZ):
+ /* FALLTHROUGH */
+ case (TBL_CELL_DHORIZ):
+ write_data_spanner(data, width);
+ break;
+ case (TBL_CELL_LONG):
+ /* FALLTHROUGH */
+ case (TBL_CELL_CENTRE):
+ /* FALLTHROUGH */
+ case (TBL_CELL_LEFT):
+ /* FALLTHROUGH */
+ case (TBL_CELL_RIGHT):
+ write_data_literal(data, width);
+ break;
+ case (TBL_CELL_NUMBER):
+ write_data_number(data, width);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+}
+
+
+static void
+write_spanner(const struct tbl_head *head)
+{
+ char *p;
+
+ p = NULL;
+ switch (head->pos) {
+ case (TBL_HEAD_VERT):
+ p = "|";
+ break;
+ case (TBL_HEAD_DVERT):
+ p = "||";
+ break;
+ default:
+ break;
+ }
+
+ assert(p);
+ printf("%s", p);
+}
+
+
+static inline void
+write_char(char c, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ printf("%c", c);
+}
Index: tbl_tree.c
===================================================================
RCS file: tbl_tree.c
diff -N tbl_tree.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_tree.c 12 Oct 2010 23:37:37 -0000
@@ -0,0 +1,86 @@
+/* $Id: tree.c,v 1.2 2009/09/11 13:24:04 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tbl_extern.h"
+
+static const char * const htypes[TBL_HEAD_MAX] = {
+ "data",
+ "vert",
+ "dvert",
+};
+
+static const char * const ctypes[TBL_CELL_MAX] = {
+ "centre",
+ "right",
+ "left",
+ "number",
+ "span",
+ "long",
+ "down",
+ "horiz",
+ "dhoriz",
+ "vert",
+ "dvert",
+};
+
+
+/* ARGSUSED */
+int
+tbl_calc_tree(struct tbl *tbl)
+{
+
+ return(1);
+}
+
+
+int
+tbl_write_tree(const struct tbl *tbl)
+{
+ struct tbl_row *row;
+ struct tbl_cell *cell;
+ struct tbl_span *span;
+ struct tbl_data *data;
+ struct tbl_head *head;
+
+ (void)printf("header\n");
+ TAILQ_FOREACH(head, &tbl->head, entries)
+ (void)printf("\t%s (=%p)\n", htypes[head->pos], head);
+
+ (void)printf("layout\n");
+ TAILQ_FOREACH(row, &tbl->row, entries) {
+ (void)printf("\trow (=%p)\n", row);
+ TAILQ_FOREACH(cell, &row->cell, entries)
+ (void)printf("\t\t%s (=%p) >%p\n",
+ ctypes[cell->pos],
+ cell, cell->head);
+ }
+
+ (void)printf("data\n");
+ TAILQ_FOREACH(span, &tbl->span, entries) {
+ (void)printf("\tspan >%p\n", span->row);
+ TAILQ_FOREACH(data, &span->data, entries)
+ (void)printf("\t\tdata >%p\n", data->cell);
+ }
+
+ return(1);
+}
--
To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: integrate tbl into mandoc
2010-10-13 0:46 integrate tbl into mandoc Ingo Schwarze
@ 2010-10-14 21:18 ` Ingo Schwarze
2010-10-14 21:55 ` Ingo Schwarze
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Ingo Schwarze @ 2010-10-14 21:18 UTC (permalink / raw)
To: tech
[-- Attachment #1: Type: text/plain, Size: 55343 bytes --]
Hi,
Replying to myself:
> One thing to do before commit is probably to replace the printfs
> in the output frontend by calls into term.c, such that indentation
> is respected and escape sequences get resolved.
Here you are.
Inline, i'm sending the updated full diff against the OpenBSD tree.
To make it easier to see how the term.c integration was done,
i'm sending a smaller diff as an attachment. That one is not
intended for applying, but just for reading.
The following still holds:
> There may be more i need to do.
> The following already look semi-useful with this:
> /usr/src/lib/libcurses/curs_attr.3tbl
> /usr/src/lib/libcurses/curs_getch.3tbl
> /usr/src/lib/libcurses/curses.3tbl
> /usr/src/usr.bin/infocmp/infocmp.1tbl
> The following still crash:
> /usr/src/lib/libcurses/curs_addch.3tbl
> /usr/src/lib/libcurses/curs_inch.3tbl
> /usr/src/lib/libcurses/curs_mouse.3tbl
> /usr/src/lib/libform/form.3tbl
> /usr/src/lib/libmenu/menu.3tbl
> /usr/src/usr.bin/tic/captoinfo.1tbl
> /usr/src/gnu/usr.sbin/mkhybrid/src/mkhybrid.8tbl
> The following have a tbl extension, but no .TS:
> /usr/src/lib/libcurses/term.5tbl
> The following are mdoc(7) with tbl:
> /usr/src/share/man/man4/wi.4tbl
> /usr/src/share/man/man4/man4.hppa/cpu.4tbl
> /usr/src/games/phantasia/phantasia.6tbl
Any objection against putting this into OpenBSD for now,
such that i can hack in tree?
That won't prevent improving the glue, later on,
when we have more time.
Yours,
Ingo
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/Makefile,v
retrieving revision 1.45
diff -u -p -r1.45 Makefile
--- Makefile 27 Sep 2010 21:25:28 -0000 1.45
+++ Makefile 14 Oct 2010 21:03:05 -0000
@@ -20,6 +20,8 @@ SRCS+= main.c mdoc_term.c chars.c term.c
SRCS+= html.c mdoc_html.c man_html.c out.c
SRCS+= term_ps.c term_ascii.c
+SRCS+= tbl_data.c tbl_layout.c tbl_option.c tbl.c tbl_term.c tbl_tree.c
+
PROG= mandoc
.include <bsd.prog.mk>
Index: man.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man.c,v
retrieving revision 1.40
diff -u -p -r1.40 man.c
--- man.c 20 Aug 2010 00:53:35 -0000 1.40
+++ man.c 14 Oct 2010 21:03:05 -0000
@@ -25,6 +25,7 @@
#include "mandoc.h"
#include "libman.h"
#include "libmandoc.h"
+#include "tbl.h"
const char *const __man_macronames[MAN_MAX] = {
"br", "TH", "SH", "SS",
@@ -36,7 +37,7 @@ const char *const __man_macronames[MAN_M
"nf", "fi", "r", "RE",
"RS", "DT", "UC", "PD",
"Sp", "Vb", "Ve", "AT",
- "in"
+ "in", "TS", "TE"
};
const char * const *man_macronames = __man_macronames;
@@ -121,10 +122,19 @@ man_endparse(struct man *m)
int
man_parseln(struct man *m, int ln, char *buf, int offs)
{
+ struct man_node *n;
if (MAN_HALT & m->flags)
return(0);
+ n = m->last;
+
+ if (n && MAN_TS == n->tok && MAN_BODY == n->type &&
+ strncmp(buf+offs, ".TE", 3)) {
+ n = n->parent;
+ return(tbl_read(n->data.TS, "<man>", ln, buf, offs) ? 1 : 0);
+ }
+
return(('.' == buf[offs] || '\'' == buf[offs]) ?
man_pmacro(m, ln, buf, offs) :
man_ptext(m, ln, buf, offs));
@@ -322,6 +332,8 @@ man_node_free(struct man_node *p)
if (p->string)
free(p->string);
+ if (p->data.TS)
+ tbl_free(p->data.TS);
free(p);
}
Index: man.h
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man.h,v
retrieving revision 1.26
diff -u -p -r1.26 man.h
--- man.h 20 Aug 2010 00:53:35 -0000 1.26
+++ man.h 14 Oct 2010 21:03:05 -0000
@@ -57,6 +57,8 @@ enum mant {
MAN_Ve,
MAN_AT,
MAN_in,
+ MAN_TS,
+ MAN_TE,
MAN_MAX
};
@@ -95,6 +97,9 @@ struct man_node {
char *string;
struct man_node *head;
struct man_node *body;
+ union {
+ struct tbl *TS;
+ } data;
};
extern const char *const *man_macronames;
Index: man_action.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_action.c,v
retrieving revision 1.24
diff -u -p -r1.24 man_action.c
--- man_action.c 25 Jul 2010 18:05:54 -0000 1.24
+++ man_action.c 14 Oct 2010 21:03:05 -0000
@@ -22,6 +22,9 @@
#include "mandoc.h"
#include "libman.h"
#include "libmandoc.h"
+#include "out.h"
+#include "term.h"
+#include "tbl.h"
struct actions {
int (*post)(struct man *);
@@ -32,6 +35,7 @@ static int post_fi(struct man *);
static int post_nf(struct man *);
static int post_AT(struct man *);
static int post_UC(struct man *);
+static int post_TS(struct man *);
const struct actions man_actions[MAN_MAX] = {
{ NULL }, /* br */
@@ -71,6 +75,8 @@ const struct actions man_actions[MAN_MAX
{ post_fi }, /* Ve */
{ post_AT }, /* AT */
{ NULL }, /* in */
+ { post_TS }, /* TS */
+ { NULL }, /* TE */
};
@@ -273,6 +279,17 @@ post_UC(struct man *m)
free(m->meta.source);
m->meta.source = mandoc_strdup(p);
+
+ return(1);
+}
+
+
+static int
+post_TS(struct man *m)
+{
+
+ if (MAN_HEAD == m->last->type)
+ m->last->parent->data.TS = tbl_alloc();
return(1);
}
Index: man_html.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_html.c,v
retrieving revision 1.18
diff -u -p -r1.18 man_html.c
--- man_html.c 25 Jul 2010 18:05:54 -0000 1.18
+++ man_html.c 14 Oct 2010 21:03:05 -0000
@@ -113,6 +113,8 @@ static const struct htmlman mans[MAN_MAX
{ man_literal_pre, NULL }, /* Ve */
{ man_ign_pre, NULL }, /* AT */
{ man_in_pre, NULL }, /* in */
+ { NULL, NULL }, /* TS */
+ { NULL, NULL }, /* TE */
};
Index: man_macro.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_macro.c,v
retrieving revision 1.20
diff -u -p -r1.20 man_macro.c
--- man_macro.c 25 Jul 2010 18:05:54 -0000 1.20
+++ man_macro.c 14 Oct 2010 21:03:06 -0000
@@ -80,6 +80,8 @@ const struct man_macro __man_macros[MAN_
{ in_line_eoln, 0 }, /* Ve */
{ in_line_eoln, 0 }, /* AT */
{ in_line_eoln, 0 }, /* in */
+ { blk_exp, MAN_EXPLICIT }, /* TS */
+ { blk_close, 0 }, /* TE */
};
const struct man_macro * const man_macros = __man_macros;
@@ -264,6 +266,9 @@ blk_close(MACRO_PROT_ARGS)
switch (tok) {
case (MAN_RE):
ntok = MAN_RS;
+ break;
+ case (MAN_TE):
+ ntok = MAN_TS;
break;
default:
abort();
Index: man_term.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_term.c,v
retrieving revision 1.46
diff -u -p -r1.46 man_term.c
--- man_term.c 21 Sep 2010 22:33:41 -0000 1.46
+++ man_term.c 14 Oct 2010 21:03:06 -0000
@@ -28,6 +28,7 @@
#include "term.h"
#include "chars.h"
#include "main.h"
+#include "tbl.h"
#define INDENT 7
#define HALFINDENT 3
@@ -92,6 +93,7 @@ static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
static int pre_literal(DECL_ARGS);
static int pre_sp(DECL_ARGS);
+static int pre_TS(DECL_ARGS);
static void post_IP(DECL_ARGS);
static void post_HP(DECL_ARGS);
@@ -138,6 +140,8 @@ static const struct termact termacts[MAN
{ pre_literal, NULL, 0 }, /* Ve */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
+ { pre_TS, NULL, 0 }, /* TS */
+ { NULL, NULL, 0 }, /* TE */
};
@@ -823,6 +827,23 @@ post_RS(DECL_ARGS)
p->offset = term_len(p, INDENT);
break;
}
+}
+
+
+/* ARGSUSED */
+static int
+pre_TS(DECL_ARGS)
+{
+
+ if (MAN_BLOCK != n->type)
+ return(0);
+
+ if ( ! tbl_close(n->data.TS, "<man>", n->line))
+ return(0);
+
+ tbl_write(p, n->data.TS);
+
+ return(0);
}
Index: man_validate.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/man_validate.c,v
retrieving revision 1.29
diff -u -p -r1.29 man_validate.c
--- man_validate.c 20 Aug 2010 00:53:35 -0000 1.29
+++ man_validate.c 14 Oct 2010 21:03:06 -0000
@@ -95,6 +95,8 @@ static const struct man_valid man_valids
{ pres_bline, posts_eq0 }, /* Ve */
{ NULL, NULL }, /* AT */
{ NULL, NULL }, /* in */
+ { NULL, NULL }, /* TS */
+ { NULL, NULL }, /* RE */
};
Index: tbl.c
===================================================================
RCS file: tbl.c
diff -N tbl.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl.c 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,546 @@
+/* $Id: tbl.c,v 1.14 2009/09/12 16:05:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "out.h"
+#include "term.h"
+#include "tbl.h"
+#include "tbl_extern.h"
+
+
+const char *const errnames[ERR_MAX] = {
+ "bad syntax", /* ERR_SYNTAX */
+ "bad option" /* ERR_OPTION */
+};
+
+static char buf[1024]; /* XXX */
+
+static enum tbl_tok tbl_next_char(char);
+static void tbl_init(struct tbl *);
+static void tbl_clear(struct tbl *);
+static struct tbl_head *tbl_head_alloc(struct tbl *);
+static void tbl_span_free(struct tbl_span *);
+static void tbl_data_free(struct tbl_data *);
+static void tbl_row_free(struct tbl_row *);
+
+static void headadj(const struct tbl_cell *,
+ struct tbl_head *);
+
+static void
+tbl_init(struct tbl *tbl)
+{
+
+ bzero(tbl, sizeof(struct tbl));
+
+ tbl->part = TBL_PART_OPTS;
+ tbl->tab = '\t';
+ tbl->linesize = 12;
+ tbl->decimal = '.';
+
+ TAILQ_INIT(&tbl->span);
+ TAILQ_INIT(&tbl->row);
+ TAILQ_INIT(&tbl->head);
+}
+
+
+int
+tbl_read(struct tbl *tbl, const char *f, int ln, const char *p, int len)
+{
+
+ if (len && TBL_PART_OPTS == tbl->part)
+ if (';' != p[len - 1])
+ tbl->part = TBL_PART_LAYOUT;
+
+ switch (tbl->part) {
+ case (TBL_PART_OPTS):
+ return(tbl_option(tbl, f, ln, p));
+ case (TBL_PART_CLAYOUT):
+ /* FALLTHROUGH */
+ case (TBL_PART_LAYOUT):
+ return(tbl_layout(tbl, f, ln, p));
+ case (TBL_PART_DATA):
+ return(tbl_data(tbl, f, ln, p));
+ case (TBL_PART_ERROR):
+ break;
+ }
+
+ return(0);
+}
+
+
+int
+tbl_close(struct tbl *tbl, const char *f, int ln)
+{
+
+ if (TBL_PART_DATA != tbl->part)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+ if ( ! tbl_data_close(tbl, f, ln))
+ return(0);
+#if 1
+ return(tbl_calc_term(tbl));
+#else
+ return(tbl_calc_tree(tbl));
+#endif
+}
+
+
+int
+tbl_write(struct termp *p, const struct tbl *tbl)
+{
+
+#if 1
+ return(tbl_write_term(p, tbl));
+#else
+ return(tbl_write_tree(tbl));
+#endif
+}
+
+
+static enum tbl_tok
+tbl_next_char(char c)
+{
+
+ /*
+ * These are delimiting tokens. They separate out words in the
+ * token stream.
+ */
+
+ switch (c) {
+ case ('('):
+ return(TBL_TOK_OPENPAREN);
+ case (')'):
+ return(TBL_TOK_CLOSEPAREN);
+ case (' '):
+ return(TBL_TOK_SPACE);
+ case ('\t'):
+ return(TBL_TOK_TAB);
+ case (';'):
+ return(TBL_TOK_SEMICOLON);
+ case ('.'):
+ return(TBL_TOK_PERIOD);
+ case (','):
+ return(TBL_TOK_COMMA);
+ case (0):
+ return(TBL_TOK_NIL);
+ default:
+ break;
+ }
+
+ return(TBL_TOK_WORD);
+}
+
+
+const char *
+tbl_last(void)
+{
+
+ return(buf);
+}
+
+
+int
+tbl_last_uint(void)
+{
+ char *ep;
+ long lval;
+
+ /* From OpenBSD's strtol(3). Gross. */
+
+ errno = 0;
+ lval = strtol(buf, &ep, 10);
+ if (buf[0] == 0 || *ep != 0)
+ return(-1);
+ if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
+ return(-1);
+ if (lval < 0 || lval > INT_MAX)
+ return(-1);
+
+ return((int)lval);
+}
+
+
+enum tbl_tok
+tbl_next(const char *p, int *pos)
+{
+ int i;
+ enum tbl_tok c;
+
+ buf[0] = 0;
+
+ if (TBL_TOK_WORD != (c = tbl_next_char(p[*pos]))) {
+ if (TBL_TOK_NIL != c) {
+ buf[0] = p[*pos];
+ buf[1] = 0;
+ (*pos)++;
+ }
+ return(c);
+ }
+
+ /*
+ * Copy words into a nil-terminated buffer. For now, we use a
+ * static buffer. Eventually this should be made into a dynamic
+ * one living in struct tbl.
+ */
+
+ for (i = 0; i < 1023; i++, (*pos)++)
+ if (TBL_TOK_WORD == tbl_next_char(p[*pos]))
+ buf[i] = p[*pos];
+ else
+ break;
+
+ assert(i < 1023);
+ buf[i] = 0;
+
+ return(TBL_TOK_WORD);
+}
+
+
+int
+tbl_err(struct tbl *tbl)
+{
+
+ (void)fprintf(stderr, "%s\n", strerror(errno));
+ tbl->part = TBL_PART_ERROR;
+ return(0);
+}
+
+
+/* ARGSUSED */
+int
+tbl_warnx(struct tbl *tbl, enum tbl_err tok,
+ const char *f, int line, int pos)
+{
+
+ (void)fprintf(stderr, "%s:%d:%d: %s\n",
+ f, line, pos + 1, errnames[tok]);
+
+ /* TODO: -Werror */
+ return(1);
+}
+
+
+int
+tbl_errx(struct tbl *tbl, enum tbl_err tok,
+ const char *f, int line, int pos)
+{
+
+ (void)fprintf(stderr, "%s:%d:%d: %s\n",
+ f, line, pos + 1, errnames[tok]);
+
+ tbl->part = TBL_PART_ERROR;
+ return(0);
+}
+
+
+struct tbl *
+tbl_alloc(void)
+{
+ struct tbl *p;
+
+ if (NULL == (p = malloc(sizeof(struct tbl))))
+ return(NULL);
+
+ tbl_init(p);
+ return(p);
+}
+
+
+void
+tbl_free(struct tbl *p)
+{
+
+ tbl_clear(p);
+ free(p);
+}
+
+
+void
+tbl_reset(struct tbl *tbl)
+{
+
+ tbl_clear(tbl);
+ tbl_init(tbl);
+}
+
+
+struct tbl_span *
+tbl_span_alloc(struct tbl *tbl)
+{
+ struct tbl_span *p, *pp;
+ struct tbl_row *row;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_span)))) {
+ (void)tbl_err(tbl);
+ return(NULL);
+ }
+
+ TAILQ_INIT(&p->data);
+ TAILQ_INSERT_TAIL(&tbl->span, p, entries);
+
+ /* LINTED */
+ pp = TAILQ_PREV(p, tbl_spanh, entries);
+
+ if (pp) {
+ row = TAILQ_NEXT(pp->row, entries);
+ if (NULL == row)
+ row = pp->row;
+ } else {
+ row = TAILQ_FIRST(&tbl->row);
+ }
+
+ assert(row);
+ p->row = row;
+ p->tbl = tbl;
+ return(p);
+}
+
+
+struct tbl_row *
+tbl_row_alloc(struct tbl *tbl)
+{
+ struct tbl_row *p;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_row)))) {
+ (void)tbl_err(tbl);
+ return(NULL);
+ }
+
+ TAILQ_INIT(&p->cell);
+ TAILQ_INSERT_TAIL(&tbl->row, p, entries);
+ p->tbl = tbl;
+ return(p);
+}
+
+
+static void
+headadj(const struct tbl_cell *cell, struct tbl_head *head)
+{
+ if (TBL_CELL_VERT != cell->pos &&
+ TBL_CELL_DVERT != cell->pos) {
+ head->pos = TBL_HEAD_DATA;
+ return;
+ }
+ if (TBL_CELL_VERT == cell->pos)
+ if (TBL_HEAD_DVERT != head->pos)
+ head->pos = TBL_HEAD_VERT;
+ if (TBL_CELL_DVERT == cell->pos)
+ head->pos = TBL_HEAD_DVERT;
+}
+
+
+static struct tbl_head *
+tbl_head_alloc(struct tbl *tbl)
+{
+ struct tbl_head *p;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_head)))) {
+ (void)tbl_err(tbl);
+ return(NULL);
+ }
+ p->tbl = tbl;
+ return(p);
+}
+
+
+struct tbl_cell *
+tbl_cell_alloc(struct tbl_row *rp, enum tbl_cellt pos)
+{
+ struct tbl_cell *p, *pp;
+ struct tbl_head *h, *hp;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_cell)))) {
+ (void)tbl_err(rp->tbl);
+ return(NULL);
+ }
+
+ TAILQ_INSERT_TAIL(&rp->cell, p, entries);
+ p->pos = pos;
+ p->row = rp;
+
+ /*
+ * This is a little bit complicated. Here we determine the
+ * header the corresponds to a cell. We add headers dynamically
+ * when need be or re-use them, otherwise. As an example, given
+ * the following:
+ *
+ * 1 c || l
+ * 2 | c | l
+ * 3 l l
+ * 3 || c | l |.
+ *
+ * We first add the new headers (as there are none) in (1); then
+ * in (2) we insert the first spanner (as it doesn't match up
+ * with the header); then we re-use the prior data headers,
+ * skipping over the spanners; then we re-use everything and add
+ * a last spanner. Note that VERT headers are made into DVERT
+ * ones.
+ */
+
+ /* LINTED */
+ pp = TAILQ_PREV(p, tbl_cellh, entries);
+
+ h = pp ? TAILQ_NEXT(pp->head, entries) :
+ TAILQ_FIRST(&rp->tbl->head);
+
+ if (h) {
+ /* Re-use data header. */
+ if (TBL_HEAD_DATA == h->pos &&
+ (TBL_CELL_VERT != p->pos &&
+ TBL_CELL_DVERT != p->pos)) {
+ p->head = h;
+ return(p);
+ }
+
+ /* Re-use spanner header. */
+ if (TBL_HEAD_DATA != h->pos &&
+ (TBL_CELL_VERT == p->pos ||
+ TBL_CELL_DVERT == p->pos)) {
+ headadj(p, h);
+ p->head = h;
+ return(p);
+ }
+
+ /* Right-shift headers with a new spanner. */
+ if (TBL_HEAD_DATA == h->pos &&
+ (TBL_CELL_VERT == p->pos ||
+ TBL_CELL_DVERT == p->pos)) {
+ if (NULL == (hp = tbl_head_alloc(rp->tbl)))
+ return(NULL);
+ TAILQ_INSERT_BEFORE(h, hp, entries);
+ headadj(p, hp);
+ p->head = hp;
+ return(p);
+ }
+
+ h = TAILQ_NEXT(h, entries);
+ if (h) {
+ headadj(p, h);
+ p->head = h;
+ return(p);
+ }
+
+ /* Fall through to default case... */
+ }
+
+ if (NULL == (hp = tbl_head_alloc(rp->tbl)))
+ return(NULL);
+ TAILQ_INSERT_TAIL(&rp->tbl->head, hp, entries);
+ headadj(p, hp);
+ p->head = hp;
+ return(p);
+}
+
+
+struct tbl_data *
+tbl_data_alloc(struct tbl_span *sp)
+{
+ struct tbl_data *p;
+ struct tbl_cell *cp;
+ struct tbl_data *dp;
+
+ if (NULL == (p = calloc(1, sizeof(struct tbl_data)))) {
+ (void)tbl_err(sp->row->tbl);
+ return(NULL);
+ }
+
+ cp = NULL;
+ /* LINTED */
+ if (NULL == (dp = TAILQ_LAST(&sp->data, tbl_datah)))
+ cp = TAILQ_FIRST(&sp->row->cell);
+ else if (dp->cell)
+ cp = TAILQ_NEXT(dp->cell, entries);
+
+ TAILQ_INSERT_TAIL(&sp->data, p, entries);
+
+ if (cp && (TBL_CELL_VERT == cp->pos ||
+ TBL_CELL_DVERT == cp->pos))
+ cp = TAILQ_NEXT(cp, entries);
+
+ p->span = sp;
+ p->cell = cp;
+ return(p);
+}
+
+
+static void
+tbl_clear(struct tbl *p)
+{
+ struct tbl_span *span;
+ struct tbl_head *head;
+ struct tbl_row *row;
+
+ /* LINTED */
+ while ((span = TAILQ_FIRST(&p->span))) {
+ TAILQ_REMOVE(&p->span, span, entries);
+ tbl_span_free(span);
+ }
+ /* LINTED */
+ while ((row = TAILQ_FIRST(&p->row))) {
+ TAILQ_REMOVE(&p->row, row, entries);
+ tbl_row_free(row);
+ }
+ /* LINTED */
+ while ((head = TAILQ_FIRST(&p->head))) {
+ TAILQ_REMOVE(&p->head, head, entries);
+ free(head);
+ }
+}
+
+
+static void
+tbl_span_free(struct tbl_span *p)
+{
+ struct tbl_data *data;
+
+ /* LINTED */
+ while ((data = TAILQ_FIRST(&p->data))) {
+ TAILQ_REMOVE(&p->data, data, entries);
+ tbl_data_free(data);
+ }
+ free(p);
+}
+
+
+static void
+tbl_data_free(struct tbl_data *p)
+{
+
+ if (p->string)
+ free(p->string);
+ free(p);
+}
+
+
+static void
+tbl_row_free(struct tbl_row *p)
+{
+ struct tbl_cell *cell;
+
+ /* LINTED */
+ while ((cell = TAILQ_FIRST(&p->cell))) {
+ TAILQ_REMOVE(&p->cell, cell, entries);
+ free(cell);
+ }
+ free(p);
+}
Index: tbl.h
===================================================================
RCS file: tbl.h
diff -N tbl.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl.h 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,34 @@
+/* $Id: tbl.h,v 1.3 2009/09/11 15:01:24 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef TBL_H
+#define TBL_H
+
+__BEGIN_DECLS
+
+struct tbl;
+
+struct tbl *tbl_alloc(void);
+void tbl_free(struct tbl *);
+void tbl_reset(struct tbl *);
+
+int tbl_read(struct tbl *, const char *, int, const char *, int);
+int tbl_close(struct tbl *, const char *, int);
+int tbl_write(struct termp *, const struct tbl *);
+
+__END_DECLS
+
+#endif /*TBL_H*/
Index: tbl_data.c
===================================================================
RCS file: tbl_data.c
diff -N tbl_data.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_data.c 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,132 @@
+/* $Id: data.c,v 1.11 2009/09/12 16:05:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "out.h"
+#include "term.h"
+#include "tbl_extern.h"
+
+/* FIXME: warn about losing data contents if cell is HORIZ. */
+
+static int data(struct tbl *, struct tbl_span *,
+ const char *, int, int,
+ const char *, int, int);
+
+
+int
+data(struct tbl *tbl, struct tbl_span *dp,
+ const char *f, int ln, int pos,
+ const char *p, int start, int end)
+{
+ struct tbl_data *dat;
+
+ if (NULL == (dat = tbl_data_alloc(dp)))
+ return(0);
+
+ if (NULL == dat->cell)
+ if ( ! tbl_warnx(tbl, ERR_SYNTAX, f, ln, pos))
+ return(0);
+
+ assert(end >= start);
+ if (NULL == (dat->string = malloc((size_t)(end - start + 1))))
+ return(tbl_err(tbl));
+
+ (void)memcpy(dat->string, &p[start], (size_t)(end - start));
+ dat->string[end - start] = 0;
+
+ /* XXX: do the strcmps, then malloc(). */
+
+ if ( ! strcmp(dat->string, "_"))
+ dat->flags |= TBL_DATA_HORIZ;
+ else if ( ! strcmp(dat->string, "="))
+ dat->flags |= TBL_DATA_DHORIZ;
+ else if ( ! strcmp(dat->string, "\\_"))
+ dat->flags |= TBL_DATA_NHORIZ;
+ else if ( ! strcmp(dat->string, "\\="))
+ dat->flags |= TBL_DATA_NDHORIZ;
+ else
+ return(1);
+
+ free(dat->string);
+ dat->string = NULL;
+ return(1);
+}
+
+
+int
+tbl_data(struct tbl *tbl, const char *f, int ln, const char *p)
+{
+ struct tbl_span *dp;
+ int i, j;
+
+ if (0 == p[0])
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+
+ if ('.' == p[0] && ! isdigit((u_char)p[1])) {
+ /*
+ * XXX: departs from tbl convention in that we disallow
+ * macros in the data body.
+ */
+ if (strncasecmp(p, ".T&", 3))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+ return(tbl_data_close(tbl, f, ln));
+ }
+
+ if (NULL == (dp = tbl_span_alloc(tbl)))
+ return(0);
+
+ if ( ! strcmp(p, "_")) {
+ dp->flags |= TBL_SPAN_HORIZ;
+ return(1);
+ } else if ( ! strcmp(p, "=")) {
+ dp->flags |= TBL_SPAN_DHORIZ;
+ return(1);
+ }
+
+ for (j = i = 0; p[i]; i++) {
+ if (p[i] != tbl->tab)
+ continue;
+ if ( ! data(tbl, dp, f, ln, i, p, j, i))
+ return(0);
+ j = i + 1;
+ }
+
+ return(data(tbl, dp, f, ln, i, p, j, i));
+}
+
+
+int
+tbl_data_close(struct tbl *tbl, const char *f, int ln)
+{
+ struct tbl_span *span;
+
+ /* LINTED */
+ span = TAILQ_LAST(&tbl->span, tbl_spanh);
+ if (NULL == span)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+ if (TAILQ_NEXT(span->row, entries))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0));
+
+ tbl->part = TBL_PART_LAYOUT;
+ return(1);
+}
Index: tbl_extern.h
===================================================================
RCS file: tbl_extern.h
diff -N tbl_extern.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_extern.h 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,183 @@
+/* $Id: extern.h,v 1.10 2009/09/13 12:37:28 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef TBL_EXTERN_H
+#define TBL_EXTERN_H
+
+enum tbl_err {
+ ERR_SYNTAX,
+ ERR_OPTION,
+ ERR_MAX
+};
+
+enum tbl_tok {
+ TBL_TOK_WORD,
+ TBL_TOK_OPENPAREN,
+ TBL_TOK_CLOSEPAREN,
+ TBL_TOK_COMMA,
+ TBL_TOK_SEMICOLON,
+ TBL_TOK_PERIOD,
+ TBL_TOK_SPACE,
+ TBL_TOK_TAB,
+ TBL_TOK_NIL
+};
+
+enum tbl_part {
+ TBL_PART_OPTS,
+ TBL_PART_LAYOUT,
+ TBL_PART_CLAYOUT,
+ TBL_PART_DATA,
+ TBL_PART_ERROR
+};
+
+struct tbl;
+struct tbl_head;
+struct tbl_row;
+struct tbl_cell;
+struct tbl_span;
+struct tbl_data;
+
+TAILQ_HEAD(tbl_rowh, tbl_row);
+TAILQ_HEAD(tbl_cellh, tbl_cell);
+TAILQ_HEAD(tbl_headh, tbl_head);
+TAILQ_HEAD(tbl_spanh, tbl_span);
+TAILQ_HEAD(tbl_datah, tbl_data);
+
+struct tbl {
+ enum tbl_part part;
+ int opts;
+#define TBL_OPT_CENTRE (1 << 0)
+#define TBL_OPT_EXPAND (1 << 1)
+#define TBL_OPT_BOX (1 << 2)
+#define TBL_OPT_DBOX (1 << 3)
+#define TBL_OPT_ALLBOX (1 << 4)
+#define TBL_OPT_NOKEEP (1 << 5)
+#define TBL_OPT_NOSPACE (1 << 6)
+ char tab;
+ char decimal;
+ int linesize;
+ char delims[2];
+ struct tbl_spanh span;
+ struct tbl_headh head;
+ struct tbl_rowh row;
+};
+
+enum tbl_headt {
+ TBL_HEAD_DATA,
+ TBL_HEAD_VERT,
+ TBL_HEAD_DVERT,
+ TBL_HEAD_MAX
+};
+
+struct tbl_head {
+ struct tbl *tbl;
+ enum tbl_headt pos;
+ int width;
+ int decimal;
+ TAILQ_ENTRY(tbl_head) entries;
+};
+
+struct tbl_row {
+ struct tbl *tbl;
+ struct tbl_cellh cell;
+ TAILQ_ENTRY(tbl_row) entries;
+};
+
+enum tbl_cellt {
+ TBL_CELL_CENTRE, /* c, C */
+ TBL_CELL_RIGHT, /* r, R */
+ TBL_CELL_LEFT, /* l, L */
+ TBL_CELL_NUMBER, /* n, N */
+ TBL_CELL_SPAN, /* s, S */
+ TBL_CELL_LONG, /* a, A */
+ TBL_CELL_DOWN, /* ^ */
+ TBL_CELL_HORIZ, /* _, - */
+ TBL_CELL_DHORIZ, /* = */
+ TBL_CELL_VERT, /* | */
+ TBL_CELL_DVERT, /* || */
+ TBL_CELL_MAX
+};
+
+struct tbl_cell {
+ struct tbl_row *row;
+ struct tbl_head *head;
+ enum tbl_cellt pos;
+ int spacing;
+ int flags;
+#define TBL_CELL_TALIGN (1 << 0) /* t, T */
+#define TBL_CELL_BALIGN (1 << 1) /* d, D */
+#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */
+#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */
+#define TBL_CELL_EQUAL (1 << 4) /* e, E */
+#define TBL_CELL_UP (1 << 5) /* u, U */
+#define TBL_CELL_WIGN (1 << 6) /* z, Z */
+ TAILQ_ENTRY(tbl_cell) entries;
+};
+
+struct tbl_data {
+ struct tbl_span *span;
+ struct tbl_cell *cell;
+ int flags;
+#define TBL_DATA_HORIZ (1 << 0)
+#define TBL_DATA_DHORIZ (1 << 1)
+#define TBL_DATA_NHORIZ (1 << 2)
+#define TBL_DATA_NDHORIZ (1 << 3)
+ char *string;
+ TAILQ_ENTRY(tbl_data) entries;
+};
+
+struct tbl_span {
+ struct tbl_row *row;
+ struct tbl *tbl;
+ int flags;
+#define TBL_SPAN_HORIZ (1 << 0)
+#define TBL_SPAN_DHORIZ (1 << 1)
+ struct tbl_datah data;
+ TAILQ_ENTRY(tbl_span) entries;
+};
+
+__BEGIN_DECLS
+
+int tbl_option(struct tbl *,
+ const char *, int, const char *);
+int tbl_layout(struct tbl *,
+ const char *, int, const char *);
+int tbl_data(struct tbl *,
+ const char *, int, const char *);
+int tbl_data_close(struct tbl *, const char *, int);
+
+enum tbl_tok tbl_next(const char *, int *);
+const char *tbl_last(void);
+int tbl_last_uint(void);
+int tbl_errx(struct tbl *, enum tbl_err,
+ const char *, int, int);
+int tbl_warnx(struct tbl *, enum tbl_err,
+ const char *, int, int);
+int tbl_err(struct tbl *);
+
+struct tbl_row *tbl_row_alloc(struct tbl *);
+struct tbl_cell *tbl_cell_alloc(struct tbl_row *, enum tbl_cellt);
+struct tbl_span *tbl_span_alloc(struct tbl *);
+struct tbl_data *tbl_data_alloc(struct tbl_span *);
+
+int tbl_write_term(struct termp *, const struct tbl *);
+int tbl_calc_term(struct tbl *);
+int tbl_write_tree(const struct tbl *);
+int tbl_calc_tree(struct tbl *);
+
+__END_DECLS
+
+#endif /*TBL_EXTERN_H*/
Index: tbl_layout.c
===================================================================
RCS file: tbl_layout.c
diff -N tbl_layout.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_layout.c 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,282 @@
+/* $Id: layout.c,v 1.7 2009/09/11 13:24:04 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "out.h"
+#include "term.h"
+#include "tbl_extern.h"
+
+struct tbl_phrase {
+ char name;
+ enum tbl_cellt key;
+};
+
+#define KEYS_MAX 17
+
+static const struct tbl_phrase keys[KEYS_MAX] = {
+ { 'c', TBL_CELL_CENTRE },
+ { 'C', TBL_CELL_CENTRE },
+ { 'r', TBL_CELL_RIGHT },
+ { 'R', TBL_CELL_RIGHT },
+ { 'l', TBL_CELL_LEFT },
+ { 'L', TBL_CELL_LEFT },
+ { 'n', TBL_CELL_NUMBER },
+ { 'N', TBL_CELL_NUMBER },
+ { 's', TBL_CELL_SPAN },
+ { 'S', TBL_CELL_SPAN },
+ { 'a', TBL_CELL_LONG },
+ { 'A', TBL_CELL_LONG },
+ { '^', TBL_CELL_DOWN },
+ { '-', TBL_CELL_HORIZ },
+ { '_', TBL_CELL_HORIZ },
+ { '=', TBL_CELL_DHORIZ },
+ { '|', TBL_CELL_VERT }
+};
+
+static int mods(struct tbl *, struct tbl_cell *,
+ const char *, int,
+ const char *, int, int);
+static int cell(struct tbl *, struct tbl_row *,
+ const char *, int, int);
+static int row(struct tbl *, const char *,
+ int, const char *, int *);
+
+
+static int
+mods(struct tbl *tbl, struct tbl_cell *cp, const char *p,
+ int pp, const char *f, int ln, int pos)
+{
+ char buf[5];
+ int i;
+
+ /*
+ * XXX: since, at least for now, modifiers are non-conflicting
+ * (are separable by value, regardless of position), we let
+ * modifiers come in any order. The existing tbl doesn't let
+ * this happen.
+ */
+
+ if (0 == p[pp])
+ return(1);
+
+ /* Parse numerical spacing from modifier string. */
+
+ if (isdigit((u_char)p[pp])) {
+ for (i = 0; i < 4; i++) {
+ if ( ! isdigit((u_char)p[pp + i]))
+ break;
+ buf[i] = p[pp + i];
+ }
+ buf[i] = 0;
+
+ /* No greater than 4 digits. */
+
+ if (4 == i)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp));
+
+ /*
+ * We can't change the spacing in any subsequent layout
+ * definitions. FIXME: I don't think we can change the
+ * spacing for a column at all, after it's already been
+ * initialised.
+ */
+
+ if (TBL_PART_CLAYOUT != tbl->part)
+ cp->spacing = atoi(buf);
+ else if ( ! tbl_warnx(tbl, ERR_SYNTAX, f, ln, pos + pp))
+ return(0);
+
+ /* Continue parsing modifiers. */
+
+ return(mods(tbl, cp, p, pp + i, f, ln, pos));
+ }
+
+ /* TODO: GNU has many more extensions. */
+
+ switch (p[pp]) {
+ case ('z'):
+ /* FALLTHROUGH */
+ case ('Z'):
+ cp->flags |= TBL_CELL_WIGN;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('u'):
+ /* FALLTHROUGH */
+ case ('U'):
+ cp->flags |= TBL_CELL_UP;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('e'):
+ /* FALLTHROUGH */
+ case ('E'):
+ cp->flags |= TBL_CELL_EQUAL;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('t'):
+ /* FALLTHROUGH */
+ case ('T'):
+ cp->flags |= TBL_CELL_TALIGN;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('d'):
+ /* FALLTHROUGH */
+ case ('D'):
+ cp->flags |= TBL_CELL_BALIGN;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('f'):
+ pp++;
+ /* FALLTHROUGH */
+ case ('B'):
+ /* FALLTHROUGH */
+ case ('I'):
+ /* FALLTHROUGH */
+ case ('b'):
+ /* FALLTHROUGH */
+ case ('i'):
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp));
+ }
+
+ switch (p[pp]) {
+ case ('b'):
+ /* FALLTHROUGH */
+ case ('B'):
+ cp->flags |= TBL_CELL_BOLD;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ case ('i'):
+ /* FALLTHROUGH */
+ case ('I'):
+ cp->flags |= TBL_CELL_ITALIC;
+ return(mods(tbl, cp, p, pp + 1, f, ln, pos));
+ default:
+ break;
+ }
+
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp));
+}
+
+
+static int
+cell(struct tbl *tbl, struct tbl_row *rp,
+ const char *f, int ln, int pos)
+{
+ struct tbl_cell *cp;
+ const char *p;
+ int j, i;
+ enum tbl_cellt c;
+
+ /* Parse the column position (`r', `R', `|', ...). */
+
+ c = TBL_CELL_MAX;
+ for (p = tbl_last(), i = 0; i < KEYS_MAX; i++) {
+ if (keys[i].name != p[0])
+ continue;
+ c = keys[i].key;
+ break;
+ }
+
+ if (i == KEYS_MAX)
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos));
+
+ /* Extra check for the double-vertical. */
+
+ if (TBL_CELL_VERT == c && '|' == p[1]) {
+ j = 2;
+ c = TBL_CELL_DVERT;
+ } else
+ j = 1;
+
+ /* Disallow subsequent spacers. */
+
+ /* LINTED */
+ cp = TAILQ_LAST(&rp->cell, tbl_cellh);
+
+ if (cp && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) &&
+ (TBL_CELL_VERT == cp->pos ||
+ TBL_CELL_DVERT == cp->pos))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos));
+
+ /* Allocate cell then parse its modifiers. */
+
+ if (NULL == (cp = tbl_cell_alloc(rp, c)))
+ return(0);
+ return(mods(tbl, cp, p, j, f, ln, pos));
+}
+
+
+static int
+row(struct tbl *tbl, const char *f, int ln,
+ const char *p, int *pos)
+{
+ struct tbl_row *rp;
+ int sv;
+
+ rp = tbl_row_alloc(tbl);
+again:
+ sv = *pos;
+
+ /*
+ * EBNF describing this section:
+ *
+ * row ::= row_list [:space:]* [.]?[\n]
+ * row_list ::= [:space:]* row_elem row_tail
+ * row_tail ::= [:space:]*[,] row_list |
+ * epsilon
+ * row_elem ::= [\t\ ]*[:alpha:]+
+ */
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_TAB):
+ /* FALLTHROUGH */
+ case (TBL_TOK_SPACE):
+ goto again;
+ case (TBL_TOK_WORD):
+ if ( ! cell(tbl, rp, f, ln, sv))
+ return(0);
+ goto again;
+ case (TBL_TOK_COMMA):
+ if (NULL == TAILQ_FIRST(&rp->cell))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ return(row(tbl, f, ln, p, pos));
+ case (TBL_TOK_PERIOD):
+ if (NULL == TAILQ_FIRST(&rp->cell))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->part = TBL_PART_DATA;
+ break;
+ case (TBL_TOK_NIL):
+ if (NULL == TAILQ_FIRST(&rp->cell))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ return(1);
+}
+
+
+int
+tbl_layout(struct tbl *tbl, const char *f, int ln, const char *p)
+{
+ int pos;
+
+ pos = 0;
+ return(row(tbl, f, ln, p, &pos));
+}
Index: tbl_option.c
===================================================================
RCS file: tbl_option.c
diff -N tbl_option.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_option.c 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,197 @@
+/* $Id: option.c,v 1.5 2009/09/09 12:51:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "out.h"
+#include "term.h"
+#include "tbl_extern.h"
+
+struct tbl_phrase {
+ char *name;
+ int key;
+ int ident;
+#define KEY_CENTRE 0
+#define KEY_DELIM 1
+#define KEY_EXPAND 2
+#define KEY_BOX 3
+#define KEY_DBOX 4
+#define KEY_ALLBOX 5
+#define KEY_TAB 6
+#define KEY_LINESIZE 7
+#define KEY_NOKEEP 8
+#define KEY_DPOINT 9
+#define KEY_NOSPACE 10
+#define KEY_FRAME 11
+#define KEY_DFRAME 12
+};
+
+#define KEY_MAXKEYS 14
+
+static const struct tbl_phrase keys[KEY_MAXKEYS] = {
+ { "center", TBL_OPT_CENTRE, KEY_CENTRE},
+ { "centre", TBL_OPT_CENTRE, KEY_CENTRE},
+ { "delim", 0, KEY_DELIM},
+ { "expand", TBL_OPT_EXPAND, KEY_EXPAND},
+ { "box", TBL_OPT_BOX, KEY_BOX},
+ { "doublebox", TBL_OPT_DBOX, KEY_DBOX},
+ { "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX},
+ { "frame", TBL_OPT_BOX, KEY_FRAME},
+ { "doubleframe", TBL_OPT_DBOX, KEY_DFRAME},
+ { "tab", 0, KEY_TAB},
+ { "linesize", 0, KEY_LINESIZE},
+ { "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP},
+ { "decimalpoint", 0, KEY_DPOINT},
+ { "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE},
+};
+
+static int arg(struct tbl *, const char *,
+ int, const char *, int *, int);
+static int opt(struct tbl *, const char *,
+ int, const char *, int *);
+
+static int
+arg(struct tbl *tbl, const char *f, int ln,
+ const char *p, int *pos, int key)
+{
+ const char *buf;
+ int sv;
+
+again:
+ sv = *pos;
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_OPENPAREN):
+ break;
+ case (TBL_TOK_SPACE):
+ /* FALLTHROUGH */
+ case (TBL_TOK_TAB):
+ goto again;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ sv = *pos;
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_WORD):
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ buf = tbl_last();
+
+ switch (key) {
+ case (KEY_DELIM):
+ if (2 != strlen(buf))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->delims[0] = buf[0];
+ tbl->delims[1] = buf[1];
+ break;
+ case (KEY_TAB):
+ if (1 != strlen(buf))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->tab = buf[0];
+ break;
+ case (KEY_LINESIZE):
+ if (-1 == (tbl->linesize = tbl_last_uint()))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ break;
+ case (KEY_DPOINT):
+ if (1 != strlen(buf))
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ tbl->decimal = buf[0];
+ break;
+ default:
+ abort();
+ }
+
+ sv = *pos;
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_CLOSEPAREN):
+ break;
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ return(1);
+}
+
+
+static int
+opt(struct tbl *tbl, const char *f, int ln, const char *p, int *pos)
+{
+ int i, sv;
+
+again:
+ sv = *pos;
+
+ /*
+ * EBNF describing this section:
+ *
+ * options ::= option_list [:space:]* [;][\n]
+ * option_list ::= option option_tail
+ * option_tail ::= [:space:]+ option_list |
+ * ::= epsilon
+ * option ::= [:alpha:]+ args
+ * args ::= [:space:]* [(] [:alpha:]+ [)]
+ */
+
+ switch (tbl_next(p, pos)) {
+ case (TBL_TOK_WORD):
+ break;
+ case (TBL_TOK_SPACE):
+ /* FALLTHROUGH */
+ case (TBL_TOK_TAB):
+ goto again;
+ case (TBL_TOK_SEMICOLON):
+ tbl->part = TBL_PART_LAYOUT;
+ return(1);
+ default:
+ return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv));
+ }
+
+ for (i = 0; i < KEY_MAXKEYS; i++) {
+ if (strcasecmp(tbl_last(), keys[i].name))
+ continue;
+ if (keys[i].key)
+ tbl->opts |= keys[i].key;
+ else if ( ! arg(tbl, f, ln, p, pos, keys[i].ident))
+ return(0);
+
+ break;
+ }
+
+ if (KEY_MAXKEYS == i)
+ return(tbl_errx(tbl, ERR_OPTION, f, ln, sv));
+
+ return(opt(tbl, f, ln, p, pos));
+}
+
+
+int
+tbl_option(struct tbl *tbl, const char *f, int ln, const char *p)
+{
+ int pos;
+
+ pos = 0;
+ return(opt(tbl, f, ln, p, &pos));
+}
Index: tbl_term.c
===================================================================
RCS file: tbl_term.c
diff -N tbl_term.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_term.c 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,518 @@
+/* $Id: term.c,v 1.13 2009/09/14 09:06:40 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "out.h"
+#include "term.h"
+#include "tbl_extern.h"
+
+/* FIXME: `n' modifier doesn't always do the right thing. */
+/* FIXME: `n' modifier doesn't use the cell-spacing buffer. */
+
+static void calc_data(struct tbl_data *);
+static void calc_data_literal(struct tbl_data *);
+static void calc_data_number(struct tbl_data *);
+static void calc_data_spanner(struct tbl_data *);
+static inline void write_char(struct termp *, char, int);
+static void write_data(struct termp *,
+ const struct tbl_data *, int);
+static void write_data_literal(struct termp *,
+ const struct tbl_data *, int);
+static void write_data_number(struct termp *,
+ const struct tbl_data *, int);
+static void write_data_spanner(struct termp *,
+ const struct tbl_data *, int);
+static void write_hframe(struct termp *, const struct tbl *);
+static void write_hrule(struct termp *, const struct tbl_span *);
+static void write_spanner(struct termp *, const struct tbl_head *);
+static void write_vframe(struct termp *, const struct tbl *);
+
+
+int
+tbl_write_term(struct termp *p, const struct tbl *tbl)
+{
+ const struct tbl_span *span;
+ const struct tbl_data *data;
+ const struct tbl_head *head;
+
+ /*
+ * Note that the absolute widths and decimal places for headers
+ * were set when tbl_calc_term was called.
+ */
+
+ p->flags |= TERMP_NONOSPACE;
+
+ /* First, write out our head horizontal frame. */
+
+ write_hframe(p, tbl);
+
+ /*
+ * Iterate through each span, and inside, through the global
+ * headers. If the global header's a spanner, print it
+ * directly; if it's data, use the corresponding data in the
+ * span as the object to print.
+ */
+
+ TAILQ_FOREACH(span, &tbl->span, entries) {
+ write_vframe(p, tbl);
+
+ /* Accomodate for the horizontal rule. */
+ if (TBL_DATA_DHORIZ & span->flags ||
+ TBL_DATA_HORIZ & span->flags) {
+ write_hrule(p, span);
+ write_vframe(p, tbl);
+ term_flushln(p);
+ continue;
+ }
+
+ data = TAILQ_FIRST(&span->data);
+ TAILQ_FOREACH(head, &tbl->head, entries) {
+ switch (head->pos) {
+ case (TBL_HEAD_VERT):
+ /* FALLTHROUGH */
+ case (TBL_HEAD_DVERT):
+ write_spanner(p, head);
+ break;
+ case (TBL_HEAD_DATA):
+ write_data(p, data, head->width);
+ if (data)
+ data = TAILQ_NEXT(data, entries);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ }
+ write_vframe(p, tbl);
+ term_flushln(p);
+ }
+
+ /* Last, write out our tail horizontal frame. */
+
+ write_hframe(p, tbl);
+
+ p->flags &= ~TERMP_NONOSPACE;
+
+ return(1);
+}
+
+
+int
+tbl_calc_term(struct tbl *tbl)
+{
+ struct tbl_span *span;
+ struct tbl_data *data;
+ struct tbl_head *head;
+
+ /* Calculate width as the max of column cells' widths. */
+
+ TAILQ_FOREACH(span, &tbl->span, entries) {
+ if (TBL_DATA_HORIZ & span->flags)
+ continue;
+ if (TBL_DATA_DHORIZ & span->flags)
+ continue;
+ if (TBL_DATA_NHORIZ & span->flags)
+ continue;
+ if (TBL_DATA_NDHORIZ & span->flags)
+ continue;
+ TAILQ_FOREACH(data, &span->data, entries)
+ calc_data(data);
+ }
+
+ /* Calculate width as the simple spanner value. */
+
+ TAILQ_FOREACH(head, &tbl->head, entries)
+ switch (head->pos) {
+ case (TBL_HEAD_VERT):
+ head->width = 1;
+ break;
+ case (TBL_HEAD_DVERT):
+ head->width = 2;
+ break;
+ default:
+ break;
+ }
+
+ return(1);
+}
+
+
+static void
+write_hrule(struct termp *p, const struct tbl_span *span)
+{
+ const struct tbl_head *head;
+ char c;
+
+ /*
+ * An hrule extends across the entire table and is demarked by a
+ * standalone `_' or whatnot in lieu of a table row. Spanning
+ * headers are marked by a `+', as are table boundaries.
+ */
+
+ c = '-';
+ if (TBL_SPAN_DHORIZ & span->flags)
+ c = '=';
+
+ /* FIXME: don't use `+' between data and a spanner! */
+
+ TAILQ_FOREACH(head, &span->tbl->head, entries) {
+ switch (head->pos) {
+ case (TBL_HEAD_DATA):
+ write_char(p, c, head->width);
+ break;
+ case (TBL_HEAD_DVERT):
+ write_char(p, '+', head->width);
+ /* FALLTHROUGH */
+ case (TBL_HEAD_VERT):
+ write_char(p, '+', head->width);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ }
+}
+
+
+static void
+write_hframe(struct termp *p, const struct tbl *tbl)
+{
+ const struct tbl_head *head;
+
+ if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts))
+ return;
+
+ /*
+ * Print out the horizontal part of a frame or double frame. A
+ * double frame has an unbroken `-' outer line the width of the
+ * table, bordered by `+'. The frame (or inner frame, in the
+ * case of the double frame) is a `-' bordered by `+' and broken
+ * by `+' whenever a span is encountered.
+ */
+
+ if (TBL_OPT_DBOX & tbl->opts) {
+ term_word(p, "+");
+ TAILQ_FOREACH(head, &tbl->head, entries)
+ write_char(p, '-', head->width);
+ term_word(p, "+");
+ term_flushln(p);
+ }
+
+ term_word(p, "+");
+ TAILQ_FOREACH(head, &tbl->head, entries) {
+ switch (head->pos) {
+ case (TBL_HEAD_DATA):
+ write_char(p, '-', head->width);
+ break;
+ default:
+ write_char(p, '+', head->width);
+ break;
+ }
+ }
+ term_word(p, "+");
+ term_flushln(p);
+}
+
+
+static void
+write_vframe(struct termp *p, const struct tbl *tbl)
+{
+ /* Always just a single vertical line. */
+
+ if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts))
+ return;
+ term_word(p, "|");
+}
+
+
+static void
+calc_data_spanner(struct tbl_data *data)
+{
+
+ /* N.B., these are horiz spanners (not vert) so always 1. */
+ data->cell->head->width = 1;
+}
+
+
+static void
+calc_data_number(struct tbl_data *data)
+{
+ int sz, d;
+ char *dp, pnt;
+
+ /*
+ * First calculate number width and decimal place (last + 1 for
+ * no-decimal numbers). If the stored decimal is subsequent
+ * ours, make our size longer by that difference
+ * (right-"shifting"); similarly, if ours is subsequent the
+ * stored, then extend the stored size by the difference.
+ * Finally, re-assign the stored values.
+ */
+
+ /* TODO: use spacing modifier. */
+
+ assert(data->string);
+ sz = (int)strlen(data->string);
+ pnt = data->span->tbl->decimal;
+
+ if (NULL == (dp = strchr(data->string, pnt)))
+ d = sz + 1;
+ else
+ d = (int)(dp - data->string) + 1;
+
+ sz += 2;
+
+ if (data->cell->head->decimal > d) {
+ sz += data->cell->head->decimal - d;
+ d = data->cell->head->decimal;
+ } else
+ data->cell->head->width +=
+ d - data->cell->head->decimal;
+
+ if (sz > data->cell->head->width)
+ data->cell->head->width = sz;
+ if (d > data->cell->head->decimal)
+ data->cell->head->decimal = d;
+}
+
+
+static void
+calc_data_literal(struct tbl_data *data)
+{
+ int sz, bufsz;
+
+ /*
+ * Calculate our width and use the spacing, with a minimum
+ * spacing dictated by position (centre, e.g,. gets a space on
+ * either side, while right/left get a single adjacent space).
+ */
+
+ assert(data->string);
+ sz = (int)strlen(data->string);
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_LONG):
+ /* FALLTHROUGH */
+ case (TBL_CELL_CENTRE):
+ bufsz = 2;
+ break;
+ default:
+ bufsz = 1;
+ break;
+ }
+
+ if (data->cell->spacing)
+ bufsz = bufsz > data->cell->spacing ?
+ bufsz : data->cell->spacing;
+
+ sz += bufsz;
+ if (data->cell->head->width < sz)
+ data->cell->head->width = sz;
+}
+
+
+static void
+calc_data(struct tbl_data *data)
+{
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_HORIZ):
+ /* FALLTHROUGH */
+ case (TBL_CELL_DHORIZ):
+ calc_data_spanner(data);
+ break;
+ case (TBL_CELL_LONG):
+ /* FALLTHROUGH */
+ case (TBL_CELL_CENTRE):
+ /* FALLTHROUGH */
+ case (TBL_CELL_LEFT):
+ /* FALLTHROUGH */
+ case (TBL_CELL_RIGHT):
+ calc_data_literal(data);
+ break;
+ case (TBL_CELL_NUMBER):
+ calc_data_number(data);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+}
+
+
+static void
+write_data_spanner(struct termp *p, const struct tbl_data *data, int width)
+{
+
+ /*
+ * Write spanners dictated by both our cell designation (in the
+ * layout) or as data.
+ */
+ if (TBL_DATA_HORIZ & data->flags)
+ write_char(p, '-', width);
+ else if (TBL_DATA_DHORIZ & data->flags)
+ write_char(p, '=', width);
+ else if (TBL_CELL_HORIZ == data->cell->pos)
+ write_char(p, '-', width);
+ else if (TBL_CELL_DHORIZ == data->cell->pos)
+ write_char(p, '=', width);
+}
+
+
+static void
+write_data_number(struct termp *p, const struct tbl_data *data, int width)
+{
+ char *dp, pnt;
+ int d, padl, sz;
+
+ /*
+ * See calc_data_number(). Left-pad by taking the offset of our
+ * and the maximum decimal; right-pad by the remaining amount.
+ */
+
+ sz = (int)term_strlen(p, data->string);
+ pnt = data->span->tbl->decimal;
+
+ if (NULL == (dp = strchr(data->string, pnt))) {
+ d = sz + 1;
+ } else {
+ d = (int)(dp - data->string) + 1;
+ }
+
+ assert(d <= data->cell->head->decimal);
+ assert(sz - d <= data->cell->head->width -
+ data->cell->head->decimal);
+
+ padl = data->cell->head->decimal - d + 1;
+ assert(width - sz - padl);
+
+ write_char(p, ' ', padl);
+ term_word(p, data->string);
+ write_char(p, ' ', width - sz - padl);
+}
+
+
+static void
+write_data_literal(struct termp *p, const struct tbl_data *data, int width)
+{
+ int padl, padr;
+
+ padl = padr = 0;
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_LONG):
+ padl = 1;
+ padr = width - (int)term_strlen(p, data->string) - 1;
+ break;
+ case (TBL_CELL_CENTRE):
+ padl = width - (int)term_strlen(p, data->string);
+ if (padl % 2)
+ padr++;
+ padl /= 2;
+ padr += padl;
+ break;
+ case (TBL_CELL_RIGHT):
+ padl = width - (int)term_strlen(p, data->string);
+ break;
+ default:
+ padr = width - (int)term_strlen(p, data->string);
+ break;
+ }
+
+ write_char(p, ' ', padl);
+ term_word(p, data->string);
+ write_char(p, ' ', padr);
+}
+
+
+static void
+write_data(struct termp *p, const struct tbl_data *data, int width)
+{
+
+ if (NULL == data) {
+ write_char(p, ' ', width);
+ return;
+ }
+
+ if (TBL_DATA_HORIZ & data->flags ||
+ TBL_DATA_DHORIZ & data->flags) {
+ write_data_spanner(p, data, width);
+ return;
+ }
+
+ switch (data->cell->pos) {
+ case (TBL_CELL_HORIZ):
+ /* FALLTHROUGH */
+ case (TBL_CELL_DHORIZ):
+ write_data_spanner(p, data, width);
+ break;
+ case (TBL_CELL_LONG):
+ /* FALLTHROUGH */
+ case (TBL_CELL_CENTRE):
+ /* FALLTHROUGH */
+ case (TBL_CELL_LEFT):
+ /* FALLTHROUGH */
+ case (TBL_CELL_RIGHT):
+ write_data_literal(p, data, width);
+ break;
+ case (TBL_CELL_NUMBER):
+ write_data_number(p, data, width);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+}
+
+
+static void
+write_spanner(struct termp *p, const struct tbl_head *head)
+{
+ char *w;
+
+ w = NULL;
+ switch (head->pos) {
+ case (TBL_HEAD_VERT):
+ w = "|";
+ break;
+ case (TBL_HEAD_DVERT):
+ w = "||";
+ break;
+ default:
+ break;
+ }
+
+ assert(p);
+ term_word(p, w);
+}
+
+
+static inline void
+write_char(struct termp *p, char c, int len)
+{
+ int i;
+ static char w[2];
+
+ w[0] = c;
+ for (i = 0; i < len; i++)
+ term_word(p, w);
+}
Index: tbl_tree.c
===================================================================
RCS file: tbl_tree.c
diff -N tbl_tree.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl_tree.c 14 Oct 2010 21:03:06 -0000
@@ -0,0 +1,88 @@
+/* $Id: tree.c,v 1.2 2009/09/11 13:24:04 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "out.h"
+#include "term.h"
+#include "tbl_extern.h"
+
+static const char * const htypes[TBL_HEAD_MAX] = {
+ "data",
+ "vert",
+ "dvert",
+};
+
+static const char * const ctypes[TBL_CELL_MAX] = {
+ "centre",
+ "right",
+ "left",
+ "number",
+ "span",
+ "long",
+ "down",
+ "horiz",
+ "dhoriz",
+ "vert",
+ "dvert",
+};
+
+
+/* ARGSUSED */
+int
+tbl_calc_tree(struct tbl *tbl)
+{
+
+ return(1);
+}
+
+
+int
+tbl_write_tree(const struct tbl *tbl)
+{
+ struct tbl_row *row;
+ struct tbl_cell *cell;
+ struct tbl_span *span;
+ struct tbl_data *data;
+ struct tbl_head *head;
+
+ (void)printf("header\n");
+ TAILQ_FOREACH(head, &tbl->head, entries)
+ (void)printf("\t%s (=%p)\n", htypes[head->pos], head);
+
+ (void)printf("layout\n");
+ TAILQ_FOREACH(row, &tbl->row, entries) {
+ (void)printf("\trow (=%p)\n", row);
+ TAILQ_FOREACH(cell, &row->cell, entries)
+ (void)printf("\t\t%s (=%p) >%p\n",
+ ctypes[cell->pos],
+ cell, cell->head);
+ }
+
+ (void)printf("data\n");
+ TAILQ_FOREACH(span, &tbl->span, entries) {
+ (void)printf("\tspan >%p\n", span->row);
+ TAILQ_FOREACH(data, &span->data, entries)
+ (void)printf("\t\tdata >%p\n", data->cell);
+ }
+
+ return(1);
+}
[-- Attachment #2: tmp.patch --]
[-- Type: text/plain, Size: 12134 bytes --]
diff -Naur mandoc-tbl-minglue/man_term.c mandoc-tbl-term/man_term.c
--- mandoc-tbl-minglue/man_term.c Thu Oct 14 22:46:41 2010
+++ mandoc-tbl-term/man_term.c Thu Oct 14 22:49:10 2010
@@ -841,7 +841,7 @@
if ( ! tbl_close(n->data.TS, "<man>", n->line))
return(0);
- tbl_write(n->data.TS);
+ tbl_write(p, n->data.TS);
return(0);
}
diff -Naur mandoc-tbl-minglue/tbl.c mandoc-tbl-term/tbl.c
--- mandoc-tbl-minglue/tbl.c Wed Oct 13 00:29:08 2010
+++ mandoc-tbl-term/tbl.c Thu Oct 14 22:50:44 2010
@@ -23,6 +23,8 @@
#include <stdlib.h>
#include <string.h>
+#include "out.h"
+#include "term.h"
#include "tbl.h"
#include "tbl_extern.h"
@@ -104,11 +106,11 @@
int
-tbl_write(const struct tbl *tbl)
+tbl_write(struct termp *p, const struct tbl *tbl)
{
#if 1
- return(tbl_write_term(tbl));
+ return(tbl_write_term(p, tbl));
#else
return(tbl_write_tree(tbl));
#endif
diff -Naur mandoc-tbl-minglue/tbl.h mandoc-tbl-term/tbl.h
--- mandoc-tbl-minglue/tbl.h Mon Sep 14 12:31:24 2009
+++ mandoc-tbl-term/tbl.h Thu Oct 14 22:50:54 2010
@@ -27,7 +27,7 @@
int tbl_read(struct tbl *, const char *, int, const char *, int);
int tbl_close(struct tbl *, const char *, int);
-int tbl_write(const struct tbl *);
+int tbl_write(struct termp *, const struct tbl *);
__END_DECLS
diff -Naur mandoc-tbl-minglue/tbl_data.c mandoc-tbl-term/tbl_data.c
--- mandoc-tbl-minglue/tbl_data.c Wed Oct 13 00:29:23 2010
+++ mandoc-tbl-term/tbl_data.c Thu Oct 14 23:01:09 2010
@@ -22,6 +22,8 @@
#include <stdlib.h>
#include <string.h>
+#include "out.h"
+#include "term.h"
#include "tbl_extern.h"
/* FIXME: warn about losing data contents if cell is HORIZ. */
diff -Naur mandoc-tbl-minglue/tbl_extern.h mandoc-tbl-term/tbl_extern.h
--- mandoc-tbl-minglue/tbl_extern.h Wed Oct 13 00:29:50 2010
+++ mandoc-tbl-term/tbl_extern.h Thu Oct 14 23:00:42 2010
@@ -173,7 +173,7 @@
struct tbl_span *tbl_span_alloc(struct tbl *);
struct tbl_data *tbl_data_alloc(struct tbl_span *);
-int tbl_write_term(const struct tbl *);
+int tbl_write_term(struct termp *, const struct tbl *);
int tbl_calc_term(struct tbl *);
int tbl_write_tree(const struct tbl *);
int tbl_calc_tree(struct tbl *);
diff -Naur mandoc-tbl-minglue/tbl_layout.c mandoc-tbl-term/tbl_layout.c
--- mandoc-tbl-minglue/tbl_layout.c Wed Oct 13 00:30:00 2010
+++ mandoc-tbl-term/tbl_layout.c Thu Oct 14 23:01:22 2010
@@ -22,6 +22,8 @@
#include <stdlib.h>
#include <string.h>
+#include "out.h"
+#include "term.h"
#include "tbl_extern.h"
struct tbl_phrase {
diff -Naur mandoc-tbl-minglue/tbl_option.c mandoc-tbl-term/tbl_option.c
--- mandoc-tbl-minglue/tbl_option.c Wed Oct 13 00:30:09 2010
+++ mandoc-tbl-term/tbl_option.c Thu Oct 14 23:01:33 2010
@@ -19,6 +19,8 @@
#include <stdlib.h>
#include <string.h>
+#include "out.h"
+#include "term.h"
#include "tbl_extern.h"
struct tbl_phrase {
diff -Naur mandoc-tbl-minglue/tbl_term.c mandoc-tbl-term/tbl_term.c
--- mandoc-tbl-minglue/tbl_term.c Wed Oct 13 00:30:18 2010
+++ mandoc-tbl-term/tbl_term.c Thu Oct 14 22:55:13 2010
@@ -21,6 +21,8 @@
#include <stdlib.h>
#include <string.h>
+#include "out.h"
+#include "term.h"
#include "tbl_extern.h"
/* FIXME: `n' modifier doesn't always do the right thing. */
@@ -30,19 +32,23 @@
static void calc_data_literal(struct tbl_data *);
static void calc_data_number(struct tbl_data *);
static void calc_data_spanner(struct tbl_data *);
-static inline void write_char(char, int);
-static void write_data(const struct tbl_data *, int);
-static void write_data_literal(const struct tbl_data *, int);
-static void write_data_number(const struct tbl_data *, int);
-static void write_data_spanner(const struct tbl_data *, int);
-static void write_hframe(const struct tbl *);
-static void write_hrule(const struct tbl_span *);
-static void write_spanner(const struct tbl_head *);
-static void write_vframe(const struct tbl *);
+static inline void write_char(struct termp *, char, int);
+static void write_data(struct termp *,
+ const struct tbl_data *, int);
+static void write_data_literal(struct termp *,
+ const struct tbl_data *, int);
+static void write_data_number(struct termp *,
+ const struct tbl_data *, int);
+static void write_data_spanner(struct termp *,
+ const struct tbl_data *, int);
+static void write_hframe(struct termp *, const struct tbl *);
+static void write_hrule(struct termp *, const struct tbl_span *);
+static void write_spanner(struct termp *, const struct tbl_head *);
+static void write_vframe(struct termp *, const struct tbl *);
int
-tbl_write_term(const struct tbl *tbl)
+tbl_write_term(struct termp *p, const struct tbl *tbl)
{
const struct tbl_span *span;
const struct tbl_data *data;
@@ -53,9 +59,11 @@
* were set when tbl_calc_term was called.
*/
+ p->flags |= TERMP_NONOSPACE;
+
/* First, write out our head horizontal frame. */
- write_hframe(tbl);
+ write_hframe(p, tbl);
/*
* Iterate through each span, and inside, through the global
@@ -65,14 +73,14 @@
*/
TAILQ_FOREACH(span, &tbl->span, entries) {
- write_vframe(tbl);
+ write_vframe(p, tbl);
/* Accomodate for the horizontal rule. */
if (TBL_DATA_DHORIZ & span->flags ||
TBL_DATA_HORIZ & span->flags) {
- write_hrule(span);
- write_vframe(tbl);
- printf("\n");
+ write_hrule(p, span);
+ write_vframe(p, tbl);
+ term_flushln(p);
continue;
}
@@ -82,10 +90,10 @@
case (TBL_HEAD_VERT):
/* FALLTHROUGH */
case (TBL_HEAD_DVERT):
- write_spanner(head);
+ write_spanner(p, head);
break;
case (TBL_HEAD_DATA):
- write_data(data, head->width);
+ write_data(p, data, head->width);
if (data)
data = TAILQ_NEXT(data, entries);
break;
@@ -94,14 +102,16 @@
/* NOTREACHED */
}
}
- write_vframe(tbl);
- printf("\n");
+ write_vframe(p, tbl);
+ term_flushln(p);
}
/* Last, write out our tail horizontal frame. */
- write_hframe(tbl);
+ write_hframe(p, tbl);
+ p->flags &= ~TERMP_NONOSPACE;
+
return(1);
}
@@ -147,7 +157,7 @@
static void
-write_hrule(const struct tbl_span *span)
+write_hrule(struct termp *p, const struct tbl_span *span)
{
const struct tbl_head *head;
char c;
@@ -167,13 +177,13 @@
TAILQ_FOREACH(head, &span->tbl->head, entries) {
switch (head->pos) {
case (TBL_HEAD_DATA):
- write_char(c, head->width);
+ write_char(p, c, head->width);
break;
case (TBL_HEAD_DVERT):
- write_char('+', head->width);
+ write_char(p, '+', head->width);
/* FALLTHROUGH */
case (TBL_HEAD_VERT):
- write_char('+', head->width);
+ write_char(p, '+', head->width);
break;
default:
abort();
@@ -184,7 +194,7 @@
static void
-write_hframe(const struct tbl *tbl)
+write_hframe(struct termp *p, const struct tbl *tbl)
{
const struct tbl_head *head;
@@ -200,35 +210,37 @@
*/
if (TBL_OPT_DBOX & tbl->opts) {
- printf("+");
+ term_word(p, "+");
TAILQ_FOREACH(head, &tbl->head, entries)
- write_char('-', head->width);
- printf("+\n");
+ write_char(p, '-', head->width);
+ term_word(p, "+");
+ term_flushln(p);
}
- printf("+");
+ term_word(p, "+");
TAILQ_FOREACH(head, &tbl->head, entries) {
switch (head->pos) {
case (TBL_HEAD_DATA):
- write_char('-', head->width);
+ write_char(p, '-', head->width);
break;
default:
- write_char('+', head->width);
+ write_char(p, '+', head->width);
break;
}
}
- printf("+\n");
+ term_word(p, "+");
+ term_flushln(p);
}
static void
-write_vframe(const struct tbl *tbl)
+write_vframe(struct termp *p, const struct tbl *tbl)
{
/* Always just a single vertical line. */
if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts))
return;
- printf("|");
+ term_word(p, "|");
}
@@ -348,7 +360,7 @@
static void
-write_data_spanner(const struct tbl_data *data, int width)
+write_data_spanner(struct termp *p, const struct tbl_data *data, int width)
{
/*
@@ -356,18 +368,18 @@
* layout) or as data.
*/
if (TBL_DATA_HORIZ & data->flags)
- write_char('-', width);
+ write_char(p, '-', width);
else if (TBL_DATA_DHORIZ & data->flags)
- write_char('=', width);
+ write_char(p, '=', width);
else if (TBL_CELL_HORIZ == data->cell->pos)
- write_char('-', width);
+ write_char(p, '-', width);
else if (TBL_CELL_DHORIZ == data->cell->pos)
- write_char('=', width);
+ write_char(p, '=', width);
}
static void
-write_data_number(const struct tbl_data *data, int width)
+write_data_number(struct termp *p, const struct tbl_data *data, int width)
{
char *dp, pnt;
int d, padl, sz;
@@ -377,7 +389,7 @@
* and the maximum decimal; right-pad by the remaining amount.
*/
- sz = (int)strlen(data->string);
+ sz = (int)term_strlen(p, data->string);
pnt = data->span->tbl->decimal;
if (NULL == (dp = strchr(data->string, pnt))) {
@@ -393,14 +405,14 @@
padl = data->cell->head->decimal - d + 1;
assert(width - sz - padl);
- write_char(' ', padl);
- (void)printf("%s", data->string);
- write_char(' ', width - sz - padl);
+ write_char(p, ' ', padl);
+ term_word(p, data->string);
+ write_char(p, ' ', width - sz - padl);
}
static void
-write_data_literal(const struct tbl_data *data, int width)
+write_data_literal(struct termp *p, const struct tbl_data *data, int width)
{
int padl, padr;
@@ -409,41 +421,41 @@
switch (data->cell->pos) {
case (TBL_CELL_LONG):
padl = 1;
- padr = width - (int)strlen(data->string) - 1;
+ padr = width - (int)term_strlen(p, data->string) - 1;
break;
case (TBL_CELL_CENTRE):
- padl = width - (int)strlen(data->string);
+ padl = width - (int)term_strlen(p, data->string);
if (padl % 2)
padr++;
padl /= 2;
padr += padl;
break;
case (TBL_CELL_RIGHT):
- padl = width - (int)strlen(data->string);
+ padl = width - (int)term_strlen(p, data->string);
break;
default:
- padr = width - (int)strlen(data->string);
+ padr = width - (int)term_strlen(p, data->string);
break;
}
- write_char(' ', padl);
- (void)printf("%s", data->string);
- write_char(' ', padr);
+ write_char(p, ' ', padl);
+ term_word(p, data->string);
+ write_char(p, ' ', padr);
}
static void
-write_data(const struct tbl_data *data, int width)
+write_data(struct termp *p, const struct tbl_data *data, int width)
{
if (NULL == data) {
- write_char(' ', width);
+ write_char(p, ' ', width);
return;
}
if (TBL_DATA_HORIZ & data->flags ||
TBL_DATA_DHORIZ & data->flags) {
- write_data_spanner(data, width);
+ write_data_spanner(p, data, width);
return;
}
@@ -451,7 +463,7 @@
case (TBL_CELL_HORIZ):
/* FALLTHROUGH */
case (TBL_CELL_DHORIZ):
- write_data_spanner(data, width);
+ write_data_spanner(p, data, width);
break;
case (TBL_CELL_LONG):
/* FALLTHROUGH */
@@ -460,10 +472,10 @@
case (TBL_CELL_LEFT):
/* FALLTHROUGH */
case (TBL_CELL_RIGHT):
- write_data_literal(data, width);
+ write_data_literal(p, data, width);
break;
case (TBL_CELL_NUMBER):
- write_data_number(data, width);
+ write_data_number(p, data, width);
break;
default:
abort();
@@ -473,32 +485,34 @@
static void
-write_spanner(const struct tbl_head *head)
+write_spanner(struct termp *p, const struct tbl_head *head)
{
- char *p;
+ char *w;
- p = NULL;
+ w = NULL;
switch (head->pos) {
case (TBL_HEAD_VERT):
- p = "|";
+ w = "|";
break;
case (TBL_HEAD_DVERT):
- p = "||";
+ w = "||";
break;
default:
break;
}
assert(p);
- printf("%s", p);
+ term_word(p, w);
}
static inline void
-write_char(char c, int len)
+write_char(struct termp *p, char c, int len)
{
int i;
+ static char w[2];
+ w[0] = c;
for (i = 0; i < len; i++)
- printf("%c", c);
+ term_word(p, w);
}
diff -Naur mandoc-tbl-minglue/tbl_tree.c mandoc-tbl-term/tbl_tree.c
--- mandoc-tbl-minglue/tbl_tree.c Wed Oct 13 00:30:28 2010
+++ mandoc-tbl-term/tbl_tree.c Thu Oct 14 23:01:46 2010
@@ -21,6 +21,8 @@
#include <stdlib.h>
#include <string.h>
+#include "out.h"
+#include "term.h"
#include "tbl_extern.h"
static const char * const htypes[TBL_HEAD_MAX] = {
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: integrate tbl into mandoc
2010-10-14 21:18 ` Ingo Schwarze
@ 2010-10-14 21:55 ` Ingo Schwarze
2010-10-14 22:19 ` Ingo Schwarze
2010-10-18 16:20 ` Kristaps Dzonsons
2 siblings, 0 replies; 7+ messages in thread
From: Ingo Schwarze @ 2010-10-14 21:55 UTC (permalink / raw)
To: tech
Hi,
this one corrects alignment by using term_*len() functions.
I guess not all details are 100% correct yet,
but this will get us started with respect to alignment.
It is cumulative to the last patch i sent just before.
Yours,
Ingo
diff -Naur mandoc-tbl-term/man_term.c mandoc-tbl/man_term.c
--- mandoc-tbl-term/man_term.c Thu Oct 14 22:49:10 2010
+++ mandoc-tbl/man_term.c Thu Oct 14 23:43:50 2010
@@ -838,7 +838,7 @@
if (MAN_BLOCK != n->type)
return(0);
- if ( ! tbl_close(n->data.TS, "<man>", n->line))
+ if ( ! tbl_close(p, n->data.TS, "<man>", n->line))
return(0);
tbl_write(p, n->data.TS);
diff -Naur mandoc-tbl-term/tbl.c mandoc-tbl/tbl.c
--- mandoc-tbl-term/tbl.c Thu Oct 14 22:50:44 2010
+++ mandoc-tbl/tbl.c Wed Oct 13 22:55:39 2010
@@ -90,7 +90,7 @@
int
-tbl_close(struct tbl *tbl, const char *f, int ln)
+tbl_close(struct termp *p, struct tbl *tbl, const char *f, int ln)
{
if (TBL_PART_DATA != tbl->part)
@@ -98,7 +98,7 @@
if ( ! tbl_data_close(tbl, f, ln))
return(0);
#if 1
- return(tbl_calc_term(tbl));
+ return(tbl_calc_term(p, tbl));
#else
return(tbl_calc_tree(tbl));
#endif
diff -Naur mandoc-tbl-term/tbl.h mandoc-tbl/tbl.h
--- mandoc-tbl-term/tbl.h Thu Oct 14 22:50:54 2010
+++ mandoc-tbl/tbl.h Wed Oct 13 22:53:55 2010
@@ -26,7 +26,7 @@
void tbl_reset(struct tbl *);
int tbl_read(struct tbl *, const char *, int, const char *, int);
-int tbl_close(struct tbl *, const char *, int);
+int tbl_close(struct termp *, struct tbl *, const char *, int);
int tbl_write(struct termp *, const struct tbl *);
__END_DECLS
diff -Naur mandoc-tbl-term/tbl_extern.h mandoc-tbl/tbl_extern.h
--- mandoc-tbl-term/tbl_extern.h Thu Oct 14 23:00:42 2010
+++ mandoc-tbl/tbl_extern.h Wed Oct 13 22:56:31 2010
@@ -174,7 +174,7 @@
struct tbl_data *tbl_data_alloc(struct tbl_span *);
int tbl_write_term(struct termp *, const struct tbl *);
-int tbl_calc_term(struct tbl *);
+int tbl_calc_term(struct termp *, struct tbl *);
int tbl_write_tree(const struct tbl *);
int tbl_calc_tree(struct tbl *);
diff -Naur mandoc-tbl-term/tbl_term.c mandoc-tbl/tbl_term.c
--- mandoc-tbl-term/tbl_term.c Thu Oct 14 23:28:00 2010
+++ mandoc-tbl/tbl_term.c Thu Oct 14 23:40:15 2010
@@ -29,10 +29,10 @@
/* FIXME: `n' modifier doesn't always do the right thing. */
/* FIXME: `n' modifier doesn't use the cell-spacing buffer. */
-static void calc_data(struct tbl_data *);
-static void calc_data_literal(struct tbl_data *);
-static void calc_data_number(struct tbl_data *);
-static void calc_data_spanner(struct tbl_data *);
+static void calc_data(struct termp *, struct tbl_data *);
+static void calc_data_literal(struct termp *, struct tbl_data *);
+static void calc_data_number(struct termp *, struct tbl_data *);
+static void calc_data_spanner(struct termp *, struct tbl_data *);
static inline void write_char(struct termp *, char, int);
static void write_data(struct termp *,
const struct tbl_data *, int);
@@ -118,7 +118,7 @@
int
-tbl_calc_term(struct tbl *tbl)
+tbl_calc_term(struct termp *p, struct tbl *tbl)
{
struct tbl_span *span;
struct tbl_data *data;
@@ -136,7 +136,7 @@
if (TBL_DATA_NDHORIZ & span->flags)
continue;
TAILQ_FOREACH(data, &span->data, entries)
- calc_data(data);
+ calc_data(p, data);
}
/* Calculate width as the simple spanner value. */
@@ -144,10 +144,10 @@
TAILQ_FOREACH(head, &tbl->head, entries)
switch (head->pos) {
case (TBL_HEAD_VERT):
- head->width = 1;
+ head->width = term_len(p, 1);
break;
case (TBL_HEAD_DVERT):
- head->width = 2;
+ head->width = term_len(p, 2);
break;
default:
break;
@@ -246,16 +246,16 @@
static void
-calc_data_spanner(struct tbl_data *data)
+calc_data_spanner(struct termp *p, struct tbl_data *data)
{
/* N.B., these are horiz spanners (not vert) so always 1. */
- data->cell->head->width = 1;
+ data->cell->head->width = term_len(p, 1);
}
static void
-calc_data_number(struct tbl_data *data)
+calc_data_number(struct termp *p, struct tbl_data *data)
{
int sz, d;
char *dp, pnt;
@@ -272,15 +272,14 @@
/* TODO: use spacing modifier. */
assert(data->string);
- sz = (int)strlen(data->string);
+ sz = (int)term_strlen(p, data->string);
pnt = data->span->tbl->decimal;
- if (NULL == (dp = strchr(data->string, pnt)))
- d = sz + 1;
- else
- d = (int)(dp - data->string) + 1;
+ dp = strchr(data->string, pnt);
+ d = dp ? sz - (int)term_strlen(p, dp) : sz;
+ d += term_len(p, 1);
- sz += 2;
+ sz += term_len(p, 2);
if (data->cell->head->decimal > d) {
sz += data->cell->head->decimal - d;
@@ -297,7 +296,7 @@
static void
-calc_data_literal(struct tbl_data *data)
+calc_data_literal(struct termp *p, struct tbl_data *data)
{
int sz, bufsz;
@@ -308,7 +307,7 @@
*/
assert(data->string);
- sz = (int)strlen(data->string);
+ sz = (int)term_strlen(p, data->string);
switch (data->cell->pos) {
case (TBL_CELL_LONG):
@@ -325,21 +324,21 @@
bufsz = bufsz > data->cell->spacing ?
bufsz : data->cell->spacing;
- sz += bufsz;
+ sz += term_len(p, bufsz);
if (data->cell->head->width < sz)
data->cell->head->width = sz;
}
static void
-calc_data(struct tbl_data *data)
+calc_data(struct termp *p, struct tbl_data *data)
{
switch (data->cell->pos) {
case (TBL_CELL_HORIZ):
/* FALLTHROUGH */
case (TBL_CELL_DHORIZ):
- calc_data_spanner(data);
+ calc_data_spanner(p, data);
break;
case (TBL_CELL_LONG):
/* FALLTHROUGH */
@@ -348,10 +347,10 @@
case (TBL_CELL_LEFT):
/* FALLTHROUGH */
case (TBL_CELL_RIGHT):
- calc_data_literal(data);
+ calc_data_literal(p, data);
break;
case (TBL_CELL_NUMBER):
- calc_data_number(data);
+ calc_data_number(p, data);
break;
default:
abort();
--
To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: integrate tbl into mandoc
2010-10-14 21:18 ` Ingo Schwarze
2010-10-14 21:55 ` Ingo Schwarze
@ 2010-10-14 22:19 ` Ingo Schwarze
2010-10-14 23:02 ` Ingo Schwarze
2010-10-18 16:20 ` Kristaps Dzonsons
2 siblings, 1 reply; 7+ messages in thread
From: Ingo Schwarze @ 2010-10-14 22:19 UTC (permalink / raw)
To: tech
Hi,
>> The following still crash:
as one might expect, options are optional,
so the following patch fixes most of these.
The following now work:
/usr/src/lib/libcurses/curs_addch.3tbl
/usr/src/lib/libcurses/curs_attr.3tbl
/usr/src/lib/libcurses/curs_getch.3tbl
/usr/src/lib/libcurses/curs_mouse.3tbl
/usr/src/lib/libcurses/curses.3tbl
/usr/src/lib/libform/form.3tbl
/usr/src/usr.bin/infocmp/infocmp.1tbl
/usr/src/usr.bin/tic/captoinfo.1tbl
These still crash:
>> /usr/src/lib/libcurses/curs_inch.3tbl
>> /usr/src/lib/libmenu/menu.3tbl
>> /usr/src/gnu/usr.sbin/mkhybrid/src/mkhybrid.8tbl
>> The following have a tbl extension, but no .TS:
>> /usr/src/lib/libcurses/term.5tbl
>> The following are mdoc(7) with tbl:
>> /usr/src/share/man/man4/wi.4tbl
>> /usr/src/share/man/man4/man4.hppa/cpu.4tbl
>> /usr/src/games/phantasia/phantasia.6tbl
Yours,
Ingo
diff -Napur mandoc-tbl-calc/tbl_option.c mandoc-tbl/tbl_option.c
--- mandoc-tbl-calc/tbl_option.c Thu Oct 14 23:24:14 2010
+++ mandoc-tbl/tbl_option.c Fri Oct 15 00:11:52 2010
@@ -141,6 +141,11 @@ opt(struct tbl *tbl, const char *f, int ln, const char
{
int i, sv;
+ if (NULL == strchr(p + *pos, ';')) {
+ tbl->part = TBL_PART_LAYOUT;
+ return(1);
+ }
+
again:
sv = *pos;
--
To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: integrate tbl into mandoc
2010-10-14 22:19 ` Ingo Schwarze
@ 2010-10-14 23:02 ` Ingo Schwarze
0 siblings, 0 replies; 7+ messages in thread
From: Ingo Schwarze @ 2010-10-14 23:02 UTC (permalink / raw)
To: tech
Hi,
> as one might expect, options are optional,
> so the following patch fixes most of these.
Gah, forget about this one, it is completely wrong.
Kristaps correctly coded the "optional" feature,
i just called the function tbl_read() with bad arguments.
See below for a better patch, which also fixes the
line break at the start of a table.
The following now work:
/usr/src/lib/libcurses/curs_addch.3tbl
/usr/src/lib/libcurses/curs_attr.3tbl
/usr/src/lib/libcurses/curs_getch.3tbl
/usr/src/lib/libcurses/curs_inch.3tbl
/usr/src/lib/libcurses/curs_mouse.3tbl
/usr/src/lib/libcurses/curses.3tbl
/usr/src/lib/libform/form.3tbl
/usr/src/lib/libmenu/menu.3tbl
/usr/src/usr.bin/infocmp/infocmp.1tbl
/usr/src/usr.bin/tic/captoinfo.1tbl
Only one still crashes:
/usr/src/gnu/usr.sbin/mkhybrid/src/mkhybrid.8tbl
> The following have a tbl extension, but no .TS:
> /usr/src/lib/libcurses/term.5tbl
> The following are mdoc(7) with tbl:
> /usr/src/share/man/man4/wi.4tbl
> /usr/src/share/man/man4/man4.hppa/cpu.4tbl
> /usr/src/games/phantasia/phantasia.6tbl
So, i will put this into OpenBSD tomorrow and do the mdoc part,
such that we can kick groff out of the tree this weekend.
Yours,
Ingo
diff -Napur mandoc-tbl-calc/man.c mandoc-tbl-opt/man.c
--- mandoc-tbl-calc/man.c Thu Oct 14 23:41:50 2010
+++ mandoc-tbl-opt/man.c Fri Oct 15 00:47:16 2010
@@ -135,7 +135,8 @@ man_parseln(struct man *m, int ln, char *buf, int offs
if (n && MAN_TS == n->tok && MAN_BODY == n->type &&
strncmp(buf+offs, ".TE", 3)) {
n = n->parent;
- return(tbl_read(n->data.TS, "<man>", ln, buf, offs) ? 1 : 0);
+ return(tbl_read(n->data.TS, "<man>", ln, buf+offs,
+ strlen(buf+offs)) ? 1 : 0);
}
return(('.' == buf[offs] || '\'' == buf[offs]) ?
diff -Napur mandoc-tbl-calc/man_term.c mandoc-tbl-opt/man_term.c
--- mandoc-tbl-calc/man_term.c Thu Oct 14 23:43:50 2010
+++ mandoc-tbl-opt/man_term.c Fri Oct 15 00:51:10 2010
@@ -841,6 +841,7 @@ pre_TS(DECL_ARGS)
if ( ! tbl_close(p, n->data.TS, "<man>", n->line))
return(0);
+ term_newln(p);
tbl_write(p, n->data.TS);
return(0);
--
To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: integrate tbl into mandoc
2010-10-14 21:18 ` Ingo Schwarze
2010-10-14 21:55 ` Ingo Schwarze
2010-10-14 22:19 ` Ingo Schwarze
@ 2010-10-18 16:20 ` Kristaps Dzonsons
2010-10-18 17:38 ` Joerg Sonnenberger
2 siblings, 1 reply; 7+ messages in thread
From: Kristaps Dzonsons @ 2010-10-18 16:20 UTC (permalink / raw)
To: tech
Hi Ingo---I'm on my way back from a little bit in the mountains. Just
getting your patches and messages now.
I'll respond over the next few days, but I warn you that I absolutely
don't intend to merge tbl into mandoc. I don't want the code volume
increased so much for a corner case. Tables are already supported by
`Bl -column'; pulling this extra code into the parser for all manuals in
the general case is wasteful.
I'll produce a patch by way of explanation, but I intend to instead have
a separate tbl utility that links with libmandoc for escape-width
calculation (which will, happily, need deduplication) that will produce
fixed text that's pumped into libman or libmdoc.
I'll need a few days, but it'll be quite straightforward.
Take care,
Kristaps
--
To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: integrate tbl into mandoc
2010-10-18 16:20 ` Kristaps Dzonsons
@ 2010-10-18 17:38 ` Joerg Sonnenberger
0 siblings, 0 replies; 7+ messages in thread
From: Joerg Sonnenberger @ 2010-10-18 17:38 UTC (permalink / raw)
To: tech
On Mon, Oct 18, 2010 at 06:20:07PM +0200, Kristaps Dzonsons wrote:
> I'll respond over the next few days, but I warn you that I
> absolutely don't intend to merge tbl into mandoc. I don't want the
> code volume increased so much for a corner case. Tables are already
> supported by `Bl -column'; pulling this extra code into the parser
> for all manuals in the general case is wasteful.
I somewhat disagree on this. The code of .Bl -column is complicated and
lacking in some important areas. Same can be said about tbl. Properly
integrating both into a shared table engine can even result in major
improvements for .Bl -column. Consider the ability to have proper
multi-line fields.
Joerg
--
To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2010-10-18 17:37 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-13 0:46 integrate tbl into mandoc Ingo Schwarze
2010-10-14 21:18 ` Ingo Schwarze
2010-10-14 21:55 ` Ingo Schwarze
2010-10-14 22:19 ` Ingo Schwarze
2010-10-14 23:02 ` Ingo Schwarze
2010-10-18 16:20 ` Kristaps Dzonsons
2010-10-18 17:38 ` Joerg Sonnenberger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).