Annotation of mandoc/man_term.c, Revision 1.110
1.110 ! kristaps 1: /* $Id: man_term.c,v 1.109 2011/05/17 14:38:34 kristaps Exp $ */
1.1 kristaps 2: /*
1.98 schwarze 3: * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.94 schwarze 4: * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
1.8 kristaps 7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 9: *
1.8 kristaps 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 17: */
1.55 kristaps 18: #ifdef HAVE_CONFIG_H
19: #include "config.h"
20: #endif
21:
1.28 kristaps 22: #include <sys/types.h>
23:
1.1 kristaps 24: #include <assert.h>
1.18 kristaps 25: #include <ctype.h>
1.1 kristaps 26: #include <stdio.h>
27: #include <stdlib.h>
28: #include <string.h>
29:
1.71 kristaps 30: #include "mandoc.h"
1.40 kristaps 31: #include "out.h"
1.36 kristaps 32: #include "man.h"
1.1 kristaps 33: #include "term.h"
1.36 kristaps 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.99 schwarze 128: { pre_ign, NULL, MAN_NOTEXT }, /* na */
1.56 kristaps 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)
1.109 kristaps 159: p->symtab = mchars_alloc();
1.36 kristaps 160:
161: n = man_node(man);
162: m = man_meta(man);
1.1 kristaps 163:
1.75 schwarze 164: term_begin(p, print_man_head, print_man_foot, m);
1.1 kristaps 165: p->flags |= TERMP_NOSPACE;
1.19 kristaps 166:
1.24 kristaps 167: mt.fl = 0;
1.77 kristaps 168: mt.lmargin = term_len(p, INDENT);
169: mt.offset = term_len(p, INDENT);
1.24 kristaps 170:
1.36 kristaps 171: if (n->child)
1.52 kristaps 172: print_man_nodelist(p, &mt, n->child, m);
1.73 kristaps 173:
174: term_end(p);
1.1 kristaps 175: }
176:
177:
1.77 kristaps 178: static size_t
179: a2height(const struct termp *p, const char *cp)
1.18 kristaps 180: {
1.40 kristaps 181: struct roffsu su;
1.18 kristaps 182:
1.77 kristaps 183: if ( ! a2roffsu(cp, &su, SCALE_VS))
184: SCALE_VS_INIT(&su, term_strlen(p, cp));
1.18 kristaps 185:
1.77 kristaps 186: return(term_vspan(p, &su));
1.18 kristaps 187: }
188:
189:
190: static int
1.77 kristaps 191: a2width(const struct termp *p, const char *cp)
1.38 kristaps 192: {
1.40 kristaps 193: struct roffsu su;
1.38 kristaps 194:
1.77 kristaps 195: if ( ! a2roffsu(cp, &su, SCALE_BU))
1.41 kristaps 196: return(-1);
1.40 kristaps 197:
1.77 kristaps 198: return((int)term_hspan(p, &su));
1.38 kristaps 199: }
200:
201:
1.39 kristaps 202: static void
203: print_bvspace(struct termp *p, const struct man_node *n)
1.18 kristaps 204: {
1.39 kristaps 205: term_newln(p);
1.101 schwarze 206:
207: if (n->body && n->body->child && MAN_TBL == n->body->child->type)
208: return;
1.18 kristaps 209:
1.39 kristaps 210: if (NULL == n->prev)
211: return;
1.18 kristaps 212:
1.39 kristaps 213: if (MAN_SS == n->prev->tok)
214: return;
215: if (MAN_SH == n->prev->tok)
216: return;
1.18 kristaps 217:
1.39 kristaps 218: term_vspace(p);
1.18 kristaps 219: }
220:
221:
1.3 kristaps 222: /* ARGSUSED */
1.1 kristaps 223: static int
1.29 kristaps 224: pre_ign(DECL_ARGS)
225: {
226:
227: return(0);
228: }
229:
230:
231: /* ARGSUSED */
232: static int
1.1 kristaps 233: pre_I(DECL_ARGS)
234: {
235:
1.52 kristaps 236: term_fontrepl(p, TERMFONT_UNDER);
1.19 kristaps 237: return(1);
238: }
239:
240:
241: /* ARGSUSED */
1.3 kristaps 242: static int
1.84 kristaps 243: pre_literal(DECL_ARGS)
1.19 kristaps 244: {
245:
1.81 kristaps 246: term_newln(p);
1.88 kristaps 247:
248: if (MAN_nf == n->tok)
1.84 kristaps 249: mt->fl |= MANT_LITERAL;
1.88 kristaps 250: else
1.84 kristaps 251: mt->fl &= ~MANT_LITERAL;
252:
1.99 schwarze 253: return(0);
1.19 kristaps 254: }
255:
256: /* ARGSUSED */
257: static int
1.88 kristaps 258: pre_alternate(DECL_ARGS)
1.3 kristaps 259: {
1.88 kristaps 260: enum termfont font[2];
261: const struct man_node *nn;
262: int savelit, i;
1.3 kristaps 263:
1.88 kristaps 264: switch (n->tok) {
265: case (MAN_RB):
266: font[0] = TERMFONT_NONE;
267: font[1] = TERMFONT_BOLD;
268: break;
269: case (MAN_RI):
270: font[0] = TERMFONT_NONE;
271: font[1] = TERMFONT_UNDER;
272: break;
273: case (MAN_BR):
274: font[0] = TERMFONT_BOLD;
275: font[1] = TERMFONT_NONE;
276: break;
277: case (MAN_BI):
278: font[0] = TERMFONT_BOLD;
279: font[1] = TERMFONT_UNDER;
280: break;
281: case (MAN_IR):
282: font[0] = TERMFONT_UNDER;
283: font[1] = TERMFONT_NONE;
284: break;
285: case (MAN_IB):
286: font[0] = TERMFONT_UNDER;
287: font[1] = TERMFONT_BOLD;
288: break;
289: default:
290: abort();
291: }
1.35 kristaps 292:
1.88 kristaps 293: savelit = MANT_LITERAL & mt->fl;
294: mt->fl &= ~MANT_LITERAL;
1.35 kristaps 295:
1.88 kristaps 296: for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
297: term_fontrepl(p, font[i]);
298: if (savelit && NULL == nn->next)
299: mt->fl |= MANT_LITERAL;
1.45 kristaps 300: print_man_node(p, mt, nn, m);
1.88 kristaps 301: if (nn->next)
1.4 kristaps 302: p->flags |= TERMP_NOSPACE;
1.3 kristaps 303: }
304:
305: return(0);
306: }
307:
308: /* ARGSUSED */
1.1 kristaps 309: static int
310: pre_B(DECL_ARGS)
311: {
312:
1.52 kristaps 313: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 314: return(1);
1.89 kristaps 315: }
316:
317: /* ARGSUSED */
318: static int
319: pre_ft(DECL_ARGS)
320: {
321: const char *cp;
322:
323: if (NULL == n->child) {
324: term_fontlast(p);
325: return(0);
326: }
327:
328: cp = n->child->string;
329: switch (*cp) {
330: case ('4'):
331: /* FALLTHROUGH */
332: case ('3'):
333: /* FALLTHROUGH */
334: case ('B'):
335: term_fontrepl(p, TERMFONT_BOLD);
336: break;
337: case ('2'):
338: /* FALLTHROUGH */
339: case ('I'):
340: term_fontrepl(p, TERMFONT_UNDER);
341: break;
342: case ('P'):
343: term_fontlast(p);
344: break;
345: case ('1'):
346: /* FALLTHROUGH */
347: case ('C'):
348: /* FALLTHROUGH */
349: case ('R'):
350: term_fontrepl(p, TERMFONT_NONE);
351: break;
352: default:
353: break;
354: }
355: return(0);
1.83 kristaps 356: }
357:
358: /* ARGSUSED */
359: static int
360: pre_in(DECL_ARGS)
361: {
362: int len, less;
363: size_t v;
364: const char *cp;
365:
366: term_newln(p);
367:
368: if (NULL == n->child) {
369: p->offset = mt->offset;
370: return(0);
371: }
372:
373: cp = n->child->string;
374: less = 0;
375:
376: if ('-' == *cp)
377: less = -1;
378: else if ('+' == *cp)
379: less = 1;
380: else
381: cp--;
382:
383: if ((len = a2width(p, ++cp)) < 0)
384: return(0);
385:
386: v = (size_t)len;
387:
388: if (less < 0)
389: p->offset -= p->offset > v ? v : p->offset;
390: else if (less > 0)
391: p->offset += v;
392: else
393: p->offset = v;
1.95 kristaps 394:
395: /* Don't let this creep beyond the right margin. */
396:
397: if (p->offset > p->rmargin)
398: p->offset = p->rmargin;
1.83 kristaps 399:
400: return(0);
1.1 kristaps 401: }
402:
403:
1.3 kristaps 404: /* ARGSUSED */
1.1 kristaps 405: static int
1.19 kristaps 406: pre_sp(DECL_ARGS)
407: {
1.77 kristaps 408: size_t i, len;
1.19 kristaps 409:
1.82 kristaps 410: switch (n->tok) {
411: case (MAN_br):
412: len = 0;
413: break;
414: default:
415: len = n->child ? a2height(p, n->child->string) : 1;
416: break;
417: }
1.38 kristaps 418:
1.19 kristaps 419: if (0 == len)
420: term_newln(p);
1.82 kristaps 421: for (i = 0; i < len; i++)
1.19 kristaps 422: term_vspace(p);
423:
1.15 kristaps 424: return(0);
425: }
426:
427:
428: /* ARGSUSED */
429: static int
1.19 kristaps 430: pre_HP(DECL_ARGS)
431: {
1.24 kristaps 432: size_t len;
433: int ival;
434: const struct man_node *nn;
1.19 kristaps 435:
1.20 kristaps 436: switch (n->type) {
437: case (MAN_BLOCK):
1.39 kristaps 438: print_bvspace(p, n);
1.24 kristaps 439: return(1);
1.20 kristaps 440: case (MAN_BODY):
441: p->flags |= TERMP_NOBREAK;
442: p->flags |= TERMP_TWOSPACE;
443: break;
444: default:
445: return(0);
446: }
447:
1.26 kristaps 448: len = mt->lmargin;
1.24 kristaps 449: ival = -1;
450:
451: /* Calculate offset. */
452:
1.39 kristaps 453: if (NULL != (nn = n->parent->head->child))
1.77 kristaps 454: if ((ival = a2width(p, nn->string)) >= 0)
1.24 kristaps 455: len = (size_t)ival;
456:
457: if (0 == len)
1.77 kristaps 458: len = term_len(p, 1);
1.24 kristaps 459:
1.26 kristaps 460: p->offset = mt->offset;
461: p->rmargin = mt->offset + len;
1.24 kristaps 462:
463: if (ival >= 0)
1.26 kristaps 464: mt->lmargin = (size_t)ival;
1.24 kristaps 465:
1.19 kristaps 466: return(1);
467: }
468:
469:
470: /* ARGSUSED */
1.20 kristaps 471: static void
472: post_HP(DECL_ARGS)
473: {
474:
475: switch (n->type) {
1.24 kristaps 476: case (MAN_BLOCK):
477: term_flushln(p);
478: break;
1.20 kristaps 479: case (MAN_BODY):
480: term_flushln(p);
481: p->flags &= ~TERMP_NOBREAK;
482: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 483: p->offset = mt->offset;
1.20 kristaps 484: p->rmargin = p->maxrmargin;
485: break;
486: default:
487: break;
488: }
489: }
490:
491:
492: /* ARGSUSED */
1.19 kristaps 493: static int
1.1 kristaps 494: pre_PP(DECL_ARGS)
495: {
496:
1.19 kristaps 497: switch (n->type) {
498: case (MAN_BLOCK):
1.77 kristaps 499: mt->lmargin = term_len(p, INDENT);
1.39 kristaps 500: print_bvspace(p, n);
1.19 kristaps 501: break;
502: default:
1.26 kristaps 503: p->offset = mt->offset;
1.19 kristaps 504: break;
505: }
506:
1.87 kristaps 507: return(MAN_HEAD != n->type);
1.1 kristaps 508: }
509:
510:
1.3 kristaps 511: /* ARGSUSED */
1.1 kristaps 512: static int
1.4 kristaps 513: pre_IP(DECL_ARGS)
514: {
1.22 kristaps 515: const struct man_node *nn;
516: size_t len;
1.94 schwarze 517: int savelit, ival;
1.18 kristaps 518:
1.22 kristaps 519: switch (n->type) {
520: case (MAN_BODY):
521: p->flags |= TERMP_NOLPAD;
522: p->flags |= TERMP_NOSPACE;
523: break;
524: case (MAN_HEAD):
525: p->flags |= TERMP_NOBREAK;
526: break;
1.23 kristaps 527: case (MAN_BLOCK):
1.39 kristaps 528: print_bvspace(p, n);
1.23 kristaps 529: /* FALLTHROUGH */
1.22 kristaps 530: default:
531: return(1);
532: }
1.18 kristaps 533:
1.26 kristaps 534: len = mt->lmargin;
1.22 kristaps 535: ival = -1;
1.4 kristaps 536:
1.94 schwarze 537: /* Calculate the offset from the optional second argument. */
1.22 kristaps 538: if (NULL != (nn = n->parent->head->child))
1.94 schwarze 539: if (NULL != (nn = nn->next))
1.77 kristaps 540: if ((ival = a2width(p, nn->string)) >= 0)
1.22 kristaps 541: len = (size_t)ival;
1.4 kristaps 542:
1.22 kristaps 543: switch (n->type) {
544: case (MAN_HEAD):
1.23 kristaps 545: /* Handle zero-width lengths. */
546: if (0 == len)
1.77 kristaps 547: len = term_len(p, 1);
1.23 kristaps 548:
1.26 kristaps 549: p->offset = mt->offset;
550: p->rmargin = mt->offset + len;
1.22 kristaps 551: if (ival < 0)
552: break;
1.18 kristaps 553:
1.24 kristaps 554: /* Set the saved left-margin. */
1.26 kristaps 555: mt->lmargin = (size_t)ival;
1.24 kristaps 556:
1.94 schwarze 557: savelit = MANT_LITERAL & mt->fl;
558: mt->fl &= ~MANT_LITERAL;
559:
560: if (n->child)
561: print_man_node(p, mt, n->child, m);
562:
563: if (savelit)
564: mt->fl |= MANT_LITERAL;
565:
1.22 kristaps 566: return(0);
1.23 kristaps 567: case (MAN_BODY):
1.26 kristaps 568: p->offset = mt->offset + len;
1.23 kristaps 569: p->rmargin = p->maxrmargin;
570: break;
1.22 kristaps 571: default:
572: break;
1.18 kristaps 573: }
574:
1.22 kristaps 575: return(1);
576: }
1.18 kristaps 577:
578:
1.22 kristaps 579: /* ARGSUSED */
580: static void
581: post_IP(DECL_ARGS)
582: {
1.4 kristaps 583:
1.22 kristaps 584: switch (n->type) {
585: case (MAN_HEAD):
586: term_flushln(p);
587: p->flags &= ~TERMP_NOBREAK;
588: p->rmargin = p->maxrmargin;
589: break;
590: case (MAN_BODY):
1.94 schwarze 591: term_newln(p);
1.22 kristaps 592: p->flags &= ~TERMP_NOLPAD;
593: break;
594: default:
595: break;
596: }
1.4 kristaps 597: }
598:
599:
600: /* ARGSUSED */
601: static int
1.1 kristaps 602: pre_TP(DECL_ARGS)
603: {
1.23 kristaps 604: const struct man_node *nn;
605: size_t len;
1.94 schwarze 606: int savelit, ival;
1.1 kristaps 607:
1.21 kristaps 608: switch (n->type) {
609: case (MAN_HEAD):
610: p->flags |= TERMP_NOBREAK;
611: break;
612: case (MAN_BODY):
613: p->flags |= TERMP_NOLPAD;
614: p->flags |= TERMP_NOSPACE;
1.23 kristaps 615: break;
616: case (MAN_BLOCK):
1.39 kristaps 617: print_bvspace(p, n);
1.23 kristaps 618: /* FALLTHROUGH */
619: default:
620: return(1);
621: }
622:
1.24 kristaps 623: len = (size_t)mt->lmargin;
1.23 kristaps 624: ival = -1;
625:
626: /* Calculate offset. */
627:
1.56 kristaps 628: if (NULL != (nn = n->parent->head->child)) {
629: while (nn && MAN_TEXT != nn->type)
630: nn = nn->next;
631: if (nn && nn->next)
1.77 kristaps 632: if ((ival = a2width(p, nn->string)) >= 0)
1.23 kristaps 633: len = (size_t)ival;
1.56 kristaps 634: }
1.23 kristaps 635:
636: switch (n->type) {
637: case (MAN_HEAD):
638: /* Handle zero-length properly. */
639: if (0 == len)
1.77 kristaps 640: len = term_len(p, 1);
1.23 kristaps 641:
1.26 kristaps 642: p->offset = mt->offset;
643: p->rmargin = mt->offset + len;
1.23 kristaps 644:
1.94 schwarze 645: savelit = MANT_LITERAL & mt->fl;
646: mt->fl &= ~MANT_LITERAL;
647:
1.23 kristaps 648: /* Don't print same-line elements. */
1.94 schwarze 649: for (nn = n->child; nn; nn = nn->next)
1.23 kristaps 650: if (nn->line > n->line)
1.45 kristaps 651: print_man_node(p, mt, nn, m);
1.24 kristaps 652:
1.94 schwarze 653: if (savelit)
654: mt->fl |= MANT_LITERAL;
655:
1.24 kristaps 656: if (ival >= 0)
1.26 kristaps 657: mt->lmargin = (size_t)ival;
1.24 kristaps 658:
1.23 kristaps 659: return(0);
660: case (MAN_BODY):
1.26 kristaps 661: p->offset = mt->offset + len;
1.23 kristaps 662: p->rmargin = p->maxrmargin;
1.21 kristaps 663: break;
664: default:
665: break;
666: }
1.16 kristaps 667:
1.21 kristaps 668: return(1);
669: }
1.1 kristaps 670:
671:
1.21 kristaps 672: /* ARGSUSED */
673: static void
674: post_TP(DECL_ARGS)
675: {
1.1 kristaps 676:
1.21 kristaps 677: switch (n->type) {
678: case (MAN_HEAD):
679: term_flushln(p);
680: p->flags &= ~TERMP_NOBREAK;
681: p->flags &= ~TERMP_TWOSPACE;
682: p->rmargin = p->maxrmargin;
683: break;
684: case (MAN_BODY):
1.94 schwarze 685: term_newln(p);
1.21 kristaps 686: p->flags &= ~TERMP_NOLPAD;
687: break;
688: default:
689: break;
690: }
1.1 kristaps 691: }
692:
693:
1.3 kristaps 694: /* ARGSUSED */
1.1 kristaps 695: static int
696: pre_SS(DECL_ARGS)
697: {
698:
1.19 kristaps 699: switch (n->type) {
700: case (MAN_BLOCK):
1.77 kristaps 701: mt->lmargin = term_len(p, INDENT);
702: mt->offset = term_len(p, INDENT);
1.24 kristaps 703: /* If following a prior empty `SS', no vspace. */
704: if (n->prev && MAN_SS == n->prev->tok)
705: if (NULL == n->prev->body->child)
706: break;
707: if (NULL == n->prev)
708: break;
709: term_vspace(p);
1.19 kristaps 710: break;
711: case (MAN_HEAD):
1.52 kristaps 712: term_fontrepl(p, TERMFONT_BOLD);
1.77 kristaps 713: p->offset = term_len(p, HALFINDENT);
1.19 kristaps 714: break;
1.24 kristaps 715: case (MAN_BODY):
1.26 kristaps 716: p->offset = mt->offset;
1.24 kristaps 717: break;
1.19 kristaps 718: default:
719: break;
720: }
721:
1.1 kristaps 722: return(1);
723: }
724:
725:
1.3 kristaps 726: /* ARGSUSED */
1.1 kristaps 727: static void
728: post_SS(DECL_ARGS)
729: {
730:
1.19 kristaps 731: switch (n->type) {
732: case (MAN_HEAD):
733: term_newln(p);
734: break;
1.24 kristaps 735: case (MAN_BODY):
736: term_newln(p);
737: break;
1.19 kristaps 738: default:
739: break;
740: }
1.1 kristaps 741: }
742:
743:
1.3 kristaps 744: /* ARGSUSED */
1.1 kristaps 745: static int
746: pre_SH(DECL_ARGS)
747: {
1.22 kristaps 748:
1.19 kristaps 749: switch (n->type) {
750: case (MAN_BLOCK):
1.77 kristaps 751: mt->lmargin = term_len(p, INDENT);
752: mt->offset = term_len(p, INDENT);
1.22 kristaps 753: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 754: if (n->prev && MAN_SH == n->prev->tok)
755: if (NULL == n->prev->body->child)
756: break;
1.61 kristaps 757: /* If the first macro, no vspae. */
758: if (NULL == n->prev)
759: break;
1.19 kristaps 760: term_vspace(p);
761: break;
762: case (MAN_HEAD):
1.52 kristaps 763: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 764: p->offset = 0;
765: break;
766: case (MAN_BODY):
1.26 kristaps 767: p->offset = mt->offset;
1.19 kristaps 768: break;
769: default:
770: break;
771: }
1.1 kristaps 772:
773: return(1);
774: }
775:
776:
1.3 kristaps 777: /* ARGSUSED */
1.1 kristaps 778: static void
779: post_SH(DECL_ARGS)
780: {
781:
1.19 kristaps 782: switch (n->type) {
783: case (MAN_HEAD):
784: term_newln(p);
785: break;
786: case (MAN_BODY):
787: term_newln(p);
788: break;
789: default:
790: break;
791: }
1.1 kristaps 792: }
793:
1.26 kristaps 794: /* ARGSUSED */
795: static int
796: pre_RS(DECL_ARGS)
797: {
1.110 ! kristaps 798: int ival;
! 799: size_t sz;
1.26 kristaps 800:
801: switch (n->type) {
802: case (MAN_BLOCK):
803: term_newln(p);
804: return(1);
805: case (MAN_HEAD):
806: return(0);
807: default:
808: break;
809: }
810:
1.110 ! kristaps 811: sz = term_len(p, INDENT);
1.26 kristaps 812:
1.110 ! kristaps 813: if (NULL != (n = n->parent->head->child))
! 814: if ((ival = a2width(p, n->string)) >= 0)
! 815: sz = (size_t)ival;
1.26 kristaps 816:
1.110 ! kristaps 817: mt->offset += sz;
1.26 kristaps 818: p->offset = mt->offset;
819:
820: return(1);
821: }
822:
823: /* ARGSUSED */
824: static void
825: post_RS(DECL_ARGS)
826: {
1.110 ! kristaps 827: int ival;
! 828: size_t sz;
1.26 kristaps 829:
830: switch (n->type) {
831: case (MAN_BLOCK):
1.110 ! kristaps 832: return;
1.59 kristaps 833: case (MAN_HEAD):
1.110 ! kristaps 834: return;
1.26 kristaps 835: default:
836: term_newln(p);
837: break;
838: }
1.110 ! kristaps 839:
! 840: sz = term_len(p, INDENT);
! 841:
! 842: if (NULL != (n = n->parent->head->child))
! 843: if ((ival = a2width(p, n->string)) >= 0)
! 844: sz = (size_t)ival;
! 845:
! 846: mt->offset = mt->offset < sz ? 0 : mt->offset - sz;
! 847: p->offset = mt->offset;
1.26 kristaps 848: }
849:
1.1 kristaps 850: static void
1.45 kristaps 851: print_man_node(DECL_ARGS)
1.1 kristaps 852: {
1.65 joerg 853: size_t rm, rmax;
1.54 kristaps 854: int c;
1.1 kristaps 855:
856: switch (n->type) {
857: case(MAN_TEXT):
1.97 kristaps 858: /*
859: * If we have a blank line, output a vertical space.
860: * If we have a space as the first character, break
861: * before printing the line's data.
862: */
1.96 kristaps 863: if ('\0' == *n->string) {
1.4 kristaps 864: term_vspace(p);
1.98 schwarze 865: return;
1.97 kristaps 866: } else if (' ' == *n->string && MAN_LINE & n->flags)
1.96 kristaps 867: term_newln(p);
1.54 kristaps 868:
1.4 kristaps 869: term_word(p, n->string);
1.52 kristaps 870:
1.97 kristaps 871: /*
872: * If we're in a literal context, make sure that words
873: * togehter on the same line stay together. This is a
874: * POST-printing call, so we check the NEXT word. Since
875: * -man doesn't have nested macros, we don't need to be
876: * more specific than this.
877: */
878: if (MANT_LITERAL & mt->fl &&
879: (NULL == n->next ||
880: n->next->line > n->line)) {
1.65 joerg 881: rm = p->rmargin;
882: rmax = p->maxrmargin;
1.60 kristaps 883: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19 kristaps 884: p->flags |= TERMP_NOSPACE;
885: term_flushln(p);
1.94 schwarze 886: p->flags &= ~TERMP_NOLPAD;
1.65 joerg 887: p->rmargin = rm;
888: p->maxrmargin = rmax;
1.19 kristaps 889: }
1.100 schwarze 890:
891: if (MAN_EOS & n->flags)
892: p->flags |= TERMP_SENTENCE;
1.102 kristaps 893: return;
894: case (MAN_EQN):
1.103 kristaps 895: term_word(p, n->eqn->data);
1.97 kristaps 896: return;
1.91 kristaps 897: case (MAN_TBL):
1.97 kristaps 898: /*
899: * Tables are preceded by a newline. Then process a
900: * table line, which will cause line termination,
901: */
1.93 kristaps 902: if (TBL_SPAN_FIRST & n->span->flags)
903: term_newln(p);
1.92 kristaps 904: term_tbl(p, n->span);
1.97 kristaps 905: return;
1.1 kristaps 906: default:
907: break;
908: }
909:
1.97 kristaps 910: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
911: term_fontrepl(p, TERMFONT_NONE);
912:
913: c = 1;
914: if (termacts[n->tok].pre)
915: c = (*termacts[n->tok].pre)(p, mt, n, m);
916:
1.1 kristaps 917: if (c && n->child)
1.52 kristaps 918: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 919:
1.97 kristaps 920: if (termacts[n->tok].post)
921: (*termacts[n->tok].post)(p, mt, n, m);
922: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
923: term_fontrepl(p, TERMFONT_NONE);
1.63 kristaps 924:
925: if (MAN_EOS & n->flags)
926: p->flags |= TERMP_SENTENCE;
1.1 kristaps 927: }
928:
929:
930: static void
1.52 kristaps 931: print_man_nodelist(DECL_ARGS)
1.1 kristaps 932: {
1.19 kristaps 933:
1.45 kristaps 934: print_man_node(p, mt, n, m);
1.1 kristaps 935: if ( ! n->next)
936: return;
1.52 kristaps 937: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 938: }
939:
940:
1.31 kristaps 941: static void
1.73 kristaps 942: print_man_foot(struct termp *p, const void *arg)
1.1 kristaps 943: {
1.73 kristaps 944: const struct man_meta *meta;
945:
946: meta = (const struct man_meta *)arg;
1.1 kristaps 947:
1.52 kristaps 948: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 949:
1.69 joerg 950: term_vspace(p);
951: term_vspace(p);
1.1 kristaps 952: term_vspace(p);
953:
954: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.104 schwarze 955: p->rmargin = p->maxrmargin - term_strlen(p, meta->date);
1.1 kristaps 956: p->offset = 0;
1.85 kristaps 957:
958: /* term_strlen() can return zero. */
959: if (p->rmargin == p->maxrmargin)
960: p->rmargin--;
1.1 kristaps 961:
962: if (meta->source)
963: term_word(p, meta->source);
964: if (meta->source)
965: term_word(p, "");
966: term_flushln(p);
967:
968: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
969: p->offset = p->rmargin;
970: p->rmargin = p->maxrmargin;
971: p->flags &= ~TERMP_NOBREAK;
972:
1.104 schwarze 973: term_word(p, meta->date);
1.1 kristaps 974: term_flushln(p);
975: }
976:
977:
1.31 kristaps 978: static void
1.73 kristaps 979: print_man_head(struct termp *p, const void *arg)
1.1 kristaps 980: {
1.46 kristaps 981: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 982: size_t buflen, titlen;
1.73 kristaps 983: const struct man_meta *m;
984:
985: m = (const struct man_meta *)arg;
1.1 kristaps 986:
1.62 kristaps 987: /*
988: * Note that old groff would spit out some spaces before the
989: * header. We discontinue this strange behaviour, but at one
990: * point we did so here.
991: */
992:
1.1 kristaps 993: p->rmargin = p->maxrmargin;
1.58 kristaps 994:
1.1 kristaps 995: p->offset = 0;
1.46 kristaps 996: buf[0] = title[0] = '\0';
1.1 kristaps 997:
1.46 kristaps 998: if (m->vol)
999: strlcpy(buf, m->vol, BUFSIZ);
1.77 kristaps 1000: buflen = term_strlen(p, buf);
1.1 kristaps 1001:
1.64 kristaps 1002: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.77 kristaps 1003: titlen = term_strlen(p, title);
1.1 kristaps 1004:
1005: p->offset = 0;
1.57 kristaps 1006: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77 kristaps 1007: (p->maxrmargin -
1008: term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57 kristaps 1009: p->maxrmargin - buflen;
1.1 kristaps 1010: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1011:
1012: term_word(p, title);
1013: term_flushln(p);
1014:
1015: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1016: p->offset = p->rmargin;
1.57 kristaps 1017: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
1018: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 1019:
1020: term_word(p, buf);
1021: term_flushln(p);
1022:
1023: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 1024: if (p->rmargin + titlen <= p->maxrmargin) {
1025: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1026: p->offset = p->rmargin;
1027: p->rmargin = p->maxrmargin;
1028: term_word(p, title);
1029: term_flushln(p);
1030: }
1.1 kristaps 1031:
1032: p->rmargin = p->maxrmargin;
1033: p->offset = 0;
1034: p->flags &= ~TERMP_NOSPACE;
1.61 kristaps 1035:
1.62 kristaps 1036: /*
1037: * Groff likes to have some leading spaces before content. Well
1038: * that's fine by me.
1039: */
1040:
1.61 kristaps 1041: term_vspace(p);
1042: term_vspace(p);
1043: term_vspace(p);
1.1 kristaps 1044: }
CVSweb