1*698f87a4SGarrett D'Amore /* $Id: tbl_term.c,v 1.25 2013/05/31 21:37:17 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore *
695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore *
1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore */
1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore #endif
2195c635efSGarrett D'Amore
2295c635efSGarrett D'Amore #include <assert.h>
2395c635efSGarrett D'Amore #include <stdio.h>
2495c635efSGarrett D'Amore #include <stdlib.h>
2595c635efSGarrett D'Amore #include <string.h>
2695c635efSGarrett D'Amore
2795c635efSGarrett D'Amore #include "mandoc.h"
2895c635efSGarrett D'Amore #include "out.h"
2995c635efSGarrett D'Amore #include "term.h"
3095c635efSGarrett D'Amore
3195c635efSGarrett D'Amore static size_t term_tbl_len(size_t, void *);
3295c635efSGarrett D'Amore static size_t term_tbl_strlen(const char *, void *);
3395c635efSGarrett D'Amore static void tbl_char(struct termp *, char, size_t);
34*698f87a4SGarrett D'Amore static void tbl_data(struct termp *, const struct tbl_opts *,
3595c635efSGarrett D'Amore const struct tbl_dat *,
3695c635efSGarrett D'Amore const struct roffcol *);
3795c635efSGarrett D'Amore static size_t tbl_rulewidth(struct termp *, const struct tbl_head *);
3895c635efSGarrett D'Amore static void tbl_hframe(struct termp *, const struct tbl_span *, int);
3995c635efSGarrett D'Amore static void tbl_literal(struct termp *, const struct tbl_dat *,
4095c635efSGarrett D'Amore const struct roffcol *);
41*698f87a4SGarrett D'Amore static void tbl_number(struct termp *, const struct tbl_opts *,
4295c635efSGarrett D'Amore const struct tbl_dat *,
4395c635efSGarrett D'Amore const struct roffcol *);
4495c635efSGarrett D'Amore static void tbl_hrule(struct termp *, const struct tbl_span *);
4595c635efSGarrett D'Amore static void tbl_vrule(struct termp *, const struct tbl_head *);
4695c635efSGarrett D'Amore
4795c635efSGarrett D'Amore
4895c635efSGarrett D'Amore static size_t
term_tbl_strlen(const char * p,void * arg)4995c635efSGarrett D'Amore term_tbl_strlen(const char *p, void *arg)
5095c635efSGarrett D'Amore {
5195c635efSGarrett D'Amore
5295c635efSGarrett D'Amore return(term_strlen((const struct termp *)arg, p));
5395c635efSGarrett D'Amore }
5495c635efSGarrett D'Amore
5595c635efSGarrett D'Amore static size_t
term_tbl_len(size_t sz,void * arg)5695c635efSGarrett D'Amore term_tbl_len(size_t sz, void *arg)
5795c635efSGarrett D'Amore {
5895c635efSGarrett D'Amore
5995c635efSGarrett D'Amore return(term_len((const struct termp *)arg, sz));
6095c635efSGarrett D'Amore }
6195c635efSGarrett D'Amore
6295c635efSGarrett D'Amore void
term_tbl(struct termp * tp,const struct tbl_span * sp)6395c635efSGarrett D'Amore term_tbl(struct termp *tp, const struct tbl_span *sp)
6495c635efSGarrett D'Amore {
6595c635efSGarrett D'Amore const struct tbl_head *hp;
6695c635efSGarrett D'Amore const struct tbl_dat *dp;
6795c635efSGarrett D'Amore struct roffcol *col;
6895c635efSGarrett D'Amore int spans;
6995c635efSGarrett D'Amore size_t rmargin, maxrmargin;
7095c635efSGarrett D'Amore
7195c635efSGarrett D'Amore rmargin = tp->rmargin;
7295c635efSGarrett D'Amore maxrmargin = tp->maxrmargin;
7395c635efSGarrett D'Amore
7495c635efSGarrett D'Amore tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
7595c635efSGarrett D'Amore
7695c635efSGarrett D'Amore /* Inhibit printing of spaces: we do padding ourselves. */
7795c635efSGarrett D'Amore
7895c635efSGarrett D'Amore tp->flags |= TERMP_NONOSPACE;
7995c635efSGarrett D'Amore tp->flags |= TERMP_NOSPACE;
8095c635efSGarrett D'Amore
8195c635efSGarrett D'Amore /*
8295c635efSGarrett D'Amore * The first time we're invoked for a given table block,
8395c635efSGarrett D'Amore * calculate the table widths and decimal positions.
8495c635efSGarrett D'Amore */
8595c635efSGarrett D'Amore
8695c635efSGarrett D'Amore if (TBL_SPAN_FIRST & sp->flags) {
8795c635efSGarrett D'Amore term_flushln(tp);
8895c635efSGarrett D'Amore
8995c635efSGarrett D'Amore tp->tbl.len = term_tbl_len;
9095c635efSGarrett D'Amore tp->tbl.slen = term_tbl_strlen;
9195c635efSGarrett D'Amore tp->tbl.arg = tp;
9295c635efSGarrett D'Amore
9395c635efSGarrett D'Amore tblcalc(&tp->tbl, sp);
9495c635efSGarrett D'Amore }
9595c635efSGarrett D'Amore
9695c635efSGarrett D'Amore /* Horizontal frame at the start of boxed tables. */
9795c635efSGarrett D'Amore
9895c635efSGarrett D'Amore if (TBL_SPAN_FIRST & sp->flags) {
99*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts)
10095c635efSGarrett D'Amore tbl_hframe(tp, sp, 1);
101*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts ||
102*698f87a4SGarrett D'Amore TBL_OPT_BOX & sp->opts->opts)
10395c635efSGarrett D'Amore tbl_hframe(tp, sp, 0);
10495c635efSGarrett D'Amore }
10595c635efSGarrett D'Amore
10695c635efSGarrett D'Amore /* Vertical frame at the start of each row. */
10795c635efSGarrett D'Amore
108*698f87a4SGarrett D'Amore if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
10995c635efSGarrett D'Amore term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
11095c635efSGarrett D'Amore TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
11195c635efSGarrett D'Amore
11295c635efSGarrett D'Amore /*
11395c635efSGarrett D'Amore * Now print the actual data itself depending on the span type.
11495c635efSGarrett D'Amore * Spanner spans get a horizontal rule; data spanners have their
11595c635efSGarrett D'Amore * data printed by matching data to header.
11695c635efSGarrett D'Amore */
11795c635efSGarrett D'Amore
11895c635efSGarrett D'Amore switch (sp->pos) {
11995c635efSGarrett D'Amore case (TBL_SPAN_HORIZ):
12095c635efSGarrett D'Amore /* FALLTHROUGH */
12195c635efSGarrett D'Amore case (TBL_SPAN_DHORIZ):
12295c635efSGarrett D'Amore tbl_hrule(tp, sp);
12395c635efSGarrett D'Amore break;
12495c635efSGarrett D'Amore case (TBL_SPAN_DATA):
12595c635efSGarrett D'Amore /* Iterate over template headers. */
12695c635efSGarrett D'Amore dp = sp->first;
12795c635efSGarrett D'Amore spans = 0;
12895c635efSGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) {
129*698f87a4SGarrett D'Amore
13095c635efSGarrett D'Amore /*
13195c635efSGarrett D'Amore * If the current data header is invoked during
13295c635efSGarrett D'Amore * a spanner ("spans" > 0), don't emit anything
13395c635efSGarrett D'Amore * at all.
13495c635efSGarrett D'Amore */
13595c635efSGarrett D'Amore
13695c635efSGarrett D'Amore if (--spans >= 0)
13795c635efSGarrett D'Amore continue;
13895c635efSGarrett D'Amore
139*698f87a4SGarrett D'Amore /* Separate columns. */
14095c635efSGarrett D'Amore
141*698f87a4SGarrett D'Amore if (NULL != hp->prev)
142*698f87a4SGarrett D'Amore tbl_vrule(tp, hp);
14395c635efSGarrett D'Amore
14495c635efSGarrett D'Amore col = &tp->tbl.cols[hp->ident];
145*698f87a4SGarrett D'Amore tbl_data(tp, sp->opts, dp, col);
14695c635efSGarrett D'Amore
14795c635efSGarrett D'Amore /*
14895c635efSGarrett D'Amore * Go to the next data cell and assign the
14995c635efSGarrett D'Amore * number of subsequent spans, if applicable.
15095c635efSGarrett D'Amore */
15195c635efSGarrett D'Amore
15295c635efSGarrett D'Amore if (dp) {
15395c635efSGarrett D'Amore spans = dp->spans;
15495c635efSGarrett D'Amore dp = dp->next;
15595c635efSGarrett D'Amore }
15695c635efSGarrett D'Amore }
15795c635efSGarrett D'Amore break;
15895c635efSGarrett D'Amore }
15995c635efSGarrett D'Amore
16095c635efSGarrett D'Amore /* Vertical frame at the end of each row. */
16195c635efSGarrett D'Amore
162*698f87a4SGarrett D'Amore if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
16395c635efSGarrett D'Amore term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
16495c635efSGarrett D'Amore TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
16595c635efSGarrett D'Amore term_flushln(tp);
16695c635efSGarrett D'Amore
16795c635efSGarrett D'Amore /*
16895c635efSGarrett D'Amore * If we're the last row, clean up after ourselves: clear the
16995c635efSGarrett D'Amore * existing table configuration and set it to NULL.
17095c635efSGarrett D'Amore */
17195c635efSGarrett D'Amore
17295c635efSGarrett D'Amore if (TBL_SPAN_LAST & sp->flags) {
173*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts ||
174*698f87a4SGarrett D'Amore TBL_OPT_BOX & sp->opts->opts) {
17595c635efSGarrett D'Amore tbl_hframe(tp, sp, 0);
176*698f87a4SGarrett D'Amore tp->skipvsp = 1;
177*698f87a4SGarrett D'Amore }
178*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts) {
17995c635efSGarrett D'Amore tbl_hframe(tp, sp, 1);
180*698f87a4SGarrett D'Amore tp->skipvsp = 2;
181*698f87a4SGarrett D'Amore }
18295c635efSGarrett D'Amore assert(tp->tbl.cols);
18395c635efSGarrett D'Amore free(tp->tbl.cols);
18495c635efSGarrett D'Amore tp->tbl.cols = NULL;
18595c635efSGarrett D'Amore }
18695c635efSGarrett D'Amore
18795c635efSGarrett D'Amore tp->flags &= ~TERMP_NONOSPACE;
18895c635efSGarrett D'Amore tp->rmargin = rmargin;
18995c635efSGarrett D'Amore tp->maxrmargin = maxrmargin;
19095c635efSGarrett D'Amore
19195c635efSGarrett D'Amore }
19295c635efSGarrett D'Amore
19395c635efSGarrett D'Amore /*
19495c635efSGarrett D'Amore * Horizontal rules extend across the entire table.
19595c635efSGarrett D'Amore * Calculate the width by iterating over columns.
19695c635efSGarrett D'Amore */
19795c635efSGarrett D'Amore static size_t
tbl_rulewidth(struct termp * tp,const struct tbl_head * hp)19895c635efSGarrett D'Amore tbl_rulewidth(struct termp *tp, const struct tbl_head *hp)
19995c635efSGarrett D'Amore {
20095c635efSGarrett D'Amore size_t width;
20195c635efSGarrett D'Amore
20295c635efSGarrett D'Amore width = tp->tbl.cols[hp->ident].width;
203*698f87a4SGarrett D'Amore
20495c635efSGarrett D'Amore /* Account for leading blanks. */
205*698f87a4SGarrett D'Amore if (hp->prev)
206*698f87a4SGarrett D'Amore width += 2 - hp->vert;
207*698f87a4SGarrett D'Amore
208*698f87a4SGarrett D'Amore /* Account for trailing blank. */
20995c635efSGarrett D'Amore width++;
210*698f87a4SGarrett D'Amore
21195c635efSGarrett D'Amore return(width);
21295c635efSGarrett D'Amore }
21395c635efSGarrett D'Amore
21495c635efSGarrett D'Amore /*
21595c635efSGarrett D'Amore * Rules inside the table can be single or double
21695c635efSGarrett D'Amore * and have crossings with vertical rules marked with pluses.
21795c635efSGarrett D'Amore */
21895c635efSGarrett D'Amore static void
tbl_hrule(struct termp * tp,const struct tbl_span * sp)21995c635efSGarrett D'Amore tbl_hrule(struct termp *tp, const struct tbl_span *sp)
22095c635efSGarrett D'Amore {
22195c635efSGarrett D'Amore const struct tbl_head *hp;
22295c635efSGarrett D'Amore char c;
22395c635efSGarrett D'Amore
22495c635efSGarrett D'Amore c = '-';
22595c635efSGarrett D'Amore if (TBL_SPAN_DHORIZ == sp->pos)
22695c635efSGarrett D'Amore c = '=';
22795c635efSGarrett D'Amore
228*698f87a4SGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) {
229*698f87a4SGarrett D'Amore if (hp->prev && hp->vert)
230*698f87a4SGarrett D'Amore tbl_char(tp, '+', hp->vert);
231*698f87a4SGarrett D'Amore tbl_char(tp, c, tbl_rulewidth(tp, hp));
232*698f87a4SGarrett D'Amore }
23395c635efSGarrett D'Amore }
23495c635efSGarrett D'Amore
23595c635efSGarrett D'Amore /*
23695c635efSGarrett D'Amore * Rules above and below the table are always single
23795c635efSGarrett D'Amore * and have an additional plus at the beginning and end.
23895c635efSGarrett D'Amore * For double frames, this function is called twice,
23995c635efSGarrett D'Amore * and the outer one does not have crossings.
24095c635efSGarrett D'Amore */
24195c635efSGarrett D'Amore static void
tbl_hframe(struct termp * tp,const struct tbl_span * sp,int outer)24295c635efSGarrett D'Amore tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer)
24395c635efSGarrett D'Amore {
24495c635efSGarrett D'Amore const struct tbl_head *hp;
24595c635efSGarrett D'Amore
24695c635efSGarrett D'Amore term_word(tp, "+");
247*698f87a4SGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) {
248*698f87a4SGarrett D'Amore if (hp->prev && hp->vert)
249*698f87a4SGarrett D'Amore tbl_char(tp, (outer ? '-' : '+'), hp->vert);
250*698f87a4SGarrett D'Amore tbl_char(tp, '-', tbl_rulewidth(tp, hp));
251*698f87a4SGarrett D'Amore }
25295c635efSGarrett D'Amore term_word(tp, "+");
25395c635efSGarrett D'Amore term_flushln(tp);
25495c635efSGarrett D'Amore }
25595c635efSGarrett D'Amore
25695c635efSGarrett D'Amore static void
tbl_data(struct termp * tp,const struct tbl_opts * opts,const struct tbl_dat * dp,const struct roffcol * col)257*698f87a4SGarrett D'Amore tbl_data(struct termp *tp, const struct tbl_opts *opts,
25895c635efSGarrett D'Amore const struct tbl_dat *dp,
25995c635efSGarrett D'Amore const struct roffcol *col)
26095c635efSGarrett D'Amore {
26195c635efSGarrett D'Amore
26295c635efSGarrett D'Amore if (NULL == dp) {
26395c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width);
26495c635efSGarrett D'Amore return;
26595c635efSGarrett D'Amore }
26695c635efSGarrett D'Amore assert(dp->layout);
26795c635efSGarrett D'Amore
26895c635efSGarrett D'Amore switch (dp->pos) {
26995c635efSGarrett D'Amore case (TBL_DATA_NONE):
27095c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width);
27195c635efSGarrett D'Amore return;
27295c635efSGarrett D'Amore case (TBL_DATA_HORIZ):
27395c635efSGarrett D'Amore /* FALLTHROUGH */
27495c635efSGarrett D'Amore case (TBL_DATA_NHORIZ):
27595c635efSGarrett D'Amore tbl_char(tp, '-', col->width);
27695c635efSGarrett D'Amore return;
27795c635efSGarrett D'Amore case (TBL_DATA_NDHORIZ):
27895c635efSGarrett D'Amore /* FALLTHROUGH */
27995c635efSGarrett D'Amore case (TBL_DATA_DHORIZ):
28095c635efSGarrett D'Amore tbl_char(tp, '=', col->width);
28195c635efSGarrett D'Amore return;
28295c635efSGarrett D'Amore default:
28395c635efSGarrett D'Amore break;
28495c635efSGarrett D'Amore }
28595c635efSGarrett D'Amore
28695c635efSGarrett D'Amore switch (dp->layout->pos) {
28795c635efSGarrett D'Amore case (TBL_CELL_HORIZ):
28895c635efSGarrett D'Amore tbl_char(tp, '-', col->width);
28995c635efSGarrett D'Amore break;
29095c635efSGarrett D'Amore case (TBL_CELL_DHORIZ):
29195c635efSGarrett D'Amore tbl_char(tp, '=', col->width);
29295c635efSGarrett D'Amore break;
29395c635efSGarrett D'Amore case (TBL_CELL_LONG):
29495c635efSGarrett D'Amore /* FALLTHROUGH */
29595c635efSGarrett D'Amore case (TBL_CELL_CENTRE):
29695c635efSGarrett D'Amore /* FALLTHROUGH */
29795c635efSGarrett D'Amore case (TBL_CELL_LEFT):
29895c635efSGarrett D'Amore /* FALLTHROUGH */
29995c635efSGarrett D'Amore case (TBL_CELL_RIGHT):
30095c635efSGarrett D'Amore tbl_literal(tp, dp, col);
30195c635efSGarrett D'Amore break;
30295c635efSGarrett D'Amore case (TBL_CELL_NUMBER):
303*698f87a4SGarrett D'Amore tbl_number(tp, opts, dp, col);
30495c635efSGarrett D'Amore break;
30595c635efSGarrett D'Amore case (TBL_CELL_DOWN):
30695c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width);
30795c635efSGarrett D'Amore break;
30895c635efSGarrett D'Amore default:
30995c635efSGarrett D'Amore abort();
31095c635efSGarrett D'Amore /* NOTREACHED */
31195c635efSGarrett D'Amore }
31295c635efSGarrett D'Amore }
31395c635efSGarrett D'Amore
31495c635efSGarrett D'Amore static void
tbl_vrule(struct termp * tp,const struct tbl_head * hp)31595c635efSGarrett D'Amore tbl_vrule(struct termp *tp, const struct tbl_head *hp)
31695c635efSGarrett D'Amore {
31795c635efSGarrett D'Amore
318*698f87a4SGarrett D'Amore tbl_char(tp, ASCII_NBRSP, 1);
319*698f87a4SGarrett D'Amore if (0 < hp->vert)
320*698f87a4SGarrett D'Amore tbl_char(tp, '|', hp->vert);
321*698f87a4SGarrett D'Amore if (2 > hp->vert)
322*698f87a4SGarrett D'Amore tbl_char(tp, ASCII_NBRSP, 2 - hp->vert);
32395c635efSGarrett D'Amore }
32495c635efSGarrett D'Amore
32595c635efSGarrett D'Amore static void
tbl_char(struct termp * tp,char c,size_t len)32695c635efSGarrett D'Amore tbl_char(struct termp *tp, char c, size_t len)
32795c635efSGarrett D'Amore {
32895c635efSGarrett D'Amore size_t i, sz;
32995c635efSGarrett D'Amore char cp[2];
33095c635efSGarrett D'Amore
33195c635efSGarrett D'Amore cp[0] = c;
33295c635efSGarrett D'Amore cp[1] = '\0';
33395c635efSGarrett D'Amore
33495c635efSGarrett D'Amore sz = term_strlen(tp, cp);
33595c635efSGarrett D'Amore
33695c635efSGarrett D'Amore for (i = 0; i < len; i += sz)
33795c635efSGarrett D'Amore term_word(tp, cp);
33895c635efSGarrett D'Amore }
33995c635efSGarrett D'Amore
34095c635efSGarrett D'Amore static void
tbl_literal(struct termp * tp,const struct tbl_dat * dp,const struct roffcol * col)34195c635efSGarrett D'Amore tbl_literal(struct termp *tp, const struct tbl_dat *dp,
34295c635efSGarrett D'Amore const struct roffcol *col)
34395c635efSGarrett D'Amore {
344*698f87a4SGarrett D'Amore struct tbl_head *hp;
345*698f87a4SGarrett D'Amore size_t width, len, padl, padr;
346*698f87a4SGarrett D'Amore int spans;
34795c635efSGarrett D'Amore
34895c635efSGarrett D'Amore assert(dp->string);
34995c635efSGarrett D'Amore len = term_strlen(tp, dp->string);
350*698f87a4SGarrett D'Amore
351*698f87a4SGarrett D'Amore hp = dp->layout->head->next;
352*698f87a4SGarrett D'Amore width = col->width;
353*698f87a4SGarrett D'Amore for (spans = dp->spans; spans--; hp = hp->next)
354*698f87a4SGarrett D'Amore width += tp->tbl.cols[hp->ident].width + 3;
355*698f87a4SGarrett D'Amore
356*698f87a4SGarrett D'Amore padr = width > len ? width - len : 0;
35795c635efSGarrett D'Amore padl = 0;
35895c635efSGarrett D'Amore
35995c635efSGarrett D'Amore switch (dp->layout->pos) {
36095c635efSGarrett D'Amore case (TBL_CELL_LONG):
36195c635efSGarrett D'Amore padl = term_len(tp, 1);
36295c635efSGarrett D'Amore padr = padr > padl ? padr - padl : 0;
36395c635efSGarrett D'Amore break;
36495c635efSGarrett D'Amore case (TBL_CELL_CENTRE):
36595c635efSGarrett D'Amore if (2 > padr)
36695c635efSGarrett D'Amore break;
36795c635efSGarrett D'Amore padl = padr / 2;
36895c635efSGarrett D'Amore padr -= padl;
36995c635efSGarrett D'Amore break;
37095c635efSGarrett D'Amore case (TBL_CELL_RIGHT):
37195c635efSGarrett D'Amore padl = padr;
37295c635efSGarrett D'Amore padr = 0;
37395c635efSGarrett D'Amore break;
37495c635efSGarrett D'Amore default:
37595c635efSGarrett D'Amore break;
37695c635efSGarrett D'Amore }
37795c635efSGarrett D'Amore
37895c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl);
37995c635efSGarrett D'Amore term_word(tp, dp->string);
38095c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padr);
38195c635efSGarrett D'Amore }
38295c635efSGarrett D'Amore
38395c635efSGarrett D'Amore static void
tbl_number(struct termp * tp,const struct tbl_opts * opts,const struct tbl_dat * dp,const struct roffcol * col)384*698f87a4SGarrett D'Amore tbl_number(struct termp *tp, const struct tbl_opts *opts,
38595c635efSGarrett D'Amore const struct tbl_dat *dp,
38695c635efSGarrett D'Amore const struct roffcol *col)
38795c635efSGarrett D'Amore {
38895c635efSGarrett D'Amore char *cp;
38995c635efSGarrett D'Amore char buf[2];
39095c635efSGarrett D'Amore size_t sz, psz, ssz, d, padl;
39195c635efSGarrett D'Amore int i;
39295c635efSGarrett D'Amore
39395c635efSGarrett D'Amore /*
39495c635efSGarrett D'Amore * See calc_data_number(). Left-pad by taking the offset of our
39595c635efSGarrett D'Amore * and the maximum decimal; right-pad by the remaining amount.
39695c635efSGarrett D'Amore */
39795c635efSGarrett D'Amore
39895c635efSGarrett D'Amore assert(dp->string);
39995c635efSGarrett D'Amore
40095c635efSGarrett D'Amore sz = term_strlen(tp, dp->string);
40195c635efSGarrett D'Amore
402*698f87a4SGarrett D'Amore buf[0] = opts->decimal;
40395c635efSGarrett D'Amore buf[1] = '\0';
40495c635efSGarrett D'Amore
40595c635efSGarrett D'Amore psz = term_strlen(tp, buf);
40695c635efSGarrett D'Amore
407*698f87a4SGarrett D'Amore if (NULL != (cp = strrchr(dp->string, opts->decimal))) {
40895c635efSGarrett D'Amore buf[1] = '\0';
40995c635efSGarrett D'Amore for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
41095c635efSGarrett D'Amore buf[0] = dp->string[i];
41195c635efSGarrett D'Amore ssz += term_strlen(tp, buf);
41295c635efSGarrett D'Amore }
41395c635efSGarrett D'Amore d = ssz + psz;
41495c635efSGarrett D'Amore } else
41595c635efSGarrett D'Amore d = sz + psz;
41695c635efSGarrett D'Amore
41795c635efSGarrett D'Amore padl = col->decimal - d;
41895c635efSGarrett D'Amore
41995c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl);
42095c635efSGarrett D'Amore term_word(tp, dp->string);
42195c635efSGarrett D'Amore if (col->width > sz + padl)
42295c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
42395c635efSGarrett D'Amore }
42495c635efSGarrett D'Amore
425