From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp1.rz.uni-karlsruhe.de (Debian-exim@smtp1.rz.uni-karlsruhe.de [129.13.185.217]) by krisdoz.my.domain (8.14.3/8.14.3) with ESMTP id o9ELIYss000417 for ; Thu, 14 Oct 2010 17:18:36 -0400 (EDT) Received: from hekate.usta.de (asta-nat.asta.uni-karlsruhe.de [172.22.63.82]) by smtp1.rz.uni-karlsruhe.de with esmtp (Exim 4.63 #1) id 1P6VC4-0007kD-JR; Thu, 14 Oct 2010 23:18:32 +0200 Received: from donnerwolke.usta.de ([172.24.96.3]) by hekate.usta.de with esmtp (Exim 4.71) (envelope-from ) id 1P6VC4-00015m-HA for tech@mdocml.bsd.lv; Thu, 14 Oct 2010 23:18:32 +0200 Received: from iris.usta.de ([172.24.96.5] helo=usta.de) by donnerwolke.usta.de with esmtp (Exim 4.69) (envelope-from ) id 1P6VC4-0008AJ-Fg for tech@mdocml.bsd.lv; Thu, 14 Oct 2010 23:18:32 +0200 Received: from schwarze by usta.de with local (Exim 4.71) (envelope-from ) id 1P6VC4-0006sF-3w for tech@mdocml.bsd.lv; Thu, 14 Oct 2010 23:18:32 +0200 Date: Thu, 14 Oct 2010 23:18:31 +0200 From: Ingo Schwarze To: tech@mdocml.bsd.lv Subject: Re: integrate tbl into mandoc Message-ID: <20101014211831.GB30282@iris.usta.de> References: <20101013004622.GC18513@iris.usta.de> X-Mailinglist: mdocml-tech Reply-To: tech@mdocml.bsd.lv MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="SkvwRMAIpAhPCcCJ" Content-Disposition: inline In-Reply-To: <20101013004622.GC18513@iris.usta.de> User-Agent: Mutt/1.5.20 (2009-06-14) --SkvwRMAIpAhPCcCJ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 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, "", 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, "", 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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 + * + * 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 +#include + +#include +#include +#include +#include + +#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 + * + * 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 + * + * 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 +#include + +#include +#include +#include +#include + +#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 + * + * 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 + +#include +#include + +#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 + * + * 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 + +#include +#include +#include +#include + +#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 + * + * 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 + +#include +#include +#include +#include + +#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); +} --SkvwRMAIpAhPCcCJ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="tmp.patch" 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, "", 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 #include +#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 #include +#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 #include +#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 #include +#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 #include +#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 #include +#include "out.h" +#include "term.h" #include "tbl_extern.h" static const char * const htypes[TBL_HEAD_MAX] = { --SkvwRMAIpAhPCcCJ-- -- To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv