Annotation of mandoc/man_term.c, Revision 1.78
1.78 ! kristaps 1: /* $Id: man_term.c,v 1.77 2010/06/25 18:53:14 kristaps Exp $ */
1.1 kristaps 2: /*
1.76 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.8 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.8 kristaps 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
1.55 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
1.28 kristaps 21: #include <sys/types.h>
22:
1.1 kristaps 23: #include <assert.h>
1.18 kristaps 24: #include <ctype.h>
1.1 kristaps 25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28:
1.71 kristaps 29: #include "mandoc.h"
1.40 kristaps 30: #include "out.h"
1.78 ! kristaps 31: #include "regs.h"
1.36 kristaps 32: #include "man.h"
1.1 kristaps 33: #include "term.h"
1.36 kristaps 34: #include "chars.h"
35: #include "main.h"
1.1 kristaps 36:
1.18 kristaps 37: #define INDENT 7
38: #define HALFINDENT 3
39:
1.44 kristaps 40: /* FIXME: have PD set the default vspace width. */
41:
1.24 kristaps 42: struct mtermp {
43: int fl;
1.19 kristaps 44: #define MANT_LITERAL (1 << 0)
1.26 kristaps 45: /*
46: * Default amount to indent the left margin after leading text
47: * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
48: * indent). This needs to be saved because `HP' and so on, if
49: * not having a specified value, must default.
50: *
51: * Note that this is the indentation AFTER the left offset, so
52: * the total offset is usually offset + lmargin.
53: */
54: size_t lmargin;
55: /*
56: * The default offset, i.e., the amount between any text and the
57: * page boundary.
58: */
59: size_t offset;
1.24 kristaps 60: };
1.19 kristaps 61:
1.1 kristaps 62: #define DECL_ARGS struct termp *p, \
1.24 kristaps 63: struct mtermp *mt, \
1.1 kristaps 64: const struct man_node *n, \
65: const struct man_meta *m
66:
67: struct termact {
68: int (*pre)(DECL_ARGS);
69: void (*post)(DECL_ARGS);
1.56 kristaps 70: int flags;
71: #define MAN_NOTEXT (1 << 0) /* Never has text children. */
1.1 kristaps 72: };
73:
1.77 kristaps 74: static int a2width(const struct termp *, const char *);
75: static size_t a2height(const struct termp *, const char *);
1.39 kristaps 76:
1.52 kristaps 77: static void print_man_nodelist(DECL_ARGS);
1.45 kristaps 78: static void print_man_node(DECL_ARGS);
1.74 kristaps 79: static void print_man_head(struct termp *, const void *);
1.73 kristaps 80: static void print_man_foot(struct termp *, const void *);
1.39 kristaps 81: static void print_bvspace(struct termp *,
82: const struct man_node *);
83:
1.1 kristaps 84: static int pre_B(DECL_ARGS);
1.3 kristaps 85: static int pre_BI(DECL_ARGS);
1.19 kristaps 86: static int pre_HP(DECL_ARGS);
1.1 kristaps 87: static int pre_I(DECL_ARGS);
1.4 kristaps 88: static int pre_IP(DECL_ARGS);
1.1 kristaps 89: static int pre_PP(DECL_ARGS);
1.3 kristaps 90: static int pre_RB(DECL_ARGS);
91: static int pre_RI(DECL_ARGS);
1.26 kristaps 92: static int pre_RS(DECL_ARGS);
1.1 kristaps 93: static int pre_SH(DECL_ARGS);
94: static int pre_SS(DECL_ARGS);
95: static int pre_TP(DECL_ARGS);
1.19 kristaps 96: static int pre_br(DECL_ARGS);
97: static int pre_fi(DECL_ARGS);
1.29 kristaps 98: static int pre_ign(DECL_ARGS);
1.19 kristaps 99: static int pre_nf(DECL_ARGS);
100: static int pre_sp(DECL_ARGS);
1.1 kristaps 101:
1.22 kristaps 102: static void post_IP(DECL_ARGS);
1.20 kristaps 103: static void post_HP(DECL_ARGS);
1.26 kristaps 104: static void post_RS(DECL_ARGS);
1.1 kristaps 105: static void post_SH(DECL_ARGS);
106: static void post_SS(DECL_ARGS);
1.21 kristaps 107: static void post_TP(DECL_ARGS);
1.1 kristaps 108:
1.32 kristaps 109: static const struct termact termacts[MAN_MAX] = {
1.56 kristaps 110: { pre_br, NULL, MAN_NOTEXT }, /* br */
111: { NULL, NULL, 0 }, /* TH */
112: { pre_SH, post_SH, 0 }, /* SH */
113: { pre_SS, post_SS, 0 }, /* SS */
114: { pre_TP, post_TP, 0 }, /* TP */
115: { pre_PP, NULL, 0 }, /* LP */
116: { pre_PP, NULL, 0 }, /* PP */
117: { pre_PP, NULL, 0 }, /* P */
118: { pre_IP, post_IP, 0 }, /* IP */
119: { pre_HP, post_HP, 0 }, /* HP */
120: { NULL, NULL, 0 }, /* SM */
121: { pre_B, NULL, 0 }, /* SB */
122: { pre_BI, NULL, 0 }, /* BI */
123: { pre_BI, NULL, 0 }, /* IB */
124: { pre_RB, NULL, 0 }, /* BR */
125: { pre_RB, NULL, 0 }, /* RB */
126: { NULL, NULL, 0 }, /* R */
127: { pre_B, NULL, 0 }, /* B */
128: { pre_I, NULL, 0 }, /* I */
129: { pre_RI, NULL, 0 }, /* IR */
130: { pre_RI, NULL, 0 }, /* RI */
131: { NULL, NULL, MAN_NOTEXT }, /* na */
132: { pre_I, NULL, 0 }, /* i */
133: { pre_sp, NULL, MAN_NOTEXT }, /* sp */
134: { pre_nf, NULL, 0 }, /* nf */
135: { pre_fi, NULL, 0 }, /* fi */
136: { NULL, NULL, 0 }, /* r */
137: { NULL, NULL, 0 }, /* RE */
138: { pre_RS, post_RS, 0 }, /* RS */
139: { pre_ign, NULL, 0 }, /* DT */
140: { pre_ign, NULL, 0 }, /* UC */
141: { pre_ign, NULL, 0 }, /* PD */
1.57 kristaps 142: { pre_sp, NULL, MAN_NOTEXT }, /* Sp */
143: { pre_nf, NULL, 0 }, /* Vb */
144: { pre_fi, NULL, 0 }, /* Ve */
1.70 joerg 145: { pre_ign, NULL, 0 }, /* AT */
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.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.24 kristaps 266: mt->fl |= MANT_LITERAL;
1.57 kristaps 267: return(MAN_Vb != n->tok);
1.19 kristaps 268: }
269:
270:
271: /* ARGSUSED */
272: static int
1.35 kristaps 273: pre_RB(DECL_ARGS)
1.3 kristaps 274: {
275: const struct man_node *nn;
276: int i;
277:
278: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 279: if (i % 2 && MAN_RB == n->tok)
1.52 kristaps 280: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 281: else if ( ! (i % 2) && MAN_RB != n->tok)
1.52 kristaps 282: term_fontrepl(p, TERMFONT_BOLD);
283: else
284: term_fontrepl(p, TERMFONT_NONE);
1.35 kristaps 285:
1.4 kristaps 286: if (i > 0)
287: p->flags |= TERMP_NOSPACE;
1.35 kristaps 288:
1.45 kristaps 289: print_man_node(p, mt, nn, m);
1.3 kristaps 290: }
291: return(0);
292: }
293:
294:
295: /* ARGSUSED */
296: static int
297: pre_RI(DECL_ARGS)
298: {
299: const struct man_node *nn;
300: int i;
301:
302: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.49 kristaps 303: if (i % 2 && MAN_RI == n->tok)
1.52 kristaps 304: term_fontrepl(p, TERMFONT_UNDER);
1.49 kristaps 305: else if ( ! (i % 2) && MAN_RI != n->tok)
1.52 kristaps 306: term_fontrepl(p, TERMFONT_UNDER);
307: else
308: term_fontrepl(p, TERMFONT_NONE);
1.49 kristaps 309:
1.4 kristaps 310: if (i > 0)
311: p->flags |= TERMP_NOSPACE;
1.52 kristaps 312:
1.45 kristaps 313: print_man_node(p, mt, nn, m);
1.3 kristaps 314: }
315: return(0);
316: }
317:
318:
319: /* ARGSUSED */
320: static int
321: pre_BI(DECL_ARGS)
322: {
1.35 kristaps 323: const struct man_node *nn;
324: int i;
1.3 kristaps 325:
326: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 327: if (i % 2 && MAN_BI == n->tok)
1.52 kristaps 328: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 329: else if (i % 2)
1.52 kristaps 330: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 331: else if (MAN_BI == n->tok)
1.52 kristaps 332: term_fontrepl(p, TERMFONT_BOLD);
1.30 kristaps 333: else
1.52 kristaps 334: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 335:
336: if (i)
1.4 kristaps 337: p->flags |= TERMP_NOSPACE;
1.52 kristaps 338:
1.45 kristaps 339: print_man_node(p, mt, nn, m);
1.3 kristaps 340: }
341: return(0);
342: }
343:
344:
345: /* ARGSUSED */
1.1 kristaps 346: static int
347: pre_B(DECL_ARGS)
348: {
349:
1.52 kristaps 350: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 351: return(1);
352: }
353:
354:
1.3 kristaps 355: /* ARGSUSED */
1.1 kristaps 356: static int
1.19 kristaps 357: pre_sp(DECL_ARGS)
358: {
1.77 kristaps 359: size_t i, len;
1.19 kristaps 360:
1.77 kristaps 361: len = n->child ?
362: a2height(p, n->child->string) : term_len(p, 1);
1.38 kristaps 363:
1.19 kristaps 364: if (0 == len)
365: term_newln(p);
1.61 kristaps 366: for (i = 0; i <= len; i++)
1.19 kristaps 367: term_vspace(p);
368:
369: return(0);
370: }
371:
372:
373: /* ARGSUSED */
374: static int
1.15 kristaps 375: pre_br(DECL_ARGS)
376: {
377:
378: term_newln(p);
379: return(0);
380: }
381:
382:
383: /* ARGSUSED */
384: static int
1.19 kristaps 385: pre_HP(DECL_ARGS)
386: {
1.24 kristaps 387: size_t len;
388: int ival;
389: const struct man_node *nn;
1.19 kristaps 390:
1.20 kristaps 391: switch (n->type) {
392: case (MAN_BLOCK):
1.39 kristaps 393: print_bvspace(p, n);
1.24 kristaps 394: return(1);
1.20 kristaps 395: case (MAN_BODY):
396: p->flags |= TERMP_NOBREAK;
397: p->flags |= TERMP_TWOSPACE;
398: break;
399: default:
400: return(0);
401: }
402:
1.26 kristaps 403: len = mt->lmargin;
1.24 kristaps 404: ival = -1;
405:
406: /* Calculate offset. */
407:
1.39 kristaps 408: if (NULL != (nn = n->parent->head->child))
1.77 kristaps 409: if ((ival = a2width(p, nn->string)) >= 0)
1.24 kristaps 410: len = (size_t)ival;
411:
412: if (0 == len)
1.77 kristaps 413: len = term_len(p, 1);
1.24 kristaps 414:
1.26 kristaps 415: p->offset = mt->offset;
416: p->rmargin = mt->offset + len;
1.24 kristaps 417:
418: if (ival >= 0)
1.26 kristaps 419: mt->lmargin = (size_t)ival;
1.24 kristaps 420:
1.19 kristaps 421: return(1);
422: }
423:
424:
425: /* ARGSUSED */
1.20 kristaps 426: static void
427: post_HP(DECL_ARGS)
428: {
429:
430: switch (n->type) {
1.24 kristaps 431: case (MAN_BLOCK):
432: term_flushln(p);
433: break;
1.20 kristaps 434: case (MAN_BODY):
435: term_flushln(p);
436: p->flags &= ~TERMP_NOBREAK;
437: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 438: p->offset = mt->offset;
1.20 kristaps 439: p->rmargin = p->maxrmargin;
440: break;
441: default:
442: break;
443: }
444: }
445:
446:
447: /* ARGSUSED */
1.19 kristaps 448: static int
1.1 kristaps 449: pre_PP(DECL_ARGS)
450: {
451:
1.19 kristaps 452: switch (n->type) {
453: case (MAN_BLOCK):
1.77 kristaps 454: mt->lmargin = term_len(p, INDENT);
1.39 kristaps 455: print_bvspace(p, n);
1.19 kristaps 456: break;
457: default:
1.26 kristaps 458: p->offset = mt->offset;
1.19 kristaps 459: break;
460: }
461:
462: return(1);
1.1 kristaps 463: }
464:
465:
1.3 kristaps 466: /* ARGSUSED */
1.1 kristaps 467: static int
1.4 kristaps 468: pre_IP(DECL_ARGS)
469: {
1.22 kristaps 470: const struct man_node *nn;
471: size_t len;
472: int ival;
1.18 kristaps 473:
1.22 kristaps 474: switch (n->type) {
475: case (MAN_BODY):
476: p->flags |= TERMP_NOLPAD;
477: p->flags |= TERMP_NOSPACE;
478: break;
479: case (MAN_HEAD):
480: p->flags |= TERMP_NOBREAK;
481: break;
1.23 kristaps 482: case (MAN_BLOCK):
1.39 kristaps 483: print_bvspace(p, n);
1.23 kristaps 484: /* FALLTHROUGH */
1.22 kristaps 485: default:
486: return(1);
487: }
1.18 kristaps 488:
1.26 kristaps 489: len = mt->lmargin;
1.22 kristaps 490: ival = -1;
1.4 kristaps 491:
1.22 kristaps 492: /* Calculate offset. */
1.4 kristaps 493:
1.22 kristaps 494: if (NULL != (nn = n->parent->head->child))
495: if (NULL != (nn = nn->next)) {
496: for ( ; nn->next; nn = nn->next)
497: /* Do nothing. */ ;
1.77 kristaps 498: if ((ival = a2width(p, nn->string)) >= 0)
1.22 kristaps 499: len = (size_t)ival;
500: }
1.4 kristaps 501:
1.22 kristaps 502: switch (n->type) {
503: case (MAN_HEAD):
1.23 kristaps 504: /* Handle zero-width lengths. */
505: if (0 == len)
1.77 kristaps 506: len = term_len(p, 1);
1.23 kristaps 507:
1.26 kristaps 508: p->offset = mt->offset;
509: p->rmargin = mt->offset + len;
1.22 kristaps 510: if (ival < 0)
511: break;
1.18 kristaps 512:
1.24 kristaps 513: /* Set the saved left-margin. */
1.26 kristaps 514: mt->lmargin = (size_t)ival;
1.24 kristaps 515:
1.22 kristaps 516: /* Don't print the length value. */
517: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 518: print_man_node(p, mt, nn, m);
1.22 kristaps 519: return(0);
1.23 kristaps 520: case (MAN_BODY):
1.26 kristaps 521: p->offset = mt->offset + len;
1.23 kristaps 522: p->rmargin = p->maxrmargin;
523: break;
1.22 kristaps 524: default:
525: break;
1.18 kristaps 526: }
527:
1.22 kristaps 528: return(1);
529: }
1.18 kristaps 530:
531:
1.22 kristaps 532: /* ARGSUSED */
533: static void
534: post_IP(DECL_ARGS)
535: {
1.4 kristaps 536:
1.22 kristaps 537: switch (n->type) {
538: case (MAN_HEAD):
539: term_flushln(p);
540: p->flags &= ~TERMP_NOBREAK;
541: p->rmargin = p->maxrmargin;
542: break;
543: case (MAN_BODY):
544: term_flushln(p);
545: p->flags &= ~TERMP_NOLPAD;
546: break;
547: default:
548: break;
549: }
1.4 kristaps 550: }
551:
552:
553: /* ARGSUSED */
554: static int
1.1 kristaps 555: pre_TP(DECL_ARGS)
556: {
1.23 kristaps 557: const struct man_node *nn;
558: size_t len;
559: int ival;
1.1 kristaps 560:
1.21 kristaps 561: switch (n->type) {
562: case (MAN_HEAD):
563: p->flags |= TERMP_NOBREAK;
564: p->flags |= TERMP_TWOSPACE;
565: break;
566: case (MAN_BODY):
567: p->flags |= TERMP_NOLPAD;
568: p->flags |= TERMP_NOSPACE;
1.23 kristaps 569: break;
570: case (MAN_BLOCK):
1.39 kristaps 571: print_bvspace(p, n);
1.23 kristaps 572: /* FALLTHROUGH */
573: default:
574: return(1);
575: }
576:
1.24 kristaps 577: len = (size_t)mt->lmargin;
1.23 kristaps 578: ival = -1;
579:
580: /* Calculate offset. */
581:
1.56 kristaps 582: if (NULL != (nn = n->parent->head->child)) {
583: while (nn && MAN_TEXT != nn->type)
584: nn = nn->next;
585: if (nn && nn->next)
1.77 kristaps 586: if ((ival = a2width(p, nn->string)) >= 0)
1.23 kristaps 587: len = (size_t)ival;
1.56 kristaps 588: }
1.23 kristaps 589:
590: switch (n->type) {
591: case (MAN_HEAD):
592: /* Handle zero-length properly. */
593: if (0 == len)
1.77 kristaps 594: len = term_len(p, 1);
1.23 kristaps 595:
1.26 kristaps 596: p->offset = mt->offset;
597: p->rmargin = mt->offset + len;
1.23 kristaps 598:
599: /* Don't print same-line elements. */
600: for (nn = n->child; nn; nn = nn->next)
601: if (nn->line > n->line)
1.45 kristaps 602: print_man_node(p, mt, nn, m);
1.24 kristaps 603:
604: if (ival >= 0)
1.26 kristaps 605: mt->lmargin = (size_t)ival;
1.24 kristaps 606:
1.23 kristaps 607: return(0);
608: case (MAN_BODY):
1.26 kristaps 609: p->offset = mt->offset + len;
1.23 kristaps 610: p->rmargin = p->maxrmargin;
1.21 kristaps 611: break;
612: default:
613: break;
614: }
1.16 kristaps 615:
1.21 kristaps 616: return(1);
617: }
1.1 kristaps 618:
619:
1.21 kristaps 620: /* ARGSUSED */
621: static void
622: post_TP(DECL_ARGS)
623: {
1.1 kristaps 624:
1.21 kristaps 625: switch (n->type) {
626: case (MAN_HEAD):
627: term_flushln(p);
628: p->flags &= ~TERMP_NOBREAK;
629: p->flags &= ~TERMP_TWOSPACE;
630: p->rmargin = p->maxrmargin;
631: break;
632: case (MAN_BODY):
633: term_flushln(p);
634: p->flags &= ~TERMP_NOLPAD;
635: break;
636: default:
637: break;
638: }
1.1 kristaps 639: }
640:
641:
1.3 kristaps 642: /* ARGSUSED */
1.1 kristaps 643: static int
644: pre_SS(DECL_ARGS)
645: {
646:
1.19 kristaps 647: switch (n->type) {
648: case (MAN_BLOCK):
1.77 kristaps 649: mt->lmargin = term_len(p, INDENT);
650: mt->offset = term_len(p, INDENT);
1.24 kristaps 651: /* If following a prior empty `SS', no vspace. */
652: if (n->prev && MAN_SS == n->prev->tok)
653: if (NULL == n->prev->body->child)
654: break;
655: if (NULL == n->prev)
656: break;
657: term_vspace(p);
1.19 kristaps 658: break;
659: case (MAN_HEAD):
1.52 kristaps 660: term_fontrepl(p, TERMFONT_BOLD);
1.77 kristaps 661: p->offset = term_len(p, HALFINDENT);
1.19 kristaps 662: break;
1.24 kristaps 663: case (MAN_BODY):
1.26 kristaps 664: p->offset = mt->offset;
1.24 kristaps 665: break;
1.19 kristaps 666: default:
667: break;
668: }
669:
1.1 kristaps 670: return(1);
671: }
672:
673:
1.3 kristaps 674: /* ARGSUSED */
1.1 kristaps 675: static void
676: post_SS(DECL_ARGS)
677: {
678:
1.19 kristaps 679: switch (n->type) {
680: case (MAN_HEAD):
681: term_newln(p);
682: break;
1.24 kristaps 683: case (MAN_BODY):
684: term_newln(p);
685: break;
1.19 kristaps 686: default:
687: break;
688: }
1.1 kristaps 689: }
690:
691:
1.3 kristaps 692: /* ARGSUSED */
1.1 kristaps 693: static int
694: pre_SH(DECL_ARGS)
695: {
1.22 kristaps 696:
1.19 kristaps 697: switch (n->type) {
698: case (MAN_BLOCK):
1.77 kristaps 699: mt->lmargin = term_len(p, INDENT);
700: mt->offset = term_len(p, INDENT);
1.22 kristaps 701: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 702: if (n->prev && MAN_SH == n->prev->tok)
703: if (NULL == n->prev->body->child)
704: break;
1.61 kristaps 705: /* If the first macro, no vspae. */
706: if (NULL == n->prev)
707: break;
1.19 kristaps 708: term_vspace(p);
709: break;
710: case (MAN_HEAD):
1.52 kristaps 711: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 712: p->offset = 0;
713: break;
714: case (MAN_BODY):
1.26 kristaps 715: p->offset = mt->offset;
1.19 kristaps 716: break;
717: default:
718: break;
719: }
1.1 kristaps 720:
721: return(1);
722: }
723:
724:
1.3 kristaps 725: /* ARGSUSED */
1.1 kristaps 726: static void
727: post_SH(DECL_ARGS)
728: {
729:
1.19 kristaps 730: switch (n->type) {
731: case (MAN_HEAD):
732: term_newln(p);
733: break;
734: case (MAN_BODY):
735: term_newln(p);
736: break;
737: default:
738: break;
739: }
1.1 kristaps 740: }
741:
742:
1.26 kristaps 743: /* ARGSUSED */
744: static int
745: pre_RS(DECL_ARGS)
746: {
747: const struct man_node *nn;
748: int ival;
749:
750: switch (n->type) {
751: case (MAN_BLOCK):
752: term_newln(p);
753: return(1);
754: case (MAN_HEAD):
755: return(0);
756: default:
757: break;
758: }
759:
760: if (NULL == (nn = n->parent->head->child)) {
1.77 kristaps 761: mt->offset = mt->lmargin + term_len(p, INDENT);
1.26 kristaps 762: p->offset = mt->offset;
763: return(1);
764: }
765:
1.77 kristaps 766: if ((ival = a2width(p, nn->string)) < 0)
1.26 kristaps 767: return(1);
768:
1.77 kristaps 769: mt->offset = term_len(p, INDENT) + (size_t)ival;
1.26 kristaps 770: p->offset = mt->offset;
771:
772: return(1);
773: }
774:
775:
776: /* ARGSUSED */
777: static void
778: post_RS(DECL_ARGS)
779: {
780:
781: switch (n->type) {
782: case (MAN_BLOCK):
1.77 kristaps 783: mt->offset = mt->lmargin = term_len(p, INDENT);
1.59 kristaps 784: break;
785: case (MAN_HEAD):
1.26 kristaps 786: break;
787: default:
788: term_newln(p);
1.77 kristaps 789: p->offset = term_len(p, INDENT);
1.26 kristaps 790: break;
791: }
792: }
793:
794:
1.1 kristaps 795: static void
1.45 kristaps 796: print_man_node(DECL_ARGS)
1.1 kristaps 797: {
1.65 joerg 798: size_t rm, rmax;
1.54 kristaps 799: int c;
1.1 kristaps 800:
801: c = 1;
802:
803: switch (n->type) {
804: case(MAN_TEXT):
1.4 kristaps 805: if (0 == *n->string) {
806: term_vspace(p);
1.1 kristaps 807: break;
808: }
1.54 kristaps 809:
1.4 kristaps 810: term_word(p, n->string);
1.52 kristaps 811:
1.19 kristaps 812: /* FIXME: this means that macro lines are munged! */
1.52 kristaps 813:
1.24 kristaps 814: if (MANT_LITERAL & mt->fl) {
1.65 joerg 815: rm = p->rmargin;
816: rmax = p->maxrmargin;
1.60 kristaps 817: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19 kristaps 818: p->flags |= TERMP_NOSPACE;
819: term_flushln(p);
1.65 joerg 820: p->rmargin = rm;
821: p->maxrmargin = rmax;
1.19 kristaps 822: }
1.1 kristaps 823: break;
824: default:
1.56 kristaps 825: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
826: term_fontrepl(p, TERMFONT_NONE);
1.19 kristaps 827: if (termacts[n->tok].pre)
1.24 kristaps 828: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 829: break;
830: }
831:
832: if (c && n->child)
1.52 kristaps 833: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 834:
1.51 kristaps 835: if (MAN_TEXT != n->type) {
1.1 kristaps 836: if (termacts[n->tok].post)
1.24 kristaps 837: (*termacts[n->tok].post)(p, mt, n, m);
1.56 kristaps 838: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
839: term_fontrepl(p, TERMFONT_NONE);
1.51 kristaps 840: }
1.63 kristaps 841:
842: if (MAN_EOS & n->flags)
843: p->flags |= TERMP_SENTENCE;
1.1 kristaps 844: }
845:
846:
847: static void
1.52 kristaps 848: print_man_nodelist(DECL_ARGS)
1.1 kristaps 849: {
1.19 kristaps 850:
1.45 kristaps 851: print_man_node(p, mt, n, m);
1.1 kristaps 852: if ( ! n->next)
853: return;
1.52 kristaps 854: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 855: }
856:
857:
1.31 kristaps 858: static void
1.73 kristaps 859: print_man_foot(struct termp *p, const void *arg)
1.1 kristaps 860: {
1.43 kristaps 861: char buf[DATESIZ];
1.73 kristaps 862: const struct man_meta *meta;
863:
864: meta = (const struct man_meta *)arg;
1.1 kristaps 865:
1.52 kristaps 866: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 867:
1.72 kristaps 868: if (meta->rawdate)
869: strlcpy(buf, meta->rawdate, DATESIZ);
870: else
871: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 872:
1.69 joerg 873: term_vspace(p);
874: term_vspace(p);
1.1 kristaps 875: term_vspace(p);
876:
877: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.77 kristaps 878: p->rmargin = p->maxrmargin - term_strlen(p, buf);
1.1 kristaps 879: p->offset = 0;
880:
881: if (meta->source)
882: term_word(p, meta->source);
883: if (meta->source)
884: term_word(p, "");
885: term_flushln(p);
886:
887: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
888: p->offset = p->rmargin;
889: p->rmargin = p->maxrmargin;
890: p->flags &= ~TERMP_NOBREAK;
891:
892: term_word(p, buf);
893: term_flushln(p);
894: }
895:
896:
1.31 kristaps 897: static void
1.73 kristaps 898: print_man_head(struct termp *p, const void *arg)
1.1 kristaps 899: {
1.46 kristaps 900: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 901: size_t buflen, titlen;
1.73 kristaps 902: const struct man_meta *m;
903:
904: m = (const struct man_meta *)arg;
1.1 kristaps 905:
1.62 kristaps 906: /*
907: * Note that old groff would spit out some spaces before the
908: * header. We discontinue this strange behaviour, but at one
909: * point we did so here.
910: */
911:
1.1 kristaps 912: p->rmargin = p->maxrmargin;
1.58 kristaps 913:
1.1 kristaps 914: p->offset = 0;
1.46 kristaps 915: buf[0] = title[0] = '\0';
1.1 kristaps 916:
1.46 kristaps 917: if (m->vol)
918: strlcpy(buf, m->vol, BUFSIZ);
1.77 kristaps 919: buflen = term_strlen(p, buf);
1.1 kristaps 920:
1.64 kristaps 921: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.77 kristaps 922: titlen = term_strlen(p, title);
1.1 kristaps 923:
924: p->offset = 0;
1.57 kristaps 925: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77 kristaps 926: (p->maxrmargin -
927: term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57 kristaps 928: p->maxrmargin - buflen;
1.1 kristaps 929: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
930:
931: term_word(p, title);
932: term_flushln(p);
933:
934: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
935: p->offset = p->rmargin;
1.57 kristaps 936: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
937: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 938:
939: term_word(p, buf);
940: term_flushln(p);
941:
942: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 943: if (p->rmargin + titlen <= p->maxrmargin) {
944: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
945: p->offset = p->rmargin;
946: p->rmargin = p->maxrmargin;
947: term_word(p, title);
948: term_flushln(p);
949: }
1.1 kristaps 950:
951: p->rmargin = p->maxrmargin;
952: p->offset = 0;
953: p->flags &= ~TERMP_NOSPACE;
1.61 kristaps 954:
1.62 kristaps 955: /*
956: * Groff likes to have some leading spaces before content. Well
957: * that's fine by me.
958: */
959:
1.61 kristaps 960: term_vspace(p);
961: term_vspace(p);
962: term_vspace(p);
1.1 kristaps 963: }
CVSweb