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