Sending this here as suggested by henn...@.
Comments welcome!
----- Forwarded message from Ingo Schwarze <[email protected]> -----
Hi,
here is my plan to get rid of groff in base:
(1) tonight: commit tbl(1) support for man(7) into mandoc
(2) tomorrow: commit tbl(1) support for mdoc(7) into mandoc
(3) tomorrow: send patches to switch "tbl | nroff"
over to mandoc in the base build system
(4) tomorrow: send patches to unlink the last me(7) and ms(7)
documents form the base build
(5) beginning of next week: espie@ could enable the groff port
(6) beginning of next week: disable groff in the base build
I suggest to get this done as soon as possible,
well before the ports hackathon.
As a reminder, at least at the beginning, the plan is to give
ports containing man(7) or mdoc(7) manual pages a build dependency -
but not a run dependency - on the groff port, and to allow the
respective port maintainer to switch the port over to using mandoc(1),
*IF* and when he regards that switch as worthwhile.
Thus, the intention is to avoid any kind of a make-work project
for porters.
The following patch is what i hope to get into the tree this night,
to achieve (1). Final testing may yet result in minor tweaks.
After that, (2) will be easy, analogous, and a much smaller patch.
Step (1) lets the following build with mandoc:
/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/libcurses/term.5tbl
/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
Step (2) will hopefully fix:
/usr/src/share/man/man4/wi.4tbl
/usr/src/share/man/man4/man4.hppa/cpu.4tbl
/usr/src/games/phantasia/phantasia.6tbl
With the patch below, the command to build these is just:
mandoc /usr/src/lib/libcurses/curs_addch.3tbl
Of course, there are still a few minor issues.
For example, the .T{ macro is not yet supported,
but i think that should not keep us from moving forward.
Any reason to not do the steps (1) to (4) right now?
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 15 Oct 2010 10:39:15 -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 15 Oct 2010 10:39:15 -0000
@@ -26,6 +26,10 @@
#include "libman.h"
#include "libmandoc.h"
+#include "out.h"
+#include "term.h"
+#include "tbl.h"
+
const char *const __man_macronames[MAN_MAX] = {
"br", "TH", "SH", "SS",
"TP", "LP", "PP", "P",
@@ -36,7 +40,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 +125,20 @@ 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,
+ strlen(buf+offs)) ? 1 : 0);
+ }
+
return(('.' == buf[offs] || '\'' == buf[offs]) ?
man_pmacro(m, ln, buf, offs) :
man_ptext(m, ln, buf, offs));
@@ -322,6 +336,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 15 Oct 2010 10:39:15 -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 15 Oct 2010 10:39:15 -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 15 Oct 2010 10:39:16 -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 15 Oct 2010 10:39:16 -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 15 Oct 2010 10:39:16 -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,24 @@ 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(p, n->data.TS, "<man>", n->line))
+ return(0);
+
+ term_newln(p);
+ 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 15 Oct 2010 10:39:16 -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 }, /* TE */
};
Index: tbl.c
===================================================================
RCS file: tbl.c
diff -N tbl.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tbl.c 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,546 @@
+/* $Id: tbl.c,v 1.14 2009/09/12 16:05:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ *
+ * 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 termp *p, 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(p, 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 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,34 @@
+/* $Id: tbl.h,v 1.3 2009/09/11 15:01:24 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ *
+ * 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 termp *, 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 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,132 @@
+/* $Id: data.c,v 1.11 2009/09/12 16:05:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ *
+ * 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 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,183 @@
+/* $Id: extern.h,v 1.10 2009/09/13 12:37:28 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ *
+ * 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 termp *, 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 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,282 @@
+/* $Id: layout.c,v 1.7 2009/09/11 13:24:04 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ *
+ * 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 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,197 @@
+/* $Id: option.c,v 1.5 2009/09/09 12:51:34 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ *
+ * 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 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,523 @@
+/* $Id: term.c,v 1.13 2009/09/14 09:06:40 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ * Copyright (c) 2010 Ingo Schwarze <[email protected]>
+ *
+ * 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 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);
+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 termp *p, 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(p, data);
+ }
+
+ /* Calculate width as the simple spanner value. */
+
+ TAILQ_FOREACH(head, &tbl->head, entries)
+ switch (head->pos) {
+ case (TBL_HEAD_VERT):
+ head->width = term_len(p, 1);
+ break;
+ case (TBL_HEAD_DVERT):
+ head->width = term_len(p, 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 termp *p, struct tbl_data *data)
+{
+
+ /* N.B., these are horiz spanners (not vert) so always 1. */
+ data->cell->head->width = term_len(p, 1);
+}
+
+
+static void
+calc_data_number(struct termp *p, 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)term_strlen(p, data->string);
+ pnt = data->span->tbl->decimal;
+
+ dp = strchr(data->string, pnt);
+ d = dp ? sz - (int)term_strlen(p, dp) : sz;
+ d += term_len(p, 1);
+
+ sz += term_len(p, 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 termp *p, 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)term_strlen(p, 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 += term_len(p, bufsz);
+ if (data->cell->head->width < sz)
+ data->cell->head->width = sz;
+}
+
+
+static void
+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(p, data);
+ break;
+ case (TBL_CELL_LONG):
+ /* FALLTHROUGH */
+ case (TBL_CELL_CENTRE):
+ /* FALLTHROUGH */
+ case (TBL_CELL_LEFT):
+ /* FALLTHROUGH */
+ case (TBL_CELL_RIGHT):
+ calc_data_literal(p, data);
+ break;
+ case (TBL_CELL_NUMBER):
+ calc_data_number(p, data);
+ break;
+ case (TBL_CELL_SPAN):
+ data->cell->head->width = 0;
+ 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;
+ case (TBL_CELL_SPAN):
+ 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 15 Oct 2010 10:39:18 -0000
@@ -0,0 +1,88 @@
+/* $Id: tree.c,v 1.2 2009/09/11 13:24:04 kristaps Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons <[email protected]>
+ *
+ * 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);
+}
----- End forwarded message -----