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