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