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