Print this page
Update to 1.12.3.
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mandoc/man_term.c
+++ new/usr/src/cmd/mandoc/man_term.c
1 -/* $Id: man_term.c,v 1.127 2012/01/03 15:16:24 kristaps Exp $ */
1 +/* $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */
2 2 /*
3 - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
3 + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
5 5 *
6 6 * Permission to use, copy, modify, and distribute this software for any
7 7 * purpose with or without fee is hereby granted, provided that the above
8 8 * copyright notice and this permission notice appear in all copies.
9 9 *
10 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 17 */
18 18 #ifdef HAVE_CONFIG_H
19 19 #include "config.h"
20 20 #endif
21 21
22 22 #include <sys/types.h>
23 23
24 24 #include <assert.h>
25 25 #include <ctype.h>
26 26 #include <stdio.h>
27 27 #include <stdlib.h>
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
28 28 #include <string.h>
29 29
30 30 #include "mandoc.h"
31 31 #include "out.h"
32 32 #include "man.h"
33 33 #include "term.h"
34 34 #include "main.h"
35 35
36 36 #define MAXMARGINS 64 /* maximum number of indented scopes */
37 37
38 -/* FIXME: have PD set the default vspace width. */
39 -
40 38 struct mtermp {
41 39 int fl;
42 40 #define MANT_LITERAL (1 << 0)
43 41 size_t lmargin[MAXMARGINS]; /* margins (incl. visible page) */
44 42 int lmargincur; /* index of current margin */
45 43 int lmarginsz; /* actual number of nested margins */
46 44 size_t offset; /* default offset to visible page */
45 + int pardist; /* vert. space before par., unit: [v] */
47 46 };
48 47
49 48 #define DECL_ARGS struct termp *p, \
50 49 struct mtermp *mt, \
51 50 const struct man_node *n, \
52 - const struct man_meta *m
51 + const struct man_meta *meta
53 52
54 53 struct termact {
55 54 int (*pre)(DECL_ARGS);
56 55 void (*post)(DECL_ARGS);
57 56 int flags;
58 57 #define MAN_NOTEXT (1 << 0) /* Never has text children. */
59 58 };
60 59
61 60 static int a2width(const struct termp *, const char *);
62 61 static size_t a2height(const struct termp *, const char *);
63 62
64 63 static void print_man_nodelist(DECL_ARGS);
65 64 static void print_man_node(DECL_ARGS);
66 65 static void print_man_head(struct termp *, const void *);
67 66 static void print_man_foot(struct termp *, const void *);
68 67 static void print_bvspace(struct termp *,
69 - const struct man_node *);
68 + const struct man_node *, int);
70 69
71 70 static int pre_B(DECL_ARGS);
72 71 static int pre_HP(DECL_ARGS);
73 72 static int pre_I(DECL_ARGS);
74 73 static int pre_IP(DECL_ARGS);
75 74 static int pre_OP(DECL_ARGS);
75 +static int pre_PD(DECL_ARGS);
76 76 static int pre_PP(DECL_ARGS);
77 77 static int pre_RS(DECL_ARGS);
78 78 static int pre_SH(DECL_ARGS);
79 79 static int pre_SS(DECL_ARGS);
80 80 static int pre_TP(DECL_ARGS);
81 +static int pre_UR(DECL_ARGS);
81 82 static int pre_alternate(DECL_ARGS);
82 83 static int pre_ft(DECL_ARGS);
83 84 static int pre_ign(DECL_ARGS);
84 85 static int pre_in(DECL_ARGS);
85 86 static int pre_literal(DECL_ARGS);
86 87 static int pre_sp(DECL_ARGS);
87 88
88 89 static void post_IP(DECL_ARGS);
89 90 static void post_HP(DECL_ARGS);
90 91 static void post_RS(DECL_ARGS);
91 92 static void post_SH(DECL_ARGS);
92 93 static void post_SS(DECL_ARGS);
93 94 static void post_TP(DECL_ARGS);
95 +static void post_UR(DECL_ARGS);
94 96
95 97 static const struct termact termacts[MAN_MAX] = {
96 98 { pre_sp, NULL, MAN_NOTEXT }, /* br */
97 99 { NULL, NULL, 0 }, /* TH */
98 100 { pre_SH, post_SH, 0 }, /* SH */
99 101 { pre_SS, post_SS, 0 }, /* SS */
100 102 { pre_TP, post_TP, 0 }, /* TP */
101 103 { pre_PP, NULL, 0 }, /* LP */
102 104 { pre_PP, NULL, 0 }, /* PP */
103 105 { pre_PP, NULL, 0 }, /* P */
104 106 { pre_IP, post_IP, 0 }, /* IP */
105 107 { pre_HP, post_HP, 0 }, /* HP */
106 108 { NULL, NULL, 0 }, /* SM */
107 109 { pre_B, NULL, 0 }, /* SB */
108 110 { pre_alternate, NULL, 0 }, /* BI */
109 111 { pre_alternate, NULL, 0 }, /* IB */
110 112 { pre_alternate, NULL, 0 }, /* BR */
111 113 { pre_alternate, NULL, 0 }, /* RB */
112 114 { NULL, NULL, 0 }, /* R */
113 115 { pre_B, NULL, 0 }, /* B */
114 116 { pre_I, NULL, 0 }, /* I */
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
115 117 { pre_alternate, NULL, 0 }, /* IR */
116 118 { pre_alternate, NULL, 0 }, /* RI */
117 119 { pre_ign, NULL, MAN_NOTEXT }, /* na */
118 120 { pre_sp, NULL, MAN_NOTEXT }, /* sp */
119 121 { pre_literal, NULL, 0 }, /* nf */
120 122 { pre_literal, NULL, 0 }, /* fi */
121 123 { NULL, NULL, 0 }, /* RE */
122 124 { pre_RS, post_RS, 0 }, /* RS */
123 125 { pre_ign, NULL, 0 }, /* DT */
124 126 { pre_ign, NULL, 0 }, /* UC */
125 - { pre_ign, NULL, 0 }, /* PD */
127 + { pre_PD, NULL, MAN_NOTEXT }, /* PD */
126 128 { pre_ign, NULL, 0 }, /* AT */
127 129 { pre_in, NULL, MAN_NOTEXT }, /* in */
128 130 { pre_ft, NULL, MAN_NOTEXT }, /* ft */
129 131 { pre_OP, NULL, 0 }, /* OP */
132 + { pre_literal, NULL, 0 }, /* EX */
133 + { pre_literal, NULL, 0 }, /* EE */
134 + { pre_UR, post_UR, 0 }, /* UR */
135 + { NULL, NULL, 0 }, /* UE */
130 136 };
131 137
132 138
133 139
134 140 void
135 141 terminal_man(void *arg, const struct man *man)
136 142 {
137 143 struct termp *p;
138 144 const struct man_node *n;
139 - const struct man_meta *m;
145 + const struct man_meta *meta;
140 146 struct mtermp mt;
141 147
142 148 p = (struct termp *)arg;
143 149
144 150 if (0 == p->defindent)
145 151 p->defindent = 7;
146 152
147 153 p->overstep = 0;
148 154 p->maxrmargin = p->defrmargin;
149 155 p->tabwidth = term_len(p, 5);
150 156
151 157 if (NULL == p->symtab)
152 158 p->symtab = mchars_alloc();
153 159
154 160 n = man_node(man);
155 - m = man_meta(man);
161 + meta = man_meta(man);
156 162
157 - term_begin(p, print_man_head, print_man_foot, m);
163 + term_begin(p, print_man_head, print_man_foot, meta);
158 164 p->flags |= TERMP_NOSPACE;
159 165
160 166 memset(&mt, 0, sizeof(struct mtermp));
161 167
162 168 mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
163 169 mt.offset = term_len(p, p->defindent);
170 + mt.pardist = 1;
164 171
165 172 if (n->child)
166 - print_man_nodelist(p, &mt, n->child, m);
173 + print_man_nodelist(p, &mt, n->child, meta);
167 174
168 175 term_end(p);
169 176 }
170 177
171 178
172 179 static size_t
173 180 a2height(const struct termp *p, const char *cp)
174 181 {
175 182 struct roffsu su;
176 183
177 184 if ( ! a2roffsu(cp, &su, SCALE_VS))
178 185 SCALE_VS_INIT(&su, atoi(cp));
179 186
180 187 return(term_vspan(p, &su));
181 188 }
182 189
183 190
184 191 static int
185 192 a2width(const struct termp *p, const char *cp)
186 193 {
187 194 struct roffsu su;
188 195
189 196 if ( ! a2roffsu(cp, &su, SCALE_BU))
190 197 return(-1);
191 198
192 199 return((int)term_hspan(p, &su));
193 200 }
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
194 201
195 202 /*
196 203 * Printing leading vertical space before a block.
197 204 * This is used for the paragraph macros.
198 205 * The rules are pretty simple, since there's very little nesting going
199 206 * on here. Basically, if we're the first within another block (SS/SH),
200 207 * then don't emit vertical space. If we are (RS), then do. If not the
201 208 * first, print it.
202 209 */
203 210 static void
204 -print_bvspace(struct termp *p, const struct man_node *n)
211 +print_bvspace(struct termp *p, const struct man_node *n, int pardist)
205 212 {
213 + int i;
206 214
207 215 term_newln(p);
208 216
209 217 if (n->body && n->body->child)
210 218 if (MAN_TBL == n->body->child->type)
211 219 return;
212 220
213 221 if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
214 222 if (NULL == n->prev)
215 223 return;
216 224
217 - term_vspace(p);
225 + for (i = 0; i < pardist; i++)
226 + term_vspace(p);
218 227 }
219 228
220 229 /* ARGSUSED */
221 230 static int
222 231 pre_ign(DECL_ARGS)
223 232 {
224 233
225 234 return(0);
226 235 }
227 236
228 237
229 238 /* ARGSUSED */
230 239 static int
231 240 pre_I(DECL_ARGS)
232 241 {
233 242
234 243 term_fontrepl(p, TERMFONT_UNDER);
235 244 return(1);
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
236 245 }
237 246
238 247
239 248 /* ARGSUSED */
240 249 static int
241 250 pre_literal(DECL_ARGS)
242 251 {
243 252
244 253 term_newln(p);
245 254
246 - if (MAN_nf == n->tok)
255 + if (MAN_nf == n->tok || MAN_EX == n->tok)
247 256 mt->fl |= MANT_LITERAL;
248 257 else
249 258 mt->fl &= ~MANT_LITERAL;
250 259
251 260 /*
252 261 * Unlike .IP and .TP, .HP does not have a HEAD.
253 262 * So in case a second call to term_flushln() is needed,
254 263 * indentation has to be set up explicitly.
255 264 */
256 265 if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
257 266 p->offset = p->rmargin;
258 267 p->rmargin = p->maxrmargin;
259 - p->flags &= ~(TERMP_NOBREAK | TERMP_TWOSPACE);
268 + p->trailspace = 0;
269 + p->flags &= ~TERMP_NOBREAK;
260 270 p->flags |= TERMP_NOSPACE;
261 271 }
262 272
263 273 return(0);
264 274 }
265 275
266 276 /* ARGSUSED */
267 277 static int
278 +pre_PD(DECL_ARGS)
279 +{
280 +
281 + n = n->child;
282 + if (0 == n) {
283 + mt->pardist = 1;
284 + return(0);
285 + }
286 + assert(MAN_TEXT == n->type);
287 + mt->pardist = atoi(n->string);
288 + return(0);
289 +}
290 +
291 +/* ARGSUSED */
292 +static int
268 293 pre_alternate(DECL_ARGS)
269 294 {
270 295 enum termfont font[2];
271 296 const struct man_node *nn;
272 297 int savelit, i;
273 298
274 299 switch (n->tok) {
275 300 case (MAN_RB):
276 301 font[0] = TERMFONT_NONE;
277 302 font[1] = TERMFONT_BOLD;
278 303 break;
279 304 case (MAN_RI):
280 305 font[0] = TERMFONT_NONE;
281 306 font[1] = TERMFONT_UNDER;
282 307 break;
283 308 case (MAN_BR):
284 309 font[0] = TERMFONT_BOLD;
285 310 font[1] = TERMFONT_NONE;
286 311 break;
287 312 case (MAN_BI):
288 313 font[0] = TERMFONT_BOLD;
289 314 font[1] = TERMFONT_UNDER;
290 315 break;
291 316 case (MAN_IR):
292 317 font[0] = TERMFONT_UNDER;
293 318 font[1] = TERMFONT_NONE;
294 319 break;
295 320 case (MAN_IB):
296 321 font[0] = TERMFONT_UNDER;
297 322 font[1] = TERMFONT_BOLD;
298 323 break;
299 324 default:
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
300 325 abort();
301 326 }
302 327
303 328 savelit = MANT_LITERAL & mt->fl;
304 329 mt->fl &= ~MANT_LITERAL;
305 330
306 331 for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
307 332 term_fontrepl(p, font[i]);
308 333 if (savelit && NULL == nn->next)
309 334 mt->fl |= MANT_LITERAL;
310 - print_man_node(p, mt, nn, m);
335 + print_man_node(p, mt, nn, meta);
311 336 if (nn->next)
312 337 p->flags |= TERMP_NOSPACE;
313 338 }
314 339
315 340 return(0);
316 341 }
317 342
318 343 /* ARGSUSED */
319 344 static int
320 345 pre_B(DECL_ARGS)
321 346 {
322 347
323 348 term_fontrepl(p, TERMFONT_BOLD);
324 349 return(1);
325 350 }
326 351
327 352 /* ARGSUSED */
328 353 static int
329 354 pre_OP(DECL_ARGS)
330 355 {
331 356
332 357 term_word(p, "[");
333 358 p->flags |= TERMP_NOSPACE;
334 359
335 360 if (NULL != (n = n->child)) {
336 361 term_fontrepl(p, TERMFONT_BOLD);
337 362 term_word(p, n->string);
338 363 }
339 364 if (NULL != n && NULL != n->next) {
340 365 term_fontrepl(p, TERMFONT_UNDER);
341 366 term_word(p, n->next->string);
342 367 }
343 368
344 369 term_fontrepl(p, TERMFONT_NONE);
345 370 p->flags |= TERMP_NOSPACE;
346 371 term_word(p, "]");
347 372 return(0);
348 373 }
349 374
350 375 /* ARGSUSED */
351 376 static int
352 377 pre_ft(DECL_ARGS)
353 378 {
354 379 const char *cp;
355 380
356 381 if (NULL == n->child) {
357 382 term_fontlast(p);
358 383 return(0);
359 384 }
360 385
361 386 cp = n->child->string;
362 387 switch (*cp) {
363 388 case ('4'):
364 389 /* FALLTHROUGH */
365 390 case ('3'):
366 391 /* FALLTHROUGH */
367 392 case ('B'):
368 393 term_fontrepl(p, TERMFONT_BOLD);
369 394 break;
370 395 case ('2'):
371 396 /* FALLTHROUGH */
372 397 case ('I'):
373 398 term_fontrepl(p, TERMFONT_UNDER);
374 399 break;
375 400 case ('P'):
376 401 term_fontlast(p);
377 402 break;
378 403 case ('1'):
379 404 /* FALLTHROUGH */
380 405 case ('C'):
381 406 /* FALLTHROUGH */
382 407 case ('R'):
383 408 term_fontrepl(p, TERMFONT_NONE);
384 409 break;
385 410 default:
386 411 break;
387 412 }
388 413 return(0);
389 414 }
390 415
391 416 /* ARGSUSED */
392 417 static int
393 418 pre_in(DECL_ARGS)
394 419 {
395 420 int len, less;
396 421 size_t v;
397 422 const char *cp;
398 423
399 424 term_newln(p);
400 425
401 426 if (NULL == n->child) {
402 427 p->offset = mt->offset;
403 428 return(0);
404 429 }
405 430
406 431 cp = n->child->string;
407 432 less = 0;
408 433
409 434 if ('-' == *cp)
410 435 less = -1;
411 436 else if ('+' == *cp)
412 437 less = 1;
413 438 else
414 439 cp--;
415 440
416 441 if ((len = a2width(p, ++cp)) < 0)
417 442 return(0);
418 443
419 444 v = (size_t)len;
420 445
421 446 if (less < 0)
422 447 p->offset -= p->offset > v ? v : p->offset;
423 448 else if (less > 0)
424 449 p->offset += v;
425 450 else
426 451 p->offset = v;
427 452
428 453 /* Don't let this creep beyond the right margin. */
429 454
430 455 if (p->offset > p->rmargin)
↓ open down ↓ |
110 lines elided |
↑ open up ↑ |
431 456 p->offset = p->rmargin;
432 457
433 458 return(0);
434 459 }
435 460
436 461
437 462 /* ARGSUSED */
438 463 static int
439 464 pre_sp(DECL_ARGS)
440 465 {
466 + char *s;
441 467 size_t i, len;
468 + int neg;
442 469
443 470 if ((NULL == n->prev && n->parent)) {
444 - if (MAN_SS == n->parent->tok)
471 + switch (n->parent->tok) {
472 + case (MAN_SH):
473 + /* FALLTHROUGH */
474 + case (MAN_SS):
475 + /* FALLTHROUGH */
476 + case (MAN_PP):
477 + /* FALLTHROUGH */
478 + case (MAN_LP):
479 + /* FALLTHROUGH */
480 + case (MAN_P):
481 + /* FALLTHROUGH */
445 482 return(0);
446 - if (MAN_SH == n->parent->tok)
447 - return(0);
483 + default:
484 + break;
485 + }
448 486 }
449 487
488 + neg = 0;
450 489 switch (n->tok) {
451 490 case (MAN_br):
452 491 len = 0;
453 492 break;
454 493 default:
455 - len = n->child ? a2height(p, n->child->string) : 1;
494 + if (NULL == n->child) {
495 + len = 1;
496 + break;
497 + }
498 + s = n->child->string;
499 + if ('-' == *s) {
500 + neg = 1;
501 + s++;
502 + }
503 + len = a2height(p, s);
456 504 break;
457 505 }
458 506
459 507 if (0 == len)
460 508 term_newln(p);
461 - for (i = 0; i < len; i++)
462 - term_vspace(p);
509 + else if (neg)
510 + p->skipvsp += len;
511 + else
512 + for (i = 0; i < len; i++)
513 + term_vspace(p);
463 514
464 515 return(0);
465 516 }
466 517
467 518
468 519 /* ARGSUSED */
469 520 static int
470 521 pre_HP(DECL_ARGS)
471 522 {
472 523 size_t len, one;
473 524 int ival;
474 525 const struct man_node *nn;
475 526
476 527 switch (n->type) {
477 528 case (MAN_BLOCK):
478 - print_bvspace(p, n);
529 + print_bvspace(p, n, mt->pardist);
479 530 return(1);
480 531 case (MAN_BODY):
481 - p->flags |= TERMP_NOBREAK;
482 - p->flags |= TERMP_TWOSPACE;
483 532 break;
484 533 default:
485 534 return(0);
486 535 }
487 536
537 + if ( ! (MANT_LITERAL & mt->fl)) {
538 + p->flags |= TERMP_NOBREAK;
539 + p->trailspace = 2;
540 + }
541 +
488 542 len = mt->lmargin[mt->lmargincur];
489 543 ival = -1;
490 544
491 545 /* Calculate offset. */
492 546
493 547 if (NULL != (nn = n->parent->head->child))
494 548 if ((ival = a2width(p, nn->string)) >= 0)
495 549 len = (size_t)ival;
496 550
497 551 one = term_len(p, 1);
498 552 if (len < one)
499 553 len = one;
500 554
501 555 p->offset = mt->offset;
502 556 p->rmargin = mt->offset + len;
503 557
504 558 if (ival >= 0)
505 559 mt->lmargin[mt->lmargincur] = (size_t)ival;
506 560
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
507 561 return(1);
508 562 }
509 563
510 564
511 565 /* ARGSUSED */
512 566 static void
513 567 post_HP(DECL_ARGS)
514 568 {
515 569
516 570 switch (n->type) {
517 - case (MAN_BLOCK):
518 - term_flushln(p);
519 - break;
520 571 case (MAN_BODY):
521 - term_flushln(p);
572 + term_newln(p);
522 573 p->flags &= ~TERMP_NOBREAK;
523 - p->flags &= ~TERMP_TWOSPACE;
574 + p->trailspace = 0;
524 575 p->offset = mt->offset;
525 576 p->rmargin = p->maxrmargin;
526 577 break;
527 578 default:
528 579 break;
529 580 }
530 581 }
531 582
532 583
533 584 /* ARGSUSED */
534 585 static int
535 586 pre_PP(DECL_ARGS)
536 587 {
537 588
538 589 switch (n->type) {
539 590 case (MAN_BLOCK):
540 591 mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
541 - print_bvspace(p, n);
592 + print_bvspace(p, n, mt->pardist);
542 593 break;
543 594 default:
544 595 p->offset = mt->offset;
545 596 break;
546 597 }
547 598
548 599 return(MAN_HEAD != n->type);
549 600 }
550 601
551 602
552 603 /* ARGSUSED */
553 604 static int
554 605 pre_IP(DECL_ARGS)
555 606 {
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
556 607 const struct man_node *nn;
557 608 size_t len;
558 609 int savelit, ival;
559 610
560 611 switch (n->type) {
561 612 case (MAN_BODY):
562 613 p->flags |= TERMP_NOSPACE;
563 614 break;
564 615 case (MAN_HEAD):
565 616 p->flags |= TERMP_NOBREAK;
617 + p->trailspace = 1;
566 618 break;
567 619 case (MAN_BLOCK):
568 - print_bvspace(p, n);
620 + print_bvspace(p, n, mt->pardist);
569 621 /* FALLTHROUGH */
570 622 default:
571 623 return(1);
572 624 }
573 625
574 626 len = mt->lmargin[mt->lmargincur];
575 627 ival = -1;
576 628
577 629 /* Calculate the offset from the optional second argument. */
578 630 if (NULL != (nn = n->parent->head->child))
579 631 if (NULL != (nn = nn->next))
580 632 if ((ival = a2width(p, nn->string)) >= 0)
581 633 len = (size_t)ival;
582 634
583 635 switch (n->type) {
584 636 case (MAN_HEAD):
585 637 /* Handle zero-width lengths. */
586 638 if (0 == len)
587 639 len = term_len(p, 1);
588 640
589 641 p->offset = mt->offset;
590 642 p->rmargin = mt->offset + len;
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
591 643 if (ival < 0)
592 644 break;
593 645
594 646 /* Set the saved left-margin. */
595 647 mt->lmargin[mt->lmargincur] = (size_t)ival;
596 648
597 649 savelit = MANT_LITERAL & mt->fl;
598 650 mt->fl &= ~MANT_LITERAL;
599 651
600 652 if (n->child)
601 - print_man_node(p, mt, n->child, m);
653 + print_man_node(p, mt, n->child, meta);
602 654
603 655 if (savelit)
604 656 mt->fl |= MANT_LITERAL;
605 657
606 658 return(0);
607 659 case (MAN_BODY):
608 660 p->offset = mt->offset + len;
609 661 p->rmargin = p->maxrmargin;
610 662 break;
611 663 default:
612 664 break;
613 665 }
614 666
615 667 return(1);
616 668 }
617 669
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
618 670
619 671 /* ARGSUSED */
620 672 static void
621 673 post_IP(DECL_ARGS)
622 674 {
623 675
624 676 switch (n->type) {
625 677 case (MAN_HEAD):
626 678 term_flushln(p);
627 679 p->flags &= ~TERMP_NOBREAK;
680 + p->trailspace = 0;
628 681 p->rmargin = p->maxrmargin;
629 682 break;
630 683 case (MAN_BODY):
631 684 term_newln(p);
685 + p->offset = mt->offset;
632 686 break;
633 687 default:
634 688 break;
635 689 }
636 690 }
637 691
638 692
639 693 /* ARGSUSED */
640 694 static int
641 695 pre_TP(DECL_ARGS)
642 696 {
643 697 const struct man_node *nn;
644 698 size_t len;
645 699 int savelit, ival;
646 700
647 701 switch (n->type) {
648 702 case (MAN_HEAD):
649 703 p->flags |= TERMP_NOBREAK;
704 + p->trailspace = 1;
650 705 break;
651 706 case (MAN_BODY):
652 707 p->flags |= TERMP_NOSPACE;
653 708 break;
654 709 case (MAN_BLOCK):
655 - print_bvspace(p, n);
710 + print_bvspace(p, n, mt->pardist);
656 711 /* FALLTHROUGH */
657 712 default:
658 713 return(1);
659 714 }
660 715
661 716 len = (size_t)mt->lmargin[mt->lmargincur];
662 717 ival = -1;
663 718
664 719 /* Calculate offset. */
665 720
666 721 if (NULL != (nn = n->parent->head->child))
667 722 if (nn->string && nn->parent->line == nn->line)
668 723 if ((ival = a2width(p, nn->string)) >= 0)
669 724 len = (size_t)ival;
670 725
671 726 switch (n->type) {
672 727 case (MAN_HEAD):
673 728 /* Handle zero-length properly. */
674 729 if (0 == len)
675 730 len = term_len(p, 1);
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
676 731
677 732 p->offset = mt->offset;
678 733 p->rmargin = mt->offset + len;
679 734
680 735 savelit = MANT_LITERAL & mt->fl;
681 736 mt->fl &= ~MANT_LITERAL;
682 737
683 738 /* Don't print same-line elements. */
684 739 for (nn = n->child; nn; nn = nn->next)
685 740 if (nn->line > n->line)
686 - print_man_node(p, mt, nn, m);
741 + print_man_node(p, mt, nn, meta);
687 742
688 743 if (savelit)
689 744 mt->fl |= MANT_LITERAL;
690 745 if (ival >= 0)
691 746 mt->lmargin[mt->lmargincur] = (size_t)ival;
692 747
693 748 return(0);
694 749 case (MAN_BODY):
695 750 p->offset = mt->offset + len;
696 751 p->rmargin = p->maxrmargin;
752 + p->trailspace = 0;
753 + p->flags &= ~TERMP_NOBREAK;
697 754 break;
698 755 default:
699 756 break;
700 757 }
701 758
702 759 return(1);
703 760 }
704 761
705 762
706 763 /* ARGSUSED */
707 764 static void
708 765 post_TP(DECL_ARGS)
709 766 {
710 767
711 768 switch (n->type) {
712 769 case (MAN_HEAD):
713 770 term_flushln(p);
714 - p->flags &= ~TERMP_NOBREAK;
715 - p->flags &= ~TERMP_TWOSPACE;
716 - p->rmargin = p->maxrmargin;
717 771 break;
718 772 case (MAN_BODY):
719 773 term_newln(p);
774 + p->offset = mt->offset;
720 775 break;
721 776 default:
722 777 break;
723 778 }
724 779 }
725 780
726 781
727 782 /* ARGSUSED */
728 783 static int
729 784 pre_SS(DECL_ARGS)
730 785 {
786 + int i;
731 787
732 788 switch (n->type) {
733 789 case (MAN_BLOCK):
734 790 mt->fl &= ~MANT_LITERAL;
735 791 mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
736 792 mt->offset = term_len(p, p->defindent);
737 793 /* If following a prior empty `SS', no vspace. */
738 794 if (n->prev && MAN_SS == n->prev->tok)
739 795 if (NULL == n->prev->body->child)
740 796 break;
741 797 if (NULL == n->prev)
742 798 break;
743 - term_vspace(p);
799 + for (i = 0; i < mt->pardist; i++)
800 + term_vspace(p);
744 801 break;
745 802 case (MAN_HEAD):
746 803 term_fontrepl(p, TERMFONT_BOLD);
747 - p->offset = term_len(p, p->defindent/2);
804 + p->offset = term_len(p, 3);
748 805 break;
749 806 case (MAN_BODY):
750 807 p->offset = mt->offset;
751 808 break;
752 809 default:
753 810 break;
754 811 }
755 812
756 813 return(1);
757 814 }
758 815
759 816
760 817 /* ARGSUSED */
761 818 static void
762 819 post_SS(DECL_ARGS)
763 820 {
764 821
765 822 switch (n->type) {
766 823 case (MAN_HEAD):
767 824 term_newln(p);
768 825 break;
769 826 case (MAN_BODY):
770 827 term_newln(p);
771 828 break;
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
772 829 default:
773 830 break;
774 831 }
775 832 }
776 833
777 834
778 835 /* ARGSUSED */
779 836 static int
780 837 pre_SH(DECL_ARGS)
781 838 {
839 + int i;
782 840
783 841 switch (n->type) {
784 842 case (MAN_BLOCK):
785 843 mt->fl &= ~MANT_LITERAL;
786 844 mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
787 845 mt->offset = term_len(p, p->defindent);
788 846 /* If following a prior empty `SH', no vspace. */
789 847 if (n->prev && MAN_SH == n->prev->tok)
790 848 if (NULL == n->prev->body->child)
791 849 break;
792 850 /* If the first macro, no vspae. */
793 851 if (NULL == n->prev)
794 852 break;
795 - term_vspace(p);
853 + for (i = 0; i < mt->pardist; i++)
854 + term_vspace(p);
796 855 break;
797 856 case (MAN_HEAD):
798 857 term_fontrepl(p, TERMFONT_BOLD);
799 858 p->offset = 0;
800 859 break;
801 860 case (MAN_BODY):
802 861 p->offset = mt->offset;
803 862 break;
804 863 default:
805 864 break;
806 865 }
807 866
808 867 return(1);
809 868 }
810 869
811 870
812 871 /* ARGSUSED */
813 872 static void
814 873 post_SH(DECL_ARGS)
815 874 {
816 875
817 876 switch (n->type) {
818 877 case (MAN_HEAD):
819 878 term_newln(p);
820 879 break;
821 880 case (MAN_BODY):
822 881 term_newln(p);
823 882 break;
824 883 default:
825 884 break;
826 885 }
827 886 }
828 887
829 888 /* ARGSUSED */
830 889 static int
831 890 pre_RS(DECL_ARGS)
832 891 {
833 892 int ival;
834 893 size_t sz;
835 894
836 895 switch (n->type) {
837 896 case (MAN_BLOCK):
838 897 term_newln(p);
839 898 return(1);
840 899 case (MAN_HEAD):
841 900 return(0);
842 901 default:
843 902 break;
844 903 }
845 904
846 905 sz = term_len(p, p->defindent);
847 906
848 907 if (NULL != (n = n->parent->head->child))
849 908 if ((ival = a2width(p, n->string)) >= 0)
850 909 sz = (size_t)ival;
851 910
852 911 mt->offset += sz;
853 912 p->rmargin = p->maxrmargin;
854 913 p->offset = mt->offset < p->rmargin ? mt->offset : p->rmargin;
855 914
856 915 if (++mt->lmarginsz < MAXMARGINS)
857 916 mt->lmargincur = mt->lmarginsz;
858 917
859 918 mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1];
860 919 return(1);
861 920 }
862 921
863 922 /* ARGSUSED */
864 923 static void
865 924 post_RS(DECL_ARGS)
866 925 {
867 926 int ival;
868 927 size_t sz;
869 928
870 929 switch (n->type) {
871 930 case (MAN_BLOCK):
872 931 return;
873 932 case (MAN_HEAD):
874 933 return;
875 934 default:
876 935 term_newln(p);
877 936 break;
878 937 }
879 938
880 939 sz = term_len(p, p->defindent);
881 940
882 941 if (NULL != (n = n->parent->head->child))
↓ open down ↓ |
77 lines elided |
↑ open up ↑ |
883 942 if ((ival = a2width(p, n->string)) >= 0)
884 943 sz = (size_t)ival;
885 944
886 945 mt->offset = mt->offset < sz ? 0 : mt->offset - sz;
887 946 p->offset = mt->offset;
888 947
889 948 if (--mt->lmarginsz < MAXMARGINS)
890 949 mt->lmargincur = mt->lmarginsz;
891 950 }
892 951
952 +/* ARGSUSED */
953 +static int
954 +pre_UR(DECL_ARGS)
955 +{
956 +
957 + return (MAN_HEAD != n->type);
958 +}
959 +
960 +/* ARGSUSED */
893 961 static void
962 +post_UR(DECL_ARGS)
963 +{
964 +
965 + if (MAN_BLOCK != n->type)
966 + return;
967 +
968 + term_word(p, "<");
969 + p->flags |= TERMP_NOSPACE;
970 +
971 + if (NULL != n->child->child)
972 + print_man_node(p, mt, n->child->child, meta);
973 +
974 + p->flags |= TERMP_NOSPACE;
975 + term_word(p, ">");
976 +}
977 +
978 +static void
894 979 print_man_node(DECL_ARGS)
895 980 {
896 981 size_t rm, rmax;
897 982 int c;
898 983
899 984 switch (n->type) {
900 985 case(MAN_TEXT):
901 986 /*
902 987 * If we have a blank line, output a vertical space.
903 988 * If we have a space as the first character, break
904 989 * before printing the line's data.
905 990 */
906 991 if ('\0' == *n->string) {
907 992 term_vspace(p);
908 993 return;
909 994 } else if (' ' == *n->string && MAN_LINE & n->flags)
910 995 term_newln(p);
911 996
912 997 term_word(p, n->string);
998 + goto out;
913 999
914 - /*
915 - * If we're in a literal context, make sure that words
916 - * togehter on the same line stay together. This is a
917 - * POST-printing call, so we check the NEXT word. Since
918 - * -man doesn't have nested macros, we don't need to be
919 - * more specific than this.
920 - */
921 - if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
922 - (NULL == n->next ||
923 - n->next->line > n->line)) {
924 - rm = p->rmargin;
925 - rmax = p->maxrmargin;
926 - p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
927 - p->flags |= TERMP_NOSPACE;
928 - term_flushln(p);
929 - p->rmargin = rm;
930 - p->maxrmargin = rmax;
931 - }
932 -
933 - if (MAN_EOS & n->flags)
934 - p->flags |= TERMP_SENTENCE;
935 - return;
936 1000 case (MAN_EQN):
937 1001 term_eqn(p, n->eqn);
938 1002 return;
939 1003 case (MAN_TBL):
940 1004 /*
941 1005 * Tables are preceded by a newline. Then process a
942 1006 * table line, which will cause line termination,
943 1007 */
944 1008 if (TBL_SPAN_FIRST & n->span->flags)
945 1009 term_newln(p);
946 1010 term_tbl(p, n->span);
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
947 1011 return;
948 1012 default:
949 1013 break;
950 1014 }
951 1015
952 1016 if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
953 1017 term_fontrepl(p, TERMFONT_NONE);
954 1018
955 1019 c = 1;
956 1020 if (termacts[n->tok].pre)
957 - c = (*termacts[n->tok].pre)(p, mt, n, m);
1021 + c = (*termacts[n->tok].pre)(p, mt, n, meta);
958 1022
959 1023 if (c && n->child)
960 - print_man_nodelist(p, mt, n->child, m);
1024 + print_man_nodelist(p, mt, n->child, meta);
961 1025
962 1026 if (termacts[n->tok].post)
963 - (*termacts[n->tok].post)(p, mt, n, m);
1027 + (*termacts[n->tok].post)(p, mt, n, meta);
964 1028 if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
965 1029 term_fontrepl(p, TERMFONT_NONE);
966 1030
1031 +out:
1032 + /*
1033 + * If we're in a literal context, make sure that words
1034 + * together on the same line stay together. This is a
1035 + * POST-printing call, so we check the NEXT word. Since
1036 + * -man doesn't have nested macros, we don't need to be
1037 + * more specific than this.
1038 + */
1039 + if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
1040 + (NULL == n->next || n->next->line > n->line)) {
1041 + rm = p->rmargin;
1042 + rmax = p->maxrmargin;
1043 + p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1044 + p->flags |= TERMP_NOSPACE;
1045 + if (NULL != n->string && '\0' != *n->string)
1046 + term_flushln(p);
1047 + else
1048 + term_newln(p);
1049 + if (rm < rmax && n->parent->tok == MAN_HP) {
1050 + p->offset = rm;
1051 + p->rmargin = rmax;
1052 + } else
1053 + p->rmargin = rm;
1054 + p->maxrmargin = rmax;
1055 + }
967 1056 if (MAN_EOS & n->flags)
968 1057 p->flags |= TERMP_SENTENCE;
969 1058 }
970 1059
971 1060
972 1061 static void
973 1062 print_man_nodelist(DECL_ARGS)
974 1063 {
975 1064
976 - print_man_node(p, mt, n, m);
1065 + print_man_node(p, mt, n, meta);
977 1066 if ( ! n->next)
978 1067 return;
979 - print_man_nodelist(p, mt, n->next, m);
1068 + print_man_nodelist(p, mt, n->next, meta);
980 1069 }
981 1070
982 1071
983 1072 static void
984 1073 print_man_foot(struct termp *p, const void *arg)
985 1074 {
986 1075 char title[BUFSIZ];
987 1076 size_t datelen;
988 1077 const struct man_meta *meta;
989 1078
990 1079 meta = (const struct man_meta *)arg;
991 1080 assert(meta->title);
992 1081 assert(meta->msec);
993 1082 assert(meta->date);
994 1083
995 1084 term_fontrepl(p, TERMFONT_NONE);
996 1085
997 1086 term_vspace(p);
998 1087
999 1088 /*
1000 1089 * Temporary, undocumented option to imitate mdoc(7) output.
1001 1090 * In the bottom right corner, use the source instead of
1002 1091 * the title.
1003 1092 */
1004 1093
1005 1094 if ( ! p->mdocstyle) {
1006 1095 term_vspace(p);
1007 1096 term_vspace(p);
1008 1097 snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
1009 1098 } else if (meta->source) {
1010 1099 strlcpy(title, meta->source, BUFSIZ);
1011 1100 } else {
1012 1101 title[0] = '\0';
1013 1102 }
1014 1103 datelen = term_strlen(p, meta->date);
1015 1104
1016 1105 /* Bottom left corner: manual source. */
1017 1106
1018 1107 p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1108 + p->trailspace = 1;
1019 1109 p->offset = 0;
1020 1110 p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
1021 1111
1022 1112 if (meta->source)
1023 1113 term_word(p, meta->source);
1024 1114 term_flushln(p);
1025 1115
1026 1116 /* At the bottom in the middle: manual date. */
1027 1117
1028 1118 p->flags |= TERMP_NOSPACE;
1029 1119 p->offset = p->rmargin;
1030 1120 p->rmargin = p->maxrmargin - term_strlen(p, title);
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
1031 1121 if (p->offset + datelen >= p->rmargin)
1032 1122 p->rmargin = p->offset + datelen;
1033 1123
1034 1124 term_word(p, meta->date);
1035 1125 term_flushln(p);
1036 1126
1037 1127 /* Bottom right corner: manual title and section. */
1038 1128
1039 1129 p->flags &= ~TERMP_NOBREAK;
1040 1130 p->flags |= TERMP_NOSPACE;
1131 + p->trailspace = 0;
1041 1132 p->offset = p->rmargin;
1042 1133 p->rmargin = p->maxrmargin;
1043 1134
1044 1135 term_word(p, title);
1045 1136 term_flushln(p);
1046 1137 }
1047 1138
1048 1139
1049 1140 static void
1050 1141 print_man_head(struct termp *p, const void *arg)
1051 1142 {
1052 1143 char buf[BUFSIZ], title[BUFSIZ];
1053 1144 size_t buflen, titlen;
1054 - const struct man_meta *m;
1145 + const struct man_meta *meta;
1055 1146
1056 - m = (const struct man_meta *)arg;
1057 - assert(m->title);
1058 - assert(m->msec);
1147 + meta = (const struct man_meta *)arg;
1148 + assert(meta->title);
1149 + assert(meta->msec);
1059 1150
1060 - if (m->vol)
1061 - strlcpy(buf, m->vol, BUFSIZ);
1151 + if (meta->vol)
1152 + strlcpy(buf, meta->vol, BUFSIZ);
1062 1153 else
1063 1154 buf[0] = '\0';
1064 1155 buflen = term_strlen(p, buf);
1065 1156
1066 1157 /* Top left corner: manual title and section. */
1067 1158
1068 - snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1159 + snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
1069 1160 titlen = term_strlen(p, title);
1070 1161
1071 1162 p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1163 + p->trailspace = 1;
1072 1164 p->offset = 0;
1073 1165 p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1074 1166 (p->maxrmargin -
1075 1167 term_strlen(p, buf) + term_len(p, 1)) / 2 :
1076 1168 p->maxrmargin - buflen;
1077 1169
1078 1170 term_word(p, title);
1079 1171 term_flushln(p);
1080 1172
1081 1173 /* At the top in the middle: manual volume. */
1082 1174
1083 1175 p->flags |= TERMP_NOSPACE;
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
1084 1176 p->offset = p->rmargin;
1085 1177 p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
1086 1178 p->maxrmargin - titlen : p->maxrmargin;
1087 1179
1088 1180 term_word(p, buf);
1089 1181 term_flushln(p);
1090 1182
1091 1183 /* Top right corner: title and section, again. */
1092 1184
1093 1185 p->flags &= ~TERMP_NOBREAK;
1186 + p->trailspace = 0;
1094 1187 if (p->rmargin + titlen <= p->maxrmargin) {
1095 1188 p->flags |= TERMP_NOSPACE;
1096 1189 p->offset = p->rmargin;
1097 1190 p->rmargin = p->maxrmargin;
1098 1191 term_word(p, title);
1099 1192 term_flushln(p);
1100 1193 }
1101 1194
1102 1195 p->flags &= ~TERMP_NOSPACE;
1103 1196 p->offset = 0;
1104 1197 p->rmargin = p->maxrmargin;
1105 1198
1106 1199 /*
1107 1200 * Groff prints three blank lines before the content.
1108 1201 * Do the same, except in the temporary, undocumented
1109 1202 * mode imitating mdoc(7) output.
1110 1203 */
1111 1204
1112 1205 term_vspace(p);
1113 1206 if ( ! p->mdocstyle) {
1114 1207 term_vspace(p);
1115 1208 term_vspace(p);
1116 1209 }
1117 1210 }
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX