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