xref: /titanic_51/usr/src/cmd/mandoc/tbl_term.c (revision 260e9a87725c090ba5835b1f9f0b62fa2f96036f)
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
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
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
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
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
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
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
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
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
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