GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
36 |
i = term_hen((const struct termp *)arg, su); |
|
55 |
18 |
return i > 0 ? i : 0; |
|
56 |
} |
||
57 |
|||
58 |
static size_t |
||
59 |
term_tbl_strlen(const char *p, void *arg) |
||
60 |
{ |
||
61 |
33884 |
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 |
2736 |
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 |
14334 |
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 |
✓✓ | 7167 |
if (tp->tbl.cols == NULL) { |
90 |
2204 |
tp->tbl.len = term_tbl_len; |
|
91 |
2204 |
tp->tbl.slen = term_tbl_strlen; |
|
92 |
2204 |
tp->tbl.sulen = term_tbl_sulen; |
|
93 |
2204 |
tp->tbl.arg = tp; |
|
94 |
|||
95 |
2204 |
tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin); |
|
96 |
|||
97 |
/* Tables leak .ta settings to subsequent text. */ |
||
98 |
|||
99 |
2204 |
term_tab_set(tp, NULL); |
|
100 |
✓✓ | 5046 |
coloff = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || |
101 |
638 |
sp->opts->lvert; |
|
102 |
✓✓ | 16118 |
for (ic = 0; ic < sp->opts->cols; ic++) { |
103 |
5855 |
coloff += tp->tbl.cols[ic].width; |
|
104 |
5855 |
term_tab_iset(coloff); |
|
105 |
5855 |
coloff += tp->tbl.cols[ic].spacing; |
|
106 |
} |
||
107 |
|||
108 |
/* Center the table as a whole. */ |
||
109 |
|||
110 |
2204 |
offset = tp->tcol->offset; |
|
111 |
✓✓ | 2204 |
if (sp->opts->opts & TBL_OPT_CENTRE) { |
112 |
✓✓ | 174 |
tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) |
113 |
54 |
? 2 : !!sp->opts->lvert + !!sp->opts->rvert; |
|
114 |
✓✓ | 132 |
for (ic = 0; ic + 1 < sp->opts->cols; ic++) |
115 |
12 |
tsz += tp->tbl.cols[ic].width + |
|
116 |
6 |
tp->tbl.cols[ic].spacing; |
|
117 |
✓✗ | 60 |
if (sp->opts->cols) |
118 |
60 |
tsz += tp->tbl.cols[sp->opts->cols - 1].width; |
|
119 |
✓✓ | 60 |
if (offset + tsz > tp->tcol->rmargin) |
120 |
18 |
tsz -= 1; |
|
121 |
✓✓ | 177 |
tp->tcol->offset = offset + tp->tcol->rmargin > tsz ? |
122 |
57 |
(offset + tp->tcol->rmargin - tsz) / 2 : 0; |
|
123 |
60 |
} |
|
124 |
|||
125 |
/* Horizontal frame at the start of boxed tables. */ |
||
126 |
|||
127 |
✓✓ | 2204 |
if (sp->opts->opts & TBL_OPT_DBOX) |
128 |
732 |
tbl_hrule(tp, sp, 3); |
|
129 |
✓✓ | 2204 |
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) |
130 |
1566 |
tbl_hrule(tp, sp, 2); |
|
131 |
} |
||
132 |
|||
133 |
/* Set up the columns. */ |
||
134 |
|||
135 |
14334 |
tp->flags |= TERMP_MULTICOL; |
|
136 |
horiz = 0; |
||
137 |
✗✓✓✓ |
14334 |
switch (sp->pos) { |
138 |
case TBL_SPAN_HORIZ: |
||
139 |
case TBL_SPAN_DHORIZ: |
||
140 |
horiz = 1; |
||
141 |
78 |
term_setcol(tp, 1); |
|
142 |
78 |
break; |
|
143 |
case TBL_SPAN_DATA: |
||
144 |
7089 |
term_setcol(tp, sp->opts->cols + 2); |
|
145 |
7089 |
coloff = tp->tcol->offset; |
|
146 |
|||
147 |
/* Set up a column for a left vertical frame. */ |
||
148 |
|||
149 |
✓✓✓✓ |
8982 |
if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || |
150 |
1893 |
sp->opts->lvert) |
|
151 |
5445 |
coloff++; |
|
152 |
7089 |
tp->tcol->rmargin = coloff; |
|
153 |
|||
154 |
/* Set up the data columns. */ |
||
155 |
|||
156 |
7089 |
dp = sp->first; |
|
157 |
spans = 0; |
||
158 |
✓✓ | 51612 |
for (ic = 0; ic < sp->opts->cols; ic++) { |
159 |
✓✓ | 18717 |
if (spans == 0) { |
160 |
18672 |
tp->tcol++; |
|
161 |
18672 |
tp->tcol->offset = coloff; |
|
162 |
18672 |
} |
|
163 |
18717 |
coloff += tp->tbl.cols[ic].width; |
|
164 |
18717 |
tp->tcol->rmargin = coloff; |
|
165 |
✓✓ | 18717 |
if (ic + 1 < sp->opts->cols) |
166 |
11628 |
coloff += tp->tbl.cols[ic].spacing; |
|
167 |
✓✓ | 18717 |
if (spans) { |
168 |
45 |
spans--; |
|
169 |
45 |
continue; |
|
170 |
} |
||
171 |
✓✓ | 18672 |
if (dp == NULL) |
172 |
continue; |
||
173 |
18186 |
spans = dp->spans; |
|
174 |
✓✓✓✗ |
25266 |
if (ic || sp->layout->first->pos != TBL_CELL_SPAN) |
175 |
18186 |
dp = dp->next; |
|
176 |
} |
||
177 |
|||
178 |
/* Set up a column for a right vertical frame. */ |
||
179 |
|||
180 |
7089 |
tp->tcol++; |
|
181 |
7089 |
tp->tcol->offset = coloff + 1; |
|
182 |
7089 |
tp->tcol->rmargin = tp->maxrmargin; |
|
183 |
|||
184 |
/* Spans may have reduced the number of columns. */ |
||
185 |
|||
186 |
7089 |
tp->lasttcol = tp->tcol - tp->tcols; |
|
187 |
|||
188 |
/* Fill the buffers for all data columns. */ |
||
189 |
|||
190 |
7089 |
tp->tcol = tp->tcols; |
|
191 |
7089 |
cp = cpn = sp->layout->first; |
|
192 |
7089 |
dp = sp->first; |
|
193 |
spans = 0; |
||
194 |
✓✓ | 51612 |
for (ic = 0; ic < sp->opts->cols; ic++) { |
195 |
✓✗ | 18717 |
if (cpn != NULL) { |
196 |
cp = cpn; |
||
197 |
18717 |
cpn = cpn->next; |
|
198 |
18717 |
} |
|
199 |
✓✓ | 18717 |
if (spans) { |
200 |
45 |
spans--; |
|
201 |
45 |
continue; |
|
202 |
} |
||
203 |
18672 |
tp->tcol++; |
|
204 |
18672 |
tp->col = 0; |
|
205 |
18672 |
tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic); |
|
206 |
✓✓ | 18672 |
if (dp == NULL) |
207 |
continue; |
||
208 |
18186 |
spans = dp->spans; |
|
209 |
✓✗ | 18186 |
if (cp->pos != TBL_CELL_SPAN) |
210 |
18186 |
dp = dp->next; |
|
211 |
} |
||
212 |
break; |
||
213 |
} |
||
214 |
|||
215 |
7167 |
do { |
|
216 |
/* Print the vertical frame at the start of each row. */ |
||
217 |
|||
218 |
7212 |
tp->tcol = tp->tcols; |
|
219 |
fc = '\0'; |
||
220 |
✓✓✓✓ |
13722 |
if (sp->layout->vert || |
221 |
✓✓✓✓ |
11479 |
(sp->next != NULL && sp->next->layout->vert && |
222 |
✓✓ | 243 |
sp->next->pos == TBL_SPAN_DATA) || |
223 |
✓✓✓✓ |
11056 |
(sp->prev != NULL && sp->prev->layout->vert && |
224 |
✓✓✓✓ ✗✓ |
663 |
(horiz || (IS_HORIZ(sp->layout->first) && |
225 |
✓✗✗✓ |
120 |
!IS_HORIZ(sp->prev->layout->first)))) || |
226 |
6510 |
sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)) |
|
227 |
✓✓✓✓ |
21324 |
fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|'; |
228 |
✓✓✓✓ |
1752 |
else if (horiz && sp->opts->lvert) |
229 |
3 |
fc = '-'; |
|
230 |
✓✓ | 7212 |
if (fc != '\0') { |
231 |
5472 |
(*tp->advance)(tp, tp->tcols->offset); |
|
232 |
5472 |
(*tp->letter)(tp, fc); |
|
233 |
5472 |
tp->viscol = tp->tcol->offset + 1; |
|
234 |
5472 |
} |
|
235 |
|||
236 |
/* Print the data cells. */ |
||
237 |
|||
238 |
more = 0; |
||
239 |
✓✓ | 7212 |
if (horiz) { |
240 |
78 |
tbl_hrule(tp, sp, 0); |
|
241 |
78 |
term_flushln(tp); |
|
242 |
78 |
} else { |
|
243 |
7134 |
cp = sp->layout->first; |
|
244 |
✓✓ | 19174 |
cpn = sp->next == NULL ? NULL : |
245 |
4906 |
sp->next->layout->first; |
|
246 |
✓✓ | 19219 |
cpp = sp->prev == NULL ? NULL : |
247 |
4951 |
sp->prev->layout->first; |
|
248 |
7134 |
dp = sp->first; |
|
249 |
spans = 0; |
||
250 |
✓✓ | 52002 |
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 |
✓✗ | 18867 |
if (cp != NULL) { |
259 |
18867 |
vert = cp->vert; |
|
260 |
✓✗✓ | 18867 |
switch (cp->pos) { |
261 |
case TBL_CELL_HORIZ: |
||
262 |
fc = '-'; |
||
263 |
1845 |
break; |
|
264 |
case TBL_CELL_DHORIZ: |
||
265 |
fc = '='; |
||
266 |
break; |
||
267 |
default: |
||
268 |
fc = ' '; |
||
269 |
17022 |
break; |
|
270 |
} |
||
271 |
} else { |
||
272 |
vert = 0; |
||
273 |
fc = ' '; |
||
274 |
} |
||
275 |
✓✓ | 18867 |
if (cpp != NULL) { |
276 |
✓✓✓✗ |
13711 |
if (vert == 0 && |
277 |
cp != NULL && |
||
278 |
✓✓✗✓ |
22556 |
((IS_HORIZ(cp) && |
279 |
✓✗✗✓ |
2148 |
!IS_HORIZ(cpp)) || |
280 |
✓✓ | 10741 |
(cp->next != NULL && |
281 |
✓✗ | 6339 |
cpp->next != NULL && |
282 |
✓✓✗✓ |
12003 |
IS_HORIZ(cp->next) && |
283 |
✓✗ | 1350 |
!IS_HORIZ(cpp->next)))) |
284 |
1749 |
vert = cpp->vert; |
|
285 |
13036 |
cpp = cpp->next; |
|
286 |
13036 |
} |
|
287 |
✓✓✓✓ |
35847 |
if (vert == 0 && |
288 |
16980 |
sp->opts->opts & TBL_OPT_ALLBOX) |
|
289 |
5997 |
vert = 1; |
|
290 |
✓✓ | 18867 |
if (cpn != NULL) { |
291 |
✓✓ | 12904 |
if (vert == 0) |
292 |
7390 |
vert = cpn->vert; |
|
293 |
12904 |
cpn = cpn->next; |
|
294 |
12904 |
} |
|
295 |
✓✗ | 18867 |
if (cp != NULL) |
296 |
18867 |
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 |
✓✓ | 18867 |
if (spans) { |
305 |
45 |
spans--; |
|
306 |
45 |
continue; |
|
307 |
} |
||
308 |
✓✓ | 18822 |
if (dp != NULL) { |
309 |
18336 |
spans = dp->spans; |
|
310 |
✓✓✓✗ |
32586 |
if (ic || sp->layout->first->pos |
311 |
7125 |
!= TBL_CELL_SPAN) |
|
312 |
18336 |
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 |
18822 |
tp->tcol++; |
|
321 |
✓✓ | 18822 |
if (tp->tcol->col < tp->tcol->lastcol) |
322 |
18699 |
term_flushln(tp); |
|
323 |
✓✓ | 18822 |
if (tp->tcol->col < tp->tcol->lastcol) |
324 |
45 |
more = 1; |
|
325 |
|||
326 |
/* |
||
327 |
* Vertical frames between data cells, |
||
328 |
* but not after the last column. |
||
329 |
*/ |
||
330 |
|||
331 |
✓✓✓✓ ✓✓ |
43572 |
if (fc == ' ' && ((vert == 0 && |
332 |
✓✓✓✓ ✗✓ |
20538 |
(cp == NULL || !IS_HORIZ(cp))) || |
333 |
7773 |
tp->tcol + 1 == tp->tcols + tp->lasttcol)) |
|
334 |
continue; |
||
335 |
|||
336 |
✓✓ | 6936 |
if (tp->viscol < tp->tcol->rmargin) { |
337 |
276 |
(*tp->advance)(tp, tp->tcol->rmargin |
|
338 |
138 |
- tp->viscol); |
|
339 |
138 |
tp->viscol = tp->tcol->rmargin; |
|
340 |
138 |
} |
|
341 |
✓✓ | 41733 |
while (tp->viscol < tp->tcol->rmargin + |
342 |
13911 |
tp->tbl.cols[ic].spacing / 2) { |
|
343 |
6975 |
(*tp->letter)(tp, fc); |
|
344 |
6975 |
tp->viscol++; |
|
345 |
} |
||
346 |
|||
347 |
✓✓ | 6936 |
if (tp->tcol + 1 == tp->tcols + tp->lasttcol) |
348 |
continue; |
||
349 |
|||
350 |
✓✓ | 6465 |
if (fc == ' ' && cp != NULL) { |
351 |
✓✗✓ | 6201 |
switch (cp->pos) { |
352 |
case TBL_CELL_HORIZ: |
||
353 |
fc = '-'; |
||
354 |
1110 |
break; |
|
355 |
case TBL_CELL_DHORIZ: |
||
356 |
fc = '='; |
||
357 |
break; |
||
358 |
default: |
||
359 |
break; |
||
360 |
} |
||
361 |
} |
||
362 |
✓✗ | 6465 |
if (tp->tbl.cols[ic].spacing) { |
363 |
✓✓ | 12930 |
(*tp->letter)(tp, fc == ' ' ? '|' : |
364 |
2484 |
vert ? '+' : fc); |
|
365 |
6465 |
tp->viscol++; |
|
366 |
6465 |
} |
|
367 |
|||
368 |
✓✓ | 6465 |
if (fc != ' ') { |
369 |
✓✗✓✓ |
4968 |
if (cp != NULL && |
370 |
2484 |
cp->pos == TBL_CELL_HORIZ) |
|
371 |
1371 |
fc = '-'; |
|
372 |
✓✗✗✓ |
2226 |
else if (cp != NULL && |
373 |
1113 |
cp->pos == TBL_CELL_DHORIZ) |
|
374 |
fc = '='; |
||
375 |
else |
||
376 |
fc = ' '; |
||
377 |
} |
||
378 |
✓✓✓✓ |
11919 |
if (tp->tbl.cols[ic].spacing > 2 && |
379 |
✓✓ | 11901 |
(vert > 1 || fc != ' ')) { |
380 |
✓✓ | 4200 |
(*tp->letter)(tp, fc == ' ' ? '|' : |
381 |
1371 |
vert > 1 ? '+' : fc); |
|
382 |
2100 |
tp->viscol++; |
|
383 |
2100 |
} |
|
384 |
} |
||
385 |
} |
||
386 |
|||
387 |
/* Print the vertical frame at the end of each row. */ |
||
388 |
|||
389 |
fc = '\0'; |
||
390 |
✓✓✓✓ |
13734 |
if ((sp->layout->last->vert && |
391 |
✗✓ | 387 |
sp->layout->last->col + 1 == sp->opts->cols) || |
392 |
✓✓ | 6825 |
(sp->next != NULL && |
393 |
✓✓ | 4672 |
sp->next->layout->last->vert && |
394 |
✗✓ | 240 |
sp->next->layout->last->col + 1 == sp->opts->cols) || |
395 |
✓✓ | 6585 |
(sp->prev != NULL && |
396 |
✓✓ | 4492 |
sp->prev->layout->last->vert && |
397 |
✓✗ | 243 |
sp->prev->layout->last->col + 1 == sp->opts->cols && |
398 |
✓✓✓✓ ✗✓ |
663 |
(horiz || (IS_HORIZ(sp->layout->last) && |
399 |
✓✗✗✓ |
120 |
!IS_HORIZ(sp->prev->layout->last)))) || |
400 |
6522 |
(sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))) |
|
401 |
✓✓✓✓ |
21282 |
fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|'; |
402 |
✓✓✓✓ |
1767 |
else if (horiz && sp->opts->rvert) |
403 |
3 |
fc = '-'; |
|
404 |
✓✓ | 7212 |
if (fc != '\0') { |
405 |
✓✓✓✓ ✓✓✗✓ |
21633 |
if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 || |
406 |
414 |
sp->layout->last->col + 1 < sp->opts->cols)) { |
|
407 |
4977 |
tp->tcol++; |
|
408 |
9954 |
(*tp->advance)(tp, |
|
409 |
✓✓ | 14925 |
tp->tcol->offset > tp->viscol ? |
410 |
4971 |
tp->tcol->offset - tp->viscol : 1); |
|
411 |
4977 |
} |
|
412 |
5460 |
(*tp->letter)(tp, fc); |
|
413 |
5460 |
} |
|
414 |
7212 |
(*tp->endline)(tp); |
|
415 |
7212 |
tp->viscol = 0; |
|
416 |
✓✓ | 7212 |
} 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 |
7167 |
term_setcol(tp, 1); |
|
425 |
7167 |
tp->flags &= ~TERMP_MULTICOL; |
|
426 |
7167 |
tp->tcol->rmargin = tp->maxrmargin; |
|
427 |
✓✓ | 7167 |
if (sp->next == NULL) { |
428 |
✓✓ | 2204 |
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) { |
429 |
1566 |
tbl_hrule(tp, sp, 2); |
|
430 |
1566 |
tp->skipvsp = 1; |
|
431 |
1566 |
} |
|
432 |
✓✓ | 2204 |
if (sp->opts->opts & TBL_OPT_DBOX) { |
433 |
732 |
tbl_hrule(tp, sp, 3); |
|
434 |
732 |
tp->skipvsp = 2; |
|
435 |
732 |
} |
|
436 |
✗✓ | 2204 |
assert(tp->tbl.cols); |
437 |
2204 |
free(tp->tbl.cols); |
|
438 |
2204 |
tp->tbl.cols = NULL; |
|
439 |
2204 |
tp->tcol->offset = offset; |
|
440 |
✓✓✓✓ ✓✓ |
12070 |
} else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX && |
441 |
✓✗✓✓ |
3582 |
(sp->next == NULL || sp->next->pos == TBL_SPAN_DATA || |
442 |
6 |
sp->next->next != NULL)) |
|
443 |
1788 |
tbl_hrule(tp, sp, 1); |
|
444 |
|||
445 |
7167 |
tp->flags &= ~TERMP_NONOSPACE; |
|
446 |
7167 |
} |
|
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 |
✓✓ | 21252 |
line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-'; |
464 |
6462 |
cross = (kind < 3) ? '+' : '-'; |
|
465 |
|||
466 |
✓✓ | 6462 |
if (kind) |
467 |
6384 |
term_word(tp, "+"); |
|
468 |
6462 |
cp = sp->layout->first; |
|
469 |
✓✓✓✓ |
13050 |
cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first; |
470 |
6462 |
if (cpp == cp) |
|
471 |
cpp = NULL; |
||
472 |
✓✓✓✓ |
16644 |
cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first; |
473 |
6462 |
if (cpn == cp) |
|
474 |
cpn = NULL; |
||
475 |
16347 |
for (;;) { |
|
476 |
16347 |
col = tp->tbl.cols + cp->col; |
|
477 |
16347 |
tbl_char(tp, line, col->width + col->spacing / 2); |
|
478 |
16347 |
vert = cp->vert; |
|
479 |
✓✓ | 16347 |
if ((cp = cp->next) == NULL) |
480 |
break; |
||
481 |
✓✓ | 9885 |
if (cpp != NULL) { |
482 |
✓✓ | 12 |
if (vert < cpp->vert) |
483 |
6 |
vert = cpp->vert; |
|
484 |
12 |
cpp = cpp->next; |
|
485 |
12 |
} |
|
486 |
✓✓ | 9885 |
if (cpn != NULL) { |
487 |
✓✓ | 2688 |
if (vert < cpn->vert) |
488 |
348 |
vert = cpn->vert; |
|
489 |
2688 |
cpn = cpn->next; |
|
490 |
2688 |
} |
|
491 |
✓✓ | 9885 |
if (sp->opts->opts & TBL_OPT_ALLBOX && !vert) |
492 |
5391 |
vert = 1; |
|
493 |
✓✓ | 9885 |
if (col->spacing) |
494 |
9879 |
tbl_char(tp, vert ? cross : line, 1); |
|
495 |
✓✓ | 9885 |
if (col->spacing > 2) |
496 |
9867 |
tbl_char(tp, vert > 1 ? cross : line, 1); |
|
497 |
✓✓ | 9885 |
if (col->spacing > 4) |
498 |
18 |
tbl_char(tp, line, (col->spacing - 3) / 2); |
|
499 |
} |
||
500 |
✓✓ | 6462 |
if (kind) { |
501 |
6384 |
term_word(tp, "+"); |
|
502 |
6384 |
term_flushln(tp); |
|
503 |
6384 |
} |
|
504 |
6462 |
} |
|
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 |
✓✗✓ | 37344 |
switch (cp->pos) { |
512 |
case TBL_CELL_HORIZ: |
||
513 |
1845 |
tbl_char(tp, '-', col->width); |
|
514 |
1845 |
return; |
|
515 |
case TBL_CELL_DHORIZ: |
||
516 |
tbl_char(tp, '=', col->width); |
||
517 |
return; |
||
518 |
default: |
||
519 |
break; |
||
520 |
} |
||
521 |
|||
522 |
✓✓ | 16827 |
if (dp == NULL) |
523 |
return; |
||
524 |
|||
525 |
✗✗✗✗ ✓✗ |
16818 |
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 |
✗✗✗✓ ✓✗✗✓ |
33627 |
switch (cp->pos) { |
541 |
case TBL_CELL_LONG: |
||
542 |
case TBL_CELL_CENTRE: |
||
543 |
case TBL_CELL_LEFT: |
||
544 |
case TBL_CELL_RIGHT: |
||
545 |
16770 |
tbl_literal(tp, dp, col); |
|
546 |
16770 |
break; |
|
547 |
case TBL_CELL_NUMBER: |
||
548 |
39 |
tbl_number(tp, opts, dp, col); |
|
549 |
39 |
break; |
|
550 |
case TBL_CELL_DOWN: |
||
551 |
case TBL_CELL_SPAN: |
||
552 |
break; |
||
553 |
default: |
||
554 |
abort(); |
||
555 |
} |
||
556 |
18672 |
} |
|
557 |
|||
558 |
static void |
||
559 |
tbl_char(struct termp *tp, char c, size_t len) |
||
560 |
{ |
||
561 |
size_t i, sz; |
||
562 |
143040 |
char cp[2]; |
|
563 |
|||
564 |
71520 |
cp[0] = c; |
|
565 |
71520 |
cp[1] = '\0'; |
|
566 |
|||
567 |
71520 |
sz = term_strlen(tp, cp); |
|
568 |
|||
569 |
✓✓ | 301632 |
for (i = 0; i < len; i += sz) |
570 |
79296 |
term_word(tp, cp); |
|
571 |
71520 |
} |
|
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 |
✗✓ | 33540 |
assert(dp->string); |
581 |
16770 |
len = term_strlen(tp, dp->string); |
|
582 |
16770 |
width = col->width; |
|
583 |
16770 |
ic = dp->layout->col; |
|
584 |
16770 |
spans = dp->spans; |
|
585 |
✓✓ | 33630 |
while (spans--) |
586 |
45 |
width += tp->tbl.cols[++ic].width + 3; |
|
587 |
|||
588 |
✓✓ | 35062 |
padr = width > len ? width - len : 0; |
589 |
padl = 0; |
||
590 |
|||
591 |
✗✓✓✓ |
17037 |
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 |
✓✓ | 96 |
if (2 > padr) |
598 |
break; |
||
599 |
48 |
padl = padr / 2; |
|
600 |
48 |
padr -= padl; |
|
601 |
48 |
break; |
|
602 |
case TBL_CELL_RIGHT: |
||
603 |
padl = padr; |
||
604 |
padr = 0; |
||
605 |
171 |
break; |
|
606 |
default: |
||
607 |
break; |
||
608 |
} |
||
609 |
|||
610 |
16770 |
tbl_char(tp, ASCII_NBRSP, padl); |
|
611 |
16770 |
tbl_word(tp, dp); |
|
612 |
16770 |
tbl_char(tp, ASCII_NBRSP, padr); |
|
613 |
16770 |
} |
|
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 |
78 |
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 |
✗✓ | 39 |
assert(dp->string); |
631 |
|||
632 |
39 |
sz = term_strlen(tp, dp->string); |
|
633 |
|||
634 |
39 |
buf[0] = opts->decimal; |
|
635 |
39 |
buf[1] = '\0'; |
|
636 |
|||
637 |
39 |
psz = term_strlen(tp, buf); |
|
638 |
|||
639 |
✓✗ | 39 |
if ((cp = strrchr(dp->string, opts->decimal)) != NULL) { |
640 |
✓✓ | 228 |
for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { |
641 |
75 |
buf[0] = dp->string[i]; |
|
642 |
75 |
ssz += term_strlen(tp, buf); |
|
643 |
} |
||
644 |
39 |
d = ssz + psz; |
|
645 |
39 |
} else |
|
646 |
d = sz + psz; |
||
647 |
|||
648 |
✓✓✓✓ |
57 |
if (col->decimal > d && col->width > sz) { |
649 |
12 |
padl = col->decimal - d; |
|
650 |
✗✓ | 12 |
if (padl + sz > col->width) |
651 |
padl = col->width - sz; |
||
652 |
12 |
tbl_char(tp, ASCII_NBRSP, padl); |
|
653 |
12 |
} else |
|
654 |
padl = 0; |
||
655 |
39 |
tbl_word(tp, dp); |
|
656 |
✓✓ | 39 |
if (col->width > sz + padl) |
657 |
12 |
tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); |
|
658 |
39 |
} |
|
659 |
|||
660 |
static void |
||
661 |
tbl_word(struct termp *tp, const struct tbl_dat *dp) |
||
662 |
{ |
||
663 |
int prev_font; |
||
664 |
|||
665 |
33618 |
prev_font = tp->fonti; |
|
666 |
✓✓ | 16809 |
if (dp->layout->flags & TBL_CELL_BOLD) |
667 |
27 |
term_fontpush(tp, TERMFONT_BOLD); |
|
668 |
✓✓ | 16782 |
else if (dp->layout->flags & TBL_CELL_ITALIC) |
669 |
18 |
term_fontpush(tp, TERMFONT_UNDER); |
|
670 |
|||
671 |
16809 |
term_word(tp, dp->string); |
|
672 |
|||
673 |
16809 |
term_fontpopq(tp, prev_font); |
|
674 |
16809 |
} |
Generated by: GCOVR (Version 3.3) |