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