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