Annotation of mandoc/man_term.c, Revision 1.47
1.47 ! kristaps 1: /* $Id: man_term.c,v 1.46 2009/10/27 08:49:44 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.45 kristaps 76: static void print_man_body(DECL_ARGS);
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.3 kristaps 88: static int pre_IR(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_r(DECL_ARGS);
101: static int pre_sp(DECL_ARGS);
1.1 kristaps 102:
103: static void post_B(DECL_ARGS);
104: static void post_I(DECL_ARGS);
1.22 kristaps 105: static void post_IP(DECL_ARGS);
1.20 kristaps 106: static void post_HP(DECL_ARGS);
1.26 kristaps 107: static void post_RS(DECL_ARGS);
1.1 kristaps 108: static void post_SH(DECL_ARGS);
109: static void post_SS(DECL_ARGS);
1.21 kristaps 110: static void post_TP(DECL_ARGS);
1.19 kristaps 111: static void post_i(DECL_ARGS);
1.1 kristaps 112:
1.32 kristaps 113: static const struct termact termacts[MAN_MAX] = {
1.15 kristaps 114: { pre_br, NULL }, /* br */
1.1 kristaps 115: { NULL, NULL }, /* TH */
116: { pre_SH, post_SH }, /* SH */
117: { pre_SS, post_SS }, /* SS */
1.21 kristaps 118: { pre_TP, post_TP }, /* TP */
1.1 kristaps 119: { pre_PP, NULL }, /* LP */
120: { pre_PP, NULL }, /* PP */
121: { pre_PP, NULL }, /* P */
1.22 kristaps 122: { pre_IP, post_IP }, /* IP */
1.20 kristaps 123: { pre_HP, post_HP }, /* HP */
1.1 kristaps 124: { NULL, NULL }, /* SM */
125: { pre_B, post_B }, /* SB */
1.3 kristaps 126: { pre_BI, NULL }, /* BI */
1.35 kristaps 127: { pre_BI, NULL }, /* IB */
128: { pre_RB, NULL }, /* BR */
1.3 kristaps 129: { pre_RB, NULL }, /* RB */
1.1 kristaps 130: { NULL, NULL }, /* R */
131: { pre_B, post_B }, /* B */
132: { pre_I, post_I }, /* I */
1.3 kristaps 133: { pre_IR, NULL }, /* IR */
134: { pre_RI, NULL }, /* RI */
1.27 kristaps 135: { NULL, NULL }, /* na */
1.19 kristaps 136: { pre_I, post_i }, /* i */
137: { pre_sp, NULL }, /* sp */
138: { pre_nf, NULL }, /* nf */
139: { pre_fi, NULL }, /* fi */
140: { pre_r, NULL }, /* r */
1.25 kristaps 141: { NULL, NULL }, /* RE */
1.26 kristaps 142: { pre_RS, post_RS }, /* RS */
1.29 kristaps 143: { pre_ign, NULL }, /* DT */
144: { pre_ign, NULL }, /* UC */
1.44 kristaps 145: { pre_ign, NULL }, /* PD */
1.1 kristaps 146: };
147:
148:
149:
1.31 kristaps 150: void
1.36 kristaps 151: terminal_man(void *arg, const struct man *man)
1.1 kristaps 152: {
1.36 kristaps 153: struct termp *p;
154: const struct man_node *n;
155: const struct man_meta *m;
156: struct mtermp mt;
157:
158: p = (struct termp *)arg;
159:
160: if (NULL == p->symtab)
161: switch (p->enc) {
162: case (TERMENC_ASCII):
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.45 kristaps 181: print_man_body(p, &mt, n->child, m);
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.30 kristaps 245: p->under++;
1.1 kristaps 246: return(1);
247: }
248:
249:
1.3 kristaps 250: /* ARGSUSED */
1.19 kristaps 251: static int
252: pre_r(DECL_ARGS)
253: {
254:
1.30 kristaps 255: p->bold = p->under = 0;
1.19 kristaps 256: return(1);
257: }
258:
259:
260: /* ARGSUSED */
261: static void
262: post_i(DECL_ARGS)
263: {
264:
265: if (n->nchild)
1.30 kristaps 266: p->under--;
1.19 kristaps 267: }
268:
269:
270: /* ARGSUSED */
1.1 kristaps 271: static void
272: post_I(DECL_ARGS)
273: {
274:
1.30 kristaps 275: p->under--;
1.1 kristaps 276: }
277:
278:
1.3 kristaps 279: /* ARGSUSED */
280: static int
1.19 kristaps 281: pre_fi(DECL_ARGS)
282: {
283:
1.24 kristaps 284: mt->fl &= ~MANT_LITERAL;
1.19 kristaps 285: return(1);
286: }
287:
288:
289: /* ARGSUSED */
290: static int
291: pre_nf(DECL_ARGS)
292: {
293:
294: term_newln(p);
1.24 kristaps 295: mt->fl |= MANT_LITERAL;
1.19 kristaps 296: return(1);
297: }
298:
299:
300: /* ARGSUSED */
301: static int
1.3 kristaps 302: pre_IR(DECL_ARGS)
303: {
304: const struct man_node *nn;
305: int i;
306:
307: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
308: if ( ! (i % 2))
1.30 kristaps 309: p->under++;
1.4 kristaps 310: if (i > 0)
311: p->flags |= TERMP_NOSPACE;
1.45 kristaps 312: print_man_node(p, mt, nn, m);
1.3 kristaps 313: if ( ! (i % 2))
1.30 kristaps 314: p->under--;
1.3 kristaps 315: }
316: return(0);
317: }
318:
319:
320: /* ARGSUSED */
321: static int
1.35 kristaps 322: pre_RB(DECL_ARGS)
1.3 kristaps 323: {
324: const struct man_node *nn;
325: int i;
326:
327: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 328: if (i % 2 && MAN_RB == n->tok)
329: p->bold++;
330: else if ( ! (i % 2) && MAN_RB != n->tok)
1.30 kristaps 331: p->bold++;
1.35 kristaps 332:
1.4 kristaps 333: if (i > 0)
334: p->flags |= TERMP_NOSPACE;
1.35 kristaps 335:
1.45 kristaps 336: print_man_node(p, mt, nn, m);
1.35 kristaps 337:
338: if (i % 2 && MAN_RB == n->tok)
1.30 kristaps 339: p->bold--;
1.35 kristaps 340: else if ( ! (i % 2) && MAN_RB != n->tok)
1.30 kristaps 341: p->bold--;
1.3 kristaps 342: }
343: return(0);
344: }
345:
346:
347: /* ARGSUSED */
348: static int
349: pre_RI(DECL_ARGS)
350: {
351: const struct man_node *nn;
352: int i;
353:
354: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
355: if ( ! (i % 2))
1.30 kristaps 356: p->under++;
1.4 kristaps 357: if (i > 0)
358: p->flags |= TERMP_NOSPACE;
1.45 kristaps 359: print_man_node(p, mt, nn, m);
1.3 kristaps 360: if ( ! (i % 2))
1.30 kristaps 361: p->under--;
1.3 kristaps 362: }
363: return(0);
364: }
365:
366:
367: /* ARGSUSED */
368: static int
369: pre_BI(DECL_ARGS)
370: {
1.35 kristaps 371: const struct man_node *nn;
372: int i;
1.3 kristaps 373:
374: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 375: if (i % 2 && MAN_BI == n->tok)
1.30 kristaps 376: p->under++;
1.35 kristaps 377: else if (i % 2)
378: p->bold++;
379: else if (MAN_BI == n->tok)
380: p->bold++;
1.30 kristaps 381: else
1.35 kristaps 382: p->under++;
383:
384: if (i)
1.4 kristaps 385: p->flags |= TERMP_NOSPACE;
1.45 kristaps 386: print_man_node(p, mt, nn, m);
1.35 kristaps 387:
388: if (i % 2 && MAN_BI == n->tok)
1.30 kristaps 389: p->under--;
1.35 kristaps 390: else if (i % 2)
391: p->bold--;
392: else if (MAN_BI == n->tok)
393: p->bold--;
1.30 kristaps 394: else
1.35 kristaps 395: p->under--;
1.3 kristaps 396: }
397: return(0);
398: }
399:
400:
401: /* ARGSUSED */
1.1 kristaps 402: static int
403: pre_B(DECL_ARGS)
404: {
405:
1.30 kristaps 406: p->bold++;
1.1 kristaps 407: return(1);
408: }
409:
410:
1.3 kristaps 411: /* ARGSUSED */
1.1 kristaps 412: static void
413: post_B(DECL_ARGS)
414: {
415:
1.30 kristaps 416: p->bold--;
1.1 kristaps 417: }
418:
419:
1.3 kristaps 420: /* ARGSUSED */
1.1 kristaps 421: static int
1.19 kristaps 422: pre_sp(DECL_ARGS)
423: {
424: int i, len;
425:
1.45 kristaps 426: len = n->child ? a2height(n->child) : 1;
1.38 kristaps 427:
1.19 kristaps 428: if (0 == len)
429: term_newln(p);
430: for (i = 0; i < len; i++)
431: term_vspace(p);
432:
433: return(0);
434: }
435:
436:
437: /* ARGSUSED */
438: static int
1.15 kristaps 439: pre_br(DECL_ARGS)
440: {
441:
442: term_newln(p);
443: return(0);
444: }
445:
446:
447: /* ARGSUSED */
448: static int
1.19 kristaps 449: pre_HP(DECL_ARGS)
450: {
1.24 kristaps 451: size_t len;
452: int ival;
453: const struct man_node *nn;
1.19 kristaps 454:
1.20 kristaps 455: switch (n->type) {
456: case (MAN_BLOCK):
1.39 kristaps 457: print_bvspace(p, n);
1.24 kristaps 458: return(1);
1.20 kristaps 459: case (MAN_BODY):
460: p->flags |= TERMP_NOBREAK;
461: p->flags |= TERMP_TWOSPACE;
462: break;
463: default:
464: return(0);
465: }
466:
1.26 kristaps 467: len = mt->lmargin;
1.24 kristaps 468: ival = -1;
469:
470: /* Calculate offset. */
471:
1.39 kristaps 472: if (NULL != (nn = n->parent->head->child))
1.45 kristaps 473: if ((ival = a2width(nn)) >= 0)
1.24 kristaps 474: len = (size_t)ival;
475:
476: if (0 == len)
477: len = 1;
478:
1.26 kristaps 479: p->offset = mt->offset;
480: p->rmargin = mt->offset + len;
1.24 kristaps 481:
482: if (ival >= 0)
1.26 kristaps 483: mt->lmargin = (size_t)ival;
1.24 kristaps 484:
1.19 kristaps 485: return(1);
486: }
487:
488:
489: /* ARGSUSED */
1.20 kristaps 490: static void
491: post_HP(DECL_ARGS)
492: {
493:
494: switch (n->type) {
1.24 kristaps 495: case (MAN_BLOCK):
496: term_flushln(p);
497: break;
1.20 kristaps 498: case (MAN_BODY):
499: term_flushln(p);
500: p->flags &= ~TERMP_NOBREAK;
501: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 502: p->offset = mt->offset;
1.20 kristaps 503: p->rmargin = p->maxrmargin;
504: break;
505: default:
506: break;
507: }
508: }
509:
510:
511: /* ARGSUSED */
1.19 kristaps 512: static int
1.1 kristaps 513: pre_PP(DECL_ARGS)
514: {
515:
1.19 kristaps 516: switch (n->type) {
517: case (MAN_BLOCK):
1.24 kristaps 518: mt->lmargin = INDENT;
1.39 kristaps 519: print_bvspace(p, n);
1.19 kristaps 520: break;
521: default:
1.26 kristaps 522: p->offset = mt->offset;
1.19 kristaps 523: break;
524: }
525:
526: return(1);
1.1 kristaps 527: }
528:
529:
1.3 kristaps 530: /* ARGSUSED */
1.1 kristaps 531: static int
1.4 kristaps 532: pre_IP(DECL_ARGS)
533: {
1.22 kristaps 534: const struct man_node *nn;
535: size_t len;
536: int ival;
1.18 kristaps 537:
1.22 kristaps 538: switch (n->type) {
539: case (MAN_BODY):
540: p->flags |= TERMP_NOLPAD;
541: p->flags |= TERMP_NOSPACE;
542: break;
543: case (MAN_HEAD):
544: p->flags |= TERMP_NOBREAK;
545: p->flags |= TERMP_TWOSPACE;
546: break;
1.23 kristaps 547: case (MAN_BLOCK):
1.39 kristaps 548: print_bvspace(p, n);
1.23 kristaps 549: /* FALLTHROUGH */
1.22 kristaps 550: default:
551: return(1);
552: }
1.18 kristaps 553:
1.26 kristaps 554: len = mt->lmargin;
1.22 kristaps 555: ival = -1;
1.4 kristaps 556:
1.22 kristaps 557: /* Calculate offset. */
1.4 kristaps 558:
1.22 kristaps 559: if (NULL != (nn = n->parent->head->child))
560: if (NULL != (nn = nn->next)) {
561: for ( ; nn->next; nn = nn->next)
562: /* Do nothing. */ ;
1.45 kristaps 563: if ((ival = a2width(nn)) >= 0)
1.22 kristaps 564: len = (size_t)ival;
565: }
1.4 kristaps 566:
1.22 kristaps 567: switch (n->type) {
568: case (MAN_HEAD):
1.23 kristaps 569: /* Handle zero-width lengths. */
570: if (0 == len)
571: len = 1;
572:
1.26 kristaps 573: p->offset = mt->offset;
574: p->rmargin = mt->offset + len;
1.22 kristaps 575: if (ival < 0)
576: break;
1.18 kristaps 577:
1.24 kristaps 578: /* Set the saved left-margin. */
1.26 kristaps 579: mt->lmargin = (size_t)ival;
1.24 kristaps 580:
1.22 kristaps 581: /* Don't print the length value. */
582: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 583: print_man_node(p, mt, nn, m);
1.22 kristaps 584: return(0);
1.23 kristaps 585: case (MAN_BODY):
1.26 kristaps 586: p->offset = mt->offset + len;
1.23 kristaps 587: p->rmargin = p->maxrmargin;
588: break;
1.22 kristaps 589: default:
590: break;
1.18 kristaps 591: }
592:
1.22 kristaps 593: return(1);
594: }
1.18 kristaps 595:
596:
1.22 kristaps 597: /* ARGSUSED */
598: static void
599: post_IP(DECL_ARGS)
600: {
1.4 kristaps 601:
1.22 kristaps 602: switch (n->type) {
603: case (MAN_HEAD):
604: term_flushln(p);
605: p->flags &= ~TERMP_NOBREAK;
606: p->flags &= ~TERMP_TWOSPACE;
607: p->rmargin = p->maxrmargin;
608: break;
609: case (MAN_BODY):
610: term_flushln(p);
611: p->flags &= ~TERMP_NOLPAD;
612: break;
613: default:
614: break;
615: }
1.4 kristaps 616: }
617:
618:
619: /* ARGSUSED */
620: static int
1.1 kristaps 621: pre_TP(DECL_ARGS)
622: {
1.23 kristaps 623: const struct man_node *nn;
624: size_t len;
625: int ival;
1.1 kristaps 626:
1.21 kristaps 627: switch (n->type) {
628: case (MAN_HEAD):
629: p->flags |= TERMP_NOBREAK;
630: p->flags |= TERMP_TWOSPACE;
631: break;
632: case (MAN_BODY):
633: p->flags |= TERMP_NOLPAD;
634: p->flags |= TERMP_NOSPACE;
1.23 kristaps 635: break;
636: case (MAN_BLOCK):
1.39 kristaps 637: print_bvspace(p, n);
1.23 kristaps 638: /* FALLTHROUGH */
639: default:
640: return(1);
641: }
642:
1.24 kristaps 643: len = (size_t)mt->lmargin;
1.23 kristaps 644: ival = -1;
645:
646: /* Calculate offset. */
647:
648: if (NULL != (nn = n->parent->head->child))
1.39 kristaps 649: if (NULL != nn->next)
1.45 kristaps 650: if ((ival = a2width(nn)) >= 0)
1.23 kristaps 651: len = (size_t)ival;
652:
653: switch (n->type) {
654: case (MAN_HEAD):
655: /* Handle zero-length properly. */
656: if (0 == len)
657: len = 1;
658:
1.26 kristaps 659: p->offset = mt->offset;
660: p->rmargin = mt->offset + len;
1.23 kristaps 661:
662: /* Don't print same-line elements. */
663: for (nn = n->child; nn; nn = nn->next)
664: if (nn->line > n->line)
1.45 kristaps 665: print_man_node(p, mt, nn, m);
1.24 kristaps 666:
667: if (ival >= 0)
1.26 kristaps 668: mt->lmargin = (size_t)ival;
1.24 kristaps 669:
1.23 kristaps 670: return(0);
671: case (MAN_BODY):
1.26 kristaps 672: p->offset = mt->offset + len;
1.23 kristaps 673: p->rmargin = p->maxrmargin;
1.21 kristaps 674: break;
675: default:
676: break;
677: }
1.16 kristaps 678:
1.21 kristaps 679: return(1);
680: }
1.1 kristaps 681:
682:
1.21 kristaps 683: /* ARGSUSED */
684: static void
685: post_TP(DECL_ARGS)
686: {
1.1 kristaps 687:
1.21 kristaps 688: switch (n->type) {
689: case (MAN_HEAD):
690: term_flushln(p);
691: p->flags &= ~TERMP_NOBREAK;
692: p->flags &= ~TERMP_TWOSPACE;
693: p->rmargin = p->maxrmargin;
694: break;
695: case (MAN_BODY):
696: term_flushln(p);
697: p->flags &= ~TERMP_NOLPAD;
698: break;
699: default:
700: break;
701: }
1.1 kristaps 702: }
703:
704:
1.3 kristaps 705: /* ARGSUSED */
1.1 kristaps 706: static int
707: pre_SS(DECL_ARGS)
708: {
709:
1.19 kristaps 710: switch (n->type) {
711: case (MAN_BLOCK):
1.24 kristaps 712: mt->lmargin = INDENT;
1.26 kristaps 713: mt->offset = INDENT;
1.24 kristaps 714: /* If following a prior empty `SS', no vspace. */
715: if (n->prev && MAN_SS == n->prev->tok)
716: if (NULL == n->prev->body->child)
717: break;
718: if (NULL == n->prev)
719: break;
720: term_vspace(p);
1.19 kristaps 721: break;
722: case (MAN_HEAD):
1.30 kristaps 723: p->bold++;
1.19 kristaps 724: p->offset = HALFINDENT;
725: break;
1.24 kristaps 726: case (MAN_BODY):
1.26 kristaps 727: p->offset = mt->offset;
1.24 kristaps 728: break;
1.19 kristaps 729: default:
730: break;
731: }
732:
1.1 kristaps 733: return(1);
734: }
735:
736:
1.3 kristaps 737: /* ARGSUSED */
1.1 kristaps 738: static void
739: post_SS(DECL_ARGS)
740: {
741:
1.19 kristaps 742: switch (n->type) {
743: case (MAN_HEAD):
744: term_newln(p);
1.30 kristaps 745: p->bold--;
1.19 kristaps 746: break;
1.24 kristaps 747: case (MAN_BODY):
748: term_newln(p);
749: break;
1.19 kristaps 750: default:
751: break;
752: }
1.1 kristaps 753: }
754:
755:
1.3 kristaps 756: /* ARGSUSED */
1.1 kristaps 757: static int
758: pre_SH(DECL_ARGS)
759: {
1.22 kristaps 760:
1.19 kristaps 761: switch (n->type) {
762: case (MAN_BLOCK):
1.24 kristaps 763: mt->lmargin = INDENT;
1.26 kristaps 764: mt->offset = INDENT;
1.22 kristaps 765: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 766: if (n->prev && MAN_SH == n->prev->tok)
767: if (NULL == n->prev->body->child)
768: break;
769: term_vspace(p);
770: break;
771: case (MAN_HEAD):
1.30 kristaps 772: p->bold++;
1.19 kristaps 773: p->offset = 0;
774: break;
775: case (MAN_BODY):
1.26 kristaps 776: p->offset = mt->offset;
1.19 kristaps 777: break;
778: default:
779: break;
780: }
1.1 kristaps 781:
782: return(1);
783: }
784:
785:
1.3 kristaps 786: /* ARGSUSED */
1.1 kristaps 787: static void
788: post_SH(DECL_ARGS)
789: {
790:
1.19 kristaps 791: switch (n->type) {
792: case (MAN_HEAD):
793: term_newln(p);
1.30 kristaps 794: p->bold--;
1.19 kristaps 795: break;
796: case (MAN_BODY):
797: term_newln(p);
798: break;
799: default:
800: break;
801: }
1.1 kristaps 802: }
803:
804:
1.26 kristaps 805: /* ARGSUSED */
806: static int
807: pre_RS(DECL_ARGS)
808: {
809: const struct man_node *nn;
810: int ival;
811:
812: switch (n->type) {
813: case (MAN_BLOCK):
814: term_newln(p);
815: return(1);
816: case (MAN_HEAD):
817: return(0);
818: default:
819: break;
820: }
821:
822: if (NULL == (nn = n->parent->head->child)) {
823: mt->offset = mt->lmargin + INDENT;
824: p->offset = mt->offset;
825: return(1);
826: }
827:
1.45 kristaps 828: if ((ival = a2width(nn)) < 0)
1.26 kristaps 829: return(1);
830:
831: mt->offset = INDENT + (size_t)ival;
832: p->offset = mt->offset;
833:
834: return(1);
835: }
836:
837:
838: /* ARGSUSED */
839: static void
840: post_RS(DECL_ARGS)
841: {
842:
843: switch (n->type) {
844: case (MAN_BLOCK):
845: mt->offset = mt->lmargin = INDENT;
846: break;
847: default:
848: term_newln(p);
849: p->offset = INDENT;
850: break;
851: }
852: }
853:
854:
1.1 kristaps 855: static void
1.45 kristaps 856: print_man_node(DECL_ARGS)
1.1 kristaps 857: {
1.4 kristaps 858: int c, sz;
1.1 kristaps 859:
860: c = 1;
861:
862: switch (n->type) {
863: case(MAN_TEXT):
1.4 kristaps 864: if (0 == *n->string) {
865: term_vspace(p);
1.1 kristaps 866: break;
867: }
1.4 kristaps 868: /*
869: * Note! This is hacky. Here, we recognise the `\c'
870: * escape embedded in so many -man pages. It's supposed
871: * to remove the subsequent space, so we mark NOSPACE if
872: * it's encountered in the string.
873: */
874: sz = (int)strlen(n->string);
875: term_word(p, n->string);
876: if (sz >= 2 && n->string[sz - 1] == 'c' &&
877: n->string[sz - 2] == '\\')
878: p->flags |= TERMP_NOSPACE;
1.19 kristaps 879: /* FIXME: this means that macro lines are munged! */
1.24 kristaps 880: if (MANT_LITERAL & mt->fl) {
1.19 kristaps 881: p->flags |= TERMP_NOSPACE;
882: term_flushln(p);
883: }
1.1 kristaps 884: break;
885: default:
1.19 kristaps 886: if (termacts[n->tok].pre)
1.24 kristaps 887: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 888: break;
889: }
890:
891: if (c && n->child)
1.45 kristaps 892: print_man_body(p, mt, n->child, m);
1.1 kristaps 893:
1.19 kristaps 894: if (MAN_TEXT != n->type)
1.1 kristaps 895: if (termacts[n->tok].post)
1.24 kristaps 896: (*termacts[n->tok].post)(p, mt, n, m);
1.1 kristaps 897: }
898:
899:
900: static void
1.45 kristaps 901: print_man_body(DECL_ARGS)
1.1 kristaps 902: {
1.19 kristaps 903:
1.45 kristaps 904: print_man_node(p, mt, n, m);
1.1 kristaps 905: if ( ! n->next)
906: return;
1.45 kristaps 907: print_man_body(p, mt, n->next, m);
1.1 kristaps 908: }
909:
910:
1.31 kristaps 911: static void
1.45 kristaps 912: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1 kristaps 913: {
1.43 kristaps 914: char buf[DATESIZ];
1.1 kristaps 915:
1.43 kristaps 916: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 917:
918: term_vspace(p);
919:
920: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
921: p->rmargin = p->maxrmargin - strlen(buf);
922: p->offset = 0;
923:
924: if (meta->source)
925: term_word(p, meta->source);
926: if (meta->source)
927: term_word(p, "");
928: term_flushln(p);
929:
930: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
931: p->offset = p->rmargin;
932: p->rmargin = p->maxrmargin;
933: p->flags &= ~TERMP_NOBREAK;
934:
935: term_word(p, buf);
936: term_flushln(p);
937: }
938:
939:
1.31 kristaps 940: static void
1.46 kristaps 941: print_man_head(struct termp *p, const struct man_meta *m)
1.1 kristaps 942: {
1.46 kristaps 943: char buf[BUFSIZ], title[BUFSIZ];
1.1 kristaps 944:
945: p->rmargin = p->maxrmargin;
946: p->offset = 0;
1.46 kristaps 947: buf[0] = title[0] = '\0';
1.1 kristaps 948:
1.46 kristaps 949: if (m->vol)
950: strlcpy(buf, m->vol, BUFSIZ);
1.1 kristaps 951:
1.46 kristaps 952: snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
1.1 kristaps 953:
954: p->offset = 0;
1.10 kristaps 955: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 956: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
957:
958: term_word(p, title);
959: term_flushln(p);
960:
961: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
962: p->offset = p->rmargin;
963: p->rmargin = p->maxrmargin - strlen(title);
964:
965: term_word(p, buf);
966: term_flushln(p);
967:
968: p->offset = p->rmargin;
969: p->rmargin = p->maxrmargin;
970: p->flags &= ~TERMP_NOBREAK;
971: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
972:
973: term_word(p, title);
974: term_flushln(p);
975:
976: p->rmargin = p->maxrmargin;
977: p->offset = 0;
978: p->flags &= ~TERMP_NOSPACE;
979: }
CVSweb