GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/tbl_term.c Lines: 334 349 95.7 %
Date: 2017-11-07 Branches: 293 345 84.9 %

Line Branch Exec Source
1
/*	$OpenBSD: tbl_term.c,v 1.45 2017/07/31 16:14:04 schwarze Exp $ */
2
/*
3
 * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4
 * Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
#include <sys/types.h>
19
20
#include <assert.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "mandoc.h"
26
#include "out.h"
27
#include "term.h"
28
29
#define	IS_HORIZ(cp)	((cp)->pos == TBL_CELL_HORIZ || \
30
			 (cp)->pos == TBL_CELL_DHORIZ)
31
32
static	size_t	term_tbl_len(size_t, void *);
33
static	size_t	term_tbl_strlen(const char *, void *);
34
static	size_t	term_tbl_sulen(const struct roffsu *, void *);
35
static	void	tbl_char(struct termp *, char, size_t);
36
static	void	tbl_data(struct termp *, const struct tbl_opts *,
37
			const struct tbl_cell *,
38
			const struct tbl_dat *,
39
			const struct roffcol *);
40
static	void	tbl_literal(struct termp *, const struct tbl_dat *,
41
			const struct roffcol *);
42
static	void	tbl_number(struct termp *, const struct tbl_opts *,
43
			const struct tbl_dat *,
44
			const struct roffcol *);
45
static	void	tbl_hrule(struct termp *, const struct tbl_span *, int);
46
static	void	tbl_word(struct termp *, const struct tbl_dat *);
47
48
49
static size_t
50
term_tbl_sulen(const struct roffsu *su, void *arg)
51
{
52
	int	 i;
53
54
108
	i = term_hen((const struct termp *)arg, su);
55
54
	return i > 0 ? i : 0;
56
}
57
58
static size_t
59
term_tbl_strlen(const char *p, void *arg)
60
{
61
99684
	return term_strlen((const struct termp *)arg, p);
62
}
63
64
static size_t
65
term_tbl_len(size_t sz, void *arg)
66
{
67
8208
	return term_len((const struct termp *)arg, sz);
68
}
69
70
void
71
term_tbl(struct termp *tp, const struct tbl_span *sp)
72
{
73
	const struct tbl_cell	*cp, *cpn, *cpp;
74
	const struct tbl_dat	*dp;
75
	static size_t		 offset;
76
	size_t			 coloff, tsz;
77
	int			 ic, horiz, spans, vert, more;
78
	char			 fc;
79
80
	/* Inhibit printing of spaces: we do padding ourselves. */
81
82
42498
	tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE;
83
84
	/*
85
	 * The first time we're invoked for a given table block,
86
	 * calculate the table widths and decimal positions.
87
	 */
88
89
21249
	if (tp->tbl.cols == NULL) {
90
6588
		tp->tbl.len = term_tbl_len;
91
6588
		tp->tbl.slen = term_tbl_strlen;
92
6588
		tp->tbl.sulen = term_tbl_sulen;
93
6588
		tp->tbl.arg = tp;
94
95
6588
		tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin);
96
97
		/* Tables leak .ta settings to subsequent text. */
98
99
6588
		term_tab_set(tp, NULL);
100
15066
		coloff = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
101
1890
		    sp->opts->lvert;
102
48114
		for (ic = 0; ic < sp->opts->cols; ic++) {
103
17469
			coloff += tp->tbl.cols[ic].width;
104
17469
			term_tab_iset(coloff);
105
17469
			coloff += tp->tbl.cols[ic].spacing;
106
		}
107
108
		/* Center the table as a whole. */
109
110
6588
		offset = tp->tcol->offset;
111
6588
		if (sp->opts->opts & TBL_OPT_CENTRE) {
112
522
			tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
113
162
			    ? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
114
396
			for (ic = 0; ic + 1 < sp->opts->cols; ic++)
115
36
				tsz += tp->tbl.cols[ic].width +
116
18
				    tp->tbl.cols[ic].spacing;
117
180
			if (sp->opts->cols)
118
180
				tsz += tp->tbl.cols[sp->opts->cols - 1].width;
119
180
			if (offset + tsz > tp->tcol->rmargin)
120
54
				tsz -= 1;
121
531
			tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
122
171
			    (offset + tp->tcol->rmargin - tsz) / 2 : 0;
123
180
		}
124
125
		/* Horizontal frame at the start of boxed tables. */
126
127
6588
		if (sp->opts->opts & TBL_OPT_DBOX)
128
2196
			tbl_hrule(tp, sp, 3);
129
6588
		if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
130
4698
			tbl_hrule(tp, sp, 2);
131
	}
132
133
	/* Set up the columns. */
134
135
42498
	tp->flags |= TERMP_MULTICOL;
136
	horiz = 0;
137

42498
	switch (sp->pos) {
138
	case TBL_SPAN_HORIZ:
139
	case TBL_SPAN_DHORIZ:
140
		horiz = 1;
141
234
		term_setcol(tp, 1);
142
234
		break;
143
	case TBL_SPAN_DATA:
144
21015
		term_setcol(tp, sp->opts->cols + 2);
145
21015
		coloff = tp->tcol->offset;
146
147
		/* Set up a column for a left vertical frame. */
148
149

26442
		if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
150
5427
		    sp->opts->lvert)
151
16335
			coloff++;
152
21015
		tp->tcol->rmargin = coloff;
153
154
		/* Set up the data columns. */
155
156
21015
		dp = sp->first;
157
		spans = 0;
158
152316
		for (ic = 0; ic < sp->opts->cols; ic++) {
159
55143
			if (spans == 0) {
160
55008
				tp->tcol++;
161
55008
				tp->tcol->offset = coloff;
162
55008
			}
163
55143
			coloff += tp->tbl.cols[ic].width;
164
55143
			tp->tcol->rmargin = coloff;
165
55143
			if (ic + 1 < sp->opts->cols)
166
34128
				coloff += tp->tbl.cols[ic].spacing;
167
55143
			if (spans) {
168
135
				spans--;
169
135
				continue;
170
			}
171
55008
			if (dp == NULL)
172
				continue;
173
53550
			spans = dp->spans;
174

74538
			if (ic || sp->layout->first->pos != TBL_CELL_SPAN)
175
53550
				dp = dp->next;
176
		}
177
178
		/* Set up a column for a right vertical frame. */
179
180
21015
		tp->tcol++;
181
21015
		tp->tcol->offset = coloff + 1;
182
21015
		tp->tcol->rmargin = tp->maxrmargin;
183
184
		/* Spans may have reduced the number of columns. */
185
186
21015
		tp->lasttcol = tp->tcol - tp->tcols;
187
188
		/* Fill the buffers for all data columns. */
189
190
21015
		tp->tcol = tp->tcols;
191
21015
		cp = cpn = sp->layout->first;
192
21015
		dp = sp->first;
193
		spans = 0;
194
152316
		for (ic = 0; ic < sp->opts->cols; ic++) {
195
55143
			if (cpn != NULL) {
196
				cp = cpn;
197
55143
				cpn = cpn->next;
198
55143
			}
199
55143
			if (spans) {
200
135
				spans--;
201
135
				continue;
202
			}
203
55008
			tp->tcol++;
204
55008
			tp->col = 0;
205
55008
			tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
206
55008
			if (dp == NULL)
207
				continue;
208
53550
			spans = dp->spans;
209
53550
			if (cp->pos != TBL_CELL_SPAN)
210
53550
				dp = dp->next;
211
		}
212
		break;
213
	}
214
215
	do {
216
		/* Print the vertical frame at the start of each row. */
217
218
21384
		tp->tcol = tp->tcols;
219
		fc = '\0';
220

40662
		if (sp->layout->vert ||
221

33957
		    (sp->next != NULL && sp->next->layout->vert &&
222
729
		     sp->next->pos == TBL_SPAN_DATA) ||
223

32688
		    (sp->prev != NULL && sp->prev->layout->vert &&
224

1989
		     (horiz || (IS_HORIZ(sp->layout->first) &&
225

360
		       !IS_HORIZ(sp->prev->layout->first)))) ||
226
19278
		    sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
227

63972
			fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|';
228

5004
		else if (horiz && sp->opts->lvert)
229
9
			fc = '-';
230
21384
		if (fc != '\0') {
231
16416
			(*tp->advance)(tp, tp->tcols->offset);
232
16416
			(*tp->letter)(tp, fc);
233
16416
			tp->viscol = tp->tcol->offset + 1;
234
16416
		}
235
236
		/* Print the data cells. */
237
238
		more = 0;
239
21384
		if (horiz) {
240
234
			tbl_hrule(tp, sp, 0);
241
234
			term_flushln(tp);
242
234
		} else {
243
21150
			cp = sp->layout->first;
244
56790
			cpn = sp->next == NULL ? NULL :
245
14490
			    sp->next->layout->first;
246
56925
			cpp = sp->prev == NULL ? NULL :
247
14625
			    sp->prev->layout->first;
248
21150
			dp = sp->first;
249
			spans = 0;
250
153486
			for (ic = 0; ic < sp->opts->cols; ic++) {
251
252
				/*
253
				 * Figure out whether to print a
254
				 * vertical line after this cell
255
				 * and advance to next layout cell.
256
				 */
257
258
55593
				if (cp != NULL) {
259
55593
					vert = cp->vert;
260
55593
					switch (cp->pos) {
261
					case TBL_CELL_HORIZ:
262
						fc = '-';
263
5535
						break;
264
					case TBL_CELL_DHORIZ:
265
						fc = '=';
266
						break;
267
					default:
268
						fc = ' ';
269
50058
						break;
270
					}
271
				} else {
272
					vert = 0;
273
					fc = ' ';
274
				}
275
55593
				if (cpp != NULL) {
276

40221
					if (vert == 0 &&
277
					    cp != NULL &&
278

65844
					    ((IS_HORIZ(cp) &&
279

6444
					      !IS_HORIZ(cpp)) ||
280
31311
					     (cp->next != NULL &&
281
18333
					      cpp->next != NULL &&
282

34641
					      IS_HORIZ(cp->next) &&
283
4050
					      !IS_HORIZ(cpp->next))))
284
5247
						vert = cpp->vert;
285
38196
					cpp = cpp->next;
286
38196
				}
287

105525
				if (vert == 0 &&
288
49932
				    sp->opts->opts & TBL_OPT_ALLBOX)
289
17991
					vert = 1;
290
55593
				if (cpn != NULL) {
291
37800
					if (vert == 0)
292
21258
						vert = cpn->vert;
293
37800
					cpn = cpn->next;
294
37800
				}
295
55593
				if (cp != NULL)
296
55593
					cp = cp->next;
297
298
				/*
299
				 * Skip later cells in a span,
300
				 * figure out whether to start a span,
301
				 * and advance to next data cell.
302
				 */
303
304
55593
				if (spans) {
305
135
					spans--;
306
135
					continue;
307
				}
308
55458
				if (dp != NULL) {
309
54000
					spans = dp->spans;
310

96246
					if (ic || sp->layout->first->pos
311
21123
					    != TBL_CELL_SPAN)
312
54000
						dp = dp->next;
313
				}
314
315
				/*
316
				 * Print one line of text in the cell
317
				 * and remember whether there is more.
318
				 */
319
320
55458
				tp->tcol++;
321
55458
				if (tp->tcol->col < tp->tcol->lastcol)
322
55089
					term_flushln(tp);
323
55458
				if (tp->tcol->col < tp->tcol->lastcol)
324
135
					more = 1;
325
326
				/*
327
				 * Vertical frames between data cells,
328
				 * but not after the last column.
329
				 */
330
331

128700
				if (fc == ' ' && ((vert == 0 &&
332

59094
				     (cp == NULL || !IS_HORIZ(cp))) ||
333
23319
				    tp->tcol + 1 == tp->tcols + tp->lasttcol))
334
					continue;
335
336
20808
				if (tp->viscol < tp->tcol->rmargin) {
337
828
					(*tp->advance)(tp, tp->tcol->rmargin
338
414
					   - tp->viscol);
339
414
					tp->viscol = tp->tcol->rmargin;
340
414
				}
341
104391
				while (tp->viscol < tp->tcol->rmargin +
342
41733
				    tp->tbl.cols[ic].spacing / 2) {
343
20925
					(*tp->letter)(tp, fc);
344
20925
					tp->viscol++;
345
				}
346
347
20808
				if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
348
					continue;
349
350
19395
				if (fc == ' ' && cp != NULL) {
351
18603
					switch (cp->pos) {
352
					case TBL_CELL_HORIZ:
353
						fc = '-';
354
3330
						break;
355
					case TBL_CELL_DHORIZ:
356
						fc = '=';
357
						break;
358
					default:
359
						break;
360
					}
361
				}
362
19395
				if (tp->tbl.cols[ic].spacing) {
363
38790
					(*tp->letter)(tp, fc == ' ' ? '|' :
364
7452
					    vert ? '+' : fc);
365
19395
					tp->viscol++;
366
19395
				}
367
368
19395
				if (fc != ' ') {
369

14904
					if (cp != NULL &&
370
7452
					    cp->pos == TBL_CELL_HORIZ)
371
4113
						fc = '-';
372

6678
					else if (cp != NULL &&
373
3339
					    cp->pos == TBL_CELL_DHORIZ)
374
						fc = '=';
375
					else
376
						fc = ' ';
377
				}
378

35757
				if (tp->tbl.cols[ic].spacing > 2 &&
379
35703
				    (vert > 1 || fc != ' ')) {
380
12600
					(*tp->letter)(tp, fc == ' ' ? '|' :
381
4113
					    vert > 1 ? '+' : fc);
382
6300
					tp->viscol++;
383
6300
				}
384
			}
385
		}
386
387
		/* Print the vertical frame at the end of each row. */
388
389
		fc = '\0';
390

40698
		if ((sp->layout->last->vert &&
391
1161
		     sp->layout->last->col + 1 == sp->opts->cols) ||
392
20223
		    (sp->next != NULL &&
393
13788
		     sp->next->layout->last->vert &&
394
720
		     sp->next->layout->last->col + 1 == sp->opts->cols) ||
395
19503
		    (sp->prev != NULL &&
396
13248
		     sp->prev->layout->last->vert &&
397
729
		     sp->prev->layout->last->col + 1 == sp->opts->cols &&
398

1989
		     (horiz || (IS_HORIZ(sp->layout->last) &&
399

360
		      !IS_HORIZ(sp->prev->layout->last)))) ||
400
19314
		    (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
401

63846
			fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|';
402

5049
		else if (horiz && sp->opts->rvert)
403
9
			fc = '-';
404
21384
		if (fc != '\0') {
405


64899
			if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
406
1242
			    sp->layout->last->col + 1 < sp->opts->cols)) {
407
14931
				tp->tcol++;
408
29862
				(*tp->advance)(tp,
409
44775
				    tp->tcol->offset > tp->viscol ?
410
14913
				    tp->tcol->offset - tp->viscol : 1);
411
14931
			}
412
16380
			(*tp->letter)(tp, fc);
413
16380
		}
414
21384
		(*tp->endline)(tp);
415
21384
		tp->viscol = 0;
416
21384
	} while (more);
417
418
	/*
419
	 * Clean up after this row.  If it is the last line
420
	 * of the table, print the box line and clean up
421
	 * column data; otherwise, print the allbox line.
422
	 */
423
424
21249
	term_setcol(tp, 1);
425
21249
	tp->flags &= ~TERMP_MULTICOL;
426
21249
	tp->tcol->rmargin = tp->maxrmargin;
427
21249
	if (sp->next == NULL) {
428
6588
		if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
429
4698
			tbl_hrule(tp, sp, 2);
430
4698
			tp->skipvsp = 1;
431
4698
		}
432
6588
		if (sp->opts->opts & TBL_OPT_DBOX) {
433
2196
			tbl_hrule(tp, sp, 3);
434
2196
			tp->skipvsp = 2;
435
2196
		}
436
6588
		assert(tp->tbl.cols);
437
6588
		free(tp->tbl.cols);
438
6588
		tp->tbl.cols = NULL;
439
6588
		tp->tcol->offset = offset;
440

35730
	} else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX &&
441

10746
	    (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA ||
442
18
	     sp->next->next != NULL))
443
5364
		tbl_hrule(tp, sp, 1);
444
445
21249
	tp->flags &= ~TERMP_NONOSPACE;
446
21249
}
447
448
/*
449
 * Kinds of horizontal rulers:
450
 * 0: inside the table (single or double line with crossings)
451
 * 1: inside the table (single or double line with crossings and ends)
452
 * 2: inner frame (single line with crossings and ends)
453
 * 3: outer frame (single line without crossings with ends)
454
 */
455
static void
456
tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
457
{
458
	const struct tbl_cell *cp, *cpn, *cpp;
459
	const struct roffcol *col;
460
	int	 vert;
461
	char	 line, cross;
462
463
63756
	line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
464
19386
	cross = (kind < 3) ? '+' : '-';
465
466
19386
	if (kind)
467
19152
		term_word(tp, "+");
468
19386
	cp = sp->layout->first;
469

39150
	cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first;
470
19386
	if (cpp == cp)
471
		cpp = NULL;
472

49932
	cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first;
473
19386
	if (cpn == cp)
474
		cpn = NULL;
475
19386
	for (;;) {
476
49041
		col = tp->tbl.cols + cp->col;
477
49041
		tbl_char(tp, line, col->width + col->spacing / 2);
478
49041
		vert = cp->vert;
479
49041
		if ((cp = cp->next) == NULL)
480
			 break;
481
29655
		if (cpp != NULL) {
482
36
			if (vert < cpp->vert)
483
18
				vert = cpp->vert;
484
36
			cpp = cpp->next;
485
36
		}
486
29655
		if (cpn != NULL) {
487
8064
			if (vert < cpn->vert)
488
1044
				vert = cpn->vert;
489
8064
			cpn = cpn->next;
490
8064
		}
491
29655
		if (sp->opts->opts & TBL_OPT_ALLBOX && !vert)
492
16173
			vert = 1;
493
29655
		if (col->spacing)
494
29637
			tbl_char(tp, vert ? cross : line, 1);
495
29655
		if (col->spacing > 2)
496
29601
			tbl_char(tp, vert > 1 ? cross : line, 1);
497
29655
		if (col->spacing > 4)
498
54
			tbl_char(tp, line, (col->spacing - 3) / 2);
499
	}
500
19386
	if (kind) {
501
19152
		term_word(tp, "+");
502
19152
		term_flushln(tp);
503
19152
	}
504
19386
}
505
506
static void
507
tbl_data(struct termp *tp, const struct tbl_opts *opts,
508
    const struct tbl_cell *cp, const struct tbl_dat *dp,
509
    const struct roffcol *col)
510
{
511
110016
	switch (cp->pos) {
512
	case TBL_CELL_HORIZ:
513
5535
		tbl_char(tp, '-', col->width);
514
5535
		return;
515
	case TBL_CELL_DHORIZ:
516
		tbl_char(tp, '=', col->width);
517
		return;
518
	default:
519
		break;
520
	}
521
522
49473
	if (dp == NULL)
523
		return;
524
525

49446
	switch (dp->pos) {
526
	case TBL_DATA_NONE:
527
		return;
528
	case TBL_DATA_HORIZ:
529
	case TBL_DATA_NHORIZ:
530
		tbl_char(tp, '-', col->width);
531
		return;
532
	case TBL_DATA_NDHORIZ:
533
	case TBL_DATA_DHORIZ:
534
		tbl_char(tp, '=', col->width);
535
		return;
536
	default:
537
		break;
538
	}
539
540


98865
	switch (cp->pos) {
541
	case TBL_CELL_LONG:
542
	case TBL_CELL_CENTRE:
543
	case TBL_CELL_LEFT:
544
	case TBL_CELL_RIGHT:
545
49302
		tbl_literal(tp, dp, col);
546
49302
		break;
547
	case TBL_CELL_NUMBER:
548
117
		tbl_number(tp, opts, dp, col);
549
117
		break;
550
	case TBL_CELL_DOWN:
551
	case TBL_CELL_SPAN:
552
		break;
553
	default:
554
		abort();
555
	}
556
55008
}
557
558
static void
559
tbl_char(struct termp *tp, char c, size_t len)
560
{
561
	size_t		i, sz;
562
425088
	char		cp[2];
563
564
212544
	cp[0] = c;
565
212544
	cp[1] = '\0';
566
567
212544
	sz = term_strlen(tp, cp);
568
569
895572
	for (i = 0; i < len; i += sz)
570
235242
		term_word(tp, cp);
571
212544
}
572
573
static void
574
tbl_literal(struct termp *tp, const struct tbl_dat *dp,
575
		const struct roffcol *col)
576
{
577
	size_t		 len, padl, padr, width;
578
	int		 ic, spans;
579
580
98604
	assert(dp->string);
581
49302
	len = term_strlen(tp, dp->string);
582
49302
	width = col->width;
583
49302
	ic = dp->layout->col;
584
49302
	spans = dp->spans;
585
98874
	while (spans--)
586
135
		width += tp->tbl.cols[++ic].width + 3;
587
588
102582
	padr = width > len ? width - len : 0;
589
	padl = 0;
590
591

50103
	switch (dp->layout->pos) {
592
	case TBL_CELL_LONG:
593
		padl = term_len(tp, 1);
594
		padr = padr > padl ? padr - padl : 0;
595
		break;
596
	case TBL_CELL_CENTRE:
597
288
		if (2 > padr)
598
			break;
599
144
		padl = padr / 2;
600
144
		padr -= padl;
601
144
		break;
602
	case TBL_CELL_RIGHT:
603
		padl = padr;
604
		padr = 0;
605
513
		break;
606
	default:
607
		break;
608
	}
609
610
49302
	tbl_char(tp, ASCII_NBRSP, padl);
611
49302
	tbl_word(tp, dp);
612
49302
	tbl_char(tp, ASCII_NBRSP, padr);
613
49302
}
614
615
static void
616
tbl_number(struct termp *tp, const struct tbl_opts *opts,
617
		const struct tbl_dat *dp,
618
		const struct roffcol *col)
619
{
620
	char		*cp;
621
234
	char		 buf[2];
622
	size_t		 sz, psz, ssz, d, padl;
623
	int		 i;
624
625
	/*
626
	 * See calc_data_number().  Left-pad by taking the offset of our
627
	 * and the maximum decimal; right-pad by the remaining amount.
628
	 */
629
630
117
	assert(dp->string);
631
632
117
	sz = term_strlen(tp, dp->string);
633
634
117
	buf[0] = opts->decimal;
635
117
	buf[1] = '\0';
636
637
117
	psz = term_strlen(tp, buf);
638
639
117
	if ((cp = strrchr(dp->string, opts->decimal)) != NULL) {
640
684
		for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
641
225
			buf[0] = dp->string[i];
642
225
			ssz += term_strlen(tp, buf);
643
		}
644
117
		d = ssz + psz;
645
117
	} else
646
		d = sz + psz;
647
648

171
	if (col->decimal > d && col->width > sz) {
649
36
		padl = col->decimal - d;
650
36
		if (padl + sz > col->width)
651
			padl = col->width - sz;
652
36
		tbl_char(tp, ASCII_NBRSP, padl);
653
36
	} else
654
		padl = 0;
655
117
	tbl_word(tp, dp);
656
117
	if (col->width > sz + padl)
657
36
		tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
658
117
}
659
660
static void
661
tbl_word(struct termp *tp, const struct tbl_dat *dp)
662
{
663
	int		 prev_font;
664
665
98838
	prev_font = tp->fonti;
666
49419
	if (dp->layout->flags & TBL_CELL_BOLD)
667
81
		term_fontpush(tp, TERMFONT_BOLD);
668
49338
	else if (dp->layout->flags & TBL_CELL_ITALIC)
669
54
		term_fontpush(tp, TERMFONT_UNDER);
670
671
49419
	term_word(tp, dp->string);
672
673
49419
	term_fontpopq(tp, prev_font);
674
49419
}