Annotation of mandoc/man_term.c, Revision 1.66
1.66 ! joerg 1: /* $Id: man_term.c,v 1.65 2010/05/15 16:18:23 joerg 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;
1.65 joerg 166: p->maxrmargin = p->defrmargin;
1.58 kristaps 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: break;
1.23 kristaps 488: case (MAN_BLOCK):
1.39 kristaps 489: print_bvspace(p, n);
1.23 kristaps 490: /* FALLTHROUGH */
1.22 kristaps 491: default:
492: return(1);
493: }
1.18 kristaps 494:
1.26 kristaps 495: len = mt->lmargin;
1.22 kristaps 496: ival = -1;
1.4 kristaps 497:
1.22 kristaps 498: /* Calculate offset. */
1.4 kristaps 499:
1.22 kristaps 500: if (NULL != (nn = n->parent->head->child))
501: if (NULL != (nn = nn->next)) {
502: for ( ; nn->next; nn = nn->next)
503: /* Do nothing. */ ;
1.45 kristaps 504: if ((ival = a2width(nn)) >= 0)
1.22 kristaps 505: len = (size_t)ival;
506: }
1.4 kristaps 507:
1.22 kristaps 508: switch (n->type) {
509: case (MAN_HEAD):
1.23 kristaps 510: /* Handle zero-width lengths. */
511: if (0 == len)
512: len = 1;
513:
1.26 kristaps 514: p->offset = mt->offset;
515: p->rmargin = mt->offset + len;
1.22 kristaps 516: if (ival < 0)
517: break;
1.18 kristaps 518:
1.24 kristaps 519: /* Set the saved left-margin. */
1.26 kristaps 520: mt->lmargin = (size_t)ival;
1.24 kristaps 521:
1.22 kristaps 522: /* Don't print the length value. */
523: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 524: print_man_node(p, mt, nn, m);
1.22 kristaps 525: return(0);
1.23 kristaps 526: case (MAN_BODY):
1.26 kristaps 527: p->offset = mt->offset + len;
1.23 kristaps 528: p->rmargin = p->maxrmargin;
529: break;
1.22 kristaps 530: default:
531: break;
1.18 kristaps 532: }
533:
1.22 kristaps 534: return(1);
535: }
1.18 kristaps 536:
537:
1.22 kristaps 538: /* ARGSUSED */
539: static void
540: post_IP(DECL_ARGS)
541: {
1.4 kristaps 542:
1.22 kristaps 543: switch (n->type) {
544: case (MAN_HEAD):
545: term_flushln(p);
546: p->flags &= ~TERMP_NOBREAK;
547: p->rmargin = p->maxrmargin;
548: break;
549: case (MAN_BODY):
550: term_flushln(p);
551: p->flags &= ~TERMP_NOLPAD;
552: break;
553: default:
554: break;
555: }
1.4 kristaps 556: }
557:
558:
559: /* ARGSUSED */
560: static int
1.1 kristaps 561: pre_TP(DECL_ARGS)
562: {
1.23 kristaps 563: const struct man_node *nn;
564: size_t len;
565: int ival;
1.1 kristaps 566:
1.21 kristaps 567: switch (n->type) {
568: case (MAN_HEAD):
569: p->flags |= TERMP_NOBREAK;
570: p->flags |= TERMP_TWOSPACE;
571: break;
572: case (MAN_BODY):
573: p->flags |= TERMP_NOLPAD;
574: p->flags |= TERMP_NOSPACE;
1.23 kristaps 575: break;
576: case (MAN_BLOCK):
1.39 kristaps 577: print_bvspace(p, n);
1.23 kristaps 578: /* FALLTHROUGH */
579: default:
580: return(1);
581: }
582:
1.24 kristaps 583: len = (size_t)mt->lmargin;
1.23 kristaps 584: ival = -1;
585:
586: /* Calculate offset. */
587:
1.56 kristaps 588: if (NULL != (nn = n->parent->head->child)) {
589: while (nn && MAN_TEXT != nn->type)
590: nn = nn->next;
591: if (nn && nn->next)
1.45 kristaps 592: if ((ival = a2width(nn)) >= 0)
1.23 kristaps 593: len = (size_t)ival;
1.56 kristaps 594: }
1.23 kristaps 595:
596: switch (n->type) {
597: case (MAN_HEAD):
598: /* Handle zero-length properly. */
599: if (0 == len)
600: len = 1;
601:
1.26 kristaps 602: p->offset = mt->offset;
603: p->rmargin = mt->offset + len;
1.23 kristaps 604:
605: /* Don't print same-line elements. */
606: for (nn = n->child; nn; nn = nn->next)
607: if (nn->line > n->line)
1.45 kristaps 608: print_man_node(p, mt, nn, m);
1.24 kristaps 609:
610: if (ival >= 0)
1.26 kristaps 611: mt->lmargin = (size_t)ival;
1.24 kristaps 612:
1.23 kristaps 613: return(0);
614: case (MAN_BODY):
1.26 kristaps 615: p->offset = mt->offset + len;
1.23 kristaps 616: p->rmargin = p->maxrmargin;
1.21 kristaps 617: break;
618: default:
619: break;
620: }
1.16 kristaps 621:
1.21 kristaps 622: return(1);
623: }
1.1 kristaps 624:
625:
1.21 kristaps 626: /* ARGSUSED */
627: static void
628: post_TP(DECL_ARGS)
629: {
1.1 kristaps 630:
1.21 kristaps 631: switch (n->type) {
632: case (MAN_HEAD):
633: term_flushln(p);
634: p->flags &= ~TERMP_NOBREAK;
635: p->flags &= ~TERMP_TWOSPACE;
636: p->rmargin = p->maxrmargin;
637: break;
638: case (MAN_BODY):
639: term_flushln(p);
640: p->flags &= ~TERMP_NOLPAD;
641: break;
642: default:
643: break;
644: }
1.1 kristaps 645: }
646:
647:
1.3 kristaps 648: /* ARGSUSED */
1.1 kristaps 649: static int
650: pre_SS(DECL_ARGS)
651: {
652:
1.19 kristaps 653: switch (n->type) {
654: case (MAN_BLOCK):
1.24 kristaps 655: mt->lmargin = INDENT;
1.26 kristaps 656: mt->offset = INDENT;
1.24 kristaps 657: /* If following a prior empty `SS', no vspace. */
658: if (n->prev && MAN_SS == n->prev->tok)
659: if (NULL == n->prev->body->child)
660: break;
661: if (NULL == n->prev)
662: break;
663: term_vspace(p);
1.19 kristaps 664: break;
665: case (MAN_HEAD):
1.52 kristaps 666: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 667: p->offset = HALFINDENT;
668: break;
1.24 kristaps 669: case (MAN_BODY):
1.26 kristaps 670: p->offset = mt->offset;
1.24 kristaps 671: break;
1.19 kristaps 672: default:
673: break;
674: }
675:
1.1 kristaps 676: return(1);
677: }
678:
679:
1.3 kristaps 680: /* ARGSUSED */
1.1 kristaps 681: static void
682: post_SS(DECL_ARGS)
683: {
684:
1.19 kristaps 685: switch (n->type) {
686: case (MAN_HEAD):
687: term_newln(p);
688: break;
1.24 kristaps 689: case (MAN_BODY):
690: term_newln(p);
691: break;
1.19 kristaps 692: default:
693: break;
694: }
1.1 kristaps 695: }
696:
697:
1.3 kristaps 698: /* ARGSUSED */
1.1 kristaps 699: static int
700: pre_SH(DECL_ARGS)
701: {
1.22 kristaps 702:
1.19 kristaps 703: switch (n->type) {
704: case (MAN_BLOCK):
1.24 kristaps 705: mt->lmargin = INDENT;
1.26 kristaps 706: mt->offset = INDENT;
1.22 kristaps 707: /* If following a prior empty `SH', no vspace. */
1.19 kristaps 708: if (n->prev && MAN_SH == n->prev->tok)
709: if (NULL == n->prev->body->child)
710: break;
1.61 kristaps 711: /* If the first macro, no vspae. */
712: if (NULL == n->prev)
713: break;
1.19 kristaps 714: term_vspace(p);
715: break;
716: case (MAN_HEAD):
1.52 kristaps 717: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 718: p->offset = 0;
719: break;
720: case (MAN_BODY):
1.26 kristaps 721: p->offset = mt->offset;
1.19 kristaps 722: break;
723: default:
724: break;
725: }
1.1 kristaps 726:
727: return(1);
728: }
729:
730:
1.3 kristaps 731: /* ARGSUSED */
1.1 kristaps 732: static void
733: post_SH(DECL_ARGS)
734: {
735:
1.19 kristaps 736: switch (n->type) {
737: case (MAN_HEAD):
738: term_newln(p);
739: break;
740: case (MAN_BODY):
741: term_newln(p);
742: break;
743: default:
744: break;
745: }
1.1 kristaps 746: }
747:
748:
1.26 kristaps 749: /* ARGSUSED */
750: static int
751: pre_RS(DECL_ARGS)
752: {
753: const struct man_node *nn;
754: int ival;
755:
756: switch (n->type) {
757: case (MAN_BLOCK):
758: term_newln(p);
759: return(1);
760: case (MAN_HEAD):
761: return(0);
762: default:
763: break;
764: }
765:
766: if (NULL == (nn = n->parent->head->child)) {
767: mt->offset = mt->lmargin + INDENT;
768: p->offset = mt->offset;
769: return(1);
770: }
771:
1.45 kristaps 772: if ((ival = a2width(nn)) < 0)
1.26 kristaps 773: return(1);
774:
775: mt->offset = INDENT + (size_t)ival;
776: p->offset = mt->offset;
777:
778: return(1);
779: }
780:
781:
782: /* ARGSUSED */
783: static void
784: post_RS(DECL_ARGS)
785: {
786:
787: switch (n->type) {
788: case (MAN_BLOCK):
789: mt->offset = mt->lmargin = INDENT;
1.59 kristaps 790: break;
791: case (MAN_HEAD):
1.26 kristaps 792: break;
793: default:
794: term_newln(p);
795: p->offset = INDENT;
796: break;
797: }
798: }
799:
800:
1.1 kristaps 801: static void
1.45 kristaps 802: print_man_node(DECL_ARGS)
1.1 kristaps 803: {
1.65 joerg 804: size_t rm, rmax;
1.54 kristaps 805: int c;
1.1 kristaps 806:
807: c = 1;
808:
809: switch (n->type) {
810: case(MAN_TEXT):
1.4 kristaps 811: if (0 == *n->string) {
812: term_vspace(p);
1.1 kristaps 813: break;
814: }
1.54 kristaps 815:
1.4 kristaps 816: term_word(p, n->string);
1.52 kristaps 817:
1.19 kristaps 818: /* FIXME: this means that macro lines are munged! */
1.52 kristaps 819:
1.24 kristaps 820: if (MANT_LITERAL & mt->fl) {
1.65 joerg 821: rm = p->rmargin;
822: rmax = p->maxrmargin;
1.60 kristaps 823: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19 kristaps 824: p->flags |= TERMP_NOSPACE;
825: term_flushln(p);
1.65 joerg 826: p->rmargin = rm;
827: p->maxrmargin = rmax;
1.19 kristaps 828: }
1.1 kristaps 829: break;
830: default:
1.56 kristaps 831: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
832: term_fontrepl(p, TERMFONT_NONE);
1.19 kristaps 833: if (termacts[n->tok].pre)
1.24 kristaps 834: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 835: break;
836: }
837:
838: if (c && n->child)
1.52 kristaps 839: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 840:
1.51 kristaps 841: if (MAN_TEXT != n->type) {
1.1 kristaps 842: if (termacts[n->tok].post)
1.24 kristaps 843: (*termacts[n->tok].post)(p, mt, n, m);
1.56 kristaps 844: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
845: term_fontrepl(p, TERMFONT_NONE);
1.51 kristaps 846: }
1.63 kristaps 847:
848: if (MAN_EOS & n->flags)
849: p->flags |= TERMP_SENTENCE;
1.1 kristaps 850: }
851:
852:
853: static void
1.52 kristaps 854: print_man_nodelist(DECL_ARGS)
1.1 kristaps 855: {
1.19 kristaps 856:
1.45 kristaps 857: print_man_node(p, mt, n, m);
1.1 kristaps 858: if ( ! n->next)
859: return;
1.52 kristaps 860: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 861: }
862:
863:
1.31 kristaps 864: static void
1.45 kristaps 865: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1 kristaps 866: {
1.43 kristaps 867: char buf[DATESIZ];
1.1 kristaps 868:
1.52 kristaps 869: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 870:
1.43 kristaps 871: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 872:
873: term_vspace(p);
874:
875: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
876: p->rmargin = p->maxrmargin - strlen(buf);
877: p->offset = 0;
878:
879: if (meta->source)
880: term_word(p, meta->source);
881: if (meta->source)
882: term_word(p, "");
883: term_flushln(p);
884:
885: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
886: p->offset = p->rmargin;
887: p->rmargin = p->maxrmargin;
888: p->flags &= ~TERMP_NOBREAK;
889:
890: term_word(p, buf);
891: term_flushln(p);
892: }
893:
894:
1.31 kristaps 895: static void
1.46 kristaps 896: print_man_head(struct termp *p, const struct man_meta *m)
1.1 kristaps 897: {
1.46 kristaps 898: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 899: size_t buflen, titlen;
1.1 kristaps 900:
1.62 kristaps 901: /*
902: * Note that old groff would spit out some spaces before the
903: * header. We discontinue this strange behaviour, but at one
904: * point we did so here.
905: */
906:
1.1 kristaps 907: p->rmargin = p->maxrmargin;
1.58 kristaps 908:
1.1 kristaps 909: p->offset = 0;
1.46 kristaps 910: buf[0] = title[0] = '\0';
1.1 kristaps 911:
1.46 kristaps 912: if (m->vol)
913: strlcpy(buf, m->vol, BUFSIZ);
1.57 kristaps 914: buflen = strlen(buf);
1.1 kristaps 915:
1.64 kristaps 916: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.57 kristaps 917: titlen = strlen(title);
1.1 kristaps 918:
919: p->offset = 0;
1.57 kristaps 920: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
921: (p->maxrmargin - strlen(buf) + 1) / 2 :
922: p->maxrmargin - buflen;
1.1 kristaps 923: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
924:
925: term_word(p, title);
926: term_flushln(p);
927:
928: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
929: p->offset = p->rmargin;
1.57 kristaps 930: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
931: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 932:
933: term_word(p, buf);
934: term_flushln(p);
935:
936: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 937: if (p->rmargin + titlen <= p->maxrmargin) {
938: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
939: p->offset = p->rmargin;
940: p->rmargin = p->maxrmargin;
941: term_word(p, title);
942: term_flushln(p);
943: }
1.1 kristaps 944:
945: p->rmargin = p->maxrmargin;
946: p->offset = 0;
947: p->flags &= ~TERMP_NOSPACE;
1.61 kristaps 948:
1.62 kristaps 949: /*
950: * Groff likes to have some leading spaces before content. Well
951: * that's fine by me.
952: */
953:
1.61 kristaps 954: term_vspace(p);
955: term_vspace(p);
956: term_vspace(p);
1.1 kristaps 957: }
CVSweb