Print this page
9718 update mandoc to 1.14.4
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mandoc/mdoc_term.c
+++ new/usr/src/cmd/mandoc/mdoc_term.c
1 -/* $Id: mdoc_term.c,v 1.364 2017/06/14 17:51:15 schwarze Exp $ */
1 +/* $Id: mdoc_term.c,v 1.367 2018/04/11 17:11:13 schwarze Exp $ */
2 2 /*
3 3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 - * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
4 + * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
5 5 * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
6 6 *
7 7 * Permission to use, copy, modify, and distribute this software for any
8 8 * purpose with or without fee is hereby granted, provided that the above
9 9 * copyright notice and this permission notice appear in all copies.
10 10 *
11 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
12 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
14 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 18 */
19 19 #include "config.h"
20 20
21 21 #include <sys/types.h>
22 22
23 23 #include <assert.h>
24 24 #include <ctype.h>
25 25 #include <limits.h>
26 26 #include <stdint.h>
27 27 #include <stdio.h>
28 28 #include <stdlib.h>
29 29 #include <string.h>
30 30
31 31 #include "mandoc_aux.h"
32 32 #include "mandoc.h"
33 33 #include "roff.h"
34 34 #include "mdoc.h"
35 35 #include "out.h"
36 36 #include "term.h"
37 37 #include "tag.h"
38 38 #include "main.h"
39 39
40 40 struct termpair {
41 41 struct termpair *ppair;
42 42 int count;
43 43 };
44 44
45 45 #define DECL_ARGS struct termp *p, \
46 46 struct termpair *pair, \
47 47 const struct roff_meta *meta, \
48 48 struct roff_node *n
49 49
50 50 struct termact {
51 51 int (*pre)(DECL_ARGS);
52 52 void (*post)(DECL_ARGS);
53 53 };
54 54
55 55 static int a2width(const struct termp *, const char *);
56 56
57 57 static void print_bvspace(struct termp *,
58 58 const struct roff_node *,
59 59 const struct roff_node *);
60 60 static void print_mdoc_node(DECL_ARGS);
61 61 static void print_mdoc_nodelist(DECL_ARGS);
62 62 static void print_mdoc_head(struct termp *, const struct roff_meta *);
63 63 static void print_mdoc_foot(struct termp *, const struct roff_meta *);
64 64 static void synopsis_pre(struct termp *,
65 65 const struct roff_node *);
66 66
67 67 static void termp____post(DECL_ARGS);
68 68 static void termp__t_post(DECL_ARGS);
69 69 static void termp_bd_post(DECL_ARGS);
70 70 static void termp_bk_post(DECL_ARGS);
71 71 static void termp_bl_post(DECL_ARGS);
72 72 static void termp_eo_post(DECL_ARGS);
73 73 static void termp_fd_post(DECL_ARGS);
74 74 static void termp_fo_post(DECL_ARGS);
75 75 static void termp_in_post(DECL_ARGS);
76 76 static void termp_it_post(DECL_ARGS);
77 77 static void termp_lb_post(DECL_ARGS);
78 78 static void termp_nm_post(DECL_ARGS);
79 79 static void termp_pf_post(DECL_ARGS);
80 80 static void termp_quote_post(DECL_ARGS);
81 81 static void termp_sh_post(DECL_ARGS);
82 82 static void termp_ss_post(DECL_ARGS);
83 83 static void termp_xx_post(DECL_ARGS);
84 84
85 85 static int termp__a_pre(DECL_ARGS);
86 86 static int termp__t_pre(DECL_ARGS);
87 87 static int termp_an_pre(DECL_ARGS);
88 88 static int termp_ap_pre(DECL_ARGS);
89 89 static int termp_bd_pre(DECL_ARGS);
90 90 static int termp_bf_pre(DECL_ARGS);
91 91 static int termp_bk_pre(DECL_ARGS);
92 92 static int termp_bl_pre(DECL_ARGS);
93 93 static int termp_bold_pre(DECL_ARGS);
94 94 static int termp_cd_pre(DECL_ARGS);
95 95 static int termp_d1_pre(DECL_ARGS);
96 96 static int termp_eo_pre(DECL_ARGS);
97 97 static int termp_em_pre(DECL_ARGS);
98 98 static int termp_er_pre(DECL_ARGS);
99 99 static int termp_ex_pre(DECL_ARGS);
100 100 static int termp_fa_pre(DECL_ARGS);
101 101 static int termp_fd_pre(DECL_ARGS);
102 102 static int termp_fl_pre(DECL_ARGS);
103 103 static int termp_fn_pre(DECL_ARGS);
104 104 static int termp_fo_pre(DECL_ARGS);
105 105 static int termp_ft_pre(DECL_ARGS);
106 106 static int termp_in_pre(DECL_ARGS);
107 107 static int termp_it_pre(DECL_ARGS);
108 108 static int termp_li_pre(DECL_ARGS);
109 109 static int termp_lk_pre(DECL_ARGS);
110 110 static int termp_nd_pre(DECL_ARGS);
111 111 static int termp_nm_pre(DECL_ARGS);
112 112 static int termp_ns_pre(DECL_ARGS);
113 113 static int termp_quote_pre(DECL_ARGS);
114 114 static int termp_rs_pre(DECL_ARGS);
115 115 static int termp_sh_pre(DECL_ARGS);
116 116 static int termp_skip_pre(DECL_ARGS);
117 117 static int termp_sm_pre(DECL_ARGS);
118 118 static int termp_pp_pre(DECL_ARGS);
119 119 static int termp_ss_pre(DECL_ARGS);
120 120 static int termp_sy_pre(DECL_ARGS);
121 121 static int termp_tag_pre(DECL_ARGS);
122 122 static int termp_under_pre(DECL_ARGS);
123 123 static int termp_vt_pre(DECL_ARGS);
124 124 static int termp_xr_pre(DECL_ARGS);
125 125 static int termp_xx_pre(DECL_ARGS);
126 126
127 127 static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
128 128 { NULL, NULL }, /* Dd */
129 129 { NULL, NULL }, /* Dt */
130 130 { NULL, NULL }, /* Os */
131 131 { termp_sh_pre, termp_sh_post }, /* Sh */
132 132 { termp_ss_pre, termp_ss_post }, /* Ss */
133 133 { termp_pp_pre, NULL }, /* Pp */
134 134 { termp_d1_pre, termp_bl_post }, /* D1 */
135 135 { termp_d1_pre, termp_bl_post }, /* Dl */
136 136 { termp_bd_pre, termp_bd_post }, /* Bd */
137 137 { NULL, NULL }, /* Ed */
138 138 { termp_bl_pre, termp_bl_post }, /* Bl */
139 139 { NULL, NULL }, /* El */
140 140 { termp_it_pre, termp_it_post }, /* It */
141 141 { termp_under_pre, NULL }, /* Ad */
142 142 { termp_an_pre, NULL }, /* An */
143 143 { termp_ap_pre, NULL }, /* Ap */
144 144 { termp_under_pre, NULL }, /* Ar */
145 145 { termp_cd_pre, NULL }, /* Cd */
146 146 { termp_bold_pre, NULL }, /* Cm */
147 147 { termp_li_pre, NULL }, /* Dv */
148 148 { termp_er_pre, NULL }, /* Er */
149 149 { termp_tag_pre, NULL }, /* Ev */
150 150 { termp_ex_pre, NULL }, /* Ex */
151 151 { termp_fa_pre, NULL }, /* Fa */
152 152 { termp_fd_pre, termp_fd_post }, /* Fd */
153 153 { termp_fl_pre, NULL }, /* Fl */
154 154 { termp_fn_pre, NULL }, /* Fn */
155 155 { termp_ft_pre, NULL }, /* Ft */
156 156 { termp_bold_pre, NULL }, /* Ic */
157 157 { termp_in_pre, termp_in_post }, /* In */
158 158 { termp_li_pre, NULL }, /* Li */
159 159 { termp_nd_pre, NULL }, /* Nd */
160 160 { termp_nm_pre, termp_nm_post }, /* Nm */
161 161 { termp_quote_pre, termp_quote_post }, /* Op */
162 162 { termp_ft_pre, NULL }, /* Ot */
163 163 { termp_under_pre, NULL }, /* Pa */
164 164 { termp_ex_pre, NULL }, /* Rv */
165 165 { NULL, NULL }, /* St */
166 166 { termp_under_pre, NULL }, /* Va */
167 167 { termp_vt_pre, NULL }, /* Vt */
168 168 { termp_xr_pre, NULL }, /* Xr */
169 169 { termp__a_pre, termp____post }, /* %A */
170 170 { termp_under_pre, termp____post }, /* %B */
171 171 { NULL, termp____post }, /* %D */
172 172 { termp_under_pre, termp____post }, /* %I */
173 173 { termp_under_pre, termp____post }, /* %J */
174 174 { NULL, termp____post }, /* %N */
175 175 { NULL, termp____post }, /* %O */
176 176 { NULL, termp____post }, /* %P */
177 177 { NULL, termp____post }, /* %R */
178 178 { termp__t_pre, termp__t_post }, /* %T */
179 179 { NULL, termp____post }, /* %V */
180 180 { NULL, NULL }, /* Ac */
181 181 { termp_quote_pre, termp_quote_post }, /* Ao */
182 182 { termp_quote_pre, termp_quote_post }, /* Aq */
183 183 { NULL, NULL }, /* At */
184 184 { NULL, NULL }, /* Bc */
185 185 { termp_bf_pre, NULL }, /* Bf */
186 186 { termp_quote_pre, termp_quote_post }, /* Bo */
187 187 { termp_quote_pre, termp_quote_post }, /* Bq */
188 188 { termp_xx_pre, termp_xx_post }, /* Bsx */
189 189 { NULL, NULL }, /* Bx */
190 190 { termp_skip_pre, NULL }, /* Db */
191 191 { NULL, NULL }, /* Dc */
192 192 { termp_quote_pre, termp_quote_post }, /* Do */
193 193 { termp_quote_pre, termp_quote_post }, /* Dq */
194 194 { NULL, NULL }, /* Ec */ /* FIXME: no space */
195 195 { NULL, NULL }, /* Ef */
196 196 { termp_em_pre, NULL }, /* Em */
197 197 { termp_eo_pre, termp_eo_post }, /* Eo */
198 198 { termp_xx_pre, termp_xx_post }, /* Fx */
199 199 { termp_bold_pre, NULL }, /* Ms */
200 200 { termp_li_pre, NULL }, /* No */
201 201 { termp_ns_pre, NULL }, /* Ns */
202 202 { termp_xx_pre, termp_xx_post }, /* Nx */
203 203 { termp_xx_pre, termp_xx_post }, /* Ox */
204 204 { NULL, NULL }, /* Pc */
205 205 { NULL, termp_pf_post }, /* Pf */
206 206 { termp_quote_pre, termp_quote_post }, /* Po */
207 207 { termp_quote_pre, termp_quote_post }, /* Pq */
208 208 { NULL, NULL }, /* Qc */
209 209 { termp_quote_pre, termp_quote_post }, /* Ql */
210 210 { termp_quote_pre, termp_quote_post }, /* Qo */
211 211 { termp_quote_pre, termp_quote_post }, /* Qq */
212 212 { NULL, NULL }, /* Re */
213 213 { termp_rs_pre, NULL }, /* Rs */
214 214 { NULL, NULL }, /* Sc */
215 215 { termp_quote_pre, termp_quote_post }, /* So */
216 216 { termp_quote_pre, termp_quote_post }, /* Sq */
217 217 { termp_sm_pre, NULL }, /* Sm */
218 218 { termp_under_pre, NULL }, /* Sx */
219 219 { termp_sy_pre, NULL }, /* Sy */
220 220 { NULL, NULL }, /* Tn */
221 221 { termp_xx_pre, termp_xx_post }, /* Ux */
222 222 { NULL, NULL }, /* Xc */
223 223 { NULL, NULL }, /* Xo */
224 224 { termp_fo_pre, termp_fo_post }, /* Fo */
225 225 { NULL, NULL }, /* Fc */
226 226 { termp_quote_pre, termp_quote_post }, /* Oo */
227 227 { NULL, NULL }, /* Oc */
228 228 { termp_bk_pre, termp_bk_post }, /* Bk */
229 229 { NULL, NULL }, /* Ek */
230 230 { NULL, NULL }, /* Bt */
231 231 { NULL, NULL }, /* Hf */
232 232 { termp_under_pre, NULL }, /* Fr */
233 233 { NULL, NULL }, /* Ud */
234 234 { NULL, termp_lb_post }, /* Lb */
235 235 { termp_pp_pre, NULL }, /* Lp */
236 236 { termp_lk_pre, NULL }, /* Lk */
237 237 { termp_under_pre, NULL }, /* Mt */
238 238 { termp_quote_pre, termp_quote_post }, /* Brq */
239 239 { termp_quote_pre, termp_quote_post }, /* Bro */
240 240 { NULL, NULL }, /* Brc */
241 241 { NULL, termp____post }, /* %C */
242 242 { termp_skip_pre, NULL }, /* Es */
243 243 { termp_quote_pre, termp_quote_post }, /* En */
244 244 { termp_xx_pre, termp_xx_post }, /* Dx */
245 245 { NULL, termp____post }, /* %Q */
246 246 { NULL, termp____post }, /* %U */
247 247 { NULL, NULL }, /* Ta */
248 248 };
249 249 static const struct termact *const termacts = __termacts - MDOC_Dd;
250 250
251 251 static int fn_prio;
252 252
253 253
254 254 void
255 255 terminal_mdoc(void *arg, const struct roff_man *mdoc)
256 256 {
257 257 struct roff_node *n;
258 258 struct termp *p;
259 259 size_t save_defindent;
260 260
261 261 p = (struct termp *)arg;
262 262 p->tcol->rmargin = p->maxrmargin = p->defrmargin;
263 263 term_tab_set(p, NULL);
264 264 term_tab_set(p, "T");
265 265 term_tab_set(p, ".5i");
266 266
267 267 n = mdoc->first->child;
268 268 if (p->synopsisonly) {
269 269 while (n != NULL) {
270 270 if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
271 271 if (n->child->next->child != NULL)
272 272 print_mdoc_nodelist(p, NULL,
273 273 &mdoc->meta,
274 274 n->child->next->child);
275 275 term_newln(p);
↓ open down ↓ |
261 lines elided |
↑ open up ↑ |
276 276 break;
277 277 }
278 278 n = n->next;
279 279 }
280 280 } else {
281 281 save_defindent = p->defindent;
282 282 if (p->defindent == 0)
283 283 p->defindent = 5;
284 284 term_begin(p, print_mdoc_head, print_mdoc_foot,
285 285 &mdoc->meta);
286 - while (n != NULL && n->flags & NODE_NOPRT)
286 + while (n != NULL &&
287 + (n->type == ROFFT_COMMENT ||
288 + n->flags & NODE_NOPRT))
287 289 n = n->next;
288 290 if (n != NULL) {
289 291 if (n->tok != MDOC_Sh)
290 292 term_vspace(p);
291 293 print_mdoc_nodelist(p, NULL, &mdoc->meta, n);
292 294 }
293 295 term_end(p);
294 296 p->defindent = save_defindent;
295 297 }
296 298 }
297 299
298 300 static void
299 301 print_mdoc_nodelist(DECL_ARGS)
300 302 {
301 303
302 304 while (n != NULL) {
303 305 print_mdoc_node(p, pair, meta, n);
304 306 n = n->next;
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
305 307 }
306 308 }
307 309
308 310 static void
309 311 print_mdoc_node(DECL_ARGS)
310 312 {
311 313 int chld;
312 314 struct termpair npair;
313 315 size_t offset, rmargin;
314 316
315 - if (n->flags & NODE_NOPRT)
317 + if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
316 318 return;
317 319
318 320 chld = 1;
319 321 offset = p->tcol->offset;
320 322 rmargin = p->tcol->rmargin;
321 323 n->flags &= ~NODE_ENDED;
322 324 n->prev_font = p->fonti;
323 325
324 326 memset(&npair, 0, sizeof(struct termpair));
325 327 npair.ppair = pair;
326 328
327 329 /*
328 330 * Keeps only work until the end of a line. If a keep was
329 331 * invoked in a prior line, revert it to PREKEEP.
330 332 */
331 333
332 334 if (p->flags & TERMP_KEEP && n->flags & NODE_LINE) {
333 335 p->flags &= ~TERMP_KEEP;
334 336 p->flags |= TERMP_PREKEEP;
335 337 }
336 338
337 339 /*
338 340 * After the keep flags have been set up, we may now
339 341 * produce output. Note that some pre-handlers do so.
340 342 */
341 343
342 344 switch (n->type) {
343 345 case ROFFT_TEXT:
344 346 if (*n->string == ' ' && n->flags & NODE_LINE &&
345 347 (p->flags & TERMP_NONEWLINE) == 0)
346 348 term_newln(p);
347 349 if (NODE_DELIMC & n->flags)
348 350 p->flags |= TERMP_NOSPACE;
349 351 term_word(p, n->string);
350 352 if (NODE_DELIMO & n->flags)
351 353 p->flags |= TERMP_NOSPACE;
352 354 break;
353 355 case ROFFT_EQN:
354 356 if ( ! (n->flags & NODE_LINE))
355 357 p->flags |= TERMP_NOSPACE;
356 358 term_eqn(p, n->eqn);
357 359 if (n->next != NULL && ! (n->next->flags & NODE_LINE))
358 360 p->flags |= TERMP_NOSPACE;
359 361 break;
360 362 case ROFFT_TBL:
361 363 if (p->tbl.cols == NULL)
362 364 term_newln(p);
363 365 term_tbl(p, n->span);
364 366 break;
365 367 default:
366 368 if (n->tok < ROFF_MAX) {
367 369 roff_term_pre(p, n);
368 370 return;
369 371 }
370 372 assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
371 373 if (termacts[n->tok].pre != NULL &&
372 374 (n->end == ENDBODY_NOT || n->child != NULL))
373 375 chld = (*termacts[n->tok].pre)
374 376 (p, &npair, meta, n);
375 377 break;
376 378 }
377 379
378 380 if (chld && n->child)
379 381 print_mdoc_nodelist(p, &npair, meta, n->child);
380 382
381 383 term_fontpopq(p,
382 384 (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
383 385
384 386 switch (n->type) {
385 387 case ROFFT_TEXT:
386 388 break;
387 389 case ROFFT_TBL:
388 390 break;
389 391 case ROFFT_EQN:
390 392 break;
391 393 default:
392 394 if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED)
393 395 break;
394 396 (void)(*termacts[n->tok].post)(p, &npair, meta, n);
395 397
396 398 /*
397 399 * Explicit end tokens not only call the post
398 400 * handler, but also tell the respective block
399 401 * that it must not call the post handler again.
400 402 */
401 403 if (ENDBODY_NOT != n->end)
402 404 n->body->flags |= NODE_ENDED;
403 405 break;
404 406 }
405 407
406 408 if (NODE_EOS & n->flags)
407 409 p->flags |= TERMP_SENTENCE;
408 410
409 411 if (n->type != ROFFT_TEXT)
410 412 p->tcol->offset = offset;
411 413 p->tcol->rmargin = rmargin;
412 414 }
413 415
414 416 static void
415 417 print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
416 418 {
417 419 size_t sz;
418 420
419 421 term_fontrepl(p, TERMFONT_NONE);
420 422
421 423 /*
422 424 * Output the footer in new-groff style, that is, three columns
423 425 * with the middle being the manual date and flanking columns
424 426 * being the operating system:
425 427 *
426 428 * SYSTEM DATE SYSTEM
427 429 */
428 430
429 431 term_vspace(p);
430 432
431 433 p->tcol->offset = 0;
432 434 sz = term_strlen(p, meta->date);
433 435 p->tcol->rmargin = p->maxrmargin > sz ?
434 436 (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
435 437 p->trailspace = 1;
436 438 p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
437 439
438 440 term_word(p, meta->os);
439 441 term_flushln(p);
440 442
441 443 p->tcol->offset = p->tcol->rmargin;
442 444 sz = term_strlen(p, meta->os);
443 445 p->tcol->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
444 446 p->flags |= TERMP_NOSPACE;
445 447
446 448 term_word(p, meta->date);
447 449 term_flushln(p);
448 450
449 451 p->tcol->offset = p->tcol->rmargin;
450 452 p->tcol->rmargin = p->maxrmargin;
451 453 p->trailspace = 0;
452 454 p->flags &= ~TERMP_NOBREAK;
453 455 p->flags |= TERMP_NOSPACE;
454 456
455 457 term_word(p, meta->os);
456 458 term_flushln(p);
457 459
458 460 p->tcol->offset = 0;
459 461 p->tcol->rmargin = p->maxrmargin;
460 462 p->flags = 0;
461 463 }
462 464
463 465 static void
464 466 print_mdoc_head(struct termp *p, const struct roff_meta *meta)
465 467 {
466 468 char *volume, *title;
467 469 size_t vollen, titlen;
468 470
469 471 /*
470 472 * The header is strange. It has three components, which are
471 473 * really two with the first duplicated. It goes like this:
472 474 *
473 475 * IDENTIFIER TITLE IDENTIFIER
474 476 *
475 477 * The IDENTIFIER is NAME(SECTION), which is the command-name
476 478 * (if given, or "unknown" if not) followed by the manual page
477 479 * section. These are given in `Dt'. The TITLE is a free-form
478 480 * string depending on the manual volume. If not specified, it
479 481 * switches on the manual section.
480 482 */
481 483
482 484 assert(meta->vol);
483 485 if (NULL == meta->arch)
484 486 volume = mandoc_strdup(meta->vol);
485 487 else
486 488 mandoc_asprintf(&volume, "%s (%s)",
487 489 meta->vol, meta->arch);
488 490 vollen = term_strlen(p, volume);
489 491
490 492 if (NULL == meta->msec)
491 493 title = mandoc_strdup(meta->title);
492 494 else
493 495 mandoc_asprintf(&title, "%s(%s)",
494 496 meta->title, meta->msec);
495 497 titlen = term_strlen(p, title);
496 498
497 499 p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
498 500 p->trailspace = 1;
499 501 p->tcol->offset = 0;
500 502 p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
501 503 (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
502 504 vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
503 505
504 506 term_word(p, title);
505 507 term_flushln(p);
506 508
507 509 p->flags |= TERMP_NOSPACE;
508 510 p->tcol->offset = p->tcol->rmargin;
509 511 p->tcol->rmargin = p->tcol->offset + vollen + titlen <
510 512 p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
511 513
512 514 term_word(p, volume);
513 515 term_flushln(p);
514 516
515 517 p->flags &= ~TERMP_NOBREAK;
516 518 p->trailspace = 0;
517 519 if (p->tcol->rmargin + titlen <= p->maxrmargin) {
518 520 p->flags |= TERMP_NOSPACE;
519 521 p->tcol->offset = p->tcol->rmargin;
520 522 p->tcol->rmargin = p->maxrmargin;
521 523 term_word(p, title);
522 524 term_flushln(p);
523 525 }
524 526
525 527 p->flags &= ~TERMP_NOSPACE;
526 528 p->tcol->offset = 0;
527 529 p->tcol->rmargin = p->maxrmargin;
528 530 free(title);
529 531 free(volume);
530 532 }
531 533
532 534 static int
533 535 a2width(const struct termp *p, const char *v)
534 536 {
535 537 struct roffsu su;
536 538 const char *end;
537 539
538 540 end = a2roffsu(v, &su, SCALE_MAX);
539 541 if (end == NULL || *end != '\0') {
540 542 SCALE_HS_INIT(&su, term_strlen(p, v));
541 543 su.scale /= term_strlen(p, "0");
542 544 }
543 545 return term_hen(p, &su);
544 546 }
545 547
546 548 /*
547 549 * Determine how much space to print out before block elements of `It'
548 550 * (and thus `Bl') and `Bd'. And then go ahead and print that space,
549 551 * too.
550 552 */
551 553 static void
552 554 print_bvspace(struct termp *p,
553 555 const struct roff_node *bl,
554 556 const struct roff_node *n)
555 557 {
556 558 const struct roff_node *nn;
557 559
558 560 assert(n);
559 561
↓ open down ↓ |
234 lines elided |
↑ open up ↑ |
560 562 term_newln(p);
561 563
562 564 if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
563 565 return;
564 566 if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
565 567 return;
566 568
567 569 /* Do not vspace directly after Ss/Sh. */
568 570
569 571 nn = n;
570 - while (nn->prev != NULL && nn->prev->flags & NODE_NOPRT)
572 + while (nn->prev != NULL &&
573 + (nn->prev->type == ROFFT_COMMENT ||
574 + nn->prev->flags & NODE_NOPRT))
571 575 nn = nn->prev;
572 576 while (nn->prev == NULL) {
573 577 do {
574 578 nn = nn->parent;
575 579 if (nn->type == ROFFT_ROOT)
576 580 return;
577 581 } while (nn->type != ROFFT_BLOCK);
578 582 if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
579 583 return;
580 584 if (nn->tok == MDOC_It &&
581 585 nn->parent->parent->norm->Bl.type != LIST_item)
582 586 break;
583 587 }
584 588
585 589 /* A `-column' does not assert vspace within the list. */
586 590
587 591 if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
588 592 if (n->prev && MDOC_It == n->prev->tok)
589 593 return;
590 594
591 595 /* A `-diag' without body does not vspace. */
592 596
593 597 if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
594 598 if (n->prev && MDOC_It == n->prev->tok) {
595 599 assert(n->prev->body);
596 600 if (NULL == n->prev->body->child)
597 601 return;
598 602 }
599 603
600 604 term_vspace(p);
601 605 }
602 606
603 607
604 608 static int
605 609 termp_it_pre(DECL_ARGS)
606 610 {
607 611 struct roffsu su;
608 612 char buf[24];
609 613 const struct roff_node *bl, *nn;
610 614 size_t ncols, dcol;
611 615 int i, offset, width;
612 616 enum mdoc_list type;
613 617
614 618 if (n->type == ROFFT_BLOCK) {
615 619 print_bvspace(p, n->parent->parent, n);
616 620 return 1;
617 621 }
618 622
619 623 bl = n->parent->parent->parent;
620 624 type = bl->norm->Bl.type;
621 625
622 626 /*
623 627 * Defaults for specific list types.
624 628 */
625 629
626 630 switch (type) {
627 631 case LIST_bullet:
628 632 case LIST_dash:
629 633 case LIST_hyphen:
630 634 case LIST_enum:
631 635 width = term_len(p, 2);
632 636 break;
633 637 case LIST_hang:
634 638 case LIST_tag:
635 639 width = term_len(p, 8);
636 640 break;
637 641 case LIST_column:
638 642 width = term_len(p, 10);
639 643 break;
640 644 default:
641 645 width = 0;
642 646 break;
643 647 }
644 648 offset = 0;
645 649
646 650 /*
647 651 * First calculate width and offset. This is pretty easy unless
648 652 * we're a -column list, in which case all prior columns must
649 653 * be accounted for.
650 654 */
651 655
652 656 if (bl->norm->Bl.offs != NULL) {
653 657 offset = a2width(p, bl->norm->Bl.offs);
654 658 if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
655 659 offset = -p->tcol->offset;
656 660 else if (offset > SHRT_MAX)
657 661 offset = 0;
658 662 }
659 663
660 664 switch (type) {
661 665 case LIST_column:
662 666 if (n->type == ROFFT_HEAD)
663 667 break;
664 668
665 669 /*
666 670 * Imitate groff's column handling:
667 671 * - For each earlier column, add its width.
668 672 * - For less than 5 columns, add four more blanks per
669 673 * column.
670 674 * - For exactly 5 columns, add three more blank per
671 675 * column.
672 676 * - For more than 5 columns, add only one column.
673 677 */
674 678 ncols = bl->norm->Bl.ncols;
675 679 dcol = ncols < 5 ? term_len(p, 4) :
676 680 ncols == 5 ? term_len(p, 3) : term_len(p, 1);
677 681
678 682 /*
679 683 * Calculate the offset by applying all prior ROFFT_BODY,
680 684 * so we stop at the ROFFT_HEAD (nn->prev == NULL).
681 685 */
682 686
683 687 for (i = 0, nn = n->prev;
684 688 nn->prev && i < (int)ncols;
685 689 nn = nn->prev, i++) {
686 690 SCALE_HS_INIT(&su,
687 691 term_strlen(p, bl->norm->Bl.cols[i]));
688 692 su.scale /= term_strlen(p, "0");
689 693 offset += term_hen(p, &su) + dcol;
690 694 }
691 695
692 696 /*
693 697 * When exceeding the declared number of columns, leave
694 698 * the remaining widths at 0. This will later be
695 699 * adjusted to the default width of 10, or, for the last
696 700 * column, stretched to the right margin.
697 701 */
698 702 if (i >= (int)ncols)
699 703 break;
700 704
701 705 /*
702 706 * Use the declared column widths, extended as explained
703 707 * in the preceding paragraph.
704 708 */
705 709 SCALE_HS_INIT(&su, term_strlen(p, bl->norm->Bl.cols[i]));
706 710 su.scale /= term_strlen(p, "0");
707 711 width = term_hen(p, &su) + dcol;
708 712 break;
709 713 default:
710 714 if (NULL == bl->norm->Bl.width)
711 715 break;
712 716
713 717 /*
714 718 * Note: buffer the width by 2, which is groff's magic
715 719 * number for buffering single arguments. See the above
716 720 * handling for column for how this changes.
717 721 */
718 722 width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
719 723 if (width < 0 && (size_t)(-width) > p->tcol->offset)
720 724 width = -p->tcol->offset;
721 725 else if (width > SHRT_MAX)
722 726 width = 0;
723 727 break;
724 728 }
725 729
726 730 /*
727 731 * Whitespace control. Inset bodies need an initial space,
728 732 * while diagonal bodies need two.
729 733 */
730 734
731 735 p->flags |= TERMP_NOSPACE;
732 736
733 737 switch (type) {
734 738 case LIST_diag:
735 739 if (n->type == ROFFT_BODY)
736 740 term_word(p, "\\ \\ ");
737 741 break;
738 742 case LIST_inset:
739 743 if (n->type == ROFFT_BODY && n->parent->head->child != NULL)
740 744 term_word(p, "\\ ");
741 745 break;
742 746 default:
743 747 break;
744 748 }
745 749
746 750 p->flags |= TERMP_NOSPACE;
747 751
748 752 switch (type) {
749 753 case LIST_diag:
750 754 if (n->type == ROFFT_HEAD)
751 755 term_fontpush(p, TERMFONT_BOLD);
752 756 break;
753 757 default:
754 758 break;
755 759 }
756 760
757 761 /*
758 762 * Pad and break control. This is the tricky part. These flags
759 763 * are documented in term_flushln() in term.c. Note that we're
760 764 * going to unset all of these flags in termp_it_post() when we
761 765 * exit.
762 766 */
763 767
764 768 switch (type) {
765 769 case LIST_enum:
766 770 case LIST_bullet:
767 771 case LIST_dash:
768 772 case LIST_hyphen:
769 773 if (n->type == ROFFT_HEAD) {
770 774 p->flags |= TERMP_NOBREAK | TERMP_HANG;
771 775 p->trailspace = 1;
772 776 } else if (width <= (int)term_len(p, 2))
773 777 p->flags |= TERMP_NOPAD;
774 778 break;
775 779 case LIST_hang:
776 780 if (n->type != ROFFT_HEAD)
777 781 break;
778 782 p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
779 783 p->trailspace = 1;
780 784 break;
781 785 case LIST_tag:
782 786 if (n->type != ROFFT_HEAD)
783 787 break;
784 788
785 789 p->flags |= TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND;
786 790 p->trailspace = 2;
787 791
788 792 if (NULL == n->next || NULL == n->next->child)
789 793 p->flags |= TERMP_HANG;
790 794 break;
791 795 case LIST_column:
792 796 if (n->type == ROFFT_HEAD)
793 797 break;
794 798
795 799 if (NULL == n->next) {
796 800 p->flags &= ~TERMP_NOBREAK;
797 801 p->trailspace = 0;
798 802 } else {
799 803 p->flags |= TERMP_NOBREAK;
800 804 p->trailspace = 1;
801 805 }
802 806
803 807 break;
804 808 case LIST_diag:
805 809 if (n->type != ROFFT_HEAD)
806 810 break;
807 811 p->flags |= TERMP_NOBREAK | TERMP_BRIND;
808 812 p->trailspace = 1;
809 813 break;
810 814 default:
811 815 break;
812 816 }
813 817
814 818 /*
815 819 * Margin control. Set-head-width lists have their right
816 820 * margins shortened. The body for these lists has the offset
817 821 * necessarily lengthened. Everybody gets the offset.
818 822 */
819 823
820 824 p->tcol->offset += offset;
821 825
822 826 switch (type) {
823 827 case LIST_bullet:
824 828 case LIST_dash:
825 829 case LIST_enum:
826 830 case LIST_hyphen:
827 831 case LIST_hang:
828 832 case LIST_tag:
829 833 if (n->type == ROFFT_HEAD)
830 834 p->tcol->rmargin = p->tcol->offset + width;
831 835 else
832 836 p->tcol->offset += width;
833 837 break;
834 838 case LIST_column:
835 839 assert(width);
836 840 p->tcol->rmargin = p->tcol->offset + width;
837 841 /*
838 842 * XXX - this behaviour is not documented: the
839 843 * right-most column is filled to the right margin.
840 844 */
841 845 if (n->type == ROFFT_HEAD)
842 846 break;
843 847 if (n->next == NULL && p->tcol->rmargin < p->maxrmargin)
844 848 p->tcol->rmargin = p->maxrmargin;
845 849 break;
846 850 default:
847 851 break;
848 852 }
849 853
850 854 /*
851 855 * The dash, hyphen, bullet and enum lists all have a special
852 856 * HEAD character (temporarily bold, in some cases).
853 857 */
854 858
855 859 if (n->type == ROFFT_HEAD)
856 860 switch (type) {
857 861 case LIST_bullet:
858 862 term_fontpush(p, TERMFONT_BOLD);
859 863 term_word(p, "\\[bu]");
860 864 term_fontpop(p);
861 865 break;
862 866 case LIST_dash:
863 867 case LIST_hyphen:
864 868 term_fontpush(p, TERMFONT_BOLD);
865 869 term_word(p, "-");
866 870 term_fontpop(p);
867 871 break;
868 872 case LIST_enum:
869 873 (pair->ppair->ppair->count)++;
870 874 (void)snprintf(buf, sizeof(buf), "%d.",
871 875 pair->ppair->ppair->count);
872 876 term_word(p, buf);
873 877 break;
874 878 default:
875 879 break;
876 880 }
877 881
878 882 /*
879 883 * If we're not going to process our children, indicate so here.
880 884 */
881 885
882 886 switch (type) {
883 887 case LIST_bullet:
884 888 case LIST_item:
885 889 case LIST_dash:
886 890 case LIST_hyphen:
887 891 case LIST_enum:
888 892 if (n->type == ROFFT_HEAD)
889 893 return 0;
890 894 break;
891 895 case LIST_column:
892 896 if (n->type == ROFFT_HEAD)
893 897 return 0;
894 898 p->minbl = 0;
895 899 break;
896 900 default:
897 901 break;
898 902 }
899 903
900 904 return 1;
901 905 }
902 906
903 907 static void
904 908 termp_it_post(DECL_ARGS)
905 909 {
906 910 enum mdoc_list type;
907 911
908 912 if (n->type == ROFFT_BLOCK)
909 913 return;
910 914
911 915 type = n->parent->parent->parent->norm->Bl.type;
912 916
913 917 switch (type) {
914 918 case LIST_item:
915 919 case LIST_diag:
916 920 case LIST_inset:
917 921 if (n->type == ROFFT_BODY)
918 922 term_newln(p);
919 923 break;
920 924 case LIST_column:
921 925 if (n->type == ROFFT_BODY)
922 926 term_flushln(p);
923 927 break;
924 928 default:
925 929 term_newln(p);
926 930 break;
927 931 }
928 932
929 933 /*
930 934 * Now that our output is flushed, we can reset our tags. Since
931 935 * only `It' sets these flags, we're free to assume that nobody
932 936 * has munged them in the meanwhile.
933 937 */
934 938
935 939 p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | TERMP_HANG);
936 940 p->trailspace = 0;
937 941 }
938 942
939 943 static int
940 944 termp_nm_pre(DECL_ARGS)
941 945 {
942 946 const char *cp;
943 947
944 948 if (n->type == ROFFT_BLOCK) {
945 949 p->flags |= TERMP_PREKEEP;
946 950 return 1;
947 951 }
948 952
949 953 if (n->type == ROFFT_BODY) {
950 954 if (n->child == NULL)
951 955 return 0;
952 956 p->flags |= TERMP_NOSPACE;
953 957 cp = NULL;
954 958 if (n->prev->child != NULL)
955 959 cp = n->prev->child->string;
956 960 if (cp == NULL)
957 961 cp = meta->name;
958 962 if (cp == NULL)
959 963 p->tcol->offset += term_len(p, 6);
960 964 else
961 965 p->tcol->offset += term_len(p, 1) +
962 966 term_strlen(p, cp);
963 967 return 1;
964 968 }
965 969
966 970 if (n->child == NULL)
967 971 return 0;
968 972
969 973 if (n->type == ROFFT_HEAD)
970 974 synopsis_pre(p, n->parent);
971 975
972 976 if (n->type == ROFFT_HEAD &&
973 977 n->next != NULL && n->next->child != NULL) {
974 978 p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
975 979 p->trailspace = 1;
976 980 p->tcol->rmargin = p->tcol->offset + term_len(p, 1);
977 981 if (n->child == NULL)
978 982 p->tcol->rmargin += term_strlen(p, meta->name);
979 983 else if (n->child->type == ROFFT_TEXT) {
980 984 p->tcol->rmargin += term_strlen(p, n->child->string);
981 985 if (n->child->next != NULL)
982 986 p->flags |= TERMP_HANG;
983 987 } else {
984 988 p->tcol->rmargin += term_len(p, 5);
985 989 p->flags |= TERMP_HANG;
986 990 }
987 991 }
988 992
989 993 term_fontpush(p, TERMFONT_BOLD);
990 994 return 1;
991 995 }
992 996
993 997 static void
994 998 termp_nm_post(DECL_ARGS)
995 999 {
996 1000
997 1001 if (n->type == ROFFT_BLOCK) {
998 1002 p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
999 1003 } else if (n->type == ROFFT_HEAD &&
1000 1004 NULL != n->next && NULL != n->next->child) {
1001 1005 term_flushln(p);
1002 1006 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
1003 1007 p->trailspace = 0;
1004 1008 } else if (n->type == ROFFT_BODY && n->child != NULL)
1005 1009 term_flushln(p);
1006 1010 }
1007 1011
1008 1012 static int
1009 1013 termp_fl_pre(DECL_ARGS)
1010 1014 {
1011 1015
1012 1016 termp_tag_pre(p, pair, meta, n);
1013 1017 term_fontpush(p, TERMFONT_BOLD);
1014 1018 term_word(p, "\\-");
1015 1019
1016 1020 if (!(n->child == NULL &&
1017 1021 (n->next == NULL ||
1018 1022 n->next->type == ROFFT_TEXT ||
1019 1023 n->next->flags & NODE_LINE)))
1020 1024 p->flags |= TERMP_NOSPACE;
1021 1025
1022 1026 return 1;
1023 1027 }
1024 1028
1025 1029 static int
1026 1030 termp__a_pre(DECL_ARGS)
1027 1031 {
1028 1032
1029 1033 if (n->prev && MDOC__A == n->prev->tok)
1030 1034 if (NULL == n->next || MDOC__A != n->next->tok)
1031 1035 term_word(p, "and");
1032 1036
1033 1037 return 1;
1034 1038 }
1035 1039
1036 1040 static int
1037 1041 termp_an_pre(DECL_ARGS)
1038 1042 {
1039 1043
1040 1044 if (n->norm->An.auth == AUTH_split) {
1041 1045 p->flags &= ~TERMP_NOSPLIT;
1042 1046 p->flags |= TERMP_SPLIT;
1043 1047 return 0;
1044 1048 }
1045 1049 if (n->norm->An.auth == AUTH_nosplit) {
1046 1050 p->flags &= ~TERMP_SPLIT;
1047 1051 p->flags |= TERMP_NOSPLIT;
1048 1052 return 0;
1049 1053 }
1050 1054
1051 1055 if (p->flags & TERMP_SPLIT)
1052 1056 term_newln(p);
1053 1057
1054 1058 if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
1055 1059 p->flags |= TERMP_SPLIT;
1056 1060
1057 1061 return 1;
1058 1062 }
1059 1063
1060 1064 static int
1061 1065 termp_ns_pre(DECL_ARGS)
1062 1066 {
1063 1067
1064 1068 if ( ! (NODE_LINE & n->flags))
1065 1069 p->flags |= TERMP_NOSPACE;
1066 1070 return 1;
1067 1071 }
1068 1072
1069 1073 static int
1070 1074 termp_rs_pre(DECL_ARGS)
1071 1075 {
1072 1076
1073 1077 if (SEC_SEE_ALSO != n->sec)
1074 1078 return 1;
1075 1079 if (n->type == ROFFT_BLOCK && n->prev != NULL)
1076 1080 term_vspace(p);
1077 1081 return 1;
1078 1082 }
1079 1083
1080 1084 static int
1081 1085 termp_ex_pre(DECL_ARGS)
1082 1086 {
1083 1087 term_newln(p);
1084 1088 return 1;
1085 1089 }
1086 1090
1087 1091 static int
1088 1092 termp_nd_pre(DECL_ARGS)
1089 1093 {
1090 1094
1091 1095 if (n->type == ROFFT_BODY)
1092 1096 term_word(p, "\\(en");
1093 1097 return 1;
1094 1098 }
1095 1099
1096 1100 static int
1097 1101 termp_bl_pre(DECL_ARGS)
1098 1102 {
1099 1103
1100 1104 return n->type != ROFFT_HEAD;
1101 1105 }
1102 1106
1103 1107 static void
1104 1108 termp_bl_post(DECL_ARGS)
1105 1109 {
1106 1110
1107 1111 if (n->type != ROFFT_BLOCK)
1108 1112 return;
1109 1113 term_newln(p);
1110 1114 if (n->tok != MDOC_Bl || n->norm->Bl.type != LIST_column)
1111 1115 return;
1112 1116 term_tab_set(p, NULL);
1113 1117 term_tab_set(p, "T");
1114 1118 term_tab_set(p, ".5i");
1115 1119 }
1116 1120
1117 1121 static int
1118 1122 termp_xr_pre(DECL_ARGS)
1119 1123 {
1120 1124
1121 1125 if (NULL == (n = n->child))
1122 1126 return 0;
1123 1127
1124 1128 assert(n->type == ROFFT_TEXT);
1125 1129 term_word(p, n->string);
1126 1130
1127 1131 if (NULL == (n = n->next))
1128 1132 return 0;
1129 1133
1130 1134 p->flags |= TERMP_NOSPACE;
1131 1135 term_word(p, "(");
1132 1136 p->flags |= TERMP_NOSPACE;
1133 1137
1134 1138 assert(n->type == ROFFT_TEXT);
1135 1139 term_word(p, n->string);
1136 1140
1137 1141 p->flags |= TERMP_NOSPACE;
1138 1142 term_word(p, ")");
1139 1143
1140 1144 return 0;
1141 1145 }
1142 1146
1143 1147 /*
1144 1148 * This decides how to assert whitespace before any of the SYNOPSIS set
1145 1149 * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
1146 1150 * macro combos).
1147 1151 */
1148 1152 static void
1149 1153 synopsis_pre(struct termp *p, const struct roff_node *n)
1150 1154 {
1151 1155 /*
1152 1156 * Obviously, if we're not in a SYNOPSIS or no prior macros
1153 1157 * exist, do nothing.
1154 1158 */
1155 1159 if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
1156 1160 return;
1157 1161
1158 1162 /*
1159 1163 * If we're the second in a pair of like elements, emit our
1160 1164 * newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
1161 1165 * case we soldier on.
1162 1166 */
1163 1167 if (n->prev->tok == n->tok &&
1164 1168 MDOC_Ft != n->tok &&
1165 1169 MDOC_Fo != n->tok &&
1166 1170 MDOC_Fn != n->tok) {
1167 1171 term_newln(p);
1168 1172 return;
1169 1173 }
1170 1174
1171 1175 /*
1172 1176 * If we're one of the SYNOPSIS set and non-like pair-wise after
1173 1177 * another (or Fn/Fo, which we've let slip through) then assert
1174 1178 * vertical space, else only newline and move on.
1175 1179 */
1176 1180 switch (n->prev->tok) {
1177 1181 case MDOC_Fd:
1178 1182 case MDOC_Fn:
1179 1183 case MDOC_Fo:
1180 1184 case MDOC_In:
1181 1185 case MDOC_Vt:
1182 1186 term_vspace(p);
1183 1187 break;
1184 1188 case MDOC_Ft:
1185 1189 if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
1186 1190 term_vspace(p);
1187 1191 break;
1188 1192 }
1189 1193 /* FALLTHROUGH */
1190 1194 default:
1191 1195 term_newln(p);
1192 1196 break;
1193 1197 }
1194 1198 }
1195 1199
1196 1200 static int
1197 1201 termp_vt_pre(DECL_ARGS)
1198 1202 {
1199 1203
1200 1204 if (n->type == ROFFT_ELEM) {
1201 1205 synopsis_pre(p, n);
1202 1206 return termp_under_pre(p, pair, meta, n);
1203 1207 } else if (n->type == ROFFT_BLOCK) {
1204 1208 synopsis_pre(p, n);
1205 1209 return 1;
1206 1210 } else if (n->type == ROFFT_HEAD)
1207 1211 return 0;
1208 1212
1209 1213 return termp_under_pre(p, pair, meta, n);
1210 1214 }
1211 1215
1212 1216 static int
1213 1217 termp_bold_pre(DECL_ARGS)
1214 1218 {
1215 1219
1216 1220 termp_tag_pre(p, pair, meta, n);
1217 1221 term_fontpush(p, TERMFONT_BOLD);
1218 1222 return 1;
1219 1223 }
1220 1224
1221 1225 static int
1222 1226 termp_fd_pre(DECL_ARGS)
1223 1227 {
1224 1228
1225 1229 synopsis_pre(p, n);
1226 1230 return termp_bold_pre(p, pair, meta, n);
1227 1231 }
1228 1232
1229 1233 static void
1230 1234 termp_fd_post(DECL_ARGS)
1231 1235 {
1232 1236
1233 1237 term_newln(p);
1234 1238 }
1235 1239
1236 1240 static int
1237 1241 termp_sh_pre(DECL_ARGS)
1238 1242 {
1239 1243
1240 1244 switch (n->type) {
1241 1245 case ROFFT_BLOCK:
1242 1246 /*
1243 1247 * Vertical space before sections, except
1244 1248 * when the previous section was empty.
1245 1249 */
1246 1250 if (n->prev == NULL ||
1247 1251 n->prev->tok != MDOC_Sh ||
1248 1252 (n->prev->body != NULL &&
1249 1253 n->prev->body->child != NULL))
1250 1254 term_vspace(p);
1251 1255 break;
1252 1256 case ROFFT_HEAD:
1253 1257 term_fontpush(p, TERMFONT_BOLD);
1254 1258 break;
1255 1259 case ROFFT_BODY:
1256 1260 p->tcol->offset = term_len(p, p->defindent);
1257 1261 term_tab_set(p, NULL);
1258 1262 term_tab_set(p, "T");
1259 1263 term_tab_set(p, ".5i");
1260 1264 switch (n->sec) {
1261 1265 case SEC_DESCRIPTION:
1262 1266 fn_prio = 0;
1263 1267 break;
1264 1268 case SEC_AUTHORS:
1265 1269 p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
1266 1270 break;
1267 1271 default:
1268 1272 break;
1269 1273 }
1270 1274 break;
1271 1275 default:
1272 1276 break;
1273 1277 }
1274 1278 return 1;
1275 1279 }
1276 1280
1277 1281 static void
1278 1282 termp_sh_post(DECL_ARGS)
1279 1283 {
1280 1284
1281 1285 switch (n->type) {
1282 1286 case ROFFT_HEAD:
1283 1287 term_newln(p);
1284 1288 break;
1285 1289 case ROFFT_BODY:
1286 1290 term_newln(p);
1287 1291 p->tcol->offset = 0;
1288 1292 break;
1289 1293 default:
1290 1294 break;
1291 1295 }
1292 1296 }
1293 1297
1294 1298 static void
1295 1299 termp_lb_post(DECL_ARGS)
1296 1300 {
1297 1301
1298 1302 if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags)
1299 1303 term_newln(p);
1300 1304 }
1301 1305
1302 1306 static int
1303 1307 termp_d1_pre(DECL_ARGS)
1304 1308 {
1305 1309
1306 1310 if (n->type != ROFFT_BLOCK)
1307 1311 return 1;
1308 1312 term_newln(p);
1309 1313 p->tcol->offset += term_len(p, p->defindent + 1);
1310 1314 term_tab_set(p, NULL);
1311 1315 term_tab_set(p, "T");
1312 1316 term_tab_set(p, ".5i");
1313 1317 return 1;
1314 1318 }
1315 1319
1316 1320 static int
1317 1321 termp_ft_pre(DECL_ARGS)
1318 1322 {
1319 1323
1320 1324 /* NB: NODE_LINE does not effect this! */
1321 1325 synopsis_pre(p, n);
1322 1326 term_fontpush(p, TERMFONT_UNDER);
1323 1327 return 1;
1324 1328 }
1325 1329
1326 1330 static int
1327 1331 termp_fn_pre(DECL_ARGS)
1328 1332 {
1329 1333 size_t rmargin = 0;
1330 1334 int pretty;
1331 1335
1332 1336 pretty = NODE_SYNPRETTY & n->flags;
1333 1337
1334 1338 synopsis_pre(p, n);
1335 1339
1336 1340 if (NULL == (n = n->child))
1337 1341 return 0;
1338 1342
1339 1343 if (pretty) {
1340 1344 rmargin = p->tcol->rmargin;
1341 1345 p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
1342 1346 p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
1343 1347 }
1344 1348
1345 1349 assert(n->type == ROFFT_TEXT);
1346 1350 term_fontpush(p, TERMFONT_BOLD);
1347 1351 term_word(p, n->string);
1348 1352 term_fontpop(p);
1349 1353
1350 1354 if (n->sec == SEC_DESCRIPTION || n->sec == SEC_CUSTOM)
1351 1355 tag_put(n->string, ++fn_prio, p->line);
1352 1356
1353 1357 if (pretty) {
1354 1358 term_flushln(p);
1355 1359 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
1356 1360 p->flags |= TERMP_NOPAD;
1357 1361 p->tcol->offset = p->tcol->rmargin;
1358 1362 p->tcol->rmargin = rmargin;
1359 1363 }
1360 1364
1361 1365 p->flags |= TERMP_NOSPACE;
1362 1366 term_word(p, "(");
1363 1367 p->flags |= TERMP_NOSPACE;
1364 1368
1365 1369 for (n = n->next; n; n = n->next) {
1366 1370 assert(n->type == ROFFT_TEXT);
1367 1371 term_fontpush(p, TERMFONT_UNDER);
1368 1372 if (pretty)
1369 1373 p->flags |= TERMP_NBRWORD;
1370 1374 term_word(p, n->string);
1371 1375 term_fontpop(p);
1372 1376
1373 1377 if (n->next) {
1374 1378 p->flags |= TERMP_NOSPACE;
1375 1379 term_word(p, ",");
1376 1380 }
1377 1381 }
1378 1382
1379 1383 p->flags |= TERMP_NOSPACE;
1380 1384 term_word(p, ")");
1381 1385
1382 1386 if (pretty) {
1383 1387 p->flags |= TERMP_NOSPACE;
1384 1388 term_word(p, ";");
1385 1389 term_flushln(p);
1386 1390 }
1387 1391
1388 1392 return 0;
1389 1393 }
1390 1394
1391 1395 static int
1392 1396 termp_fa_pre(DECL_ARGS)
1393 1397 {
1394 1398 const struct roff_node *nn;
1395 1399
1396 1400 if (n->parent->tok != MDOC_Fo) {
1397 1401 term_fontpush(p, TERMFONT_UNDER);
1398 1402 return 1;
1399 1403 }
1400 1404
1401 1405 for (nn = n->child; nn; nn = nn->next) {
1402 1406 term_fontpush(p, TERMFONT_UNDER);
1403 1407 p->flags |= TERMP_NBRWORD;
1404 1408 term_word(p, nn->string);
1405 1409 term_fontpop(p);
1406 1410
1407 1411 if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
1408 1412 p->flags |= TERMP_NOSPACE;
1409 1413 term_word(p, ",");
1410 1414 }
1411 1415 }
1412 1416
1413 1417 return 0;
1414 1418 }
1415 1419
1416 1420 static int
1417 1421 termp_bd_pre(DECL_ARGS)
1418 1422 {
1419 1423 size_t lm, len;
1420 1424 struct roff_node *nn;
1421 1425 int offset;
1422 1426
1423 1427 if (n->type == ROFFT_BLOCK) {
1424 1428 print_bvspace(p, n, n);
1425 1429 return 1;
1426 1430 } else if (n->type == ROFFT_HEAD)
1427 1431 return 0;
1428 1432
1429 1433 /* Handle the -offset argument. */
1430 1434
1431 1435 if (n->norm->Bd.offs == NULL ||
1432 1436 ! strcmp(n->norm->Bd.offs, "left"))
1433 1437 /* nothing */;
1434 1438 else if ( ! strcmp(n->norm->Bd.offs, "indent"))
1435 1439 p->tcol->offset += term_len(p, p->defindent + 1);
1436 1440 else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
1437 1441 p->tcol->offset += term_len(p, (p->defindent + 1) * 2);
1438 1442 else {
1439 1443 offset = a2width(p, n->norm->Bd.offs);
1440 1444 if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
1441 1445 p->tcol->offset = 0;
1442 1446 else if (offset < SHRT_MAX)
1443 1447 p->tcol->offset += offset;
1444 1448 }
1445 1449
1446 1450 /*
1447 1451 * If -ragged or -filled are specified, the block does nothing
1448 1452 * but change the indentation. If -unfilled or -literal are
1449 1453 * specified, text is printed exactly as entered in the display:
1450 1454 * for macro lines, a newline is appended to the line. Blank
1451 1455 * lines are allowed.
1452 1456 */
1453 1457
1454 1458 if (n->norm->Bd.type != DISP_literal &&
1455 1459 n->norm->Bd.type != DISP_unfilled &&
1456 1460 n->norm->Bd.type != DISP_centered)
1457 1461 return 1;
1458 1462
1459 1463 if (n->norm->Bd.type == DISP_literal) {
1460 1464 term_tab_set(p, NULL);
1461 1465 term_tab_set(p, "T");
1462 1466 term_tab_set(p, "8n");
1463 1467 }
1464 1468
1465 1469 lm = p->tcol->offset;
1466 1470 p->flags |= TERMP_BRNEVER;
1467 1471 for (nn = n->child; nn != NULL; nn = nn->next) {
1468 1472 if (n->norm->Bd.type == DISP_centered) {
1469 1473 if (nn->type == ROFFT_TEXT) {
1470 1474 len = term_strlen(p, nn->string);
1471 1475 p->tcol->offset = len >= p->tcol->rmargin ?
1472 1476 0 : lm + len >= p->tcol->rmargin ?
1473 1477 p->tcol->rmargin - len :
1474 1478 (lm + p->tcol->rmargin - len) / 2;
1475 1479 } else
1476 1480 p->tcol->offset = lm;
1477 1481 }
1478 1482 print_mdoc_node(p, pair, meta, nn);
1479 1483 /*
1480 1484 * If the printed node flushes its own line, then we
1481 1485 * needn't do it here as well. This is hacky, but the
1482 1486 * notion of selective eoln whitespace is pretty dumb
1483 1487 * anyway, so don't sweat it.
1484 1488 */
1485 1489 if (nn->tok < ROFF_MAX)
1486 1490 continue;
1487 1491 switch (nn->tok) {
1488 1492 case MDOC_Sm:
1489 1493 case MDOC_Bl:
1490 1494 case MDOC_D1:
1491 1495 case MDOC_Dl:
1492 1496 case MDOC_Lp:
1493 1497 case MDOC_Pp:
1494 1498 continue;
1495 1499 default:
1496 1500 break;
1497 1501 }
1498 1502 if (p->flags & TERMP_NONEWLINE ||
1499 1503 (nn->next && ! (nn->next->flags & NODE_LINE)))
1500 1504 continue;
1501 1505 term_flushln(p);
1502 1506 p->flags |= TERMP_NOSPACE;
1503 1507 }
1504 1508 p->flags &= ~TERMP_BRNEVER;
1505 1509 return 0;
1506 1510 }
1507 1511
1508 1512 static void
1509 1513 termp_bd_post(DECL_ARGS)
1510 1514 {
1511 1515 if (n->type != ROFFT_BODY)
1512 1516 return;
1513 1517 if (DISP_literal == n->norm->Bd.type ||
1514 1518 DISP_unfilled == n->norm->Bd.type)
1515 1519 p->flags |= TERMP_BRNEVER;
1516 1520 p->flags |= TERMP_NOSPACE;
1517 1521 term_newln(p);
1518 1522 p->flags &= ~TERMP_BRNEVER;
1519 1523 }
1520 1524
1521 1525 static int
1522 1526 termp_xx_pre(DECL_ARGS)
1523 1527 {
1524 1528 if ((n->aux = p->flags & TERMP_PREKEEP) == 0)
1525 1529 p->flags |= TERMP_PREKEEP;
1526 1530 return 1;
1527 1531 }
1528 1532
1529 1533 static void
1530 1534 termp_xx_post(DECL_ARGS)
1531 1535 {
1532 1536 if (n->aux == 0)
1533 1537 p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
1534 1538 }
1535 1539
1536 1540 static void
1537 1541 termp_pf_post(DECL_ARGS)
1538 1542 {
1539 1543
1540 1544 if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
1541 1545 p->flags |= TERMP_NOSPACE;
1542 1546 }
↓ open down ↓ |
962 lines elided |
↑ open up ↑ |
1543 1547
1544 1548 static int
1545 1549 termp_ss_pre(DECL_ARGS)
1546 1550 {
1547 1551 struct roff_node *nn;
1548 1552
1549 1553 switch (n->type) {
1550 1554 case ROFFT_BLOCK:
1551 1555 term_newln(p);
1552 1556 for (nn = n->prev; nn != NULL; nn = nn->prev)
1553 - if ((nn->flags & NODE_NOPRT) == 0)
1557 + if (nn->type != ROFFT_COMMENT &&
1558 + (nn->flags & NODE_NOPRT) == 0)
1554 1559 break;
1555 1560 if (nn != NULL)
1556 1561 term_vspace(p);
1557 1562 break;
1558 1563 case ROFFT_HEAD:
1559 1564 term_fontpush(p, TERMFONT_BOLD);
1560 1565 p->tcol->offset = term_len(p, (p->defindent+1)/2);
1561 1566 break;
1562 1567 case ROFFT_BODY:
1563 1568 p->tcol->offset = term_len(p, p->defindent);
1564 1569 term_tab_set(p, NULL);
1565 1570 term_tab_set(p, "T");
1566 1571 term_tab_set(p, ".5i");
1567 1572 break;
1568 1573 default:
1569 1574 break;
1570 1575 }
1571 1576
1572 1577 return 1;
1573 1578 }
1574 1579
1575 1580 static void
1576 1581 termp_ss_post(DECL_ARGS)
1577 1582 {
1578 1583
1579 1584 if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY)
1580 1585 term_newln(p);
1581 1586 }
1582 1587
1583 1588 static int
1584 1589 termp_cd_pre(DECL_ARGS)
1585 1590 {
1586 1591
1587 1592 synopsis_pre(p, n);
1588 1593 term_fontpush(p, TERMFONT_BOLD);
1589 1594 return 1;
1590 1595 }
1591 1596
1592 1597 static int
1593 1598 termp_in_pre(DECL_ARGS)
1594 1599 {
1595 1600
1596 1601 synopsis_pre(p, n);
1597 1602
1598 1603 if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags) {
1599 1604 term_fontpush(p, TERMFONT_BOLD);
1600 1605 term_word(p, "#include");
1601 1606 term_word(p, "<");
1602 1607 } else {
1603 1608 term_word(p, "<");
1604 1609 term_fontpush(p, TERMFONT_UNDER);
1605 1610 }
1606 1611
1607 1612 p->flags |= TERMP_NOSPACE;
1608 1613 return 1;
1609 1614 }
1610 1615
1611 1616 static void
1612 1617 termp_in_post(DECL_ARGS)
1613 1618 {
1614 1619
1615 1620 if (NODE_SYNPRETTY & n->flags)
1616 1621 term_fontpush(p, TERMFONT_BOLD);
1617 1622
1618 1623 p->flags |= TERMP_NOSPACE;
1619 1624 term_word(p, ">");
1620 1625
1621 1626 if (NODE_SYNPRETTY & n->flags)
1622 1627 term_fontpop(p);
1623 1628 }
1624 1629
1625 1630 static int
1626 1631 termp_pp_pre(DECL_ARGS)
1627 1632 {
1628 1633 fn_prio = 0;
1629 1634 term_vspace(p);
1630 1635 return 0;
1631 1636 }
1632 1637
1633 1638 static int
1634 1639 termp_skip_pre(DECL_ARGS)
1635 1640 {
1636 1641
1637 1642 return 0;
1638 1643 }
1639 1644
1640 1645 static int
1641 1646 termp_quote_pre(DECL_ARGS)
1642 1647 {
1643 1648
1644 1649 if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
1645 1650 return 1;
1646 1651
1647 1652 switch (n->tok) {
1648 1653 case MDOC_Ao:
1649 1654 case MDOC_Aq:
1650 1655 term_word(p, n->child != NULL && n->child->next == NULL &&
1651 1656 n->child->tok == MDOC_Mt ? "<" : "\\(la");
1652 1657 break;
1653 1658 case MDOC_Bro:
1654 1659 case MDOC_Brq:
1655 1660 term_word(p, "{");
1656 1661 break;
↓ open down ↓ |
93 lines elided |
↑ open up ↑ |
1657 1662 case MDOC_Oo:
1658 1663 case MDOC_Op:
1659 1664 case MDOC_Bo:
1660 1665 case MDOC_Bq:
1661 1666 term_word(p, "[");
1662 1667 break;
1663 1668 case MDOC__T:
1664 1669 /* FALLTHROUGH */
1665 1670 case MDOC_Do:
1666 1671 case MDOC_Dq:
1667 - term_word(p, "\\(Lq");
1672 + term_word(p, "\\(lq");
1668 1673 break;
1669 1674 case MDOC_En:
1670 1675 if (NULL == n->norm->Es ||
1671 1676 NULL == n->norm->Es->child)
1672 1677 return 1;
1673 1678 term_word(p, n->norm->Es->child->string);
1674 1679 break;
1675 1680 case MDOC_Po:
1676 1681 case MDOC_Pq:
1677 1682 term_word(p, "(");
1678 1683 break;
1679 1684 case MDOC_Qo:
1680 1685 case MDOC_Qq:
1681 1686 term_word(p, "\"");
1682 1687 break;
1683 1688 case MDOC_Ql:
1684 1689 case MDOC_So:
1685 1690 case MDOC_Sq:
1686 1691 term_word(p, "\\(oq");
1687 1692 break;
1688 1693 default:
1689 1694 abort();
1690 1695 }
1691 1696
1692 1697 p->flags |= TERMP_NOSPACE;
1693 1698 return 1;
1694 1699 }
1695 1700
1696 1701 static void
1697 1702 termp_quote_post(DECL_ARGS)
1698 1703 {
1699 1704
1700 1705 if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
1701 1706 return;
1702 1707
1703 1708 p->flags |= TERMP_NOSPACE;
1704 1709
1705 1710 switch (n->tok) {
1706 1711 case MDOC_Ao:
1707 1712 case MDOC_Aq:
1708 1713 term_word(p, n->child != NULL && n->child->next == NULL &&
1709 1714 n->child->tok == MDOC_Mt ? ">" : "\\(ra");
1710 1715 break;
1711 1716 case MDOC_Bro:
1712 1717 case MDOC_Brq:
1713 1718 term_word(p, "}");
1714 1719 break;
↓ open down ↓ |
37 lines elided |
↑ open up ↑ |
1715 1720 case MDOC_Oo:
1716 1721 case MDOC_Op:
1717 1722 case MDOC_Bo:
1718 1723 case MDOC_Bq:
1719 1724 term_word(p, "]");
1720 1725 break;
1721 1726 case MDOC__T:
1722 1727 /* FALLTHROUGH */
1723 1728 case MDOC_Do:
1724 1729 case MDOC_Dq:
1725 - term_word(p, "\\(Rq");
1730 + term_word(p, "\\(rq");
1726 1731 break;
1727 1732 case MDOC_En:
1728 1733 if (n->norm->Es == NULL ||
1729 1734 n->norm->Es->child == NULL ||
1730 1735 n->norm->Es->child->next == NULL)
1731 1736 p->flags &= ~TERMP_NOSPACE;
1732 1737 else
1733 1738 term_word(p, n->norm->Es->child->next->string);
1734 1739 break;
1735 1740 case MDOC_Po:
1736 1741 case MDOC_Pq:
1737 1742 term_word(p, ")");
1738 1743 break;
1739 1744 case MDOC_Qo:
1740 1745 case MDOC_Qq:
1741 1746 term_word(p, "\"");
1742 1747 break;
1743 1748 case MDOC_Ql:
1744 1749 case MDOC_So:
1745 1750 case MDOC_Sq:
1746 1751 term_word(p, "\\(cq");
1747 1752 break;
1748 1753 default:
1749 1754 abort();
1750 1755 }
1751 1756 }
1752 1757
1753 1758 static int
1754 1759 termp_eo_pre(DECL_ARGS)
1755 1760 {
1756 1761
1757 1762 if (n->type != ROFFT_BODY)
1758 1763 return 1;
1759 1764
1760 1765 if (n->end == ENDBODY_NOT &&
1761 1766 n->parent->head->child == NULL &&
1762 1767 n->child != NULL &&
1763 1768 n->child->end != ENDBODY_NOT)
1764 1769 term_word(p, "\\&");
1765 1770 else if (n->end != ENDBODY_NOT ? n->child != NULL :
1766 1771 n->parent->head->child != NULL && (n->child != NULL ||
1767 1772 (n->parent->tail != NULL && n->parent->tail->child != NULL)))
1768 1773 p->flags |= TERMP_NOSPACE;
1769 1774
1770 1775 return 1;
1771 1776 }
1772 1777
1773 1778 static void
1774 1779 termp_eo_post(DECL_ARGS)
1775 1780 {
1776 1781 int body, tail;
1777 1782
1778 1783 if (n->type != ROFFT_BODY)
1779 1784 return;
1780 1785
1781 1786 if (n->end != ENDBODY_NOT) {
1782 1787 p->flags &= ~TERMP_NOSPACE;
1783 1788 return;
1784 1789 }
1785 1790
1786 1791 body = n->child != NULL || n->parent->head->child != NULL;
1787 1792 tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
1788 1793
1789 1794 if (body && tail)
1790 1795 p->flags |= TERMP_NOSPACE;
1791 1796 else if ( ! (body || tail))
1792 1797 term_word(p, "\\&");
1793 1798 else if ( ! tail)
1794 1799 p->flags &= ~TERMP_NOSPACE;
1795 1800 }
1796 1801
1797 1802 static int
1798 1803 termp_fo_pre(DECL_ARGS)
1799 1804 {
1800 1805 size_t rmargin = 0;
1801 1806 int pretty;
1802 1807
1803 1808 pretty = NODE_SYNPRETTY & n->flags;
1804 1809
1805 1810 if (n->type == ROFFT_BLOCK) {
1806 1811 synopsis_pre(p, n);
1807 1812 return 1;
1808 1813 } else if (n->type == ROFFT_BODY) {
1809 1814 if (pretty) {
1810 1815 rmargin = p->tcol->rmargin;
1811 1816 p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
1812 1817 p->flags |= TERMP_NOBREAK | TERMP_BRIND |
1813 1818 TERMP_HANG;
1814 1819 }
1815 1820 p->flags |= TERMP_NOSPACE;
1816 1821 term_word(p, "(");
1817 1822 p->flags |= TERMP_NOSPACE;
1818 1823 if (pretty) {
1819 1824 term_flushln(p);
1820 1825 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
1821 1826 TERMP_HANG);
1822 1827 p->flags |= TERMP_NOPAD;
1823 1828 p->tcol->offset = p->tcol->rmargin;
1824 1829 p->tcol->rmargin = rmargin;
1825 1830 }
1826 1831 return 1;
1827 1832 }
1828 1833
1829 1834 if (NULL == n->child)
1830 1835 return 0;
1831 1836
1832 1837 /* XXX: we drop non-initial arguments as per groff. */
1833 1838
1834 1839 assert(n->child->string);
1835 1840 term_fontpush(p, TERMFONT_BOLD);
1836 1841 term_word(p, n->child->string);
1837 1842 return 0;
1838 1843 }
1839 1844
1840 1845 static void
1841 1846 termp_fo_post(DECL_ARGS)
1842 1847 {
1843 1848
1844 1849 if (n->type != ROFFT_BODY)
1845 1850 return;
1846 1851
1847 1852 p->flags |= TERMP_NOSPACE;
1848 1853 term_word(p, ")");
1849 1854
1850 1855 if (NODE_SYNPRETTY & n->flags) {
1851 1856 p->flags |= TERMP_NOSPACE;
1852 1857 term_word(p, ";");
1853 1858 term_flushln(p);
1854 1859 }
1855 1860 }
1856 1861
1857 1862 static int
1858 1863 termp_bf_pre(DECL_ARGS)
1859 1864 {
1860 1865
1861 1866 if (n->type == ROFFT_HEAD)
1862 1867 return 0;
1863 1868 else if (n->type != ROFFT_BODY)
1864 1869 return 1;
1865 1870
1866 1871 if (FONT_Em == n->norm->Bf.font)
1867 1872 term_fontpush(p, TERMFONT_UNDER);
1868 1873 else if (FONT_Sy == n->norm->Bf.font)
1869 1874 term_fontpush(p, TERMFONT_BOLD);
1870 1875 else
1871 1876 term_fontpush(p, TERMFONT_NONE);
1872 1877
1873 1878 return 1;
1874 1879 }
1875 1880
1876 1881 static int
1877 1882 termp_sm_pre(DECL_ARGS)
1878 1883 {
1879 1884
1880 1885 if (NULL == n->child)
1881 1886 p->flags ^= TERMP_NONOSPACE;
1882 1887 else if (0 == strcmp("on", n->child->string))
1883 1888 p->flags &= ~TERMP_NONOSPACE;
1884 1889 else
1885 1890 p->flags |= TERMP_NONOSPACE;
1886 1891
1887 1892 if (p->col && ! (TERMP_NONOSPACE & p->flags))
1888 1893 p->flags &= ~TERMP_NOSPACE;
1889 1894
1890 1895 return 0;
1891 1896 }
1892 1897
1893 1898 static int
1894 1899 termp_ap_pre(DECL_ARGS)
1895 1900 {
1896 1901
1897 1902 p->flags |= TERMP_NOSPACE;
1898 1903 term_word(p, "'");
1899 1904 p->flags |= TERMP_NOSPACE;
1900 1905 return 1;
1901 1906 }
1902 1907
1903 1908 static void
1904 1909 termp____post(DECL_ARGS)
1905 1910 {
1906 1911
1907 1912 /*
1908 1913 * Handle lists of authors. In general, print each followed by
1909 1914 * a comma. Don't print the comma if there are only two
1910 1915 * authors.
1911 1916 */
1912 1917 if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
1913 1918 if (NULL == n->next->next || MDOC__A != n->next->next->tok)
1914 1919 if (NULL == n->prev || MDOC__A != n->prev->tok)
1915 1920 return;
1916 1921
1917 1922 /* TODO: %U. */
1918 1923
1919 1924 if (NULL == n->parent || MDOC_Rs != n->parent->tok)
1920 1925 return;
1921 1926
1922 1927 p->flags |= TERMP_NOSPACE;
1923 1928 if (NULL == n->next) {
1924 1929 term_word(p, ".");
1925 1930 p->flags |= TERMP_SENTENCE;
1926 1931 } else
1927 1932 term_word(p, ",");
1928 1933 }
1929 1934
1930 1935 static int
1931 1936 termp_li_pre(DECL_ARGS)
1932 1937 {
↓ open down ↓ |
197 lines elided |
↑ open up ↑ |
1933 1938
1934 1939 termp_tag_pre(p, pair, meta, n);
1935 1940 term_fontpush(p, TERMFONT_NONE);
1936 1941 return 1;
1937 1942 }
1938 1943
1939 1944 static int
1940 1945 termp_lk_pre(DECL_ARGS)
1941 1946 {
1942 1947 const struct roff_node *link, *descr, *punct;
1943 - int display;
1944 1948
1945 1949 if ((link = n->child) == NULL)
1946 1950 return 0;
1947 1951
1948 1952 /* Find beginning of trailing punctuation. */
1949 1953 punct = n->last;
1950 1954 while (punct != link && punct->flags & NODE_DELIMC)
1951 1955 punct = punct->prev;
1952 1956 punct = punct->next;
1953 1957
1954 1958 /* Link text. */
1955 1959 if ((descr = link->next) != NULL && descr != punct) {
1956 1960 term_fontpush(p, TERMFONT_UNDER);
1957 1961 while (descr != punct) {
1958 1962 if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
1959 1963 p->flags |= TERMP_NOSPACE;
1960 1964 term_word(p, descr->string);
1961 1965 descr = descr->next;
1962 1966 }
1963 1967 term_fontpop(p);
1964 1968 p->flags |= TERMP_NOSPACE;
1965 1969 term_word(p, ":");
1966 1970 }
1967 1971
1968 1972 /* Link target. */
1969 - display = term_strlen(p, link->string) >= 26;
1970 - if (display) {
1971 - term_newln(p);
1972 - p->tcol->offset += term_len(p, p->defindent + 1);
1973 - }
1974 1973 term_fontpush(p, TERMFONT_BOLD);
1975 1974 term_word(p, link->string);
1976 1975 term_fontpop(p);
1977 1976
1978 1977 /* Trailing punctuation. */
1979 1978 while (punct != NULL) {
1980 1979 p->flags |= TERMP_NOSPACE;
1981 1980 term_word(p, punct->string);
1982 1981 punct = punct->next;
1983 1982 }
1984 - if (display)
1985 - term_newln(p);
1986 1983 return 0;
1987 1984 }
1988 1985
1989 1986 static int
1990 1987 termp_bk_pre(DECL_ARGS)
1991 1988 {
1992 1989
1993 1990 switch (n->type) {
1994 1991 case ROFFT_BLOCK:
1995 1992 break;
1996 1993 case ROFFT_HEAD:
1997 1994 return 0;
1998 1995 case ROFFT_BODY:
1999 1996 if (n->parent->args != NULL || n->prev->child == NULL)
2000 1997 p->flags |= TERMP_PREKEEP;
2001 1998 break;
2002 1999 default:
2003 2000 abort();
2004 2001 }
2005 2002
2006 2003 return 1;
2007 2004 }
2008 2005
2009 2006 static void
2010 2007 termp_bk_post(DECL_ARGS)
2011 2008 {
2012 2009
2013 2010 if (n->type == ROFFT_BODY)
2014 2011 p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
2015 2012 }
2016 2013
2017 2014 static void
2018 2015 termp__t_post(DECL_ARGS)
2019 2016 {
2020 2017
2021 2018 /*
2022 2019 * If we're in an `Rs' and there's a journal present, then quote
2023 2020 * us instead of underlining us (for disambiguation).
2024 2021 */
2025 2022 if (n->parent && MDOC_Rs == n->parent->tok &&
2026 2023 n->parent->norm->Rs.quote_T)
2027 2024 termp_quote_post(p, pair, meta, n);
2028 2025
2029 2026 termp____post(p, pair, meta, n);
2030 2027 }
2031 2028
2032 2029 static int
2033 2030 termp__t_pre(DECL_ARGS)
2034 2031 {
2035 2032
2036 2033 /*
2037 2034 * If we're in an `Rs' and there's a journal present, then quote
2038 2035 * us instead of underlining us (for disambiguation).
2039 2036 */
2040 2037 if (n->parent && MDOC_Rs == n->parent->tok &&
2041 2038 n->parent->norm->Rs.quote_T)
2042 2039 return termp_quote_pre(p, pair, meta, n);
2043 2040
2044 2041 term_fontpush(p, TERMFONT_UNDER);
2045 2042 return 1;
2046 2043 }
2047 2044
2048 2045 static int
2049 2046 termp_under_pre(DECL_ARGS)
2050 2047 {
2051 2048
2052 2049 term_fontpush(p, TERMFONT_UNDER);
2053 2050 return 1;
2054 2051 }
2055 2052
2056 2053 static int
2057 2054 termp_em_pre(DECL_ARGS)
2058 2055 {
2059 2056 if (n->child != NULL &&
2060 2057 n->child->type == ROFFT_TEXT)
2061 2058 tag_put(n->child->string, 0, p->line);
2062 2059 term_fontpush(p, TERMFONT_UNDER);
2063 2060 return 1;
2064 2061 }
2065 2062
2066 2063 static int
2067 2064 termp_sy_pre(DECL_ARGS)
2068 2065 {
2069 2066 if (n->child != NULL &&
2070 2067 n->child->type == ROFFT_TEXT)
2071 2068 tag_put(n->child->string, 0, p->line);
2072 2069 term_fontpush(p, TERMFONT_BOLD);
2073 2070 return 1;
2074 2071 }
2075 2072
2076 2073 static int
2077 2074 termp_er_pre(DECL_ARGS)
2078 2075 {
2079 2076
2080 2077 if (n->sec == SEC_ERRORS &&
2081 2078 (n->parent->tok == MDOC_It ||
2082 2079 (n->parent->tok == MDOC_Bq &&
2083 2080 n->parent->parent->parent->tok == MDOC_It)))
2084 2081 tag_put(n->child->string, 1, p->line);
2085 2082 return 1;
2086 2083 }
2087 2084
2088 2085 static int
2089 2086 termp_tag_pre(DECL_ARGS)
2090 2087 {
2091 2088
2092 2089 if (n->child != NULL &&
2093 2090 n->child->type == ROFFT_TEXT &&
2094 2091 (n->prev == NULL ||
2095 2092 (n->prev->type == ROFFT_TEXT &&
2096 2093 strcmp(n->prev->string, "|") == 0)) &&
2097 2094 (n->parent->tok == MDOC_It ||
2098 2095 (n->parent->tok == MDOC_Xo &&
2099 2096 n->parent->parent->prev == NULL &&
2100 2097 n->parent->parent->parent->tok == MDOC_It)))
2101 2098 tag_put(n->child->string, 1, p->line);
2102 2099 return 1;
2103 2100 }
↓ open down ↓ |
108 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX