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