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