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