xref: /titanic_53/usr/src/cmd/mandoc/tbl_term.c (revision 95c635efb7c3b86efc493e0447eaec7aecca3f0f)
1*95c635efSGarrett D'Amore /*	$Id: tbl_term.c,v 1.21 2011/09/20 23:05:49 schwarze Exp $ */
2*95c635efSGarrett D'Amore /*
3*95c635efSGarrett D'Amore  * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*95c635efSGarrett D'Amore  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
5*95c635efSGarrett D'Amore  *
6*95c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
7*95c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
8*95c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
9*95c635efSGarrett D'Amore  *
10*95c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*95c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*95c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*95c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*95c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*95c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*95c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*95c635efSGarrett D'Amore  */
18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
19*95c635efSGarrett D'Amore #include "config.h"
20*95c635efSGarrett D'Amore #endif
21*95c635efSGarrett D'Amore 
22*95c635efSGarrett D'Amore #include <assert.h>
23*95c635efSGarrett D'Amore #include <stdio.h>
24*95c635efSGarrett D'Amore #include <stdlib.h>
25*95c635efSGarrett D'Amore #include <string.h>
26*95c635efSGarrett D'Amore 
27*95c635efSGarrett D'Amore #include "mandoc.h"
28*95c635efSGarrett D'Amore #include "out.h"
29*95c635efSGarrett D'Amore #include "term.h"
30*95c635efSGarrett D'Amore 
31*95c635efSGarrett D'Amore static	size_t	term_tbl_len(size_t, void *);
32*95c635efSGarrett D'Amore static	size_t	term_tbl_strlen(const char *, void *);
33*95c635efSGarrett D'Amore static	void	tbl_char(struct termp *, char, size_t);
34*95c635efSGarrett D'Amore static	void	tbl_data(struct termp *, const struct tbl *,
35*95c635efSGarrett D'Amore 			const struct tbl_dat *,
36*95c635efSGarrett D'Amore 			const struct roffcol *);
37*95c635efSGarrett D'Amore static	size_t	tbl_rulewidth(struct termp *, const struct tbl_head *);
38*95c635efSGarrett D'Amore static	void	tbl_hframe(struct termp *, const struct tbl_span *, int);
39*95c635efSGarrett D'Amore static	void	tbl_literal(struct termp *, const struct tbl_dat *,
40*95c635efSGarrett D'Amore 			const struct roffcol *);
41*95c635efSGarrett D'Amore static	void	tbl_number(struct termp *, const struct tbl *,
42*95c635efSGarrett D'Amore 			const struct tbl_dat *,
43*95c635efSGarrett D'Amore 			const struct roffcol *);
44*95c635efSGarrett D'Amore static	void	tbl_hrule(struct termp *, const struct tbl_span *);
45*95c635efSGarrett D'Amore static	void	tbl_vrule(struct termp *, const struct tbl_head *);
46*95c635efSGarrett D'Amore 
47*95c635efSGarrett D'Amore 
48*95c635efSGarrett D'Amore static size_t
49*95c635efSGarrett D'Amore term_tbl_strlen(const char *p, void *arg)
50*95c635efSGarrett D'Amore {
51*95c635efSGarrett D'Amore 
52*95c635efSGarrett D'Amore 	return(term_strlen((const struct termp *)arg, p));
53*95c635efSGarrett D'Amore }
54*95c635efSGarrett D'Amore 
55*95c635efSGarrett D'Amore static size_t
56*95c635efSGarrett D'Amore term_tbl_len(size_t sz, void *arg)
57*95c635efSGarrett D'Amore {
58*95c635efSGarrett D'Amore 
59*95c635efSGarrett D'Amore 	return(term_len((const struct termp *)arg, sz));
60*95c635efSGarrett D'Amore }
61*95c635efSGarrett D'Amore 
62*95c635efSGarrett D'Amore void
63*95c635efSGarrett D'Amore term_tbl(struct termp *tp, const struct tbl_span *sp)
64*95c635efSGarrett D'Amore {
65*95c635efSGarrett D'Amore 	const struct tbl_head	*hp;
66*95c635efSGarrett D'Amore 	const struct tbl_dat	*dp;
67*95c635efSGarrett D'Amore 	struct roffcol		*col;
68*95c635efSGarrett D'Amore 	int			 spans;
69*95c635efSGarrett D'Amore 	size_t		   	 rmargin, maxrmargin;
70*95c635efSGarrett D'Amore 
71*95c635efSGarrett D'Amore 	rmargin = tp->rmargin;
72*95c635efSGarrett D'Amore 	maxrmargin = tp->maxrmargin;
73*95c635efSGarrett D'Amore 
74*95c635efSGarrett D'Amore 	tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
75*95c635efSGarrett D'Amore 
76*95c635efSGarrett D'Amore 	/* Inhibit printing of spaces: we do padding ourselves. */
77*95c635efSGarrett D'Amore 
78*95c635efSGarrett D'Amore 	tp->flags |= TERMP_NONOSPACE;
79*95c635efSGarrett D'Amore 	tp->flags |= TERMP_NOSPACE;
80*95c635efSGarrett D'Amore 
81*95c635efSGarrett D'Amore 	/*
82*95c635efSGarrett D'Amore 	 * The first time we're invoked for a given table block,
83*95c635efSGarrett D'Amore 	 * calculate the table widths and decimal positions.
84*95c635efSGarrett D'Amore 	 */
85*95c635efSGarrett D'Amore 
86*95c635efSGarrett D'Amore 	if (TBL_SPAN_FIRST & sp->flags) {
87*95c635efSGarrett D'Amore 		term_flushln(tp);
88*95c635efSGarrett D'Amore 
89*95c635efSGarrett D'Amore 		tp->tbl.len = term_tbl_len;
90*95c635efSGarrett D'Amore 		tp->tbl.slen = term_tbl_strlen;
91*95c635efSGarrett D'Amore 		tp->tbl.arg = tp;
92*95c635efSGarrett D'Amore 
93*95c635efSGarrett D'Amore 		tblcalc(&tp->tbl, sp);
94*95c635efSGarrett D'Amore 	}
95*95c635efSGarrett D'Amore 
96*95c635efSGarrett D'Amore 	/* Horizontal frame at the start of boxed tables. */
97*95c635efSGarrett D'Amore 
98*95c635efSGarrett D'Amore 	if (TBL_SPAN_FIRST & sp->flags) {
99*95c635efSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->tbl->opts)
100*95c635efSGarrett D'Amore 			tbl_hframe(tp, sp, 1);
101*95c635efSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->tbl->opts ||
102*95c635efSGarrett D'Amore 		    TBL_OPT_BOX  & sp->tbl->opts)
103*95c635efSGarrett D'Amore 			tbl_hframe(tp, sp, 0);
104*95c635efSGarrett D'Amore 	}
105*95c635efSGarrett D'Amore 
106*95c635efSGarrett D'Amore 	/* Vertical frame at the start of each row. */
107*95c635efSGarrett D'Amore 
108*95c635efSGarrett D'Amore 	if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts)
109*95c635efSGarrett D'Amore 		term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
110*95c635efSGarrett D'Amore 			TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
111*95c635efSGarrett D'Amore 
112*95c635efSGarrett D'Amore 	/*
113*95c635efSGarrett D'Amore 	 * Now print the actual data itself depending on the span type.
114*95c635efSGarrett D'Amore 	 * Spanner spans get a horizontal rule; data spanners have their
115*95c635efSGarrett D'Amore 	 * data printed by matching data to header.
116*95c635efSGarrett D'Amore 	 */
117*95c635efSGarrett D'Amore 
118*95c635efSGarrett D'Amore 	switch (sp->pos) {
119*95c635efSGarrett D'Amore 	case (TBL_SPAN_HORIZ):
120*95c635efSGarrett D'Amore 		/* FALLTHROUGH */
121*95c635efSGarrett D'Amore 	case (TBL_SPAN_DHORIZ):
122*95c635efSGarrett D'Amore 		tbl_hrule(tp, sp);
123*95c635efSGarrett D'Amore 		break;
124*95c635efSGarrett D'Amore 	case (TBL_SPAN_DATA):
125*95c635efSGarrett D'Amore 		/* Iterate over template headers. */
126*95c635efSGarrett D'Amore 		dp = sp->first;
127*95c635efSGarrett D'Amore 		spans = 0;
128*95c635efSGarrett D'Amore 		for (hp = sp->head; hp; hp = hp->next) {
129*95c635efSGarrett D'Amore 			/*
130*95c635efSGarrett D'Amore 			 * If the current data header is invoked during
131*95c635efSGarrett D'Amore 			 * a spanner ("spans" > 0), don't emit anything
132*95c635efSGarrett D'Amore 			 * at all.
133*95c635efSGarrett D'Amore 			 */
134*95c635efSGarrett D'Amore 			switch (hp->pos) {
135*95c635efSGarrett D'Amore 			case (TBL_HEAD_VERT):
136*95c635efSGarrett D'Amore 				/* FALLTHROUGH */
137*95c635efSGarrett D'Amore 			case (TBL_HEAD_DVERT):
138*95c635efSGarrett D'Amore 				if (spans <= 0)
139*95c635efSGarrett D'Amore 					tbl_vrule(tp, hp);
140*95c635efSGarrett D'Amore 				continue;
141*95c635efSGarrett D'Amore 			case (TBL_HEAD_DATA):
142*95c635efSGarrett D'Amore 				break;
143*95c635efSGarrett D'Amore 			}
144*95c635efSGarrett D'Amore 
145*95c635efSGarrett D'Amore 			if (--spans >= 0)
146*95c635efSGarrett D'Amore 				continue;
147*95c635efSGarrett D'Amore 
148*95c635efSGarrett D'Amore 			/*
149*95c635efSGarrett D'Amore 			 * All cells get a leading blank, except the
150*95c635efSGarrett D'Amore 			 * first one and those after double rulers.
151*95c635efSGarrett D'Amore 			 */
152*95c635efSGarrett D'Amore 
153*95c635efSGarrett D'Amore 			if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos)
154*95c635efSGarrett D'Amore 				tbl_char(tp, ASCII_NBRSP, 1);
155*95c635efSGarrett D'Amore 
156*95c635efSGarrett D'Amore 			col = &tp->tbl.cols[hp->ident];
157*95c635efSGarrett D'Amore 			tbl_data(tp, sp->tbl, dp, col);
158*95c635efSGarrett D'Amore 
159*95c635efSGarrett D'Amore 			/* No trailing blanks. */
160*95c635efSGarrett D'Amore 
161*95c635efSGarrett D'Amore 			if (NULL == hp->next)
162*95c635efSGarrett D'Amore 				break;
163*95c635efSGarrett D'Amore 
164*95c635efSGarrett D'Amore 			/*
165*95c635efSGarrett D'Amore 			 * Add another blank between cells,
166*95c635efSGarrett D'Amore 			 * or two when there is no vertical ruler.
167*95c635efSGarrett D'Amore 			 */
168*95c635efSGarrett D'Amore 
169*95c635efSGarrett D'Amore 			tbl_char(tp, ASCII_NBRSP,
170*95c635efSGarrett D'Amore 			    TBL_HEAD_VERT  == hp->next->pos ||
171*95c635efSGarrett D'Amore 			    TBL_HEAD_DVERT == hp->next->pos ? 1 : 2);
172*95c635efSGarrett D'Amore 
173*95c635efSGarrett D'Amore 			/*
174*95c635efSGarrett D'Amore 			 * Go to the next data cell and assign the
175*95c635efSGarrett D'Amore 			 * number of subsequent spans, if applicable.
176*95c635efSGarrett D'Amore 			 */
177*95c635efSGarrett D'Amore 
178*95c635efSGarrett D'Amore 			if (dp) {
179*95c635efSGarrett D'Amore 				spans = dp->spans;
180*95c635efSGarrett D'Amore 				dp = dp->next;
181*95c635efSGarrett D'Amore 			}
182*95c635efSGarrett D'Amore 		}
183*95c635efSGarrett D'Amore 		break;
184*95c635efSGarrett D'Amore 	}
185*95c635efSGarrett D'Amore 
186*95c635efSGarrett D'Amore 	/* Vertical frame at the end of each row. */
187*95c635efSGarrett D'Amore 
188*95c635efSGarrett D'Amore 	if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts)
189*95c635efSGarrett D'Amore 		term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
190*95c635efSGarrett D'Amore 			TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
191*95c635efSGarrett D'Amore 	term_flushln(tp);
192*95c635efSGarrett D'Amore 
193*95c635efSGarrett D'Amore 	/*
194*95c635efSGarrett D'Amore 	 * If we're the last row, clean up after ourselves: clear the
195*95c635efSGarrett D'Amore 	 * existing table configuration and set it to NULL.
196*95c635efSGarrett D'Amore 	 */
197*95c635efSGarrett D'Amore 
198*95c635efSGarrett D'Amore 	if (TBL_SPAN_LAST & sp->flags) {
199*95c635efSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->tbl->opts ||
200*95c635efSGarrett D'Amore 		    TBL_OPT_BOX  & sp->tbl->opts)
201*95c635efSGarrett D'Amore 			tbl_hframe(tp, sp, 0);
202*95c635efSGarrett D'Amore 		if (TBL_OPT_DBOX & sp->tbl->opts)
203*95c635efSGarrett D'Amore 			tbl_hframe(tp, sp, 1);
204*95c635efSGarrett D'Amore 		assert(tp->tbl.cols);
205*95c635efSGarrett D'Amore 		free(tp->tbl.cols);
206*95c635efSGarrett D'Amore 		tp->tbl.cols = NULL;
207*95c635efSGarrett D'Amore 	}
208*95c635efSGarrett D'Amore 
209*95c635efSGarrett D'Amore 	tp->flags &= ~TERMP_NONOSPACE;
210*95c635efSGarrett D'Amore 	tp->rmargin = rmargin;
211*95c635efSGarrett D'Amore 	tp->maxrmargin = maxrmargin;
212*95c635efSGarrett D'Amore 
213*95c635efSGarrett D'Amore }
214*95c635efSGarrett D'Amore 
215*95c635efSGarrett D'Amore /*
216*95c635efSGarrett D'Amore  * Horizontal rules extend across the entire table.
217*95c635efSGarrett D'Amore  * Calculate the width by iterating over columns.
218*95c635efSGarrett D'Amore  */
219*95c635efSGarrett D'Amore static size_t
220*95c635efSGarrett D'Amore tbl_rulewidth(struct termp *tp, const struct tbl_head *hp)
221*95c635efSGarrett D'Amore {
222*95c635efSGarrett D'Amore 	size_t		 width;
223*95c635efSGarrett D'Amore 
224*95c635efSGarrett D'Amore 	width = tp->tbl.cols[hp->ident].width;
225*95c635efSGarrett D'Amore 	if (TBL_HEAD_DATA == hp->pos) {
226*95c635efSGarrett D'Amore 		/* Account for leading blanks. */
227*95c635efSGarrett D'Amore 		if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos)
228*95c635efSGarrett D'Amore 			width++;
229*95c635efSGarrett D'Amore 		/* Account for trailing blanks. */
230*95c635efSGarrett D'Amore 		width++;
231*95c635efSGarrett D'Amore 		if (hp->next &&
232*95c635efSGarrett D'Amore 		    TBL_HEAD_VERT  != hp->next->pos &&
233*95c635efSGarrett D'Amore 		    TBL_HEAD_DVERT != hp->next->pos)
234*95c635efSGarrett D'Amore 			width++;
235*95c635efSGarrett D'Amore 	}
236*95c635efSGarrett D'Amore 	return(width);
237*95c635efSGarrett D'Amore }
238*95c635efSGarrett D'Amore 
239*95c635efSGarrett D'Amore /*
240*95c635efSGarrett D'Amore  * Rules inside the table can be single or double
241*95c635efSGarrett D'Amore  * and have crossings with vertical rules marked with pluses.
242*95c635efSGarrett D'Amore  */
243*95c635efSGarrett D'Amore static void
244*95c635efSGarrett D'Amore tbl_hrule(struct termp *tp, const struct tbl_span *sp)
245*95c635efSGarrett D'Amore {
246*95c635efSGarrett D'Amore 	const struct tbl_head *hp;
247*95c635efSGarrett D'Amore 	char		 c;
248*95c635efSGarrett D'Amore 
249*95c635efSGarrett D'Amore 	c = '-';
250*95c635efSGarrett D'Amore 	if (TBL_SPAN_DHORIZ == sp->pos)
251*95c635efSGarrett D'Amore 		c = '=';
252*95c635efSGarrett D'Amore 
253*95c635efSGarrett D'Amore 	for (hp = sp->head; hp; hp = hp->next)
254*95c635efSGarrett D'Amore 		tbl_char(tp,
255*95c635efSGarrett D'Amore 		    TBL_HEAD_DATA == hp->pos ? c : '+',
256*95c635efSGarrett D'Amore 		    tbl_rulewidth(tp, hp));
257*95c635efSGarrett D'Amore }
258*95c635efSGarrett D'Amore 
259*95c635efSGarrett D'Amore /*
260*95c635efSGarrett D'Amore  * Rules above and below the table are always single
261*95c635efSGarrett D'Amore  * and have an additional plus at the beginning and end.
262*95c635efSGarrett D'Amore  * For double frames, this function is called twice,
263*95c635efSGarrett D'Amore  * and the outer one does not have crossings.
264*95c635efSGarrett D'Amore  */
265*95c635efSGarrett D'Amore static void
266*95c635efSGarrett D'Amore tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer)
267*95c635efSGarrett D'Amore {
268*95c635efSGarrett D'Amore 	const struct tbl_head *hp;
269*95c635efSGarrett D'Amore 
270*95c635efSGarrett D'Amore 	term_word(tp, "+");
271*95c635efSGarrett D'Amore 	for (hp = sp->head; hp; hp = hp->next)
272*95c635efSGarrett D'Amore 		tbl_char(tp,
273*95c635efSGarrett D'Amore 		    outer || TBL_HEAD_DATA == hp->pos ? '-' : '+',
274*95c635efSGarrett D'Amore 		    tbl_rulewidth(tp, hp));
275*95c635efSGarrett D'Amore 	term_word(tp, "+");
276*95c635efSGarrett D'Amore 	term_flushln(tp);
277*95c635efSGarrett D'Amore }
278*95c635efSGarrett D'Amore 
279*95c635efSGarrett D'Amore static void
280*95c635efSGarrett D'Amore tbl_data(struct termp *tp, const struct tbl *tbl,
281*95c635efSGarrett D'Amore 		const struct tbl_dat *dp,
282*95c635efSGarrett D'Amore 		const struct roffcol *col)
283*95c635efSGarrett D'Amore {
284*95c635efSGarrett D'Amore 
285*95c635efSGarrett D'Amore 	if (NULL == dp) {
286*95c635efSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width);
287*95c635efSGarrett D'Amore 		return;
288*95c635efSGarrett D'Amore 	}
289*95c635efSGarrett D'Amore 	assert(dp->layout);
290*95c635efSGarrett D'Amore 
291*95c635efSGarrett D'Amore 	switch (dp->pos) {
292*95c635efSGarrett D'Amore 	case (TBL_DATA_NONE):
293*95c635efSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width);
294*95c635efSGarrett D'Amore 		return;
295*95c635efSGarrett D'Amore 	case (TBL_DATA_HORIZ):
296*95c635efSGarrett D'Amore 		/* FALLTHROUGH */
297*95c635efSGarrett D'Amore 	case (TBL_DATA_NHORIZ):
298*95c635efSGarrett D'Amore 		tbl_char(tp, '-', col->width);
299*95c635efSGarrett D'Amore 		return;
300*95c635efSGarrett D'Amore 	case (TBL_DATA_NDHORIZ):
301*95c635efSGarrett D'Amore 		/* FALLTHROUGH */
302*95c635efSGarrett D'Amore 	case (TBL_DATA_DHORIZ):
303*95c635efSGarrett D'Amore 		tbl_char(tp, '=', col->width);
304*95c635efSGarrett D'Amore 		return;
305*95c635efSGarrett D'Amore 	default:
306*95c635efSGarrett D'Amore 		break;
307*95c635efSGarrett D'Amore 	}
308*95c635efSGarrett D'Amore 
309*95c635efSGarrett D'Amore 	switch (dp->layout->pos) {
310*95c635efSGarrett D'Amore 	case (TBL_CELL_HORIZ):
311*95c635efSGarrett D'Amore 		tbl_char(tp, '-', col->width);
312*95c635efSGarrett D'Amore 		break;
313*95c635efSGarrett D'Amore 	case (TBL_CELL_DHORIZ):
314*95c635efSGarrett D'Amore 		tbl_char(tp, '=', col->width);
315*95c635efSGarrett D'Amore 		break;
316*95c635efSGarrett D'Amore 	case (TBL_CELL_LONG):
317*95c635efSGarrett D'Amore 		/* FALLTHROUGH */
318*95c635efSGarrett D'Amore 	case (TBL_CELL_CENTRE):
319*95c635efSGarrett D'Amore 		/* FALLTHROUGH */
320*95c635efSGarrett D'Amore 	case (TBL_CELL_LEFT):
321*95c635efSGarrett D'Amore 		/* FALLTHROUGH */
322*95c635efSGarrett D'Amore 	case (TBL_CELL_RIGHT):
323*95c635efSGarrett D'Amore 		tbl_literal(tp, dp, col);
324*95c635efSGarrett D'Amore 		break;
325*95c635efSGarrett D'Amore 	case (TBL_CELL_NUMBER):
326*95c635efSGarrett D'Amore 		tbl_number(tp, tbl, dp, col);
327*95c635efSGarrett D'Amore 		break;
328*95c635efSGarrett D'Amore 	case (TBL_CELL_DOWN):
329*95c635efSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width);
330*95c635efSGarrett D'Amore 		break;
331*95c635efSGarrett D'Amore 	default:
332*95c635efSGarrett D'Amore 		abort();
333*95c635efSGarrett D'Amore 		/* NOTREACHED */
334*95c635efSGarrett D'Amore 	}
335*95c635efSGarrett D'Amore }
336*95c635efSGarrett D'Amore 
337*95c635efSGarrett D'Amore static void
338*95c635efSGarrett D'Amore tbl_vrule(struct termp *tp, const struct tbl_head *hp)
339*95c635efSGarrett D'Amore {
340*95c635efSGarrett D'Amore 
341*95c635efSGarrett D'Amore 	switch (hp->pos) {
342*95c635efSGarrett D'Amore 	case (TBL_HEAD_VERT):
343*95c635efSGarrett D'Amore 		term_word(tp, "|");
344*95c635efSGarrett D'Amore 		break;
345*95c635efSGarrett D'Amore 	case (TBL_HEAD_DVERT):
346*95c635efSGarrett D'Amore 		term_word(tp, "||");
347*95c635efSGarrett D'Amore 		break;
348*95c635efSGarrett D'Amore 	default:
349*95c635efSGarrett D'Amore 		break;
350*95c635efSGarrett D'Amore 	}
351*95c635efSGarrett D'Amore }
352*95c635efSGarrett D'Amore 
353*95c635efSGarrett D'Amore static void
354*95c635efSGarrett D'Amore tbl_char(struct termp *tp, char c, size_t len)
355*95c635efSGarrett D'Amore {
356*95c635efSGarrett D'Amore 	size_t		i, sz;
357*95c635efSGarrett D'Amore 	char		cp[2];
358*95c635efSGarrett D'Amore 
359*95c635efSGarrett D'Amore 	cp[0] = c;
360*95c635efSGarrett D'Amore 	cp[1] = '\0';
361*95c635efSGarrett D'Amore 
362*95c635efSGarrett D'Amore 	sz = term_strlen(tp, cp);
363*95c635efSGarrett D'Amore 
364*95c635efSGarrett D'Amore 	for (i = 0; i < len; i += sz)
365*95c635efSGarrett D'Amore 		term_word(tp, cp);
366*95c635efSGarrett D'Amore }
367*95c635efSGarrett D'Amore 
368*95c635efSGarrett D'Amore static void
369*95c635efSGarrett D'Amore tbl_literal(struct termp *tp, const struct tbl_dat *dp,
370*95c635efSGarrett D'Amore 		const struct roffcol *col)
371*95c635efSGarrett D'Amore {
372*95c635efSGarrett D'Amore 	size_t		 len, padl, padr;
373*95c635efSGarrett D'Amore 
374*95c635efSGarrett D'Amore 	assert(dp->string);
375*95c635efSGarrett D'Amore 	len = term_strlen(tp, dp->string);
376*95c635efSGarrett D'Amore 	padr = col->width > len ? col->width - len : 0;
377*95c635efSGarrett D'Amore 	padl = 0;
378*95c635efSGarrett D'Amore 
379*95c635efSGarrett D'Amore 	switch (dp->layout->pos) {
380*95c635efSGarrett D'Amore 	case (TBL_CELL_LONG):
381*95c635efSGarrett D'Amore 		padl = term_len(tp, 1);
382*95c635efSGarrett D'Amore 		padr = padr > padl ? padr - padl : 0;
383*95c635efSGarrett D'Amore 		break;
384*95c635efSGarrett D'Amore 	case (TBL_CELL_CENTRE):
385*95c635efSGarrett D'Amore 		if (2 > padr)
386*95c635efSGarrett D'Amore 			break;
387*95c635efSGarrett D'Amore 		padl = padr / 2;
388*95c635efSGarrett D'Amore 		padr -= padl;
389*95c635efSGarrett D'Amore 		break;
390*95c635efSGarrett D'Amore 	case (TBL_CELL_RIGHT):
391*95c635efSGarrett D'Amore 		padl = padr;
392*95c635efSGarrett D'Amore 		padr = 0;
393*95c635efSGarrett D'Amore 		break;
394*95c635efSGarrett D'Amore 	default:
395*95c635efSGarrett D'Amore 		break;
396*95c635efSGarrett D'Amore 	}
397*95c635efSGarrett D'Amore 
398*95c635efSGarrett D'Amore 	tbl_char(tp, ASCII_NBRSP, padl);
399*95c635efSGarrett D'Amore 	term_word(tp, dp->string);
400*95c635efSGarrett D'Amore 	tbl_char(tp, ASCII_NBRSP, padr);
401*95c635efSGarrett D'Amore }
402*95c635efSGarrett D'Amore 
403*95c635efSGarrett D'Amore static void
404*95c635efSGarrett D'Amore tbl_number(struct termp *tp, const struct tbl *tbl,
405*95c635efSGarrett D'Amore 		const struct tbl_dat *dp,
406*95c635efSGarrett D'Amore 		const struct roffcol *col)
407*95c635efSGarrett D'Amore {
408*95c635efSGarrett D'Amore 	char		*cp;
409*95c635efSGarrett D'Amore 	char		 buf[2];
410*95c635efSGarrett D'Amore 	size_t		 sz, psz, ssz, d, padl;
411*95c635efSGarrett D'Amore 	int		 i;
412*95c635efSGarrett D'Amore 
413*95c635efSGarrett D'Amore 	/*
414*95c635efSGarrett D'Amore 	 * See calc_data_number().  Left-pad by taking the offset of our
415*95c635efSGarrett D'Amore 	 * and the maximum decimal; right-pad by the remaining amount.
416*95c635efSGarrett D'Amore 	 */
417*95c635efSGarrett D'Amore 
418*95c635efSGarrett D'Amore 	assert(dp->string);
419*95c635efSGarrett D'Amore 
420*95c635efSGarrett D'Amore 	sz = term_strlen(tp, dp->string);
421*95c635efSGarrett D'Amore 
422*95c635efSGarrett D'Amore 	buf[0] = tbl->decimal;
423*95c635efSGarrett D'Amore 	buf[1] = '\0';
424*95c635efSGarrett D'Amore 
425*95c635efSGarrett D'Amore 	psz = term_strlen(tp, buf);
426*95c635efSGarrett D'Amore 
427*95c635efSGarrett D'Amore 	if (NULL != (cp = strrchr(dp->string, tbl->decimal))) {
428*95c635efSGarrett D'Amore 		buf[1] = '\0';
429*95c635efSGarrett D'Amore 		for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
430*95c635efSGarrett D'Amore 			buf[0] = dp->string[i];
431*95c635efSGarrett D'Amore 			ssz += term_strlen(tp, buf);
432*95c635efSGarrett D'Amore 		}
433*95c635efSGarrett D'Amore 		d = ssz + psz;
434*95c635efSGarrett D'Amore 	} else
435*95c635efSGarrett D'Amore 		d = sz + psz;
436*95c635efSGarrett D'Amore 
437*95c635efSGarrett D'Amore 	padl = col->decimal - d;
438*95c635efSGarrett D'Amore 
439*95c635efSGarrett D'Amore 	tbl_char(tp, ASCII_NBRSP, padl);
440*95c635efSGarrett D'Amore 	term_word(tp, dp->string);
441*95c635efSGarrett D'Amore 	if (col->width > sz + padl)
442*95c635efSGarrett D'Amore 		tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
443*95c635efSGarrett D'Amore }
444*95c635efSGarrett D'Amore 
445