Annotation of mandoc/man_term.c, Revision 1.52
1.52 ! kristaps 1: /* $Id: man_term.c,v 1.51 2009/11/10 12:03:30 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.19 kristaps 107: static void post_i(DECL_ARGS);
1.1 kristaps 108:
1.32 kristaps 109: static const struct termact termacts[MAN_MAX] = {
1.15 kristaps 110: { pre_br, NULL }, /* br */
1.1 kristaps 111: { NULL, NULL }, /* TH */
112: { pre_SH, post_SH }, /* SH */
113: { pre_SS, post_SS }, /* SS */
1.21 kristaps 114: { pre_TP, post_TP }, /* TP */
1.1 kristaps 115: { pre_PP, NULL }, /* LP */
116: { pre_PP, NULL }, /* PP */
117: { pre_PP, NULL }, /* P */
1.22 kristaps 118: { pre_IP, post_IP }, /* IP */
1.20 kristaps 119: { pre_HP, post_HP }, /* HP */
1.1 kristaps 120: { NULL, NULL }, /* SM */
1.52 ! kristaps 121: { pre_B, NULL }, /* SB */
1.3 kristaps 122: { pre_BI, NULL }, /* BI */
1.35 kristaps 123: { pre_BI, NULL }, /* IB */
124: { pre_RB, NULL }, /* BR */
1.3 kristaps 125: { pre_RB, NULL }, /* RB */
1.1 kristaps 126: { NULL, NULL }, /* R */
1.52 ! kristaps 127: { pre_B, NULL }, /* B */
! 128: { pre_I, NULL }, /* I */
1.49 kristaps 129: { pre_RI, NULL }, /* IR */
1.3 kristaps 130: { pre_RI, NULL }, /* RI */
1.27 kristaps 131: { NULL, NULL }, /* na */
1.19 kristaps 132: { pre_I, post_i }, /* i */
133: { pre_sp, NULL }, /* sp */
134: { pre_nf, NULL }, /* nf */
135: { pre_fi, NULL }, /* fi */
1.52 ! kristaps 136: { NULL, NULL }, /* r */
1.25 kristaps 137: { NULL, NULL }, /* RE */
1.26 kristaps 138: { pre_RS, post_RS }, /* RS */
1.29 kristaps 139: { pre_ign, NULL }, /* DT */
140: { pre_ign, NULL }, /* UC */
1.44 kristaps 141: { pre_ign, NULL }, /* PD */
1.1 kristaps 142: };
143:
144:
145:
1.31 kristaps 146: void
1.36 kristaps 147: terminal_man(void *arg, const struct man *man)
1.1 kristaps 148: {
1.36 kristaps 149: struct termp *p;
150: const struct man_node *n;
151: const struct man_meta *m;
152: struct mtermp mt;
153:
154: p = (struct termp *)arg;
155:
156: if (NULL == p->symtab)
157: switch (p->enc) {
158: case (TERMENC_ASCII):
159: p->symtab = chars_init(CHARS_ASCII);
160: break;
161: default:
162: abort();
163: /* NOTREACHED */
164: }
165:
166: n = man_node(man);
167: m = man_meta(man);
1.1 kristaps 168:
1.45 kristaps 169: print_man_head(p, m);
1.1 kristaps 170: p->flags |= TERMP_NOSPACE;
1.19 kristaps 171:
1.24 kristaps 172: mt.fl = 0;
173: mt.lmargin = INDENT;
1.26 kristaps 174: mt.offset = INDENT;
1.24 kristaps 175:
1.36 kristaps 176: if (n->child)
1.52 ! kristaps 177: print_man_nodelist(p, &mt, n->child, m);
1.45 kristaps 178: print_man_foot(p, m);
1.1 kristaps 179: }
180:
181:
1.39 kristaps 182: static int
1.45 kristaps 183: a2height(const struct man_node *n)
1.18 kristaps 184: {
1.40 kristaps 185: struct roffsu su;
1.18 kristaps 186:
1.39 kristaps 187: assert(MAN_TEXT == n->type);
188: assert(n->string);
1.40 kristaps 189: if ( ! a2roffsu(n->string, &su, SCALE_VS))
190: SCALE_VS_INIT(&su, strlen(n->string));
1.18 kristaps 191:
1.41 kristaps 192: return((int)term_vspan(&su));
1.18 kristaps 193: }
194:
195:
196: static int
1.45 kristaps 197: a2width(const struct man_node *n)
1.38 kristaps 198: {
1.40 kristaps 199: struct roffsu su;
1.38 kristaps 200:
1.39 kristaps 201: assert(MAN_TEXT == n->type);
202: assert(n->string);
1.40 kristaps 203: if ( ! a2roffsu(n->string, &su, SCALE_BU))
1.41 kristaps 204: return(-1);
1.40 kristaps 205:
1.41 kristaps 206: return((int)term_hspan(&su));
1.38 kristaps 207: }
208:
209:
1.39 kristaps 210: static void
211: print_bvspace(struct termp *p, const struct man_node *n)
1.18 kristaps 212: {
1.39 kristaps 213: term_newln(p);
1.18 kristaps 214:
1.39 kristaps 215: if (NULL == n->prev)
216: return;
1.18 kristaps 217:
1.39 kristaps 218: if (MAN_SS == n->prev->tok)
219: return;
220: if (MAN_SH == n->prev->tok)
221: return;
1.18 kristaps 222:
1.39 kristaps 223: term_vspace(p);
1.18 kristaps 224: }
225:
226:
1.3 kristaps 227: /* ARGSUSED */
1.1 kristaps 228: static int
1.29 kristaps 229: pre_ign(DECL_ARGS)
230: {
231:
232: return(0);
233: }
234:
235:
236: /* ARGSUSED */
237: static int
1.1 kristaps 238: pre_I(DECL_ARGS)
239: {
240:
1.52 ! kristaps 241: term_fontrepl(p, TERMFONT_UNDER);
1.19 kristaps 242: return(1);
243: }
244:
245:
246: /* ARGSUSED */
247: static void
248: post_i(DECL_ARGS)
249: {
250:
1.52 ! kristaps 251: /* FIXME */
! 252: /*if (n->nchild)
! 253: p->under--;*/
1.1 kristaps 254: }
255:
256:
1.3 kristaps 257: /* ARGSUSED */
258: static int
1.19 kristaps 259: pre_fi(DECL_ARGS)
260: {
261:
1.24 kristaps 262: mt->fl &= ~MANT_LITERAL;
1.19 kristaps 263: return(1);
264: }
265:
266:
267: /* ARGSUSED */
268: static int
269: pre_nf(DECL_ARGS)
270: {
271:
272: term_newln(p);
1.24 kristaps 273: mt->fl |= MANT_LITERAL;
1.19 kristaps 274: return(1);
275: }
276:
277:
278: /* ARGSUSED */
279: static int
1.35 kristaps 280: pre_RB(DECL_ARGS)
1.3 kristaps 281: {
282: const struct man_node *nn;
283: int i;
284:
285: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 286: if (i % 2 && MAN_RB == n->tok)
1.52 ! kristaps 287: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 288: else if ( ! (i % 2) && MAN_RB != n->tok)
1.52 ! kristaps 289: term_fontrepl(p, TERMFONT_BOLD);
! 290: else
! 291: term_fontrepl(p, TERMFONT_NONE);
1.35 kristaps 292:
1.4 kristaps 293: if (i > 0)
294: p->flags |= TERMP_NOSPACE;
1.35 kristaps 295:
1.45 kristaps 296: print_man_node(p, mt, nn, m);
1.3 kristaps 297: }
298: return(0);
299: }
300:
301:
302: /* ARGSUSED */
303: static int
304: pre_RI(DECL_ARGS)
305: {
306: const struct man_node *nn;
307: int i;
308:
309: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.49 kristaps 310: if (i % 2 && MAN_RI == n->tok)
1.52 ! kristaps 311: term_fontrepl(p, TERMFONT_UNDER);
1.49 kristaps 312: else if ( ! (i % 2) && MAN_RI != n->tok)
1.52 ! kristaps 313: term_fontrepl(p, TERMFONT_UNDER);
! 314: else
! 315: term_fontrepl(p, TERMFONT_NONE);
1.49 kristaps 316:
1.4 kristaps 317: if (i > 0)
318: p->flags |= TERMP_NOSPACE;
1.52 ! kristaps 319:
1.45 kristaps 320: print_man_node(p, mt, nn, m);
1.3 kristaps 321: }
322: return(0);
323: }
324:
325:
326: /* ARGSUSED */
327: static int
328: pre_BI(DECL_ARGS)
329: {
1.35 kristaps 330: const struct man_node *nn;
331: int i;
1.3 kristaps 332:
333: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 334: if (i % 2 && MAN_BI == n->tok)
1.52 ! kristaps 335: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 336: else if (i % 2)
1.52 ! kristaps 337: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 338: else if (MAN_BI == n->tok)
1.52 ! kristaps 339: term_fontrepl(p, TERMFONT_BOLD);
1.30 kristaps 340: else
1.52 ! kristaps 341: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 342:
343: if (i)
1.4 kristaps 344: p->flags |= TERMP_NOSPACE;
1.52 ! kristaps 345:
1.45 kristaps 346: print_man_node(p, mt, nn, m);
1.3 kristaps 347: }
348: return(0);
349: }
350:
351:
352: /* ARGSUSED */
1.1 kristaps 353: static int
354: pre_B(DECL_ARGS)
355: {
356:
1.52 ! kristaps 357: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 358: return(1);
359: }
360:
361:
1.3 kristaps 362: /* ARGSUSED */
1.1 kristaps 363: static int
1.19 kristaps 364: pre_sp(DECL_ARGS)
365: {
366: int i, len;
367:
1.45 kristaps 368: len = n->child ? a2height(n->child) : 1;
1.38 kristaps 369:
1.19 kristaps 370: if (0 == len)
371: term_newln(p);
372: for (i = 0; i < len; i++)
373: term_vspace(p);
374:
375: return(0);
376: }
377:
378:
379: /* ARGSUSED */
380: static int
1.15 kristaps 381: pre_br(DECL_ARGS)
382: {
383:
384: term_newln(p);
385: return(0);
386: }
387:
388:
389: /* ARGSUSED */
390: static int
1.19 kristaps 391: pre_HP(DECL_ARGS)
392: {
1.24 kristaps 393: size_t len;
394: int ival;
395: const struct man_node *nn;
1.19 kristaps 396:
1.20 kristaps 397: switch (n->type) {
398: case (MAN_BLOCK):
1.39 kristaps 399: print_bvspace(p, n);
1.24 kristaps 400: return(1);
1.20 kristaps 401: case (MAN_BODY):
402: p->flags |= TERMP_NOBREAK;
403: p->flags |= TERMP_TWOSPACE;
404: break;
405: default:
406: return(0);
407: }
408:
1.26 kristaps 409: len = mt->lmargin;
1.24 kristaps 410: ival = -1;
411:
412: /* Calculate offset. */
413:
1.39 kristaps 414: if (NULL != (nn = n->parent->head->child))
1.45 kristaps 415: if ((ival = a2width(nn)) >= 0)
1.24 kristaps 416: len = (size_t)ival;
417:
418: if (0 == len)
419: len = 1;
420:
1.26 kristaps 421: p->offset = mt->offset;
422: p->rmargin = mt->offset + len;
1.24 kristaps 423:
424: if (ival >= 0)
1.26 kristaps 425: mt->lmargin = (size_t)ival;
1.24 kristaps 426:
1.19 kristaps 427: return(1);
428: }
429:
430:
431: /* ARGSUSED */
1.20 kristaps 432: static void
433: post_HP(DECL_ARGS)
434: {
435:
436: switch (n->type) {
1.24 kristaps 437: case (MAN_BLOCK):
438: term_flushln(p);
439: break;
1.20 kristaps 440: case (MAN_BODY):
441: term_flushln(p);
442: p->flags &= ~TERMP_NOBREAK;
443: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 444: p->offset = mt->offset;
1.20 kristaps 445: p->rmargin = p->maxrmargin;
446: break;
447: default:
448: break;
449: }
450: }
451:
452:
453: /* ARGSUSED */
1.19 kristaps 454: static int
1.1 kristaps 455: pre_PP(DECL_ARGS)
456: {
457:
1.19 kristaps 458: switch (n->type) {
459: case (MAN_BLOCK):
1.24 kristaps 460: mt->lmargin = INDENT;
1.39 kristaps 461: print_bvspace(p, n);
1.19 kristaps 462: break;
463: default:
1.26 kristaps 464: p->offset = mt->offset;
1.19 kristaps 465: break;
466: }
467:
468: return(1);
1.1 kristaps 469: }
470:
471:
1.3 kristaps 472: /* ARGSUSED */
1.1 kristaps 473: static int
1.4 kristaps 474: pre_IP(DECL_ARGS)
475: {
1.22 kristaps 476: const struct man_node *nn;
477: size_t len;
478: int ival;
1.18 kristaps 479:
1.22 kristaps 480: switch (n->type) {
481: case (MAN_BODY):
482: p->flags |= TERMP_NOLPAD;
483: p->flags |= TERMP_NOSPACE;
484: break;
485: case (MAN_HEAD):
486: p->flags |= TERMP_NOBREAK;
487: p->flags |= TERMP_TWOSPACE;
488: break;
1.23 kristaps 489: case (MAN_BLOCK):
1.39 kristaps 490: print_bvspace(p, n);
1.23 kristaps 491: /* FALLTHROUGH */
1.22 kristaps 492: default:
493: return(1);
494: }
1.18 kristaps 495:
1.26 kristaps 496: len = mt->lmargin;
1.22 kristaps 497: ival = -1;
1.4 kristaps 498:
1.22 kristaps 499: /* Calculate offset. */
1.4 kristaps 500:
1.22 kristaps 501: if (NULL != (nn = n->parent->head->child))
502: if (NULL != (nn = nn->next)) {
503: for ( ; nn->next; nn = nn->next)
504: /* Do nothing. */ ;
1.45 kristaps 505: if ((ival = a2width(nn)) >= 0)
1.22 kristaps 506: len = (size_t)ival;
507: }
1.4 kristaps 508:
1.22 kristaps 509: switch (n->type) {
510: case (MAN_HEAD):
1.23 kristaps 511: /* Handle zero-width lengths. */
512: if (0 == len)
513: len = 1;
514:
1.26 kristaps 515: p->offset = mt->offset;
516: p->rmargin = mt->offset + len;
1.22 kristaps 517: if (ival < 0)
518: break;
1.18 kristaps 519:
1.24 kristaps 520: /* Set the saved left-margin. */
1.26 kristaps 521: mt->lmargin = (size_t)ival;
1.24 kristaps 522:
1.22 kristaps 523: /* Don't print the length value. */
524: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 525: print_man_node(p, mt, nn, m);
1.22 kristaps 526: return(0);
1.23 kristaps 527: case (MAN_BODY):
1.26 kristaps 528: p->offset = mt->offset + len;
1.23 kristaps 529: p->rmargin = p->maxrmargin;
530: break;
1.22 kristaps 531: default:
532: break;
1.18 kristaps 533: }
534:
1.22 kristaps 535: return(1);
536: }
1.18 kristaps 537:
538:
1.22 kristaps 539: /* ARGSUSED */
540: static void
541: post_IP(DECL_ARGS)
542: {
1.4 kristaps 543:
1.22 kristaps 544: switch (n->type) {
545: case (MAN_HEAD):
546: term_flushln(p);
547: p->flags &= ~TERMP_NOBREAK;
548: p->flags &= ~TERMP_TWOSPACE;
549: p->rmargin = p->maxrmargin;
550: break;
551: case (MAN_BODY):
552: term_flushln(p);
553: p->flags &= ~TERMP_NOLPAD;
554: break;
555: default:
556: break;
557: }
1.4 kristaps 558: }
559:
560:
561: /* ARGSUSED */
562: static int
1.1 kristaps 563: pre_TP(DECL_ARGS)
564: {
1.23 kristaps 565: const struct man_node *nn;
566: size_t len;
567: int ival;
1.1 kristaps 568:
1.21 kristaps 569: switch (n->type) {
570: case (MAN_HEAD):
571: p->flags |= TERMP_NOBREAK;
572: p->flags |= TERMP_TWOSPACE;
573: break;
574: case (MAN_BODY):
575: p->flags |= TERMP_NOLPAD;
576: p->flags |= TERMP_NOSPACE;
1.23 kristaps 577: break;
578: case (MAN_BLOCK):
1.39 kristaps 579: print_bvspace(p, n);
1.23 kristaps 580: /* FALLTHROUGH */
581: default:
582: return(1);
583: }
584:
1.24 kristaps 585: len = (size_t)mt->lmargin;
1.23 kristaps 586: ival = -1;
587:
588: /* Calculate offset. */
589:
590: if (NULL != (nn = n->parent->head->child))
1.39 kristaps 591: if (NULL != nn->next)
1.45 kristaps 592: if ((ival = a2width(nn)) >= 0)
1.23 kristaps 593: len = (size_t)ival;
594:
595: switch (n->type) {
596: case (MAN_HEAD):
597: /* Handle zero-length properly. */
598: if (0 == len)
599: len = 1;
600:
1.26 kristaps 601: p->offset = mt->offset;
602: p->rmargin = mt->offset + len;
1.23 kristaps 603:
604: /* Don't print same-line elements. */
605: for (nn = n->child; nn; nn = nn->next)
606: if (nn->line > n->line)
1.45 kristaps 607: print_man_node(p, mt, nn, m);
1.24 kristaps 608:
609: if (ival >= 0)
1.26 kristaps 610: mt->lmargin = (size_t)ival;
1.24 kristaps 611:
1.23 kristaps 612: return(0);
613: case (MAN_BODY):
1.26 kristaps 614: p->offset = mt->offset + len;
1.23 kristaps 615: p->rmargin = p->maxrmargin;
1.21 kristaps 616: break;
617: default:
618: break;
619: }
1.16 kristaps 620:
1.21 kristaps 621: return(1);
622: }
1.1 kristaps 623:
624:
1.21 kristaps 625: /* ARGSUSED */
626: static void
627: post_TP(DECL_ARGS)
628: {
1.1 kristaps 629:
1.21 kristaps 630: switch (n->type) {
631: case (MAN_HEAD):
632: term_flushln(p);
633: p->flags &= ~TERMP_NOBREAK;
634: p->flags &= ~TERMP_TWOSPACE;
635: p->rmargin = p->maxrmargin;
636: break;
637: case (MAN_BODY):
638: term_flushln(p);
639: p->flags &= ~TERMP_NOLPAD;
640: break;
641: default:
642: break;
643: }
1.1 kristaps 644: }
645:
646:
1.3 kristaps 647: /* ARGSUSED */
1.1 kristaps 648: static int
649: pre_SS(DECL_ARGS)
650: {
651:
1.19 kristaps 652: switch (n->type) {
653: case (MAN_BLOCK):
1.24 kristaps 654: mt->lmargin = INDENT;
1.26 kristaps 655: mt->offset = INDENT;
1.24 kristaps 656: /* If following a prior empty `SS', no vspace. */
657: if (n->prev && MAN_SS == n->prev->tok)
658: if (NULL == n->prev->body->child)
659: break;
660: if (NULL == n->prev)
661: break;
662: term_vspace(p);
1.19 kristaps 663: break;
664: case (MAN_HEAD):
1.52 ! kristaps 665: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 666: p->offset = HALFINDENT;
667: break;
1.24 kristaps 668: case (MAN_BODY):
1.26 kristaps 669: p->offset = mt->offset;
1.24 kristaps 670: break;
1.19 kristaps 671: default:
672: break;
673: }
674:
1.1 kristaps 675: return(1);
676: }
677:
678:
1.3 kristaps 679: /* ARGSUSED */
1.1 kristaps 680: static void
681: post_SS(DECL_ARGS)
682: {
683:
1.19 kristaps 684: switch (n->type) {
685: case (MAN_HEAD):
686: term_newln(p);
687: break;
1.24 kristaps 688: case (MAN_BODY):
689: term_newln(p);
690: break;
1.19 kristaps 691: default:
692: break;
693: }
1.1 kristaps 694: }
695:
696:
1.3 kristaps 697: /* ARGSUSED */
1.1 kristaps 698: static int
699: pre_SH(DECL_ARGS)
700: {
1.22 kristaps 701:
1.19 kristaps 702: switch (n->type) {
703: case (MAN_BLOCK):
1.24 kristaps 704: mt->lmargin = INDENT;
1.26 kristaps 705: mt->offset = INDENT;
1.22 kristaps 706: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 707: if (n->prev && MAN_SH == n->prev->tok)
708: if (NULL == n->prev->body->child)
709: break;
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;
786: break;
787: default:
788: term_newln(p);
789: p->offset = INDENT;
790: break;
791: }
792: }
793:
794:
1.1 kristaps 795: static void
1.45 kristaps 796: print_man_node(DECL_ARGS)
1.1 kristaps 797: {
1.4 kristaps 798: int c, sz;
1.1 kristaps 799:
800: c = 1;
801:
802: switch (n->type) {
803: case(MAN_TEXT):
1.4 kristaps 804: if (0 == *n->string) {
805: term_vspace(p);
1.1 kristaps 806: break;
807: }
1.4 kristaps 808: /*
809: * Note! This is hacky. Here, we recognise the `\c'
810: * escape embedded in so many -man pages. It's supposed
811: * to remove the subsequent space, so we mark NOSPACE if
812: * it's encountered in the string.
813: */
814: sz = (int)strlen(n->string);
815: term_word(p, n->string);
816: if (sz >= 2 && n->string[sz - 1] == 'c' &&
817: n->string[sz - 2] == '\\')
818: p->flags |= TERMP_NOSPACE;
1.52 ! kristaps 819:
1.19 kristaps 820: /* FIXME: this means that macro lines are munged! */
1.52 ! kristaps 821:
1.24 kristaps 822: if (MANT_LITERAL & mt->fl) {
1.19 kristaps 823: p->flags |= TERMP_NOSPACE;
824: term_flushln(p);
825: }
1.1 kristaps 826: break;
827: default:
1.52 ! kristaps 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.52 ! kristaps 840: term_fontrepl(p, TERMFONT_NONE);
1.51 kristaps 841: }
1.1 kristaps 842: }
843:
844:
845: static void
1.52 ! kristaps 846: print_man_nodelist(DECL_ARGS)
1.1 kristaps 847: {
1.19 kristaps 848:
1.45 kristaps 849: print_man_node(p, mt, n, m);
1.1 kristaps 850: if ( ! n->next)
851: return;
1.52 ! kristaps 852: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 853: }
854:
855:
1.31 kristaps 856: static void
1.45 kristaps 857: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1 kristaps 858: {
1.43 kristaps 859: char buf[DATESIZ];
1.1 kristaps 860:
1.52 ! kristaps 861: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 862:
1.43 kristaps 863: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 864:
865: term_vspace(p);
866:
867: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
868: p->rmargin = p->maxrmargin - strlen(buf);
869: p->offset = 0;
870:
871: if (meta->source)
872: term_word(p, meta->source);
873: if (meta->source)
874: term_word(p, "");
875: term_flushln(p);
876:
877: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
878: p->offset = p->rmargin;
879: p->rmargin = p->maxrmargin;
880: p->flags &= ~TERMP_NOBREAK;
881:
882: term_word(p, buf);
883: term_flushln(p);
884: }
885:
886:
1.31 kristaps 887: static void
1.46 kristaps 888: print_man_head(struct termp *p, const struct man_meta *m)
1.1 kristaps 889: {
1.46 kristaps 890: char buf[BUFSIZ], title[BUFSIZ];
1.1 kristaps 891:
892: p->rmargin = p->maxrmargin;
893: p->offset = 0;
1.46 kristaps 894: buf[0] = title[0] = '\0';
1.1 kristaps 895:
1.46 kristaps 896: if (m->vol)
897: strlcpy(buf, m->vol, BUFSIZ);
1.1 kristaps 898:
1.46 kristaps 899: snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
1.1 kristaps 900:
901: p->offset = 0;
1.10 kristaps 902: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 903: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
904:
905: term_word(p, title);
906: term_flushln(p);
907:
908: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
909: p->offset = p->rmargin;
910: p->rmargin = p->maxrmargin - strlen(title);
911:
912: term_word(p, buf);
913: term_flushln(p);
914:
915: p->offset = p->rmargin;
916: p->rmargin = p->maxrmargin;
917: p->flags &= ~TERMP_NOBREAK;
918: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
919:
920: term_word(p, title);
921: term_flushln(p);
922:
923: p->rmargin = p->maxrmargin;
924: p->offset = 0;
925: p->flags &= ~TERMP_NOSPACE;
926: }
CVSweb