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