Annotation of mandoc/man_term.c, Revision 1.58
1.58 ! kristaps 1: /* $Id: man_term.c,v 1.57 2010/03/23 11:30:48 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.1 kristaps 145: };
146:
147:
148:
1.31 kristaps 149: void
1.36 kristaps 150: terminal_man(void *arg, const struct man *man)
1.1 kristaps 151: {
1.36 kristaps 152: struct termp *p;
153: const struct man_node *n;
154: const struct man_meta *m;
155: struct mtermp mt;
156:
157: p = (struct termp *)arg;
158:
1.58 ! kristaps 159: p->overstep = 0;
! 160: p->maxrmargin = 65;
! 161:
1.36 kristaps 162: if (NULL == p->symtab)
163: switch (p->enc) {
164: case (TERMENC_ASCII):
165: p->symtab = chars_init(CHARS_ASCII);
166: break;
167: default:
168: abort();
169: /* NOTREACHED */
170: }
171:
172: n = man_node(man);
173: m = man_meta(man);
1.1 kristaps 174:
1.45 kristaps 175: print_man_head(p, m);
1.1 kristaps 176: p->flags |= TERMP_NOSPACE;
1.19 kristaps 177:
1.24 kristaps 178: mt.fl = 0;
179: mt.lmargin = INDENT;
1.26 kristaps 180: mt.offset = INDENT;
1.24 kristaps 181:
1.36 kristaps 182: if (n->child)
1.52 kristaps 183: print_man_nodelist(p, &mt, n->child, m);
1.45 kristaps 184: print_man_foot(p, m);
1.1 kristaps 185: }
186:
187:
1.39 kristaps 188: static int
1.45 kristaps 189: a2height(const struct man_node *n)
1.18 kristaps 190: {
1.40 kristaps 191: struct roffsu su;
1.18 kristaps 192:
1.39 kristaps 193: assert(MAN_TEXT == n->type);
194: assert(n->string);
1.40 kristaps 195: if ( ! a2roffsu(n->string, &su, SCALE_VS))
196: SCALE_VS_INIT(&su, strlen(n->string));
1.18 kristaps 197:
1.41 kristaps 198: return((int)term_vspan(&su));
1.18 kristaps 199: }
200:
201:
202: static int
1.45 kristaps 203: a2width(const struct man_node *n)
1.38 kristaps 204: {
1.40 kristaps 205: struct roffsu su;
1.38 kristaps 206:
1.39 kristaps 207: assert(MAN_TEXT == n->type);
208: assert(n->string);
1.40 kristaps 209: if ( ! a2roffsu(n->string, &su, SCALE_BU))
1.41 kristaps 210: return(-1);
1.40 kristaps 211:
1.41 kristaps 212: return((int)term_hspan(&su));
1.38 kristaps 213: }
214:
215:
1.39 kristaps 216: static void
217: print_bvspace(struct termp *p, const struct man_node *n)
1.18 kristaps 218: {
1.39 kristaps 219: term_newln(p);
1.18 kristaps 220:
1.39 kristaps 221: if (NULL == n->prev)
222: return;
1.18 kristaps 223:
1.39 kristaps 224: if (MAN_SS == n->prev->tok)
225: return;
226: if (MAN_SH == n->prev->tok)
227: return;
1.18 kristaps 228:
1.39 kristaps 229: term_vspace(p);
1.18 kristaps 230: }
231:
232:
1.3 kristaps 233: /* ARGSUSED */
1.1 kristaps 234: static int
1.29 kristaps 235: pre_ign(DECL_ARGS)
236: {
237:
238: return(0);
239: }
240:
241:
242: /* ARGSUSED */
243: static int
1.1 kristaps 244: pre_I(DECL_ARGS)
245: {
246:
1.52 kristaps 247: term_fontrepl(p, TERMFONT_UNDER);
1.19 kristaps 248: return(1);
249: }
250:
251:
252: /* ARGSUSED */
1.3 kristaps 253: static int
1.19 kristaps 254: pre_fi(DECL_ARGS)
255: {
256:
1.57 kristaps 257: p->rmargin = p->maxrmargin = 65;
1.24 kristaps 258: mt->fl &= ~MANT_LITERAL;
1.19 kristaps 259: return(1);
260: }
261:
262:
263: /* ARGSUSED */
264: static int
265: pre_nf(DECL_ARGS)
266: {
267:
1.57 kristaps 268: p->rmargin = p->maxrmargin = 78;
1.19 kristaps 269: term_newln(p);
1.24 kristaps 270: mt->fl |= MANT_LITERAL;
1.57 kristaps 271:
272: return(MAN_Vb != n->tok);
1.19 kristaps 273: }
274:
275:
276: /* ARGSUSED */
277: static int
1.35 kristaps 278: pre_RB(DECL_ARGS)
1.3 kristaps 279: {
280: const struct man_node *nn;
281: int i;
282:
283: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 284: if (i % 2 && MAN_RB == n->tok)
1.52 kristaps 285: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 286: else if ( ! (i % 2) && MAN_RB != n->tok)
1.52 kristaps 287: term_fontrepl(p, TERMFONT_BOLD);
288: else
289: term_fontrepl(p, TERMFONT_NONE);
1.35 kristaps 290:
1.4 kristaps 291: if (i > 0)
292: p->flags |= TERMP_NOSPACE;
1.35 kristaps 293:
1.45 kristaps 294: print_man_node(p, mt, nn, m);
1.3 kristaps 295: }
296: return(0);
297: }
298:
299:
300: /* ARGSUSED */
301: static int
302: pre_RI(DECL_ARGS)
303: {
304: const struct man_node *nn;
305: int i;
306:
307: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.49 kristaps 308: if (i % 2 && MAN_RI == n->tok)
1.52 kristaps 309: term_fontrepl(p, TERMFONT_UNDER);
1.49 kristaps 310: else if ( ! (i % 2) && MAN_RI != n->tok)
1.52 kristaps 311: term_fontrepl(p, TERMFONT_UNDER);
312: else
313: term_fontrepl(p, TERMFONT_NONE);
1.49 kristaps 314:
1.4 kristaps 315: if (i > 0)
316: p->flags |= TERMP_NOSPACE;
1.52 kristaps 317:
1.45 kristaps 318: print_man_node(p, mt, nn, m);
1.3 kristaps 319: }
320: return(0);
321: }
322:
323:
324: /* ARGSUSED */
325: static int
326: pre_BI(DECL_ARGS)
327: {
1.35 kristaps 328: const struct man_node *nn;
329: int i;
1.3 kristaps 330:
331: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.35 kristaps 332: if (i % 2 && MAN_BI == n->tok)
1.52 kristaps 333: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 334: else if (i % 2)
1.52 kristaps 335: term_fontrepl(p, TERMFONT_BOLD);
1.35 kristaps 336: else if (MAN_BI == n->tok)
1.52 kristaps 337: term_fontrepl(p, TERMFONT_BOLD);
1.30 kristaps 338: else
1.52 kristaps 339: term_fontrepl(p, TERMFONT_UNDER);
1.35 kristaps 340:
341: if (i)
1.4 kristaps 342: p->flags |= TERMP_NOSPACE;
1.52 kristaps 343:
1.45 kristaps 344: print_man_node(p, mt, nn, m);
1.3 kristaps 345: }
346: return(0);
347: }
348:
349:
350: /* ARGSUSED */
1.1 kristaps 351: static int
352: pre_B(DECL_ARGS)
353: {
354:
1.52 kristaps 355: term_fontrepl(p, TERMFONT_BOLD);
1.1 kristaps 356: return(1);
357: }
358:
359:
1.3 kristaps 360: /* ARGSUSED */
1.1 kristaps 361: static int
1.19 kristaps 362: pre_sp(DECL_ARGS)
363: {
364: int i, len;
365:
1.45 kristaps 366: len = n->child ? a2height(n->child) : 1;
1.38 kristaps 367:
1.19 kristaps 368: if (0 == len)
369: term_newln(p);
370: for (i = 0; i < len; i++)
371: term_vspace(p);
372:
373: return(0);
374: }
375:
376:
377: /* ARGSUSED */
378: static int
1.15 kristaps 379: pre_br(DECL_ARGS)
380: {
381:
382: term_newln(p);
383: return(0);
384: }
385:
386:
387: /* ARGSUSED */
388: static int
1.19 kristaps 389: pre_HP(DECL_ARGS)
390: {
1.24 kristaps 391: size_t len;
392: int ival;
393: const struct man_node *nn;
1.19 kristaps 394:
1.20 kristaps 395: switch (n->type) {
396: case (MAN_BLOCK):
1.39 kristaps 397: print_bvspace(p, n);
1.24 kristaps 398: return(1);
1.20 kristaps 399: case (MAN_BODY):
400: p->flags |= TERMP_NOBREAK;
401: p->flags |= TERMP_TWOSPACE;
402: break;
403: default:
404: return(0);
405: }
406:
1.26 kristaps 407: len = mt->lmargin;
1.24 kristaps 408: ival = -1;
409:
410: /* Calculate offset. */
411:
1.39 kristaps 412: if (NULL != (nn = n->parent->head->child))
1.45 kristaps 413: if ((ival = a2width(nn)) >= 0)
1.24 kristaps 414: len = (size_t)ival;
415:
416: if (0 == len)
417: len = 1;
418:
1.26 kristaps 419: p->offset = mt->offset;
420: p->rmargin = mt->offset + len;
1.24 kristaps 421:
422: if (ival >= 0)
1.26 kristaps 423: mt->lmargin = (size_t)ival;
1.24 kristaps 424:
1.19 kristaps 425: return(1);
426: }
427:
428:
429: /* ARGSUSED */
1.20 kristaps 430: static void
431: post_HP(DECL_ARGS)
432: {
433:
434: switch (n->type) {
1.24 kristaps 435: case (MAN_BLOCK):
436: term_flushln(p);
437: break;
1.20 kristaps 438: case (MAN_BODY):
439: term_flushln(p);
440: p->flags &= ~TERMP_NOBREAK;
441: p->flags &= ~TERMP_TWOSPACE;
1.26 kristaps 442: p->offset = mt->offset;
1.20 kristaps 443: p->rmargin = p->maxrmargin;
444: break;
445: default:
446: break;
447: }
448: }
449:
450:
451: /* ARGSUSED */
1.19 kristaps 452: static int
1.1 kristaps 453: pre_PP(DECL_ARGS)
454: {
455:
1.19 kristaps 456: switch (n->type) {
457: case (MAN_BLOCK):
1.24 kristaps 458: mt->lmargin = INDENT;
1.39 kristaps 459: print_bvspace(p, n);
1.19 kristaps 460: break;
461: default:
1.26 kristaps 462: p->offset = mt->offset;
1.19 kristaps 463: break;
464: }
465:
466: return(1);
1.1 kristaps 467: }
468:
469:
1.3 kristaps 470: /* ARGSUSED */
1.1 kristaps 471: static int
1.4 kristaps 472: pre_IP(DECL_ARGS)
473: {
1.22 kristaps 474: const struct man_node *nn;
475: size_t len;
476: int ival;
1.18 kristaps 477:
1.22 kristaps 478: switch (n->type) {
479: case (MAN_BODY):
480: p->flags |= TERMP_NOLPAD;
481: p->flags |= TERMP_NOSPACE;
482: break;
483: case (MAN_HEAD):
484: p->flags |= TERMP_NOBREAK;
485: p->flags |= TERMP_TWOSPACE;
486: break;
1.23 kristaps 487: case (MAN_BLOCK):
1.39 kristaps 488: print_bvspace(p, n);
1.23 kristaps 489: /* FALLTHROUGH */
1.22 kristaps 490: default:
491: return(1);
492: }
1.18 kristaps 493:
1.26 kristaps 494: len = mt->lmargin;
1.22 kristaps 495: ival = -1;
1.4 kristaps 496:
1.22 kristaps 497: /* Calculate offset. */
1.4 kristaps 498:
1.22 kristaps 499: if (NULL != (nn = n->parent->head->child))
500: if (NULL != (nn = nn->next)) {
501: for ( ; nn->next; nn = nn->next)
502: /* Do nothing. */ ;
1.45 kristaps 503: if ((ival = a2width(nn)) >= 0)
1.22 kristaps 504: len = (size_t)ival;
505: }
1.4 kristaps 506:
1.22 kristaps 507: switch (n->type) {
508: case (MAN_HEAD):
1.23 kristaps 509: /* Handle zero-width lengths. */
510: if (0 == len)
511: len = 1;
512:
1.26 kristaps 513: p->offset = mt->offset;
514: p->rmargin = mt->offset + len;
1.22 kristaps 515: if (ival < 0)
516: break;
1.18 kristaps 517:
1.24 kristaps 518: /* Set the saved left-margin. */
1.26 kristaps 519: mt->lmargin = (size_t)ival;
1.24 kristaps 520:
1.22 kristaps 521: /* Don't print the length value. */
522: for (nn = n->child; nn->next; nn = nn->next)
1.45 kristaps 523: print_man_node(p, mt, nn, m);
1.22 kristaps 524: return(0);
1.23 kristaps 525: case (MAN_BODY):
1.26 kristaps 526: p->offset = mt->offset + len;
1.23 kristaps 527: p->rmargin = p->maxrmargin;
528: break;
1.22 kristaps 529: default:
530: break;
1.18 kristaps 531: }
532:
1.22 kristaps 533: return(1);
534: }
1.18 kristaps 535:
536:
1.22 kristaps 537: /* ARGSUSED */
538: static void
539: post_IP(DECL_ARGS)
540: {
1.4 kristaps 541:
1.22 kristaps 542: switch (n->type) {
543: case (MAN_HEAD):
544: term_flushln(p);
545: p->flags &= ~TERMP_NOBREAK;
546: p->flags &= ~TERMP_TWOSPACE;
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;
711: term_vspace(p);
712: break;
713: case (MAN_HEAD):
1.52 kristaps 714: term_fontrepl(p, TERMFONT_BOLD);
1.19 kristaps 715: p->offset = 0;
716: break;
717: case (MAN_BODY):
1.26 kristaps 718: p->offset = mt->offset;
1.19 kristaps 719: break;
720: default:
721: break;
722: }
1.1 kristaps 723:
724: return(1);
725: }
726:
727:
1.3 kristaps 728: /* ARGSUSED */
1.1 kristaps 729: static void
730: post_SH(DECL_ARGS)
731: {
732:
1.19 kristaps 733: switch (n->type) {
734: case (MAN_HEAD):
735: term_newln(p);
736: break;
737: case (MAN_BODY):
738: term_newln(p);
739: break;
740: default:
741: break;
742: }
1.1 kristaps 743: }
744:
745:
1.26 kristaps 746: /* ARGSUSED */
747: static int
748: pre_RS(DECL_ARGS)
749: {
750: const struct man_node *nn;
751: int ival;
752:
753: switch (n->type) {
754: case (MAN_BLOCK):
755: term_newln(p);
756: return(1);
757: case (MAN_HEAD):
758: return(0);
759: default:
760: break;
761: }
762:
763: if (NULL == (nn = n->parent->head->child)) {
764: mt->offset = mt->lmargin + INDENT;
765: p->offset = mt->offset;
766: return(1);
767: }
768:
1.45 kristaps 769: if ((ival = a2width(nn)) < 0)
1.26 kristaps 770: return(1);
771:
772: mt->offset = INDENT + (size_t)ival;
773: p->offset = mt->offset;
774:
775: return(1);
776: }
777:
778:
779: /* ARGSUSED */
780: static void
781: post_RS(DECL_ARGS)
782: {
783:
784: switch (n->type) {
785: case (MAN_BLOCK):
786: mt->offset = mt->lmargin = INDENT;
787: break;
788: default:
789: term_newln(p);
790: p->offset = INDENT;
791: break;
792: }
793: }
794:
795:
1.1 kristaps 796: static void
1.45 kristaps 797: print_man_node(DECL_ARGS)
1.1 kristaps 798: {
1.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.19 kristaps 815: p->flags |= TERMP_NOSPACE;
816: term_flushln(p);
817: }
1.1 kristaps 818: break;
819: default:
1.56 kristaps 820: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
821: term_fontrepl(p, TERMFONT_NONE);
1.19 kristaps 822: if (termacts[n->tok].pre)
1.24 kristaps 823: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 824: break;
825: }
826:
827: if (c && n->child)
1.52 kristaps 828: print_man_nodelist(p, mt, n->child, m);
1.1 kristaps 829:
1.51 kristaps 830: if (MAN_TEXT != n->type) {
1.1 kristaps 831: if (termacts[n->tok].post)
1.24 kristaps 832: (*termacts[n->tok].post)(p, mt, n, m);
1.56 kristaps 833: if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
834: term_fontrepl(p, TERMFONT_NONE);
1.51 kristaps 835: }
1.1 kristaps 836: }
837:
838:
839: static void
1.52 kristaps 840: print_man_nodelist(DECL_ARGS)
1.1 kristaps 841: {
1.19 kristaps 842:
1.45 kristaps 843: print_man_node(p, mt, n, m);
1.1 kristaps 844: if ( ! n->next)
845: return;
1.52 kristaps 846: print_man_nodelist(p, mt, n->next, m);
1.1 kristaps 847: }
848:
849:
1.31 kristaps 850: static void
1.45 kristaps 851: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1 kristaps 852: {
1.43 kristaps 853: char buf[DATESIZ];
1.1 kristaps 854:
1.52 kristaps 855: term_fontrepl(p, TERMFONT_NONE);
1.50 kristaps 856:
1.43 kristaps 857: time2a(meta->date, buf, DATESIZ);
1.1 kristaps 858:
859: term_vspace(p);
860:
861: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
862: p->rmargin = p->maxrmargin - strlen(buf);
863: p->offset = 0;
864:
865: if (meta->source)
866: term_word(p, meta->source);
867: if (meta->source)
868: term_word(p, "");
869: term_flushln(p);
870:
871: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
872: p->offset = p->rmargin;
873: p->rmargin = p->maxrmargin;
874: p->flags &= ~TERMP_NOBREAK;
875:
876: term_word(p, buf);
877: term_flushln(p);
878: }
879:
880:
1.31 kristaps 881: static void
1.46 kristaps 882: print_man_head(struct termp *p, const struct man_meta *m)
1.1 kristaps 883: {
1.46 kristaps 884: char buf[BUFSIZ], title[BUFSIZ];
1.57 kristaps 885: size_t buflen, titlen;
1.1 kristaps 886:
887: p->rmargin = p->maxrmargin;
1.58 ! kristaps 888:
1.1 kristaps 889: p->offset = 0;
1.46 kristaps 890: buf[0] = title[0] = '\0';
1.1 kristaps 891:
1.46 kristaps 892: if (m->vol)
893: strlcpy(buf, m->vol, BUFSIZ);
1.57 kristaps 894: buflen = strlen(buf);
1.1 kristaps 895:
1.46 kristaps 896: snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
1.57 kristaps 897: titlen = strlen(title);
1.1 kristaps 898:
899: p->offset = 0;
1.57 kristaps 900: p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
901: (p->maxrmargin - strlen(buf) + 1) / 2 :
902: p->maxrmargin - buflen;
1.1 kristaps 903: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
904:
905: term_word(p, title);
906: term_flushln(p);
907:
908: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
909: p->offset = p->rmargin;
1.57 kristaps 910: p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
911: p->maxrmargin - titlen : p->maxrmargin;
1.1 kristaps 912:
913: term_word(p, buf);
914: term_flushln(p);
915:
916: p->flags &= ~TERMP_NOBREAK;
1.57 kristaps 917: if (p->rmargin + titlen <= p->maxrmargin) {
918: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
919: p->offset = p->rmargin;
920: p->rmargin = p->maxrmargin;
921: term_word(p, title);
922: term_flushln(p);
923: }
1.1 kristaps 924:
925: p->rmargin = p->maxrmargin;
926: p->offset = 0;
927: p->flags &= ~TERMP_NOSPACE;
928: }
CVSweb