Annotation of mandoc/man_term.c, Revision 1.88
1.88 ! kristaps 1: /* $Id: man_term.c,v 1.87 2010/12/06 13:53:07 kristaps Exp $ */
1.1 kristaps 2: /*
1.80 schwarze 3: * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.8 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.8 kristaps 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
1.55 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
1.28 kristaps 21: #include <sys/types.h>
22:
1.1 kristaps 23: #include <assert.h>
1.18 kristaps 24: #include <ctype.h>
1.1 kristaps 25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28:
1.71 kristaps 29: #include "mandoc.h"
1.40 kristaps 30: #include "out.h"
1.36 kristaps 31: #include "man.h"
1.1 kristaps 32: #include "term.h"
1.36 kristaps 33: #include "chars.h"
34: #include "main.h"
1.1 kristaps 35:
1.18 kristaps 36: #define INDENT 7
37: #define HALFINDENT 3
38:
1.44 kristaps 39: /* FIXME: have PD set the default vspace width. */
40:
1.24 kristaps 41: struct mtermp {
42: int fl;
1.19 kristaps 43: #define MANT_LITERAL (1 << 0)
1.26 kristaps 44: /*
45: * Default amount to indent the left margin after leading text
46: * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
47: * indent). This needs to be saved because `HP' and so on, if
48: * not having a specified value, must default.
49: *
50: * Note that this is the indentation AFTER the left offset, so
51: * the total offset is usually offset + lmargin.
52: */
53: size_t lmargin;
54: /*
55: * The default offset, i.e., the amount between any text and the
56: * page boundary.
57: */
58: size_t offset;
1.24 kristaps 59: };
1.19 kristaps 60:
1.1 kristaps 61: #define DECL_ARGS struct termp *p, \
1.24 kristaps 62: struct mtermp *mt, \
1.1 kristaps 63: const struct man_node *n, \
64: const struct man_meta *m
65:
66: struct termact {
67: int (*pre)(DECL_ARGS);
68: void (*post)(DECL_ARGS);
1.56 kristaps 69: int flags;
70: #define MAN_NOTEXT (1 << 0) /* Never has text children. */
1.1 kristaps 71: };
72:
1.77 kristaps 73: static int a2width(const struct termp *, const char *);
74: static size_t a2height(const struct termp *, const char *);
1.39 kristaps 75:
1.52 kristaps 76: static void print_man_nodelist(DECL_ARGS);
1.45 kristaps 77: static void print_man_node(DECL_ARGS);
1.74 kristaps 78: static void print_man_head(struct termp *, const void *);
1.73 kristaps 79: static void print_man_foot(struct termp *, const void *);
1.39 kristaps 80: static void print_bvspace(struct termp *,
81: const struct man_node *);
82:
1.88 ! kristaps 83: static int pre_alternate(DECL_ARGS);
1.1 kristaps 84: static int pre_B(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.26 kristaps 89: static int pre_RS(DECL_ARGS);
1.1 kristaps 90: static int pre_SH(DECL_ARGS);
91: static int pre_SS(DECL_ARGS);
92: static int pre_TP(DECL_ARGS);
1.29 kristaps 93: static int pre_ign(DECL_ARGS);
1.83 kristaps 94: static int pre_in(DECL_ARGS);
1.84 kristaps 95: static int pre_literal(DECL_ARGS);
1.19 kristaps 96: static int pre_sp(DECL_ARGS);
1.1 kristaps 97:
1.22 kristaps 98: static void post_IP(DECL_ARGS);
1.20 kristaps 99: static void post_HP(DECL_ARGS);
1.26 kristaps 100: static void post_RS(DECL_ARGS);
1.1 kristaps 101: static void post_SH(DECL_ARGS);
102: static void post_SS(DECL_ARGS);
1.21 kristaps 103: static void post_TP(DECL_ARGS);
1.1 kristaps 104:
1.32 kristaps 105: static const struct termact termacts[MAN_MAX] = {
1.82 kristaps 106: { pre_sp, NULL, MAN_NOTEXT }, /* br */
1.56 kristaps 107: { NULL, NULL, 0 }, /* TH */
108: { pre_SH, post_SH, 0 }, /* SH */
109: { pre_SS, post_SS, 0 }, /* SS */
110: { pre_TP, post_TP, 0 }, /* TP */
111: { pre_PP, NULL, 0 }, /* LP */
112: { pre_PP, NULL, 0 }, /* PP */
113: { pre_PP, NULL, 0 }, /* P */
114: { pre_IP, post_IP, 0 }, /* IP */
115: { pre_HP, post_HP, 0 }, /* HP */
116: { NULL, NULL, 0 }, /* SM */
117: { pre_B, NULL, 0 }, /* SB */
1.88 ! kristaps 118: { pre_alternate, NULL, 0 }, /* BI */
! 119: { pre_alternate, NULL, 0 }, /* IB */
! 120: { pre_alternate, NULL, 0 }, /* BR */
! 121: { pre_alternate, NULL, 0 }, /* RB */
1.56 kristaps 122: { NULL, NULL, 0 }, /* R */
123: { pre_B, NULL, 0 }, /* B */
124: { pre_I, NULL, 0 }, /* I */
1.88 ! kristaps 125: { pre_alternate, NULL, 0 }, /* IR */
! 126: { pre_alternate, NULL, 0 }, /* RI */
1.56 kristaps 127: { NULL, NULL, MAN_NOTEXT }, /* na */
128: { pre_I, NULL, 0 }, /* i */
129: { pre_sp, NULL, MAN_NOTEXT }, /* sp */
1.84 kristaps 130: { pre_literal, NULL, 0 }, /* nf */
131: { pre_literal, NULL, 0 }, /* fi */
1.56 kristaps 132: { NULL, NULL, 0 }, /* r */
133: { NULL, NULL, 0 }, /* RE */
134: { pre_RS, post_RS, 0 }, /* RS */
135: { pre_ign, NULL, 0 }, /* DT */
136: { pre_ign, NULL, 0 }, /* UC */
137: { pre_ign, NULL, 0 }, /* PD */
1.70 joerg 138: { pre_ign, NULL, 0 }, /* AT */
1.83 kristaps 139: { pre_in, NULL, MAN_NOTEXT }, /* in */
1.1 kristaps 140: };
141:
142:
143:
1.31 kristaps 144: void
1.36 kristaps 145: terminal_man(void *arg, const struct man *man)
1.1 kristaps 146: {
1.36 kristaps 147: struct termp *p;
148: const struct man_node *n;
149: const struct man_meta *m;
150: struct mtermp mt;
151:
152: p = (struct termp *)arg;
153:
1.58 kristaps 154: p->overstep = 0;
1.65 joerg 155: p->maxrmargin = p->defrmargin;
1.77 kristaps 156: p->tabwidth = term_len(p, 5);
1.73 kristaps 157:
1.36 kristaps 158: if (NULL == p->symtab)
159: switch (p->enc) {
160: case (TERMENC_ASCII):
161: p->symtab = chars_init(CHARS_ASCII);
162: break;
163: default:
164: abort();
165: /* NOTREACHED */
166: }
167:
168: n = man_node(man);
169: m = man_meta(man);
1.1 kristaps 170:
1.75 schwarze 171: term_begin(p, print_man_head, print_man_foot, m);
1.1 kristaps 172: p->flags |= TERMP_NOSPACE;
1.19 kristaps 173:
1.24 kristaps 174: mt.fl = 0;
1.77 kristaps 175: mt.lmargin = term_len(p, INDENT);
176: mt.offset = term_len(p, INDENT);
1.24 kristaps 177:
1.36 kristaps 178: if (n->child)
1.52 kristaps 179: print_man_nodelist(p, &mt, n->child, m);
1.73 kristaps 180:
181: term_end(p);
1.1 kristaps 182: }
183:
184:
1.77 kristaps 185: static size_t
186: a2height(const struct termp *p, const char *cp)
1.18 kristaps 187: {
1.40 kristaps 188: struct roffsu su;
1.18 kristaps 189:
1.77 kristaps 190: if ( ! a2roffsu(cp, &su, SCALE_VS))
191: SCALE_VS_INIT(&su, term_strlen(p, cp));
1.18 kristaps 192:
1.77 kristaps 193: return(term_vspan(p, &su));
1.18 kristaps 194: }
195:
196:
197: static int
1.77 kristaps 198: a2width(const struct termp *p, const char *cp)
1.38 kristaps 199: {
1.40 kristaps 200: struct roffsu su;
1.38 kristaps 201:
1.77 kristaps 202: if ( ! a2roffsu(cp, &su, SCALE_BU))
1.41 kristaps 203: return(-1);
1.40 kristaps 204:
1.77 kristaps 205: return((int)term_hspan(p, &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.84 kristaps 247: pre_literal(DECL_ARGS)
1.19 kristaps 248: {
249:
1.81 kristaps 250: term_newln(p);
1.88 ! kristaps 251:
! 252: if (MAN_nf == n->tok)
1.84 kristaps 253: mt->fl |= MANT_LITERAL;
1.88 ! kristaps 254: else
1.84 kristaps 255: mt->fl &= ~MANT_LITERAL;
256:
1.19 kristaps 257: return(1);
258: }
259:
260: /* ARGSUSED */
261: static int
1.88 ! kristaps 262: pre_alternate(DECL_ARGS)
1.3 kristaps 263: {
1.88 ! kristaps 264: enum termfont font[2];
! 265: const struct man_node *nn;
! 266: int savelit, i;
1.3 kristaps 267:
1.88 ! kristaps 268: switch (n->tok) {
! 269: case (MAN_RB):
! 270: font[0] = TERMFONT_NONE;
! 271: font[1] = TERMFONT_BOLD;
! 272: break;
! 273: case (MAN_RI):
! 274: font[0] = TERMFONT_NONE;
! 275: font[1] = TERMFONT_UNDER;
! 276: break;
! 277: case (MAN_BR):
! 278: font[0] = TERMFONT_BOLD;
! 279: font[1] = TERMFONT_NONE;
! 280: break;
! 281: case (MAN_BI):
! 282: font[0] = TERMFONT_BOLD;
! 283: font[1] = TERMFONT_UNDER;
! 284: break;
! 285: case (MAN_IR):
! 286: font[0] = TERMFONT_UNDER;
! 287: font[1] = TERMFONT_NONE;
! 288: break;
! 289: case (MAN_IB):
! 290: font[0] = TERMFONT_UNDER;
! 291: font[1] = TERMFONT_BOLD;
! 292: break;
! 293: default:
! 294: abort();
! 295: }
1.35 kristaps 296:
1.88 ! kristaps 297: savelit = MANT_LITERAL & mt->fl;
! 298: mt->fl &= ~MANT_LITERAL;
1.35 kristaps 299:
1.88 ! kristaps 300: for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
! 301: term_fontrepl(p, font[i]);
! 302: if (savelit && NULL == nn->next)
! 303: mt->fl |= MANT_LITERAL;
1.45 kristaps 304: print_man_node(p, mt, nn, m);
1.88 ! kristaps 305: if (nn->next)
1.4 kristaps 306: p->flags |= TERMP_NOSPACE;
1.3 kristaps 307: }
308:
309: return(0);
310: }
311:
312: /* ARGSUSED */
1.1 kristaps 313: static int
314: pre_B(DECL_ARGS)
315: {
316:
1.52 kristaps 317: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 318: return(1);
1.83 kristaps 319: }
320:
321: /* ARGSUSED */
322: static int
323: pre_in(DECL_ARGS)
324: {
325: int len, less;
326: size_t v;
327: const char *cp;
328:
329: term_newln(p);
330:
331: if (NULL == n->child) {
332: p->offset = mt->offset;
333: return(0);
334: }
335:
336: cp = n->child->string;
337: less = 0;
338:
339: if ('-' == *cp)
340: less = -1;
341: else if ('+' == *cp)
342: less = 1;
343: else
344: cp--;
345:
346: if ((len = a2width(p, ++cp)) < 0)
347: return(0);
348:
349: v = (size_t)len;
350:
351: if (less < 0)
352: p->offset -= p->offset > v ? v : p->offset;
353: else if (less > 0)
354: p->offset += v;
355: else
356: p->offset = v;
357:
358: return(0);
1.1 kristaps 359: }
360:
361:
1.3 kristaps 362: /* ARGSUSED */
1.1 kristaps 363: static int
1.19 kristaps 364: pre_sp(DECL_ARGS)
365: {
1.77 kristaps 366: size_t i, len;
1.19 kristaps 367:
1.82 kristaps 368: switch (n->tok) {
369: case (MAN_br):
370: len = 0;
371: break;
372: default:
373: len = n->child ? a2height(p, n->child->string) : 1;
374: break;
375: }
1.38 kristaps 376:
1.19 kristaps 377: if (0 == len)
378: term_newln(p);
1.82 kristaps 379: for (i = 0; i < len; i++)
1.19 kristaps 380: term_vspace(p);
381:
1.15 kristaps 382: return(0);
383: }
384:
385:
386: /* ARGSUSED */
387: static int
1.19 kristaps 388: pre_HP(DECL_ARGS)
389: {
1.24 kristaps 390: size_t len;
391: int ival;
392: const struct man_node *nn;
1.19 kristaps 393:
1.20 kristaps 394: switch (n->type) {
395: case (MAN_BLOCK):
1.39 kristaps 396: print_bvspace(p, n);
1.24 kristaps 397: return(1);
1.20 kristaps 398: case (MAN_BODY):
399: p->flags |= TERMP_NOBREAK;
400: p->flags |= TERMP_TWOSPACE;
401: break;
402: default:
403: return(0);
404: }
405:
1.26 kristaps 406: len = mt->lmargin;
1.24 kristaps 407: ival = -1;
408:
409: /* Calculate offset. */
410:
1.39 kristaps 411: if (NULL != (nn = n->parent->head->child))
1.77 kristaps 412: if ((ival = a2width(p, nn->string)) >= 0)
1.24 kristaps 413: len = (size_t)ival;
414:
415: if (0 == len)
1.77 kristaps 416: len = term_len(p, 1);
1.24 kristaps 417:
1.26 kristaps 418: p->offset = mt->offset;
419: p->rmargin = mt->offset + len;
1.24 kristaps 420:
421: if (ival >= 0)
1.26 kristaps 422: mt->lmargin = (size_t)ival;
1.24 kristaps 423:
1.19 kristaps 424: return(1);
425: }
426:
427:
428: /* ARGSUSED */
1.20 kristaps 429: static void
430: post_HP(DECL_ARGS)
431: {
432:
433: switch (n->type) {
1.24 kristaps 434: case (MAN_BLOCK):
435: term_flushln(p);
436: break;
1.20 kristaps 437: case (MAN_BODY):
438: term_flushln(p);
439: p->flags &= ~TERMP_NOBREAK;
440: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 441: p->offset = mt->offset;
1.20 kristaps 442: p->rmargin = p->maxrmargin;
443: break;
444: default:
445: break;
446: }
447: }
448:
449:
450: /* ARGSUSED */
1.19 kristaps 451: static int
1.1 kristaps 452: pre_PP(DECL_ARGS)
453: {
454:
1.19 kristaps 455: switch (n->type) {
456: case (MAN_BLOCK):
1.77 kristaps 457: mt->lmargin = term_len(p, INDENT);
1.39 kristaps 458: print_bvspace(p, n);
1.19 kristaps 459: break;
460: default:
1.26 kristaps 461: p->offset = mt->offset;
1.19 kristaps 462: break;
463: }
464:
1.87 kristaps 465: return(MAN_HEAD != n->type);
1.1 kristaps 466: }
467:
468:
1.3 kristaps 469: /* ARGSUSED */
1.1 kristaps 470: static int
1.4 kristaps 471: pre_IP(DECL_ARGS)
472: {
1.22 kristaps 473: const struct man_node *nn;
474: size_t len;
475: int ival;
1.18 kristaps 476:
1.22 kristaps 477: switch (n->type) {
478: case (MAN_BODY):
479: p->flags |= TERMP_NOLPAD;
480: p->flags |= TERMP_NOSPACE;
481: break;
482: case (MAN_HEAD):
483: p->flags |= TERMP_NOBREAK;
484: break;
1.23 kristaps 485: case (MAN_BLOCK):
1.39 kristaps 486: print_bvspace(p, n);
1.23 kristaps 487: /* FALLTHROUGH */
1.22 kristaps 488: default:
489: return(1);
490: }
1.18 kristaps 491:
1.26 kristaps 492: len = mt->lmargin;
1.22 kristaps 493: ival = -1;
1.4 kristaps 494:
1.22 kristaps 495: /* Calculate offset. */
1.4 kristaps 496:
1.22 kristaps 497: if (NULL != (nn = n->parent->head->child))
498: if (NULL != (nn = nn->next)) {
499: for ( ; nn->next; nn = nn->next)
500: /* Do nothing. */ ;
1.77 kristaps 501: if ((ival = a2width(p, nn->string)) >= 0)
1.22 kristaps 502: len = (size_t)ival;
503: }
1.4 kristaps 504:
1.22 kristaps 505: switch (n->type) {
506: case (MAN_HEAD):
1.23 kristaps 507: /* Handle zero-width lengths. */
508: if (0 == len)
1.77 kristaps 509: len = term_len(p, 1);
1.23 kristaps 510:
1.26 kristaps 511: p->offset = mt->offset;
512: p->rmargin = mt->offset + len;
1.22 kristaps 513: if (ival < 0)
514: break;
1.18 kristaps 515:
1.24 kristaps 516: /* Set the saved left-margin. */
1.26 kristaps 517: mt->lmargin = (size_t)ival;
1.24 kristaps 518:
1.22 kristaps 519: /* Don't print the length value. */
520: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 521: print_man_node(p, mt, nn, m);
1.22 kristaps 522: return(0);
1.23 kristaps 523: case (MAN_BODY):
1.26 kristaps 524: p->offset = mt->offset + len;
1.23 kristaps 525: p->rmargin = p->maxrmargin;
526: break;
1.22 kristaps 527: default:
528: break;
1.18 kristaps 529: }
530:
1.22 kristaps 531: return(1);
532: }
1.18 kristaps 533:
534:
1.22 kristaps 535: /* ARGSUSED */
536: static void
537: post_IP(DECL_ARGS)
538: {
1.4 kristaps 539:
1.22 kristaps 540: switch (n->type) {
541: case (MAN_HEAD):
542: term_flushln(p);
543: p->flags &= ~TERMP_NOBREAK;
544: p->rmargin = p->maxrmargin;
545: break;
546: case (MAN_BODY):
547: term_flushln(p);
548: p->flags &= ~TERMP_NOLPAD;
549: break;
550: default:
551: break;
552: }
1.4 kristaps 553: }
554:
555:
556: /* ARGSUSED */
557: static int
1.1 kristaps 558: pre_TP(DECL_ARGS)
559: {
1.23 kristaps 560: const struct man_node *nn;
561: size_t len;
562: int ival;
1.1 kristaps 563:
1.21 kristaps 564: switch (n->type) {
565: case (MAN_HEAD):
566: p->flags |= TERMP_NOBREAK;
567: p->flags |= TERMP_TWOSPACE;
568: break;
569: case (MAN_BODY):
570: p->flags |= TERMP_NOLPAD;
571: p->flags |= TERMP_NOSPACE;
1.23 kristaps 572: break;
573: case (MAN_BLOCK):
1.39 kristaps 574: print_bvspace(p, n);
1.23 kristaps 575: /* FALLTHROUGH */
576: default:
577: return(1);
578: }
579:
1.24 kristaps 580: len = (size_t)mt->lmargin;
1.23 kristaps 581: ival = -1;
582:
583: /* Calculate offset. */
584:
1.56 kristaps 585: if (NULL != (nn = n->parent->head->child)) {
586: while (nn && MAN_TEXT != nn->type)
587: nn = nn->next;
588: if (nn && nn->next)
1.77 kristaps 589: if ((ival = a2width(p, nn->string)) >= 0)
1.23 kristaps 590: len = (size_t)ival;
1.56 kristaps 591: }
1.23 kristaps 592:
593: switch (n->type) {
594: case (MAN_HEAD):
595: /* Handle zero-length properly. */
596: if (0 == len)
1.77 kristaps 597: len = term_len(p, 1);
1.23 kristaps 598:
1.26 kristaps 599: p->offset = mt->offset;
600: p->rmargin = mt->offset + len;
1.23 kristaps 601:
602: /* Don't print same-line elements. */
603: for (nn = n->child; nn; nn = nn->next)
604: if (nn->line > n->line)
1.45 kristaps 605: print_man_node(p, mt, nn, m);
1.24 kristaps 606:
607: if (ival >= 0)
1.26 kristaps 608: mt->lmargin = (size_t)ival;
1.24 kristaps 609:
1.23 kristaps 610: return(0);
611: case (MAN_BODY):
1.26 kristaps 612: p->offset = mt->offset + len;
1.23 kristaps 613: p->rmargin = p->maxrmargin;
1.21 kristaps 614: break;
615: default:
616: break;
617: }
1.16 kristaps 618:
1.21 kristaps 619: return(1);
620: }
1.1 kristaps 621:
622:
1.21 kristaps 623: /* ARGSUSED */
624: static void
625: post_TP(DECL_ARGS)
626: {
1.1 kristaps 627:
1.21 kristaps 628: switch (n->type) {
629: case (MAN_HEAD):
630: term_flushln(p);
631: p->flags &= ~TERMP_NOBREAK;
632: p->flags &= ~TERMP_TWOSPACE;
633: p->rmargin = p->maxrmargin;
634: break;
635: case (MAN_BODY):
636: term_flushln(p);
637: p->flags &= ~TERMP_NOLPAD;
638: break;
639: default:
640: break;
641: }
1.1 kristaps 642: }
643:
644:
1.3 kristaps 645: /* ARGSUSED */
1.1 kristaps 646: static int
647: pre_SS(DECL_ARGS)
648: {
649:
1.19 kristaps 650: switch (n->type) {
651: case (MAN_BLOCK):
1.77 kristaps 652: mt->lmargin = term_len(p, INDENT);
653: mt->offset = term_len(p, INDENT);
1.24 kristaps 654: /* If following a prior empty `SS', no vspace. */
655: if (n->prev && MAN_SS == n->prev->tok)
656: if (NULL == n->prev->body->child)
657: break;
658: if (NULL == n->prev)
659: break;
660: term_vspace(p);
1.19 kristaps 661: break;
662: case (MAN_HEAD):
1.52 kristaps 663: term_fontrepl(p, TERMFONT_BOLD);
1.77 kristaps 664: p->offset = term_len(p, HALFINDENT);
1.19 kristaps 665: break;
1.24 kristaps 666: case (MAN_BODY):
1.26 kristaps 667: p->offset = mt->offset;
1.24 kristaps 668: break;
1.19 kristaps 669: default:
670: break;
671: }
672:
1.1 kristaps 673: return(1);
674: }
675:
676:
1.3 kristaps 677: /* ARGSUSED */
1.1 kristaps 678: static void
679: post_SS(DECL_ARGS)
680: {
681:
1.19 kristaps 682: switch (n->type) {
683: case (MAN_HEAD):
684: term_newln(p);
685: break;
1.24 kristaps 686: case (MAN_BODY):
687: term_newln(p);
688: break;
1.19 kristaps 689: default:
690: break;
691: }
1.1 kristaps 692: }
693:
694:
1.3 kristaps 695: /* ARGSUSED */
1.1 kristaps 696: static int
697: pre_SH(DECL_ARGS)
698: {
1.22 kristaps 699:
1.19 kristaps 700: switch (n->type) {
701: case (MAN_BLOCK):
1.77 kristaps 702: mt->lmargin = term_len(p, INDENT);
703: mt->offset = term_len(p, INDENT);
1.22 kristaps 704: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 705: if (n->prev && MAN_SH == n->prev->tok)
706: if (NULL == n->prev->body->child)
707: break;
1.61 kristaps 708: /* If the first macro, no vspae. */
709: if (NULL == n->prev)
710: break;
1.19 kristaps 711: term_vspace(p);
712: break;
713: case (MAN_HEAD):
1.52 kristaps 714: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 715: p->offset = 0;
716: break;
717: case (MAN_BODY):
1.26 kristaps 718: p->offset = mt->offset;
1.19 kristaps 719: break;
720: default:
721: break;
722: }
1.1 kristaps 723:
724: return(1);
725: }
726:
727:
1.3 kristaps 728: /* ARGSUSED */
1.1 kristaps 729: static void
730: post_SH(DECL_ARGS)
731: {
732:
1.19 kristaps 733: switch (n->type) {
734: case (MAN_HEAD):
735: term_newln(p);
736: break;
737: case (MAN_BODY):
738: term_newln(p);
739: break;
740: default:
741: break;
742: }
1.1 kristaps 743: }
744:
745:
1.26 kristaps 746: /* ARGSUSED */
747: static int
748: pre_RS(DECL_ARGS)
749: {
750: const struct man_node *nn;
751: int ival;
752:
753: switch (n->type) {
754: case (MAN_BLOCK):
755: term_newln(p);
756: return(1);
757: case (MAN_HEAD):
758: return(0);
759: default:
760: break;
761: }
762:
763: if (NULL == (nn = n->parent->head->child)) {
1.77 kristaps 764: mt->offset = mt->lmargin + term_len(p, INDENT);
1.26 kristaps 765: p->offset = mt->offset;
766: return(1);
767: }
768:
1.77 kristaps 769: if ((ival = a2width(p, nn->string)) < 0)
1.26 kristaps 770: return(1);
771:
1.77 kristaps 772: mt->offset = term_len(p, INDENT) + (size_t)ival;
1.26 kristaps 773: p->offset = mt->offset;
774:
775: return(1);
776: }
777:
778:
779: /* ARGSUSED */
780: static void
781: post_RS(DECL_ARGS)
782: {
783:
784: switch (n->type) {
785: case (MAN_BLOCK):
1.77 kristaps 786: mt->offset = mt->lmargin = term_len(p, INDENT);
1.59 kristaps 787: break;
788: case (MAN_HEAD):
1.26 kristaps 789: break;
790: default:
791: term_newln(p);
1.77 kristaps 792: p->offset = term_len(p, INDENT);
1.26 kristaps 793: break;
794: }
795: }
796:
797:
1.1 kristaps 798: static void
1.45 kristaps 799: print_man_node(DECL_ARGS)
1.1 kristaps 800: {
1.65 joerg 801: size_t rm, rmax;
1.54 kristaps 802: int c;
1.1 kristaps 803:
804: c = 1;
805:
806: switch (n->type) {
807: case(MAN_TEXT):
1.4 kristaps 808: if (0 == *n->string) {
809: term_vspace(p);
1.1 kristaps 810: break;
811: }
1.54 kristaps 812:
1.4 kristaps 813: term_word(p, n->string);
1.52 kristaps 814:
1.19 kristaps 815: /* FIXME: this means that macro lines are munged! */
1.52 kristaps 816:
1.24 kristaps 817: if (MANT_LITERAL & mt->fl) {
1.65 joerg 818: rm = p->rmargin;
819: rmax = p->maxrmargin;
1.60 kristaps 820: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19 kristaps 821: p->flags |= TERMP_NOSPACE;
822: term_flushln(p);
1.65 joerg 823: p->rmargin = rm;
824: p->maxrmargin = rmax;
1.19 kristaps 825: }
1.1 kristaps 826: break;
827: default:
1.56 kristaps 828: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
829: term_fontrepl(p, TERMFONT_NONE);
1.19 kristaps 830: if (termacts[n->tok].pre)
1.24 kristaps 831: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 832: break;
833: }
834:
835: if (c && n->child)
1.52 kristaps 836: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 837:
1.51 kristaps 838: if (MAN_TEXT != n->type) {
1.1 kristaps 839: if (termacts[n->tok].post)
1.24 kristaps 840: (*termacts[n->tok].post)(p, mt, n, m);
1.56 kristaps 841: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
842: term_fontrepl(p, TERMFONT_NONE);
1.51 kristaps 843: }
1.63 kristaps 844:
845: if (MAN_EOS & n->flags)
846: p->flags |= TERMP_SENTENCE;
1.1 kristaps 847: }
848:
849:
850: static void
1.52 kristaps 851: print_man_nodelist(DECL_ARGS)
1.1 kristaps 852: {
1.19 kristaps 853:
1.45 kristaps 854: print_man_node(p, mt, n, m);
1.1 kristaps 855: if ( ! n->next)
856: return;
1.52 kristaps 857: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 858: }
859:
860:
1.31 kristaps 861: static void
1.73 kristaps 862: print_man_foot(struct termp *p, const void *arg)
1.1 kristaps 863: {
1.43 kristaps 864: char buf[DATESIZ];
1.73 kristaps 865: const struct man_meta *meta;
866:
867: meta = (const struct man_meta *)arg;
1.1 kristaps 868:
1.52 kristaps 869: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 870:
1.72 kristaps 871: if (meta->rawdate)
872: strlcpy(buf, meta->rawdate, DATESIZ);
873: else
874: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 875:
1.69 joerg 876: term_vspace(p);
877: term_vspace(p);
1.1 kristaps 878: term_vspace(p);
879:
880: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.77 kristaps 881: p->rmargin = p->maxrmargin - term_strlen(p, buf);
1.1 kristaps 882: p->offset = 0;
1.85 kristaps 883:
884: /* term_strlen() can return zero. */
885: if (p->rmargin == p->maxrmargin)
886: p->rmargin--;
1.1 kristaps 887:
888: if (meta->source)
889: term_word(p, meta->source);
890: if (meta->source)
891: term_word(p, "");
892: term_flushln(p);
893:
894: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
895: p->offset = p->rmargin;
896: p->rmargin = p->maxrmargin;
897: p->flags &= ~TERMP_NOBREAK;
898:
899: term_word(p, buf);
900: term_flushln(p);
901: }
902:
903:
1.31 kristaps 904: static void
1.73 kristaps 905: print_man_head(struct termp *p, const void *arg)
1.1 kristaps 906: {
1.46 kristaps 907: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 908: size_t buflen, titlen;
1.73 kristaps 909: const struct man_meta *m;
910:
911: m = (const struct man_meta *)arg;
1.1 kristaps 912:
1.62 kristaps 913: /*
914: * Note that old groff would spit out some spaces before the
915: * header. We discontinue this strange behaviour, but at one
916: * point we did so here.
917: */
918:
1.1 kristaps 919: p->rmargin = p->maxrmargin;
1.58 kristaps 920:
1.1 kristaps 921: p->offset = 0;
1.46 kristaps 922: buf[0] = title[0] = '\0';
1.1 kristaps 923:
1.46 kristaps 924: if (m->vol)
925: strlcpy(buf, m->vol, BUFSIZ);
1.77 kristaps 926: buflen = term_strlen(p, buf);
1.1 kristaps 927:
1.64 kristaps 928: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.77 kristaps 929: titlen = term_strlen(p, title);
1.1 kristaps 930:
931: p->offset = 0;
1.57 kristaps 932: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77 kristaps 933: (p->maxrmargin -
934: term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57 kristaps 935: p->maxrmargin - buflen;
1.1 kristaps 936: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
937:
938: term_word(p, title);
939: term_flushln(p);
940:
941: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
942: p->offset = p->rmargin;
1.57 kristaps 943: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
944: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 945:
946: term_word(p, buf);
947: term_flushln(p);
948:
949: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 950: if (p->rmargin + titlen <= p->maxrmargin) {
951: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
952: p->offset = p->rmargin;
953: p->rmargin = p->maxrmargin;
954: term_word(p, title);
955: term_flushln(p);
956: }
1.1 kristaps 957:
958: p->rmargin = p->maxrmargin;
959: p->offset = 0;
960: p->flags &= ~TERMP_NOSPACE;
1.61 kristaps 961:
1.62 kristaps 962: /*
963: * Groff likes to have some leading spaces before content. Well
964: * that's fine by me.
965: */
966:
1.61 kristaps 967: term_vspace(p);
968: term_vspace(p);
969: term_vspace(p);
1.1 kristaps 970: }
CVSweb