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