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