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