Annotation of src/usr.bin/mandoc/man_term.c, Revision 1.26
1.26 ! schwarze 1: /* $Id: man_term.c,v 1.25 2010/03/02 01:24:04 schwarze Exp $ */
1.1 kristaps 2: /*
1.2 schwarze 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.2 schwarze 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.2 schwarze 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
1.13 schwarze 17: #include <sys/types.h>
18:
1.1 kristaps 19: #include <assert.h>
1.11 schwarze 20: #include <ctype.h>
1.1 kristaps 21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <string.h>
24:
1.18 schwarze 25: #include "out.h"
26: #include "man.h"
1.1 kristaps 27: #include "term.h"
1.18 schwarze 28: #include "chars.h"
29: #include "main.h"
1.10 schwarze 30:
31: #define INDENT 7
32: #define HALFINDENT 3
1.1 kristaps 33:
1.19 schwarze 34: /* FIXME: have PD set the default vspace width. */
35:
1.11 schwarze 36: struct mtermp {
37: int fl;
38: #define MANT_LITERAL (1 << 0)
1.13 schwarze 39: /*
40: * Default amount to indent the left margin after leading text
41: * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
42: * indent). This needs to be saved because `HP' and so on, if
43: * not having a specified value, must default.
44: *
45: * Note that this is the indentation AFTER the left offset, so
46: * the total offset is usually offset + lmargin.
47: */
48: size_t lmargin;
49: /*
50: * The default offset, i.e., the amount between any text and the
51: * page boundary.
52: */
53: size_t offset;
1.11 schwarze 54: };
55:
1.1 kristaps 56: #define DECL_ARGS struct termp *p, \
1.11 schwarze 57: struct mtermp *mt, \
1.1 kristaps 58: const struct man_node *n, \
59: const struct man_meta *m
60:
61: struct termact {
62: int (*pre)(DECL_ARGS);
63: void (*post)(DECL_ARGS);
1.26 ! schwarze 64: int flags;
! 65: #define MAN_NOTEXT (1 << 0) /* Never has text children. */
1.1 kristaps 66: };
67:
1.19 schwarze 68: static int a2width(const struct man_node *);
69: static int a2height(const struct man_node *);
1.18 schwarze 70:
1.19 schwarze 71: static void print_man_head(struct termp *,
1.18 schwarze 72: const struct man_meta *);
1.21 schwarze 73: static void print_man_nodelist(DECL_ARGS);
1.19 schwarze 74: static void print_man_node(DECL_ARGS);
75: static void print_man_foot(struct termp *,
1.18 schwarze 76: const struct man_meta *);
77: static void print_bvspace(struct termp *,
78: const struct man_node *);
79:
1.1 kristaps 80: static int pre_B(DECL_ARGS);
81: static int pre_BI(DECL_ARGS);
1.11 schwarze 82: static int pre_HP(DECL_ARGS);
1.1 kristaps 83: static int pre_I(DECL_ARGS);
84: static int pre_IP(DECL_ARGS);
85: static int pre_PP(DECL_ARGS);
86: static int pre_RB(DECL_ARGS);
87: static int pre_RI(DECL_ARGS);
1.13 schwarze 88: static int pre_RS(DECL_ARGS);
1.1 kristaps 89: static int pre_SH(DECL_ARGS);
90: static int pre_SS(DECL_ARGS);
91: static int pre_TP(DECL_ARGS);
1.11 schwarze 92: static int pre_br(DECL_ARGS);
93: static int pre_fi(DECL_ARGS);
1.14 schwarze 94: static int pre_ign(DECL_ARGS);
1.11 schwarze 95: static int pre_nf(DECL_ARGS);
96: static int pre_sp(DECL_ARGS);
1.1 kristaps 97:
1.11 schwarze 98: static void post_IP(DECL_ARGS);
99: static void post_HP(DECL_ARGS);
1.13 schwarze 100: static void post_RS(DECL_ARGS);
1.1 kristaps 101: static void post_SH(DECL_ARGS);
102: static void post_SS(DECL_ARGS);
1.11 schwarze 103: static void post_TP(DECL_ARGS);
1.1 kristaps 104:
1.17 schwarze 105: static const struct termact termacts[MAN_MAX] = {
1.26 ! schwarze 106: { pre_br, NULL, MAN_NOTEXT }, /* br */
! 107: { NULL, NULL, 0 }, /* TH */
! 108: { pre_SH, post_SH, 0 }, /* SH */
! 109: { pre_SS, post_SS, 0 }, /* SS */
! 110: { pre_TP, post_TP, 0 }, /* TP */
! 111: { pre_PP, NULL, 0 }, /* LP */
! 112: { pre_PP, NULL, 0 }, /* PP */
! 113: { pre_PP, NULL, 0 }, /* P */
! 114: { pre_IP, post_IP, 0 }, /* IP */
! 115: { pre_HP, post_HP, 0 }, /* HP */
! 116: { NULL, NULL, 0 }, /* SM */
! 117: { pre_B, NULL, 0 }, /* SB */
! 118: { pre_BI, NULL, 0 }, /* BI */
! 119: { pre_BI, NULL, 0 }, /* IB */
! 120: { pre_RB, NULL, 0 }, /* BR */
! 121: { pre_RB, NULL, 0 }, /* RB */
! 122: { NULL, NULL, 0 }, /* R */
! 123: { pre_B, NULL, 0 }, /* B */
! 124: { pre_I, NULL, 0 }, /* I */
! 125: { pre_RI, NULL, 0 }, /* IR */
! 126: { pre_RI, NULL, 0 }, /* RI */
! 127: { NULL, NULL, MAN_NOTEXT }, /* na */
! 128: { pre_I, NULL, 0 }, /* i */
! 129: { pre_sp, NULL, MAN_NOTEXT }, /* sp */
! 130: { pre_nf, NULL, 0 }, /* nf */
! 131: { pre_fi, NULL, 0 }, /* fi */
! 132: { NULL, NULL, 0 }, /* r */
! 133: { NULL, NULL, 0 }, /* RE */
! 134: { pre_RS, post_RS, 0 }, /* RS */
! 135: { pre_ign, NULL, 0 }, /* DT */
! 136: { pre_ign, NULL, 0 }, /* UC */
! 137: { pre_ign, NULL, 0 }, /* PD */
! 138: { pre_sp, NULL, MAN_NOTEXT }, /* Sp */
! 139: { pre_nf, NULL, 0 }, /* Vb */
! 140: { pre_fi, NULL, 0 }, /* Ve */
1.1 kristaps 141: };
1.11 schwarze 142:
1.1 kristaps 143:
144:
1.16 schwarze 145: void
1.18 schwarze 146: terminal_man(void *arg, const struct man *man)
1.1 kristaps 147: {
1.18 schwarze 148: struct termp *p;
149: const struct man_node *n;
150: const struct man_meta *m;
151: struct mtermp mt;
152:
153: p = (struct termp *)arg;
154:
155: if (NULL == p->symtab)
156: switch (p->enc) {
157: case (TERMENC_ASCII):
1.24 schwarze 158: p->maxrmargin = 65;
1.18 schwarze 159: p->symtab = chars_init(CHARS_ASCII);
160: break;
161: default:
162: abort();
163: /* NOTREACHED */
164: }
165:
166: n = man_node(man);
167: m = man_meta(man);
1.1 kristaps 168:
1.19 schwarze 169: print_man_head(p, m);
1.1 kristaps 170: p->flags |= TERMP_NOSPACE;
1.11 schwarze 171:
172: mt.fl = 0;
173: mt.lmargin = INDENT;
1.13 schwarze 174: mt.offset = INDENT;
1.11 schwarze 175:
1.18 schwarze 176: if (n->child)
1.21 schwarze 177: print_man_nodelist(p, &mt, n->child, m);
1.19 schwarze 178: print_man_foot(p, m);
1.1 kristaps 179: }
180:
181:
1.18 schwarze 182: static int
1.19 schwarze 183: a2height(const struct man_node *n)
1.11 schwarze 184: {
1.18 schwarze 185: struct roffsu su;
1.11 schwarze 186:
1.18 schwarze 187: assert(MAN_TEXT == n->type);
188: assert(n->string);
189: if ( ! a2roffsu(n->string, &su, SCALE_VS))
190: SCALE_VS_INIT(&su, strlen(n->string));
1.11 schwarze 191:
1.18 schwarze 192: return((int)term_vspan(&su));
1.11 schwarze 193: }
194:
195:
196: static int
1.19 schwarze 197: a2width(const struct man_node *n)
1.11 schwarze 198: {
1.18 schwarze 199: struct roffsu su;
1.11 schwarze 200:
201: assert(MAN_TEXT == n->type);
202: assert(n->string);
1.18 schwarze 203: if ( ! a2roffsu(n->string, &su, SCALE_BU))
204: return(-1);
205:
206: return((int)term_hspan(&su));
207: }
1.11 schwarze 208:
209:
1.18 schwarze 210: static void
211: print_bvspace(struct termp *p, const struct man_node *n)
212: {
213: term_newln(p);
1.11 schwarze 214:
1.18 schwarze 215: if (NULL == n->prev)
216: return;
1.11 schwarze 217:
1.18 schwarze 218: if (MAN_SS == n->prev->tok)
219: return;
220: if (MAN_SH == n->prev->tok)
221: return;
1.11 schwarze 222:
1.18 schwarze 223: term_vspace(p);
1.14 schwarze 224: }
225:
226:
227: /* ARGSUSED */
228: static int
229: pre_ign(DECL_ARGS)
230: {
231:
232: return(0);
1.11 schwarze 233: }
234:
235:
1.1 kristaps 236: /* ARGSUSED */
237: static int
238: pre_I(DECL_ARGS)
239: {
240:
1.21 schwarze 241: term_fontrepl(p, TERMFONT_UNDER);
1.1 kristaps 242: return(1);
243: }
244:
245:
246: /* ARGSUSED */
1.11 schwarze 247: static int
248: pre_fi(DECL_ARGS)
249: {
250:
1.24 schwarze 251: p->rmargin = p->maxrmargin = 65;
1.11 schwarze 252: mt->fl &= ~MANT_LITERAL;
253: return(1);
254: }
255:
256:
257: /* ARGSUSED */
258: static int
259: pre_nf(DECL_ARGS)
260: {
261:
1.24 schwarze 262: p->rmargin = p->maxrmargin = 160;
1.11 schwarze 263: term_newln(p);
264: mt->fl |= MANT_LITERAL;
265: return(1);
266: }
267:
268:
269: /* ARGSUSED */
270: static int
1.17 schwarze 271: pre_RB(DECL_ARGS)
1.1 kristaps 272: {
273: const struct man_node *nn;
274: int i;
275:
276: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17 schwarze 277: if (i % 2 && MAN_RB == n->tok)
1.21 schwarze 278: term_fontrepl(p, TERMFONT_BOLD);
1.17 schwarze 279: else if ( ! (i % 2) && MAN_RB != n->tok)
1.21 schwarze 280: term_fontrepl(p, TERMFONT_BOLD);
281: else
282: term_fontrepl(p, TERMFONT_NONE);
1.17 schwarze 283:
1.1 kristaps 284: if (i > 0)
285: p->flags |= TERMP_NOSPACE;
1.17 schwarze 286:
1.19 schwarze 287: print_man_node(p, mt, nn, m);
1.1 kristaps 288: }
289: return(0);
290: }
291:
292:
293: /* ARGSUSED */
294: static int
295: pre_RI(DECL_ARGS)
296: {
297: const struct man_node *nn;
298: int i;
299:
300: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.21 schwarze 301: if (i % 2 && MAN_RI == n->tok)
302: term_fontrepl(p, TERMFONT_UNDER);
303: else if ( ! (i % 2) && MAN_RI != n->tok)
304: term_fontrepl(p, TERMFONT_UNDER);
305: else
306: term_fontrepl(p, TERMFONT_NONE);
307:
1.1 kristaps 308: if (i > 0)
309: p->flags |= TERMP_NOSPACE;
1.21 schwarze 310:
1.19 schwarze 311: print_man_node(p, mt, nn, m);
1.1 kristaps 312: }
313: return(0);
314: }
315:
316:
317: /* ARGSUSED */
318: static int
319: pre_BI(DECL_ARGS)
320: {
1.17 schwarze 321: const struct man_node *nn;
322: int i;
1.1 kristaps 323:
324: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17 schwarze 325: if (i % 2 && MAN_BI == n->tok)
1.21 schwarze 326: term_fontrepl(p, TERMFONT_UNDER);
1.17 schwarze 327: else if (i % 2)
1.21 schwarze 328: term_fontrepl(p, TERMFONT_BOLD);
1.17 schwarze 329: else if (MAN_BI == n->tok)
1.21 schwarze 330: term_fontrepl(p, TERMFONT_BOLD);
1.15 schwarze 331: else
1.21 schwarze 332: term_fontrepl(p, TERMFONT_UNDER);
1.17 schwarze 333:
334: if (i)
1.1 kristaps 335: p->flags |= TERMP_NOSPACE;
1.21 schwarze 336:
1.19 schwarze 337: print_man_node(p, mt, nn, m);
1.1 kristaps 338: }
339: return(0);
340: }
341:
342:
343: /* ARGSUSED */
344: static int
345: pre_B(DECL_ARGS)
346: {
347:
1.21 schwarze 348: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 349: return(1);
350: }
351:
352:
353: /* ARGSUSED */
354: static int
1.11 schwarze 355: pre_sp(DECL_ARGS)
356: {
357: int i, len;
358:
1.19 schwarze 359: len = n->child ? a2height(n->child) : 1;
1.11 schwarze 360:
361: if (0 == len)
362: term_newln(p);
363: for (i = 0; i < len; i++)
364: term_vspace(p);
365:
366: return(0);
367: }
368:
369:
370: /* ARGSUSED */
371: static int
1.8 schwarze 372: pre_br(DECL_ARGS)
373: {
374:
375: term_newln(p);
376: return(0);
377: }
378:
379:
380: /* ARGSUSED */
381: static int
1.11 schwarze 382: pre_HP(DECL_ARGS)
383: {
384: size_t len;
385: int ival;
386: const struct man_node *nn;
387:
388: switch (n->type) {
389: case (MAN_BLOCK):
1.18 schwarze 390: print_bvspace(p, n);
1.11 schwarze 391: return(1);
392: case (MAN_BODY):
393: p->flags |= TERMP_NOBREAK;
394: p->flags |= TERMP_TWOSPACE;
395: break;
396: default:
397: return(0);
398: }
399:
1.13 schwarze 400: len = mt->lmargin;
1.11 schwarze 401: ival = -1;
402:
403: /* Calculate offset. */
404:
405: if (NULL != (nn = n->parent->head->child))
1.19 schwarze 406: if ((ival = a2width(nn)) >= 0)
1.11 schwarze 407: len = (size_t)ival;
408:
409: if (0 == len)
410: len = 1;
411:
1.13 schwarze 412: p->offset = mt->offset;
413: p->rmargin = mt->offset + len;
1.11 schwarze 414:
415: if (ival >= 0)
1.13 schwarze 416: mt->lmargin = (size_t)ival;
1.11 schwarze 417:
418: return(1);
419: }
420:
421:
422: /* ARGSUSED */
423: static void
424: post_HP(DECL_ARGS)
425: {
426:
427: switch (n->type) {
428: case (MAN_BLOCK):
429: term_flushln(p);
430: break;
431: case (MAN_BODY):
432: term_flushln(p);
433: p->flags &= ~TERMP_NOBREAK;
434: p->flags &= ~TERMP_TWOSPACE;
1.13 schwarze 435: p->offset = mt->offset;
1.11 schwarze 436: p->rmargin = p->maxrmargin;
437: break;
438: default:
439: break;
440: }
441: }
442:
443:
444: /* ARGSUSED */
445: static int
1.1 kristaps 446: pre_PP(DECL_ARGS)
447: {
448:
1.11 schwarze 449: switch (n->type) {
450: case (MAN_BLOCK):
451: mt->lmargin = INDENT;
1.18 schwarze 452: print_bvspace(p, n);
1.11 schwarze 453: break;
454: default:
1.13 schwarze 455: p->offset = mt->offset;
1.11 schwarze 456: break;
457: }
458:
459: return(1);
1.1 kristaps 460: }
461:
462:
463: /* ARGSUSED */
464: static int
465: pre_IP(DECL_ARGS)
466: {
1.11 schwarze 467: const struct man_node *nn;
468: size_t len;
469: int ival;
470:
471: switch (n->type) {
472: case (MAN_BODY):
473: p->flags |= TERMP_NOLPAD;
474: p->flags |= TERMP_NOSPACE;
475: break;
476: case (MAN_HEAD):
477: p->flags |= TERMP_NOBREAK;
478: p->flags |= TERMP_TWOSPACE;
479: break;
480: case (MAN_BLOCK):
1.18 schwarze 481: print_bvspace(p, n);
1.11 schwarze 482: /* FALLTHROUGH */
483: default:
484: return(1);
485: }
486:
1.13 schwarze 487: len = mt->lmargin;
1.11 schwarze 488: ival = -1;
489:
490: /* Calculate offset. */
491:
492: if (NULL != (nn = n->parent->head->child))
493: if (NULL != (nn = nn->next)) {
494: for ( ; nn->next; nn = nn->next)
495: /* Do nothing. */ ;
1.19 schwarze 496: if ((ival = a2width(nn)) >= 0)
1.11 schwarze 497: len = (size_t)ival;
498: }
499:
500: switch (n->type) {
501: case (MAN_HEAD):
502: /* Handle zero-width lengths. */
503: if (0 == len)
504: len = 1;
505:
1.13 schwarze 506: p->offset = mt->offset;
507: p->rmargin = mt->offset + len;
1.11 schwarze 508: if (ival < 0)
509: break;
510:
511: /* Set the saved left-margin. */
1.13 schwarze 512: mt->lmargin = (size_t)ival;
1.1 kristaps 513:
1.11 schwarze 514: /* Don't print the length value. */
515: for (nn = n->child; nn->next; nn = nn->next)
1.19 schwarze 516: print_man_node(p, mt, nn, m);
1.11 schwarze 517: return(0);
518: case (MAN_BODY):
1.13 schwarze 519: p->offset = mt->offset + len;
1.11 schwarze 520: p->rmargin = p->maxrmargin;
521: break;
522: default:
523: break;
524: }
1.1 kristaps 525:
1.11 schwarze 526: return(1);
527: }
1.1 kristaps 528:
529:
1.11 schwarze 530: /* ARGSUSED */
531: static void
532: post_IP(DECL_ARGS)
533: {
1.4 schwarze 534:
1.11 schwarze 535: switch (n->type) {
536: case (MAN_HEAD):
537: term_flushln(p);
538: p->flags &= ~TERMP_NOBREAK;
539: p->flags &= ~TERMP_TWOSPACE;
540: p->rmargin = p->maxrmargin;
541: break;
542: case (MAN_BODY):
543: term_flushln(p);
544: p->flags &= ~TERMP_NOLPAD;
545: break;
546: default:
547: break;
548: }
1.1 kristaps 549: }
550:
551:
552: /* ARGSUSED */
553: static int
554: pre_TP(DECL_ARGS)
555: {
1.11 schwarze 556: const struct man_node *nn;
557: size_t len;
558: int ival;
559:
560: switch (n->type) {
561: case (MAN_HEAD):
562: p->flags |= TERMP_NOBREAK;
563: p->flags |= TERMP_TWOSPACE;
564: break;
565: case (MAN_BODY):
566: p->flags |= TERMP_NOLPAD;
567: p->flags |= TERMP_NOSPACE;
568: break;
569: case (MAN_BLOCK):
1.18 schwarze 570: print_bvspace(p, n);
1.11 schwarze 571: /* FALLTHROUGH */
572: default:
573: return(1);
574: }
575:
576: len = (size_t)mt->lmargin;
577: ival = -1;
578:
579: /* Calculate offset. */
1.1 kristaps 580:
1.22 schwarze 581: if (NULL != (nn = n->parent->head->child)) {
582: while (nn && MAN_TEXT != nn->type)
583: nn = nn->next;
584: if (nn && nn->next)
1.19 schwarze 585: if ((ival = a2width(nn)) >= 0)
1.11 schwarze 586: len = (size_t)ival;
1.22 schwarze 587: }
1.8 schwarze 588:
1.11 schwarze 589: switch (n->type) {
590: case (MAN_HEAD):
591: /* Handle zero-length properly. */
592: if (0 == len)
593: len = 1;
594:
1.13 schwarze 595: p->offset = mt->offset;
596: p->rmargin = mt->offset + len;
1.11 schwarze 597:
598: /* Don't print same-line elements. */
599: for (nn = n->child; nn; nn = nn->next)
600: if (nn->line > n->line)
1.19 schwarze 601: print_man_node(p, mt, nn, m);
1.11 schwarze 602:
603: if (ival >= 0)
1.13 schwarze 604: mt->lmargin = (size_t)ival;
1.11 schwarze 605:
606: return(0);
607: case (MAN_BODY):
1.13 schwarze 608: p->offset = mt->offset + len;
1.11 schwarze 609: p->rmargin = p->maxrmargin;
610: break;
611: default:
612: break;
613: }
1.1 kristaps 614:
1.11 schwarze 615: return(1);
616: }
1.1 kristaps 617:
618:
1.11 schwarze 619: /* ARGSUSED */
620: static void
621: post_TP(DECL_ARGS)
622: {
1.1 kristaps 623:
1.11 schwarze 624: switch (n->type) {
625: case (MAN_HEAD):
626: term_flushln(p);
627: p->flags &= ~TERMP_NOBREAK;
628: p->flags &= ~TERMP_TWOSPACE;
629: p->rmargin = p->maxrmargin;
630: break;
631: case (MAN_BODY):
632: term_flushln(p);
633: p->flags &= ~TERMP_NOLPAD;
634: break;
635: default:
636: break;
637: }
1.1 kristaps 638: }
639:
640:
641: /* ARGSUSED */
642: static int
643: pre_SS(DECL_ARGS)
644: {
645:
1.11 schwarze 646: switch (n->type) {
647: case (MAN_BLOCK):
648: mt->lmargin = INDENT;
1.13 schwarze 649: mt->offset = INDENT;
1.11 schwarze 650: /* If following a prior empty `SS', no vspace. */
651: if (n->prev && MAN_SS == n->prev->tok)
652: if (NULL == n->prev->body->child)
653: break;
654: if (NULL == n->prev)
655: break;
656: term_vspace(p);
657: break;
658: case (MAN_HEAD):
1.21 schwarze 659: term_fontrepl(p, TERMFONT_BOLD);
1.11 schwarze 660: p->offset = HALFINDENT;
661: break;
662: case (MAN_BODY):
1.13 schwarze 663: p->offset = mt->offset;
1.11 schwarze 664: break;
665: default:
666: break;
667: }
668:
1.1 kristaps 669: return(1);
670: }
671:
672:
673: /* ARGSUSED */
674: static void
675: post_SS(DECL_ARGS)
676: {
677:
1.11 schwarze 678: switch (n->type) {
679: case (MAN_HEAD):
680: term_newln(p);
681: break;
682: case (MAN_BODY):
683: term_newln(p);
684: break;
685: default:
686: break;
687: }
1.1 kristaps 688: }
689:
690:
691: /* ARGSUSED */
692: static int
693: pre_SH(DECL_ARGS)
694: {
695:
1.11 schwarze 696: switch (n->type) {
697: case (MAN_BLOCK):
698: mt->lmargin = INDENT;
1.13 schwarze 699: mt->offset = INDENT;
1.11 schwarze 700: /* If following a prior empty `SH', no vspace. */
701: if (n->prev && MAN_SH == n->prev->tok)
702: if (NULL == n->prev->body->child)
703: break;
704: term_vspace(p);
705: break;
706: case (MAN_HEAD):
1.21 schwarze 707: term_fontrepl(p, TERMFONT_BOLD);
1.11 schwarze 708: p->offset = 0;
709: break;
710: case (MAN_BODY):
1.13 schwarze 711: p->offset = mt->offset;
1.11 schwarze 712: break;
713: default:
714: break;
715: }
716:
1.1 kristaps 717: return(1);
718: }
719:
720:
721: /* ARGSUSED */
722: static void
723: post_SH(DECL_ARGS)
724: {
725:
1.11 schwarze 726: switch (n->type) {
727: case (MAN_HEAD):
728: term_newln(p);
729: break;
730: case (MAN_BODY):
731: term_newln(p);
732: break;
733: default:
1.13 schwarze 734: break;
735: }
736: }
737:
738:
739: /* ARGSUSED */
740: static int
741: pre_RS(DECL_ARGS)
742: {
743: const struct man_node *nn;
744: int ival;
745:
746: switch (n->type) {
747: case (MAN_BLOCK):
748: term_newln(p);
749: return(1);
750: case (MAN_HEAD):
751: return(0);
752: default:
753: break;
754: }
755:
756: if (NULL == (nn = n->parent->head->child)) {
757: mt->offset = mt->lmargin + INDENT;
758: p->offset = mt->offset;
759: return(1);
760: }
761:
1.19 schwarze 762: if ((ival = a2width(nn)) < 0)
1.13 schwarze 763: return(1);
764:
765: mt->offset = INDENT + (size_t)ival;
766: p->offset = mt->offset;
767:
768: return(1);
769: }
770:
771:
772: /* ARGSUSED */
773: static void
774: post_RS(DECL_ARGS)
775: {
776:
777: switch (n->type) {
778: case (MAN_BLOCK):
779: mt->offset = mt->lmargin = INDENT;
780: break;
781: default:
782: term_newln(p);
783: p->offset = INDENT;
1.11 schwarze 784: break;
785: }
1.1 kristaps 786: }
787:
788:
789: static void
1.19 schwarze 790: print_man_node(DECL_ARGS)
1.1 kristaps 791: {
1.21 schwarze 792: int c;
1.1 kristaps 793:
794: c = 1;
795:
796: switch (n->type) {
797: case(MAN_TEXT):
798: if (0 == *n->string) {
799: term_vspace(p);
800: break;
801: }
1.21 schwarze 802:
1.1 kristaps 803: term_word(p, n->string);
1.21 schwarze 804:
1.11 schwarze 805: /* FIXME: this means that macro lines are munged! */
1.21 schwarze 806:
1.11 schwarze 807: if (MANT_LITERAL & mt->fl) {
808: p->flags |= TERMP_NOSPACE;
809: term_flushln(p);
810: }
1.1 kristaps 811: break;
812: default:
1.26 ! schwarze 813: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
! 814: term_fontrepl(p, TERMFONT_NONE);
1.11 schwarze 815: if (termacts[n->tok].pre)
816: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 817: break;
818: }
819:
820: if (c && n->child)
1.21 schwarze 821: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 822:
1.21 schwarze 823: if (MAN_TEXT != n->type) {
1.1 kristaps 824: if (termacts[n->tok].post)
1.11 schwarze 825: (*termacts[n->tok].post)(p, mt, n, m);
1.26 ! schwarze 826: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
! 827: term_fontrepl(p, TERMFONT_NONE);
1.21 schwarze 828: }
1.1 kristaps 829: }
830:
831:
832: static void
1.21 schwarze 833: print_man_nodelist(DECL_ARGS)
1.1 kristaps 834: {
1.11 schwarze 835:
1.19 schwarze 836: print_man_node(p, mt, n, m);
1.1 kristaps 837: if ( ! n->next)
838: return;
1.21 schwarze 839: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 840: }
841:
842:
843: static void
1.19 schwarze 844: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1 kristaps 845: {
1.19 schwarze 846: char buf[DATESIZ];
1.21 schwarze 847:
848: term_fontrepl(p, TERMFONT_NONE);
1.1 kristaps 849:
1.19 schwarze 850: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 851:
852: term_vspace(p);
853:
854: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
855: p->rmargin = p->maxrmargin - strlen(buf);
856: p->offset = 0;
857:
858: if (meta->source)
859: term_word(p, meta->source);
860: if (meta->source)
861: term_word(p, "");
862: term_flushln(p);
863:
864: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
865: p->offset = p->rmargin;
866: p->rmargin = p->maxrmargin;
867: p->flags &= ~TERMP_NOBREAK;
868:
869: term_word(p, buf);
870: term_flushln(p);
871: }
872:
873:
874: static void
1.20 schwarze 875: print_man_head(struct termp *p, const struct man_meta *m)
1.1 kristaps 876: {
1.20 schwarze 877: char buf[BUFSIZ], title[BUFSIZ];
1.25 schwarze 878: size_t buflen, titlen;
1.1 kristaps 879:
880: p->rmargin = p->maxrmargin;
881: p->offset = 0;
1.20 schwarze 882: buf[0] = title[0] = '\0';
1.1 kristaps 883:
1.20 schwarze 884: if (m->vol)
885: strlcpy(buf, m->vol, BUFSIZ);
1.25 schwarze 886: buflen = strlen(buf);
1.1 kristaps 887:
1.20 schwarze 888: snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
1.25 schwarze 889: titlen = strlen(title);
1.1 kristaps 890:
891: p->offset = 0;
1.25 schwarze 892: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
893: (p->maxrmargin - strlen(buf) + 1) / 2 :
894: p->maxrmargin - buflen;
1.1 kristaps 895: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
896:
897: term_word(p, title);
898: term_flushln(p);
899:
900: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
901: p->offset = p->rmargin;
1.25 schwarze 902: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
903: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 904:
905: term_word(p, buf);
906: term_flushln(p);
907:
908: p->flags &= ~TERMP_NOBREAK;
1.25 schwarze 909: if (p->rmargin + titlen <= p->maxrmargin) {
910: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
911: p->offset = p->rmargin;
912: p->rmargin = p->maxrmargin;
913: term_word(p, title);
914: term_flushln(p);
915: }
1.1 kristaps 916:
917: p->rmargin = p->maxrmargin;
918: p->offset = 0;
919: p->flags &= ~TERMP_NOSPACE;
920: }