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