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