diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | man_term.c | 1 | ||||
-rw-r--r-- | mdoc_term.c | 1 | ||||
-rw-r--r-- | tbl_term.c | 358 | ||||
-rw-r--r-- | term.h | 1 | ||||
-rw-r--r-- | term_ascii.c | 1 |
6 files changed, 366 insertions, 3 deletions
@@ -65,15 +65,16 @@ MANSRCS = man_macro.c man.c man_hash.c man_validate.c \ MAINLNS = main.ln mdoc_term.ln chars.ln term.ln tree.ln \ compat.ln man_term.ln html.ln mdoc_html.ln \ - man_html.ln out.ln term_ps.ln term_ascii.ln + man_html.ln out.ln term_ps.ln term_ascii.ln \ + tbl_term.ln MAINOBJS = main.o mdoc_term.o chars.o term.o tree.o compat.o \ man_term.o html.o mdoc_html.o man_html.o out.o \ - term_ps.o term_ascii.o + term_ps.o term_ascii.o tbl_term.o MAINSRCS = main.c mdoc_term.c chars.c term.c tree.c compat.c \ man_term.c html.c mdoc_html.c man_html.c out.c \ - term_ps.c term_ascii.c + term_ps.c term_ascii.c tbl_term.c LLNS = llib-llibmdoc.ln llib-llibman.ln llib-lmandoc.ln \ llib-llibmandoc.ln llib-llibroff.ln @@ -866,6 +866,7 @@ print_man_node(DECL_ARGS) } break; case (MAN_TBL): + term_tbl(p, n->span); break; default: if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) diff --git a/mdoc_term.c b/mdoc_term.c index b7417569..48551056 100644 --- a/mdoc_term.c +++ b/mdoc_term.c @@ -318,6 +318,7 @@ print_mdoc_node(DECL_ARGS) term_word(p, n->string); break; case (MDOC_TBL): + term_tbl(p, n->span); break; default: if (termacts[n->tok].pre && ENDBODY_NOT == n->end) diff --git a/tbl_term.c b/tbl_term.c new file mode 100644 index 00000000..05ba3d70 --- /dev/null +++ b/tbl_term.c @@ -0,0 +1,358 @@ +/* $Id$ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc.h" +#include "out.h" +#include "term.h" + +/* FIXME: `n' modifier doesn't always do the right thing. */ +/* FIXME: `n' modifier doesn't use the cell-spacing buffer. */ + +static inline void tbl_char(struct termp *, char, int); +static void tbl_hframe(struct termp *, + const struct tbl_span *); +static void tbl_data_number(struct termp *, + const struct tbl *, + const struct tbl_dat *, int); +static void tbl_data_literal(struct termp *, + const struct tbl_dat *, int); +static void tbl_data_spanner(struct termp *, + const struct tbl_dat *, int); +static void tbl_data(struct termp *, const struct tbl *, + const struct tbl_dat *, int); +static void tbl_spanner(struct termp *, + const struct tbl_head *); +static void tbl_hrule(struct termp *, + const struct tbl_span *); +static void tbl_vframe(struct termp *, const struct tbl *); + +void +term_tbl(struct termp *tp, const struct tbl_span *sp) +{ + const struct tbl_head *hp; + const struct tbl_dat *dp; + + if (TBL_SPAN_FIRST & sp->flags) + term_flushln(tp); + + if (TBL_SPAN_FIRST & sp->flags) + tbl_hframe(tp, sp); + + tp->flags |= TERMP_NONOSPACE; + tp->flags |= TERMP_NOSPACE; + + tbl_vframe(tp, sp->tbl); + + switch (sp->pos) { + case (TBL_SPAN_HORIZ): + /* FALLTHROUGH */ + case (TBL_SPAN_DHORIZ): + tbl_hrule(tp, sp); + tbl_vframe(tp, sp->tbl); + term_newln(tp); + tp->flags &= ~TERMP_NONOSPACE; + return; + default: + break; + } + + dp = sp->first; + for (hp = sp->head; hp; hp = hp->next) { + switch (hp->pos) { + case (TBL_HEAD_VERT): + /* FALLTHROUGH */ + case (TBL_HEAD_DVERT): + tbl_spanner(tp, hp); + break; + case (TBL_HEAD_DATA): + tbl_data(tp, sp->tbl, dp, hp->width); + if (dp) + dp = dp->next; + break; + default: + abort(); + /* NOTREACHED */ + } + } + + tbl_vframe(tp, sp->tbl); + term_flushln(tp); + + if (TBL_SPAN_LAST & sp->flags) + tbl_hframe(tp, sp); + + tp->flags &= ~TERMP_NONOSPACE; + +} + +static void +tbl_hrule(struct termp *tp, const struct tbl_span *sp) +{ + const struct tbl_head *hp; + 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 == sp->pos) + c = '='; + + /* FIXME: don't use `+' between data and a spanner! */ + + for (hp = sp->head; hp; hp = hp->next) { + switch (hp->pos) { + case (TBL_HEAD_DATA): + tbl_char(tp, c, hp->width); + break; + case (TBL_HEAD_DVERT): + tbl_char(tp, '+', hp->width); + /* FALLTHROUGH */ + case (TBL_HEAD_VERT): + tbl_char(tp, '+', hp->width); + break; + default: + abort(); + /* NOTREACHED */ + } + } +} + +static void +tbl_hframe(struct termp *tp, const struct tbl_span *sp) +{ + const struct tbl_head *hp; + + if ( ! (TBL_OPT_BOX & sp->tbl->opts || + TBL_OPT_DBOX & sp->tbl->opts)) + return; + + tp->flags |= TERMP_NONOSPACE; + tp->flags |= TERMP_NOSPACE; + + /* + * 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 & sp->tbl->opts) { + term_word(tp, "+"); + for (hp = sp->head; hp; hp = hp->next) + tbl_char(tp, '-', hp->width); + term_word(tp, "+"); + term_flushln(tp); + } + + term_word(tp, "+"); + for (hp = sp->head; hp; hp = hp->next) { + switch (hp->pos) { + case (TBL_HEAD_DATA): + tbl_char(tp, '-', hp->width); + break; + default: + tbl_char(tp, '+', hp->width); + break; + } + } + term_word(tp, "+"); + term_flushln(tp); +} + +static void +tbl_data(struct termp *tp, const struct tbl *tbl, + const struct tbl_dat *dp, int width) +{ + enum tbl_cellt pos; + + if (NULL == dp) { + tbl_char(tp, ASCII_NBRSP, width); + return; + } + + switch (dp->pos) { + case (TBL_DATA_HORIZ): + /* FALLTHROUGH */ + case (TBL_DATA_DHORIZ): + tbl_data_spanner(tp, dp, width); + return; + default: + break; + } + + pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT; + + switch (pos) { + case (TBL_CELL_HORIZ): + /* FALLTHROUGH */ + case (TBL_CELL_DHORIZ): + tbl_data_spanner(tp, dp, width); + break; + case (TBL_CELL_LONG): + /* FALLTHROUGH */ + case (TBL_CELL_CENTRE): + /* FALLTHROUGH */ + case (TBL_CELL_LEFT): + /* FALLTHROUGH */ + case (TBL_CELL_RIGHT): + tbl_data_literal(tp, dp, width); + break; + case (TBL_CELL_NUMBER): + tbl_data_number(tp, tbl, dp, width); + break; + default: + abort(); + /* NOTREACHED */ + } +} +static void +tbl_spanner(struct termp *tp, const struct tbl_head *hp) +{ + + switch (hp->pos) { + case (TBL_HEAD_VERT): + term_word(tp, "|"); + break; + case (TBL_HEAD_DVERT): + term_word(tp, "||"); + break; + default: + break; + } +} + +static void +tbl_vframe(struct termp *tp, const struct tbl *tbl) +{ + /* Always just a single vertical line. */ + + if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts) + term_word(tp, "|"); +} + + +static inline void +tbl_char(struct termp *tp, char c, int len) +{ + int i; + char cp[2]; + + cp[0] = c; + cp[1] = '\0'; + + for (i = 0; i < len; i++) + term_word(tp, cp); +} + +static void +tbl_data_spanner(struct termp *tp, const struct tbl_dat *dp, int width) +{ + + switch (dp->pos) { + case (TBL_DATA_HORIZ): + case (TBL_DATA_NHORIZ): + tbl_char(tp, '-', width); + break; + case (TBL_DATA_DHORIZ): + case (TBL_DATA_NDHORIZ): + tbl_char(tp, '=', width); + break; + default: + break; + } +} + +static void +tbl_data_literal(struct termp *tp, const struct tbl_dat *dp, int width) +{ + int padl, padr; + enum tbl_cellt pos; + + padl = padr = 0; + + pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT; + + switch (pos) { + case (TBL_CELL_LONG): + padl = 1; + padr = width - (int)strlen(dp->string) - 1; + break; + case (TBL_CELL_CENTRE): + padl = width - (int)strlen(dp->string); + if (padl % 2) + padr++; + padl /= 2; + padr += padl; + break; + case (TBL_CELL_RIGHT): + padl = width - (int)strlen(dp->string); + break; + default: + padr = width - (int)strlen(dp->string); + break; + } + + tbl_char(tp, ASCII_NBRSP, padl); + term_word(tp, dp->string); + tbl_char(tp, ASCII_NBRSP, padr); +} + +static void +tbl_data_number(struct termp *tp, const struct tbl *tbl, + const struct tbl_dat *dp, int width) +{ + char *decp, pnt; + int d, padl, sz; + + /* + * See calc_data_number(). Left-pad by taking the offset of our + * and the maximum decimal; right-pad by the remaining amount. + */ + + sz = (int)strlen(dp->string); + pnt = tbl->decimal; + + if (NULL == (decp = strchr(dp->string, pnt))) { + d = sz + 1; + } else { + d = (int)(decp - dp->string) + 1; + } + + assert(d <= dp->layout->head->decimal); + assert(sz - d <= dp->layout->head->width - + dp->layout->head->decimal); + + padl = dp->layout->head->decimal - d + 1; + assert(width - sz - padl); + + tbl_char(tp, ASCII_NBRSP, padl); + term_word(tp, dp->string); + tbl_char(tp, ASCII_NBRSP, width - sz - padl); +} @@ -120,6 +120,7 @@ struct termp { }; struct termp *term_alloc(enum termenc); +void term_tbl(struct termp *, const struct tbl_span *); void term_free(struct termp *); void term_newln(struct termp *); void term_vspace(struct termp *); diff --git a/term_ascii.c b/term_ascii.c index 8be733a6..3517b341 100644 --- a/term_ascii.c +++ b/term_ascii.c @@ -26,6 +26,7 @@ #include <stdlib.h> #include <unistd.h> +#include "mandoc.h" #include "out.h" #include "term.h" #include "main.h" |