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