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