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