Annotation of src/usr.bin/mandoc/man_term.c, Revision 1.18
1.18 ! schwarze 1: /* $Id: man_term.c,v 1.17 2009/10/19 21:43:16 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 <err.h>
22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <string.h>
25:
1.18 ! schwarze 26: #include "out.h"
! 27: #include "man.h"
1.1 kristaps 28: #include "term.h"
1.18 ! schwarze 29: #include "chars.h"
! 30: #include "main.h"
1.10 schwarze 31:
32: #define INDENT 7
33: #define HALFINDENT 3
1.1 kristaps 34:
1.11 schwarze 35: struct mtermp {
36: int fl;
37: #define MANT_LITERAL (1 << 0)
1.13 schwarze 38: /*
39: * Default amount to indent the left margin after leading text
40: * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
41: * indent). This needs to be saved because `HP' and so on, if
42: * not having a specified value, must default.
43: *
44: * Note that this is the indentation AFTER the left offset, so
45: * the total offset is usually offset + lmargin.
46: */
47: size_t lmargin;
48: /*
49: * The default offset, i.e., the amount between any text and the
50: * page boundary.
51: */
52: size_t offset;
1.11 schwarze 53: };
54:
1.1 kristaps 55: #define DECL_ARGS struct termp *p, \
1.11 schwarze 56: struct mtermp *mt, \
1.1 kristaps 57: const struct man_node *n, \
58: const struct man_meta *m
59:
60: struct termact {
61: int (*pre)(DECL_ARGS);
62: void (*post)(DECL_ARGS);
63: };
64:
1.18 ! schwarze 65: static int arg2width(const struct man_node *);
! 66: static int arg2height(const struct man_node *);
! 67:
! 68: static void print_head(struct termp *,
! 69: const struct man_meta *);
! 70: static void print_body(DECL_ARGS);
! 71: static void print_node(DECL_ARGS);
! 72: static void print_foot(struct termp *,
! 73: const struct man_meta *);
! 74: static void print_bvspace(struct termp *,
! 75: const struct man_node *);
! 76:
1.1 kristaps 77: static int pre_B(DECL_ARGS);
78: static int pre_BI(DECL_ARGS);
1.11 schwarze 79: static int pre_HP(DECL_ARGS);
1.1 kristaps 80: static int pre_I(DECL_ARGS);
81: static int pre_IP(DECL_ARGS);
82: static int pre_IR(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_r(DECL_ARGS);
95: static int pre_sp(DECL_ARGS);
1.1 kristaps 96:
97: static void post_B(DECL_ARGS);
98: static void post_I(DECL_ARGS);
1.11 schwarze 99: static void post_IP(DECL_ARGS);
100: static void post_HP(DECL_ARGS);
1.13 schwarze 101: static void post_RS(DECL_ARGS);
1.1 kristaps 102: static void post_SH(DECL_ARGS);
103: static void post_SS(DECL_ARGS);
1.11 schwarze 104: static void post_TP(DECL_ARGS);
105: static void post_i(DECL_ARGS);
1.1 kristaps 106:
1.17 schwarze 107: static const struct termact termacts[MAN_MAX] = {
1.8 schwarze 108: { pre_br, NULL }, /* br */
1.1 kristaps 109: { NULL, NULL }, /* TH */
110: { pre_SH, post_SH }, /* SH */
111: { pre_SS, post_SS }, /* SS */
1.11 schwarze 112: { pre_TP, post_TP }, /* TP */
1.1 kristaps 113: { pre_PP, NULL }, /* LP */
114: { pre_PP, NULL }, /* PP */
115: { pre_PP, NULL }, /* P */
1.11 schwarze 116: { pre_IP, post_IP }, /* IP */
117: { pre_HP, post_HP }, /* HP */
1.1 kristaps 118: { NULL, NULL }, /* SM */
119: { pre_B, post_B }, /* SB */
120: { pre_BI, NULL }, /* BI */
1.17 schwarze 121: { pre_BI, NULL }, /* IB */
122: { pre_RB, NULL }, /* BR */
1.1 kristaps 123: { pre_RB, NULL }, /* RB */
124: { NULL, NULL }, /* R */
125: { pre_B, post_B }, /* B */
126: { pre_I, post_I }, /* I */
127: { pre_IR, NULL }, /* IR */
128: { pre_RI, NULL }, /* RI */
1.13 schwarze 129: { NULL, NULL }, /* na */
1.11 schwarze 130: { pre_I, post_i }, /* i */
131: { pre_sp, NULL }, /* sp */
132: { pre_nf, NULL }, /* nf */
133: { pre_fi, NULL }, /* fi */
134: { pre_r, NULL }, /* r */
1.13 schwarze 135: { NULL, NULL }, /* RE */
136: { pre_RS, post_RS }, /* RS */
1.14 schwarze 137: { pre_ign, NULL }, /* DT */
138: { pre_ign, NULL }, /* UC */
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.18 ! schwarze 166: print_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)
! 174: print_body(p, &mt, n->child, m);
! 175: print_foot(p, m);
1.1 kristaps 176: }
177:
178:
1.18 ! schwarze 179: static int
! 180: arg2height(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.18 ! schwarze 194: arg2width(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.15 schwarze 238: p->under++;
1.1 kristaps 239: return(1);
240: }
241:
242:
243: /* ARGSUSED */
1.11 schwarze 244: static int
245: pre_r(DECL_ARGS)
246: {
247:
1.15 schwarze 248: p->bold = p->under = 0;
1.11 schwarze 249: return(1);
250: }
251:
252:
253: /* ARGSUSED */
254: static void
255: post_i(DECL_ARGS)
256: {
257:
258: if (n->nchild)
1.15 schwarze 259: p->under--;
1.11 schwarze 260: }
261:
262:
263: /* ARGSUSED */
1.1 kristaps 264: static void
265: post_I(DECL_ARGS)
266: {
267:
1.15 schwarze 268: p->under--;
1.1 kristaps 269: }
270:
271:
272: /* ARGSUSED */
273: static int
1.11 schwarze 274: pre_fi(DECL_ARGS)
275: {
276:
277: mt->fl &= ~MANT_LITERAL;
278: return(1);
279: }
280:
281:
282: /* ARGSUSED */
283: static int
284: pre_nf(DECL_ARGS)
285: {
286:
287: term_newln(p);
288: mt->fl |= MANT_LITERAL;
289: return(1);
290: }
291:
292:
293: /* ARGSUSED */
294: static int
1.1 kristaps 295: pre_IR(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++) {
301: if ( ! (i % 2))
1.15 schwarze 302: p->under++;
1.1 kristaps 303: if (i > 0)
304: p->flags |= TERMP_NOSPACE;
1.11 schwarze 305: print_node(p, mt, nn, m);
1.1 kristaps 306: if ( ! (i % 2))
1.15 schwarze 307: p->under--;
1.1 kristaps 308: }
309: return(0);
310: }
311:
312:
313: /* ARGSUSED */
314: static int
1.17 schwarze 315: pre_RB(DECL_ARGS)
1.1 kristaps 316: {
317: const struct man_node *nn;
318: int i;
319:
320: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17 schwarze 321: if (i % 2 && MAN_RB == n->tok)
322: p->bold++;
323: else if ( ! (i % 2) && MAN_RB != n->tok)
1.15 schwarze 324: p->bold++;
1.17 schwarze 325:
1.1 kristaps 326: if (i > 0)
327: p->flags |= TERMP_NOSPACE;
1.17 schwarze 328:
1.11 schwarze 329: print_node(p, mt, nn, m);
1.17 schwarze 330:
331: if (i % 2 && MAN_RB == n->tok)
1.15 schwarze 332: p->bold--;
1.17 schwarze 333: else if ( ! (i % 2) && MAN_RB != n->tok)
1.15 schwarze 334: p->bold--;
1.1 kristaps 335: }
336: return(0);
337: }
338:
339:
340: /* ARGSUSED */
341: static int
342: pre_RI(DECL_ARGS)
343: {
344: const struct man_node *nn;
345: int i;
346:
347: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
348: if ( ! (i % 2))
1.15 schwarze 349: p->under++;
1.1 kristaps 350: if (i > 0)
351: p->flags |= TERMP_NOSPACE;
1.11 schwarze 352: print_node(p, mt, nn, m);
1.1 kristaps 353: if ( ! (i % 2))
1.15 schwarze 354: p->under--;
1.1 kristaps 355: }
356: return(0);
357: }
358:
359:
360: /* ARGSUSED */
361: static int
362: pre_BI(DECL_ARGS)
363: {
1.17 schwarze 364: const struct man_node *nn;
365: int i;
1.1 kristaps 366:
367: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17 schwarze 368: if (i % 2 && MAN_BI == n->tok)
1.15 schwarze 369: p->under++;
1.17 schwarze 370: else if (i % 2)
371: p->bold++;
372: else if (MAN_BI == n->tok)
373: p->bold++;
1.15 schwarze 374: else
1.17 schwarze 375: p->under++;
376:
377: if (i)
1.1 kristaps 378: p->flags |= TERMP_NOSPACE;
1.11 schwarze 379: print_node(p, mt, nn, m);
1.17 schwarze 380:
381: if (i % 2 && MAN_BI == n->tok)
1.15 schwarze 382: p->under--;
1.17 schwarze 383: else if (i % 2)
384: p->bold--;
385: else if (MAN_BI == n->tok)
386: p->bold--;
1.15 schwarze 387: else
1.17 schwarze 388: p->under--;
1.1 kristaps 389: }
390: return(0);
391: }
392:
393:
394: /* ARGSUSED */
395: static int
396: pre_B(DECL_ARGS)
397: {
398:
1.15 schwarze 399: p->bold++;
1.1 kristaps 400: return(1);
401: }
402:
403:
404: /* ARGSUSED */
405: static void
406: post_B(DECL_ARGS)
407: {
408:
1.15 schwarze 409: p->bold--;
1.1 kristaps 410: }
411:
412:
413: /* ARGSUSED */
414: static int
1.11 schwarze 415: pre_sp(DECL_ARGS)
416: {
417: int i, len;
418:
1.18 ! schwarze 419: len = n->child ? arg2height(n->child) : 1;
1.11 schwarze 420:
421: if (0 == len)
422: term_newln(p);
423: for (i = 0; i < len; i++)
424: term_vspace(p);
425:
426: return(0);
427: }
428:
429:
430: /* ARGSUSED */
431: static int
1.8 schwarze 432: pre_br(DECL_ARGS)
433: {
434:
435: term_newln(p);
436: return(0);
437: }
438:
439:
440: /* ARGSUSED */
441: static int
1.11 schwarze 442: pre_HP(DECL_ARGS)
443: {
444: size_t len;
445: int ival;
446: const struct man_node *nn;
447:
448: switch (n->type) {
449: case (MAN_BLOCK):
1.18 ! schwarze 450: print_bvspace(p, n);
1.11 schwarze 451: return(1);
452: case (MAN_BODY):
453: p->flags |= TERMP_NOBREAK;
454: p->flags |= TERMP_TWOSPACE;
455: break;
456: default:
457: return(0);
458: }
459:
1.13 schwarze 460: len = mt->lmargin;
1.11 schwarze 461: ival = -1;
462:
463: /* Calculate offset. */
464:
465: if (NULL != (nn = n->parent->head->child))
1.18 ! schwarze 466: if ((ival = arg2width(nn)) >= 0)
1.11 schwarze 467: len = (size_t)ival;
468:
469: if (0 == len)
470: len = 1;
471:
1.13 schwarze 472: p->offset = mt->offset;
473: p->rmargin = mt->offset + len;
1.11 schwarze 474:
475: if (ival >= 0)
1.13 schwarze 476: mt->lmargin = (size_t)ival;
1.11 schwarze 477:
478: return(1);
479: }
480:
481:
482: /* ARGSUSED */
483: static void
484: post_HP(DECL_ARGS)
485: {
486:
487: switch (n->type) {
488: case (MAN_BLOCK):
489: term_flushln(p);
490: break;
491: case (MAN_BODY):
492: term_flushln(p);
493: p->flags &= ~TERMP_NOBREAK;
494: p->flags &= ~TERMP_TWOSPACE;
1.13 schwarze 495: p->offset = mt->offset;
1.11 schwarze 496: p->rmargin = p->maxrmargin;
497: break;
498: default:
499: break;
500: }
501: }
502:
503:
504: /* ARGSUSED */
505: static int
1.1 kristaps 506: pre_PP(DECL_ARGS)
507: {
508:
1.11 schwarze 509: switch (n->type) {
510: case (MAN_BLOCK):
511: mt->lmargin = INDENT;
1.18 ! schwarze 512: print_bvspace(p, n);
1.11 schwarze 513: break;
514: default:
1.13 schwarze 515: p->offset = mt->offset;
1.11 schwarze 516: break;
517: }
518:
519: return(1);
1.1 kristaps 520: }
521:
522:
523: /* ARGSUSED */
524: static int
525: pre_IP(DECL_ARGS)
526: {
1.11 schwarze 527: const struct man_node *nn;
528: size_t len;
529: int ival;
530:
531: switch (n->type) {
532: case (MAN_BODY):
533: p->flags |= TERMP_NOLPAD;
534: p->flags |= TERMP_NOSPACE;
535: break;
536: case (MAN_HEAD):
537: p->flags |= TERMP_NOBREAK;
538: p->flags |= TERMP_TWOSPACE;
539: break;
540: case (MAN_BLOCK):
1.18 ! schwarze 541: print_bvspace(p, n);
1.11 schwarze 542: /* FALLTHROUGH */
543: default:
544: return(1);
545: }
546:
1.13 schwarze 547: len = mt->lmargin;
1.11 schwarze 548: ival = -1;
549:
550: /* Calculate offset. */
551:
552: if (NULL != (nn = n->parent->head->child))
553: if (NULL != (nn = nn->next)) {
554: for ( ; nn->next; nn = nn->next)
555: /* Do nothing. */ ;
1.18 ! schwarze 556: if ((ival = arg2width(nn)) >= 0)
1.11 schwarze 557: len = (size_t)ival;
558: }
559:
560: switch (n->type) {
561: case (MAN_HEAD):
562: /* Handle zero-width lengths. */
563: if (0 == len)
564: len = 1;
565:
1.13 schwarze 566: p->offset = mt->offset;
567: p->rmargin = mt->offset + len;
1.11 schwarze 568: if (ival < 0)
569: break;
570:
571: /* Set the saved left-margin. */
1.13 schwarze 572: mt->lmargin = (size_t)ival;
1.1 kristaps 573:
1.11 schwarze 574: /* Don't print the length value. */
575: for (nn = n->child; nn->next; nn = nn->next)
576: print_node(p, mt, nn, m);
577: return(0);
578: case (MAN_BODY):
1.13 schwarze 579: p->offset = mt->offset + len;
1.11 schwarze 580: p->rmargin = p->maxrmargin;
581: break;
582: default:
583: break;
584: }
1.1 kristaps 585:
1.11 schwarze 586: return(1);
587: }
1.1 kristaps 588:
589:
1.11 schwarze 590: /* ARGSUSED */
591: static void
592: post_IP(DECL_ARGS)
593: {
1.4 schwarze 594:
1.11 schwarze 595: switch (n->type) {
596: case (MAN_HEAD):
597: term_flushln(p);
598: p->flags &= ~TERMP_NOBREAK;
599: p->flags &= ~TERMP_TWOSPACE;
600: p->rmargin = p->maxrmargin;
601: break;
602: case (MAN_BODY):
603: term_flushln(p);
604: p->flags &= ~TERMP_NOLPAD;
605: break;
606: default:
607: break;
608: }
1.1 kristaps 609: }
610:
611:
612: /* ARGSUSED */
613: static int
614: pre_TP(DECL_ARGS)
615: {
1.11 schwarze 616: const struct man_node *nn;
617: size_t len;
618: int ival;
619:
620: switch (n->type) {
621: case (MAN_HEAD):
622: p->flags |= TERMP_NOBREAK;
623: p->flags |= TERMP_TWOSPACE;
624: break;
625: case (MAN_BODY):
626: p->flags |= TERMP_NOLPAD;
627: p->flags |= TERMP_NOSPACE;
628: break;
629: case (MAN_BLOCK):
1.18 ! schwarze 630: print_bvspace(p, n);
1.11 schwarze 631: /* FALLTHROUGH */
632: default:
633: return(1);
634: }
635:
636: len = (size_t)mt->lmargin;
637: ival = -1;
638:
639: /* Calculate offset. */
1.1 kristaps 640:
1.11 schwarze 641: if (NULL != (nn = n->parent->head->child))
642: if (NULL != nn->next)
1.18 ! schwarze 643: if ((ival = arg2width(nn)) >= 0)
1.11 schwarze 644: len = (size_t)ival;
1.8 schwarze 645:
1.11 schwarze 646: switch (n->type) {
647: case (MAN_HEAD):
648: /* Handle zero-length properly. */
649: if (0 == len)
650: len = 1;
651:
1.13 schwarze 652: p->offset = mt->offset;
653: p->rmargin = mt->offset + len;
1.11 schwarze 654:
655: /* Don't print same-line elements. */
656: for (nn = n->child; nn; nn = nn->next)
657: if (nn->line > n->line)
658: print_node(p, mt, nn, m);
659:
660: if (ival >= 0)
1.13 schwarze 661: mt->lmargin = (size_t)ival;
1.11 schwarze 662:
663: return(0);
664: case (MAN_BODY):
1.13 schwarze 665: p->offset = mt->offset + len;
1.11 schwarze 666: p->rmargin = p->maxrmargin;
667: break;
668: default:
669: break;
670: }
1.1 kristaps 671:
1.11 schwarze 672: return(1);
673: }
1.1 kristaps 674:
675:
1.11 schwarze 676: /* ARGSUSED */
677: static void
678: post_TP(DECL_ARGS)
679: {
1.1 kristaps 680:
1.11 schwarze 681: switch (n->type) {
682: case (MAN_HEAD):
683: term_flushln(p);
684: p->flags &= ~TERMP_NOBREAK;
685: p->flags &= ~TERMP_TWOSPACE;
686: p->rmargin = p->maxrmargin;
687: break;
688: case (MAN_BODY):
689: term_flushln(p);
690: p->flags &= ~TERMP_NOLPAD;
691: break;
692: default:
693: break;
694: }
1.1 kristaps 695: }
696:
697:
698: /* ARGSUSED */
699: static int
700: pre_SS(DECL_ARGS)
701: {
702:
1.11 schwarze 703: switch (n->type) {
704: case (MAN_BLOCK):
705: mt->lmargin = INDENT;
1.13 schwarze 706: mt->offset = INDENT;
1.11 schwarze 707: /* If following a prior empty `SS', no vspace. */
708: if (n->prev && MAN_SS == n->prev->tok)
709: if (NULL == n->prev->body->child)
710: break;
711: if (NULL == n->prev)
712: break;
713: term_vspace(p);
714: break;
715: case (MAN_HEAD):
1.15 schwarze 716: p->bold++;
1.11 schwarze 717: p->offset = HALFINDENT;
718: break;
719: case (MAN_BODY):
1.13 schwarze 720: p->offset = mt->offset;
1.11 schwarze 721: break;
722: default:
723: break;
724: }
725:
1.1 kristaps 726: return(1);
727: }
728:
729:
730: /* ARGSUSED */
731: static void
732: post_SS(DECL_ARGS)
733: {
734:
1.11 schwarze 735: switch (n->type) {
736: case (MAN_HEAD):
737: term_newln(p);
1.15 schwarze 738: p->bold--;
1.11 schwarze 739: break;
740: case (MAN_BODY):
741: term_newln(p);
742: break;
743: default:
744: break;
745: }
1.1 kristaps 746: }
747:
748:
749: /* ARGSUSED */
750: static int
751: pre_SH(DECL_ARGS)
752: {
753:
1.11 schwarze 754: switch (n->type) {
755: case (MAN_BLOCK):
756: mt->lmargin = INDENT;
1.13 schwarze 757: mt->offset = INDENT;
1.11 schwarze 758: /* If following a prior empty `SH', no vspace. */
759: if (n->prev && MAN_SH == n->prev->tok)
760: if (NULL == n->prev->body->child)
761: break;
762: term_vspace(p);
763: break;
764: case (MAN_HEAD):
1.15 schwarze 765: p->bold++;
1.11 schwarze 766: p->offset = 0;
767: break;
768: case (MAN_BODY):
1.13 schwarze 769: p->offset = mt->offset;
1.11 schwarze 770: break;
771: default:
772: break;
773: }
774:
1.1 kristaps 775: return(1);
776: }
777:
778:
779: /* ARGSUSED */
780: static void
781: post_SH(DECL_ARGS)
782: {
783:
1.11 schwarze 784: switch (n->type) {
785: case (MAN_HEAD):
786: term_newln(p);
1.15 schwarze 787: p->bold--;
1.11 schwarze 788: break;
789: case (MAN_BODY):
790: term_newln(p);
791: break;
792: default:
1.13 schwarze 793: break;
794: }
795: }
796:
797:
798: /* ARGSUSED */
799: static int
800: pre_RS(DECL_ARGS)
801: {
802: const struct man_node *nn;
803: int ival;
804:
805: switch (n->type) {
806: case (MAN_BLOCK):
807: term_newln(p);
808: return(1);
809: case (MAN_HEAD):
810: return(0);
811: default:
812: break;
813: }
814:
815: if (NULL == (nn = n->parent->head->child)) {
816: mt->offset = mt->lmargin + INDENT;
817: p->offset = mt->offset;
818: return(1);
819: }
820:
1.18 ! schwarze 821: if ((ival = arg2width(nn)) < 0)
1.13 schwarze 822: return(1);
823:
824: mt->offset = INDENT + (size_t)ival;
825: p->offset = mt->offset;
826:
827: return(1);
828: }
829:
830:
831: /* ARGSUSED */
832: static void
833: post_RS(DECL_ARGS)
834: {
835:
836: switch (n->type) {
837: case (MAN_BLOCK):
838: mt->offset = mt->lmargin = INDENT;
839: break;
840: default:
841: term_newln(p);
842: p->offset = INDENT;
1.11 schwarze 843: break;
844: }
1.1 kristaps 845: }
846:
847:
848: static void
849: print_node(DECL_ARGS)
850: {
851: int c, sz;
852:
853: c = 1;
854:
855: switch (n->type) {
856: case(MAN_TEXT):
857: if (0 == *n->string) {
858: term_vspace(p);
859: break;
860: }
861: /*
862: * Note! This is hacky. Here, we recognise the `\c'
863: * escape embedded in so many -man pages. It's supposed
864: * to remove the subsequent space, so we mark NOSPACE if
865: * it's encountered in the string.
866: */
867: sz = (int)strlen(n->string);
868: term_word(p, n->string);
869: if (sz >= 2 && n->string[sz - 1] == 'c' &&
870: n->string[sz - 2] == '\\')
871: p->flags |= TERMP_NOSPACE;
1.11 schwarze 872: /* FIXME: this means that macro lines are munged! */
873: if (MANT_LITERAL & mt->fl) {
874: p->flags |= TERMP_NOSPACE;
875: term_flushln(p);
876: }
1.1 kristaps 877: break;
878: default:
1.11 schwarze 879: if (termacts[n->tok].pre)
880: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 881: break;
882: }
883:
884: if (c && n->child)
1.11 schwarze 885: print_body(p, mt, n->child, m);
1.1 kristaps 886:
1.11 schwarze 887: if (MAN_TEXT != n->type)
1.1 kristaps 888: if (termacts[n->tok].post)
1.11 schwarze 889: (*termacts[n->tok].post)(p, mt, n, m);
1.1 kristaps 890: }
891:
892:
893: static void
894: print_body(DECL_ARGS)
895: {
1.11 schwarze 896:
897: print_node(p, mt, n, m);
1.1 kristaps 898: if ( ! n->next)
899: return;
1.11 schwarze 900: print_body(p, mt, n->next, m);
1.1 kristaps 901: }
902:
903:
904: static void
905: print_foot(struct termp *p, const struct man_meta *meta)
906: {
907: struct tm *tm;
1.17 schwarze 908: char buf[BUFSIZ];
1.1 kristaps 909:
910: tm = localtime(&meta->date);
911:
1.3 schwarze 912: if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
1.17 schwarze 913: (void)strlcpy(buf, "(invalid date)", BUFSIZ);
1.1 kristaps 914:
915: term_vspace(p);
916:
917: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
918: p->rmargin = p->maxrmargin - strlen(buf);
919: p->offset = 0;
920:
921: if (meta->source)
922: term_word(p, meta->source);
923: if (meta->source)
924: term_word(p, "");
925: term_flushln(p);
926:
927: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
928: p->offset = p->rmargin;
929: p->rmargin = p->maxrmargin;
930: p->flags &= ~TERMP_NOBREAK;
931:
932: term_word(p, buf);
933: term_flushln(p);
934: }
935:
936:
937: static void
938: print_head(struct termp *p, const struct man_meta *meta)
939: {
940: char *buf, *title;
941:
942: p->rmargin = p->maxrmargin;
943: p->offset = 0;
944:
945: if (NULL == (buf = malloc(p->rmargin)))
1.16 schwarze 946: err(EXIT_FAILURE, "malloc");
1.1 kristaps 947: if (NULL == (title = malloc(p->rmargin)))
1.16 schwarze 948: err(EXIT_FAILURE, "malloc");
1.1 kristaps 949:
950: if (meta->vol)
951: (void)strlcpy(buf, meta->vol, p->rmargin);
952: else
953: *buf = 0;
954:
955: (void)snprintf(title, p->rmargin, "%s(%d)",
956: meta->title, meta->msec);
957:
958: p->offset = 0;
1.5 schwarze 959: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 960: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
961:
962: term_word(p, title);
963: term_flushln(p);
964:
965: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
966: p->offset = p->rmargin;
967: p->rmargin = p->maxrmargin - strlen(title);
968:
969: term_word(p, buf);
970: term_flushln(p);
971:
972: p->offset = p->rmargin;
973: p->rmargin = p->maxrmargin;
974: p->flags &= ~TERMP_NOBREAK;
975: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
976:
977: term_word(p, title);
978: term_flushln(p);
979:
980: p->rmargin = p->maxrmargin;
981: p->offset = 0;
982: p->flags &= ~TERMP_NOSPACE;
983:
984: free(title);
985: free(buf);
986: }
987: