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