Annotation of mandoc/man_term.c, Revision 1.93
1.93 ! kristaps 1: /* $Id: man_term.c,v 1.92 2011/01/02 12:21: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.89 kristaps 97: static int pre_ft(DECL_ARGS);
1.1 kristaps 98:
1.22 kristaps 99: static void post_IP(DECL_ARGS);
1.20 kristaps 100: static void post_HP(DECL_ARGS);
1.26 kristaps 101: static void post_RS(DECL_ARGS);
1.1 kristaps 102: static void post_SH(DECL_ARGS);
103: static void post_SS(DECL_ARGS);
1.21 kristaps 104: static void post_TP(DECL_ARGS);
1.1 kristaps 105:
1.32 kristaps 106: static const struct termact termacts[MAN_MAX] = {
1.82 kristaps 107: { pre_sp, NULL, MAN_NOTEXT }, /* br */
1.56 kristaps 108: { NULL, NULL, 0 }, /* TH */
109: { pre_SH, post_SH, 0 }, /* SH */
110: { pre_SS, post_SS, 0 }, /* SS */
111: { pre_TP, post_TP, 0 }, /* TP */
112: { pre_PP, NULL, 0 }, /* LP */
113: { pre_PP, NULL, 0 }, /* PP */
114: { pre_PP, NULL, 0 }, /* P */
115: { pre_IP, post_IP, 0 }, /* IP */
116: { pre_HP, post_HP, 0 }, /* HP */
117: { NULL, NULL, 0 }, /* SM */
118: { pre_B, NULL, 0 }, /* SB */
1.88 kristaps 119: { pre_alternate, NULL, 0 }, /* BI */
120: { pre_alternate, NULL, 0 }, /* IB */
121: { pre_alternate, NULL, 0 }, /* BR */
122: { pre_alternate, NULL, 0 }, /* RB */
1.56 kristaps 123: { NULL, NULL, 0 }, /* R */
124: { pre_B, NULL, 0 }, /* B */
125: { pre_I, NULL, 0 }, /* I */
1.88 kristaps 126: { pre_alternate, NULL, 0 }, /* IR */
127: { pre_alternate, NULL, 0 }, /* RI */
1.56 kristaps 128: { NULL, NULL, MAN_NOTEXT }, /* na */
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 }, /* RE */
133: { pre_RS, post_RS, 0 }, /* RS */
134: { pre_ign, NULL, 0 }, /* DT */
135: { pre_ign, NULL, 0 }, /* UC */
136: { pre_ign, NULL, 0 }, /* PD */
1.70 joerg 137: { pre_ign, NULL, 0 }, /* AT */
1.83 kristaps 138: { pre_in, NULL, MAN_NOTEXT }, /* in */
1.89 kristaps 139: { pre_ft, NULL, MAN_NOTEXT }, /* ft */
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.89 kristaps 319: }
320:
321: /* ARGSUSED */
322: static int
323: pre_ft(DECL_ARGS)
324: {
325: const char *cp;
326:
327: if (NULL == n->child) {
328: term_fontlast(p);
329: return(0);
330: }
331:
332: cp = n->child->string;
333: switch (*cp) {
334: case ('4'):
335: /* FALLTHROUGH */
336: case ('3'):
337: /* FALLTHROUGH */
338: case ('B'):
339: term_fontrepl(p, TERMFONT_BOLD);
340: break;
341: case ('2'):
342: /* FALLTHROUGH */
343: case ('I'):
344: term_fontrepl(p, TERMFONT_UNDER);
345: break;
346: case ('P'):
347: term_fontlast(p);
348: break;
349: case ('1'):
350: /* FALLTHROUGH */
351: case ('C'):
352: /* FALLTHROUGH */
353: case ('R'):
354: term_fontrepl(p, TERMFONT_NONE);
355: break;
356: default:
357: break;
358: }
359: return(0);
1.83 kristaps 360: }
361:
362: /* ARGSUSED */
363: static int
364: pre_in(DECL_ARGS)
365: {
366: int len, less;
367: size_t v;
368: const char *cp;
369:
370: term_newln(p);
371:
372: if (NULL == n->child) {
373: p->offset = mt->offset;
374: return(0);
375: }
376:
377: cp = n->child->string;
378: less = 0;
379:
380: if ('-' == *cp)
381: less = -1;
382: else if ('+' == *cp)
383: less = 1;
384: else
385: cp--;
386:
387: if ((len = a2width(p, ++cp)) < 0)
388: return(0);
389:
390: v = (size_t)len;
391:
392: if (less < 0)
393: p->offset -= p->offset > v ? v : p->offset;
394: else if (less > 0)
395: p->offset += v;
396: else
397: p->offset = v;
398:
399: return(0);
1.1 kristaps 400: }
401:
402:
1.3 kristaps 403: /* ARGSUSED */
1.1 kristaps 404: static int
1.19 kristaps 405: pre_sp(DECL_ARGS)
406: {
1.77 kristaps 407: size_t i, len;
1.19 kristaps 408:
1.82 kristaps 409: switch (n->tok) {
410: case (MAN_br):
411: len = 0;
412: break;
413: default:
414: len = n->child ? a2height(p, n->child->string) : 1;
415: break;
416: }
1.38 kristaps 417:
1.19 kristaps 418: if (0 == len)
419: term_newln(p);
1.82 kristaps 420: for (i = 0; i < len; i++)
1.19 kristaps 421: term_vspace(p);
422:
1.15 kristaps 423: return(0);
424: }
425:
426:
427: /* ARGSUSED */
428: static int
1.19 kristaps 429: pre_HP(DECL_ARGS)
430: {
1.24 kristaps 431: size_t len;
432: int ival;
433: const struct man_node *nn;
1.19 kristaps 434:
1.20 kristaps 435: switch (n->type) {
436: case (MAN_BLOCK):
1.39 kristaps 437: print_bvspace(p, n);
1.24 kristaps 438: return(1);
1.20 kristaps 439: case (MAN_BODY):
440: p->flags |= TERMP_NOBREAK;
441: p->flags |= TERMP_TWOSPACE;
442: break;
443: default:
444: return(0);
445: }
446:
1.26 kristaps 447: len = mt->lmargin;
1.24 kristaps 448: ival = -1;
449:
450: /* Calculate offset. */
451:
1.39 kristaps 452: if (NULL != (nn = n->parent->head->child))
1.77 kristaps 453: if ((ival = a2width(p, nn->string)) >= 0)
1.24 kristaps 454: len = (size_t)ival;
455:
456: if (0 == len)
1.77 kristaps 457: len = term_len(p, 1);
1.24 kristaps 458:
1.26 kristaps 459: p->offset = mt->offset;
460: p->rmargin = mt->offset + len;
1.24 kristaps 461:
462: if (ival >= 0)
1.26 kristaps 463: mt->lmargin = (size_t)ival;
1.24 kristaps 464:
1.19 kristaps 465: return(1);
466: }
467:
468:
469: /* ARGSUSED */
1.20 kristaps 470: static void
471: post_HP(DECL_ARGS)
472: {
473:
474: switch (n->type) {
1.24 kristaps 475: case (MAN_BLOCK):
476: term_flushln(p);
477: break;
1.20 kristaps 478: case (MAN_BODY):
479: term_flushln(p);
480: p->flags &= ~TERMP_NOBREAK;
481: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 482: p->offset = mt->offset;
1.20 kristaps 483: p->rmargin = p->maxrmargin;
484: break;
485: default:
486: break;
487: }
488: }
489:
490:
491: /* ARGSUSED */
1.19 kristaps 492: static int
1.1 kristaps 493: pre_PP(DECL_ARGS)
494: {
495:
1.19 kristaps 496: switch (n->type) {
497: case (MAN_BLOCK):
1.77 kristaps 498: mt->lmargin = term_len(p, INDENT);
1.39 kristaps 499: print_bvspace(p, n);
1.19 kristaps 500: break;
501: default:
1.26 kristaps 502: p->offset = mt->offset;
1.19 kristaps 503: break;
504: }
505:
1.87 kristaps 506: return(MAN_HEAD != n->type);
1.1 kristaps 507: }
508:
509:
1.3 kristaps 510: /* ARGSUSED */
1.1 kristaps 511: static int
1.4 kristaps 512: pre_IP(DECL_ARGS)
513: {
1.22 kristaps 514: const struct man_node *nn;
515: size_t len;
516: int ival;
1.18 kristaps 517:
1.22 kristaps 518: switch (n->type) {
519: case (MAN_BODY):
520: p->flags |= TERMP_NOLPAD;
521: p->flags |= TERMP_NOSPACE;
522: break;
523: case (MAN_HEAD):
524: p->flags |= TERMP_NOBREAK;
525: break;
1.23 kristaps 526: case (MAN_BLOCK):
1.39 kristaps 527: print_bvspace(p, n);
1.23 kristaps 528: /* FALLTHROUGH */
1.22 kristaps 529: default:
530: return(1);
531: }
1.18 kristaps 532:
1.26 kristaps 533: len = mt->lmargin;
1.22 kristaps 534: ival = -1;
1.4 kristaps 535:
1.22 kristaps 536: /* Calculate offset. */
1.4 kristaps 537:
1.22 kristaps 538: if (NULL != (nn = n->parent->head->child))
539: if (NULL != (nn = nn->next)) {
540: for ( ; nn->next; nn = nn->next)
541: /* Do nothing. */ ;
1.77 kristaps 542: if ((ival = a2width(p, nn->string)) >= 0)
1.22 kristaps 543: len = (size_t)ival;
544: }
1.4 kristaps 545:
1.22 kristaps 546: switch (n->type) {
547: case (MAN_HEAD):
1.23 kristaps 548: /* Handle zero-width lengths. */
549: if (0 == len)
1.77 kristaps 550: len = term_len(p, 1);
1.23 kristaps 551:
1.26 kristaps 552: p->offset = mt->offset;
553: p->rmargin = mt->offset + len;
1.22 kristaps 554: if (ival < 0)
555: break;
1.18 kristaps 556:
1.24 kristaps 557: /* Set the saved left-margin. */
1.26 kristaps 558: mt->lmargin = (size_t)ival;
1.24 kristaps 559:
1.22 kristaps 560: /* Don't print the length value. */
561: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 562: print_man_node(p, mt, nn, m);
1.22 kristaps 563: return(0);
1.23 kristaps 564: case (MAN_BODY):
1.26 kristaps 565: p->offset = mt->offset + len;
1.23 kristaps 566: p->rmargin = p->maxrmargin;
567: break;
1.22 kristaps 568: default:
569: break;
1.18 kristaps 570: }
571:
1.22 kristaps 572: return(1);
573: }
1.18 kristaps 574:
575:
1.22 kristaps 576: /* ARGSUSED */
577: static void
578: post_IP(DECL_ARGS)
579: {
1.4 kristaps 580:
1.22 kristaps 581: switch (n->type) {
582: case (MAN_HEAD):
583: term_flushln(p);
584: p->flags &= ~TERMP_NOBREAK;
585: p->rmargin = p->maxrmargin;
586: break;
587: case (MAN_BODY):
588: term_flushln(p);
589: p->flags &= ~TERMP_NOLPAD;
590: break;
591: default:
592: break;
593: }
1.4 kristaps 594: }
595:
596:
597: /* ARGSUSED */
598: static int
1.1 kristaps 599: pre_TP(DECL_ARGS)
600: {
1.23 kristaps 601: const struct man_node *nn;
602: size_t len;
603: int ival;
1.1 kristaps 604:
1.21 kristaps 605: switch (n->type) {
606: case (MAN_HEAD):
607: p->flags |= TERMP_NOBREAK;
608: p->flags |= TERMP_TWOSPACE;
609: break;
610: case (MAN_BODY):
611: p->flags |= TERMP_NOLPAD;
612: p->flags |= TERMP_NOSPACE;
1.23 kristaps 613: break;
614: case (MAN_BLOCK):
1.39 kristaps 615: print_bvspace(p, n);
1.23 kristaps 616: /* FALLTHROUGH */
617: default:
618: return(1);
619: }
620:
1.24 kristaps 621: len = (size_t)mt->lmargin;
1.23 kristaps 622: ival = -1;
623:
624: /* Calculate offset. */
625:
1.56 kristaps 626: if (NULL != (nn = n->parent->head->child)) {
627: while (nn && MAN_TEXT != nn->type)
628: nn = nn->next;
629: if (nn && nn->next)
1.77 kristaps 630: if ((ival = a2width(p, nn->string)) >= 0)
1.23 kristaps 631: len = (size_t)ival;
1.56 kristaps 632: }
1.23 kristaps 633:
634: switch (n->type) {
635: case (MAN_HEAD):
636: /* Handle zero-length properly. */
637: if (0 == len)
1.77 kristaps 638: len = term_len(p, 1);
1.23 kristaps 639:
1.26 kristaps 640: p->offset = mt->offset;
641: p->rmargin = mt->offset + len;
1.23 kristaps 642:
643: /* Don't print same-line elements. */
644: for (nn = n->child; nn; nn = nn->next)
645: if (nn->line > n->line)
1.45 kristaps 646: print_man_node(p, mt, nn, m);
1.24 kristaps 647:
648: if (ival >= 0)
1.26 kristaps 649: mt->lmargin = (size_t)ival;
1.24 kristaps 650:
1.23 kristaps 651: return(0);
652: case (MAN_BODY):
1.26 kristaps 653: p->offset = mt->offset + len;
1.23 kristaps 654: p->rmargin = p->maxrmargin;
1.21 kristaps 655: break;
656: default:
657: break;
658: }
1.16 kristaps 659:
1.21 kristaps 660: return(1);
661: }
1.1 kristaps 662:
663:
1.21 kristaps 664: /* ARGSUSED */
665: static void
666: post_TP(DECL_ARGS)
667: {
1.1 kristaps 668:
1.21 kristaps 669: switch (n->type) {
670: case (MAN_HEAD):
671: term_flushln(p);
672: p->flags &= ~TERMP_NOBREAK;
673: p->flags &= ~TERMP_TWOSPACE;
674: p->rmargin = p->maxrmargin;
675: break;
676: case (MAN_BODY):
677: term_flushln(p);
678: p->flags &= ~TERMP_NOLPAD;
679: break;
680: default:
681: break;
682: }
1.1 kristaps 683: }
684:
685:
1.3 kristaps 686: /* ARGSUSED */
1.1 kristaps 687: static int
688: pre_SS(DECL_ARGS)
689: {
690:
1.19 kristaps 691: switch (n->type) {
692: case (MAN_BLOCK):
1.77 kristaps 693: mt->lmargin = term_len(p, INDENT);
694: mt->offset = term_len(p, INDENT);
1.24 kristaps 695: /* If following a prior empty `SS', no vspace. */
696: if (n->prev && MAN_SS == n->prev->tok)
697: if (NULL == n->prev->body->child)
698: break;
699: if (NULL == n->prev)
700: break;
701: term_vspace(p);
1.19 kristaps 702: break;
703: case (MAN_HEAD):
1.52 kristaps 704: term_fontrepl(p, TERMFONT_BOLD);
1.77 kristaps 705: p->offset = term_len(p, HALFINDENT);
1.19 kristaps 706: break;
1.24 kristaps 707: case (MAN_BODY):
1.26 kristaps 708: p->offset = mt->offset;
1.24 kristaps 709: break;
1.19 kristaps 710: default:
711: break;
712: }
713:
1.1 kristaps 714: return(1);
715: }
716:
717:
1.3 kristaps 718: /* ARGSUSED */
1.1 kristaps 719: static void
720: post_SS(DECL_ARGS)
721: {
722:
1.19 kristaps 723: switch (n->type) {
724: case (MAN_HEAD):
725: term_newln(p);
726: break;
1.24 kristaps 727: case (MAN_BODY):
728: term_newln(p);
729: break;
1.19 kristaps 730: default:
731: break;
732: }
1.1 kristaps 733: }
734:
735:
1.3 kristaps 736: /* ARGSUSED */
1.1 kristaps 737: static int
738: pre_SH(DECL_ARGS)
739: {
1.22 kristaps 740:
1.19 kristaps 741: switch (n->type) {
742: case (MAN_BLOCK):
1.77 kristaps 743: mt->lmargin = term_len(p, INDENT);
744: mt->offset = term_len(p, INDENT);
1.22 kristaps 745: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 746: if (n->prev && MAN_SH == n->prev->tok)
747: if (NULL == n->prev->body->child)
748: break;
1.61 kristaps 749: /* If the first macro, no vspae. */
750: if (NULL == n->prev)
751: break;
1.19 kristaps 752: term_vspace(p);
753: break;
754: case (MAN_HEAD):
1.52 kristaps 755: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 756: p->offset = 0;
757: break;
758: case (MAN_BODY):
1.26 kristaps 759: p->offset = mt->offset;
1.19 kristaps 760: break;
761: default:
762: break;
763: }
1.1 kristaps 764:
765: return(1);
766: }
767:
768:
1.3 kristaps 769: /* ARGSUSED */
1.1 kristaps 770: static void
771: post_SH(DECL_ARGS)
772: {
773:
1.19 kristaps 774: switch (n->type) {
775: case (MAN_HEAD):
776: term_newln(p);
777: break;
778: case (MAN_BODY):
779: term_newln(p);
780: break;
781: default:
782: break;
783: }
1.1 kristaps 784: }
785:
786:
1.26 kristaps 787: /* ARGSUSED */
788: static int
789: pre_RS(DECL_ARGS)
790: {
791: const struct man_node *nn;
792: int ival;
793:
794: switch (n->type) {
795: case (MAN_BLOCK):
796: term_newln(p);
797: return(1);
798: case (MAN_HEAD):
799: return(0);
800: default:
801: break;
802: }
803:
804: if (NULL == (nn = n->parent->head->child)) {
1.77 kristaps 805: mt->offset = mt->lmargin + term_len(p, INDENT);
1.26 kristaps 806: p->offset = mt->offset;
807: return(1);
808: }
809:
1.77 kristaps 810: if ((ival = a2width(p, nn->string)) < 0)
1.26 kristaps 811: return(1);
812:
1.77 kristaps 813: mt->offset = term_len(p, INDENT) + (size_t)ival;
1.26 kristaps 814: p->offset = mt->offset;
815:
816: return(1);
817: }
818:
819:
820: /* ARGSUSED */
821: static void
822: post_RS(DECL_ARGS)
823: {
824:
825: switch (n->type) {
826: case (MAN_BLOCK):
1.77 kristaps 827: mt->offset = mt->lmargin = term_len(p, INDENT);
1.59 kristaps 828: break;
829: case (MAN_HEAD):
1.26 kristaps 830: break;
831: default:
832: term_newln(p);
1.77 kristaps 833: p->offset = term_len(p, INDENT);
1.26 kristaps 834: break;
835: }
836: }
837:
838:
1.1 kristaps 839: static void
1.45 kristaps 840: print_man_node(DECL_ARGS)
1.1 kristaps 841: {
1.65 joerg 842: size_t rm, rmax;
1.54 kristaps 843: int c;
1.1 kristaps 844:
845: c = 1;
846:
847: switch (n->type) {
848: case(MAN_TEXT):
1.4 kristaps 849: if (0 == *n->string) {
850: term_vspace(p);
1.1 kristaps 851: break;
852: }
1.54 kristaps 853:
1.4 kristaps 854: term_word(p, n->string);
1.52 kristaps 855:
1.19 kristaps 856: /* FIXME: this means that macro lines are munged! */
1.52 kristaps 857:
1.24 kristaps 858: if (MANT_LITERAL & mt->fl) {
1.65 joerg 859: rm = p->rmargin;
860: rmax = p->maxrmargin;
1.60 kristaps 861: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19 kristaps 862: p->flags |= TERMP_NOSPACE;
863: term_flushln(p);
1.65 joerg 864: p->rmargin = rm;
865: p->maxrmargin = rmax;
1.19 kristaps 866: }
1.1 kristaps 867: break;
1.91 kristaps 868: case (MAN_TBL):
1.93 ! kristaps 869: if (TBL_SPAN_FIRST & n->span->flags)
! 870: term_newln(p);
1.92 kristaps 871: term_tbl(p, n->span);
1.91 kristaps 872: break;
1.1 kristaps 873: default:
1.56 kristaps 874: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
875: term_fontrepl(p, TERMFONT_NONE);
1.19 kristaps 876: if (termacts[n->tok].pre)
1.24 kristaps 877: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 878: break;
879: }
880:
881: if (c && n->child)
1.52 kristaps 882: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 883:
1.91 kristaps 884: switch (n->type) {
885: case (MAN_TEXT):
886: /* FALLTHROUGH */
887: case (MAN_TBL):
888: break;
889: default:
1.1 kristaps 890: if (termacts[n->tok].post)
1.24 kristaps 891: (*termacts[n->tok].post)(p, mt, n, m);
1.56 kristaps 892: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
893: term_fontrepl(p, TERMFONT_NONE);
1.91 kristaps 894: break;
1.51 kristaps 895: }
1.63 kristaps 896:
897: if (MAN_EOS & n->flags)
898: p->flags |= TERMP_SENTENCE;
1.1 kristaps 899: }
900:
901:
902: static void
1.52 kristaps 903: print_man_nodelist(DECL_ARGS)
1.1 kristaps 904: {
1.19 kristaps 905:
1.45 kristaps 906: print_man_node(p, mt, n, m);
1.1 kristaps 907: if ( ! n->next)
908: return;
1.52 kristaps 909: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 910: }
911:
912:
1.31 kristaps 913: static void
1.73 kristaps 914: print_man_foot(struct termp *p, const void *arg)
1.1 kristaps 915: {
1.43 kristaps 916: char buf[DATESIZ];
1.73 kristaps 917: const struct man_meta *meta;
918:
919: meta = (const struct man_meta *)arg;
1.1 kristaps 920:
1.52 kristaps 921: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 922:
1.72 kristaps 923: if (meta->rawdate)
924: strlcpy(buf, meta->rawdate, DATESIZ);
925: else
926: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 927:
1.69 joerg 928: term_vspace(p);
929: term_vspace(p);
1.1 kristaps 930: term_vspace(p);
931:
932: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.77 kristaps 933: p->rmargin = p->maxrmargin - term_strlen(p, buf);
1.1 kristaps 934: p->offset = 0;
1.85 kristaps 935:
936: /* term_strlen() can return zero. */
937: if (p->rmargin == p->maxrmargin)
938: p->rmargin--;
1.1 kristaps 939:
940: if (meta->source)
941: term_word(p, meta->source);
942: if (meta->source)
943: term_word(p, "");
944: term_flushln(p);
945:
946: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
947: p->offset = p->rmargin;
948: p->rmargin = p->maxrmargin;
949: p->flags &= ~TERMP_NOBREAK;
950:
951: term_word(p, buf);
952: term_flushln(p);
953: }
954:
955:
1.31 kristaps 956: static void
1.73 kristaps 957: print_man_head(struct termp *p, const void *arg)
1.1 kristaps 958: {
1.46 kristaps 959: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 960: size_t buflen, titlen;
1.73 kristaps 961: const struct man_meta *m;
962:
963: m = (const struct man_meta *)arg;
1.1 kristaps 964:
1.62 kristaps 965: /*
966: * Note that old groff would spit out some spaces before the
967: * header. We discontinue this strange behaviour, but at one
968: * point we did so here.
969: */
970:
1.1 kristaps 971: p->rmargin = p->maxrmargin;
1.58 kristaps 972:
1.1 kristaps 973: p->offset = 0;
1.46 kristaps 974: buf[0] = title[0] = '\0';
1.1 kristaps 975:
1.46 kristaps 976: if (m->vol)
977: strlcpy(buf, m->vol, BUFSIZ);
1.77 kristaps 978: buflen = term_strlen(p, buf);
1.1 kristaps 979:
1.64 kristaps 980: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.77 kristaps 981: titlen = term_strlen(p, title);
1.1 kristaps 982:
983: p->offset = 0;
1.57 kristaps 984: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77 kristaps 985: (p->maxrmargin -
986: term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57 kristaps 987: p->maxrmargin - buflen;
1.1 kristaps 988: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
989:
990: term_word(p, title);
991: term_flushln(p);
992:
993: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
994: p->offset = p->rmargin;
1.57 kristaps 995: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
996: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 997:
998: term_word(p, buf);
999: term_flushln(p);
1000:
1001: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 1002: if (p->rmargin + titlen <= p->maxrmargin) {
1003: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1004: p->offset = p->rmargin;
1005: p->rmargin = p->maxrmargin;
1006: term_word(p, title);
1007: term_flushln(p);
1008: }
1.1 kristaps 1009:
1010: p->rmargin = p->maxrmargin;
1011: p->offset = 0;
1012: p->flags &= ~TERMP_NOSPACE;
1.61 kristaps 1013:
1.62 kristaps 1014: /*
1015: * Groff likes to have some leading spaces before content. Well
1016: * that's fine by me.
1017: */
1018:
1.61 kristaps 1019: term_vspace(p);
1020: term_vspace(p);
1021: term_vspace(p);
1.1 kristaps 1022: }
CVSweb