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