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