Annotation of mandoc/man_term.c, Revision 1.98
1.98 ! schwarze 1: /* $Id: man_term.c,v 1.97 2011/01/12 15:23:25 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 "chars.h"
35: #include "main.h"
1.1 kristaps 36:
1.18 kristaps 37: #define INDENT 7
38: #define HALFINDENT 3
39:
1.44 kristaps 40: /* FIXME: have PD set the default vspace width. */
41:
1.24 kristaps 42: struct mtermp {
43: int fl;
1.19 kristaps 44: #define MANT_LITERAL (1 << 0)
1.26 kristaps 45: /*
46: * Default amount to indent the left margin after leading text
47: * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
48: * indent). This needs to be saved because `HP' and so on, if
49: * not having a specified value, must default.
50: *
51: * Note that this is the indentation AFTER the left offset, so
52: * the total offset is usually offset + lmargin.
53: */
54: size_t lmargin;
55: /*
56: * The default offset, i.e., the amount between any text and the
57: * page boundary.
58: */
59: size_t offset;
1.24 kristaps 60: };
1.19 kristaps 61:
1.1 kristaps 62: #define DECL_ARGS struct termp *p, \
1.24 kristaps 63: struct mtermp *mt, \
1.1 kristaps 64: const struct man_node *n, \
65: const struct man_meta *m
66:
67: struct termact {
68: int (*pre)(DECL_ARGS);
69: void (*post)(DECL_ARGS);
1.56 kristaps 70: int flags;
71: #define MAN_NOTEXT (1 << 0) /* Never has text children. */
1.1 kristaps 72: };
73:
1.77 kristaps 74: static int a2width(const struct termp *, const char *);
75: static size_t a2height(const struct termp *, const char *);
1.39 kristaps 76:
1.52 kristaps 77: static void print_man_nodelist(DECL_ARGS);
1.45 kristaps 78: static void print_man_node(DECL_ARGS);
1.74 kristaps 79: static void print_man_head(struct termp *, const void *);
1.73 kristaps 80: static void print_man_foot(struct termp *, const void *);
1.39 kristaps 81: static void print_bvspace(struct termp *,
82: const struct man_node *);
83:
1.88 kristaps 84: static int pre_alternate(DECL_ARGS);
1.1 kristaps 85: static int pre_B(DECL_ARGS);
1.19 kristaps 86: static int pre_HP(DECL_ARGS);
1.1 kristaps 87: static int pre_I(DECL_ARGS);
1.4 kristaps 88: static int pre_IP(DECL_ARGS);
1.1 kristaps 89: static int pre_PP(DECL_ARGS);
1.26 kristaps 90: static int pre_RS(DECL_ARGS);
1.1 kristaps 91: static int pre_SH(DECL_ARGS);
92: static int pre_SS(DECL_ARGS);
93: static int pre_TP(DECL_ARGS);
1.29 kristaps 94: static int pre_ign(DECL_ARGS);
1.83 kristaps 95: static int pre_in(DECL_ARGS);
1.84 kristaps 96: static int pre_literal(DECL_ARGS);
1.19 kristaps 97: static int pre_sp(DECL_ARGS);
1.89 kristaps 98: static int pre_ft(DECL_ARGS);
1.1 kristaps 99:
1.22 kristaps 100: static void post_IP(DECL_ARGS);
1.20 kristaps 101: static void post_HP(DECL_ARGS);
1.26 kristaps 102: static void post_RS(DECL_ARGS);
1.1 kristaps 103: static void post_SH(DECL_ARGS);
104: static void post_SS(DECL_ARGS);
1.21 kristaps 105: static void post_TP(DECL_ARGS);
1.1 kristaps 106:
1.32 kristaps 107: static const struct termact termacts[MAN_MAX] = {
1.82 kristaps 108: { pre_sp, NULL, MAN_NOTEXT }, /* br */
1.56 kristaps 109: { NULL, NULL, 0 }, /* TH */
110: { pre_SH, post_SH, 0 }, /* SH */
111: { pre_SS, post_SS, 0 }, /* SS */
112: { pre_TP, post_TP, 0 }, /* TP */
113: { pre_PP, NULL, 0 }, /* LP */
114: { pre_PP, NULL, 0 }, /* PP */
115: { pre_PP, NULL, 0 }, /* P */
116: { pre_IP, post_IP, 0 }, /* IP */
117: { pre_HP, post_HP, 0 }, /* HP */
118: { NULL, NULL, 0 }, /* SM */
119: { pre_B, NULL, 0 }, /* SB */
1.88 kristaps 120: { pre_alternate, NULL, 0 }, /* BI */
121: { pre_alternate, NULL, 0 }, /* IB */
122: { pre_alternate, NULL, 0 }, /* BR */
123: { pre_alternate, NULL, 0 }, /* RB */
1.56 kristaps 124: { NULL, NULL, 0 }, /* R */
125: { pre_B, NULL, 0 }, /* B */
126: { pre_I, NULL, 0 }, /* I */
1.88 kristaps 127: { pre_alternate, NULL, 0 }, /* IR */
128: { pre_alternate, NULL, 0 }, /* RI */
1.56 kristaps 129: { NULL, NULL, MAN_NOTEXT }, /* na */
130: { pre_sp, NULL, MAN_NOTEXT }, /* sp */
1.84 kristaps 131: { pre_literal, NULL, 0 }, /* nf */
132: { pre_literal, NULL, 0 }, /* fi */
1.56 kristaps 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.89 kristaps 140: { pre_ft, NULL, MAN_NOTEXT }, /* ft */
1.1 kristaps 141: };
142:
143:
144:
1.31 kristaps 145: void
1.36 kristaps 146: terminal_man(void *arg, const struct man *man)
1.1 kristaps 147: {
1.36 kristaps 148: struct termp *p;
149: const struct man_node *n;
150: const struct man_meta *m;
151: struct mtermp mt;
152:
153: p = (struct termp *)arg;
154:
1.58 kristaps 155: p->overstep = 0;
1.65 joerg 156: p->maxrmargin = p->defrmargin;
1.77 kristaps 157: p->tabwidth = term_len(p, 5);
1.73 kristaps 158:
1.36 kristaps 159: if (NULL == p->symtab)
160: switch (p->enc) {
161: case (TERMENC_ASCII):
162: p->symtab = chars_init(CHARS_ASCII);
163: break;
164: default:
165: abort();
166: /* NOTREACHED */
167: }
168:
169: n = man_node(man);
170: m = man_meta(man);
1.1 kristaps 171:
1.75 schwarze 172: term_begin(p, print_man_head, print_man_foot, m);
1.1 kristaps 173: p->flags |= TERMP_NOSPACE;
1.19 kristaps 174:
1.24 kristaps 175: mt.fl = 0;
1.77 kristaps 176: mt.lmargin = term_len(p, INDENT);
177: mt.offset = term_len(p, INDENT);
1.24 kristaps 178:
1.36 kristaps 179: if (n->child)
1.52 kristaps 180: print_man_nodelist(p, &mt, n->child, m);
1.73 kristaps 181:
182: term_end(p);
1.1 kristaps 183: }
184:
185:
1.77 kristaps 186: static size_t
187: a2height(const struct termp *p, const char *cp)
1.18 kristaps 188: {
1.40 kristaps 189: struct roffsu su;
1.18 kristaps 190:
1.77 kristaps 191: if ( ! a2roffsu(cp, &su, SCALE_VS))
192: SCALE_VS_INIT(&su, term_strlen(p, cp));
1.18 kristaps 193:
1.77 kristaps 194: return(term_vspan(p, &su));
1.18 kristaps 195: }
196:
197:
198: static int
1.77 kristaps 199: a2width(const struct termp *p, const char *cp)
1.38 kristaps 200: {
1.40 kristaps 201: struct roffsu su;
1.38 kristaps 202:
1.77 kristaps 203: if ( ! a2roffsu(cp, &su, SCALE_BU))
1.41 kristaps 204: return(-1);
1.40 kristaps 205:
1.77 kristaps 206: return((int)term_hspan(p, &su));
1.38 kristaps 207: }
208:
209:
1.39 kristaps 210: static void
211: print_bvspace(struct termp *p, const struct man_node *n)
1.18 kristaps 212: {
1.39 kristaps 213: term_newln(p);
1.18 kristaps 214:
1.39 kristaps 215: if (NULL == n->prev)
216: return;
1.18 kristaps 217:
1.39 kristaps 218: if (MAN_SS == n->prev->tok)
219: return;
220: if (MAN_SH == n->prev->tok)
221: return;
1.18 kristaps 222:
1.39 kristaps 223: term_vspace(p);
1.18 kristaps 224: }
225:
226:
1.3 kristaps 227: /* ARGSUSED */
1.1 kristaps 228: static int
1.29 kristaps 229: pre_ign(DECL_ARGS)
230: {
231:
232: return(0);
233: }
234:
235:
236: /* ARGSUSED */
237: static int
1.1 kristaps 238: pre_I(DECL_ARGS)
239: {
240:
1.52 kristaps 241: term_fontrepl(p, TERMFONT_UNDER);
1.19 kristaps 242: return(1);
243: }
244:
245:
246: /* ARGSUSED */
1.3 kristaps 247: static int
1.84 kristaps 248: pre_literal(DECL_ARGS)
1.19 kristaps 249: {
250:
1.81 kristaps 251: term_newln(p);
1.88 kristaps 252:
253: if (MAN_nf == n->tok)
1.84 kristaps 254: mt->fl |= MANT_LITERAL;
1.88 kristaps 255: else
1.84 kristaps 256: mt->fl &= ~MANT_LITERAL;
257:
1.19 kristaps 258: return(1);
259: }
260:
261: /* ARGSUSED */
262: static int
1.88 kristaps 263: pre_alternate(DECL_ARGS)
1.3 kristaps 264: {
1.88 kristaps 265: enum termfont font[2];
266: const struct man_node *nn;
267: int savelit, i;
1.3 kristaps 268:
1.88 kristaps 269: switch (n->tok) {
270: case (MAN_RB):
271: font[0] = TERMFONT_NONE;
272: font[1] = TERMFONT_BOLD;
273: break;
274: case (MAN_RI):
275: font[0] = TERMFONT_NONE;
276: font[1] = TERMFONT_UNDER;
277: break;
278: case (MAN_BR):
279: font[0] = TERMFONT_BOLD;
280: font[1] = TERMFONT_NONE;
281: break;
282: case (MAN_BI):
283: font[0] = TERMFONT_BOLD;
284: font[1] = TERMFONT_UNDER;
285: break;
286: case (MAN_IR):
287: font[0] = TERMFONT_UNDER;
288: font[1] = TERMFONT_NONE;
289: break;
290: case (MAN_IB):
291: font[0] = TERMFONT_UNDER;
292: font[1] = TERMFONT_BOLD;
293: break;
294: default:
295: abort();
296: }
1.35 kristaps 297:
1.88 kristaps 298: savelit = MANT_LITERAL & mt->fl;
299: mt->fl &= ~MANT_LITERAL;
1.35 kristaps 300:
1.88 kristaps 301: for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
302: term_fontrepl(p, font[i]);
303: if (savelit && NULL == nn->next)
304: mt->fl |= MANT_LITERAL;
1.45 kristaps 305: print_man_node(p, mt, nn, m);
1.88 kristaps 306: if (nn->next)
1.4 kristaps 307: p->flags |= TERMP_NOSPACE;
1.3 kristaps 308: }
309:
310: return(0);
311: }
312:
313: /* ARGSUSED */
1.1 kristaps 314: static int
315: pre_B(DECL_ARGS)
316: {
317:
1.52 kristaps 318: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 319: return(1);
1.89 kristaps 320: }
321:
322: /* ARGSUSED */
323: static int
324: pre_ft(DECL_ARGS)
325: {
326: const char *cp;
327:
328: if (NULL == n->child) {
329: term_fontlast(p);
330: return(0);
331: }
332:
333: cp = n->child->string;
334: switch (*cp) {
335: case ('4'):
336: /* FALLTHROUGH */
337: case ('3'):
338: /* FALLTHROUGH */
339: case ('B'):
340: term_fontrepl(p, TERMFONT_BOLD);
341: break;
342: case ('2'):
343: /* FALLTHROUGH */
344: case ('I'):
345: term_fontrepl(p, TERMFONT_UNDER);
346: break;
347: case ('P'):
348: term_fontlast(p);
349: break;
350: case ('1'):
351: /* FALLTHROUGH */
352: case ('C'):
353: /* FALLTHROUGH */
354: case ('R'):
355: term_fontrepl(p, TERMFONT_NONE);
356: break;
357: default:
358: break;
359: }
360: return(0);
1.83 kristaps 361: }
362:
363: /* ARGSUSED */
364: static int
365: pre_in(DECL_ARGS)
366: {
367: int len, less;
368: size_t v;
369: const char *cp;
370:
371: term_newln(p);
372:
373: if (NULL == n->child) {
374: p->offset = mt->offset;
375: return(0);
376: }
377:
378: cp = n->child->string;
379: less = 0;
380:
381: if ('-' == *cp)
382: less = -1;
383: else if ('+' == *cp)
384: less = 1;
385: else
386: cp--;
387:
388: if ((len = a2width(p, ++cp)) < 0)
389: return(0);
390:
391: v = (size_t)len;
392:
393: if (less < 0)
394: p->offset -= p->offset > v ? v : p->offset;
395: else if (less > 0)
396: p->offset += v;
397: else
398: p->offset = v;
1.95 kristaps 399:
400: /* Don't let this creep beyond the right margin. */
401:
402: if (p->offset > p->rmargin)
403: p->offset = p->rmargin;
1.83 kristaps 404:
405: return(0);
1.1 kristaps 406: }
407:
408:
1.3 kristaps 409: /* ARGSUSED */
1.1 kristaps 410: static int
1.19 kristaps 411: pre_sp(DECL_ARGS)
412: {
1.77 kristaps 413: size_t i, len;
1.19 kristaps 414:
1.82 kristaps 415: switch (n->tok) {
416: case (MAN_br):
417: len = 0;
418: break;
419: default:
420: len = n->child ? a2height(p, n->child->string) : 1;
421: break;
422: }
1.38 kristaps 423:
1.19 kristaps 424: if (0 == len)
425: term_newln(p);
1.82 kristaps 426: for (i = 0; i < len; i++)
1.19 kristaps 427: term_vspace(p);
428:
1.15 kristaps 429: return(0);
430: }
431:
432:
433: /* ARGSUSED */
434: static int
1.19 kristaps 435: pre_HP(DECL_ARGS)
436: {
1.24 kristaps 437: size_t len;
438: int ival;
439: const struct man_node *nn;
1.19 kristaps 440:
1.20 kristaps 441: switch (n->type) {
442: case (MAN_BLOCK):
1.39 kristaps 443: print_bvspace(p, n);
1.24 kristaps 444: return(1);
1.20 kristaps 445: case (MAN_BODY):
446: p->flags |= TERMP_NOBREAK;
447: p->flags |= TERMP_TWOSPACE;
448: break;
449: default:
450: return(0);
451: }
452:
1.26 kristaps 453: len = mt->lmargin;
1.24 kristaps 454: ival = -1;
455:
456: /* Calculate offset. */
457:
1.39 kristaps 458: if (NULL != (nn = n->parent->head->child))
1.77 kristaps 459: if ((ival = a2width(p, nn->string)) >= 0)
1.24 kristaps 460: len = (size_t)ival;
461:
462: if (0 == len)
1.77 kristaps 463: len = term_len(p, 1);
1.24 kristaps 464:
1.26 kristaps 465: p->offset = mt->offset;
466: p->rmargin = mt->offset + len;
1.24 kristaps 467:
468: if (ival >= 0)
1.26 kristaps 469: mt->lmargin = (size_t)ival;
1.24 kristaps 470:
1.19 kristaps 471: return(1);
472: }
473:
474:
475: /* ARGSUSED */
1.20 kristaps 476: static void
477: post_HP(DECL_ARGS)
478: {
479:
480: switch (n->type) {
1.24 kristaps 481: case (MAN_BLOCK):
482: term_flushln(p);
483: break;
1.20 kristaps 484: case (MAN_BODY):
485: term_flushln(p);
486: p->flags &= ~TERMP_NOBREAK;
487: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 488: p->offset = mt->offset;
1.20 kristaps 489: p->rmargin = p->maxrmargin;
490: break;
491: default:
492: break;
493: }
494: }
495:
496:
497: /* ARGSUSED */
1.19 kristaps 498: static int
1.1 kristaps 499: pre_PP(DECL_ARGS)
500: {
501:
1.19 kristaps 502: switch (n->type) {
503: case (MAN_BLOCK):
1.77 kristaps 504: mt->lmargin = term_len(p, INDENT);
1.39 kristaps 505: print_bvspace(p, n);
1.19 kristaps 506: break;
507: default:
1.26 kristaps 508: p->offset = mt->offset;
1.19 kristaps 509: break;
510: }
511:
1.87 kristaps 512: return(MAN_HEAD != n->type);
1.1 kristaps 513: }
514:
515:
1.3 kristaps 516: /* ARGSUSED */
1.1 kristaps 517: static int
1.4 kristaps 518: pre_IP(DECL_ARGS)
519: {
1.22 kristaps 520: const struct man_node *nn;
521: size_t len;
1.94 schwarze 522: int savelit, ival;
1.18 kristaps 523:
1.22 kristaps 524: switch (n->type) {
525: case (MAN_BODY):
526: p->flags |= TERMP_NOLPAD;
527: p->flags |= TERMP_NOSPACE;
528: break;
529: case (MAN_HEAD):
530: p->flags |= TERMP_NOBREAK;
531: break;
1.23 kristaps 532: case (MAN_BLOCK):
1.39 kristaps 533: print_bvspace(p, n);
1.23 kristaps 534: /* FALLTHROUGH */
1.22 kristaps 535: default:
536: return(1);
537: }
1.18 kristaps 538:
1.26 kristaps 539: len = mt->lmargin;
1.22 kristaps 540: ival = -1;
1.4 kristaps 541:
1.94 schwarze 542: /* Calculate the offset from the optional second argument. */
1.22 kristaps 543: if (NULL != (nn = n->parent->head->child))
1.94 schwarze 544: if (NULL != (nn = nn->next))
1.77 kristaps 545: if ((ival = a2width(p, nn->string)) >= 0)
1.22 kristaps 546: len = (size_t)ival;
1.4 kristaps 547:
1.22 kristaps 548: switch (n->type) {
549: case (MAN_HEAD):
1.23 kristaps 550: /* Handle zero-width lengths. */
551: if (0 == len)
1.77 kristaps 552: len = term_len(p, 1);
1.23 kristaps 553:
1.26 kristaps 554: p->offset = mt->offset;
555: p->rmargin = mt->offset + len;
1.22 kristaps 556: if (ival < 0)
557: break;
1.18 kristaps 558:
1.24 kristaps 559: /* Set the saved left-margin. */
1.26 kristaps 560: mt->lmargin = (size_t)ival;
1.24 kristaps 561:
1.94 schwarze 562: savelit = MANT_LITERAL & mt->fl;
563: mt->fl &= ~MANT_LITERAL;
564:
565: if (n->child)
566: print_man_node(p, mt, n->child, m);
567:
568: if (savelit)
569: mt->fl |= MANT_LITERAL;
570:
1.22 kristaps 571: return(0);
1.23 kristaps 572: case (MAN_BODY):
1.26 kristaps 573: p->offset = mt->offset + len;
1.23 kristaps 574: p->rmargin = p->maxrmargin;
575: break;
1.22 kristaps 576: default:
577: break;
1.18 kristaps 578: }
579:
1.22 kristaps 580: return(1);
581: }
1.18 kristaps 582:
583:
1.22 kristaps 584: /* ARGSUSED */
585: static void
586: post_IP(DECL_ARGS)
587: {
1.4 kristaps 588:
1.22 kristaps 589: switch (n->type) {
590: case (MAN_HEAD):
591: term_flushln(p);
592: p->flags &= ~TERMP_NOBREAK;
593: p->rmargin = p->maxrmargin;
594: break;
595: case (MAN_BODY):
1.94 schwarze 596: term_newln(p);
1.22 kristaps 597: p->flags &= ~TERMP_NOLPAD;
598: break;
599: default:
600: break;
601: }
1.4 kristaps 602: }
603:
604:
605: /* ARGSUSED */
606: static int
1.1 kristaps 607: pre_TP(DECL_ARGS)
608: {
1.23 kristaps 609: const struct man_node *nn;
610: size_t len;
1.94 schwarze 611: int savelit, ival;
1.1 kristaps 612:
1.21 kristaps 613: switch (n->type) {
614: case (MAN_HEAD):
615: p->flags |= TERMP_NOBREAK;
616: break;
617: case (MAN_BODY):
618: p->flags |= TERMP_NOLPAD;
619: p->flags |= TERMP_NOSPACE;
1.23 kristaps 620: break;
621: case (MAN_BLOCK):
1.39 kristaps 622: print_bvspace(p, n);
1.23 kristaps 623: /* FALLTHROUGH */
624: default:
625: return(1);
626: }
627:
1.24 kristaps 628: len = (size_t)mt->lmargin;
1.23 kristaps 629: ival = -1;
630:
631: /* Calculate offset. */
632:
1.56 kristaps 633: if (NULL != (nn = n->parent->head->child)) {
634: while (nn && MAN_TEXT != nn->type)
635: nn = nn->next;
636: if (nn && nn->next)
1.77 kristaps 637: if ((ival = a2width(p, nn->string)) >= 0)
1.23 kristaps 638: len = (size_t)ival;
1.56 kristaps 639: }
1.23 kristaps 640:
641: switch (n->type) {
642: case (MAN_HEAD):
643: /* Handle zero-length properly. */
644: if (0 == len)
1.77 kristaps 645: len = term_len(p, 1);
1.23 kristaps 646:
1.26 kristaps 647: p->offset = mt->offset;
648: p->rmargin = mt->offset + len;
1.23 kristaps 649:
1.94 schwarze 650: savelit = MANT_LITERAL & mt->fl;
651: mt->fl &= ~MANT_LITERAL;
652:
1.23 kristaps 653: /* Don't print same-line elements. */
1.94 schwarze 654: for (nn = n->child; nn; nn = nn->next)
1.23 kristaps 655: if (nn->line > n->line)
1.45 kristaps 656: print_man_node(p, mt, nn, m);
1.24 kristaps 657:
1.94 schwarze 658: if (savelit)
659: mt->fl |= MANT_LITERAL;
660:
1.24 kristaps 661: if (ival >= 0)
1.26 kristaps 662: mt->lmargin = (size_t)ival;
1.24 kristaps 663:
1.23 kristaps 664: return(0);
665: case (MAN_BODY):
1.26 kristaps 666: p->offset = mt->offset + len;
1.23 kristaps 667: p->rmargin = p->maxrmargin;
1.21 kristaps 668: break;
669: default:
670: break;
671: }
1.16 kristaps 672:
1.21 kristaps 673: return(1);
674: }
1.1 kristaps 675:
676:
1.21 kristaps 677: /* ARGSUSED */
678: static void
679: post_TP(DECL_ARGS)
680: {
1.1 kristaps 681:
1.21 kristaps 682: switch (n->type) {
683: case (MAN_HEAD):
684: term_flushln(p);
685: p->flags &= ~TERMP_NOBREAK;
686: p->flags &= ~TERMP_TWOSPACE;
687: p->rmargin = p->maxrmargin;
688: break;
689: case (MAN_BODY):
1.94 schwarze 690: term_newln(p);
1.21 kristaps 691: p->flags &= ~TERMP_NOLPAD;
692: break;
693: default:
694: break;
695: }
1.1 kristaps 696: }
697:
698:
1.3 kristaps 699: /* ARGSUSED */
1.1 kristaps 700: static int
701: pre_SS(DECL_ARGS)
702: {
703:
1.19 kristaps 704: switch (n->type) {
705: case (MAN_BLOCK):
1.77 kristaps 706: mt->lmargin = term_len(p, INDENT);
707: mt->offset = term_len(p, INDENT);
1.24 kristaps 708: /* If following a prior empty `SS', no vspace. */
709: if (n->prev && MAN_SS == n->prev->tok)
710: if (NULL == n->prev->body->child)
711: break;
712: if (NULL == n->prev)
713: break;
714: term_vspace(p);
1.19 kristaps 715: break;
716: case (MAN_HEAD):
1.52 kristaps 717: term_fontrepl(p, TERMFONT_BOLD);
1.77 kristaps 718: p->offset = term_len(p, HALFINDENT);
1.19 kristaps 719: break;
1.24 kristaps 720: case (MAN_BODY):
1.26 kristaps 721: p->offset = mt->offset;
1.24 kristaps 722: break;
1.19 kristaps 723: default:
724: break;
725: }
726:
1.1 kristaps 727: return(1);
728: }
729:
730:
1.3 kristaps 731: /* ARGSUSED */
1.1 kristaps 732: static void
733: post_SS(DECL_ARGS)
734: {
735:
1.19 kristaps 736: switch (n->type) {
737: case (MAN_HEAD):
738: term_newln(p);
739: break;
1.24 kristaps 740: case (MAN_BODY):
741: term_newln(p);
742: break;
1.19 kristaps 743: default:
744: break;
745: }
1.1 kristaps 746: }
747:
748:
1.3 kristaps 749: /* ARGSUSED */
1.1 kristaps 750: static int
751: pre_SH(DECL_ARGS)
752: {
1.22 kristaps 753:
1.19 kristaps 754: switch (n->type) {
755: case (MAN_BLOCK):
1.77 kristaps 756: mt->lmargin = term_len(p, INDENT);
757: mt->offset = term_len(p, INDENT);
1.22 kristaps 758: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 759: if (n->prev && MAN_SH == n->prev->tok)
760: if (NULL == n->prev->body->child)
761: break;
1.61 kristaps 762: /* If the first macro, no vspae. */
763: if (NULL == n->prev)
764: break;
1.19 kristaps 765: term_vspace(p);
766: break;
767: case (MAN_HEAD):
1.52 kristaps 768: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 769: p->offset = 0;
770: break;
771: case (MAN_BODY):
1.26 kristaps 772: p->offset = mt->offset;
1.19 kristaps 773: break;
774: default:
775: break;
776: }
1.1 kristaps 777:
778: return(1);
779: }
780:
781:
1.3 kristaps 782: /* ARGSUSED */
1.1 kristaps 783: static void
784: post_SH(DECL_ARGS)
785: {
786:
1.19 kristaps 787: switch (n->type) {
788: case (MAN_HEAD):
789: term_newln(p);
790: break;
791: case (MAN_BODY):
792: term_newln(p);
793: break;
794: default:
795: break;
796: }
1.1 kristaps 797: }
798:
799:
1.26 kristaps 800: /* ARGSUSED */
801: static int
802: pre_RS(DECL_ARGS)
803: {
804: const struct man_node *nn;
805: int ival;
806:
807: switch (n->type) {
808: case (MAN_BLOCK):
809: term_newln(p);
810: return(1);
811: case (MAN_HEAD):
812: return(0);
813: default:
814: break;
815: }
816:
817: if (NULL == (nn = n->parent->head->child)) {
1.77 kristaps 818: mt->offset = mt->lmargin + term_len(p, INDENT);
1.26 kristaps 819: p->offset = mt->offset;
820: return(1);
821: }
822:
1.77 kristaps 823: if ((ival = a2width(p, nn->string)) < 0)
1.26 kristaps 824: return(1);
825:
1.77 kristaps 826: mt->offset = term_len(p, INDENT) + (size_t)ival;
1.26 kristaps 827: p->offset = mt->offset;
828:
829: return(1);
830: }
831:
832:
833: /* ARGSUSED */
834: static void
835: post_RS(DECL_ARGS)
836: {
837:
838: switch (n->type) {
839: case (MAN_BLOCK):
1.77 kristaps 840: mt->offset = mt->lmargin = term_len(p, INDENT);
1.59 kristaps 841: break;
842: case (MAN_HEAD):
1.26 kristaps 843: break;
844: default:
845: term_newln(p);
1.77 kristaps 846: p->offset = term_len(p, INDENT);
1.26 kristaps 847: break;
848: }
849: }
850:
851:
1.1 kristaps 852: static void
1.45 kristaps 853: print_man_node(DECL_ARGS)
1.1 kristaps 854: {
1.65 joerg 855: size_t rm, rmax;
1.54 kristaps 856: int c;
1.1 kristaps 857:
858: switch (n->type) {
859: case(MAN_TEXT):
1.97 kristaps 860: /*
861: * If we have a blank line, output a vertical space.
862: * If we have a space as the first character, break
863: * before printing the line's data.
864: */
1.96 kristaps 865: if ('\0' == *n->string) {
1.4 kristaps 866: term_vspace(p);
1.98 ! schwarze 867: return;
1.97 kristaps 868: } else if (' ' == *n->string && MAN_LINE & n->flags)
1.96 kristaps 869: term_newln(p);
1.54 kristaps 870:
1.4 kristaps 871: term_word(p, n->string);
1.52 kristaps 872:
1.97 kristaps 873: /*
874: * If we're in a literal context, make sure that words
875: * togehter on the same line stay together. This is a
876: * POST-printing call, so we check the NEXT word. Since
877: * -man doesn't have nested macros, we don't need to be
878: * more specific than this.
879: */
880: if (MANT_LITERAL & mt->fl &&
881: (NULL == n->next ||
882: n->next->line > n->line)) {
1.65 joerg 883: rm = p->rmargin;
884: rmax = p->maxrmargin;
1.60 kristaps 885: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19 kristaps 886: p->flags |= TERMP_NOSPACE;
887: term_flushln(p);
1.94 schwarze 888: p->flags &= ~TERMP_NOLPAD;
1.65 joerg 889: p->rmargin = rm;
890: p->maxrmargin = rmax;
1.19 kristaps 891: }
1.97 kristaps 892: return;
1.91 kristaps 893: case (MAN_TBL):
1.97 kristaps 894: /*
895: * Tables are preceded by a newline. Then process a
896: * table line, which will cause line termination,
897: */
1.93 kristaps 898: if (TBL_SPAN_FIRST & n->span->flags)
899: term_newln(p);
1.92 kristaps 900: term_tbl(p, n->span);
1.97 kristaps 901: return;
1.1 kristaps 902: default:
903: break;
904: }
905:
1.97 kristaps 906: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
907: term_fontrepl(p, TERMFONT_NONE);
908:
909: c = 1;
910: if (termacts[n->tok].pre)
911: c = (*termacts[n->tok].pre)(p, mt, n, m);
912:
1.1 kristaps 913: if (c && n->child)
1.52 kristaps 914: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 915:
1.97 kristaps 916: if (termacts[n->tok].post)
917: (*termacts[n->tok].post)(p, mt, n, m);
918: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
919: term_fontrepl(p, TERMFONT_NONE);
1.63 kristaps 920:
921: if (MAN_EOS & n->flags)
922: p->flags |= TERMP_SENTENCE;
1.1 kristaps 923: }
924:
925:
926: static void
1.52 kristaps 927: print_man_nodelist(DECL_ARGS)
1.1 kristaps 928: {
1.19 kristaps 929:
1.45 kristaps 930: print_man_node(p, mt, n, m);
1.1 kristaps 931: if ( ! n->next)
932: return;
1.52 kristaps 933: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 934: }
935:
936:
1.31 kristaps 937: static void
1.73 kristaps 938: print_man_foot(struct termp *p, const void *arg)
1.1 kristaps 939: {
1.43 kristaps 940: char buf[DATESIZ];
1.73 kristaps 941: const struct man_meta *meta;
942:
943: meta = (const struct man_meta *)arg;
1.1 kristaps 944:
1.52 kristaps 945: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 946:
1.72 kristaps 947: if (meta->rawdate)
948: strlcpy(buf, meta->rawdate, DATESIZ);
949: else
950: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 951:
1.69 joerg 952: term_vspace(p);
953: term_vspace(p);
1.1 kristaps 954: term_vspace(p);
955:
956: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.77 kristaps 957: p->rmargin = p->maxrmargin - term_strlen(p, buf);
1.1 kristaps 958: p->offset = 0;
1.85 kristaps 959:
960: /* term_strlen() can return zero. */
961: if (p->rmargin == p->maxrmargin)
962: p->rmargin--;
1.1 kristaps 963:
964: if (meta->source)
965: term_word(p, meta->source);
966: if (meta->source)
967: term_word(p, "");
968: term_flushln(p);
969:
970: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
971: p->offset = p->rmargin;
972: p->rmargin = p->maxrmargin;
973: p->flags &= ~TERMP_NOBREAK;
974:
975: term_word(p, buf);
976: term_flushln(p);
977: }
978:
979:
1.31 kristaps 980: static void
1.73 kristaps 981: print_man_head(struct termp *p, const void *arg)
1.1 kristaps 982: {
1.46 kristaps 983: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 984: size_t buflen, titlen;
1.73 kristaps 985: const struct man_meta *m;
986:
987: m = (const struct man_meta *)arg;
1.1 kristaps 988:
1.62 kristaps 989: /*
990: * Note that old groff would spit out some spaces before the
991: * header. We discontinue this strange behaviour, but at one
992: * point we did so here.
993: */
994:
1.1 kristaps 995: p->rmargin = p->maxrmargin;
1.58 kristaps 996:
1.1 kristaps 997: p->offset = 0;
1.46 kristaps 998: buf[0] = title[0] = '\0';
1.1 kristaps 999:
1.46 kristaps 1000: if (m->vol)
1001: strlcpy(buf, m->vol, BUFSIZ);
1.77 kristaps 1002: buflen = term_strlen(p, buf);
1.1 kristaps 1003:
1.64 kristaps 1004: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.77 kristaps 1005: titlen = term_strlen(p, title);
1.1 kristaps 1006:
1007: p->offset = 0;
1.57 kristaps 1008: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77 kristaps 1009: (p->maxrmargin -
1010: term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57 kristaps 1011: p->maxrmargin - buflen;
1.1 kristaps 1012: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1013:
1014: term_word(p, title);
1015: term_flushln(p);
1016:
1017: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1018: p->offset = p->rmargin;
1.57 kristaps 1019: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
1020: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 1021:
1022: term_word(p, buf);
1023: term_flushln(p);
1024:
1025: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 1026: if (p->rmargin + titlen <= p->maxrmargin) {
1027: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1028: p->offset = p->rmargin;
1029: p->rmargin = p->maxrmargin;
1030: term_word(p, title);
1031: term_flushln(p);
1032: }
1.1 kristaps 1033:
1034: p->rmargin = p->maxrmargin;
1035: p->offset = 0;
1036: p->flags &= ~TERMP_NOSPACE;
1.61 kristaps 1037:
1.62 kristaps 1038: /*
1039: * Groff likes to have some leading spaces before content. Well
1040: * that's fine by me.
1041: */
1042:
1.61 kristaps 1043: term_vspace(p);
1044: term_vspace(p);
1045: term_vspace(p);
1.1 kristaps 1046: }
CVSweb