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