GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: man_term.c,v 1.162 2017/07/31 15:18:59 schwarze Exp $ */ |
||
2 |
/* |
||
3 |
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> |
||
4 |
* Copyright (c) 2010-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 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 <limits.h> |
||
23 |
#include <stdio.h> |
||
24 |
#include <stdlib.h> |
||
25 |
#include <string.h> |
||
26 |
|||
27 |
#include "mandoc_aux.h" |
||
28 |
#include "mandoc.h" |
||
29 |
#include "roff.h" |
||
30 |
#include "man.h" |
||
31 |
#include "out.h" |
||
32 |
#include "term.h" |
||
33 |
#include "main.h" |
||
34 |
|||
35 |
#define MAXMARGINS 64 /* maximum number of indented scopes */ |
||
36 |
|||
37 |
struct mtermp { |
||
38 |
int fl; |
||
39 |
#define MANT_LITERAL (1 << 0) |
||
40 |
int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */ |
||
41 |
int lmargincur; /* index of current margin */ |
||
42 |
int lmarginsz; /* actual number of nested margins */ |
||
43 |
size_t offset; /* default offset to visible page */ |
||
44 |
int pardist; /* vert. space before par., unit: [v] */ |
||
45 |
}; |
||
46 |
|||
47 |
#define DECL_ARGS struct termp *p, \ |
||
48 |
struct mtermp *mt, \ |
||
49 |
struct roff_node *n, \ |
||
50 |
const struct roff_meta *meta |
||
51 |
|||
52 |
struct termact { |
||
53 |
int (*pre)(DECL_ARGS); |
||
54 |
void (*post)(DECL_ARGS); |
||
55 |
int flags; |
||
56 |
#define MAN_NOTEXT (1 << 0) /* Never has text children. */ |
||
57 |
}; |
||
58 |
|||
59 |
static void print_man_nodelist(DECL_ARGS); |
||
60 |
static void print_man_node(DECL_ARGS); |
||
61 |
static void print_man_head(struct termp *, |
||
62 |
const struct roff_meta *); |
||
63 |
static void print_man_foot(struct termp *, |
||
64 |
const struct roff_meta *); |
||
65 |
static void print_bvspace(struct termp *, |
||
66 |
const struct roff_node *, int); |
||
67 |
|||
68 |
static int pre_B(DECL_ARGS); |
||
69 |
static int pre_DT(DECL_ARGS); |
||
70 |
static int pre_HP(DECL_ARGS); |
||
71 |
static int pre_I(DECL_ARGS); |
||
72 |
static int pre_IP(DECL_ARGS); |
||
73 |
static int pre_OP(DECL_ARGS); |
||
74 |
static int pre_PD(DECL_ARGS); |
||
75 |
static int pre_PP(DECL_ARGS); |
||
76 |
static int pre_RS(DECL_ARGS); |
||
77 |
static int pre_SH(DECL_ARGS); |
||
78 |
static int pre_SS(DECL_ARGS); |
||
79 |
static int pre_TP(DECL_ARGS); |
||
80 |
static int pre_UR(DECL_ARGS); |
||
81 |
static int pre_alternate(DECL_ARGS); |
||
82 |
static int pre_ign(DECL_ARGS); |
||
83 |
static int pre_in(DECL_ARGS); |
||
84 |
static int pre_literal(DECL_ARGS); |
||
85 |
|||
86 |
static void post_IP(DECL_ARGS); |
||
87 |
static void post_HP(DECL_ARGS); |
||
88 |
static void post_RS(DECL_ARGS); |
||
89 |
static void post_SH(DECL_ARGS); |
||
90 |
static void post_SS(DECL_ARGS); |
||
91 |
static void post_TP(DECL_ARGS); |
||
92 |
static void post_UR(DECL_ARGS); |
||
93 |
|||
94 |
static const struct termact __termacts[MAN_MAX - MAN_TH] = { |
||
95 |
{ NULL, NULL, 0 }, /* TH */ |
||
96 |
{ pre_SH, post_SH, 0 }, /* SH */ |
||
97 |
{ pre_SS, post_SS, 0 }, /* SS */ |
||
98 |
{ pre_TP, post_TP, 0 }, /* TP */ |
||
99 |
{ pre_PP, NULL, 0 }, /* LP */ |
||
100 |
{ pre_PP, NULL, 0 }, /* PP */ |
||
101 |
{ pre_PP, NULL, 0 }, /* P */ |
||
102 |
{ pre_IP, post_IP, 0 }, /* IP */ |
||
103 |
{ pre_HP, post_HP, 0 }, /* HP */ |
||
104 |
{ NULL, NULL, 0 }, /* SM */ |
||
105 |
{ pre_B, NULL, 0 }, /* SB */ |
||
106 |
{ pre_alternate, NULL, 0 }, /* BI */ |
||
107 |
{ pre_alternate, NULL, 0 }, /* IB */ |
||
108 |
{ pre_alternate, NULL, 0 }, /* BR */ |
||
109 |
{ pre_alternate, NULL, 0 }, /* RB */ |
||
110 |
{ NULL, NULL, 0 }, /* R */ |
||
111 |
{ pre_B, NULL, 0 }, /* B */ |
||
112 |
{ pre_I, NULL, 0 }, /* I */ |
||
113 |
{ pre_alternate, NULL, 0 }, /* IR */ |
||
114 |
{ pre_alternate, NULL, 0 }, /* RI */ |
||
115 |
{ pre_literal, NULL, 0 }, /* nf */ |
||
116 |
{ pre_literal, NULL, 0 }, /* fi */ |
||
117 |
{ NULL, NULL, 0 }, /* RE */ |
||
118 |
{ pre_RS, post_RS, 0 }, /* RS */ |
||
119 |
{ pre_DT, NULL, 0 }, /* DT */ |
||
120 |
{ pre_ign, NULL, MAN_NOTEXT }, /* UC */ |
||
121 |
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */ |
||
122 |
{ pre_ign, NULL, 0 }, /* AT */ |
||
123 |
{ pre_in, NULL, MAN_NOTEXT }, /* in */ |
||
124 |
{ pre_OP, NULL, 0 }, /* OP */ |
||
125 |
{ pre_literal, NULL, 0 }, /* EX */ |
||
126 |
{ pre_literal, NULL, 0 }, /* EE */ |
||
127 |
{ pre_UR, post_UR, 0 }, /* UR */ |
||
128 |
{ NULL, NULL, 0 }, /* UE */ |
||
129 |
{ pre_UR, post_UR, 0 }, /* MT */ |
||
130 |
{ NULL, NULL, 0 }, /* ME */ |
||
131 |
}; |
||
132 |
static const struct termact *termacts = __termacts - MAN_TH; |
||
133 |
|||
134 |
|||
135 |
void |
||
136 |
terminal_man(void *arg, const struct roff_man *man) |
||
137 |
{ |
||
138 |
struct termp *p; |
||
139 |
struct roff_node *n; |
||
140 |
2318 |
struct mtermp mt; |
|
141 |
size_t save_defindent; |
||
142 |
|||
143 |
1159 |
p = (struct termp *)arg; |
|
144 |
1159 |
save_defindent = p->defindent; |
|
145 |
✓✗✓✓ |
2318 |
if (p->synopsisonly == 0 && p->defindent == 0) |
146 |
526 |
p->defindent = 7; |
|
147 |
1159 |
p->tcol->rmargin = p->maxrmargin = p->defrmargin; |
|
148 |
1159 |
term_tab_set(p, NULL); |
|
149 |
1159 |
term_tab_set(p, "T"); |
|
150 |
1159 |
term_tab_set(p, ".5i"); |
|
151 |
|||
152 |
1159 |
memset(&mt, 0, sizeof(struct mtermp)); |
|
153 |
1159 |
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); |
|
154 |
1159 |
mt.offset = term_len(p, p->defindent); |
|
155 |
1159 |
mt.pardist = 1; |
|
156 |
|||
157 |
1159 |
n = man->first->child; |
|
158 |
✗✓ | 1159 |
if (p->synopsisonly) { |
159 |
while (n != NULL) { |
||
160 |
if (n->tok == MAN_SH && |
||
161 |
n->child->child->type == ROFFT_TEXT && |
||
162 |
!strcmp(n->child->child->string, "SYNOPSIS")) { |
||
163 |
if (n->child->next->child != NULL) |
||
164 |
print_man_nodelist(p, &mt, |
||
165 |
n->child->next->child, |
||
166 |
&man->meta); |
||
167 |
term_newln(p); |
||
168 |
break; |
||
169 |
} |
||
170 |
n = n->next; |
||
171 |
} |
||
172 |
} else { |
||
173 |
1159 |
term_begin(p, print_man_head, print_man_foot, &man->meta); |
|
174 |
1159 |
p->flags |= TERMP_NOSPACE; |
|
175 |
✓✓ | 1159 |
if (n != NULL) |
176 |
1153 |
print_man_nodelist(p, &mt, n, &man->meta); |
|
177 |
1159 |
term_end(p); |
|
178 |
} |
||
179 |
1159 |
p->defindent = save_defindent; |
|
180 |
1159 |
} |
|
181 |
|||
182 |
/* |
||
183 |
* Printing leading vertical space before a block. |
||
184 |
* This is used for the paragraph macros. |
||
185 |
* The rules are pretty simple, since there's very little nesting going |
||
186 |
* on here. Basically, if we're the first within another block (SS/SH), |
||
187 |
* then don't emit vertical space. If we are (RS), then do. If not the |
||
188 |
* first, print it. |
||
189 |
*/ |
||
190 |
static void |
||
191 |
print_bvspace(struct termp *p, const struct roff_node *n, int pardist) |
||
192 |
{ |
||
193 |
int i; |
||
194 |
|||
195 |
5022 |
term_newln(p); |
|
196 |
|||
197 |
✓✗✓✓ |
5022 |
if (n->body && n->body->child) |
198 |
✗✓ | 2478 |
if (n->body->child->type == ROFFT_TBL) |
199 |
return; |
||
200 |
|||
201 |
✓✓✓✓ |
5010 |
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) |
202 |
✓✓ | 2370 |
if (NULL == n->prev) |
203 |
126 |
return; |
|
204 |
|||
205 |
✓✓ | 8784 |
for (i = 0; i < pardist; i++) |
206 |
2007 |
term_vspace(p); |
|
207 |
4896 |
} |
|
208 |
|||
209 |
|||
210 |
static int |
||
211 |
pre_ign(DECL_ARGS) |
||
212 |
{ |
||
213 |
|||
214 |
return 0; |
||
215 |
} |
||
216 |
|||
217 |
static int |
||
218 |
pre_I(DECL_ARGS) |
||
219 |
{ |
||
220 |
|||
221 |
term_fontrepl(p, TERMFONT_UNDER); |
||
222 |
return 1; |
||
223 |
} |
||
224 |
|||
225 |
static int |
||
226 |
pre_literal(DECL_ARGS) |
||
227 |
{ |
||
228 |
|||
229 |
834 |
term_newln(p); |
|
230 |
|||
231 |
✓✓✓✓ |
636 |
if (n->tok == MAN_nf || n->tok == MAN_EX) |
232 |
219 |
mt->fl |= MANT_LITERAL; |
|
233 |
else |
||
234 |
198 |
mt->fl &= ~MANT_LITERAL; |
|
235 |
|||
236 |
/* |
||
237 |
* Unlike .IP and .TP, .HP does not have a HEAD. |
||
238 |
* So in case a second call to term_flushln() is needed, |
||
239 |
* indentation has to be set up explicitly. |
||
240 |
*/ |
||
241 |
✓✓✓✗ |
423 |
if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) { |
242 |
6 |
p->tcol->offset = p->tcol->rmargin; |
|
243 |
6 |
p->tcol->rmargin = p->maxrmargin; |
|
244 |
6 |
p->trailspace = 0; |
|
245 |
6 |
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); |
|
246 |
6 |
p->flags |= TERMP_NOSPACE; |
|
247 |
6 |
} |
|
248 |
|||
249 |
417 |
return 0; |
|
250 |
} |
||
251 |
|||
252 |
static int |
||
253 |
pre_PD(DECL_ARGS) |
||
254 |
{ |
||
255 |
684 |
struct roffsu su; |
|
256 |
|||
257 |
342 |
n = n->child; |
|
258 |
✓✓ | 342 |
if (n == NULL) { |
259 |
126 |
mt->pardist = 1; |
|
260 |
126 |
return 0; |
|
261 |
} |
||
262 |
✗✓ | 216 |
assert(n->type == ROFFT_TEXT); |
263 |
✓✓ | 216 |
if (a2roffsu(n->string, &su, SCALE_VS) != NULL) |
264 |
213 |
mt->pardist = term_vspan(p, &su); |
|
265 |
216 |
return 0; |
|
266 |
342 |
} |
|
267 |
|||
268 |
static int |
||
269 |
pre_alternate(DECL_ARGS) |
||
270 |
{ |
||
271 |
330 |
enum termfont font[2]; |
|
272 |
struct roff_node *nn; |
||
273 |
int savelit, i; |
||
274 |
|||
275 |
✗✗✓✗ ✓✗✓ |
220 |
switch (n->tok) { |
276 |
case MAN_RB: |
||
277 |
font[0] = TERMFONT_NONE; |
||
278 |
font[1] = TERMFONT_BOLD; |
||
279 |
break; |
||
280 |
case MAN_RI: |
||
281 |
font[0] = TERMFONT_NONE; |
||
282 |
font[1] = TERMFONT_UNDER; |
||
283 |
break; |
||
284 |
case MAN_BR: |
||
285 |
font[0] = TERMFONT_BOLD; |
||
286 |
font[1] = TERMFONT_NONE; |
||
287 |
break; |
||
288 |
case MAN_BI: |
||
289 |
font[0] = TERMFONT_BOLD; |
||
290 |
font[1] = TERMFONT_UNDER; |
||
291 |
32 |
break; |
|
292 |
case MAN_IR: |
||
293 |
font[0] = TERMFONT_UNDER; |
||
294 |
font[1] = TERMFONT_NONE; |
||
295 |
break; |
||
296 |
case MAN_IB: |
||
297 |
font[0] = TERMFONT_UNDER; |
||
298 |
font[1] = TERMFONT_BOLD; |
||
299 |
78 |
break; |
|
300 |
default: |
||
301 |
abort(); |
||
302 |
} |
||
303 |
|||
304 |
110 |
savelit = MANT_LITERAL & mt->fl; |
|
305 |
110 |
mt->fl &= ~MANT_LITERAL; |
|
306 |
|||
307 |
✓✓ | 736 |
for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { |
308 |
258 |
term_fontrepl(p, font[i]); |
|
309 |
✓✓✓✓ |
306 |
if (savelit && NULL == nn->next) |
310 |
12 |
mt->fl |= MANT_LITERAL; |
|
311 |
✗✓ | 258 |
assert(nn->type == ROFFT_TEXT); |
312 |
258 |
term_word(p, nn->string); |
|
313 |
✗✓ | 258 |
if (nn->flags & NODE_EOS) |
314 |
p->flags |= TERMP_SENTENCE; |
||
315 |
✓✓ | 258 |
if (nn->next) |
316 |
148 |
p->flags |= TERMP_NOSPACE; |
|
317 |
} |
||
318 |
|||
319 |
110 |
return 0; |
|
320 |
110 |
} |
|
321 |
|||
322 |
static int |
||
323 |
pre_B(DECL_ARGS) |
||
324 |
{ |
||
325 |
|||
326 |
162 |
term_fontrepl(p, TERMFONT_BOLD); |
|
327 |
81 |
return 1; |
|
328 |
} |
||
329 |
|||
330 |
static int |
||
331 |
pre_OP(DECL_ARGS) |
||
332 |
{ |
||
333 |
|||
334 |
24 |
term_word(p, "["); |
|
335 |
12 |
p->flags |= TERMP_NOSPACE; |
|
336 |
|||
337 |
✓✓ | 12 |
if (NULL != (n = n->child)) { |
338 |
9 |
term_fontrepl(p, TERMFONT_BOLD); |
|
339 |
9 |
term_word(p, n->string); |
|
340 |
9 |
} |
|
341 |
✓✓✓✓ |
21 |
if (NULL != n && NULL != n->next) { |
342 |
6 |
term_fontrepl(p, TERMFONT_UNDER); |
|
343 |
6 |
term_word(p, n->next->string); |
|
344 |
6 |
} |
|
345 |
|||
346 |
12 |
term_fontrepl(p, TERMFONT_NONE); |
|
347 |
12 |
p->flags |= TERMP_NOSPACE; |
|
348 |
12 |
term_word(p, "]"); |
|
349 |
12 |
return 0; |
|
350 |
} |
||
351 |
|||
352 |
static int |
||
353 |
pre_in(DECL_ARGS) |
||
354 |
{ |
||
355 |
78 |
struct roffsu su; |
|
356 |
const char *cp; |
||
357 |
size_t v; |
||
358 |
int less; |
||
359 |
|||
360 |
39 |
term_newln(p); |
|
361 |
|||
362 |
✗✓ | 39 |
if (n->child == NULL) { |
363 |
p->tcol->offset = mt->offset; |
||
364 |
return 0; |
||
365 |
} |
||
366 |
|||
367 |
39 |
cp = n->child->string; |
|
368 |
less = 0; |
||
369 |
|||
370 |
✓✓ | 39 |
if ('-' == *cp) |
371 |
3 |
less = -1; |
|
372 |
✓✓ | 36 |
else if ('+' == *cp) |
373 |
3 |
less = 1; |
|
374 |
else |
||
375 |
33 |
cp--; |
|
376 |
|||
377 |
✗✓ | 39 |
if (a2roffsu(++cp, &su, SCALE_EN) == NULL) |
378 |
return 0; |
||
379 |
|||
380 |
39 |
v = term_hen(p, &su); |
|
381 |
|||
382 |
✓✓ | 39 |
if (less < 0) |
383 |
✓✗ | 9 |
p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset; |
384 |
✓✓ | 36 |
else if (less > 0) |
385 |
3 |
p->tcol->offset += v; |
|
386 |
else |
||
387 |
p->tcol->offset = v; |
||
388 |
✗✓ | 39 |
if (p->tcol->offset > SHRT_MAX) |
389 |
p->tcol->offset = term_len(p, p->defindent); |
||
390 |
|||
391 |
39 |
return 0; |
|
392 |
39 |
} |
|
393 |
|||
394 |
static int |
||
395 |
pre_DT(DECL_ARGS) |
||
396 |
{ |
||
397 |
term_tab_set(p, NULL); |
||
398 |
term_tab_set(p, "T"); |
||
399 |
term_tab_set(p, ".5i"); |
||
400 |
return 0; |
||
401 |
} |
||
402 |
|||
403 |
static int |
||
404 |
pre_HP(DECL_ARGS) |
||
405 |
{ |
||
406 |
1926 |
struct roffsu su; |
|
407 |
const struct roff_node *nn; |
||
408 |
int len; |
||
409 |
|||
410 |
✓✓✓ | 963 |
switch (n->type) { |
411 |
case ROFFT_BLOCK: |
||
412 |
321 |
print_bvspace(p, n, mt->pardist); |
|
413 |
321 |
return 1; |
|
414 |
case ROFFT_BODY: |
||
415 |
break; |
||
416 |
default: |
||
417 |
321 |
return 0; |
|
418 |
} |
||
419 |
|||
420 |
✓✓ | 321 |
if ( ! (MANT_LITERAL & mt->fl)) { |
421 |
309 |
p->flags |= TERMP_NOBREAK | TERMP_BRIND; |
|
422 |
309 |
p->trailspace = 2; |
|
423 |
309 |
} |
|
424 |
|||
425 |
/* Calculate offset. */ |
||
426 |
|||
427 |
✓✓✓✗ |
612 |
if ((nn = n->parent->head->child) != NULL && |
428 |
291 |
a2roffsu(nn->string, &su, SCALE_EN) != NULL) { |
|
429 |
291 |
len = term_hen(p, &su); |
|
430 |
✓✓✓✓ |
321 |
if (len < 0 && (size_t)(-len) > mt->offset) |
431 |
3 |
len = -mt->offset; |
|
432 |
✗✓ | 288 |
else if (len > SHRT_MAX) |
433 |
len = term_len(p, p->defindent); |
||
434 |
291 |
mt->lmargin[mt->lmargincur] = len; |
|
435 |
291 |
} else |
|
436 |
30 |
len = mt->lmargin[mt->lmargincur]; |
|
437 |
|||
438 |
321 |
p->tcol->offset = mt->offset; |
|
439 |
321 |
p->tcol->rmargin = mt->offset + len; |
|
440 |
321 |
return 1; |
|
441 |
963 |
} |
|
442 |
|||
443 |
static void |
||
444 |
post_HP(DECL_ARGS) |
||
445 |
{ |
||
446 |
|||
447 |
✓✓ | 1926 |
switch (n->type) { |
448 |
case ROFFT_BODY: |
||
449 |
321 |
term_newln(p); |
|
450 |
|||
451 |
/* |
||
452 |
* Compatibility with a groff bug. |
||
453 |
* The .HP macro uses the undocumented .tag request |
||
454 |
* which causes a line break and cancels no-space |
||
455 |
* mode even if there isn't any output. |
||
456 |
*/ |
||
457 |
|||
458 |
✓✓ | 321 |
if (n->child == NULL) |
459 |
3 |
term_vspace(p); |
|
460 |
|||
461 |
321 |
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); |
|
462 |
321 |
p->trailspace = 0; |
|
463 |
321 |
p->tcol->offset = mt->offset; |
|
464 |
321 |
p->tcol->rmargin = p->maxrmargin; |
|
465 |
321 |
break; |
|
466 |
default: |
||
467 |
break; |
||
468 |
} |
||
469 |
963 |
} |
|
470 |
|||
471 |
static int |
||
472 |
pre_PP(DECL_ARGS) |
||
473 |
{ |
||
474 |
|||
475 |
✓✓ | 8100 |
switch (n->type) { |
476 |
case ROFFT_BLOCK: |
||
477 |
1350 |
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); |
|
478 |
1350 |
print_bvspace(p, n, mt->pardist); |
|
479 |
1350 |
break; |
|
480 |
default: |
||
481 |
2700 |
p->tcol->offset = mt->offset; |
|
482 |
2700 |
break; |
|
483 |
} |
||
484 |
|||
485 |
4050 |
return n->type != ROFFT_HEAD; |
|
486 |
} |
||
487 |
|||
488 |
static int |
||
489 |
pre_IP(DECL_ARGS) |
||
490 |
{ |
||
491 |
1344 |
struct roffsu su; |
|
492 |
const struct roff_node *nn; |
||
493 |
int len, savelit; |
||
494 |
|||
495 |
✓✓✓✓ |
768 |
switch (n->type) { |
496 |
case ROFFT_BODY: |
||
497 |
192 |
p->flags |= TERMP_NOSPACE; |
|
498 |
192 |
break; |
|
499 |
case ROFFT_HEAD: |
||
500 |
192 |
p->flags |= TERMP_NOBREAK; |
|
501 |
192 |
p->trailspace = 1; |
|
502 |
192 |
break; |
|
503 |
case ROFFT_BLOCK: |
||
504 |
192 |
print_bvspace(p, n, mt->pardist); |
|
505 |
/* FALLTHROUGH */ |
||
506 |
default: |
||
507 |
192 |
return 1; |
|
508 |
} |
||
509 |
|||
510 |
/* Calculate the offset from the optional second argument. */ |
||
511 |
✓✓✓✓ |
630 |
if ((nn = n->parent->head->child) != NULL && |
512 |
✓✓ | 378 |
(nn = nn->next) != NULL && |
513 |
246 |
a2roffsu(nn->string, &su, SCALE_EN) != NULL) { |
|
514 |
234 |
len = term_hen(p, &su); |
|
515 |
✓✓✓✓ |
258 |
if (len < 0 && (size_t)(-len) > mt->offset) |
516 |
12 |
len = -mt->offset; |
|
517 |
✗✓ | 222 |
else if (len > SHRT_MAX) |
518 |
len = term_len(p, p->defindent); |
||
519 |
234 |
mt->lmargin[mt->lmargincur] = len; |
|
520 |
234 |
} else |
|
521 |
150 |
len = mt->lmargin[mt->lmargincur]; |
|
522 |
|||
523 |
✓✓✓ | 576 |
switch (n->type) { |
524 |
case ROFFT_HEAD: |
||
525 |
192 |
p->tcol->offset = mt->offset; |
|
526 |
192 |
p->tcol->rmargin = mt->offset + len; |
|
527 |
|||
528 |
192 |
savelit = MANT_LITERAL & mt->fl; |
|
529 |
192 |
mt->fl &= ~MANT_LITERAL; |
|
530 |
|||
531 |
✓✓ | 192 |
if (n->child) |
532 |
189 |
print_man_node(p, mt, n->child, meta); |
|
533 |
|||
534 |
✓✓ | 192 |
if (savelit) |
535 |
45 |
mt->fl |= MANT_LITERAL; |
|
536 |
|||
537 |
192 |
return 0; |
|
538 |
case ROFFT_BODY: |
||
539 |
192 |
p->tcol->offset = mt->offset + len; |
|
540 |
192 |
p->tcol->rmargin = p->maxrmargin; |
|
541 |
192 |
break; |
|
542 |
default: |
||
543 |
break; |
||
544 |
} |
||
545 |
|||
546 |
192 |
return 1; |
|
547 |
576 |
} |
|
548 |
|||
549 |
static void |
||
550 |
post_IP(DECL_ARGS) |
||
551 |
{ |
||
552 |
|||
553 |
✓✓✓ | 1536 |
switch (n->type) { |
554 |
case ROFFT_HEAD: |
||
555 |
192 |
term_flushln(p); |
|
556 |
192 |
p->flags &= ~TERMP_NOBREAK; |
|
557 |
192 |
p->trailspace = 0; |
|
558 |
192 |
p->tcol->rmargin = p->maxrmargin; |
|
559 |
192 |
break; |
|
560 |
case ROFFT_BODY: |
||
561 |
192 |
term_newln(p); |
|
562 |
192 |
p->tcol->offset = mt->offset; |
|
563 |
192 |
break; |
|
564 |
default: |
||
565 |
break; |
||
566 |
} |
||
567 |
576 |
} |
|
568 |
|||
569 |
static int |
||
570 |
pre_TP(DECL_ARGS) |
||
571 |
{ |
||
572 |
4536 |
struct roffsu su; |
|
573 |
struct roff_node *nn; |
||
574 |
int len, savelit; |
||
575 |
|||
576 |
✓✓✓✓ |
2592 |
switch (n->type) { |
577 |
case ROFFT_HEAD: |
||
578 |
648 |
p->flags |= TERMP_NOBREAK | TERMP_BRTRSP; |
|
579 |
648 |
p->trailspace = 1; |
|
580 |
648 |
break; |
|
581 |
case ROFFT_BODY: |
||
582 |
648 |
p->flags |= TERMP_NOSPACE; |
|
583 |
648 |
break; |
|
584 |
case ROFFT_BLOCK: |
||
585 |
648 |
print_bvspace(p, n, mt->pardist); |
|
586 |
/* FALLTHROUGH */ |
||
587 |
default: |
||
588 |
648 |
return 1; |
|
589 |
} |
||
590 |
|||
591 |
/* Calculate offset. */ |
||
592 |
|||
593 |
✓✗✓✓ |
2430 |
if ((nn = n->parent->head->child) != NULL && |
594 |
✓✓✓✓ |
2580 |
nn->string != NULL && ! (NODE_LINE & nn->flags) && |
595 |
1134 |
a2roffsu(nn->string, &su, SCALE_EN) != NULL) { |
|
596 |
1116 |
len = term_hen(p, &su); |
|
597 |
✓✓✓✓ |
1140 |
if (len < 0 && (size_t)(-len) > mt->offset) |
598 |
12 |
len = -mt->offset; |
|
599 |
✗✓ | 1104 |
else if (len > SHRT_MAX) |
600 |
len = term_len(p, p->defindent); |
||
601 |
1116 |
mt->lmargin[mt->lmargincur] = len; |
|
602 |
1116 |
} else |
|
603 |
180 |
len = mt->lmargin[mt->lmargincur]; |
|
604 |
|||
605 |
✓✓✓ | 1944 |
switch (n->type) { |
606 |
case ROFFT_HEAD: |
||
607 |
648 |
p->tcol->offset = mt->offset; |
|
608 |
648 |
p->tcol->rmargin = mt->offset + len; |
|
609 |
|||
610 |
648 |
savelit = MANT_LITERAL & mt->fl; |
|
611 |
648 |
mt->fl &= ~MANT_LITERAL; |
|
612 |
|||
613 |
/* Don't print same-line elements. */ |
||
614 |
648 |
nn = n->child; |
|
615 |
✓✗✓✓ |
3699 |
while (NULL != nn && 0 == (NODE_LINE & nn->flags)) |
616 |
585 |
nn = nn->next; |
|
617 |
|||
618 |
✓✓ | 2610 |
while (NULL != nn) { |
619 |
657 |
print_man_node(p, mt, nn, meta); |
|
620 |
657 |
nn = nn->next; |
|
621 |
} |
||
622 |
|||
623 |
✓✓ | 648 |
if (savelit) |
624 |
39 |
mt->fl |= MANT_LITERAL; |
|
625 |
648 |
return 0; |
|
626 |
case ROFFT_BODY: |
||
627 |
648 |
p->tcol->offset = mt->offset + len; |
|
628 |
648 |
p->tcol->rmargin = p->maxrmargin; |
|
629 |
648 |
p->trailspace = 0; |
|
630 |
648 |
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); |
|
631 |
648 |
break; |
|
632 |
default: |
||
633 |
break; |
||
634 |
} |
||
635 |
|||
636 |
648 |
return 1; |
|
637 |
1944 |
} |
|
638 |
|||
639 |
static void |
||
640 |
post_TP(DECL_ARGS) |
||
641 |
{ |
||
642 |
|||
643 |
✓✓✓ | 5184 |
switch (n->type) { |
644 |
case ROFFT_HEAD: |
||
645 |
648 |
term_flushln(p); |
|
646 |
648 |
break; |
|
647 |
case ROFFT_BODY: |
||
648 |
648 |
term_newln(p); |
|
649 |
648 |
p->tcol->offset = mt->offset; |
|
650 |
648 |
break; |
|
651 |
default: |
||
652 |
break; |
||
653 |
} |
||
654 |
1944 |
} |
|
655 |
|||
656 |
static int |
||
657 |
pre_SS(DECL_ARGS) |
||
658 |
{ |
||
659 |
int i; |
||
660 |
|||
661 |
✓✓✓✓ |
1665 |
switch (n->type) { |
662 |
case ROFFT_BLOCK: |
||
663 |
185 |
mt->fl &= ~MANT_LITERAL; |
|
664 |
185 |
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); |
|
665 |
185 |
mt->offset = term_len(p, p->defindent); |
|
666 |
|||
667 |
/* |
||
668 |
* No vertical space before the first subsection |
||
669 |
* and after an empty subsection. |
||
670 |
*/ |
||
671 |
|||
672 |
185 |
do { |
|
673 |
185 |
n = n->prev; |
|
674 |
✓✓✓✓ ✗✓ |
481 |
} while (n != NULL && n->tok >= MAN_TH && |
675 |
132 |
termacts[n->tok].flags & MAN_NOTEXT); |
|
676 |
✓✓✓✓ ✓✗ |
457 |
if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL)) |
677 |
break; |
||
678 |
|||
679 |
✓✓ | 656 |
for (i = 0; i < mt->pardist; i++) |
680 |
164 |
term_vspace(p); |
|
681 |
break; |
||
682 |
case ROFFT_HEAD: |
||
683 |
185 |
term_fontrepl(p, TERMFONT_BOLD); |
|
684 |
185 |
p->tcol->offset = term_len(p, 3); |
|
685 |
185 |
p->tcol->rmargin = mt->offset; |
|
686 |
185 |
p->trailspace = mt->offset; |
|
687 |
185 |
p->flags |= TERMP_NOBREAK | TERMP_BRIND; |
|
688 |
185 |
break; |
|
689 |
case ROFFT_BODY: |
||
690 |
185 |
p->tcol->offset = mt->offset; |
|
691 |
185 |
p->tcol->rmargin = p->maxrmargin; |
|
692 |
185 |
p->trailspace = 0; |
|
693 |
185 |
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); |
|
694 |
185 |
break; |
|
695 |
default: |
||
696 |
break; |
||
697 |
} |
||
698 |
|||
699 |
555 |
return 1; |
|
700 |
} |
||
701 |
|||
702 |
static void |
||
703 |
post_SS(DECL_ARGS) |
||
704 |
{ |
||
705 |
|||
706 |
✓✓✓ | 1480 |
switch (n->type) { |
707 |
case ROFFT_HEAD: |
||
708 |
185 |
term_newln(p); |
|
709 |
185 |
break; |
|
710 |
case ROFFT_BODY: |
||
711 |
185 |
term_newln(p); |
|
712 |
185 |
break; |
|
713 |
default: |
||
714 |
break; |
||
715 |
} |
||
716 |
555 |
} |
|
717 |
|||
718 |
static int |
||
719 |
pre_SH(DECL_ARGS) |
||
720 |
{ |
||
721 |
int i; |
||
722 |
|||
723 |
✓✓✓✓ |
22590 |
switch (n->type) { |
724 |
case ROFFT_BLOCK: |
||
725 |
2510 |
mt->fl &= ~MANT_LITERAL; |
|
726 |
2510 |
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); |
|
727 |
2510 |
mt->offset = term_len(p, p->defindent); |
|
728 |
|||
729 |
/* |
||
730 |
* No vertical space before the first section |
||
731 |
* and after an empty section. |
||
732 |
*/ |
||
733 |
|||
734 |
2510 |
do { |
|
735 |
2510 |
n = n->prev; |
|
736 |
✓✓✓✓ ✗✓ |
5230 |
} while (n != NULL && n->tok >= MAN_TH && |
737 |
1357 |
termacts[n->tok].flags & MAN_NOTEXT); |
|
738 |
✓✓✓✓ ✓✓ |
5227 |
if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL)) |
739 |
break; |
||
740 |
|||
741 |
✓✓ | 5392 |
for (i = 0; i < mt->pardist; i++) |
742 |
1348 |
term_vspace(p); |
|
743 |
break; |
||
744 |
case ROFFT_HEAD: |
||
745 |
2510 |
term_fontrepl(p, TERMFONT_BOLD); |
|
746 |
2510 |
p->tcol->offset = 0; |
|
747 |
2510 |
p->tcol->rmargin = mt->offset; |
|
748 |
2510 |
p->trailspace = mt->offset; |
|
749 |
2510 |
p->flags |= TERMP_NOBREAK | TERMP_BRIND; |
|
750 |
2510 |
break; |
|
751 |
case ROFFT_BODY: |
||
752 |
2510 |
p->tcol->offset = mt->offset; |
|
753 |
2510 |
p->tcol->rmargin = p->maxrmargin; |
|
754 |
2510 |
p->trailspace = 0; |
|
755 |
2510 |
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); |
|
756 |
2510 |
break; |
|
757 |
default: |
||
758 |
break; |
||
759 |
} |
||
760 |
|||
761 |
7530 |
return 1; |
|
762 |
} |
||
763 |
|||
764 |
static void |
||
765 |
post_SH(DECL_ARGS) |
||
766 |
{ |
||
767 |
|||
768 |
✓✓✓ | 20080 |
switch (n->type) { |
769 |
case ROFFT_HEAD: |
||
770 |
2510 |
term_newln(p); |
|
771 |
2510 |
break; |
|
772 |
case ROFFT_BODY: |
||
773 |
2510 |
term_newln(p); |
|
774 |
2510 |
break; |
|
775 |
default: |
||
776 |
break; |
||
777 |
} |
||
778 |
7530 |
} |
|
779 |
|||
780 |
static int |
||
781 |
pre_RS(DECL_ARGS) |
||
782 |
{ |
||
783 |
2232 |
struct roffsu su; |
|
784 |
|||
785 |
✓✓✓ | 1116 |
switch (n->type) { |
786 |
case ROFFT_BLOCK: |
||
787 |
372 |
term_newln(p); |
|
788 |
372 |
return 1; |
|
789 |
case ROFFT_HEAD: |
||
790 |
372 |
return 0; |
|
791 |
default: |
||
792 |
break; |
||
793 |
} |
||
794 |
|||
795 |
372 |
n = n->parent->head; |
|
796 |
372 |
n->aux = SHRT_MAX + 1; |
|
797 |
✓✓ | 372 |
if (n->child == NULL) |
798 |
45 |
n->aux = mt->lmargin[mt->lmargincur]; |
|
799 |
✓✗ | 327 |
else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL) |
800 |
327 |
n->aux = term_hen(p, &su); |
|
801 |
✓✓✓✓ |
762 |
if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) |
802 |
3 |
n->aux = -mt->offset; |
|
803 |
✗✓ | 369 |
else if (n->aux > SHRT_MAX) |
804 |
n->aux = term_len(p, p->defindent); |
||
805 |
|||
806 |
375 |
mt->offset += n->aux; |
|
807 |
372 |
p->tcol->offset = mt->offset; |
|
808 |
372 |
p->tcol->rmargin = p->maxrmargin; |
|
809 |
|||
810 |
✓✗ | 372 |
if (++mt->lmarginsz < MAXMARGINS) |
811 |
372 |
mt->lmargincur = mt->lmarginsz; |
|
812 |
|||
813 |
372 |
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); |
|
814 |
372 |
return 1; |
|
815 |
1116 |
} |
|
816 |
|||
817 |
static void |
||
818 |
post_RS(DECL_ARGS) |
||
819 |
{ |
||
820 |
|||
821 |
✓✓ | 2232 |
switch (n->type) { |
822 |
case ROFFT_BLOCK: |
||
823 |
return; |
||
824 |
case ROFFT_HEAD: |
||
825 |
return; |
||
826 |
default: |
||
827 |
372 |
term_newln(p); |
|
828 |
break; |
||
829 |
} |
||
830 |
|||
831 |
372 |
mt->offset -= n->parent->head->aux; |
|
832 |
372 |
p->tcol->offset = mt->offset; |
|
833 |
|||
834 |
✓✗ | 372 |
if (--mt->lmarginsz < MAXMARGINS) |
835 |
372 |
mt->lmargincur = mt->lmarginsz; |
|
836 |
1116 |
} |
|
837 |
|||
838 |
static int |
||
839 |
pre_UR(DECL_ARGS) |
||
840 |
{ |
||
841 |
|||
842 |
252 |
return n->type != ROFFT_HEAD; |
|
843 |
} |
||
844 |
|||
845 |
static void |
||
846 |
post_UR(DECL_ARGS) |
||
847 |
{ |
||
848 |
|||
849 |
✓✓ | 252 |
if (n->type != ROFFT_BLOCK) |
850 |
return; |
||
851 |
|||
852 |
42 |
term_word(p, "<"); |
|
853 |
42 |
p->flags |= TERMP_NOSPACE; |
|
854 |
|||
855 |
✓✓ | 42 |
if (NULL != n->child->child) |
856 |
36 |
print_man_node(p, mt, n->child->child, meta); |
|
857 |
|||
858 |
42 |
p->flags |= TERMP_NOSPACE; |
|
859 |
42 |
term_word(p, ">"); |
|
860 |
168 |
} |
|
861 |
|||
862 |
static void |
||
863 |
print_man_node(DECL_ARGS) |
||
864 |
{ |
||
865 |
int c; |
||
866 |
|||
867 |
✓✗✓✓ |
80122 |
switch (n->type) { |
868 |
case ROFFT_TEXT: |
||
869 |
/* |
||
870 |
* If we have a blank line, output a vertical space. |
||
871 |
* If we have a space as the first character, break |
||
872 |
* before printing the line's data. |
||
873 |
*/ |
||
874 |
✓✓ | 19788 |
if (*n->string == '\0') { |
875 |
✓✓ | 21 |
if (p->flags & TERMP_NONEWLINE) |
876 |
3 |
term_newln(p); |
|
877 |
else |
||
878 |
18 |
term_vspace(p); |
|
879 |
21 |
return; |
|
880 |
✓✓✓✗ ✓✗ |
19797 |
} else if (*n->string == ' ' && n->flags & NODE_LINE && |
881 |
15 |
(p->flags & TERMP_NONEWLINE) == 0) |
|
882 |
15 |
term_newln(p); |
|
883 |
|||
884 |
19767 |
term_word(p, n->string); |
|
885 |
19767 |
goto out; |
|
886 |
|||
887 |
case ROFFT_EQN: |
||
888 |
if ( ! (n->flags & NODE_LINE)) |
||
889 |
p->flags |= TERMP_NOSPACE; |
||
890 |
term_eqn(p, n->eqn); |
||
891 |
if (n->next != NULL && ! (n->next->flags & NODE_LINE)) |
||
892 |
p->flags |= TERMP_NOSPACE; |
||
893 |
return; |
||
894 |
case ROFFT_TBL: |
||
895 |
✓✓ | 921 |
if (p->tbl.cols == NULL) |
896 |
356 |
term_vspace(p); |
|
897 |
921 |
term_tbl(p, n->span); |
|
898 |
921 |
return; |
|
899 |
default: |
||
900 |
break; |
||
901 |
} |
||
902 |
|||
903 |
✓✓ | 19352 |
if (n->tok < ROFF_MAX) { |
904 |
1416 |
roff_term_pre(p, n); |
|
905 |
1416 |
return; |
|
906 |
} |
||
907 |
|||
908 |
✓✗✗✓ |
35872 |
assert(n->tok >= MAN_TH && n->tok <= MAN_MAX); |
909 |
✓✓ | 17936 |
if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) |
910 |
17555 |
term_fontrepl(p, TERMFONT_NONE); |
|
911 |
|||
912 |
c = 1; |
||
913 |
✓✓ | 17936 |
if (termacts[n->tok].pre) |
914 |
17861 |
c = (*termacts[n->tok].pre)(p, mt, n, meta); |
|
915 |
|||
916 |
✓✓✓✓ |
32027 |
if (c && n->child) |
917 |
13995 |
print_man_nodelist(p, mt, n->child, meta); |
|
918 |
|||
919 |
✓✓ | 17936 |
if (termacts[n->tok].post) |
920 |
12810 |
(*termacts[n->tok].post)(p, mt, n, meta); |
|
921 |
✓✓ | 17936 |
if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) |
922 |
17555 |
term_fontrepl(p, TERMFONT_NONE); |
|
923 |
|||
924 |
out: |
||
925 |
/* |
||
926 |
* If we're in a literal context, make sure that words |
||
927 |
* together on the same line stay together. This is a |
||
928 |
* POST-printing call, so we check the NEXT word. Since |
||
929 |
* -man doesn't have nested macros, we don't need to be |
||
930 |
* more specific than this. |
||
931 |
*/ |
||
932 |
✓✓✓✓ |
41846 |
if (mt->fl & MANT_LITERAL && |
933 |
✓✓ | 4650 |
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && |
934 |
✓✓ | 8739 |
(n->next == NULL || n->next->flags & NODE_LINE)) { |
935 |
4458 |
p->flags |= TERMP_BRNEVER | TERMP_NOSPACE; |
|
936 |
✓✓✓✗ |
8250 |
if (n->string != NULL && *n->string != '\0') |
937 |
3792 |
term_flushln(p); |
|
938 |
else |
||
939 |
666 |
term_newln(p); |
|
940 |
4458 |
p->flags &= ~TERMP_BRNEVER; |
|
941 |
✓✓✓✗ |
4470 |
if (p->tcol->rmargin < p->maxrmargin && |
942 |
12 |
n->parent->tok == MAN_HP) { |
|
943 |
12 |
p->tcol->offset = p->tcol->rmargin; |
|
944 |
12 |
p->tcol->rmargin = p->maxrmargin; |
|
945 |
12 |
} |
|
946 |
} |
||
947 |
✓✓ | 37703 |
if (NODE_EOS & n->flags) |
948 |
1029 |
p->flags |= TERMP_SENTENCE; |
|
949 |
77764 |
} |
|
950 |
|||
951 |
|||
952 |
static void |
||
953 |
print_man_nodelist(DECL_ARGS) |
||
954 |
{ |
||
955 |
|||
956 |
✓✓ | 123802 |
while (n != NULL) { |
957 |
39179 |
print_man_node(p, mt, n, meta); |
|
958 |
39179 |
n = n->next; |
|
959 |
} |
||
960 |
15148 |
} |
|
961 |
|||
962 |
static void |
||
963 |
print_man_foot(struct termp *p, const struct roff_meta *meta) |
||
964 |
{ |
||
965 |
2318 |
char *title; |
|
966 |
size_t datelen, titlen; |
||
967 |
|||
968 |
✗✓ | 1159 |
assert(meta->title); |
969 |
✗✓ | 1159 |
assert(meta->msec); |
970 |
✗✓ | 1159 |
assert(meta->date); |
971 |
|||
972 |
1159 |
term_fontrepl(p, TERMFONT_NONE); |
|
973 |
|||
974 |
✓✓ | 1159 |
if (meta->hasbody) |
975 |
1153 |
term_vspace(p); |
|
976 |
|||
977 |
/* |
||
978 |
* Temporary, undocumented option to imitate mdoc(7) output. |
||
979 |
* In the bottom right corner, use the operating system |
||
980 |
* instead of the title. |
||
981 |
*/ |
||
982 |
|||
983 |
✓✓ | 1159 |
if ( ! p->mdocstyle) { |
984 |
✓✓ | 526 |
if (meta->hasbody) { |
985 |
523 |
term_vspace(p); |
|
986 |
523 |
term_vspace(p); |
|
987 |
523 |
} |
|
988 |
526 |
mandoc_asprintf(&title, "%s(%s)", |
|
989 |
526 |
meta->title, meta->msec); |
|
990 |
✓✗ | 1159 |
} else if (meta->os) { |
991 |
633 |
title = mandoc_strdup(meta->os); |
|
992 |
633 |
} else { |
|
993 |
title = mandoc_strdup(""); |
||
994 |
} |
||
995 |
1159 |
datelen = term_strlen(p, meta->date); |
|
996 |
|||
997 |
/* Bottom left corner: operating system. */ |
||
998 |
|||
999 |
1159 |
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; |
|
1000 |
1159 |
p->trailspace = 1; |
|
1001 |
1159 |
p->tcol->offset = 0; |
|
1002 |
✓✓ | 3471 |
p->tcol->rmargin = p->maxrmargin > datelen ? |
1003 |
1153 |
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; |
|
1004 |
|||
1005 |
✓✗ | 1159 |
if (meta->os) |
1006 |
1159 |
term_word(p, meta->os); |
|
1007 |
1159 |
term_flushln(p); |
|
1008 |
|||
1009 |
/* At the bottom in the middle: manual date. */ |
||
1010 |
|||
1011 |
1159 |
p->tcol->offset = p->tcol->rmargin; |
|
1012 |
1159 |
titlen = term_strlen(p, title); |
|
1013 |
✓✓ | 3471 |
p->tcol->rmargin = p->maxrmargin > titlen ? |
1014 |
1153 |
p->maxrmargin - titlen : 0; |
|
1015 |
1159 |
p->flags |= TERMP_NOSPACE; |
|
1016 |
|||
1017 |
1159 |
term_word(p, meta->date); |
|
1018 |
1159 |
term_flushln(p); |
|
1019 |
|||
1020 |
/* Bottom right corner: manual title and section. */ |
||
1021 |
|||
1022 |
1159 |
p->flags &= ~TERMP_NOBREAK; |
|
1023 |
1159 |
p->flags |= TERMP_NOSPACE; |
|
1024 |
1159 |
p->trailspace = 0; |
|
1025 |
1159 |
p->tcol->offset = p->tcol->rmargin; |
|
1026 |
1159 |
p->tcol->rmargin = p->maxrmargin; |
|
1027 |
|||
1028 |
1159 |
term_word(p, title); |
|
1029 |
1159 |
term_flushln(p); |
|
1030 |
1159 |
free(title); |
|
1031 |
1159 |
} |
|
1032 |
|||
1033 |
static void |
||
1034 |
print_man_head(struct termp *p, const struct roff_meta *meta) |
||
1035 |
{ |
||
1036 |
const char *volume; |
||
1037 |
2318 |
char *title; |
|
1038 |
size_t vollen, titlen; |
||
1039 |
|||
1040 |
✗✓ | 1159 |
assert(meta->title); |
1041 |
✗✓ | 1159 |
assert(meta->msec); |
1042 |
|||
1043 |
✓✓ | 3468 |
volume = NULL == meta->vol ? "" : meta->vol; |
1044 |
1159 |
vollen = term_strlen(p, volume); |
|
1045 |
|||
1046 |
/* Top left corner: manual title and section. */ |
||
1047 |
|||
1048 |
1159 |
mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); |
|
1049 |
1159 |
titlen = term_strlen(p, title); |
|
1050 |
|||
1051 |
1159 |
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; |
|
1052 |
1159 |
p->trailspace = 1; |
|
1053 |
1159 |
p->tcol->offset = 0; |
|
1054 |
✓✓ | 3471 |
p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? |
1055 |
1153 |
(p->maxrmargin - vollen + term_len(p, 1)) / 2 : |
|
1056 |
✓✓ | 9 |
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; |
1057 |
|||
1058 |
1159 |
term_word(p, title); |
|
1059 |
1159 |
term_flushln(p); |
|
1060 |
|||
1061 |
/* At the top in the middle: manual volume. */ |
||
1062 |
|||
1063 |
1159 |
p->flags |= TERMP_NOSPACE; |
|
1064 |
1159 |
p->tcol->offset = p->tcol->rmargin; |
|
1065 |
3477 |
p->tcol->rmargin = p->tcol->offset + vollen + titlen < |
|
1066 |
2318 |
p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin; |
|
1067 |
|||
1068 |
1159 |
term_word(p, volume); |
|
1069 |
1159 |
term_flushln(p); |
|
1070 |
|||
1071 |
/* Top right corner: title and section, again. */ |
||
1072 |
|||
1073 |
1159 |
p->flags &= ~TERMP_NOBREAK; |
|
1074 |
1159 |
p->trailspace = 0; |
|
1075 |
✓✓ | 1159 |
if (p->tcol->rmargin + titlen <= p->maxrmargin) { |
1076 |
1153 |
p->flags |= TERMP_NOSPACE; |
|
1077 |
1153 |
p->tcol->offset = p->tcol->rmargin; |
|
1078 |
1153 |
p->tcol->rmargin = p->maxrmargin; |
|
1079 |
1153 |
term_word(p, title); |
|
1080 |
1153 |
term_flushln(p); |
|
1081 |
1153 |
} |
|
1082 |
|||
1083 |
1159 |
p->flags &= ~TERMP_NOSPACE; |
|
1084 |
1159 |
p->tcol->offset = 0; |
|
1085 |
1159 |
p->tcol->rmargin = p->maxrmargin; |
|
1086 |
|||
1087 |
/* |
||
1088 |
* Groff prints three blank lines before the content. |
||
1089 |
* Do the same, except in the temporary, undocumented |
||
1090 |
* mode imitating mdoc(7) output. |
||
1091 |
*/ |
||
1092 |
|||
1093 |
1159 |
term_vspace(p); |
|
1094 |
✓✓ | 1159 |
if ( ! p->mdocstyle) { |
1095 |
526 |
term_vspace(p); |
|
1096 |
526 |
term_vspace(p); |
|
1097 |
526 |
} |
|
1098 |
1159 |
free(title); |
|
1099 |
1159 |
} |
Generated by: GCOVR (Version 3.3) |