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