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