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