Annotation of src/usr.bin/mandoc/man_term.c, Revision 1.14
1.14 ! schwarze 1: /* $Id: man_term.c,v 1.13 2009/08/22 23:17:40 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:
220: p->flags |= TERMP_UNDER;
221: return(1);
222: }
223:
224:
225: /* ARGSUSED */
1.11 schwarze 226: static int
227: pre_r(DECL_ARGS)
228: {
229:
230: p->flags &= ~TERMP_UNDER;
231: p->flags &= ~TERMP_BOLD;
232: return(1);
233: }
234:
235:
236: /* ARGSUSED */
237: static void
238: post_i(DECL_ARGS)
239: {
240:
241: if (n->nchild)
242: p->flags &= ~TERMP_UNDER;
243: }
244:
245:
246: /* ARGSUSED */
1.1 kristaps 247: static void
248: post_I(DECL_ARGS)
249: {
250:
251: p->flags &= ~TERMP_UNDER;
252: }
253:
254:
255: /* ARGSUSED */
256: static int
1.11 schwarze 257: pre_fi(DECL_ARGS)
258: {
259:
260: mt->fl &= ~MANT_LITERAL;
261: return(1);
262: }
263:
264:
265: /* ARGSUSED */
266: static int
267: pre_nf(DECL_ARGS)
268: {
269:
270: term_newln(p);
271: mt->fl |= MANT_LITERAL;
272: return(1);
273: }
274:
275:
276: /* ARGSUSED */
277: static int
1.1 kristaps 278: pre_IR(DECL_ARGS)
279: {
280: const struct man_node *nn;
281: int i;
282:
283: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
284: if ( ! (i % 2))
285: p->flags |= TERMP_UNDER;
286: if (i > 0)
287: p->flags |= TERMP_NOSPACE;
1.11 schwarze 288: print_node(p, mt, nn, m);
1.1 kristaps 289: if ( ! (i % 2))
290: p->flags &= ~TERMP_UNDER;
291: }
292: return(0);
293: }
294:
295:
296: /* ARGSUSED */
297: static int
298: pre_IB(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: p->flags |= i % 2 ? TERMP_BOLD : TERMP_UNDER;
305: if (i > 0)
306: p->flags |= TERMP_NOSPACE;
1.11 schwarze 307: print_node(p, mt, nn, m);
1.1 kristaps 308: p->flags &= i % 2 ? ~TERMP_BOLD : ~TERMP_UNDER;
309: }
310: return(0);
311: }
312:
313:
314: /* ARGSUSED */
315: static int
316: pre_RB(DECL_ARGS)
317: {
318: const struct man_node *nn;
319: int i;
320:
321: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
322: if (i % 2)
323: p->flags |= TERMP_BOLD;
324: if (i > 0)
325: p->flags |= TERMP_NOSPACE;
1.11 schwarze 326: print_node(p, mt, nn, m);
1.1 kristaps 327: if (i % 2)
328: p->flags &= ~TERMP_BOLD;
329: }
330: return(0);
331: }
332:
333:
334: /* ARGSUSED */
335: static int
336: pre_RI(DECL_ARGS)
337: {
338: const struct man_node *nn;
339: int i;
340:
341: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
342: if ( ! (i % 2))
343: p->flags |= TERMP_UNDER;
344: if (i > 0)
345: p->flags |= TERMP_NOSPACE;
1.11 schwarze 346: print_node(p, mt, nn, m);
1.1 kristaps 347: if ( ! (i % 2))
348: p->flags &= ~TERMP_UNDER;
349: }
350: return(0);
351: }
352:
353:
354: /* ARGSUSED */
355: static int
356: pre_BR(DECL_ARGS)
357: {
358: const struct man_node *nn;
359: int i;
360:
361: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
362: if ( ! (i % 2))
363: p->flags |= TERMP_BOLD;
364: if (i > 0)
365: p->flags |= TERMP_NOSPACE;
1.11 schwarze 366: print_node(p, mt, nn, m);
1.1 kristaps 367: if ( ! (i % 2))
368: p->flags &= ~TERMP_BOLD;
369: }
370: return(0);
371: }
372:
373:
374: /* ARGSUSED */
375: static int
376: pre_BI(DECL_ARGS)
377: {
378: const struct man_node *nn;
379: int i;
380:
381: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
382: p->flags |= i % 2 ? TERMP_UNDER : TERMP_BOLD;
383: if (i > 0)
384: p->flags |= TERMP_NOSPACE;
1.11 schwarze 385: print_node(p, mt, nn, m);
1.1 kristaps 386: p->flags &= i % 2 ? ~TERMP_UNDER : ~TERMP_BOLD;
387: }
388: return(0);
389: }
390:
391:
392: /* ARGSUSED */
393: static int
394: pre_B(DECL_ARGS)
395: {
396:
397: p->flags |= TERMP_BOLD;
398: return(1);
399: }
400:
401:
402: /* ARGSUSED */
403: static void
404: post_B(DECL_ARGS)
405: {
406:
407: p->flags &= ~TERMP_BOLD;
408: }
409:
410:
411: /* ARGSUSED */
412: static int
1.11 schwarze 413: pre_sp(DECL_ARGS)
414: {
415: int i, len;
416:
417: if (NULL == n->child) {
418: term_vspace(p);
419: return(0);
420: }
421:
422: len = atoi(n->child->string);
423: if (0 == len)
424: term_newln(p);
425: for (i = 0; i < len; i++)
426: term_vspace(p);
427:
428: return(0);
429: }
430:
431:
432: /* ARGSUSED */
433: static int
1.8 schwarze 434: pre_br(DECL_ARGS)
435: {
436:
437: term_newln(p);
438: return(0);
439: }
440:
441:
442: /* ARGSUSED */
443: static int
1.11 schwarze 444: pre_HP(DECL_ARGS)
445: {
446: size_t len;
447: int ival;
448: const struct man_node *nn;
449:
450: switch (n->type) {
451: case (MAN_BLOCK):
452: fmt_block_vspace(p, n);
453: return(1);
454: case (MAN_BODY):
455: p->flags |= TERMP_NOBREAK;
456: p->flags |= TERMP_TWOSPACE;
457: break;
458: default:
459: return(0);
460: }
461:
1.13 schwarze 462: len = mt->lmargin;
1.11 schwarze 463: ival = -1;
464:
465: /* Calculate offset. */
466:
467: if (NULL != (nn = n->parent->head->child))
468: if ((ival = arg_width(nn)) >= 0)
469: len = (size_t)ival;
470:
471: if (0 == len)
472: len = 1;
473:
1.13 schwarze 474: p->offset = mt->offset;
475: p->rmargin = mt->offset + len;
1.11 schwarze 476:
477: if (ival >= 0)
1.13 schwarze 478: mt->lmargin = (size_t)ival;
1.11 schwarze 479:
480: return(1);
481: }
482:
483:
484: /* ARGSUSED */
485: static void
486: post_HP(DECL_ARGS)
487: {
488:
489: switch (n->type) {
490: case (MAN_BLOCK):
491: term_flushln(p);
492: break;
493: case (MAN_BODY):
494: term_flushln(p);
495: p->flags &= ~TERMP_NOBREAK;
496: p->flags &= ~TERMP_TWOSPACE;
1.13 schwarze 497: p->offset = mt->offset;
1.11 schwarze 498: p->rmargin = p->maxrmargin;
499: break;
500: default:
501: break;
502: }
503: }
504:
505:
506: /* ARGSUSED */
507: static int
1.1 kristaps 508: pre_PP(DECL_ARGS)
509: {
510:
1.11 schwarze 511: switch (n->type) {
512: case (MAN_BLOCK):
513: mt->lmargin = INDENT;
514: fmt_block_vspace(p, n);
515: break;
516: default:
1.13 schwarze 517: p->offset = mt->offset;
1.11 schwarze 518: break;
519: }
520:
521: return(1);
1.1 kristaps 522: }
523:
524:
525: /* ARGSUSED */
526: static int
527: pre_IP(DECL_ARGS)
528: {
1.11 schwarze 529: const struct man_node *nn;
530: size_t len;
531: int ival;
532:
533: switch (n->type) {
534: case (MAN_BODY):
535: p->flags |= TERMP_NOLPAD;
536: p->flags |= TERMP_NOSPACE;
537: break;
538: case (MAN_HEAD):
539: p->flags |= TERMP_NOBREAK;
540: p->flags |= TERMP_TWOSPACE;
541: break;
542: case (MAN_BLOCK):
543: fmt_block_vspace(p, n);
544: /* FALLTHROUGH */
545: default:
546: return(1);
547: }
548:
1.13 schwarze 549: len = mt->lmargin;
1.11 schwarze 550: ival = -1;
551:
552: /* Calculate offset. */
553:
554: if (NULL != (nn = n->parent->head->child))
555: if (NULL != (nn = nn->next)) {
556: for ( ; nn->next; nn = nn->next)
557: /* Do nothing. */ ;
558: if ((ival = arg_width(nn)) >= 0)
559: len = (size_t)ival;
560: }
561:
562: switch (n->type) {
563: case (MAN_HEAD):
564: /* Handle zero-width lengths. */
565: if (0 == len)
566: len = 1;
567:
1.13 schwarze 568: p->offset = mt->offset;
569: p->rmargin = mt->offset + len;
1.11 schwarze 570: if (ival < 0)
571: break;
572:
573: /* Set the saved left-margin. */
1.13 schwarze 574: mt->lmargin = (size_t)ival;
1.1 kristaps 575:
1.11 schwarze 576: /* Don't print the length value. */
577: for (nn = n->child; nn->next; nn = nn->next)
578: print_node(p, mt, nn, m);
579: return(0);
580: case (MAN_BODY):
1.13 schwarze 581: p->offset = mt->offset + len;
1.11 schwarze 582: p->rmargin = p->maxrmargin;
583: break;
584: default:
585: break;
586: }
1.1 kristaps 587:
1.11 schwarze 588: return(1);
589: }
1.1 kristaps 590:
591:
1.11 schwarze 592: /* ARGSUSED */
593: static void
594: post_IP(DECL_ARGS)
595: {
1.4 schwarze 596:
1.11 schwarze 597: switch (n->type) {
598: case (MAN_HEAD):
599: term_flushln(p);
600: p->flags &= ~TERMP_NOBREAK;
601: p->flags &= ~TERMP_TWOSPACE;
602: p->rmargin = p->maxrmargin;
603: break;
604: case (MAN_BODY):
605: term_flushln(p);
606: p->flags &= ~TERMP_NOLPAD;
607: break;
608: default:
609: break;
610: }
1.1 kristaps 611: }
612:
613:
614: /* ARGSUSED */
615: static int
616: pre_TP(DECL_ARGS)
617: {
1.11 schwarze 618: const struct man_node *nn;
619: size_t len;
620: int ival;
621:
622: switch (n->type) {
623: case (MAN_HEAD):
624: p->flags |= TERMP_NOBREAK;
625: p->flags |= TERMP_TWOSPACE;
626: break;
627: case (MAN_BODY):
628: p->flags |= TERMP_NOLPAD;
629: p->flags |= TERMP_NOSPACE;
630: break;
631: case (MAN_BLOCK):
632: fmt_block_vspace(p, n);
633: /* FALLTHROUGH */
634: default:
635: return(1);
636: }
637:
638: len = (size_t)mt->lmargin;
639: ival = -1;
640:
641: /* Calculate offset. */
1.1 kristaps 642:
1.11 schwarze 643: if (NULL != (nn = n->parent->head->child))
644: if (NULL != nn->next)
645: if ((ival = arg_width(nn)) >= 0)
646: len = (size_t)ival;
1.8 schwarze 647:
1.11 schwarze 648: switch (n->type) {
649: case (MAN_HEAD):
650: /* Handle zero-length properly. */
651: if (0 == len)
652: len = 1;
653:
1.13 schwarze 654: p->offset = mt->offset;
655: p->rmargin = mt->offset + len;
1.11 schwarze 656:
657: /* Don't print same-line elements. */
658: for (nn = n->child; nn; nn = nn->next)
659: if (nn->line > n->line)
660: print_node(p, mt, nn, m);
661:
662: if (ival >= 0)
1.13 schwarze 663: mt->lmargin = (size_t)ival;
1.11 schwarze 664:
665: return(0);
666: case (MAN_BODY):
1.13 schwarze 667: p->offset = mt->offset + len;
1.11 schwarze 668: p->rmargin = p->maxrmargin;
669: break;
670: default:
671: break;
672: }
1.1 kristaps 673:
1.11 schwarze 674: return(1);
675: }
1.1 kristaps 676:
677:
1.11 schwarze 678: /* ARGSUSED */
679: static void
680: post_TP(DECL_ARGS)
681: {
1.1 kristaps 682:
1.11 schwarze 683: switch (n->type) {
684: case (MAN_HEAD):
685: term_flushln(p);
686: p->flags &= ~TERMP_NOBREAK;
687: p->flags &= ~TERMP_TWOSPACE;
688: p->rmargin = p->maxrmargin;
689: break;
690: case (MAN_BODY):
691: term_flushln(p);
692: p->flags &= ~TERMP_NOLPAD;
693: break;
694: default:
695: break;
696: }
1.1 kristaps 697: }
698:
699:
700: /* ARGSUSED */
701: static int
702: pre_SS(DECL_ARGS)
703: {
704:
1.11 schwarze 705: switch (n->type) {
706: case (MAN_BLOCK):
707: mt->lmargin = INDENT;
1.13 schwarze 708: mt->offset = INDENT;
1.11 schwarze 709: /* If following a prior empty `SS', no vspace. */
710: if (n->prev && MAN_SS == n->prev->tok)
711: if (NULL == n->prev->body->child)
712: break;
713: if (NULL == n->prev)
714: break;
715: term_vspace(p);
716: break;
717: case (MAN_HEAD):
718: p->flags |= TERMP_BOLD;
719: p->offset = HALFINDENT;
720: break;
721: case (MAN_BODY):
1.13 schwarze 722: p->offset = mt->offset;
1.11 schwarze 723: break;
724: default:
725: break;
726: }
727:
1.1 kristaps 728: return(1);
729: }
730:
731:
732: /* ARGSUSED */
733: static void
734: post_SS(DECL_ARGS)
735: {
736:
1.11 schwarze 737: switch (n->type) {
738: case (MAN_HEAD):
739: term_newln(p);
740: p->flags &= ~TERMP_BOLD;
741: break;
742: case (MAN_BODY):
743: term_newln(p);
744: break;
745: default:
746: break;
747: }
1.1 kristaps 748: }
749:
750:
751: /* ARGSUSED */
752: static int
753: pre_SH(DECL_ARGS)
754: {
755:
1.11 schwarze 756: switch (n->type) {
757: case (MAN_BLOCK):
758: mt->lmargin = INDENT;
1.13 schwarze 759: mt->offset = INDENT;
1.11 schwarze 760: /* If following a prior empty `SH', no vspace. */
761: if (n->prev && MAN_SH == n->prev->tok)
762: if (NULL == n->prev->body->child)
763: break;
764: term_vspace(p);
765: break;
766: case (MAN_HEAD):
767: p->flags |= TERMP_BOLD;
768: p->offset = 0;
769: break;
770: case (MAN_BODY):
1.13 schwarze 771: p->offset = mt->offset;
1.11 schwarze 772: break;
773: default:
774: break;
775: }
776:
1.1 kristaps 777: return(1);
778: }
779:
780:
781: /* ARGSUSED */
782: static void
783: post_SH(DECL_ARGS)
784: {
785:
1.11 schwarze 786: switch (n->type) {
787: case (MAN_HEAD):
788: term_newln(p);
789: p->flags &= ~TERMP_BOLD;
790: break;
791: case (MAN_BODY):
792: term_newln(p);
793: break;
794: default:
1.13 schwarze 795: break;
796: }
797: }
798:
799:
800: /* ARGSUSED */
801: static int
802: pre_RS(DECL_ARGS)
803: {
804: const struct man_node *nn;
805: int ival;
806:
807: switch (n->type) {
808: case (MAN_BLOCK):
809: term_newln(p);
810: return(1);
811: case (MAN_HEAD):
812: return(0);
813: default:
814: break;
815: }
816:
817: if (NULL == (nn = n->parent->head->child)) {
818: mt->offset = mt->lmargin + INDENT;
819: p->offset = mt->offset;
820: return(1);
821: }
822:
823: if ((ival = arg_width(nn)) < 0)
824: return(1);
825:
826: mt->offset = INDENT + (size_t)ival;
827: p->offset = mt->offset;
828:
829: return(1);
830: }
831:
832:
833: /* ARGSUSED */
834: static void
835: post_RS(DECL_ARGS)
836: {
837:
838: switch (n->type) {
839: case (MAN_BLOCK):
840: mt->offset = mt->lmargin = INDENT;
841: break;
842: default:
843: term_newln(p);
844: p->offset = INDENT;
1.11 schwarze 845: break;
846: }
1.1 kristaps 847: }
848:
849:
850: static void
851: print_node(DECL_ARGS)
852: {
853: int c, sz;
854:
855: c = 1;
856:
857: switch (n->type) {
858: case(MAN_TEXT):
859: if (0 == *n->string) {
860: term_vspace(p);
861: break;
862: }
863: /*
864: * Note! This is hacky. Here, we recognise the `\c'
865: * escape embedded in so many -man pages. It's supposed
866: * to remove the subsequent space, so we mark NOSPACE if
867: * it's encountered in the string.
868: */
869: sz = (int)strlen(n->string);
870: term_word(p, n->string);
871: if (sz >= 2 && n->string[sz - 1] == 'c' &&
872: n->string[sz - 2] == '\\')
873: p->flags |= TERMP_NOSPACE;
1.11 schwarze 874: /* FIXME: this means that macro lines are munged! */
875: if (MANT_LITERAL & mt->fl) {
876: p->flags |= TERMP_NOSPACE;
877: term_flushln(p);
878: }
1.1 kristaps 879: break;
880: default:
1.11 schwarze 881: if (termacts[n->tok].pre)
882: c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1 kristaps 883: break;
884: }
885:
886: if (c && n->child)
1.11 schwarze 887: print_body(p, mt, n->child, m);
1.1 kristaps 888:
1.11 schwarze 889: if (MAN_TEXT != n->type)
1.1 kristaps 890: if (termacts[n->tok].post)
1.11 schwarze 891: (*termacts[n->tok].post)(p, mt, n, m);
1.1 kristaps 892: }
893:
894:
895: static void
896: print_body(DECL_ARGS)
897: {
1.11 schwarze 898:
899: print_node(p, mt, n, m);
1.1 kristaps 900: if ( ! n->next)
901: return;
1.11 schwarze 902: print_body(p, mt, n->next, m);
1.1 kristaps 903: }
904:
905:
906: static void
907: print_foot(struct termp *p, const struct man_meta *meta)
908: {
909: struct tm *tm;
910: char *buf;
911:
912: if (NULL == (buf = malloc(p->rmargin)))
913: err(1, "malloc");
914:
915: tm = localtime(&meta->date);
916:
1.3 schwarze 917: if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
1.1 kristaps 918: err(1, "strftime");
919:
920: term_vspace(p);
921:
922: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
923: p->rmargin = p->maxrmargin - strlen(buf);
924: p->offset = 0;
925:
926: if (meta->source)
927: term_word(p, meta->source);
928: if (meta->source)
929: term_word(p, "");
930: term_flushln(p);
931:
932: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
933: p->offset = p->rmargin;
934: p->rmargin = p->maxrmargin;
935: p->flags &= ~TERMP_NOBREAK;
936:
937: term_word(p, buf);
938: term_flushln(p);
939:
940: free(buf);
941: }
942:
943:
944: static void
945: print_head(struct termp *p, const struct man_meta *meta)
946: {
947: char *buf, *title;
948:
949: p->rmargin = p->maxrmargin;
950: p->offset = 0;
951:
952: if (NULL == (buf = malloc(p->rmargin)))
953: err(1, "malloc");
954: if (NULL == (title = malloc(p->rmargin)))
955: err(1, "malloc");
956:
957: if (meta->vol)
958: (void)strlcpy(buf, meta->vol, p->rmargin);
959: else
960: *buf = 0;
961:
962: (void)snprintf(title, p->rmargin, "%s(%d)",
963: meta->title, meta->msec);
964:
965: p->offset = 0;
1.5 schwarze 966: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 967: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
968:
969: term_word(p, title);
970: term_flushln(p);
971:
972: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
973: p->offset = p->rmargin;
974: p->rmargin = p->maxrmargin - strlen(title);
975:
976: term_word(p, buf);
977: term_flushln(p);
978:
979: p->offset = p->rmargin;
980: p->rmargin = p->maxrmargin;
981: p->flags &= ~TERMP_NOBREAK;
982: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
983:
984: term_word(p, title);
985: term_flushln(p);
986:
987: p->rmargin = p->maxrmargin;
988: p->offset = 0;
989: p->flags &= ~TERMP_NOSPACE;
990:
991: free(title);
992: free(buf);
993: }
994: