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