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