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