Annotation of mandoc/man_term.c, Revision 1.79
1.79 ! kristaps 1: /* $Id: man_term.c,v 1.78 2010/06/26 15:36:37 kristaps Exp $ */
1.1 kristaps 2: /*
1.76 kristaps 3: * Copyright (c) 2008, 2009 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.1 kristaps 83: static int pre_B(DECL_ARGS);
1.3 kristaps 84: static int pre_BI(DECL_ARGS);
1.19 kristaps 85: static int pre_HP(DECL_ARGS);
1.1 kristaps 86: static int pre_I(DECL_ARGS);
1.4 kristaps 87: static int pre_IP(DECL_ARGS);
1.1 kristaps 88: static int pre_PP(DECL_ARGS);
1.3 kristaps 89: static int pre_RB(DECL_ARGS);
90: static int pre_RI(DECL_ARGS);
1.26 kristaps 91: static int pre_RS(DECL_ARGS);
1.1 kristaps 92: static int pre_SH(DECL_ARGS);
93: static int pre_SS(DECL_ARGS);
94: static int pre_TP(DECL_ARGS);
1.19 kristaps 95: static int pre_br(DECL_ARGS);
96: static int pre_fi(DECL_ARGS);
1.29 kristaps 97: static int pre_ign(DECL_ARGS);
1.19 kristaps 98: static int pre_nf(DECL_ARGS);
99: static int pre_sp(DECL_ARGS);
1.1 kristaps 100:
1.22 kristaps 101: static void post_IP(DECL_ARGS);
1.20 kristaps 102: static void post_HP(DECL_ARGS);
1.26 kristaps 103: static void post_RS(DECL_ARGS);
1.1 kristaps 104: static void post_SH(DECL_ARGS);
105: static void post_SS(DECL_ARGS);
1.21 kristaps 106: static void post_TP(DECL_ARGS);
1.1 kristaps 107:
1.32 kristaps 108: static const struct termact termacts[MAN_MAX] = {
1.56 kristaps 109: { pre_br, NULL, MAN_NOTEXT }, /* br */
110: { NULL, NULL, 0 }, /* TH */
111: { pre_SH, post_SH, 0 }, /* SH */
112: { pre_SS, post_SS, 0 }, /* SS */
113: { pre_TP, post_TP, 0 }, /* TP */
114: { pre_PP, NULL, 0 }, /* LP */
115: { pre_PP, NULL, 0 }, /* PP */
116: { pre_PP, NULL, 0 }, /* P */
117: { pre_IP, post_IP, 0 }, /* IP */
118: { pre_HP, post_HP, 0 }, /* HP */
119: { NULL, NULL, 0 }, /* SM */
120: { pre_B, NULL, 0 }, /* SB */
121: { pre_BI, NULL, 0 }, /* BI */
122: { pre_BI, NULL, 0 }, /* IB */
123: { pre_RB, NULL, 0 }, /* BR */
124: { pre_RB, NULL, 0 }, /* RB */
125: { NULL, NULL, 0 }, /* R */
126: { pre_B, NULL, 0 }, /* B */
127: { pre_I, NULL, 0 }, /* I */
128: { pre_RI, NULL, 0 }, /* IR */
129: { pre_RI, NULL, 0 }, /* RI */
130: { NULL, NULL, MAN_NOTEXT }, /* na */
131: { pre_I, NULL, 0 }, /* i */
132: { pre_sp, NULL, MAN_NOTEXT }, /* sp */
133: { pre_nf, NULL, 0 }, /* nf */
134: { pre_fi, NULL, 0 }, /* fi */
135: { NULL, NULL, 0 }, /* r */
136: { NULL, NULL, 0 }, /* RE */
137: { pre_RS, post_RS, 0 }, /* RS */
138: { pre_ign, NULL, 0 }, /* DT */
139: { pre_ign, NULL, 0 }, /* UC */
140: { pre_ign, NULL, 0 }, /* PD */
1.57 kristaps 141: { pre_sp, NULL, MAN_NOTEXT }, /* Sp */
142: { pre_nf, NULL, 0 }, /* Vb */
143: { pre_fi, NULL, 0 }, /* Ve */
1.70 joerg 144: { pre_ign, NULL, 0 }, /* AT */
1.1 kristaps 145: };
146:
147:
148:
1.31 kristaps 149: void
1.36 kristaps 150: terminal_man(void *arg, const struct man *man)
1.1 kristaps 151: {
1.36 kristaps 152: struct termp *p;
153: const struct man_node *n;
154: const struct man_meta *m;
155: struct mtermp mt;
156:
157: p = (struct termp *)arg;
158:
1.58 kristaps 159: p->overstep = 0;
1.65 joerg 160: p->maxrmargin = p->defrmargin;
1.77 kristaps 161: p->tabwidth = term_len(p, 5);
1.73 kristaps 162:
1.36 kristaps 163: if (NULL == p->symtab)
164: switch (p->enc) {
165: case (TERMENC_ASCII):
166: p->symtab = chars_init(CHARS_ASCII);
167: break;
168: default:
169: abort();
170: /* NOTREACHED */
171: }
172:
173: n = man_node(man);
174: m = man_meta(man);
1.1 kristaps 175:
1.75 schwarze 176: term_begin(p, print_man_head, print_man_foot, m);
1.1 kristaps 177: p->flags |= TERMP_NOSPACE;
1.19 kristaps 178:
1.24 kristaps 179: mt.fl = 0;
1.77 kristaps 180: mt.lmargin = term_len(p, INDENT);
181: mt.offset = term_len(p, INDENT);
1.24 kristaps 182:
1.36 kristaps 183: if (n->child)
1.52 kristaps 184: print_man_nodelist(p, &mt, n->child, m);
1.73 kristaps 185:
186: term_end(p);
1.1 kristaps 187: }
188:
189:
1.77 kristaps 190: static size_t
191: a2height(const struct termp *p, const char *cp)
1.18 kristaps 192: {
1.40 kristaps 193: struct roffsu su;
1.18 kristaps 194:
1.77 kristaps 195: if ( ! a2roffsu(cp, &su, SCALE_VS))
196: SCALE_VS_INIT(&su, term_strlen(p, cp));
1.18 kristaps 197:
1.77 kristaps 198: return(term_vspan(p, &su));
1.18 kristaps 199: }
200:
201:
202: static int
1.77 kristaps 203: a2width(const struct termp *p, const char *cp)
1.38 kristaps 204: {
1.40 kristaps 205: struct roffsu su;
1.38 kristaps 206:
1.77 kristaps 207: if ( ! a2roffsu(cp, &su, SCALE_BU))
1.41 kristaps 208: return(-1);
1.40 kristaps 209:
1.77 kristaps 210: return((int)term_hspan(p, &su));
1.38 kristaps 211: }
212:
213:
1.39 kristaps 214: static void
215: print_bvspace(struct termp *p, const struct man_node *n)
1.18 kristaps 216: {
1.39 kristaps 217: term_newln(p);
1.18 kristaps 218:
1.39 kristaps 219: if (NULL == n->prev)
220: return;
1.18 kristaps 221:
1.39 kristaps 222: if (MAN_SS == n->prev->tok)
223: return;
224: if (MAN_SH == n->prev->tok)
225: return;
1.18 kristaps 226:
1.39 kristaps 227: term_vspace(p);
1.18 kristaps 228: }
229:
230:
1.3 kristaps 231: /* ARGSUSED */
1.1 kristaps 232: static int
1.29 kristaps 233: pre_ign(DECL_ARGS)
234: {
235:
236: return(0);
237: }
238:
239:
240: /* ARGSUSED */
241: static int
1.1 kristaps 242: pre_I(DECL_ARGS)
243: {
244:
1.52 kristaps 245: term_fontrepl(p, TERMFONT_UNDER);
1.19 kristaps 246: return(1);
247: }
248:
249:
250: /* ARGSUSED */
1.3 kristaps 251: static int
1.19 kristaps 252: pre_fi(DECL_ARGS)
253: {
254:
1.24 kristaps 255: mt->fl &= ~MANT_LITERAL;
1.19 kristaps 256: return(1);
257: }
258:
259:
260: /* ARGSUSED */
261: static int
262: pre_nf(DECL_ARGS)
263: {
264:
1.24 kristaps 265: mt->fl |= MANT_LITERAL;
1.57 kristaps 266: return(MAN_Vb != n->tok);
1.19 kristaps 267: }
268:
269:
270: /* ARGSUSED */
271: static int
1.35 kristaps 272: pre_RB(DECL_ARGS)
1.3 kristaps 273: {
274: const struct man_node *nn;
275: int i;
276:
277: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 278: if (i % 2 && MAN_RB == n->tok)
1.52 kristaps 279: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 280: else if ( ! (i % 2) && MAN_RB != n->tok)
1.52 kristaps 281: term_fontrepl(p, TERMFONT_BOLD);
282: else
283: term_fontrepl(p, TERMFONT_NONE);
1.35 kristaps 284:
1.4 kristaps 285: if (i > 0)
286: p->flags |= TERMP_NOSPACE;
1.35 kristaps 287:
1.45 kristaps 288: print_man_node(p, mt, nn, m);
1.3 kristaps 289: }
290: return(0);
291: }
292:
293:
294: /* ARGSUSED */
295: static int
296: pre_RI(DECL_ARGS)
297: {
298: const struct man_node *nn;
299: int i;
300:
301: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.49 kristaps 302: if (i % 2 && MAN_RI == n->tok)
1.52 kristaps 303: term_fontrepl(p, TERMFONT_UNDER);
1.49 kristaps 304: else if ( ! (i % 2) && MAN_RI != n->tok)
1.52 kristaps 305: term_fontrepl(p, TERMFONT_UNDER);
306: else
307: term_fontrepl(p, TERMFONT_NONE);
1.49 kristaps 308:
1.4 kristaps 309: if (i > 0)
310: p->flags |= TERMP_NOSPACE;
1.52 kristaps 311:
1.45 kristaps 312: print_man_node(p, mt, nn, m);
1.3 kristaps 313: }
314: return(0);
315: }
316:
317:
318: /* ARGSUSED */
319: static int
320: pre_BI(DECL_ARGS)
321: {
1.35 kristaps 322: const struct man_node *nn;
323: int i;
1.3 kristaps 324:
325: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 326: if (i % 2 && MAN_BI == n->tok)
1.52 kristaps 327: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 328: else if (i % 2)
1.52 kristaps 329: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 330: else if (MAN_BI == n->tok)
1.52 kristaps 331: term_fontrepl(p, TERMFONT_BOLD);
1.30 kristaps 332: else
1.52 kristaps 333: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 334:
335: if (i)
1.4 kristaps 336: p->flags |= TERMP_NOSPACE;
1.52 kristaps 337:
1.45 kristaps 338: print_man_node(p, mt, nn, m);
1.3 kristaps 339: }
340: return(0);
341: }
342:
343:
344: /* ARGSUSED */
1.1 kristaps 345: static int
346: pre_B(DECL_ARGS)
347: {
348:
1.52 kristaps 349: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 350: return(1);
351: }
352:
353:
1.3 kristaps 354: /* ARGSUSED */
1.1 kristaps 355: static int
1.19 kristaps 356: pre_sp(DECL_ARGS)
357: {
1.77 kristaps 358: size_t i, len;
1.19 kristaps 359:
1.77 kristaps 360: len = n->child ?
361: a2height(p, n->child->string) : term_len(p, 1);
1.38 kristaps 362:
1.19 kristaps 363: if (0 == len)
364: term_newln(p);
1.61 kristaps 365: for (i = 0; i <= len; i++)
1.19 kristaps 366: term_vspace(p);
367:
368: return(0);
369: }
370:
371:
372: /* ARGSUSED */
373: static int
1.15 kristaps 374: pre_br(DECL_ARGS)
375: {
376:
377: term_newln(p);
378: return(0);
379: }
380:
381:
382: /* ARGSUSED */
383: static int
1.19 kristaps 384: pre_HP(DECL_ARGS)
385: {
1.24 kristaps 386: size_t len;
387: int ival;
388: const struct man_node *nn;
1.19 kristaps 389:
1.20 kristaps 390: switch (n->type) {
391: case (MAN_BLOCK):
1.39 kristaps 392: print_bvspace(p, n);
1.24 kristaps 393: return(1);
1.20 kristaps 394: case (MAN_BODY):
395: p->flags |= TERMP_NOBREAK;
396: p->flags |= TERMP_TWOSPACE;
397: break;
398: default:
399: return(0);
400: }
401:
1.26 kristaps 402: len = mt->lmargin;
1.24 kristaps 403: ival = -1;
404:
405: /* Calculate offset. */
406:
1.39 kristaps 407: if (NULL != (nn = n->parent->head->child))
1.77 kristaps 408: if ((ival = a2width(p, nn->string)) >= 0)
1.24 kristaps 409: len = (size_t)ival;
410:
411: if (0 == len)
1.77 kristaps 412: len = term_len(p, 1);
1.24 kristaps 413:
1.26 kristaps 414: p->offset = mt->offset;
415: p->rmargin = mt->offset + len;
1.24 kristaps 416:
417: if (ival >= 0)
1.26 kristaps 418: mt->lmargin = (size_t)ival;
1.24 kristaps 419:
1.19 kristaps 420: return(1);
421: }
422:
423:
424: /* ARGSUSED */
1.20 kristaps 425: static void
426: post_HP(DECL_ARGS)
427: {
428:
429: switch (n->type) {
1.24 kristaps 430: case (MAN_BLOCK):
431: term_flushln(p);
432: break;
1.20 kristaps 433: case (MAN_BODY):
434: term_flushln(p);
435: p->flags &= ~TERMP_NOBREAK;
436: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 437: p->offset = mt->offset;
1.20 kristaps 438: p->rmargin = p->maxrmargin;
439: break;
440: default:
441: break;
442: }
443: }
444:
445:
446: /* ARGSUSED */
1.19 kristaps 447: static int
1.1 kristaps 448: pre_PP(DECL_ARGS)
449: {
450:
1.19 kristaps 451: switch (n->type) {
452: case (MAN_BLOCK):
1.77 kristaps 453: mt->lmargin = term_len(p, INDENT);
1.39 kristaps 454: print_bvspace(p, n);
1.19 kristaps 455: break;
456: default:
1.26 kristaps 457: p->offset = mt->offset;
1.19 kristaps 458: break;
459: }
460:
461: return(1);
1.1 kristaps 462: }
463:
464:
1.3 kristaps 465: /* ARGSUSED */
1.1 kristaps 466: static int
1.4 kristaps 467: pre_IP(DECL_ARGS)
468: {
1.22 kristaps 469: const struct man_node *nn;
470: size_t len;
471: int ival;
1.18 kristaps 472:
1.22 kristaps 473: switch (n->type) {
474: case (MAN_BODY):
475: p->flags |= TERMP_NOLPAD;
476: p->flags |= TERMP_NOSPACE;
477: break;
478: case (MAN_HEAD):
479: p->flags |= TERMP_NOBREAK;
480: break;
1.23 kristaps 481: case (MAN_BLOCK):
1.39 kristaps 482: print_bvspace(p, n);
1.23 kristaps 483: /* FALLTHROUGH */
1.22 kristaps 484: default:
485: return(1);
486: }
1.18 kristaps 487:
1.26 kristaps 488: len = mt->lmargin;
1.22 kristaps 489: ival = -1;
1.4 kristaps 490:
1.22 kristaps 491: /* Calculate offset. */
1.4 kristaps 492:
1.22 kristaps 493: if (NULL != (nn = n->parent->head->child))
494: if (NULL != (nn = nn->next)) {
495: for ( ; nn->next; nn = nn->next)
496: /* Do nothing. */ ;
1.77 kristaps 497: if ((ival = a2width(p, nn->string)) >= 0)
1.22 kristaps 498: len = (size_t)ival;
499: }
1.4 kristaps 500:
1.22 kristaps 501: switch (n->type) {
502: case (MAN_HEAD):
1.23 kristaps 503: /* Handle zero-width lengths. */
504: if (0 == len)
1.77 kristaps 505: len = term_len(p, 1);
1.23 kristaps 506:
1.26 kristaps 507: p->offset = mt->offset;
508: p->rmargin = mt->offset + len;
1.22 kristaps 509: if (ival < 0)
510: break;
1.18 kristaps 511:
1.24 kristaps 512: /* Set the saved left-margin. */
1.26 kristaps 513: mt->lmargin = (size_t)ival;
1.24 kristaps 514:
1.22 kristaps 515: /* Don't print the length value. */
516: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 517: print_man_node(p, mt, nn, m);
1.22 kristaps 518: return(0);
1.23 kristaps 519: case (MAN_BODY):
1.26 kristaps 520: p->offset = mt->offset + len;
1.23 kristaps 521: p->rmargin = p->maxrmargin;
522: break;
1.22 kristaps 523: default:
524: break;
1.18 kristaps 525: }
526:
1.22 kristaps 527: return(1);
528: }
1.18 kristaps 529:
530:
1.22 kristaps 531: /* ARGSUSED */
532: static void
533: post_IP(DECL_ARGS)
534: {
1.4 kristaps 535:
1.22 kristaps 536: switch (n->type) {
537: case (MAN_HEAD):
538: term_flushln(p);
539: p->flags &= ~TERMP_NOBREAK;
540: p->rmargin = p->maxrmargin;
541: break;
542: case (MAN_BODY):
543: term_flushln(p);
544: p->flags &= ~TERMP_NOLPAD;
545: break;
546: default:
547: break;
548: }
1.4 kristaps 549: }
550:
551:
552: /* ARGSUSED */
553: static int
1.1 kristaps 554: pre_TP(DECL_ARGS)
555: {
1.23 kristaps 556: const struct man_node *nn;
557: size_t len;
558: int ival;
1.1 kristaps 559:
1.21 kristaps 560: switch (n->type) {
561: case (MAN_HEAD):
562: p->flags |= TERMP_NOBREAK;
563: p->flags |= TERMP_TWOSPACE;
564: break;
565: case (MAN_BODY):
566: p->flags |= TERMP_NOLPAD;
567: p->flags |= TERMP_NOSPACE;
1.23 kristaps 568: break;
569: case (MAN_BLOCK):
1.39 kristaps 570: print_bvspace(p, n);
1.23 kristaps 571: /* FALLTHROUGH */
572: default:
573: return(1);
574: }
575:
1.24 kristaps 576: len = (size_t)mt->lmargin;
1.23 kristaps 577: ival = -1;
578:
579: /* Calculate offset. */
580:
1.56 kristaps 581: if (NULL != (nn = n->parent->head->child)) {
582: while (nn && MAN_TEXT != nn->type)
583: nn = nn->next;
584: if (nn && nn->next)
1.77 kristaps 585: if ((ival = a2width(p, nn->string)) >= 0)
1.23 kristaps 586: len = (size_t)ival;
1.56 kristaps 587: }
1.23 kristaps 588:
589: switch (n->type) {
590: case (MAN_HEAD):
591: /* Handle zero-length properly. */
592: if (0 == len)
1.77 kristaps 593: len = term_len(p, 1);
1.23 kristaps 594:
1.26 kristaps 595: p->offset = mt->offset;
596: p->rmargin = mt->offset + len;
1.23 kristaps 597:
598: /* Don't print same-line elements. */
599: for (nn = n->child; nn; nn = nn->next)
600: if (nn->line > n->line)
1.45 kristaps 601: print_man_node(p, mt, nn, m);
1.24 kristaps 602:
603: if (ival >= 0)
1.26 kristaps 604: mt->lmargin = (size_t)ival;
1.24 kristaps 605:
1.23 kristaps 606: return(0);
607: case (MAN_BODY):
1.26 kristaps 608: p->offset = mt->offset + len;
1.23 kristaps 609: p->rmargin = p->maxrmargin;
1.21 kristaps 610: break;
611: default:
612: break;
613: }
1.16 kristaps 614:
1.21 kristaps 615: return(1);
616: }
1.1 kristaps 617:
618:
1.21 kristaps 619: /* ARGSUSED */
620: static void
621: post_TP(DECL_ARGS)
622: {
1.1 kristaps 623:
1.21 kristaps 624: switch (n->type) {
625: case (MAN_HEAD):
626: term_flushln(p);
627: p->flags &= ~TERMP_NOBREAK;
628: p->flags &= ~TERMP_TWOSPACE;
629: p->rmargin = p->maxrmargin;
630: break;
631: case (MAN_BODY):
632: term_flushln(p);
633: p->flags &= ~TERMP_NOLPAD;
634: break;
635: default:
636: break;
637: }
1.1 kristaps 638: }
639:
640:
1.3 kristaps 641: /* ARGSUSED */
1.1 kristaps 642: static int
643: pre_SS(DECL_ARGS)
644: {
645:
1.19 kristaps 646: switch (n->type) {
647: case (MAN_BLOCK):
1.77 kristaps 648: mt->lmargin = term_len(p, INDENT);
649: mt->offset = term_len(p, INDENT);
1.24 kristaps 650: /* If following a prior empty `SS', no vspace. */
651: if (n->prev && MAN_SS == n->prev->tok)
652: if (NULL == n->prev->body->child)
653: break;
654: if (NULL == n->prev)
655: break;
656: term_vspace(p);
1.19 kristaps 657: break;
658: case (MAN_HEAD):
1.52 kristaps 659: term_fontrepl(p, TERMFONT_BOLD);
1.77 kristaps 660: p->offset = term_len(p, HALFINDENT);
1.19 kristaps 661: break;
1.24 kristaps 662: case (MAN_BODY):
1.26 kristaps 663: p->offset = mt->offset;
1.24 kristaps 664: break;
1.19 kristaps 665: default:
666: break;
667: }
668:
1.1 kristaps 669: return(1);
670: }
671:
672:
1.3 kristaps 673: /* ARGSUSED */
1.1 kristaps 674: static void
675: post_SS(DECL_ARGS)
676: {
677:
1.19 kristaps 678: switch (n->type) {
679: case (MAN_HEAD):
680: term_newln(p);
681: break;
1.24 kristaps 682: case (MAN_BODY):
683: term_newln(p);
684: break;
1.19 kristaps 685: default:
686: break;
687: }
1.1 kristaps 688: }
689:
690:
1.3 kristaps 691: /* ARGSUSED */
1.1 kristaps 692: static int
693: pre_SH(DECL_ARGS)
694: {
1.22 kristaps 695:
1.19 kristaps 696: switch (n->type) {
697: case (MAN_BLOCK):
1.77 kristaps 698: mt->lmargin = term_len(p, INDENT);
699: mt->offset = term_len(p, INDENT);
1.22 kristaps 700: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 701: if (n->prev && MAN_SH == n->prev->tok)
702: if (NULL == n->prev->body->child)
703: break;
1.61 kristaps 704: /* If the first macro, no vspae. */
705: if (NULL == n->prev)
706: break;
1.19 kristaps 707: term_vspace(p);
708: break;
709: case (MAN_HEAD):
1.52 kristaps 710: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 711: p->offset = 0;
712: break;
713: case (MAN_BODY):
1.26 kristaps 714: p->offset = mt->offset;
1.19 kristaps 715: break;
716: default:
717: break;
718: }
1.1 kristaps 719:
720: return(1);
721: }
722:
723:
1.3 kristaps 724: /* ARGSUSED */
1.1 kristaps 725: static void
726: post_SH(DECL_ARGS)
727: {
728:
1.19 kristaps 729: switch (n->type) {
730: case (MAN_HEAD):
731: term_newln(p);
732: break;
733: case (MAN_BODY):
734: term_newln(p);
735: break;
736: default:
737: break;
738: }
1.1 kristaps 739: }
740:
741:
1.26 kristaps 742: /* ARGSUSED */
743: static int
744: pre_RS(DECL_ARGS)
745: {
746: const struct man_node *nn;
747: int ival;
748:
749: switch (n->type) {
750: case (MAN_BLOCK):
751: term_newln(p);
752: return(1);
753: case (MAN_HEAD):
754: return(0);
755: default:
756: break;
757: }
758:
759: if (NULL == (nn = n->parent->head->child)) {
1.77 kristaps 760: mt->offset = mt->lmargin + term_len(p, INDENT);
1.26 kristaps 761: p->offset = mt->offset;
762: return(1);
763: }
764:
1.77 kristaps 765: if ((ival = a2width(p, nn->string)) < 0)
1.26 kristaps 766: return(1);
767:
1.77 kristaps 768: mt->offset = term_len(p, INDENT) + (size_t)ival;
1.26 kristaps 769: p->offset = mt->offset;
770:
771: return(1);
772: }
773:
774:
775: /* ARGSUSED */
776: static void
777: post_RS(DECL_ARGS)
778: {
779:
780: switch (n->type) {
781: case (MAN_BLOCK):
1.77 kristaps 782: mt->offset = mt->lmargin = term_len(p, INDENT);
1.59 kristaps 783: break;
784: case (MAN_HEAD):
1.26 kristaps 785: break;
786: default:
787: term_newln(p);
1.77 kristaps 788: p->offset = term_len(p, INDENT);
1.26 kristaps 789: break;
790: }
791: }
792:
793:
1.1 kristaps 794: static void
1.45 kristaps 795: print_man_node(DECL_ARGS)
1.1 kristaps 796: {
1.65 joerg 797: size_t rm, rmax;
1.54 kristaps 798: int c;
1.1 kristaps 799:
800: c = 1;
801:
802: switch (n->type) {
803: case(MAN_TEXT):
1.4 kristaps 804: if (0 == *n->string) {
805: term_vspace(p);
1.1 kristaps 806: break;
807: }
1.54 kristaps 808:
1.4 kristaps 809: term_word(p, n->string);
1.52 kristaps 810:
1.19 kristaps 811: /* FIXME: this means that macro lines are munged! */
1.52 kristaps 812:
1.24 kristaps 813: if (MANT_LITERAL & mt->fl) {
1.65 joerg 814: rm = p->rmargin;
815: rmax = p->maxrmargin;
1.60 kristaps 816: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19 kristaps 817: p->flags |= TERMP_NOSPACE;
818: term_flushln(p);
1.65 joerg 819: p->rmargin = rm;
820: p->maxrmargin = rmax;
1.19 kristaps 821: }
1.1 kristaps 822: break;
823: default:
1.56 kristaps 824: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
825: term_fontrepl(p, TERMFONT_NONE);
1.19 kristaps 826: if (termacts[n->tok].pre)
1.24 kristaps 827: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 828: break;
829: }
830:
831: if (c && n->child)
1.52 kristaps 832: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 833:
1.51 kristaps 834: if (MAN_TEXT != n->type) {
1.1 kristaps 835: if (termacts[n->tok].post)
1.24 kristaps 836: (*termacts[n->tok].post)(p, mt, n, m);
1.56 kristaps 837: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
838: term_fontrepl(p, TERMFONT_NONE);
1.51 kristaps 839: }
1.63 kristaps 840:
841: if (MAN_EOS & n->flags)
842: p->flags |= TERMP_SENTENCE;
1.1 kristaps 843: }
844:
845:
846: static void
1.52 kristaps 847: print_man_nodelist(DECL_ARGS)
1.1 kristaps 848: {
1.19 kristaps 849:
1.45 kristaps 850: print_man_node(p, mt, n, m);
1.1 kristaps 851: if ( ! n->next)
852: return;
1.52 kristaps 853: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 854: }
855:
856:
1.31 kristaps 857: static void
1.73 kristaps 858: print_man_foot(struct termp *p, const void *arg)
1.1 kristaps 859: {
1.43 kristaps 860: char buf[DATESIZ];
1.73 kristaps 861: const struct man_meta *meta;
862:
863: meta = (const struct man_meta *)arg;
1.1 kristaps 864:
1.52 kristaps 865: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 866:
1.72 kristaps 867: if (meta->rawdate)
868: strlcpy(buf, meta->rawdate, DATESIZ);
869: else
870: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 871:
1.69 joerg 872: term_vspace(p);
873: term_vspace(p);
1.1 kristaps 874: term_vspace(p);
875:
876: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.77 kristaps 877: p->rmargin = p->maxrmargin - term_strlen(p, buf);
1.1 kristaps 878: p->offset = 0;
879:
880: if (meta->source)
881: term_word(p, meta->source);
882: if (meta->source)
883: term_word(p, "");
884: term_flushln(p);
885:
886: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
887: p->offset = p->rmargin;
888: p->rmargin = p->maxrmargin;
889: p->flags &= ~TERMP_NOBREAK;
890:
891: term_word(p, buf);
892: term_flushln(p);
893: }
894:
895:
1.31 kristaps 896: static void
1.73 kristaps 897: print_man_head(struct termp *p, const void *arg)
1.1 kristaps 898: {
1.46 kristaps 899: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 900: size_t buflen, titlen;
1.73 kristaps 901: const struct man_meta *m;
902:
903: m = (const struct man_meta *)arg;
1.1 kristaps 904:
1.62 kristaps 905: /*
906: * Note that old groff would spit out some spaces before the
907: * header. We discontinue this strange behaviour, but at one
908: * point we did so here.
909: */
910:
1.1 kristaps 911: p->rmargin = p->maxrmargin;
1.58 kristaps 912:
1.1 kristaps 913: p->offset = 0;
1.46 kristaps 914: buf[0] = title[0] = '\0';
1.1 kristaps 915:
1.46 kristaps 916: if (m->vol)
917: strlcpy(buf, m->vol, BUFSIZ);
1.77 kristaps 918: buflen = term_strlen(p, buf);
1.1 kristaps 919:
1.64 kristaps 920: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.77 kristaps 921: titlen = term_strlen(p, title);
1.1 kristaps 922:
923: p->offset = 0;
1.57 kristaps 924: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77 kristaps 925: (p->maxrmargin -
926: term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57 kristaps 927: p->maxrmargin - buflen;
1.1 kristaps 928: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
929:
930: term_word(p, title);
931: term_flushln(p);
932:
933: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
934: p->offset = p->rmargin;
1.57 kristaps 935: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
936: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 937:
938: term_word(p, buf);
939: term_flushln(p);
940:
941: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 942: if (p->rmargin + titlen <= p->maxrmargin) {
943: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
944: p->offset = p->rmargin;
945: p->rmargin = p->maxrmargin;
946: term_word(p, title);
947: term_flushln(p);
948: }
1.1 kristaps 949:
950: p->rmargin = p->maxrmargin;
951: p->offset = 0;
952: p->flags &= ~TERMP_NOSPACE;
1.61 kristaps 953:
1.62 kristaps 954: /*
955: * Groff likes to have some leading spaces before content. Well
956: * that's fine by me.
957: */
958:
1.61 kristaps 959: term_vspace(p);
960: term_vspace(p);
961: term_vspace(p);
1.1 kristaps 962: }
CVSweb