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