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