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