Annotation of mandoc/man_term.c, Revision 1.57
1.57 ! kristaps 1: /* $Id: man_term.c,v 1.56 2010/03/22 05:59:32 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.40 kristaps 29: #include "out.h"
1.36 kristaps 30: #include "man.h"
1.1 kristaps 31: #include "term.h"
1.36 kristaps 32: #include "chars.h"
33: #include "main.h"
1.1 kristaps 34:
1.18 kristaps 35: #define INDENT 7
36: #define HALFINDENT 3
37:
1.44 kristaps 38: /* FIXME: have PD set the default vspace width. */
39:
1.24 kristaps 40: struct mtermp {
41: int fl;
1.19 kristaps 42: #define MANT_LITERAL (1 << 0)
1.26 kristaps 43: /*
44: * Default amount to indent the left margin after leading text
45: * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
46: * indent). This needs to be saved because `HP' and so on, if
47: * not having a specified value, must default.
48: *
49: * Note that this is the indentation AFTER the left offset, so
50: * the total offset is usually offset + lmargin.
51: */
52: size_t lmargin;
53: /*
54: * The default offset, i.e., the amount between any text and the
55: * page boundary.
56: */
57: size_t offset;
1.24 kristaps 58: };
1.19 kristaps 59:
1.1 kristaps 60: #define DECL_ARGS struct termp *p, \
1.24 kristaps 61: struct mtermp *mt, \
1.1 kristaps 62: const struct man_node *n, \
63: const struct man_meta *m
64:
65: struct termact {
66: int (*pre)(DECL_ARGS);
67: void (*post)(DECL_ARGS);
1.56 kristaps 68: int flags;
69: #define MAN_NOTEXT (1 << 0) /* Never has text children. */
1.1 kristaps 70: };
71:
1.45 kristaps 72: static int a2width(const struct man_node *);
73: static int a2height(const struct man_node *);
1.39 kristaps 74:
1.45 kristaps 75: static void print_man_head(struct termp *,
1.39 kristaps 76: const struct man_meta *);
1.52 kristaps 77: static void print_man_nodelist(DECL_ARGS);
1.45 kristaps 78: static void print_man_node(DECL_ARGS);
79: static void print_man_foot(struct termp *,
1.39 kristaps 80: const struct man_meta *);
81: static void print_bvspace(struct termp *,
82: const struct man_node *);
83:
1.1 kristaps 84: static int pre_B(DECL_ARGS);
1.3 kristaps 85: static int pre_BI(DECL_ARGS);
1.19 kristaps 86: static int pre_HP(DECL_ARGS);
1.1 kristaps 87: static int pre_I(DECL_ARGS);
1.4 kristaps 88: static int pre_IP(DECL_ARGS);
1.1 kristaps 89: static int pre_PP(DECL_ARGS);
1.3 kristaps 90: static int pre_RB(DECL_ARGS);
91: static int pre_RI(DECL_ARGS);
1.26 kristaps 92: static int pre_RS(DECL_ARGS);
1.1 kristaps 93: static int pre_SH(DECL_ARGS);
94: static int pre_SS(DECL_ARGS);
95: static int pre_TP(DECL_ARGS);
1.19 kristaps 96: static int pre_br(DECL_ARGS);
97: static int pre_fi(DECL_ARGS);
1.29 kristaps 98: static int pre_ign(DECL_ARGS);
1.19 kristaps 99: static int pre_nf(DECL_ARGS);
100: static int pre_sp(DECL_ARGS);
1.1 kristaps 101:
1.22 kristaps 102: static void post_IP(DECL_ARGS);
1.20 kristaps 103: static void post_HP(DECL_ARGS);
1.26 kristaps 104: static void post_RS(DECL_ARGS);
1.1 kristaps 105: static void post_SH(DECL_ARGS);
106: static void post_SS(DECL_ARGS);
1.21 kristaps 107: static void post_TP(DECL_ARGS);
1.1 kristaps 108:
1.32 kristaps 109: static const struct termact termacts[MAN_MAX] = {
1.56 kristaps 110: { pre_br, NULL, MAN_NOTEXT }, /* br */
111: { NULL, NULL, 0 }, /* TH */
112: { pre_SH, post_SH, 0 }, /* SH */
113: { pre_SS, post_SS, 0 }, /* SS */
114: { pre_TP, post_TP, 0 }, /* TP */
115: { pre_PP, NULL, 0 }, /* LP */
116: { pre_PP, NULL, 0 }, /* PP */
117: { pre_PP, NULL, 0 }, /* P */
118: { pre_IP, post_IP, 0 }, /* IP */
119: { pre_HP, post_HP, 0 }, /* HP */
120: { NULL, NULL, 0 }, /* SM */
121: { pre_B, NULL, 0 }, /* SB */
122: { pre_BI, NULL, 0 }, /* BI */
123: { pre_BI, NULL, 0 }, /* IB */
124: { pre_RB, NULL, 0 }, /* BR */
125: { pre_RB, NULL, 0 }, /* RB */
126: { NULL, NULL, 0 }, /* R */
127: { pre_B, NULL, 0 }, /* B */
128: { pre_I, NULL, 0 }, /* I */
129: { pre_RI, NULL, 0 }, /* IR */
130: { pre_RI, NULL, 0 }, /* RI */
131: { NULL, NULL, MAN_NOTEXT }, /* na */
132: { pre_I, NULL, 0 }, /* i */
133: { pre_sp, NULL, MAN_NOTEXT }, /* sp */
134: { pre_nf, NULL, 0 }, /* nf */
135: { pre_fi, NULL, 0 }, /* fi */
136: { NULL, NULL, 0 }, /* r */
137: { NULL, NULL, 0 }, /* RE */
138: { pre_RS, post_RS, 0 }, /* RS */
139: { pre_ign, NULL, 0 }, /* DT */
140: { pre_ign, NULL, 0 }, /* UC */
141: { pre_ign, NULL, 0 }, /* PD */
1.57 ! kristaps 142: { pre_sp, NULL, MAN_NOTEXT }, /* Sp */
! 143: { pre_nf, NULL, 0 }, /* Vb */
! 144: { pre_fi, NULL, 0 }, /* Ve */
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:
159: if (NULL == p->symtab)
160: switch (p->enc) {
161: case (TERMENC_ASCII):
1.57 ! kristaps 162: p->maxrmargin = 65;
1.36 kristaps 163: p->symtab = chars_init(CHARS_ASCII);
164: break;
165: default:
166: abort();
167: /* NOTREACHED */
168: }
169:
170: n = man_node(man);
171: m = man_meta(man);
1.1 kristaps 172:
1.45 kristaps 173: print_man_head(p, m);
1.1 kristaps 174: p->flags |= TERMP_NOSPACE;
1.19 kristaps 175:
1.24 kristaps 176: mt.fl = 0;
177: mt.lmargin = INDENT;
1.26 kristaps 178: mt.offset = INDENT;
1.24 kristaps 179:
1.36 kristaps 180: if (n->child)
1.52 kristaps 181: print_man_nodelist(p, &mt, n->child, m);
1.45 kristaps 182: print_man_foot(p, m);
1.1 kristaps 183: }
184:
185:
1.39 kristaps 186: static int
1.45 kristaps 187: a2height(const struct man_node *n)
1.18 kristaps 188: {
1.40 kristaps 189: struct roffsu su;
1.18 kristaps 190:
1.39 kristaps 191: assert(MAN_TEXT == n->type);
192: assert(n->string);
1.40 kristaps 193: if ( ! a2roffsu(n->string, &su, SCALE_VS))
194: SCALE_VS_INIT(&su, strlen(n->string));
1.18 kristaps 195:
1.41 kristaps 196: return((int)term_vspan(&su));
1.18 kristaps 197: }
198:
199:
200: static int
1.45 kristaps 201: a2width(const struct man_node *n)
1.38 kristaps 202: {
1.40 kristaps 203: struct roffsu su;
1.38 kristaps 204:
1.39 kristaps 205: assert(MAN_TEXT == n->type);
206: assert(n->string);
1.40 kristaps 207: if ( ! a2roffsu(n->string, &su, SCALE_BU))
1.41 kristaps 208: return(-1);
1.40 kristaps 209:
1.41 kristaps 210: return((int)term_hspan(&su));
1.38 kristaps 211: }
212:
213:
1.39 kristaps 214: static void
215: print_bvspace(struct termp *p, const struct man_node *n)
1.18 kristaps 216: {
1.39 kristaps 217: term_newln(p);
1.18 kristaps 218:
1.39 kristaps 219: if (NULL == n->prev)
220: return;
1.18 kristaps 221:
1.39 kristaps 222: if (MAN_SS == n->prev->tok)
223: return;
224: if (MAN_SH == n->prev->tok)
225: return;
1.18 kristaps 226:
1.39 kristaps 227: term_vspace(p);
1.18 kristaps 228: }
229:
230:
1.3 kristaps 231: /* ARGSUSED */
1.1 kristaps 232: static int
1.29 kristaps 233: pre_ign(DECL_ARGS)
234: {
235:
236: return(0);
237: }
238:
239:
240: /* ARGSUSED */
241: static int
1.1 kristaps 242: pre_I(DECL_ARGS)
243: {
244:
1.52 kristaps 245: term_fontrepl(p, TERMFONT_UNDER);
1.19 kristaps 246: return(1);
247: }
248:
249:
250: /* ARGSUSED */
1.3 kristaps 251: static int
1.19 kristaps 252: pre_fi(DECL_ARGS)
253: {
254:
1.57 ! kristaps 255: p->rmargin = p->maxrmargin = 65;
1.24 kristaps 256: mt->fl &= ~MANT_LITERAL;
1.19 kristaps 257: return(1);
258: }
259:
260:
261: /* ARGSUSED */
262: static int
263: pre_nf(DECL_ARGS)
264: {
265:
1.57 ! kristaps 266: p->rmargin = p->maxrmargin = 78;
1.19 kristaps 267: term_newln(p);
1.24 kristaps 268: mt->fl |= MANT_LITERAL;
1.57 ! kristaps 269:
! 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);
368: for (i = 0; i < len; i++)
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: p->flags |= TERMP_TWOSPACE;
484: break;
1.23 kristaps 485: case (MAN_BLOCK):
1.39 kristaps 486: print_bvspace(p, n);
1.23 kristaps 487: /* FALLTHROUGH */
1.22 kristaps 488: default:
489: return(1);
490: }
1.18 kristaps 491:
1.26 kristaps 492: len = mt->lmargin;
1.22 kristaps 493: ival = -1;
1.4 kristaps 494:
1.22 kristaps 495: /* Calculate offset. */
1.4 kristaps 496:
1.22 kristaps 497: if (NULL != (nn = n->parent->head->child))
498: if (NULL != (nn = nn->next)) {
499: for ( ; nn->next; nn = nn->next)
500: /* Do nothing. */ ;
1.45 kristaps 501: if ((ival = a2width(nn)) >= 0)
1.22 kristaps 502: len = (size_t)ival;
503: }
1.4 kristaps 504:
1.22 kristaps 505: switch (n->type) {
506: case (MAN_HEAD):
1.23 kristaps 507: /* Handle zero-width lengths. */
508: if (0 == len)
509: len = 1;
510:
1.26 kristaps 511: p->offset = mt->offset;
512: p->rmargin = mt->offset + len;
1.22 kristaps 513: if (ival < 0)
514: break;
1.18 kristaps 515:
1.24 kristaps 516: /* Set the saved left-margin. */
1.26 kristaps 517: mt->lmargin = (size_t)ival;
1.24 kristaps 518:
1.22 kristaps 519: /* Don't print the length value. */
520: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 521: print_man_node(p, mt, nn, m);
1.22 kristaps 522: return(0);
1.23 kristaps 523: case (MAN_BODY):
1.26 kristaps 524: p->offset = mt->offset + len;
1.23 kristaps 525: p->rmargin = p->maxrmargin;
526: break;
1.22 kristaps 527: default:
528: break;
1.18 kristaps 529: }
530:
1.22 kristaps 531: return(1);
532: }
1.18 kristaps 533:
534:
1.22 kristaps 535: /* ARGSUSED */
536: static void
537: post_IP(DECL_ARGS)
538: {
1.4 kristaps 539:
1.22 kristaps 540: switch (n->type) {
541: case (MAN_HEAD):
542: term_flushln(p);
543: p->flags &= ~TERMP_NOBREAK;
544: p->flags &= ~TERMP_TWOSPACE;
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.4 kristaps 554: }
555:
556:
557: /* ARGSUSED */
558: static int
1.1 kristaps 559: pre_TP(DECL_ARGS)
560: {
1.23 kristaps 561: const struct man_node *nn;
562: size_t len;
563: int ival;
1.1 kristaps 564:
1.21 kristaps 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;
1.23 kristaps 573: break;
574: case (MAN_BLOCK):
1.39 kristaps 575: print_bvspace(p, n);
1.23 kristaps 576: /* FALLTHROUGH */
577: default:
578: return(1);
579: }
580:
1.24 kristaps 581: len = (size_t)mt->lmargin;
1.23 kristaps 582: ival = -1;
583:
584: /* Calculate offset. */
585:
1.56 kristaps 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.45 kristaps 590: if ((ival = a2width(nn)) >= 0)
1.23 kristaps 591: len = (size_t)ival;
1.56 kristaps 592: }
1.23 kristaps 593:
594: switch (n->type) {
595: case (MAN_HEAD):
596: /* Handle zero-length properly. */
597: if (0 == len)
598: len = 1;
599:
1.26 kristaps 600: p->offset = mt->offset;
601: p->rmargin = mt->offset + len;
1.23 kristaps 602:
603: /* Don't print same-line elements. */
604: for (nn = n->child; nn; nn = nn->next)
605: if (nn->line > n->line)
1.45 kristaps 606: print_man_node(p, mt, nn, m);
1.24 kristaps 607:
608: if (ival >= 0)
1.26 kristaps 609: mt->lmargin = (size_t)ival;
1.24 kristaps 610:
1.23 kristaps 611: return(0);
612: case (MAN_BODY):
1.26 kristaps 613: p->offset = mt->offset + len;
1.23 kristaps 614: p->rmargin = p->maxrmargin;
1.21 kristaps 615: break;
616: default:
617: break;
618: }
1.16 kristaps 619:
1.21 kristaps 620: return(1);
621: }
1.1 kristaps 622:
623:
1.21 kristaps 624: /* ARGSUSED */
625: static void
626: post_TP(DECL_ARGS)
627: {
1.1 kristaps 628:
1.21 kristaps 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:
1.3 kristaps 646: /* ARGSUSED */
1.1 kristaps 647: static int
648: pre_SS(DECL_ARGS)
649: {
650:
1.19 kristaps 651: switch (n->type) {
652: case (MAN_BLOCK):
1.24 kristaps 653: mt->lmargin = INDENT;
1.26 kristaps 654: mt->offset = INDENT;
1.24 kristaps 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);
1.19 kristaps 662: break;
663: case (MAN_HEAD):
1.52 kristaps 664: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 665: p->offset = HALFINDENT;
666: break;
1.24 kristaps 667: case (MAN_BODY):
1.26 kristaps 668: p->offset = mt->offset;
1.24 kristaps 669: break;
1.19 kristaps 670: default:
671: break;
672: }
673:
1.1 kristaps 674: return(1);
675: }
676:
677:
1.3 kristaps 678: /* ARGSUSED */
1.1 kristaps 679: static void
680: post_SS(DECL_ARGS)
681: {
682:
1.19 kristaps 683: switch (n->type) {
684: case (MAN_HEAD):
685: term_newln(p);
686: break;
1.24 kristaps 687: case (MAN_BODY):
688: term_newln(p);
689: break;
1.19 kristaps 690: default:
691: break;
692: }
1.1 kristaps 693: }
694:
695:
1.3 kristaps 696: /* ARGSUSED */
1.1 kristaps 697: static int
698: pre_SH(DECL_ARGS)
699: {
1.22 kristaps 700:
1.19 kristaps 701: switch (n->type) {
702: case (MAN_BLOCK):
1.24 kristaps 703: mt->lmargin = INDENT;
1.26 kristaps 704: mt->offset = INDENT;
1.22 kristaps 705: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 706: if (n->prev && MAN_SH == n->prev->tok)
707: if (NULL == n->prev->body->child)
708: break;
709: term_vspace(p);
710: break;
711: case (MAN_HEAD):
1.52 kristaps 712: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 713: p->offset = 0;
714: break;
715: case (MAN_BODY):
1.26 kristaps 716: p->offset = mt->offset;
1.19 kristaps 717: break;
718: default:
719: break;
720: }
1.1 kristaps 721:
722: return(1);
723: }
724:
725:
1.3 kristaps 726: /* ARGSUSED */
1.1 kristaps 727: static void
728: post_SH(DECL_ARGS)
729: {
730:
1.19 kristaps 731: switch (n->type) {
732: case (MAN_HEAD):
733: term_newln(p);
734: break;
735: case (MAN_BODY):
736: term_newln(p);
737: break;
738: default:
739: break;
740: }
1.1 kristaps 741: }
742:
743:
1.26 kristaps 744: /* ARGSUSED */
745: static int
746: pre_RS(DECL_ARGS)
747: {
748: const struct man_node *nn;
749: int ival;
750:
751: switch (n->type) {
752: case (MAN_BLOCK):
753: term_newln(p);
754: return(1);
755: case (MAN_HEAD):
756: return(0);
757: default:
758: break;
759: }
760:
761: if (NULL == (nn = n->parent->head->child)) {
762: mt->offset = mt->lmargin + INDENT;
763: p->offset = mt->offset;
764: return(1);
765: }
766:
1.45 kristaps 767: if ((ival = a2width(nn)) < 0)
1.26 kristaps 768: return(1);
769:
770: mt->offset = INDENT + (size_t)ival;
771: p->offset = mt->offset;
772:
773: return(1);
774: }
775:
776:
777: /* ARGSUSED */
778: static void
779: post_RS(DECL_ARGS)
780: {
781:
782: switch (n->type) {
783: case (MAN_BLOCK):
784: mt->offset = mt->lmargin = INDENT;
785: break;
786: default:
787: term_newln(p);
788: p->offset = INDENT;
789: break;
790: }
791: }
792:
793:
1.1 kristaps 794: static void
1.45 kristaps 795: print_man_node(DECL_ARGS)
1.1 kristaps 796: {
1.54 kristaps 797: int c;
1.1 kristaps 798:
799: c = 1;
800:
801: switch (n->type) {
802: case(MAN_TEXT):
1.4 kristaps 803: if (0 == *n->string) {
804: term_vspace(p);
1.1 kristaps 805: break;
806: }
1.54 kristaps 807:
1.4 kristaps 808: term_word(p, n->string);
1.52 kristaps 809:
1.19 kristaps 810: /* FIXME: this means that macro lines are munged! */
1.52 kristaps 811:
1.24 kristaps 812: if (MANT_LITERAL & mt->fl) {
1.19 kristaps 813: p->flags |= TERMP_NOSPACE;
814: term_flushln(p);
815: }
1.1 kristaps 816: break;
817: default:
1.56 kristaps 818: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
819: term_fontrepl(p, TERMFONT_NONE);
1.19 kristaps 820: if (termacts[n->tok].pre)
1.24 kristaps 821: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 822: break;
823: }
824:
825: if (c && n->child)
1.52 kristaps 826: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 827:
1.51 kristaps 828: if (MAN_TEXT != n->type) {
1.1 kristaps 829: if (termacts[n->tok].post)
1.24 kristaps 830: (*termacts[n->tok].post)(p, mt, n, m);
1.56 kristaps 831: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
832: term_fontrepl(p, TERMFONT_NONE);
1.51 kristaps 833: }
1.1 kristaps 834: }
835:
836:
837: static void
1.52 kristaps 838: print_man_nodelist(DECL_ARGS)
1.1 kristaps 839: {
1.19 kristaps 840:
1.45 kristaps 841: print_man_node(p, mt, n, m);
1.1 kristaps 842: if ( ! n->next)
843: return;
1.52 kristaps 844: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 845: }
846:
847:
1.31 kristaps 848: static void
1.45 kristaps 849: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1 kristaps 850: {
1.43 kristaps 851: char buf[DATESIZ];
1.1 kristaps 852:
1.52 kristaps 853: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 854:
1.43 kristaps 855: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 856:
857: term_vspace(p);
858:
859: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
860: p->rmargin = p->maxrmargin - strlen(buf);
861: p->offset = 0;
862:
863: if (meta->source)
864: term_word(p, meta->source);
865: if (meta->source)
866: term_word(p, "");
867: term_flushln(p);
868:
869: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
870: p->offset = p->rmargin;
871: p->rmargin = p->maxrmargin;
872: p->flags &= ~TERMP_NOBREAK;
873:
874: term_word(p, buf);
875: term_flushln(p);
876: }
877:
878:
1.31 kristaps 879: static void
1.46 kristaps 880: print_man_head(struct termp *p, const struct man_meta *m)
1.1 kristaps 881: {
1.46 kristaps 882: char buf[BUFSIZ], title[BUFSIZ];
1.57 ! kristaps 883: size_t buflen, titlen;
1.1 kristaps 884:
885: p->rmargin = p->maxrmargin;
886: p->offset = 0;
1.46 kristaps 887: buf[0] = title[0] = '\0';
1.1 kristaps 888:
1.46 kristaps 889: if (m->vol)
890: strlcpy(buf, m->vol, BUFSIZ);
1.57 ! kristaps 891: buflen = strlen(buf);
1.1 kristaps 892:
1.46 kristaps 893: snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
1.57 ! kristaps 894: titlen = strlen(title);
1.1 kristaps 895:
896: p->offset = 0;
1.57 ! kristaps 897: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
! 898: (p->maxrmargin - strlen(buf) + 1) / 2 :
! 899: p->maxrmargin - buflen;
1.1 kristaps 900: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
901:
902: term_word(p, title);
903: term_flushln(p);
904:
905: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
906: p->offset = p->rmargin;
1.57 ! kristaps 907: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
! 908: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 909:
910: term_word(p, buf);
911: term_flushln(p);
912:
913: p->flags &= ~TERMP_NOBREAK;
1.57 ! kristaps 914: if (p->rmargin + titlen <= p->maxrmargin) {
! 915: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
! 916: p->offset = p->rmargin;
! 917: p->rmargin = p->maxrmargin;
! 918: term_word(p, title);
! 919: term_flushln(p);
! 920: }
1.1 kristaps 921:
922: p->rmargin = p->maxrmargin;
923: p->offset = 0;
924: p->flags &= ~TERMP_NOSPACE;
925: }
CVSweb