1*260e9a87SYuri Pankov /* $Id: tbl_term.c,v 1.40 2015/03/06 15:48:53 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*260e9a87SYuri Pankov * Copyright (c) 2011, 2012, 2014, 2015 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 #include "config.h"
19*260e9a87SYuri Pankov
20*260e9a87SYuri Pankov #include <sys/types.h>
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);
34698f87a4SGarrett 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 void tbl_literal(struct termp *, const struct tbl_dat *,
3895c635efSGarrett D'Amore const struct roffcol *);
39698f87a4SGarrett D'Amore static void tbl_number(struct termp *, const struct tbl_opts *,
4095c635efSGarrett D'Amore const struct tbl_dat *,
4195c635efSGarrett D'Amore const struct roffcol *);
42*260e9a87SYuri Pankov static void tbl_hrule(struct termp *, const struct tbl_span *, int);
43*260e9a87SYuri Pankov static void tbl_word(struct termp *, const struct tbl_dat *);
4495c635efSGarrett D'Amore
4595c635efSGarrett D'Amore
4695c635efSGarrett D'Amore static size_t
term_tbl_strlen(const char * p,void * arg)4795c635efSGarrett D'Amore term_tbl_strlen(const char *p, void *arg)
4895c635efSGarrett D'Amore {
4995c635efSGarrett D'Amore
5095c635efSGarrett D'Amore return(term_strlen((const struct termp *)arg, p));
5195c635efSGarrett D'Amore }
5295c635efSGarrett D'Amore
5395c635efSGarrett D'Amore static size_t
term_tbl_len(size_t sz,void * arg)5495c635efSGarrett D'Amore term_tbl_len(size_t sz, void *arg)
5595c635efSGarrett D'Amore {
5695c635efSGarrett D'Amore
5795c635efSGarrett D'Amore return(term_len((const struct termp *)arg, sz));
5895c635efSGarrett D'Amore }
5995c635efSGarrett D'Amore
6095c635efSGarrett D'Amore void
term_tbl(struct termp * tp,const struct tbl_span * sp)6195c635efSGarrett D'Amore term_tbl(struct termp *tp, const struct tbl_span *sp)
6295c635efSGarrett D'Amore {
63*260e9a87SYuri Pankov const struct tbl_cell *cp;
6495c635efSGarrett D'Amore const struct tbl_dat *dp;
65*260e9a87SYuri Pankov static size_t offset;
66*260e9a87SYuri Pankov size_t rmargin, maxrmargin, tsz;
67*260e9a87SYuri Pankov int ic, horiz, spans, vert;
6895c635efSGarrett D'Amore
6995c635efSGarrett D'Amore rmargin = tp->rmargin;
7095c635efSGarrett D'Amore maxrmargin = tp->maxrmargin;
7195c635efSGarrett D'Amore
7295c635efSGarrett D'Amore tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
7395c635efSGarrett D'Amore
7495c635efSGarrett D'Amore /* Inhibit printing of spaces: we do padding ourselves. */
7595c635efSGarrett D'Amore
7695c635efSGarrett D'Amore tp->flags |= TERMP_NONOSPACE;
7795c635efSGarrett D'Amore tp->flags |= TERMP_NOSPACE;
7895c635efSGarrett D'Amore
7995c635efSGarrett D'Amore /*
8095c635efSGarrett D'Amore * The first time we're invoked for a given table block,
8195c635efSGarrett D'Amore * calculate the table widths and decimal positions.
8295c635efSGarrett D'Amore */
8395c635efSGarrett D'Amore
84*260e9a87SYuri Pankov if (tp->tbl.cols == NULL) {
8595c635efSGarrett D'Amore tp->tbl.len = term_tbl_len;
8695c635efSGarrett D'Amore tp->tbl.slen = term_tbl_strlen;
8795c635efSGarrett D'Amore tp->tbl.arg = tp;
8895c635efSGarrett D'Amore
89*260e9a87SYuri Pankov tblcalc(&tp->tbl, sp, rmargin - tp->offset);
90*260e9a87SYuri Pankov
91*260e9a87SYuri Pankov /* Center the table as a whole. */
92*260e9a87SYuri Pankov
93*260e9a87SYuri Pankov offset = tp->offset;
94*260e9a87SYuri Pankov if (sp->opts->opts & TBL_OPT_CENTRE) {
95*260e9a87SYuri Pankov tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
96*260e9a87SYuri Pankov ? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
97*260e9a87SYuri Pankov for (ic = 0; ic < sp->opts->cols; ic++)
98*260e9a87SYuri Pankov tsz += tp->tbl.cols[ic].width + 3;
99*260e9a87SYuri Pankov tsz -= 3;
100*260e9a87SYuri Pankov if (offset + tsz > rmargin)
101*260e9a87SYuri Pankov tsz -= 1;
102*260e9a87SYuri Pankov tp->offset = (offset + rmargin > tsz) ?
103*260e9a87SYuri Pankov (offset + rmargin - tsz) / 2 : 0;
10495c635efSGarrett D'Amore }
10595c635efSGarrett D'Amore
10695c635efSGarrett D'Amore /* Horizontal frame at the start of boxed tables. */
10795c635efSGarrett D'Amore
108*260e9a87SYuri Pankov if (sp->opts->opts & TBL_OPT_DBOX)
109*260e9a87SYuri Pankov tbl_hrule(tp, sp, 2);
110*260e9a87SYuri Pankov if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
111*260e9a87SYuri Pankov tbl_hrule(tp, sp, 1);
11295c635efSGarrett D'Amore }
11395c635efSGarrett D'Amore
11495c635efSGarrett D'Amore /* Vertical frame at the start of each row. */
11595c635efSGarrett D'Amore
116*260e9a87SYuri Pankov horiz = sp->pos == TBL_SPAN_HORIZ || sp->pos == TBL_SPAN_DHORIZ;
117*260e9a87SYuri Pankov
118*260e9a87SYuri Pankov if (sp->layout->vert ||
119*260e9a87SYuri Pankov (sp->prev != NULL && sp->prev->layout->vert) ||
120*260e9a87SYuri Pankov sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
121*260e9a87SYuri Pankov term_word(tp, horiz ? "+" : "|");
122*260e9a87SYuri Pankov else if (sp->opts->lvert)
123*260e9a87SYuri Pankov tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1);
12495c635efSGarrett D'Amore
12595c635efSGarrett D'Amore /*
12695c635efSGarrett D'Amore * Now print the actual data itself depending on the span type.
127*260e9a87SYuri Pankov * Match data cells to column numbers.
12895c635efSGarrett D'Amore */
12995c635efSGarrett D'Amore
130*260e9a87SYuri Pankov if (sp->pos == TBL_SPAN_DATA) {
131*260e9a87SYuri Pankov cp = sp->layout->first;
13295c635efSGarrett D'Amore dp = sp->first;
13395c635efSGarrett D'Amore spans = 0;
134*260e9a87SYuri Pankov for (ic = 0; ic < sp->opts->cols; ic++) {
135698f87a4SGarrett D'Amore
13695c635efSGarrett D'Amore /*
137*260e9a87SYuri Pankov * Remeber whether we need a vertical bar
138*260e9a87SYuri Pankov * after this cell.
13995c635efSGarrett D'Amore */
14095c635efSGarrett D'Amore
141*260e9a87SYuri Pankov vert = cp == NULL ? 0 : cp->vert;
14295c635efSGarrett D'Amore
14395c635efSGarrett D'Amore /*
144*260e9a87SYuri Pankov * Print the data and advance to the next cell.
14595c635efSGarrett D'Amore */
14695c635efSGarrett D'Amore
147*260e9a87SYuri Pankov if (spans == 0) {
148*260e9a87SYuri Pankov tbl_data(tp, sp->opts, dp, tp->tbl.cols + ic);
149*260e9a87SYuri Pankov if (dp != NULL) {
15095c635efSGarrett D'Amore spans = dp->spans;
15195c635efSGarrett D'Amore dp = dp->next;
15295c635efSGarrett D'Amore }
153*260e9a87SYuri Pankov } else
154*260e9a87SYuri Pankov spans--;
155*260e9a87SYuri Pankov if (cp != NULL)
156*260e9a87SYuri Pankov cp = cp->next;
157*260e9a87SYuri Pankov
158*260e9a87SYuri Pankov /*
159*260e9a87SYuri Pankov * Separate columns, except in the middle
160*260e9a87SYuri Pankov * of spans and after the last cell.
161*260e9a87SYuri Pankov */
162*260e9a87SYuri Pankov
163*260e9a87SYuri Pankov if (ic + 1 == sp->opts->cols || spans)
164*260e9a87SYuri Pankov continue;
165*260e9a87SYuri Pankov
166*260e9a87SYuri Pankov tbl_char(tp, ASCII_NBRSP, 1);
167*260e9a87SYuri Pankov if (vert > 0)
168*260e9a87SYuri Pankov tbl_char(tp, '|', vert);
169*260e9a87SYuri Pankov if (vert < 2)
170*260e9a87SYuri Pankov tbl_char(tp, ASCII_NBRSP, 2 - vert);
17195c635efSGarrett D'Amore }
172*260e9a87SYuri Pankov } else if (horiz)
173*260e9a87SYuri Pankov tbl_hrule(tp, sp, 0);
17495c635efSGarrett D'Amore
17595c635efSGarrett D'Amore /* Vertical frame at the end of each row. */
17695c635efSGarrett D'Amore
177*260e9a87SYuri Pankov if (sp->layout->last->vert ||
178*260e9a87SYuri Pankov (sp->prev != NULL && sp->prev->layout->last->vert) ||
179*260e9a87SYuri Pankov (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
180*260e9a87SYuri Pankov term_word(tp, horiz ? "+" : " |");
181*260e9a87SYuri Pankov else if (sp->opts->rvert)
182*260e9a87SYuri Pankov tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1);
18395c635efSGarrett D'Amore term_flushln(tp);
18495c635efSGarrett D'Amore
18595c635efSGarrett D'Amore /*
18695c635efSGarrett D'Amore * If we're the last row, clean up after ourselves: clear the
18795c635efSGarrett D'Amore * existing table configuration and set it to NULL.
18895c635efSGarrett D'Amore */
18995c635efSGarrett D'Amore
190*260e9a87SYuri Pankov if (sp->next == NULL) {
191*260e9a87SYuri Pankov if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
192*260e9a87SYuri Pankov tbl_hrule(tp, sp, 1);
193698f87a4SGarrett D'Amore tp->skipvsp = 1;
194698f87a4SGarrett D'Amore }
195*260e9a87SYuri Pankov if (sp->opts->opts & TBL_OPT_DBOX) {
196*260e9a87SYuri Pankov tbl_hrule(tp, sp, 2);
197698f87a4SGarrett D'Amore tp->skipvsp = 2;
198698f87a4SGarrett D'Amore }
19995c635efSGarrett D'Amore assert(tp->tbl.cols);
20095c635efSGarrett D'Amore free(tp->tbl.cols);
20195c635efSGarrett D'Amore tp->tbl.cols = NULL;
202*260e9a87SYuri Pankov tp->offset = offset;
20395c635efSGarrett D'Amore }
20495c635efSGarrett D'Amore
20595c635efSGarrett D'Amore tp->flags &= ~TERMP_NONOSPACE;
20695c635efSGarrett D'Amore tp->rmargin = rmargin;
20795c635efSGarrett D'Amore tp->maxrmargin = maxrmargin;
20895c635efSGarrett D'Amore }
20995c635efSGarrett D'Amore
21095c635efSGarrett D'Amore /*
211*260e9a87SYuri Pankov * Kinds of horizontal rulers:
212*260e9a87SYuri Pankov * 0: inside the table (single or double line with crossings)
213*260e9a87SYuri Pankov * 1: inner frame (single line with crossings and ends)
214*260e9a87SYuri Pankov * 2: outer frame (single line without crossings with ends)
21595c635efSGarrett D'Amore */
21695c635efSGarrett D'Amore static void
tbl_hrule(struct termp * tp,const struct tbl_span * sp,int kind)217*260e9a87SYuri Pankov tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
21895c635efSGarrett D'Amore {
219*260e9a87SYuri Pankov const struct tbl_cell *c1, *c2;
220*260e9a87SYuri Pankov int vert;
221*260e9a87SYuri Pankov char line, cross;
22295c635efSGarrett D'Amore
223*260e9a87SYuri Pankov line = (kind == 0 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
224*260e9a87SYuri Pankov cross = (kind < 2) ? '+' : '-';
22595c635efSGarrett D'Amore
226*260e9a87SYuri Pankov if (kind)
22795c635efSGarrett D'Amore term_word(tp, "+");
228*260e9a87SYuri Pankov c1 = sp->layout->first;
229*260e9a87SYuri Pankov c2 = sp->prev == NULL ? NULL : sp->prev->layout->first;
230*260e9a87SYuri Pankov if (c2 == c1)
231*260e9a87SYuri Pankov c2 = NULL;
232*260e9a87SYuri Pankov for (;;) {
233*260e9a87SYuri Pankov tbl_char(tp, line, tp->tbl.cols[c1->col].width + 1);
234*260e9a87SYuri Pankov vert = c1->vert;
235*260e9a87SYuri Pankov if ((c1 = c1->next) == NULL)
236*260e9a87SYuri Pankov break;
237*260e9a87SYuri Pankov if (c2 != NULL) {
238*260e9a87SYuri Pankov if (vert < c2->vert)
239*260e9a87SYuri Pankov vert = c2->vert;
240*260e9a87SYuri Pankov c2 = c2->next;
241698f87a4SGarrett D'Amore }
242*260e9a87SYuri Pankov if (vert)
243*260e9a87SYuri Pankov tbl_char(tp, cross, vert);
244*260e9a87SYuri Pankov if (vert < 2)
245*260e9a87SYuri Pankov tbl_char(tp, line, 2 - vert);
246*260e9a87SYuri Pankov }
247*260e9a87SYuri Pankov if (kind) {
24895c635efSGarrett D'Amore term_word(tp, "+");
24995c635efSGarrett D'Amore term_flushln(tp);
25095c635efSGarrett D'Amore }
251*260e9a87SYuri Pankov }
25295c635efSGarrett D'Amore
25395c635efSGarrett D'Amore static void
tbl_data(struct termp * tp,const struct tbl_opts * opts,const struct tbl_dat * dp,const struct roffcol * col)254698f87a4SGarrett D'Amore tbl_data(struct termp *tp, const struct tbl_opts *opts,
25595c635efSGarrett D'Amore const struct tbl_dat *dp,
25695c635efSGarrett D'Amore const struct roffcol *col)
25795c635efSGarrett D'Amore {
25895c635efSGarrett D'Amore
259*260e9a87SYuri Pankov if (dp == NULL) {
26095c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width);
26195c635efSGarrett D'Amore return;
26295c635efSGarrett D'Amore }
26395c635efSGarrett D'Amore
26495c635efSGarrett D'Amore switch (dp->pos) {
265*260e9a87SYuri Pankov case TBL_DATA_NONE:
26695c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width);
26795c635efSGarrett D'Amore return;
268*260e9a87SYuri Pankov case TBL_DATA_HORIZ:
26995c635efSGarrett D'Amore /* FALLTHROUGH */
270*260e9a87SYuri Pankov case TBL_DATA_NHORIZ:
27195c635efSGarrett D'Amore tbl_char(tp, '-', col->width);
27295c635efSGarrett D'Amore return;
273*260e9a87SYuri Pankov case TBL_DATA_NDHORIZ:
27495c635efSGarrett D'Amore /* FALLTHROUGH */
275*260e9a87SYuri Pankov case TBL_DATA_DHORIZ:
27695c635efSGarrett D'Amore tbl_char(tp, '=', col->width);
27795c635efSGarrett D'Amore return;
27895c635efSGarrett D'Amore default:
27995c635efSGarrett D'Amore break;
28095c635efSGarrett D'Amore }
28195c635efSGarrett D'Amore
28295c635efSGarrett D'Amore switch (dp->layout->pos) {
283*260e9a87SYuri Pankov case TBL_CELL_HORIZ:
28495c635efSGarrett D'Amore tbl_char(tp, '-', col->width);
28595c635efSGarrett D'Amore break;
286*260e9a87SYuri Pankov case TBL_CELL_DHORIZ:
28795c635efSGarrett D'Amore tbl_char(tp, '=', col->width);
28895c635efSGarrett D'Amore break;
289*260e9a87SYuri Pankov case TBL_CELL_LONG:
29095c635efSGarrett D'Amore /* FALLTHROUGH */
291*260e9a87SYuri Pankov case TBL_CELL_CENTRE:
29295c635efSGarrett D'Amore /* FALLTHROUGH */
293*260e9a87SYuri Pankov case TBL_CELL_LEFT:
29495c635efSGarrett D'Amore /* FALLTHROUGH */
295*260e9a87SYuri Pankov case TBL_CELL_RIGHT:
29695c635efSGarrett D'Amore tbl_literal(tp, dp, col);
29795c635efSGarrett D'Amore break;
298*260e9a87SYuri Pankov case TBL_CELL_NUMBER:
299698f87a4SGarrett D'Amore tbl_number(tp, opts, dp, col);
30095c635efSGarrett D'Amore break;
301*260e9a87SYuri Pankov case TBL_CELL_DOWN:
30295c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width);
30395c635efSGarrett D'Amore break;
30495c635efSGarrett D'Amore default:
30595c635efSGarrett D'Amore abort();
30695c635efSGarrett D'Amore /* NOTREACHED */
30795c635efSGarrett D'Amore }
30895c635efSGarrett D'Amore }
30995c635efSGarrett D'Amore
31095c635efSGarrett D'Amore static void
tbl_char(struct termp * tp,char c,size_t len)31195c635efSGarrett D'Amore tbl_char(struct termp *tp, char c, size_t len)
31295c635efSGarrett D'Amore {
31395c635efSGarrett D'Amore size_t i, sz;
31495c635efSGarrett D'Amore char cp[2];
31595c635efSGarrett D'Amore
31695c635efSGarrett D'Amore cp[0] = c;
31795c635efSGarrett D'Amore cp[1] = '\0';
31895c635efSGarrett D'Amore
31995c635efSGarrett D'Amore sz = term_strlen(tp, cp);
32095c635efSGarrett D'Amore
32195c635efSGarrett D'Amore for (i = 0; i < len; i += sz)
32295c635efSGarrett D'Amore term_word(tp, cp);
32395c635efSGarrett D'Amore }
32495c635efSGarrett D'Amore
32595c635efSGarrett D'Amore static void
tbl_literal(struct termp * tp,const struct tbl_dat * dp,const struct roffcol * col)32695c635efSGarrett D'Amore tbl_literal(struct termp *tp, const struct tbl_dat *dp,
32795c635efSGarrett D'Amore const struct roffcol *col)
32895c635efSGarrett D'Amore {
329*260e9a87SYuri Pankov size_t len, padl, padr, width;
330*260e9a87SYuri Pankov int ic, spans;
33195c635efSGarrett D'Amore
33295c635efSGarrett D'Amore assert(dp->string);
33395c635efSGarrett D'Amore len = term_strlen(tp, dp->string);
334698f87a4SGarrett D'Amore width = col->width;
335*260e9a87SYuri Pankov ic = dp->layout->col;
336*260e9a87SYuri Pankov spans = dp->spans;
337*260e9a87SYuri Pankov while (spans--)
338*260e9a87SYuri Pankov width += tp->tbl.cols[++ic].width + 3;
339698f87a4SGarrett D'Amore
340698f87a4SGarrett D'Amore padr = width > len ? width - len : 0;
34195c635efSGarrett D'Amore padl = 0;
34295c635efSGarrett D'Amore
34395c635efSGarrett D'Amore switch (dp->layout->pos) {
344*260e9a87SYuri Pankov case TBL_CELL_LONG:
34595c635efSGarrett D'Amore padl = term_len(tp, 1);
34695c635efSGarrett D'Amore padr = padr > padl ? padr - padl : 0;
34795c635efSGarrett D'Amore break;
348*260e9a87SYuri Pankov case TBL_CELL_CENTRE:
34995c635efSGarrett D'Amore if (2 > padr)
35095c635efSGarrett D'Amore break;
35195c635efSGarrett D'Amore padl = padr / 2;
35295c635efSGarrett D'Amore padr -= padl;
35395c635efSGarrett D'Amore break;
354*260e9a87SYuri Pankov case TBL_CELL_RIGHT:
35595c635efSGarrett D'Amore padl = padr;
35695c635efSGarrett D'Amore padr = 0;
35795c635efSGarrett D'Amore break;
35895c635efSGarrett D'Amore default:
35995c635efSGarrett D'Amore break;
36095c635efSGarrett D'Amore }
36195c635efSGarrett D'Amore
36295c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl);
363*260e9a87SYuri Pankov tbl_word(tp, dp);
36495c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padr);
36595c635efSGarrett D'Amore }
36695c635efSGarrett D'Amore
36795c635efSGarrett D'Amore static void
tbl_number(struct termp * tp,const struct tbl_opts * opts,const struct tbl_dat * dp,const struct roffcol * col)368698f87a4SGarrett D'Amore tbl_number(struct termp *tp, const struct tbl_opts *opts,
36995c635efSGarrett D'Amore const struct tbl_dat *dp,
37095c635efSGarrett D'Amore const struct roffcol *col)
37195c635efSGarrett D'Amore {
37295c635efSGarrett D'Amore char *cp;
37395c635efSGarrett D'Amore char buf[2];
37495c635efSGarrett D'Amore size_t sz, psz, ssz, d, padl;
37595c635efSGarrett D'Amore int i;
37695c635efSGarrett D'Amore
37795c635efSGarrett D'Amore /*
37895c635efSGarrett D'Amore * See calc_data_number(). Left-pad by taking the offset of our
37995c635efSGarrett D'Amore * and the maximum decimal; right-pad by the remaining amount.
38095c635efSGarrett D'Amore */
38195c635efSGarrett D'Amore
38295c635efSGarrett D'Amore assert(dp->string);
38395c635efSGarrett D'Amore
38495c635efSGarrett D'Amore sz = term_strlen(tp, dp->string);
38595c635efSGarrett D'Amore
386698f87a4SGarrett D'Amore buf[0] = opts->decimal;
38795c635efSGarrett D'Amore buf[1] = '\0';
38895c635efSGarrett D'Amore
38995c635efSGarrett D'Amore psz = term_strlen(tp, buf);
39095c635efSGarrett D'Amore
391*260e9a87SYuri Pankov if ((cp = strrchr(dp->string, opts->decimal)) != NULL) {
39295c635efSGarrett D'Amore for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
39395c635efSGarrett D'Amore buf[0] = dp->string[i];
39495c635efSGarrett D'Amore ssz += term_strlen(tp, buf);
39595c635efSGarrett D'Amore }
39695c635efSGarrett D'Amore d = ssz + psz;
39795c635efSGarrett D'Amore } else
39895c635efSGarrett D'Amore d = sz + psz;
39995c635efSGarrett D'Amore
400*260e9a87SYuri Pankov if (col->decimal > d && col->width > sz) {
40195c635efSGarrett D'Amore padl = col->decimal - d;
402*260e9a87SYuri Pankov if (padl + sz > col->width)
403*260e9a87SYuri Pankov padl = col->width - sz;
40495c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl);
405*260e9a87SYuri Pankov } else
406*260e9a87SYuri Pankov padl = 0;
407*260e9a87SYuri Pankov tbl_word(tp, dp);
40895c635efSGarrett D'Amore if (col->width > sz + padl)
40995c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
41095c635efSGarrett D'Amore }
41195c635efSGarrett D'Amore
412*260e9a87SYuri Pankov static void
tbl_word(struct termp * tp,const struct tbl_dat * dp)413*260e9a87SYuri Pankov tbl_word(struct termp *tp, const struct tbl_dat *dp)
414*260e9a87SYuri Pankov {
415*260e9a87SYuri Pankov int prev_font;
416*260e9a87SYuri Pankov
417*260e9a87SYuri Pankov prev_font = tp->fonti;
418*260e9a87SYuri Pankov if (dp->layout->flags & TBL_CELL_BOLD)
419*260e9a87SYuri Pankov term_fontpush(tp, TERMFONT_BOLD);
420*260e9a87SYuri Pankov else if (dp->layout->flags & TBL_CELL_ITALIC)
421*260e9a87SYuri Pankov term_fontpush(tp, TERMFONT_UNDER);
422*260e9a87SYuri Pankov
423*260e9a87SYuri Pankov term_word(tp, dp->string);
424*260e9a87SYuri Pankov
425*260e9a87SYuri Pankov term_fontpopq(tp, prev_font);
426*260e9a87SYuri Pankov }
427