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