xref: /titanic_41/usr/src/cmd/mandoc/tbl_term.c (revision ffb8ebfab4941f959e7caea93ecfb348cfa3515e)
1*ffb8ebfaSGarrett D'Amore /*	$Id: tbl_term.c,v 1.25 2013/05/31 21:37:17 schwarze Exp $ */
232a712daSGarrett D'Amore /*
332a712daSGarrett D'Amore  * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*ffb8ebfaSGarrett D'Amore  * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
532a712daSGarrett D'Amore  *
632a712daSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
732a712daSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
832a712daSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
932a712daSGarrett D'Amore  *
1032a712daSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1132a712daSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1232a712daSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1332a712daSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1432a712daSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1532a712daSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1632a712daSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1732a712daSGarrett D'Amore  */
1832a712daSGarrett D'Amore #ifdef HAVE_CONFIG_H
1932a712daSGarrett D'Amore #include "config.h"
2032a712daSGarrett D'Amore #endif
2132a712daSGarrett D'Amore 
2232a712daSGarrett D'Amore #include <assert.h>
2332a712daSGarrett D'Amore #include <stdio.h>
2432a712daSGarrett D'Amore #include <stdlib.h>
2532a712daSGarrett D'Amore #include <string.h>
2632a712daSGarrett D'Amore 
2732a712daSGarrett D'Amore #include "mandoc.h"
2832a712daSGarrett D'Amore #include "out.h"
2932a712daSGarrett D'Amore #include "term.h"
3032a712daSGarrett D'Amore 
3132a712daSGarrett D'Amore static	size_t	term_tbl_len(size_t, void *);
3232a712daSGarrett D'Amore static	size_t	term_tbl_strlen(const char *, void *);
3332a712daSGarrett D'Amore static	void	tbl_char(struct termp *, char, size_t);
34*ffb8ebfaSGarrett D'Amore static	void	tbl_data(struct termp *, const struct tbl_opts *,
3532a712daSGarrett D'Amore 			const struct tbl_dat *,
3632a712daSGarrett D'Amore 			const struct roffcol *);
3732a712daSGarrett D'Amore static	size_t	tbl_rulewidth(struct termp *, const struct tbl_head *);
3832a712daSGarrett D'Amore static	void	tbl_hframe(struct termp *, const struct tbl_span *, int);
3932a712daSGarrett D'Amore static	void	tbl_literal(struct termp *, const struct tbl_dat *,
4032a712daSGarrett D'Amore 			const struct roffcol *);
41*ffb8ebfaSGarrett D'Amore static	void	tbl_number(struct termp *, const struct tbl_opts *,
4232a712daSGarrett D'Amore 			const struct tbl_dat *,
4332a712daSGarrett D'Amore 			const struct roffcol *);
4432a712daSGarrett D'Amore static	void	tbl_hrule(struct termp *, const struct tbl_span *);
4532a712daSGarrett D'Amore static	void	tbl_vrule(struct termp *, const struct tbl_head *);
4632a712daSGarrett D'Amore 
4732a712daSGarrett D'Amore 
4832a712daSGarrett D'Amore static size_t
term_tbl_strlen(const char * p,void * arg)4932a712daSGarrett D'Amore term_tbl_strlen(const char *p, void *arg)
5032a712daSGarrett D'Amore {
5132a712daSGarrett D'Amore 
5232a712daSGarrett D'Amore 	return(term_strlen((const struct termp *)arg, p));
5332a712daSGarrett D'Amore }
5432a712daSGarrett D'Amore 
5532a712daSGarrett D'Amore static size_t
term_tbl_len(size_t sz,void * arg)5632a712daSGarrett D'Amore term_tbl_len(size_t sz, void *arg)
5732a712daSGarrett D'Amore {
5832a712daSGarrett D'Amore 
5932a712daSGarrett D'Amore 	return(term_len((const struct termp *)arg, sz));
6032a712daSGarrett D'Amore }
6132a712daSGarrett D'Amore 
6232a712daSGarrett D'Amore void
term_tbl(struct termp * tp,const struct tbl_span * sp)6332a712daSGarrett D'Amore term_tbl(struct termp *tp, const struct tbl_span *sp)
6432a712daSGarrett D'Amore {
6532a712daSGarrett D'Amore 	const struct tbl_head	*hp;
6632a712daSGarrett D'Amore 	const struct tbl_dat	*dp;
6732a712daSGarrett D'Amore 	struct roffcol		*col;
6832a712daSGarrett D'Amore 	int			 spans;
6932a712daSGarrett D'Amore 	size_t		   	 rmargin, maxrmargin;
7032a712daSGarrett D'Amore 
7132a712daSGarrett D'Amore 	rmargin = tp->rmargin;
7232a712daSGarrett D'Amore 	maxrmargin = tp->maxrmargin;
7332a712daSGarrett D'Amore 
7432a712daSGarrett D'Amore 	tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
7532a712daSGarrett D'Amore 
7632a712daSGarrett D'Amore 	/* Inhibit printing of spaces: we do padding ourselves. */
7732a712daSGarrett D'Amore 
7832a712daSGarrett D'Amore 	tp->flags |= TERMP_NONOSPACE;
7932a712daSGarrett D'Amore 	tp->flags |= TERMP_NOSPACE;
8032a712daSGarrett D'Amore 
8132a712daSGarrett D'Amore 	/*
8232a712daSGarrett D'Amore 	 * The first time we're invoked for a given table block,
8332a712daSGarrett D'Amore 	 * calculate the table widths and decimal positions.
8432a712daSGarrett D'Amore 	 */
8532a712daSGarrett D'Amore 
8632a712daSGarrett D'Amore 	if (TBL_SPAN_FIRST & sp->flags) {
8732a712daSGarrett D'Amore 		term_flushln(tp);
8832a712daSGarrett D'Amore 
8932a712daSGarrett D'Amore 		tp->tbl.len = term_tbl_len;
9032a712daSGarrett D'Amore 		tp->tbl.slen = term_tbl_strlen;
9132a712daSGarrett D'Amore 		tp->tbl.arg = tp;
9232a712daSGarrett D'Amore 
9332a712daSGarrett D'Amore 		tblcalc(&tp->tbl, sp);
9432a712daSGarrett D'Amore 	}
9532a712daSGarrett D'Amore 
9632a712daSGarrett D'Amore 	/* Horizontal frame at the start of boxed tables. */
9732a712daSGarrett D'Amore 
9832a712daSGarrett D'Amore 	if (TBL_SPAN_FIRST & sp->flags) {
99*ffb8ebfaSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->opts->opts)
10032a712daSGarrett D'Amore 			tbl_hframe(tp, sp, 1);
101*ffb8ebfaSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->opts->opts ||
102*ffb8ebfaSGarrett D'Amore 		    TBL_OPT_BOX  & sp->opts->opts)
10332a712daSGarrett D'Amore 			tbl_hframe(tp, sp, 0);
10432a712daSGarrett D'Amore 	}
10532a712daSGarrett D'Amore 
10632a712daSGarrett D'Amore 	/* Vertical frame at the start of each row. */
10732a712daSGarrett D'Amore 
108*ffb8ebfaSGarrett D'Amore 	if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
10932a712daSGarrett D'Amore 		term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
11032a712daSGarrett D'Amore 			TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
11132a712daSGarrett D'Amore 
11232a712daSGarrett D'Amore 	/*
11332a712daSGarrett D'Amore 	 * Now print the actual data itself depending on the span type.
11432a712daSGarrett D'Amore 	 * Spanner spans get a horizontal rule; data spanners have their
11532a712daSGarrett D'Amore 	 * data printed by matching data to header.
11632a712daSGarrett D'Amore 	 */
11732a712daSGarrett D'Amore 
11832a712daSGarrett D'Amore 	switch (sp->pos) {
11932a712daSGarrett D'Amore 	case (TBL_SPAN_HORIZ):
12032a712daSGarrett D'Amore 		/* FALLTHROUGH */
12132a712daSGarrett D'Amore 	case (TBL_SPAN_DHORIZ):
12232a712daSGarrett D'Amore 		tbl_hrule(tp, sp);
12332a712daSGarrett D'Amore 		break;
12432a712daSGarrett D'Amore 	case (TBL_SPAN_DATA):
12532a712daSGarrett D'Amore 		/* Iterate over template headers. */
12632a712daSGarrett D'Amore 		dp = sp->first;
12732a712daSGarrett D'Amore 		spans = 0;
12832a712daSGarrett D'Amore 		for (hp = sp->head; hp; hp = hp->next) {
129*ffb8ebfaSGarrett D'Amore 
13032a712daSGarrett D'Amore 			/*
13132a712daSGarrett D'Amore 			 * If the current data header is invoked during
13232a712daSGarrett D'Amore 			 * a spanner ("spans" > 0), don't emit anything
13332a712daSGarrett D'Amore 			 * at all.
13432a712daSGarrett D'Amore 			 */
13532a712daSGarrett D'Amore 
13632a712daSGarrett D'Amore 			if (--spans >= 0)
13732a712daSGarrett D'Amore 				continue;
13832a712daSGarrett D'Amore 
139*ffb8ebfaSGarrett D'Amore 			/* Separate columns. */
14032a712daSGarrett D'Amore 
141*ffb8ebfaSGarrett D'Amore 			if (NULL != hp->prev)
142*ffb8ebfaSGarrett D'Amore 				tbl_vrule(tp, hp);
14332a712daSGarrett D'Amore 
14432a712daSGarrett D'Amore 			col = &tp->tbl.cols[hp->ident];
145*ffb8ebfaSGarrett D'Amore 			tbl_data(tp, sp->opts, dp, col);
14632a712daSGarrett D'Amore 
14732a712daSGarrett D'Amore 			/*
14832a712daSGarrett D'Amore 			 * Go to the next data cell and assign the
14932a712daSGarrett D'Amore 			 * number of subsequent spans, if applicable.
15032a712daSGarrett D'Amore 			 */
15132a712daSGarrett D'Amore 
15232a712daSGarrett D'Amore 			if (dp) {
15332a712daSGarrett D'Amore 				spans = dp->spans;
15432a712daSGarrett D'Amore 				dp = dp->next;
15532a712daSGarrett D'Amore 			}
15632a712daSGarrett D'Amore 		}
15732a712daSGarrett D'Amore 		break;
15832a712daSGarrett D'Amore 	}
15932a712daSGarrett D'Amore 
16032a712daSGarrett D'Amore 	/* Vertical frame at the end of each row. */
16132a712daSGarrett D'Amore 
162*ffb8ebfaSGarrett D'Amore 	if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
16332a712daSGarrett D'Amore 		term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
16432a712daSGarrett D'Amore 			TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
16532a712daSGarrett D'Amore 	term_flushln(tp);
16632a712daSGarrett D'Amore 
16732a712daSGarrett D'Amore 	/*
16832a712daSGarrett D'Amore 	 * If we're the last row, clean up after ourselves: clear the
16932a712daSGarrett D'Amore 	 * existing table configuration and set it to NULL.
17032a712daSGarrett D'Amore 	 */
17132a712daSGarrett D'Amore 
17232a712daSGarrett D'Amore 	if (TBL_SPAN_LAST & sp->flags) {
173*ffb8ebfaSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->opts->opts ||
174*ffb8ebfaSGarrett D'Amore 		    TBL_OPT_BOX  & sp->opts->opts) {
17532a712daSGarrett D'Amore 			tbl_hframe(tp, sp, 0);
176*ffb8ebfaSGarrett D'Amore 			tp->skipvsp = 1;
177*ffb8ebfaSGarrett D'Amore 		}
178*ffb8ebfaSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->opts->opts) {
17932a712daSGarrett D'Amore 			tbl_hframe(tp, sp, 1);
180*ffb8ebfaSGarrett D'Amore 			tp->skipvsp = 2;
181*ffb8ebfaSGarrett D'Amore 		}
18232a712daSGarrett D'Amore 		assert(tp->tbl.cols);
18332a712daSGarrett D'Amore 		free(tp->tbl.cols);
18432a712daSGarrett D'Amore 		tp->tbl.cols = NULL;
18532a712daSGarrett D'Amore 	}
18632a712daSGarrett D'Amore 
18732a712daSGarrett D'Amore 	tp->flags &= ~TERMP_NONOSPACE;
18832a712daSGarrett D'Amore 	tp->rmargin = rmargin;
18932a712daSGarrett D'Amore 	tp->maxrmargin = maxrmargin;
19032a712daSGarrett D'Amore 
19132a712daSGarrett D'Amore }
19232a712daSGarrett D'Amore 
19332a712daSGarrett D'Amore /*
19432a712daSGarrett D'Amore  * Horizontal rules extend across the entire table.
19532a712daSGarrett D'Amore  * Calculate the width by iterating over columns.
19632a712daSGarrett D'Amore  */
19732a712daSGarrett D'Amore static size_t
tbl_rulewidth(struct termp * tp,const struct tbl_head * hp)19832a712daSGarrett D'Amore tbl_rulewidth(struct termp *tp, const struct tbl_head *hp)
19932a712daSGarrett D'Amore {
20032a712daSGarrett D'Amore 	size_t		 width;
20132a712daSGarrett D'Amore 
20232a712daSGarrett D'Amore 	width = tp->tbl.cols[hp->ident].width;
203*ffb8ebfaSGarrett D'Amore 
20432a712daSGarrett D'Amore 	/* Account for leading blanks. */
205*ffb8ebfaSGarrett D'Amore 	if (hp->prev)
206*ffb8ebfaSGarrett D'Amore 		width += 2 - hp->vert;
207*ffb8ebfaSGarrett D'Amore 
208*ffb8ebfaSGarrett D'Amore 	/* Account for trailing blank. */
20932a712daSGarrett D'Amore 	width++;
210*ffb8ebfaSGarrett D'Amore 
21132a712daSGarrett D'Amore 	return(width);
21232a712daSGarrett D'Amore }
21332a712daSGarrett D'Amore 
21432a712daSGarrett D'Amore /*
21532a712daSGarrett D'Amore  * Rules inside the table can be single or double
21632a712daSGarrett D'Amore  * and have crossings with vertical rules marked with pluses.
21732a712daSGarrett D'Amore  */
21832a712daSGarrett D'Amore static void
tbl_hrule(struct termp * tp,const struct tbl_span * sp)21932a712daSGarrett D'Amore tbl_hrule(struct termp *tp, const struct tbl_span *sp)
22032a712daSGarrett D'Amore {
22132a712daSGarrett D'Amore 	const struct tbl_head *hp;
22232a712daSGarrett D'Amore 	char		 c;
22332a712daSGarrett D'Amore 
22432a712daSGarrett D'Amore 	c = '-';
22532a712daSGarrett D'Amore 	if (TBL_SPAN_DHORIZ == sp->pos)
22632a712daSGarrett D'Amore 		c = '=';
22732a712daSGarrett D'Amore 
228*ffb8ebfaSGarrett D'Amore 	for (hp = sp->head; hp; hp = hp->next) {
229*ffb8ebfaSGarrett D'Amore 		if (hp->prev && hp->vert)
230*ffb8ebfaSGarrett D'Amore 			tbl_char(tp, '+', hp->vert);
231*ffb8ebfaSGarrett D'Amore 		tbl_char(tp, c, tbl_rulewidth(tp, hp));
232*ffb8ebfaSGarrett D'Amore 	}
23332a712daSGarrett D'Amore }
23432a712daSGarrett D'Amore 
23532a712daSGarrett D'Amore /*
23632a712daSGarrett D'Amore  * Rules above and below the table are always single
23732a712daSGarrett D'Amore  * and have an additional plus at the beginning and end.
23832a712daSGarrett D'Amore  * For double frames, this function is called twice,
23932a712daSGarrett D'Amore  * and the outer one does not have crossings.
24032a712daSGarrett D'Amore  */
24132a712daSGarrett D'Amore static void
tbl_hframe(struct termp * tp,const struct tbl_span * sp,int outer)24232a712daSGarrett D'Amore tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer)
24332a712daSGarrett D'Amore {
24432a712daSGarrett D'Amore 	const struct tbl_head *hp;
24532a712daSGarrett D'Amore 
24632a712daSGarrett D'Amore 	term_word(tp, "+");
247*ffb8ebfaSGarrett D'Amore 	for (hp = sp->head; hp; hp = hp->next) {
248*ffb8ebfaSGarrett D'Amore 		if (hp->prev && hp->vert)
249*ffb8ebfaSGarrett D'Amore 			tbl_char(tp, (outer ? '-' : '+'), hp->vert);
250*ffb8ebfaSGarrett D'Amore 		tbl_char(tp, '-', tbl_rulewidth(tp, hp));
251*ffb8ebfaSGarrett D'Amore 	}
25232a712daSGarrett D'Amore 	term_word(tp, "+");
25332a712daSGarrett D'Amore 	term_flushln(tp);
25432a712daSGarrett D'Amore }
25532a712daSGarrett D'Amore 
25632a712daSGarrett D'Amore static void
tbl_data(struct termp * tp,const struct tbl_opts * opts,const struct tbl_dat * dp,const struct roffcol * col)257*ffb8ebfaSGarrett D'Amore tbl_data(struct termp *tp, const struct tbl_opts *opts,
25832a712daSGarrett D'Amore 		const struct tbl_dat *dp,
25932a712daSGarrett D'Amore 		const struct roffcol *col)
26032a712daSGarrett D'Amore {
26132a712daSGarrett D'Amore 
26232a712daSGarrett D'Amore 	if (NULL == dp) {
26332a712daSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width);
26432a712daSGarrett D'Amore 		return;
26532a712daSGarrett D'Amore 	}
26632a712daSGarrett D'Amore 	assert(dp->layout);
26732a712daSGarrett D'Amore 
26832a712daSGarrett D'Amore 	switch (dp->pos) {
26932a712daSGarrett D'Amore 	case (TBL_DATA_NONE):
27032a712daSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width);
27132a712daSGarrett D'Amore 		return;
27232a712daSGarrett D'Amore 	case (TBL_DATA_HORIZ):
27332a712daSGarrett D'Amore 		/* FALLTHROUGH */
27432a712daSGarrett D'Amore 	case (TBL_DATA_NHORIZ):
27532a712daSGarrett D'Amore 		tbl_char(tp, '-', col->width);
27632a712daSGarrett D'Amore 		return;
27732a712daSGarrett D'Amore 	case (TBL_DATA_NDHORIZ):
27832a712daSGarrett D'Amore 		/* FALLTHROUGH */
27932a712daSGarrett D'Amore 	case (TBL_DATA_DHORIZ):
28032a712daSGarrett D'Amore 		tbl_char(tp, '=', col->width);
28132a712daSGarrett D'Amore 		return;
28232a712daSGarrett D'Amore 	default:
28332a712daSGarrett D'Amore 		break;
28432a712daSGarrett D'Amore 	}
28532a712daSGarrett D'Amore 
28632a712daSGarrett D'Amore 	switch (dp->layout->pos) {
28732a712daSGarrett D'Amore 	case (TBL_CELL_HORIZ):
28832a712daSGarrett D'Amore 		tbl_char(tp, '-', col->width);
28932a712daSGarrett D'Amore 		break;
29032a712daSGarrett D'Amore 	case (TBL_CELL_DHORIZ):
29132a712daSGarrett D'Amore 		tbl_char(tp, '=', col->width);
29232a712daSGarrett D'Amore 		break;
29332a712daSGarrett D'Amore 	case (TBL_CELL_LONG):
29432a712daSGarrett D'Amore 		/* FALLTHROUGH */
29532a712daSGarrett D'Amore 	case (TBL_CELL_CENTRE):
29632a712daSGarrett D'Amore 		/* FALLTHROUGH */
29732a712daSGarrett D'Amore 	case (TBL_CELL_LEFT):
29832a712daSGarrett D'Amore 		/* FALLTHROUGH */
29932a712daSGarrett D'Amore 	case (TBL_CELL_RIGHT):
30032a712daSGarrett D'Amore 		tbl_literal(tp, dp, col);
30132a712daSGarrett D'Amore 		break;
30232a712daSGarrett D'Amore 	case (TBL_CELL_NUMBER):
303*ffb8ebfaSGarrett D'Amore 		tbl_number(tp, opts, dp, col);
30432a712daSGarrett D'Amore 		break;
30532a712daSGarrett D'Amore 	case (TBL_CELL_DOWN):
30632a712daSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width);
30732a712daSGarrett D'Amore 		break;
30832a712daSGarrett D'Amore 	default:
30932a712daSGarrett D'Amore 		abort();
31032a712daSGarrett D'Amore 		/* NOTREACHED */
31132a712daSGarrett D'Amore 	}
31232a712daSGarrett D'Amore }
31332a712daSGarrett D'Amore 
31432a712daSGarrett D'Amore static void
tbl_vrule(struct termp * tp,const struct tbl_head * hp)31532a712daSGarrett D'Amore tbl_vrule(struct termp *tp, const struct tbl_head *hp)
31632a712daSGarrett D'Amore {
31732a712daSGarrett D'Amore 
318*ffb8ebfaSGarrett D'Amore 	tbl_char(tp, ASCII_NBRSP, 1);
319*ffb8ebfaSGarrett D'Amore 	if (0 < hp->vert)
320*ffb8ebfaSGarrett D'Amore 		tbl_char(tp, '|', hp->vert);
321*ffb8ebfaSGarrett D'Amore 	if (2 > hp->vert)
322*ffb8ebfaSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, 2 - hp->vert);
32332a712daSGarrett D'Amore }
32432a712daSGarrett D'Amore 
32532a712daSGarrett D'Amore static void
tbl_char(struct termp * tp,char c,size_t len)32632a712daSGarrett D'Amore tbl_char(struct termp *tp, char c, size_t len)
32732a712daSGarrett D'Amore {
32832a712daSGarrett D'Amore 	size_t		i, sz;
32932a712daSGarrett D'Amore 	char		cp[2];
33032a712daSGarrett D'Amore 
33132a712daSGarrett D'Amore 	cp[0] = c;
33232a712daSGarrett D'Amore 	cp[1] = '\0';
33332a712daSGarrett D'Amore 
33432a712daSGarrett D'Amore 	sz = term_strlen(tp, cp);
33532a712daSGarrett D'Amore 
33632a712daSGarrett D'Amore 	for (i = 0; i < len; i += sz)
33732a712daSGarrett D'Amore 		term_word(tp, cp);
33832a712daSGarrett D'Amore }
33932a712daSGarrett D'Amore 
34032a712daSGarrett D'Amore static void
tbl_literal(struct termp * tp,const struct tbl_dat * dp,const struct roffcol * col)34132a712daSGarrett D'Amore tbl_literal(struct termp *tp, const struct tbl_dat *dp,
34232a712daSGarrett D'Amore 		const struct roffcol *col)
34332a712daSGarrett D'Amore {
344*ffb8ebfaSGarrett D'Amore 	struct tbl_head		*hp;
345*ffb8ebfaSGarrett D'Amore 	size_t			 width, len, padl, padr;
346*ffb8ebfaSGarrett D'Amore 	int			 spans;
34732a712daSGarrett D'Amore 
34832a712daSGarrett D'Amore 	assert(dp->string);
34932a712daSGarrett D'Amore 	len = term_strlen(tp, dp->string);
350*ffb8ebfaSGarrett D'Amore 
351*ffb8ebfaSGarrett D'Amore 	hp = dp->layout->head->next;
352*ffb8ebfaSGarrett D'Amore 	width = col->width;
353*ffb8ebfaSGarrett D'Amore 	for (spans = dp->spans; spans--; hp = hp->next)
354*ffb8ebfaSGarrett D'Amore 		width += tp->tbl.cols[hp->ident].width + 3;
355*ffb8ebfaSGarrett D'Amore 
356*ffb8ebfaSGarrett D'Amore 	padr = width > len ? width - len : 0;
35732a712daSGarrett D'Amore 	padl = 0;
35832a712daSGarrett D'Amore 
35932a712daSGarrett D'Amore 	switch (dp->layout->pos) {
36032a712daSGarrett D'Amore 	case (TBL_CELL_LONG):
36132a712daSGarrett D'Amore 		padl = term_len(tp, 1);
36232a712daSGarrett D'Amore 		padr = padr > padl ? padr - padl : 0;
36332a712daSGarrett D'Amore 		break;
36432a712daSGarrett D'Amore 	case (TBL_CELL_CENTRE):
36532a712daSGarrett D'Amore 		if (2 > padr)
36632a712daSGarrett D'Amore 			break;
36732a712daSGarrett D'Amore 		padl = padr / 2;
36832a712daSGarrett D'Amore 		padr -= padl;
36932a712daSGarrett D'Amore 		break;
37032a712daSGarrett D'Amore 	case (TBL_CELL_RIGHT):
37132a712daSGarrett D'Amore 		padl = padr;
37232a712daSGarrett D'Amore 		padr = 0;
37332a712daSGarrett D'Amore 		break;
37432a712daSGarrett D'Amore 	default:
37532a712daSGarrett D'Amore 		break;
37632a712daSGarrett D'Amore 	}
37732a712daSGarrett D'Amore 
37832a712daSGarrett D'Amore 	tbl_char(tp, ASCII_NBRSP, padl);
37932a712daSGarrett D'Amore 	term_word(tp, dp->string);
38032a712daSGarrett D'Amore 	tbl_char(tp, ASCII_NBRSP, padr);
38132a712daSGarrett D'Amore }
38232a712daSGarrett D'Amore 
38332a712daSGarrett D'Amore static void
tbl_number(struct termp * tp,const struct tbl_opts * opts,const struct tbl_dat * dp,const struct roffcol * col)384*ffb8ebfaSGarrett D'Amore tbl_number(struct termp *tp, const struct tbl_opts *opts,
38532a712daSGarrett D'Amore 		const struct tbl_dat *dp,
38632a712daSGarrett D'Amore 		const struct roffcol *col)
38732a712daSGarrett D'Amore {
38832a712daSGarrett D'Amore 	char		*cp;
38932a712daSGarrett D'Amore 	char		 buf[2];
39032a712daSGarrett D'Amore 	size_t		 sz, psz, ssz, d, padl;
39132a712daSGarrett D'Amore 	int		 i;
39232a712daSGarrett D'Amore 
39332a712daSGarrett D'Amore 	/*
39432a712daSGarrett D'Amore 	 * See calc_data_number().  Left-pad by taking the offset of our
39532a712daSGarrett D'Amore 	 * and the maximum decimal; right-pad by the remaining amount.
39632a712daSGarrett D'Amore 	 */
39732a712daSGarrett D'Amore 
39832a712daSGarrett D'Amore 	assert(dp->string);
39932a712daSGarrett D'Amore 
40032a712daSGarrett D'Amore 	sz = term_strlen(tp, dp->string);
40132a712daSGarrett D'Amore 
402*ffb8ebfaSGarrett D'Amore 	buf[0] = opts->decimal;
40332a712daSGarrett D'Amore 	buf[1] = '\0';
40432a712daSGarrett D'Amore 
40532a712daSGarrett D'Amore 	psz = term_strlen(tp, buf);
40632a712daSGarrett D'Amore 
407*ffb8ebfaSGarrett D'Amore 	if (NULL != (cp = strrchr(dp->string, opts->decimal))) {
40832a712daSGarrett D'Amore 		buf[1] = '\0';
40932a712daSGarrett D'Amore 		for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
41032a712daSGarrett D'Amore 			buf[0] = dp->string[i];
41132a712daSGarrett D'Amore 			ssz += term_strlen(tp, buf);
41232a712daSGarrett D'Amore 		}
41332a712daSGarrett D'Amore 		d = ssz + psz;
41432a712daSGarrett D'Amore 	} else
41532a712daSGarrett D'Amore 		d = sz + psz;
41632a712daSGarrett D'Amore 
41732a712daSGarrett D'Amore 	padl = col->decimal - d;
41832a712daSGarrett D'Amore 
41932a712daSGarrett D'Amore 	tbl_char(tp, ASCII_NBRSP, padl);
42032a712daSGarrett D'Amore 	term_word(tp, dp->string);
42132a712daSGarrett D'Amore 	if (col->width > sz + padl)
42232a712daSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
42332a712daSGarrett D'Amore }
42432a712daSGarrett D'Amore 
425