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