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