=================================================================== RCS file: /cvs/mandoc/tbl_term.c,v retrieving revision 1.1 retrieving revision 1.17 diff -u -p -r1.1 -r1.17 --- mandoc/tbl_term.c 2011/01/02 12:21:07 1.1 +++ mandoc/tbl_term.c 2011/01/10 14:56:06 1.17 @@ -1,4 +1,4 @@ -/* $Id: tbl_term.c,v 1.1 2011/01/02 12:21:07 kristaps Exp $ */ +/* $Id: tbl_term.c,v 1.17 2011/01/10 14:56:06 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -27,83 +27,150 @@ #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 size_t term_tbl_len(size_t, void *); +static size_t term_tbl_strlen(const char *, void *); +static void tbl_char(struct termp *, char, size_t); +static void tbl_data(struct termp *, const struct tbl *, + const struct tbl_dat *, + const struct roffcol *); +static void tbl_hframe(struct termp *, const struct tbl_span *); +static void tbl_literal(struct termp *, const struct tbl_dat *, + const struct roffcol *); +static void tbl_number(struct termp *, const struct tbl *, + const struct tbl_dat *, + const struct roffcol *); +static void tbl_hrule(struct termp *, const struct tbl_span *); +static void tbl_vframe(struct termp *, const struct tbl *); +static void tbl_vrule(struct termp *, const struct tbl_head *); -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 *); +static size_t +term_tbl_strlen(const char *p, void *arg) +{ + + return(term_strlen((const struct termp *)arg, p)); +} + +static size_t +term_tbl_len(size_t sz, void *arg) +{ + + return(term_len((const struct termp *)arg, sz)); +} + void term_tbl(struct termp *tp, const struct tbl_span *sp) { - const struct tbl_head *hp; - const struct tbl_dat *dp; + const struct tbl_head *hp; + const struct tbl_dat *dp; + struct roffcol *col; + int spans; + size_t rmargin, maxrmargin; - if (TBL_SPAN_FIRST & sp->flags) + rmargin = tp->rmargin; + maxrmargin = tp->maxrmargin; + + tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN; + + /* Inhibit printing of spaces: we do padding ourselves. */ + + tp->flags |= TERMP_NONOSPACE; + tp->flags |= TERMP_NOSPACE; + + /* + * The first time we're invoked for a given table block, + * calculate the table widths and decimal positions. + */ + + if (TBL_SPAN_FIRST & sp->flags) { term_flushln(tp); + tp->tbl.len = term_tbl_len; + tp->tbl.slen = term_tbl_strlen; + tp->tbl.arg = tp; + + tblcalc(&tp->tbl, sp); + } + + /* Horizontal frame at the start of boxed tables. */ + if (TBL_SPAN_FIRST & sp->flags) tbl_hframe(tp, sp); - tp->flags |= TERMP_NONOSPACE; - tp->flags |= TERMP_NOSPACE; + /* Vertical frame at the start of each row. */ tbl_vframe(tp, sp->tbl); + /* + * Now print the actual data itself depending on the span type. + * Spanner spans get a horizontal rule; data spanners have their + * data printed by matching data to header. + */ + 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; - } + case (TBL_SPAN_DATA): + /* Iterate over template headers. */ + dp = sp->first; + spans = 0; + for (hp = sp->head; hp; hp = hp->next) { + /* + * If the current data header is invoked during + * a spanner ("spans" > 0), don't emit anything + * at all. + */ + switch (hp->pos) { + case (TBL_HEAD_VERT): + /* FALLTHROUGH */ + case (TBL_HEAD_DVERT): + if (spans <= 0) + tbl_vrule(tp, hp); + continue; + case (TBL_HEAD_DATA): + 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) + if (--spans >= 0) + continue; + + col = &tp->tbl.cols[hp->ident]; + tbl_data(tp, sp->tbl, dp, col); + + /* + * Go to the next data cell and assign the + * number of subsequent spans, if applicable. + */ + + if (dp) { + spans = dp->spans; dp = dp->next; - break; - default: - abort(); - /* NOTREACHED */ + } } + break; } tbl_vframe(tp, sp->tbl); term_flushln(tp); - if (TBL_SPAN_LAST & sp->flags) + /* + * If we're the last row, clean up after ourselves: clear the + * existing table configuration and set it to NULL. + */ + + if (TBL_SPAN_LAST & sp->flags) { tbl_hframe(tp, sp); + assert(tp->tbl.cols); + free(tp->tbl.cols); + tp->tbl.cols = NULL; + } tp->flags &= ~TERMP_NONOSPACE; + tp->rmargin = rmargin; + tp->maxrmargin = maxrmargin; } @@ -112,6 +179,7 @@ tbl_hrule(struct termp *tp, const struct tbl_span *sp) { const struct tbl_head *hp; char c; + size_t width; /* * An hrule extends across the entire table and is demarked by a @@ -126,15 +194,16 @@ tbl_hrule(struct termp *tp, const struct tbl_span *sp) /* FIXME: don't use `+' between data and a spanner! */ for (hp = sp->head; hp; hp = hp->next) { + width = tp->tbl.cols[hp->ident].width; switch (hp->pos) { case (TBL_HEAD_DATA): - tbl_char(tp, c, hp->width); + tbl_char(tp, c, width); break; case (TBL_HEAD_DVERT): - tbl_char(tp, '+', hp->width); + tbl_char(tp, '+', width); /* FALLTHROUGH */ case (TBL_HEAD_VERT): - tbl_char(tp, '+', hp->width); + tbl_char(tp, '+', width); break; default: abort(); @@ -147,14 +216,12 @@ static void tbl_hframe(struct termp *tp, const struct tbl_span *sp) { const struct tbl_head *hp; + size_t width; 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 @@ -165,20 +232,23 @@ tbl_hframe(struct termp *tp, const struct tbl_span *sp if (TBL_OPT_DBOX & sp->tbl->opts) { term_word(tp, "+"); - for (hp = sp->head; hp; hp = hp->next) - tbl_char(tp, '-', hp->width); + for (hp = sp->head; hp; hp = hp->next) { + width = tp->tbl.cols[hp->ident].width; + tbl_char(tp, '-', width); + } term_word(tp, "+"); term_flushln(tp); } term_word(tp, "+"); for (hp = sp->head; hp; hp = hp->next) { + width = tp->tbl.cols[hp->ident].width; switch (hp->pos) { case (TBL_HEAD_DATA): - tbl_char(tp, '-', hp->width); + tbl_char(tp, '-', width); break; default: - tbl_char(tp, '+', hp->width); + tbl_char(tp, '+', width); break; } } @@ -188,32 +258,40 @@ tbl_hframe(struct termp *tp, const struct tbl_span *sp static void tbl_data(struct termp *tp, const struct tbl *tbl, - const struct tbl_dat *dp, int width) + const struct tbl_dat *dp, + const struct roffcol *col) { - enum tbl_cellt pos; if (NULL == dp) { - tbl_char(tp, ASCII_NBRSP, width); + tbl_char(tp, ASCII_NBRSP, col->width); return; } + assert(dp->layout); switch (dp->pos) { + case (TBL_DATA_NONE): + tbl_char(tp, ASCII_NBRSP, col->width); + return; case (TBL_DATA_HORIZ): /* FALLTHROUGH */ + case (TBL_DATA_NHORIZ): + tbl_char(tp, '-', col->width); + return; + case (TBL_DATA_NDHORIZ): + /* FALLTHROUGH */ case (TBL_DATA_DHORIZ): - tbl_data_spanner(tp, dp, width); + tbl_char(tp, '=', col->width); return; default: break; } - pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT; - - switch (pos) { + switch (dp->layout->pos) { case (TBL_CELL_HORIZ): - /* FALLTHROUGH */ + tbl_char(tp, '-', col->width); + break; case (TBL_CELL_DHORIZ): - tbl_data_spanner(tp, dp, width); + tbl_char(tp, '=', col->width); break; case (TBL_CELL_LONG): /* FALLTHROUGH */ @@ -222,18 +300,19 @@ tbl_data(struct termp *tp, const struct tbl *tbl, case (TBL_CELL_LEFT): /* FALLTHROUGH */ case (TBL_CELL_RIGHT): - tbl_data_literal(tp, dp, width); + tbl_literal(tp, dp, col); break; case (TBL_CELL_NUMBER): - tbl_data_number(tp, tbl, dp, width); + tbl_number(tp, tbl, dp, col); break; default: abort(); /* NOTREACHED */ } } + static void -tbl_spanner(struct termp *tp, const struct tbl_head *hp) +tbl_vrule(struct termp *tp, const struct tbl_head *hp) { switch (hp->pos) { @@ -251,71 +330,55 @@ tbl_spanner(struct termp *tp, const struct tbl_head *h 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) +static void +tbl_char(struct termp *tp, char c, size_t len) { - int i; + size_t i, sz; char cp[2]; cp[0] = c; cp[1] = '\0'; - for (i = 0; i < len; i++) + sz = term_strlen(tp, cp); + + for (i = 0; i < len; i += sz) term_word(tp, cp); } static void -tbl_data_spanner(struct termp *tp, const struct tbl_dat *dp, int width) +tbl_literal(struct termp *tp, const struct tbl_dat *dp, + const struct roffcol *col) { + size_t padl, padr, ssz; - 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; + assert(dp->string); - switch (pos) { + ssz = term_len(tp, 1); + + switch (dp->layout->pos) { case (TBL_CELL_LONG): - padl = 1; - padr = width - (int)strlen(dp->string) - 1; + padl = ssz; + padr = col->width - term_strlen(tp, dp->string) - ssz; break; case (TBL_CELL_CENTRE): - padl = width - (int)strlen(dp->string); + padl = col->width - term_strlen(tp, dp->string); if (padl % 2) padr++; padl /= 2; padr += padl; break; case (TBL_CELL_RIGHT): - padl = width - (int)strlen(dp->string); + padl = col->width - term_strlen(tp, dp->string); break; default: - padr = width - (int)strlen(dp->string); + padr = col->width - term_strlen(tp, dp->string); break; } @@ -325,34 +388,46 @@ tbl_data_literal(struct termp *tp, const struct tbl_da } static void -tbl_data_number(struct termp *tp, const struct tbl *tbl, - const struct tbl_dat *dp, int width) +tbl_number(struct termp *tp, const struct tbl *tbl, + const struct tbl_dat *dp, + const struct roffcol *col) { - char *decp, pnt; - int d, padl, sz; + char *cp; + char buf[2]; + size_t sz, psz, ssz, d, padl; + int i; /* * 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; + assert(dp->string); - if (NULL == (decp = strchr(dp->string, pnt))) { - d = sz + 1; - } else { - d = (int)(decp - dp->string) + 1; - } + sz = term_strlen(tp, dp->string); - assert(d <= dp->layout->head->decimal); - assert(sz - d <= dp->layout->head->width - - dp->layout->head->decimal); + buf[0] = tbl->decimal; + buf[1] = '\0'; - padl = dp->layout->head->decimal - d + 1; - assert(width - sz - padl); + psz = term_strlen(tp, buf); + if (NULL != (cp = strrchr(dp->string, tbl->decimal))) { + buf[1] = '\0'; + for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { + buf[0] = dp->string[i]; + ssz += term_strlen(tp, buf); + } + d = ssz + psz; + } else + d = sz + psz; + + sz += term_len(tp, 2); + d += term_len(tp, 1); + + padl = col->decimal - d; + tbl_char(tp, ASCII_NBRSP, padl); term_word(tp, dp->string); - tbl_char(tp, ASCII_NBRSP, width - sz - padl); + tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); } +