GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: term.c,v 1.134 2017/07/28 14:24:17 florian Exp $ */ |
||
2 |
/* |
||
3 |
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
||
4 |
* Copyright (c) 2010-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 AUTHORS DISCLAIM ALL WARRANTIES |
||
11 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||
12 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 <ctype.h> |
||
22 |
#include <stdio.h> |
||
23 |
#include <stdlib.h> |
||
24 |
#include <string.h> |
||
25 |
|||
26 |
#include "mandoc.h" |
||
27 |
#include "mandoc_aux.h" |
||
28 |
#include "out.h" |
||
29 |
#include "term.h" |
||
30 |
#include "main.h" |
||
31 |
|||
32 |
static size_t cond_width(const struct termp *, int, int *); |
||
33 |
static void adjbuf(struct termp_col *, size_t); |
||
34 |
static void bufferc(struct termp *, char); |
||
35 |
static void encode(struct termp *, const char *, size_t); |
||
36 |
static void encode1(struct termp *, int); |
||
37 |
static void endline(struct termp *); |
||
38 |
|||
39 |
|||
40 |
void |
||
41 |
term_setcol(struct termp *p, size_t maxtcol) |
||
42 |
{ |
||
43 |
✓✓ | 84996 |
if (maxtcol > p->maxtcol) { |
44 |
423 |
p->tcols = mandoc_recallocarray(p->tcols, |
|
45 |
p->maxtcol, maxtcol, sizeof(*p->tcols)); |
||
46 |
423 |
p->maxtcol = maxtcol; |
|
47 |
423 |
} |
|
48 |
42498 |
p->lasttcol = maxtcol - 1; |
|
49 |
42498 |
p->tcol = p->tcols; |
|
50 |
42498 |
} |
|
51 |
|||
52 |
void |
||
53 |
term_free(struct termp *p) |
||
54 |
{ |
||
55 |
✓✓ | 34297 |
for (p->tcol = p->tcols; p->tcol < p->tcols + p->maxtcol; p->tcol++) |
56 |
7529 |
free(p->tcol->buf); |
|
57 |
6413 |
free(p->tcols); |
|
58 |
6413 |
free(p->fontq); |
|
59 |
6413 |
free(p); |
|
60 |
6413 |
} |
|
61 |
|||
62 |
void |
||
63 |
term_begin(struct termp *p, term_margin head, |
||
64 |
term_margin foot, const struct roff_meta *arg) |
||
65 |
{ |
||
66 |
|||
67 |
12826 |
p->headf = head; |
|
68 |
6413 |
p->footf = foot; |
|
69 |
6413 |
p->argf = arg; |
|
70 |
6413 |
(*p->begin)(p); |
|
71 |
6413 |
} |
|
72 |
|||
73 |
void |
||
74 |
term_end(struct termp *p) |
||
75 |
{ |
||
76 |
|||
77 |
12826 |
(*p->end)(p); |
|
78 |
6413 |
} |
|
79 |
|||
80 |
/* |
||
81 |
* Flush a chunk of text. By default, break the output line each time |
||
82 |
* the right margin is reached, and continue output on the next line |
||
83 |
* at the same offset as the chunk itself. By default, also break the |
||
84 |
* output line at the end of the chunk. |
||
85 |
* The following flags may be specified: |
||
86 |
* |
||
87 |
* - TERMP_NOBREAK: Do not break the output line at the right margin, |
||
88 |
* but only at the max right margin. Also, do not break the output |
||
89 |
* line at the end of the chunk, such that the next call can pad to |
||
90 |
* the next column. However, if less than p->trailspace blanks, |
||
91 |
* which can be 0, 1, or 2, remain to the right margin, the line |
||
92 |
* will be broken. |
||
93 |
* - TERMP_BRTRSP: Consider trailing whitespace significant |
||
94 |
* when deciding whether the chunk fits or not. |
||
95 |
* - TERMP_BRIND: If the chunk does not fit and the output line has |
||
96 |
* to be broken, start the next line at the right margin instead |
||
97 |
* of at the offset. Used together with TERMP_NOBREAK for the tags |
||
98 |
* in various kinds of tagged lists. |
||
99 |
* - TERMP_HANG: Do not break the output line at the right margin, |
||
100 |
* append the next chunk after it even if this one is too long. |
||
101 |
* To be used together with TERMP_NOBREAK. |
||
102 |
* - TERMP_NOPAD: Start writing at the current position, |
||
103 |
* do not pad with blank characters up to the offset. |
||
104 |
*/ |
||
105 |
void |
||
106 |
term_flushln(struct termp *p) |
||
107 |
{ |
||
108 |
size_t vis; /* current visual position on output */ |
||
109 |
size_t vbl; /* number of blanks to prepend to output */ |
||
110 |
size_t vend; /* end of word visual position on output */ |
||
111 |
size_t bp; /* visual right border position */ |
||
112 |
size_t dv; /* temporary for visual pos calculations */ |
||
113 |
size_t j; /* temporary loop index for p->tcol->buf */ |
||
114 |
size_t jhy; /* last hyph before overflow w/r/t j */ |
||
115 |
size_t maxvis; /* output position of visible boundary */ |
||
116 |
int ntab; /* number of tabs to prepend */ |
||
117 |
int breakline; /* after this word */ |
||
118 |
|||
119 |
✓✓✓✓ |
933724 |
vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ? |
120 |
186203 |
0 : p->tcol->offset - p->viscol; |
|
121 |
✓✓✓✓ |
217138 |
if (p->minbl && vbl < p->minbl) |
122 |
342 |
vbl = p->minbl; |
|
123 |
✓✓ | 560310 |
maxvis = p->tcol->rmargin > p->viscol + vbl ? |
124 |
186338 |
p->tcol->rmargin - p->viscol - vbl : 0; |
|
125 |
✓✓ | 519720 |
bp = !(p->flags & TERMP_NOBREAK) ? maxvis : |
126 |
✓✓ | 82458 |
p->maxrmargin > p->viscol + vbl ? |
127 |
41220 |
p->maxrmargin - p->viscol - vbl : 0; |
|
128 |
vis = vend = 0; |
||
129 |
|||
130 |
✓✓ | 186986 |
if ((p->flags & TERMP_MULTICOL) == 0) |
131 |
131663 |
p->tcol->col = 0; |
|
132 |
✓✓ | 720638 |
while (p->tcol->col < p->tcol->lastcol) { |
133 |
|||
134 |
/* |
||
135 |
* Handle literal tab characters: collapse all |
||
136 |
* subsequent tabs into a single huge set of spaces. |
||
137 |
*/ |
||
138 |
|||
139 |
ntab = 0; |
||
140 |
✓✗✓✓ |
1623609 |
while (p->tcol->col < p->tcol->lastcol && |
141 |
541203 |
p->tcol->buf[p->tcol->col] == '\t') { |
|
142 |
7452 |
vend = term_tab_next(vis); |
|
143 |
7452 |
vbl += vend - vis; |
|
144 |
vis = vend; |
||
145 |
7452 |
ntab++; |
|
146 |
7452 |
p->tcol->col++; |
|
147 |
} |
||
148 |
|||
149 |
/* |
||
150 |
* Count up visible word characters. Control sequences |
||
151 |
* (starting with the CSI) aren't counted. A space |
||
152 |
* generates a non-printing word, which is valid (the |
||
153 |
* space is printed according to regular spacing rules). |
||
154 |
*/ |
||
155 |
|||
156 |
jhy = 0; |
||
157 |
breakline = 0; |
||
158 |
✓✓ | 7176382 |
for (j = p->tcol->col; j < p->tcol->lastcol; j++) { |
159 |
✓✓ | 3401718 |
if (p->tcol->buf[j] == '\n') { |
160 |
✓✗ | 36 |
if ((p->flags & TERMP_BRIND) == 0) |
161 |
36 |
breakline = 1; |
|
162 |
continue; |
||
163 |
} |
||
164 |
✓✓✓✓ |
6463124 |
if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t') |
165 |
break; |
||
166 |
|||
167 |
/* Back over the last printed character. */ |
||
168 |
✓✓ | 3054404 |
if (p->tcol->buf[j] == '\b') { |
169 |
✗✓ | 291573 |
assert(j); |
170 |
291573 |
vend -= (*p->width)(p, p->tcol->buf[j - 1]); |
|
171 |
291573 |
continue; |
|
172 |
} |
||
173 |
|||
174 |
/* Regular word. */ |
||
175 |
/* Break at the hyphen point if we overrun. */ |
||
176 |
✓✓✓✓ ✓✓ |
7092625 |
if (vend > vis && vend < bp && |
177 |
✓✓ | 2154917 |
(p->tcol->buf[j] == ASCII_HYPH|| |
178 |
2149239 |
p->tcol->buf[j] == ASCII_BREAK)) |
|
179 |
5732 |
jhy = j; |
|
180 |
|||
181 |
/* |
||
182 |
* Hyphenation now decided, put back a real |
||
183 |
* hyphen such that we get the correct width. |
||
184 |
*/ |
||
185 |
✓✓ | 2762831 |
if (p->tcol->buf[j] == ASCII_HYPH) |
186 |
5715 |
p->tcol->buf[j] = '-'; |
|
187 |
|||
188 |
2762831 |
vend += (*p->width)(p, p->tcol->buf[j]); |
|
189 |
2762831 |
} |
|
190 |
|||
191 |
/* |
||
192 |
* Find out whether we would exceed the right margin. |
||
193 |
* If so, break to the next line. |
||
194 |
*/ |
||
195 |
|||
196 |
✓✓✓✓ |
541135 |
if (vend > bp && jhy == 0 && vis > 0 && |
197 |
7384 |
(p->flags & TERMP_BRNEVER) == 0) { |
|
198 |
✓✓ | 7285 |
if (p->flags & TERMP_MULTICOL) |
199 |
135 |
return; |
|
200 |
|||
201 |
7150 |
endline(p); |
|
202 |
7150 |
vend -= vis; |
|
203 |
|||
204 |
/* Use pending tabs on the new line. */ |
||
205 |
|||
206 |
vbl = 0; |
||
207 |
✓✓ | 14336 |
while (ntab--) |
208 |
18 |
vbl = term_tab_next(vbl); |
|
209 |
|||
210 |
/* Re-establish indentation. */ |
||
211 |
|||
212 |
✓✓ | 7150 |
if (p->flags & TERMP_BRIND) |
213 |
819 |
vbl += p->tcol->rmargin; |
|
214 |
else |
||
215 |
6331 |
vbl += p->tcol->offset; |
|
216 |
✓✓ | 20460 |
maxvis = p->tcol->rmargin > vbl ? |
217 |
6160 |
p->tcol->rmargin - vbl : 0; |
|
218 |
✓✓ | 20604 |
bp = !(p->flags & TERMP_NOBREAK) ? maxvis : |
219 |
✓✓ | 1602 |
p->maxrmargin > vbl ? p->maxrmargin - vbl : 0; |
220 |
7150 |
} |
|
221 |
|||
222 |
/* |
||
223 |
* Write out the rest of the word. |
||
224 |
*/ |
||
225 |
|||
226 |
✓✓ | 6639474 |
for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) { |
227 |
✓✓✓✓ |
3401882 |
if (vend > bp && jhy > 0 && p->tcol->col > jhy) |
228 |
break; |
||
229 |
✓✓ | 3400140 |
if (p->tcol->buf[p->tcol->col] == '\n') |
230 |
continue; |
||
231 |
✓✓ | 3400104 |
if (p->tcol->buf[p->tcol->col] == '\t') |
232 |
break; |
||
233 |
✓✓ | 3393066 |
if (p->tcol->buf[p->tcol->col] == ' ') { |
234 |
j = p->tcol->col; |
||
235 |
✓✓✓✓ |
2048817 |
while (p->tcol->col < p->tcol->lastcol && |
236 |
682795 |
p->tcol->buf[p->tcol->col] == ' ') |
|
237 |
342766 |
p->tcol->col++; |
|
238 |
340173 |
dv = (p->tcol->col - j) * (*p->width)(p, ' '); |
|
239 |
340173 |
vbl += dv; |
|
240 |
340173 |
vend += dv; |
|
241 |
340173 |
break; |
|
242 |
} |
||
243 |
✓✓ | 3052893 |
if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) { |
244 |
21581 |
vbl += (*p->width)(p, ' '); |
|
245 |
21581 |
continue; |
|
246 |
} |
||
247 |
✓✓ | 3031312 |
if (p->tcol->buf[p->tcol->col] == ASCII_BREAK) |
248 |
continue; |
||
249 |
|||
250 |
/* |
||
251 |
* Now we definitely know there will be |
||
252 |
* printable characters to output, |
||
253 |
* so write preceding white space now. |
||
254 |
*/ |
||
255 |
✓✓ | 3031258 |
if (vbl) { |
256 |
493655 |
(*p->advance)(p, vbl); |
|
257 |
493655 |
p->viscol += vbl; |
|
258 |
vbl = 0; |
||
259 |
493655 |
} |
|
260 |
|||
261 |
3031258 |
(*p->letter)(p, p->tcol->buf[p->tcol->col]); |
|
262 |
✓✓ | 3031258 |
if (p->tcol->buf[p->tcol->col] == '\b') |
263 |
291429 |
p->viscol -= (*p->width)(p, |
|
264 |
291429 |
p->tcol->buf[p->tcol->col - 1]); |
|
265 |
else |
||
266 |
2739829 |
p->viscol += (*p->width)(p, |
|
267 |
p->tcol->buf[p->tcol->col]); |
||
268 |
} |
||
269 |
vis = vend; |
||
270 |
|||
271 |
✓✓ | 533616 |
if (breakline == 0) |
272 |
continue; |
||
273 |
|||
274 |
/* Explicitly requested output line break. */ |
||
275 |
|||
276 |
✗✓ | 36 |
if (p->flags & TERMP_MULTICOL) |
277 |
return; |
||
278 |
|||
279 |
36 |
endline(p); |
|
280 |
breakline = 0; |
||
281 |
vis = vend = 0; |
||
282 |
|||
283 |
/* Re-establish indentation. */ |
||
284 |
|||
285 |
36 |
vbl = p->tcol->offset; |
|
286 |
✓✗ | 108 |
maxvis = p->tcol->rmargin > vbl ? |
287 |
36 |
p->tcol->rmargin - vbl : 0; |
|
288 |
✓✗ | 108 |
bp = !(p->flags & TERMP_NOBREAK) ? maxvis : |
289 |
p->maxrmargin > vbl ? p->maxrmargin - vbl : 0; |
||
290 |
} |
||
291 |
|||
292 |
/* |
||
293 |
* If there was trailing white space, it was not printed; |
||
294 |
* so reset the cursor position accordingly. |
||
295 |
*/ |
||
296 |
|||
297 |
✓✓ | 186851 |
if (vis > vbl) |
298 |
186275 |
vis -= vbl; |
|
299 |
else |
||
300 |
vis = 0; |
||
301 |
|||
302 |
186851 |
p->col = p->tcol->col = p->tcol->lastcol = 0; |
|
303 |
186851 |
p->minbl = p->trailspace; |
|
304 |
186851 |
p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD); |
|
305 |
|||
306 |
✓✓ | 186851 |
if (p->flags & TERMP_MULTICOL) |
307 |
55188 |
return; |
|
308 |
|||
309 |
/* Trailing whitespace is significant in some columns. */ |
||
310 |
|||
311 |
✓✓✓✓ |
131897 |
if (vis && vbl && (TERMP_BRTRSP & p->flags)) |
312 |
99 |
vis += vbl; |
|
313 |
|||
314 |
/* If the column was overrun, break the line. */ |
||
315 |
✓✓✓✓ |
171101 |
if ((p->flags & TERMP_NOBREAK) == 0 || |
316 |
✓✓ | 41238 |
((p->flags & TERMP_HANG) == 0 && |
317 |
39438 |
vis + p->trailspace * (*p->width)(p, ' ') > maxvis)) |
|
318 |
100314 |
endline(p); |
|
319 |
318649 |
} |
|
320 |
|||
321 |
static void |
||
322 |
endline(struct termp *p) |
||
323 |
{ |
||
324 |
✗✓ | 215000 |
if ((p->flags & (TERMP_NEWMC | TERMP_ENDMC)) == TERMP_ENDMC) { |
325 |
p->mc = NULL; |
||
326 |
p->flags &= ~TERMP_ENDMC; |
||
327 |
} |
||
328 |
✗✓ | 107500 |
if (p->mc != NULL) { |
329 |
if (p->viscol && p->maxrmargin >= p->viscol) |
||
330 |
(*p->advance)(p, p->maxrmargin - p->viscol + 1); |
||
331 |
p->flags |= TERMP_NOBUF | TERMP_NOSPACE; |
||
332 |
term_word(p, p->mc); |
||
333 |
p->flags &= ~(TERMP_NOBUF | TERMP_NEWMC); |
||
334 |
} |
||
335 |
107500 |
p->viscol = 0; |
|
336 |
107500 |
p->minbl = 0; |
|
337 |
107500 |
(*p->endline)(p); |
|
338 |
107500 |
} |
|
339 |
|||
340 |
/* |
||
341 |
* A newline only breaks an existing line; it won't assert vertical |
||
342 |
* space. All data in the output buffer is flushed prior to the newline |
||
343 |
* assertion. |
||
344 |
*/ |
||
345 |
void |
||
346 |
term_newln(struct termp *p) |
||
347 |
{ |
||
348 |
|||
349 |
256892 |
p->flags |= TERMP_NOSPACE; |
|
350 |
✓✓✓✓ |
198937 |
if (p->tcol->lastcol || p->viscol) |
351 |
58171 |
term_flushln(p); |
|
352 |
128446 |
} |
|
353 |
|||
354 |
/* |
||
355 |
* Asserts a vertical space (a full, empty line-break between lines). |
||
356 |
* Note that if used twice, this will cause two blank spaces and so on. |
||
357 |
* All data in the output buffer is flushed prior to the newline |
||
358 |
* assertion. |
||
359 |
*/ |
||
360 |
void |
||
361 |
term_vspace(struct termp *p) |
||
362 |
{ |
||
363 |
|||
364 |
99396 |
term_newln(p); |
|
365 |
49698 |
p->viscol = 0; |
|
366 |
49698 |
p->minbl = 0; |
|
367 |
✓✓ | 49698 |
if (0 < p->skipvsp) |
368 |
6885 |
p->skipvsp--; |
|
369 |
else |
||
370 |
42813 |
(*p->endline)(p); |
|
371 |
49698 |
} |
|
372 |
|||
373 |
/* Swap current and previous font; for \fP and .ft P */ |
||
374 |
void |
||
375 |
term_fontlast(struct termp *p) |
||
376 |
{ |
||
377 |
enum termfont f; |
||
378 |
|||
379 |
1962 |
f = p->fontl; |
|
380 |
981 |
p->fontl = p->fontq[p->fonti]; |
|
381 |
981 |
p->fontq[p->fonti] = f; |
|
382 |
981 |
} |
|
383 |
|||
384 |
/* Set font, save current, discard previous; for \f, .ft, .B etc. */ |
||
385 |
void |
||
386 |
term_fontrepl(struct termp *p, enum termfont f) |
||
387 |
{ |
||
388 |
|||
389 |
291106 |
p->fontl = p->fontq[p->fonti]; |
|
390 |
145553 |
p->fontq[p->fonti] = f; |
|
391 |
145553 |
} |
|
392 |
|||
393 |
/* Set font, save previous. */ |
||
394 |
void |
||
395 |
term_fontpush(struct termp *p, enum termfont f) |
||
396 |
{ |
||
397 |
|||
398 |
53450 |
p->fontl = p->fontq[p->fonti]; |
|
399 |
✗✓ | 26725 |
if (++p->fonti == p->fontsz) { |
400 |
p->fontsz += 8; |
||
401 |
p->fontq = mandoc_reallocarray(p->fontq, |
||
402 |
p->fontsz, sizeof(*p->fontq)); |
||
403 |
} |
||
404 |
26725 |
p->fontq[p->fonti] = f; |
|
405 |
26725 |
} |
|
406 |
|||
407 |
/* Flush to make the saved pointer current again. */ |
||
408 |
void |
||
409 |
term_fontpopq(struct termp *p, int i) |
||
410 |
{ |
||
411 |
|||
412 |
✗✓ | 440512 |
assert(i >= 0); |
413 |
✓✓ | 220256 |
if (p->fonti > i) |
414 |
21361 |
p->fonti = i; |
|
415 |
220256 |
} |
|
416 |
|||
417 |
/* Pop one font off the stack. */ |
||
418 |
void |
||
419 |
term_fontpop(struct termp *p) |
||
420 |
{ |
||
421 |
|||
422 |
✗✓ | 10728 |
assert(p->fonti); |
423 |
5364 |
p->fonti--; |
|
424 |
5364 |
} |
|
425 |
|||
426 |
/* |
||
427 |
* Handle pwords, partial words, which may be either a single word or a |
||
428 |
* phrase that cannot be broken down (such as a literal string). This |
||
429 |
* handles word styling. |
||
430 |
*/ |
||
431 |
void |
||
432 |
term_word(struct termp *p, const char *word) |
||
433 |
{ |
||
434 |
508834 |
struct roffsu su; |
|
435 |
const char nbrsp[2] = { ASCII_NBRSP, 0 }; |
||
436 |
508834 |
const char *seq, *cp; |
|
437 |
508834 |
int sz, uc; |
|
438 |
508834 |
size_t csz, lsz, ssz; |
|
439 |
enum mandoc_esc esc; |
||
440 |
|||
441 |
✓✗ | 508834 |
if ((p->flags & TERMP_NOBUF) == 0) { |
442 |
✓✓ | 508834 |
if ((p->flags & TERMP_NOSPACE) == 0) { |
443 |
✓✓ | 54974 |
if ((p->flags & TERMP_KEEP) == 0) { |
444 |
50530 |
bufferc(p, ' '); |
|
445 |
✓✓ | 50530 |
if (p->flags & TERMP_SENTENCE) |
446 |
1927 |
bufferc(p, ' '); |
|
447 |
} else |
||
448 |
4444 |
bufferc(p, ASCII_NBRSP); |
|
449 |
} |
||
450 |
✓✓ | 508834 |
if (p->flags & TERMP_PREKEEP) |
451 |
7521 |
p->flags |= TERMP_KEEP; |
|
452 |
1017668 |
if (p->flags & TERMP_NONOSPACE) |
|
453 |
508834 |
p->flags |= TERMP_NOSPACE; |
|
454 |
else |
||
455 |
508834 |
p->flags &= ~TERMP_NOSPACE; |
|
456 |
508834 |
p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE); |
|
457 |
508834 |
p->skipvsp = 0; |
|
458 |
508834 |
} |
|
459 |
|||
460 |
✓✓ | 1094388 |
while ('\0' != *word) { |
461 |
✓✓ | 585554 |
if ('\\' != *word) { |
462 |
✓✓ | 522924 |
if (TERMP_NBRWORD & p->flags) { |
463 |
✓✓ | 1512 |
if (' ' == *word) { |
464 |
495 |
encode(p, nbrsp, 1); |
|
465 |
495 |
word++; |
|
466 |
495 |
continue; |
|
467 |
} |
||
468 |
1017 |
ssz = strcspn(word, "\\ "); |
|
469 |
1017 |
} else |
|
470 |
521412 |
ssz = strcspn(word, "\\"); |
|
471 |
522429 |
encode(p, word, ssz); |
|
472 |
522429 |
word += (int)ssz; |
|
473 |
522429 |
continue; |
|
474 |
} |
||
475 |
|||
476 |
62630 |
word++; |
|
477 |
62630 |
esc = mandoc_escape(&word, &seq, &sz); |
|
478 |
✓✓ | 62630 |
if (ESCAPE_ERROR == esc) |
479 |
continue; |
||
480 |
|||
481 |
✓✓✓✓ ✓✓✓✗ ✓✓✓✓ ✓✓✓✓ |
1090066 |
switch (esc) { |
482 |
case ESCAPE_UNICODE: |
||
483 |
6930 |
uc = mchars_num2uc(seq + 1, sz - 1); |
|
484 |
6930 |
break; |
|
485 |
case ESCAPE_NUMBERED: |
||
486 |
729 |
uc = mchars_num2char(seq, sz); |
|
487 |
✓✓ | 729 |
if (uc < 0) |
488 |
continue; |
||
489 |
break; |
||
490 |
case ESCAPE_SPECIAL: |
||
491 |
✓✓ | 28088 |
if (p->enc == TERMENC_ASCII) { |
492 |
24290 |
cp = mchars_spec2str(seq, sz, &ssz); |
|
493 |
✓✓ | 24290 |
if (cp != NULL) |
494 |
24146 |
encode(p, cp, ssz); |
|
495 |
} else { |
||
496 |
3798 |
uc = mchars_spec2cp(seq, sz); |
|
497 |
✓✓ | 3798 |
if (uc > 0) |
498 |
3618 |
encode1(p, uc); |
|
499 |
} |
||
500 |
continue; |
||
501 |
case ESCAPE_FONTBOLD: |
||
502 |
7074 |
term_fontrepl(p, TERMFONT_BOLD); |
|
503 |
7074 |
continue; |
|
504 |
case ESCAPE_FONTITALIC: |
||
505 |
4923 |
term_fontrepl(p, TERMFONT_UNDER); |
|
506 |
4923 |
continue; |
|
507 |
case ESCAPE_FONTBI: |
||
508 |
18 |
term_fontrepl(p, TERMFONT_BI); |
|
509 |
18 |
continue; |
|
510 |
case ESCAPE_FONT: |
||
511 |
case ESCAPE_FONTROMAN: |
||
512 |
13401 |
term_fontrepl(p, TERMFONT_NONE); |
|
513 |
13401 |
continue; |
|
514 |
case ESCAPE_FONTPREV: |
||
515 |
927 |
term_fontlast(p); |
|
516 |
927 |
continue; |
|
517 |
case ESCAPE_BREAK: |
||
518 |
36 |
bufferc(p, '\n'); |
|
519 |
36 |
continue; |
|
520 |
case ESCAPE_NOSPACE: |
||
521 |
✓✓ | 63 |
if (p->flags & TERMP_BACKAFTER) |
522 |
9 |
p->flags &= ~TERMP_BACKAFTER; |
|
523 |
✗✓ | 54 |
else if (*word == '\0') |
524 |
54 |
p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE); |
|
525 |
continue; |
||
526 |
case ESCAPE_HORIZ: |
||
527 |
✓✓ | 63 |
if (*seq == '|') { |
528 |
9 |
seq++; |
|
529 |
9 |
uc = -p->col; |
|
530 |
9 |
} else |
|
531 |
uc = 0; |
||
532 |
✗✓ | 63 |
if (a2roffsu(seq, &su, SCALE_EM) == NULL) |
533 |
continue; |
||
534 |
63 |
uc += term_hen(p, &su); |
|
535 |
✓✓ | 63 |
if (uc > 0) |
536 |
✓✓ | 72 |
while (uc-- > 0) |
537 |
27 |
bufferc(p, ASCII_NBRSP); |
|
538 |
✓✗ | 45 |
else if (p->col > (size_t)(-uc)) |
539 |
45 |
p->col += uc; |
|
540 |
else { |
||
541 |
uc += p->col; |
||
542 |
p->col = 0; |
||
543 |
if (p->tcol->offset > (size_t)(-uc)) { |
||
544 |
p->ti += uc; |
||
545 |
p->tcol->offset += uc; |
||
546 |
} else { |
||
547 |
p->ti -= p->tcol->offset; |
||
548 |
p->tcol->offset = 0; |
||
549 |
} |
||
550 |
} |
||
551 |
continue; |
||
552 |
case ESCAPE_HLINE: |
||
553 |
✗✓ | 63 |
if ((cp = a2roffsu(seq, &su, SCALE_EM)) == NULL) |
554 |
continue; |
||
555 |
63 |
uc = term_hen(p, &su); |
|
556 |
✗✓ | 63 |
if (uc <= 0) { |
557 |
if (p->tcol->rmargin <= p->tcol->offset) |
||
558 |
continue; |
||
559 |
lsz = p->tcol->rmargin - p->tcol->offset; |
||
560 |
} else |
||
561 |
63 |
lsz = uc; |
|
562 |
✓✓ | 63 |
if (*cp == seq[-1]) |
563 |
18 |
uc = -1; |
|
564 |
✓✓ | 45 |
else if (*cp == '\\') { |
565 |
18 |
seq = cp + 1; |
|
566 |
18 |
esc = mandoc_escape(&seq, &cp, &sz); |
|
567 |
✗✗✓✗ |
18 |
switch (esc) { |
568 |
case ESCAPE_UNICODE: |
||
569 |
uc = mchars_num2uc(cp + 1, sz - 1); |
||
570 |
break; |
||
571 |
case ESCAPE_NUMBERED: |
||
572 |
uc = mchars_num2char(cp, sz); |
||
573 |
break; |
||
574 |
case ESCAPE_SPECIAL: |
||
575 |
18 |
uc = mchars_spec2cp(cp, sz); |
|
576 |
18 |
break; |
|
577 |
default: |
||
578 |
uc = -1; |
||
579 |
break; |
||
580 |
} |
||
581 |
} else |
||
582 |
uc = *cp; |
||
583 |
✓✓✗✓ |
108 |
if (uc < 0x20 || (uc > 0x7E && uc < 0xA0)) |
584 |
18 |
uc = '_'; |
|
585 |
✓✗ | 63 |
if (p->enc == TERMENC_ASCII) { |
586 |
63 |
cp = ascii_uc2str(uc); |
|
587 |
63 |
csz = term_strlen(p, cp); |
|
588 |
63 |
ssz = strlen(cp); |
|
589 |
63 |
} else |
|
590 |
csz = (*p->width)(p, uc); |
||
591 |
✓✓ | 549 |
while (lsz >= csz) { |
592 |
✓✗ | 243 |
if (p->enc == TERMENC_ASCII) |
593 |
243 |
encode(p, cp, ssz); |
|
594 |
else |
||
595 |
encode1(p, uc); |
||
596 |
243 |
lsz -= csz; |
|
597 |
} |
||
598 |
continue; |
||
599 |
case ESCAPE_SKIPCHAR: |
||
600 |
81 |
p->flags |= TERMP_BACKAFTER; |
|
601 |
81 |
continue; |
|
602 |
case ESCAPE_OVERSTRIKE: |
||
603 |
63 |
cp = seq + sz; |
|
604 |
✓✓ | 243 |
while (seq < cp) { |
605 |
✗✓ | 117 |
if (*seq == '\\') { |
606 |
mandoc_escape(&seq, NULL, NULL); |
||
607 |
continue; |
||
608 |
} |
||
609 |
117 |
encode1(p, *seq++); |
|
610 |
✓✓ | 117 |
if (seq < cp) { |
611 |
63 |
if (p->flags & TERMP_BACKBEFORE) |
|
612 |
p->flags |= TERMP_BACKAFTER; |
||
613 |
else |
||
614 |
p->flags |= TERMP_BACKBEFORE; |
||
615 |
63 |
} |
|
616 |
} |
||
617 |
/* Trim trailing backspace/blank pair. */ |
||
618 |
✓✗✗✓ |
126 |
if (p->tcol->lastcol > 2 && |
619 |
✓✗ | 63 |
(p->tcol->buf[p->tcol->lastcol - 1] == ' ' || |
620 |
63 |
p->tcol->buf[p->tcol->lastcol - 1] == '\t')) |
|
621 |
p->tcol->lastcol -= 2; |
||
622 |
✓✗ | 63 |
if (p->col > p->tcol->lastcol) |
623 |
p->col = p->tcol->lastcol; |
||
624 |
continue; |
||
625 |
default: |
||
626 |
continue; |
||
627 |
} |
||
628 |
|||
629 |
/* |
||
630 |
* Common handling for Unicode and numbered |
||
631 |
* character escape sequences. |
||
632 |
*/ |
||
633 |
|||
634 |
✓✓ | 7623 |
if (p->enc == TERMENC_ASCII) { |
635 |
3762 |
cp = ascii_uc2str(uc); |
|
636 |
3762 |
encode(p, cp, strlen(cp)); |
|
637 |
3762 |
} else { |
|
638 |
✓✓ | 3861 |
if ((uc < 0x20 && uc != 0x09) || |
639 |
✓✓ | 3681 |
(uc > 0x7E && uc < 0xA0)) |
640 |
342 |
uc = 0xFFFD; |
|
641 |
3861 |
encode1(p, uc); |
|
642 |
} |
||
643 |
} |
||
644 |
508834 |
p->flags &= ~TERMP_NBRWORD; |
|
645 |
508834 |
} |
|
646 |
|||
647 |
static void |
||
648 |
adjbuf(struct termp_col *c, size_t sz) |
||
649 |
{ |
||
650 |
✓✓ | 14520 |
if (c->maxcols == 0) |
651 |
7259 |
c->maxcols = 1024; |
|
652 |
✓✓ | 7262 |
while (c->maxcols <= sz) |
653 |
1 |
c->maxcols <<= 2; |
|
654 |
7260 |
c->buf = mandoc_reallocarray(c->buf, c->maxcols, sizeof(*c->buf)); |
|
655 |
7260 |
} |
|
656 |
|||
657 |
static void |
||
658 |
bufferc(struct termp *p, char c) |
||
659 |
{ |
||
660 |
✗✓ | 113928 |
if (p->flags & TERMP_NOBUF) { |
661 |
(*p->letter)(p, c); |
||
662 |
return; |
||
663 |
} |
||
664 |
✗✓ | 56964 |
if (p->col + 1 >= p->tcol->maxcols) |
665 |
adjbuf(p->tcol, p->col + 1); |
||
666 |
✗✓✗✗ ✗✗ |
56964 |
if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) |
667 |
56964 |
p->tcol->buf[p->col] = c; |
|
668 |
✓✗ | 56964 |
if (p->tcol->lastcol < ++p->col) |
669 |
56964 |
p->tcol->lastcol = p->col; |
|
670 |
56964 |
} |
|
671 |
|||
672 |
/* |
||
673 |
* See encode(). |
||
674 |
* Do this for a single (probably unicode) value. |
||
675 |
* Does not check for non-decorated glyphs. |
||
676 |
*/ |
||
677 |
static void |
||
678 |
encode1(struct termp *p, int c) |
||
679 |
{ |
||
680 |
enum termfont f; |
||
681 |
|||
682 |
✗✓ | 4902128 |
if (p->flags & TERMP_NOBUF) { |
683 |
(*p->letter)(p, c); |
||
684 |
return; |
||
685 |
} |
||
686 |
|||
687 |
✓✓ | 2451064 |
if (p->col + 7 >= p->tcol->maxcols) |
688 |
9 |
adjbuf(p->tcol, p->col + 7); |
|
689 |
|||
690 |
✓✓✓✓ |
9791836 |
f = (c == ASCII_HYPH || c > 127 || isgraph(c)) ? |
691 |
2451046 |
p->fontq[p->fonti] : TERMFONT_NONE; |
|
692 |
|||
693 |
✓✓ | 2451064 |
if (p->flags & TERMP_BACKBEFORE) { |
694 |
✓✗✗✓ |
234 |
if (p->tcol->buf[p->col - 1] == ' ' || |
695 |
117 |
p->tcol->buf[p->col - 1] == '\t') |
|
696 |
p->col--; |
||
697 |
else |
||
698 |
117 |
p->tcol->buf[p->col++] = '\b'; |
|
699 |
117 |
p->flags &= ~TERMP_BACKBEFORE; |
|
700 |
117 |
} |
|
701 |
✓✓ | 2451064 |
if (f == TERMFONT_UNDER || f == TERMFONT_BI) { |
702 |
72920 |
p->tcol->buf[p->col++] = '_'; |
|
703 |
72920 |
p->tcol->buf[p->col++] = '\b'; |
|
704 |
72920 |
} |
|
705 |
✓✓ | 2451064 |
if (f == TERMFONT_BOLD || f == TERMFONT_BI) { |
706 |
✓✓ | 215863 |
if (c == ASCII_HYPH) |
707 |
2232 |
p->tcol->buf[p->col++] = '-'; |
|
708 |
else |
||
709 |
213631 |
p->tcol->buf[p->col++] = c; |
|
710 |
215863 |
p->tcol->buf[p->col++] = '\b'; |
|
711 |
215863 |
} |
|
712 |
✗✓✗✗ |
2451064 |
if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) |
713 |
2451064 |
p->tcol->buf[p->col] = c; |
|
714 |
✓✗ | 2451064 |
if (p->tcol->lastcol < ++p->col) |
715 |
2451064 |
p->tcol->lastcol = p->col; |
|
716 |
✓✓ | 2451064 |
if (p->flags & TERMP_BACKAFTER) { |
717 |
72 |
p->flags |= TERMP_BACKBEFORE; |
|
718 |
72 |
p->flags &= ~TERMP_BACKAFTER; |
|
719 |
72 |
} |
|
720 |
4902128 |
} |
|
721 |
|||
722 |
static void |
||
723 |
encode(struct termp *p, const char *word, size_t sz) |
||
724 |
{ |
||
725 |
size_t i; |
||
726 |
|||
727 |
✗✓ | 1102150 |
if (p->flags & TERMP_NOBUF) { |
728 |
for (i = 0; i < sz; i++) |
||
729 |
(*p->letter)(p, word[i]); |
||
730 |
return; |
||
731 |
} |
||
732 |
|||
733 |
✓✓ | 551075 |
if (p->col + 2 + (sz * 5) >= p->tcol->maxcols) |
734 |
7251 |
adjbuf(p->tcol, p->col + 2 + (sz * 5)); |
|
735 |
|||
736 |
✓✓ | 6623958 |
for (i = 0; i < sz; i++) { |
737 |
✓✓✓✓ |
5516093 |
if (ASCII_HYPH == word[i] || |
738 |
2755189 |
isgraph((unsigned char)word[i])) |
|
739 |
2443468 |
encode1(p, word[i]); |
|
740 |
else { |
||
741 |
✗✓✗✗ |
317436 |
if (p->tcol->lastcol <= p->col || |
742 |
(word[i] != ' ' && word[i] != ASCII_NBRSP)) |
||
743 |
317436 |
p->tcol->buf[p->col] = word[i]; |
|
744 |
317436 |
p->col++; |
|
745 |
|||
746 |
/* |
||
747 |
* Postpone the effect of \z while handling |
||
748 |
* an overstrike sequence from ascii_uc2str(). |
||
749 |
*/ |
||
750 |
|||
751 |
✓✓✗✓ |
319965 |
if (word[i] == '\b' && |
752 |
2529 |
(p->flags & TERMP_BACKBEFORE)) { |
|
753 |
p->flags &= ~TERMP_BACKBEFORE; |
||
754 |
p->flags |= TERMP_BACKAFTER; |
||
755 |
} |
||
756 |
} |
||
757 |
} |
||
758 |
✓✓ | 551075 |
if (p->tcol->lastcol < p->col) |
759 |
24375 |
p->tcol->lastcol = p->col; |
|
760 |
1102150 |
} |
|
761 |
|||
762 |
void |
||
763 |
term_setwidth(struct termp *p, const char *wstr) |
||
764 |
{ |
||
765 |
180 |
struct roffsu su; |
|
766 |
int iop, width; |
||
767 |
|||
768 |
iop = 0; |
||
769 |
width = 0; |
||
770 |
✓✓ | 90 |
if (NULL != wstr) { |
771 |
✓✗✓ | 90 |
switch (*wstr) { |
772 |
case '+': |
||
773 |
iop = 1; |
||
774 |
18 |
wstr++; |
|
775 |
18 |
break; |
|
776 |
case '-': |
||
777 |
iop = -1; |
||
778 |
wstr++; |
||
779 |
break; |
||
780 |
default: |
||
781 |
break; |
||
782 |
} |
||
783 |
✓✓ | 72 |
if (a2roffsu(wstr, &su, SCALE_MAX) != NULL) |
784 |
54 |
width = term_hspan(p, &su); |
|
785 |
else |
||
786 |
iop = 0; |
||
787 |
} |
||
788 |
90 |
(*p->setwidth)(p, iop, width); |
|
789 |
90 |
} |
|
790 |
|||
791 |
size_t |
||
792 |
term_len(const struct termp *p, size_t sz) |
||
793 |
{ |
||
794 |
|||
795 |
138078 |
return (*p->width)(p, ' ') * sz; |
|
796 |
} |
||
797 |
|||
798 |
static size_t |
||
799 |
cond_width(const struct termp *p, int c, int *skip) |
||
800 |
{ |
||
801 |
|||
802 |
✗✓ | 1854396 |
if (*skip) { |
803 |
(*skip) = 0; |
||
804 |
return 0; |
||
805 |
} else |
||
806 |
927198 |
return (*p->width)(p, c); |
|
807 |
927198 |
} |
|
808 |
|||
809 |
size_t |
||
810 |
term_strlen(const struct termp *p, const char *cp) |
||
811 |
{ |
||
812 |
347450 |
size_t sz, rsz, i; |
|
813 |
347450 |
int ssz, skip, uc; |
|
814 |
347450 |
const char *seq, *rhs; |
|
815 |
enum mandoc_esc esc; |
||
816 |
static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH, |
||
817 |
ASCII_BREAK, '\0' }; |
||
818 |
|||
819 |
/* |
||
820 |
* Account for escaped sequences within string length |
||
821 |
* calculations. This follows the logic in term_word() as we |
||
822 |
* must calculate the width of produced strings. |
||
823 |
*/ |
||
824 |
|||
825 |
sz = 0; |
||
826 |
347450 |
skip = 0; |
|
827 |
✓✓ | 1043151 |
while ('\0' != *cp) { |
828 |
348251 |
rsz = strcspn(cp, rej); |
|
829 |
✓✓ | 2352250 |
for (i = 0; i < rsz; i++) |
830 |
827874 |
sz += cond_width(p, *cp++, &skip); |
|
831 |
|||
832 |
✓✓✓✗ |
787325 |
switch (*cp) { |
833 |
case '\\': |
||
834 |
1566 |
cp++; |
|
835 |
1566 |
esc = mandoc_escape(&cp, &seq, &ssz); |
|
836 |
✗✓ | 1566 |
if (ESCAPE_ERROR == esc) |
837 |
continue; |
||
838 |
|||
839 |
rhs = NULL; |
||
840 |
|||
841 |
✓✓✗✓ ✗✗ |
3726 |
switch (esc) { |
842 |
case ESCAPE_UNICODE: |
||
843 |
1296 |
uc = mchars_num2uc(seq + 1, ssz - 1); |
|
844 |
1296 |
break; |
|
845 |
case ESCAPE_NUMBERED: |
||
846 |
uc = mchars_num2char(seq, ssz); |
||
847 |
if (uc < 0) |
||
848 |
continue; |
||
849 |
break; |
||
850 |
case ESCAPE_SPECIAL: |
||
851 |
✓✓ | 252 |
if (p->enc == TERMENC_ASCII) { |
852 |
126 |
rhs = mchars_spec2str(seq, ssz, &rsz); |
|
853 |
✓✗ | 126 |
if (rhs != NULL) |
854 |
break; |
||
855 |
} else { |
||
856 |
126 |
uc = mchars_spec2cp(seq, ssz); |
|
857 |
✓✗ | 126 |
if (uc > 0) |
858 |
sz += cond_width(p, uc, &skip); |
||
859 |
} |
||
860 |
continue; |
||
861 |
case ESCAPE_SKIPCHAR: |
||
862 |
skip = 1; |
||
863 |
continue; |
||
864 |
case ESCAPE_OVERSTRIKE: |
||
865 |
rsz = 0; |
||
866 |
rhs = seq + ssz; |
||
867 |
while (seq < rhs) { |
||
868 |
if (*seq == '\\') { |
||
869 |
mandoc_escape(&seq, NULL, NULL); |
||
870 |
continue; |
||
871 |
} |
||
872 |
i = (*p->width)(p, *seq++); |
||
873 |
if (rsz < i) |
||
874 |
rsz = i; |
||
875 |
} |
||
876 |
sz += rsz; |
||
877 |
continue; |
||
878 |
default: |
||
879 |
continue; |
||
880 |
} |
||
881 |
|||
882 |
/* |
||
883 |
* Common handling for Unicode and numbered |
||
884 |
* character escape sequences. |
||
885 |
*/ |
||
886 |
|||
887 |
✓✗ | 1296 |
if (rhs == NULL) { |
888 |
✓✓ | 1296 |
if (p->enc == TERMENC_ASCII) { |
889 |
648 |
rhs = ascii_uc2str(uc); |
|
890 |
648 |
rsz = strlen(rhs); |
|
891 |
} else { |
||
892 |
✓✓ | 648 |
if ((uc < 0x20 && uc != 0x09) || |
893 |
✓✓ | 612 |
(uc > 0x7E && uc < 0xA0)) |
894 |
90 |
uc = 0xFFFD; |
|
895 |
648 |
sz += cond_width(p, uc, &skip); |
|
896 |
648 |
continue; |
|
897 |
} |
||
898 |
648 |
} |
|
899 |
|||
900 |
✗✓ | 648 |
if (skip) { |
901 |
skip = 0; |
||
902 |
break; |
||
903 |
} |
||
904 |
|||
905 |
/* |
||
906 |
* Common handling for all escape sequences |
||
907 |
* printing more than one character. |
||
908 |
*/ |
||
909 |
|||
910 |
✓✓ | 5436 |
for (i = 0; i < rsz; i++) |
911 |
2070 |
sz += (*p->width)(p, *rhs++); |
|
912 |
break; |
||
913 |
case ASCII_NBRSP: |
||
914 |
98676 |
sz += cond_width(p, ' ', &skip); |
|
915 |
98676 |
cp++; |
|
916 |
98676 |
break; |
|
917 |
case ASCII_HYPH: |
||
918 |
sz += cond_width(p, '-', &skip); |
||
919 |
cp++; |
||
920 |
break; |
||
921 |
default: |
||
922 |
break; |
||
923 |
} |
||
924 |
} |
||
925 |
|||
926 |
347450 |
return sz; |
|
927 |
347450 |
} |
|
928 |
|||
929 |
int |
||
930 |
term_vspan(const struct termp *p, const struct roffsu *su) |
||
931 |
{ |
||
932 |
double r; |
||
933 |
int ri; |
||
934 |
|||
935 |
✓✓✗✓ ✗✓✓✗ ✓✓✗ |
6534 |
switch (su->unit) { |
936 |
case SCALE_BU: |
||
937 |
36 |
r = su->scale / 40.0; |
|
938 |
36 |
break; |
|
939 |
case SCALE_CM: |
||
940 |
27 |
r = su->scale * 6.0 / 2.54; |
|
941 |
27 |
break; |
|
942 |
case SCALE_FS: |
||
943 |
r = su->scale * 65536.0 / 40.0; |
||
944 |
break; |
||
945 |
case SCALE_IN: |
||
946 |
18 |
r = su->scale * 6.0; |
|
947 |
18 |
break; |
|
948 |
case SCALE_MM: |
||
949 |
r = su->scale * 0.006; |
||
950 |
break; |
||
951 |
case SCALE_PC: |
||
952 |
36 |
r = su->scale; |
|
953 |
36 |
break; |
|
954 |
case SCALE_PT: |
||
955 |
45 |
r = su->scale / 12.0; |
|
956 |
45 |
break; |
|
957 |
case SCALE_EN: |
||
958 |
case SCALE_EM: |
||
959 |
54 |
r = su->scale * 0.6; |
|
960 |
54 |
break; |
|
961 |
case SCALE_VS: |
||
962 |
3051 |
r = su->scale; |
|
963 |
3051 |
break; |
|
964 |
default: |
||
965 |
abort(); |
||
966 |
} |
||
967 |
3267 |
ri = r > 0.0 ? r + 0.4995 : r - 0.4995; |
|
968 |
3267 |
return ri < 66 ? ri : 1; |
|
969 |
} |
||
970 |
|||
971 |
/* |
||
972 |
* Convert a scaling width to basic units, rounding towards 0. |
||
973 |
*/ |
||
974 |
int |
||
975 |
term_hspan(const struct termp *p, const struct roffsu *su) |
||
976 |
{ |
||
977 |
|||
978 |
108 |
return (*p->hspan)(p, su); |
|
979 |
} |
||
980 |
|||
981 |
/* |
||
982 |
* Convert a scaling width to basic units, rounding to closest. |
||
983 |
*/ |
||
984 |
int |
||
985 |
term_hen(const struct termp *p, const struct roffsu *su) |
||
986 |
{ |
||
987 |
int bu; |
||
988 |
|||
989 |
✓✓ | 71916 |
if ((bu = (*p->hspan)(p, su)) >= 0) |
990 |
35175 |
return (bu + 11) / 24; |
|
991 |
else |
||
992 |
783 |
return -((-bu + 11) / 24); |
|
993 |
35958 |
} |
Generated by: GCOVR (Version 3.3) |