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