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