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