Annotation of mandoc/man_term.c, Revision 1.38
1.38 ! kristaps 1: /* $Id: man_term.c,v 1.37 2009/10/18 11:14:04 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.31 kristaps 21: #include <err.h>
1.1 kristaps 22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <string.h>
25:
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.37 kristaps 30: #include "out.h"
1.1 kristaps 31:
1.18 kristaps 32: #define INDENT 7
33: #define HALFINDENT 3
34:
1.24 kristaps 35: struct mtermp {
36: int fl;
1.19 kristaps 37: #define MANT_LITERAL (1 << 0)
1.26 kristaps 38: /*
39: * Default amount to indent the left margin after leading text
40: * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
41: * indent). This needs to be saved because `HP' and so on, if
42: * not having a specified value, must default.
43: *
44: * Note that this is the indentation AFTER the left offset, so
45: * the total offset is usually offset + lmargin.
46: */
47: size_t lmargin;
48: /*
49: * The default offset, i.e., the amount between any text and the
50: * page boundary.
51: */
52: size_t offset;
1.24 kristaps 53: };
1.19 kristaps 54:
1.1 kristaps 55: #define DECL_ARGS struct termp *p, \
1.24 kristaps 56: struct mtermp *mt, \
1.1 kristaps 57: const struct man_node *n, \
58: const struct man_meta *m
59:
60: struct termact {
61: int (*pre)(DECL_ARGS);
62: void (*post)(DECL_ARGS);
63: };
64:
65: static int pre_B(DECL_ARGS);
1.3 kristaps 66: static int pre_BI(DECL_ARGS);
1.19 kristaps 67: static int pre_HP(DECL_ARGS);
1.1 kristaps 68: static int pre_I(DECL_ARGS);
1.4 kristaps 69: static int pre_IP(DECL_ARGS);
1.3 kristaps 70: static int pre_IR(DECL_ARGS);
1.1 kristaps 71: static int pre_PP(DECL_ARGS);
1.3 kristaps 72: static int pre_RB(DECL_ARGS);
73: static int pre_RI(DECL_ARGS);
1.26 kristaps 74: static int pre_RS(DECL_ARGS);
1.1 kristaps 75: static int pre_SH(DECL_ARGS);
76: static int pre_SS(DECL_ARGS);
77: static int pre_TP(DECL_ARGS);
1.19 kristaps 78: static int pre_br(DECL_ARGS);
79: static int pre_fi(DECL_ARGS);
1.29 kristaps 80: static int pre_ign(DECL_ARGS);
1.19 kristaps 81: static int pre_nf(DECL_ARGS);
82: static int pre_r(DECL_ARGS);
83: static int pre_sp(DECL_ARGS);
1.1 kristaps 84:
85: static void post_B(DECL_ARGS);
86: static void post_I(DECL_ARGS);
1.22 kristaps 87: static void post_IP(DECL_ARGS);
1.20 kristaps 88: static void post_HP(DECL_ARGS);
1.26 kristaps 89: static void post_RS(DECL_ARGS);
1.1 kristaps 90: static void post_SH(DECL_ARGS);
91: static void post_SS(DECL_ARGS);
1.21 kristaps 92: static void post_TP(DECL_ARGS);
1.19 kristaps 93: static void post_i(DECL_ARGS);
1.1 kristaps 94:
1.32 kristaps 95: static const struct termact termacts[MAN_MAX] = {
1.15 kristaps 96: { pre_br, NULL }, /* br */
1.1 kristaps 97: { NULL, NULL }, /* TH */
98: { pre_SH, post_SH }, /* SH */
99: { pre_SS, post_SS }, /* SS */
1.21 kristaps 100: { pre_TP, post_TP }, /* TP */
1.1 kristaps 101: { pre_PP, NULL }, /* LP */
102: { pre_PP, NULL }, /* PP */
103: { pre_PP, NULL }, /* P */
1.22 kristaps 104: { pre_IP, post_IP }, /* IP */
1.20 kristaps 105: { pre_HP, post_HP }, /* HP */
1.1 kristaps 106: { NULL, NULL }, /* SM */
107: { pre_B, post_B }, /* SB */
1.3 kristaps 108: { pre_BI, NULL }, /* BI */
1.35 kristaps 109: { pre_BI, NULL }, /* IB */
110: { pre_RB, NULL }, /* BR */
1.3 kristaps 111: { pre_RB, NULL }, /* RB */
1.1 kristaps 112: { NULL, NULL }, /* R */
113: { pre_B, post_B }, /* B */
114: { pre_I, post_I }, /* I */
1.3 kristaps 115: { pre_IR, NULL }, /* IR */
116: { pre_RI, NULL }, /* RI */
1.27 kristaps 117: { NULL, NULL }, /* na */
1.19 kristaps 118: { pre_I, post_i }, /* i */
119: { pre_sp, NULL }, /* sp */
120: { pre_nf, NULL }, /* nf */
121: { pre_fi, NULL }, /* fi */
122: { pre_r, NULL }, /* r */
1.25 kristaps 123: { NULL, NULL }, /* RE */
1.26 kristaps 124: { pre_RS, post_RS }, /* RS */
1.29 kristaps 125: { pre_ign, NULL }, /* DT */
126: { pre_ign, NULL }, /* UC */
1.1 kristaps 127: };
128:
1.24 kristaps 129: #ifdef __linux__
130: extern size_t strlcpy(char *, const char *, size_t);
131: extern size_t strlcat(char *, const char *, size_t);
132: #endif
133:
1.31 kristaps 134: static void print_head(struct termp *,
1.1 kristaps 135: const struct man_meta *);
136: static void print_body(DECL_ARGS);
137: static void print_node(DECL_ARGS);
1.31 kristaps 138: static void print_foot(struct termp *,
1.1 kristaps 139: const struct man_meta *);
1.18 kristaps 140: static void fmt_block_vspace(struct termp *,
141: const struct man_node *);
1.37 kristaps 142: static int a2width(const char *);
1.38 ! kristaps 143: static int a2height(const char *);
1.1 kristaps 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.36 kristaps 169: print_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)
177: print_body(p, &mt, n->child, m);
178: print_foot(p, m);
1.1 kristaps 179: }
180:
181:
1.18 kristaps 182: static void
183: fmt_block_vspace(struct termp *p, const struct man_node *n)
184: {
185: term_newln(p);
186:
187: if (NULL == n->prev)
188: return;
189:
190: if (MAN_SS == n->prev->tok)
191: return;
192: if (MAN_SH == n->prev->tok)
193: return;
194:
195: term_vspace(p);
196: }
197:
198:
199: static int
1.38 ! kristaps 200: a2height(const char *p)
! 201: {
! 202: struct roffsu su;
! 203: double r;
! 204:
! 205: if ( ! a2roffsu(p, &su))
! 206: return(1);
! 207:
! 208: switch (su.unit) {
! 209: case (SCALE_CM):
! 210: r = su.scale * 2;
! 211: break;
! 212: case (SCALE_IN):
! 213: r = su.scale * 6;
! 214: break;
! 215: case (SCALE_PC):
! 216: r = su.scale;
! 217: break;
! 218: case (SCALE_PT):
! 219: r = su.scale / 8;
! 220: break;
! 221: case (SCALE_MM):
! 222: r = su.scale / 1000;
! 223: break;
! 224: case (SCALE_VS):
! 225: r = su.scale;
! 226: break;
! 227: default:
! 228: r = su.scale - 1;
! 229: break;
! 230: }
! 231:
! 232: if (r < 0.0)
! 233: r = 0.0;
! 234: return(/* LINTED */(int)
! 235: r);
! 236: }
! 237:
! 238:
! 239: static int
1.37 kristaps 240: a2width(const char *p)
1.18 kristaps 241: {
1.37 kristaps 242: struct roffsu su;
243: double r;
1.18 kristaps 244:
1.37 kristaps 245: if ( ! a2roffsu(p, &su))
1.18 kristaps 246: return(-1);
247:
1.37 kristaps 248: switch (su.unit) {
249: case (SCALE_CM):
250: r = 4 * su.scale;
251: break;
252: case (SCALE_IN):
253: r = 10 * su.scale;
254: break;
255: case (SCALE_PC):
256: r = 2 * su.scale;
257: break;
258: case (SCALE_PT):
259: r = (su.scale / 10) + 1;
260: break;
261: case (SCALE_MM):
262: r = su.scale / 1000;
263: break;
264: case (SCALE_VS):
265: r = su.scale * 2 - 1;
266: break;
267: default:
268: r = su.scale + 1;
269: break;
270: }
1.18 kristaps 271:
1.37 kristaps 272: if (r < 0.0)
273: r = 0.0;
274: return((int)/* LINTED */
275: r);
1.18 kristaps 276: }
277:
278:
1.3 kristaps 279: /* ARGSUSED */
1.1 kristaps 280: static int
1.29 kristaps 281: pre_ign(DECL_ARGS)
282: {
283:
284: return(0);
285: }
286:
287:
288: /* ARGSUSED */
289: static int
1.1 kristaps 290: pre_I(DECL_ARGS)
291: {
292:
1.30 kristaps 293: p->under++;
1.1 kristaps 294: return(1);
295: }
296:
297:
1.3 kristaps 298: /* ARGSUSED */
1.19 kristaps 299: static int
300: pre_r(DECL_ARGS)
301: {
302:
1.30 kristaps 303: p->bold = p->under = 0;
1.19 kristaps 304: return(1);
305: }
306:
307:
308: /* ARGSUSED */
309: static void
310: post_i(DECL_ARGS)
311: {
312:
313: if (n->nchild)
1.30 kristaps 314: p->under--;
1.19 kristaps 315: }
316:
317:
318: /* ARGSUSED */
1.1 kristaps 319: static void
320: post_I(DECL_ARGS)
321: {
322:
1.30 kristaps 323: p->under--;
1.1 kristaps 324: }
325:
326:
1.3 kristaps 327: /* ARGSUSED */
328: static int
1.19 kristaps 329: pre_fi(DECL_ARGS)
330: {
331:
1.24 kristaps 332: mt->fl &= ~MANT_LITERAL;
1.19 kristaps 333: return(1);
334: }
335:
336:
337: /* ARGSUSED */
338: static int
339: pre_nf(DECL_ARGS)
340: {
341:
342: term_newln(p);
1.24 kristaps 343: mt->fl |= MANT_LITERAL;
1.19 kristaps 344: return(1);
345: }
346:
347:
348: /* ARGSUSED */
349: static int
1.3 kristaps 350: pre_IR(DECL_ARGS)
351: {
352: const struct man_node *nn;
353: int i;
354:
355: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
356: if ( ! (i % 2))
1.30 kristaps 357: p->under++;
1.4 kristaps 358: if (i > 0)
359: p->flags |= TERMP_NOSPACE;
1.24 kristaps 360: print_node(p, mt, nn, m);
1.3 kristaps 361: if ( ! (i % 2))
1.30 kristaps 362: p->under--;
1.3 kristaps 363: }
364: return(0);
365: }
366:
367:
368: /* ARGSUSED */
369: static int
1.35 kristaps 370: pre_RB(DECL_ARGS)
1.3 kristaps 371: {
372: const struct man_node *nn;
373: int i;
374:
375: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 376: if (i % 2 && MAN_RB == n->tok)
377: p->bold++;
378: else if ( ! (i % 2) && MAN_RB != n->tok)
1.30 kristaps 379: p->bold++;
1.35 kristaps 380:
1.4 kristaps 381: if (i > 0)
382: p->flags |= TERMP_NOSPACE;
1.35 kristaps 383:
1.24 kristaps 384: print_node(p, mt, nn, m);
1.35 kristaps 385:
386: if (i % 2 && MAN_RB == n->tok)
1.30 kristaps 387: p->bold--;
1.35 kristaps 388: else if ( ! (i % 2) && MAN_RB != n->tok)
1.30 kristaps 389: p->bold--;
1.3 kristaps 390: }
391: return(0);
392: }
393:
394:
395: /* ARGSUSED */
396: static int
397: pre_RI(DECL_ARGS)
398: {
399: const struct man_node *nn;
400: int i;
401:
402: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
403: if ( ! (i % 2))
1.30 kristaps 404: p->under++;
1.4 kristaps 405: if (i > 0)
406: p->flags |= TERMP_NOSPACE;
1.24 kristaps 407: print_node(p, mt, nn, m);
1.3 kristaps 408: if ( ! (i % 2))
1.30 kristaps 409: p->under--;
1.3 kristaps 410: }
411: return(0);
412: }
413:
414:
415: /* ARGSUSED */
416: static int
417: pre_BI(DECL_ARGS)
418: {
1.35 kristaps 419: const struct man_node *nn;
420: int i;
1.3 kristaps 421:
422: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 423: if (i % 2 && MAN_BI == n->tok)
1.30 kristaps 424: p->under++;
1.35 kristaps 425: else if (i % 2)
426: p->bold++;
427: else if (MAN_BI == n->tok)
428: p->bold++;
1.30 kristaps 429: else
1.35 kristaps 430: p->under++;
431:
432: if (i)
1.4 kristaps 433: p->flags |= TERMP_NOSPACE;
1.24 kristaps 434: print_node(p, mt, nn, m);
1.35 kristaps 435:
436: if (i % 2 && MAN_BI == n->tok)
1.30 kristaps 437: p->under--;
1.35 kristaps 438: else if (i % 2)
439: p->bold--;
440: else if (MAN_BI == n->tok)
441: p->bold--;
1.30 kristaps 442: else
1.35 kristaps 443: p->under--;
1.3 kristaps 444: }
445: return(0);
446: }
447:
448:
449: /* ARGSUSED */
1.1 kristaps 450: static int
451: pre_B(DECL_ARGS)
452: {
453:
1.30 kristaps 454: p->bold++;
1.1 kristaps 455: return(1);
456: }
457:
458:
1.3 kristaps 459: /* ARGSUSED */
1.1 kristaps 460: static void
461: post_B(DECL_ARGS)
462: {
463:
1.30 kristaps 464: p->bold--;
1.1 kristaps 465: }
466:
467:
1.3 kristaps 468: /* ARGSUSED */
1.1 kristaps 469: static int
1.19 kristaps 470: pre_sp(DECL_ARGS)
471: {
472: int i, len;
473:
474: if (NULL == n->child) {
475: term_vspace(p);
476: return(0);
477: }
478:
1.38 ! kristaps 479: assert(MAN_TEXT == n->child->type);
! 480: len = a2height(n->child->string);
! 481:
1.19 kristaps 482: if (0 == len)
483: term_newln(p);
484: for (i = 0; i < len; i++)
485: term_vspace(p);
486:
487: return(0);
488: }
489:
490:
491: /* ARGSUSED */
492: static int
1.15 kristaps 493: pre_br(DECL_ARGS)
494: {
495:
496: term_newln(p);
497: return(0);
498: }
499:
500:
501: /* ARGSUSED */
502: static int
1.19 kristaps 503: pre_HP(DECL_ARGS)
504: {
1.24 kristaps 505: size_t len;
506: int ival;
507: const struct man_node *nn;
1.19 kristaps 508:
1.20 kristaps 509: switch (n->type) {
510: case (MAN_BLOCK):
511: fmt_block_vspace(p, n);
1.24 kristaps 512: return(1);
1.20 kristaps 513: case (MAN_BODY):
514: p->flags |= TERMP_NOBREAK;
515: p->flags |= TERMP_TWOSPACE;
516: break;
517: default:
518: return(0);
519: }
520:
1.26 kristaps 521: len = mt->lmargin;
1.24 kristaps 522: ival = -1;
523:
524: /* Calculate offset. */
525:
1.37 kristaps 526: if (NULL != (nn = n->parent->head->child)) {
527: assert(MAN_TEXT == nn->type);
528: if ((ival = a2width(nn->string)) >= 0)
1.24 kristaps 529: len = (size_t)ival;
1.37 kristaps 530: }
1.24 kristaps 531:
532: if (0 == len)
533: len = 1;
534:
1.26 kristaps 535: p->offset = mt->offset;
536: p->rmargin = mt->offset + len;
1.24 kristaps 537:
538: if (ival >= 0)
1.26 kristaps 539: mt->lmargin = (size_t)ival;
1.24 kristaps 540:
1.19 kristaps 541: return(1);
542: }
543:
544:
545: /* ARGSUSED */
1.20 kristaps 546: static void
547: post_HP(DECL_ARGS)
548: {
549:
550: switch (n->type) {
1.24 kristaps 551: case (MAN_BLOCK):
552: term_flushln(p);
553: break;
1.20 kristaps 554: case (MAN_BODY):
555: term_flushln(p);
556: p->flags &= ~TERMP_NOBREAK;
557: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 558: p->offset = mt->offset;
1.20 kristaps 559: p->rmargin = p->maxrmargin;
560: break;
561: default:
562: break;
563: }
564: }
565:
566:
567: /* ARGSUSED */
1.19 kristaps 568: static int
1.1 kristaps 569: pre_PP(DECL_ARGS)
570: {
571:
1.19 kristaps 572: switch (n->type) {
573: case (MAN_BLOCK):
1.24 kristaps 574: mt->lmargin = INDENT;
1.19 kristaps 575: fmt_block_vspace(p, n);
576: break;
577: default:
1.26 kristaps 578: p->offset = mt->offset;
1.19 kristaps 579: break;
580: }
581:
582: return(1);
1.1 kristaps 583: }
584:
585:
1.3 kristaps 586: /* ARGSUSED */
1.1 kristaps 587: static int
1.4 kristaps 588: pre_IP(DECL_ARGS)
589: {
1.22 kristaps 590: const struct man_node *nn;
591: size_t len;
592: int ival;
1.18 kristaps 593:
1.22 kristaps 594: switch (n->type) {
595: case (MAN_BODY):
596: p->flags |= TERMP_NOLPAD;
597: p->flags |= TERMP_NOSPACE;
598: break;
599: case (MAN_HEAD):
600: p->flags |= TERMP_NOBREAK;
601: p->flags |= TERMP_TWOSPACE;
602: break;
1.23 kristaps 603: case (MAN_BLOCK):
604: fmt_block_vspace(p, n);
605: /* FALLTHROUGH */
1.22 kristaps 606: default:
607: return(1);
608: }
1.18 kristaps 609:
1.26 kristaps 610: len = mt->lmargin;
1.22 kristaps 611: ival = -1;
1.4 kristaps 612:
1.22 kristaps 613: /* Calculate offset. */
1.4 kristaps 614:
1.22 kristaps 615: if (NULL != (nn = n->parent->head->child))
616: if (NULL != (nn = nn->next)) {
617: for ( ; nn->next; nn = nn->next)
618: /* Do nothing. */ ;
1.37 kristaps 619: assert(MAN_TEXT == nn->type);
620: if ((ival = a2width(nn->string)) >= 0)
1.22 kristaps 621: len = (size_t)ival;
622: }
1.4 kristaps 623:
1.22 kristaps 624: switch (n->type) {
625: case (MAN_HEAD):
1.23 kristaps 626: /* Handle zero-width lengths. */
627: if (0 == len)
628: len = 1;
629:
1.26 kristaps 630: p->offset = mt->offset;
631: p->rmargin = mt->offset + len;
1.22 kristaps 632: if (ival < 0)
633: break;
1.18 kristaps 634:
1.24 kristaps 635: /* Set the saved left-margin. */
1.26 kristaps 636: mt->lmargin = (size_t)ival;
1.24 kristaps 637:
1.22 kristaps 638: /* Don't print the length value. */
639: for (nn = n->child; nn->next; nn = nn->next)
1.24 kristaps 640: print_node(p, mt, nn, m);
1.22 kristaps 641: return(0);
1.23 kristaps 642: case (MAN_BODY):
1.26 kristaps 643: p->offset = mt->offset + len;
1.23 kristaps 644: p->rmargin = p->maxrmargin;
645: break;
1.22 kristaps 646: default:
647: break;
1.18 kristaps 648: }
649:
1.22 kristaps 650: return(1);
651: }
1.18 kristaps 652:
653:
1.22 kristaps 654: /* ARGSUSED */
655: static void
656: post_IP(DECL_ARGS)
657: {
1.4 kristaps 658:
1.22 kristaps 659: switch (n->type) {
660: case (MAN_HEAD):
661: term_flushln(p);
662: p->flags &= ~TERMP_NOBREAK;
663: p->flags &= ~TERMP_TWOSPACE;
664: p->rmargin = p->maxrmargin;
665: break;
666: case (MAN_BODY):
667: term_flushln(p);
668: p->flags &= ~TERMP_NOLPAD;
669: break;
670: default:
671: break;
672: }
1.4 kristaps 673: }
674:
675:
676: /* ARGSUSED */
677: static int
1.1 kristaps 678: pre_TP(DECL_ARGS)
679: {
1.23 kristaps 680: const struct man_node *nn;
681: size_t len;
682: int ival;
1.1 kristaps 683:
1.21 kristaps 684: switch (n->type) {
685: case (MAN_HEAD):
686: p->flags |= TERMP_NOBREAK;
687: p->flags |= TERMP_TWOSPACE;
688: break;
689: case (MAN_BODY):
690: p->flags |= TERMP_NOLPAD;
691: p->flags |= TERMP_NOSPACE;
1.23 kristaps 692: break;
693: case (MAN_BLOCK):
694: fmt_block_vspace(p, n);
695: /* FALLTHROUGH */
696: default:
697: return(1);
698: }
699:
1.24 kristaps 700: len = (size_t)mt->lmargin;
1.23 kristaps 701: ival = -1;
702:
703: /* Calculate offset. */
704:
705: if (NULL != (nn = n->parent->head->child))
1.37 kristaps 706: if (NULL != nn->next) {
707: assert(MAN_TEXT == nn->type);
708: if ((ival = a2width(nn->string)) >= 0)
1.23 kristaps 709: len = (size_t)ival;
1.37 kristaps 710: }
1.23 kristaps 711:
712: switch (n->type) {
713: case (MAN_HEAD):
714: /* Handle zero-length properly. */
715: if (0 == len)
716: len = 1;
717:
1.26 kristaps 718: p->offset = mt->offset;
719: p->rmargin = mt->offset + len;
1.23 kristaps 720:
721: /* Don't print same-line elements. */
722: for (nn = n->child; nn; nn = nn->next)
723: if (nn->line > n->line)
1.24 kristaps 724: print_node(p, mt, nn, m);
725:
726: if (ival >= 0)
1.26 kristaps 727: mt->lmargin = (size_t)ival;
1.24 kristaps 728:
1.23 kristaps 729: return(0);
730: case (MAN_BODY):
1.26 kristaps 731: p->offset = mt->offset + len;
1.23 kristaps 732: p->rmargin = p->maxrmargin;
1.21 kristaps 733: break;
734: default:
735: break;
736: }
1.16 kristaps 737:
1.21 kristaps 738: return(1);
739: }
1.1 kristaps 740:
741:
1.21 kristaps 742: /* ARGSUSED */
743: static void
744: post_TP(DECL_ARGS)
745: {
1.1 kristaps 746:
1.21 kristaps 747: switch (n->type) {
748: case (MAN_HEAD):
749: term_flushln(p);
750: p->flags &= ~TERMP_NOBREAK;
751: p->flags &= ~TERMP_TWOSPACE;
752: p->rmargin = p->maxrmargin;
753: break;
754: case (MAN_BODY):
755: term_flushln(p);
756: p->flags &= ~TERMP_NOLPAD;
757: break;
758: default:
759: break;
760: }
1.1 kristaps 761: }
762:
763:
1.3 kristaps 764: /* ARGSUSED */
1.1 kristaps 765: static int
766: pre_SS(DECL_ARGS)
767: {
768:
1.19 kristaps 769: switch (n->type) {
770: case (MAN_BLOCK):
1.24 kristaps 771: mt->lmargin = INDENT;
1.26 kristaps 772: mt->offset = INDENT;
1.24 kristaps 773: /* If following a prior empty `SS', no vspace. */
774: if (n->prev && MAN_SS == n->prev->tok)
775: if (NULL == n->prev->body->child)
776: break;
777: if (NULL == n->prev)
778: break;
779: term_vspace(p);
1.19 kristaps 780: break;
781: case (MAN_HEAD):
1.30 kristaps 782: p->bold++;
1.19 kristaps 783: p->offset = HALFINDENT;
784: break;
1.24 kristaps 785: case (MAN_BODY):
1.26 kristaps 786: p->offset = mt->offset;
1.24 kristaps 787: break;
1.19 kristaps 788: default:
789: break;
790: }
791:
1.1 kristaps 792: return(1);
793: }
794:
795:
1.3 kristaps 796: /* ARGSUSED */
1.1 kristaps 797: static void
798: post_SS(DECL_ARGS)
799: {
800:
1.19 kristaps 801: switch (n->type) {
802: case (MAN_HEAD):
803: term_newln(p);
1.30 kristaps 804: p->bold--;
1.19 kristaps 805: break;
1.24 kristaps 806: case (MAN_BODY):
807: term_newln(p);
808: break;
1.19 kristaps 809: default:
810: break;
811: }
1.1 kristaps 812: }
813:
814:
1.3 kristaps 815: /* ARGSUSED */
1.1 kristaps 816: static int
817: pre_SH(DECL_ARGS)
818: {
1.22 kristaps 819:
1.19 kristaps 820: switch (n->type) {
821: case (MAN_BLOCK):
1.24 kristaps 822: mt->lmargin = INDENT;
1.26 kristaps 823: mt->offset = INDENT;
1.22 kristaps 824: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 825: if (n->prev && MAN_SH == n->prev->tok)
826: if (NULL == n->prev->body->child)
827: break;
828: term_vspace(p);
829: break;
830: case (MAN_HEAD):
1.30 kristaps 831: p->bold++;
1.19 kristaps 832: p->offset = 0;
833: break;
834: case (MAN_BODY):
1.26 kristaps 835: p->offset = mt->offset;
1.19 kristaps 836: break;
837: default:
838: break;
839: }
1.1 kristaps 840:
841: return(1);
842: }
843:
844:
1.3 kristaps 845: /* ARGSUSED */
1.1 kristaps 846: static void
847: post_SH(DECL_ARGS)
848: {
849:
1.19 kristaps 850: switch (n->type) {
851: case (MAN_HEAD):
852: term_newln(p);
1.30 kristaps 853: p->bold--;
1.19 kristaps 854: break;
855: case (MAN_BODY):
856: term_newln(p);
857: break;
858: default:
859: break;
860: }
1.1 kristaps 861: }
862:
863:
1.26 kristaps 864: /* ARGSUSED */
865: static int
866: pre_RS(DECL_ARGS)
867: {
868: const struct man_node *nn;
869: int ival;
870:
871: switch (n->type) {
872: case (MAN_BLOCK):
873: term_newln(p);
874: return(1);
875: case (MAN_HEAD):
876: return(0);
877: default:
878: break;
879: }
880:
881: if (NULL == (nn = n->parent->head->child)) {
882: mt->offset = mt->lmargin + INDENT;
883: p->offset = mt->offset;
884: return(1);
885: }
886:
1.37 kristaps 887: assert(MAN_TEXT == nn->type);
888: if ((ival = a2width(nn->string)) < 0)
1.26 kristaps 889: return(1);
890:
891: mt->offset = INDENT + (size_t)ival;
892: p->offset = mt->offset;
893:
894: return(1);
895: }
896:
897:
898: /* ARGSUSED */
899: static void
900: post_RS(DECL_ARGS)
901: {
902:
903: switch (n->type) {
904: case (MAN_BLOCK):
905: mt->offset = mt->lmargin = INDENT;
906: break;
907: default:
908: term_newln(p);
909: p->offset = INDENT;
910: break;
911: }
912: }
913:
914:
1.1 kristaps 915: static void
916: print_node(DECL_ARGS)
917: {
1.4 kristaps 918: int c, sz;
1.1 kristaps 919:
920: c = 1;
921:
922: switch (n->type) {
923: case(MAN_TEXT):
1.4 kristaps 924: if (0 == *n->string) {
925: term_vspace(p);
1.1 kristaps 926: break;
927: }
1.4 kristaps 928: /*
929: * Note! This is hacky. Here, we recognise the `\c'
930: * escape embedded in so many -man pages. It's supposed
931: * to remove the subsequent space, so we mark NOSPACE if
932: * it's encountered in the string.
933: */
934: sz = (int)strlen(n->string);
935: term_word(p, n->string);
936: if (sz >= 2 && n->string[sz - 1] == 'c' &&
937: n->string[sz - 2] == '\\')
938: p->flags |= TERMP_NOSPACE;
1.19 kristaps 939: /* FIXME: this means that macro lines are munged! */
1.24 kristaps 940: if (MANT_LITERAL & mt->fl) {
1.19 kristaps 941: p->flags |= TERMP_NOSPACE;
942: term_flushln(p);
943: }
1.1 kristaps 944: break;
945: default:
1.19 kristaps 946: if (termacts[n->tok].pre)
1.24 kristaps 947: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 948: break;
949: }
950:
951: if (c && n->child)
1.24 kristaps 952: print_body(p, mt, n->child, m);
1.1 kristaps 953:
1.19 kristaps 954: if (MAN_TEXT != n->type)
1.1 kristaps 955: if (termacts[n->tok].post)
1.24 kristaps 956: (*termacts[n->tok].post)(p, mt, n, m);
1.1 kristaps 957: }
958:
959:
960: static void
961: print_body(DECL_ARGS)
962: {
1.19 kristaps 963:
1.24 kristaps 964: print_node(p, mt, n, m);
1.1 kristaps 965: if ( ! n->next)
966: return;
1.24 kristaps 967: print_body(p, mt, n->next, m);
1.1 kristaps 968: }
969:
970:
1.31 kristaps 971: static void
1.1 kristaps 972: print_foot(struct termp *p, const struct man_meta *meta)
973: {
974: struct tm *tm;
1.34 kristaps 975: char buf[BUFSIZ];
1.1 kristaps 976:
977: tm = localtime(&meta->date);
978:
979: if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
1.34 kristaps 980: (void)strlcpy(buf, "(invalid date)", BUFSIZ);
1.1 kristaps 981:
982: term_vspace(p);
983:
984: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
985: p->rmargin = p->maxrmargin - strlen(buf);
986: p->offset = 0;
987:
988: if (meta->source)
989: term_word(p, meta->source);
990: if (meta->source)
991: term_word(p, "");
992: term_flushln(p);
993:
994: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
995: p->offset = p->rmargin;
996: p->rmargin = p->maxrmargin;
997: p->flags &= ~TERMP_NOBREAK;
998:
999: term_word(p, buf);
1000: term_flushln(p);
1001: }
1002:
1003:
1.31 kristaps 1004: static void
1.1 kristaps 1005: print_head(struct termp *p, const struct man_meta *meta)
1006: {
1007: char *buf, *title;
1008:
1009: p->rmargin = p->maxrmargin;
1010: p->offset = 0;
1011:
1012: if (NULL == (buf = malloc(p->rmargin)))
1.31 kristaps 1013: err(EXIT_FAILURE, "malloc");
1.1 kristaps 1014: if (NULL == (title = malloc(p->rmargin)))
1.31 kristaps 1015: err(EXIT_FAILURE, "malloc");
1.1 kristaps 1016:
1017: if (meta->vol)
1018: (void)strlcpy(buf, meta->vol, p->rmargin);
1019: else
1020: *buf = 0;
1021:
1022: (void)snprintf(title, p->rmargin, "%s(%d)",
1023: meta->title, meta->msec);
1024:
1025: p->offset = 0;
1.10 kristaps 1026: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 1027: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1028:
1029: term_word(p, title);
1030: term_flushln(p);
1031:
1032: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1033: p->offset = p->rmargin;
1034: p->rmargin = p->maxrmargin - strlen(title);
1035:
1036: term_word(p, buf);
1037: term_flushln(p);
1038:
1039: p->offset = p->rmargin;
1040: p->rmargin = p->maxrmargin;
1041: p->flags &= ~TERMP_NOBREAK;
1042: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1043:
1044: term_word(p, title);
1045: term_flushln(p);
1046:
1047: p->rmargin = p->maxrmargin;
1048: p->offset = 0;
1049: p->flags &= ~TERMP_NOSPACE;
1050:
1051: free(title);
1052: free(buf);
1053: }
1054:
CVSweb