]>
git.cameronkatri.com Git - mandoc.git/blob - man_term.c
1 /* $Id: man_term.c,v 1.31 2009/09/16 09:41:24 kristaps Exp $ */
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
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.
17 #include <sys/types.h>
34 #define MANT_LITERAL (1 << 0)
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.
41 * Note that this is the indentation AFTER the left offset, so
42 * the total offset is usually offset + lmargin.
46 * The default offset, i.e., the amount between any text and the
52 #define DECL_ARGS struct termp *p, \
54 const struct man_node *n, \
55 const struct man_meta *m
58 int (*pre
)(DECL_ARGS
);
59 void (*post
)(DECL_ARGS
);
62 static int pre_B(DECL_ARGS
);
63 static int pre_BI(DECL_ARGS
);
64 static int pre_BR(DECL_ARGS
);
65 static int pre_HP(DECL_ARGS
);
66 static int pre_I(DECL_ARGS
);
67 static int pre_IB(DECL_ARGS
);
68 static int pre_IP(DECL_ARGS
);
69 static int pre_IR(DECL_ARGS
);
70 static int pre_PP(DECL_ARGS
);
71 static int pre_RB(DECL_ARGS
);
72 static int pre_RI(DECL_ARGS
);
73 static int pre_RS(DECL_ARGS
);
74 static int pre_SH(DECL_ARGS
);
75 static int pre_SS(DECL_ARGS
);
76 static int pre_TP(DECL_ARGS
);
77 static int pre_br(DECL_ARGS
);
78 static int pre_fi(DECL_ARGS
);
79 static int pre_ign(DECL_ARGS
);
80 static int pre_nf(DECL_ARGS
);
81 static int pre_r(DECL_ARGS
);
82 static int pre_sp(DECL_ARGS
);
84 static void post_B(DECL_ARGS
);
85 static void post_I(DECL_ARGS
);
86 static void post_IP(DECL_ARGS
);
87 static void post_HP(DECL_ARGS
);
88 static void post_RS(DECL_ARGS
);
89 static void post_SH(DECL_ARGS
);
90 static void post_SS(DECL_ARGS
);
91 static void post_TP(DECL_ARGS
);
92 static void post_i(DECL_ARGS
);
94 static const struct termact termacts
[MAN_MAX
] = {
95 { pre_br
, NULL
}, /* br */
96 { NULL
, NULL
}, /* TH */
97 { pre_SH
, post_SH
}, /* SH */
98 { pre_SS
, post_SS
}, /* SS */
99 { pre_TP
, post_TP
}, /* TP */
100 { pre_PP
, NULL
}, /* LP */
101 { pre_PP
, NULL
}, /* PP */
102 { pre_PP
, NULL
}, /* P */
103 { pre_IP
, post_IP
}, /* IP */
104 { pre_HP
, post_HP
}, /* HP */
105 { NULL
, NULL
}, /* SM */
106 { pre_B
, post_B
}, /* SB */
107 { pre_BI
, NULL
}, /* BI */
108 { pre_IB
, NULL
}, /* IB */
109 { pre_BR
, NULL
}, /* BR */
110 { pre_RB
, NULL
}, /* RB */
111 { NULL
, NULL
}, /* R */
112 { pre_B
, post_B
}, /* B */
113 { pre_I
, post_I
}, /* I */
114 { pre_IR
, NULL
}, /* IR */
115 { pre_RI
, NULL
}, /* RI */
116 { NULL
, NULL
}, /* na */
117 { pre_I
, post_i
}, /* i */
118 { pre_sp
, NULL
}, /* sp */
119 { pre_nf
, NULL
}, /* nf */
120 { pre_fi
, NULL
}, /* fi */
121 { pre_r
, NULL
}, /* r */
122 { NULL
, NULL
}, /* RE */
123 { pre_RS
, post_RS
}, /* RS */
124 { pre_ign
, NULL
}, /* DT */
125 { pre_ign
, NULL
}, /* UC */
129 extern size_t strlcpy(char *, const char *, size_t);
130 extern size_t strlcat(char *, const char *, size_t);
133 static void print_head(struct termp
*,
134 const struct man_meta
*);
135 static void print_body(DECL_ARGS
);
136 static void print_node(DECL_ARGS
);
137 static void print_foot(struct termp
*,
138 const struct man_meta
*);
139 static void fmt_block_vspace(struct termp
*,
140 const struct man_node
*);
141 static int arg_width(const struct man_node
*);
145 man_run(struct termp
*p
, const struct man
*m
)
149 print_head(p
, man_meta(m
));
150 p
->flags
|= TERMP_NOSPACE
;
156 if (man_node(m
)->child
)
157 print_body(p
, &mt
, man_node(m
)->child
, man_meta(m
));
158 print_foot(p
, man_meta(m
));
163 fmt_block_vspace(struct termp
*p
, const struct man_node
*n
)
170 if (MAN_SS
== n
->prev
->tok
)
172 if (MAN_SH
== n
->prev
->tok
)
180 arg_width(const struct man_node
*n
)
185 assert(MAN_TEXT
== n
->type
);
190 if (0 == (len
= (int)strlen(p
)))
193 for (i
= 0; i
< len
; i
++)
194 if ( ! isdigit((u_char
)p
[i
]))
198 if ('n' == p
[len
- 1] || 'm' == p
[len
- 1])
231 p
->bold
= p
->under
= 0;
260 mt
->fl
&= ~MANT_LITERAL
;
271 mt
->fl
|= MANT_LITERAL
;
280 const struct man_node
*nn
;
283 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
287 p
->flags
|= TERMP_NOSPACE
;
288 print_node(p
, mt
, nn
, m
);
300 const struct man_node
*nn
;
303 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
309 p
->flags
|= TERMP_NOSPACE
;
310 print_node(p
, mt
, nn
, m
);
324 const struct man_node
*nn
;
327 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
331 p
->flags
|= TERMP_NOSPACE
;
332 print_node(p
, mt
, nn
, m
);
344 const struct man_node
*nn
;
347 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
351 p
->flags
|= TERMP_NOSPACE
;
352 print_node(p
, mt
, nn
, m
);
364 const struct man_node
*nn
;
367 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
371 p
->flags
|= TERMP_NOSPACE
;
372 print_node(p
, mt
, nn
, m
);
384 const struct man_node
*nn
;
387 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
393 p
->flags
|= TERMP_NOSPACE
;
394 print_node(p
, mt
, nn
, m
);
429 if (NULL
== n
->child
) {
434 len
= atoi(n
->child
->string
);
437 for (i
= 0; i
< len
; i
++)
460 const struct man_node
*nn
;
464 fmt_block_vspace(p
, n
);
467 p
->flags
|= TERMP_NOBREAK
;
468 p
->flags
|= TERMP_TWOSPACE
;
477 /* Calculate offset. */
479 if (NULL
!= (nn
= n
->parent
->head
->child
))
480 if ((ival
= arg_width(nn
)) >= 0)
486 p
->offset
= mt
->offset
;
487 p
->rmargin
= mt
->offset
+ len
;
490 mt
->lmargin
= (size_t)ival
;
507 p
->flags
&= ~TERMP_NOBREAK
;
508 p
->flags
&= ~TERMP_TWOSPACE
;
509 p
->offset
= mt
->offset
;
510 p
->rmargin
= p
->maxrmargin
;
525 mt
->lmargin
= INDENT
;
526 fmt_block_vspace(p
, n
);
529 p
->offset
= mt
->offset
;
541 const struct man_node
*nn
;
547 p
->flags
|= TERMP_NOLPAD
;
548 p
->flags
|= TERMP_NOSPACE
;
551 p
->flags
|= TERMP_NOBREAK
;
552 p
->flags
|= TERMP_TWOSPACE
;
555 fmt_block_vspace(p
, n
);
564 /* Calculate offset. */
566 if (NULL
!= (nn
= n
->parent
->head
->child
))
567 if (NULL
!= (nn
= nn
->next
)) {
568 for ( ; nn
->next
; nn
= nn
->next
)
570 if ((ival
= arg_width(nn
)) >= 0)
576 /* Handle zero-width lengths. */
580 p
->offset
= mt
->offset
;
581 p
->rmargin
= mt
->offset
+ len
;
585 /* Set the saved left-margin. */
586 mt
->lmargin
= (size_t)ival
;
588 /* Don't print the length value. */
589 for (nn
= n
->child
; nn
->next
; nn
= nn
->next
)
590 print_node(p
, mt
, nn
, m
);
593 p
->offset
= mt
->offset
+ len
;
594 p
->rmargin
= p
->maxrmargin
;
612 p
->flags
&= ~TERMP_NOBREAK
;
613 p
->flags
&= ~TERMP_TWOSPACE
;
614 p
->rmargin
= p
->maxrmargin
;
618 p
->flags
&= ~TERMP_NOLPAD
;
630 const struct man_node
*nn
;
636 p
->flags
|= TERMP_NOBREAK
;
637 p
->flags
|= TERMP_TWOSPACE
;
640 p
->flags
|= TERMP_NOLPAD
;
641 p
->flags
|= TERMP_NOSPACE
;
644 fmt_block_vspace(p
, n
);
650 len
= (size_t)mt
->lmargin
;
653 /* Calculate offset. */
655 if (NULL
!= (nn
= n
->parent
->head
->child
))
656 if (NULL
!= nn
->next
)
657 if ((ival
= arg_width(nn
)) >= 0)
662 /* Handle zero-length properly. */
666 p
->offset
= mt
->offset
;
667 p
->rmargin
= mt
->offset
+ len
;
669 /* Don't print same-line elements. */
670 for (nn
= n
->child
; nn
; nn
= nn
->next
)
671 if (nn
->line
> n
->line
)
672 print_node(p
, mt
, nn
, m
);
675 mt
->lmargin
= (size_t)ival
;
679 p
->offset
= mt
->offset
+ len
;
680 p
->rmargin
= p
->maxrmargin
;
698 p
->flags
&= ~TERMP_NOBREAK
;
699 p
->flags
&= ~TERMP_TWOSPACE
;
700 p
->rmargin
= p
->maxrmargin
;
704 p
->flags
&= ~TERMP_NOLPAD
;
719 mt
->lmargin
= INDENT
;
721 /* If following a prior empty `SS', no vspace. */
722 if (n
->prev
&& MAN_SS
== n
->prev
->tok
)
723 if (NULL
== n
->prev
->body
->child
)
731 p
->offset
= HALFINDENT
;
734 p
->offset
= mt
->offset
;
770 mt
->lmargin
= INDENT
;
772 /* If following a prior empty `SH', no vspace. */
773 if (n
->prev
&& MAN_SH
== n
->prev
->tok
)
774 if (NULL
== n
->prev
->body
->child
)
783 p
->offset
= mt
->offset
;
816 const struct man_node
*nn
;
829 if (NULL
== (nn
= n
->parent
->head
->child
)) {
830 mt
->offset
= mt
->lmargin
+ INDENT
;
831 p
->offset
= mt
->offset
;
835 if ((ival
= arg_width(nn
)) < 0)
838 mt
->offset
= INDENT
+ (size_t)ival
;
839 p
->offset
= mt
->offset
;
852 mt
->offset
= mt
->lmargin
= INDENT
;
863 print_node(DECL_ARGS
)
871 if (0 == *n
->string
) {
876 * Note! This is hacky. Here, we recognise the `\c'
877 * escape embedded in so many -man pages. It's supposed
878 * to remove the subsequent space, so we mark NOSPACE if
879 * it's encountered in the string.
881 sz
= (int)strlen(n
->string
);
882 term_word(p
, n
->string
);
883 if (sz
>= 2 && n
->string
[sz
- 1] == 'c' &&
884 n
->string
[sz
- 2] == '\\')
885 p
->flags
|= TERMP_NOSPACE
;
886 /* FIXME: this means that macro lines are munged! */
887 if (MANT_LITERAL
& mt
->fl
) {
888 p
->flags
|= TERMP_NOSPACE
;
893 if (termacts
[n
->tok
].pre
)
894 c
= (*termacts
[n
->tok
].pre
)(p
, mt
, n
, m
);
899 print_body(p
, mt
, n
->child
, m
);
901 if (MAN_TEXT
!= n
->type
)
902 if (termacts
[n
->tok
].post
)
903 (*termacts
[n
->tok
].post
)(p
, mt
, n
, m
);
908 print_body(DECL_ARGS
)
911 print_node(p
, mt
, n
, m
);
914 print_body(p
, mt
, n
->next
, m
);
919 print_foot(struct termp
*p
, const struct man_meta
*meta
)
924 if (NULL
== (buf
= malloc(p
->rmargin
)))
925 err(EXIT_FAILURE
, "malloc");
927 tm
= localtime(&meta
->date
);
929 if (0 == strftime(buf
, p
->rmargin
, "%B %d, %Y", tm
))
930 err(EXIT_FAILURE
, "strftime");
934 p
->flags
|= TERMP_NOSPACE
| TERMP_NOBREAK
;
935 p
->rmargin
= p
->maxrmargin
- strlen(buf
);
939 term_word(p
, meta
->source
);
944 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
945 p
->offset
= p
->rmargin
;
946 p
->rmargin
= p
->maxrmargin
;
947 p
->flags
&= ~TERMP_NOBREAK
;
957 print_head(struct termp
*p
, const struct man_meta
*meta
)
961 p
->rmargin
= p
->maxrmargin
;
964 if (NULL
== (buf
= malloc(p
->rmargin
)))
965 err(EXIT_FAILURE
, "malloc");
966 if (NULL
== (title
= malloc(p
->rmargin
)))
967 err(EXIT_FAILURE
, "malloc");
970 (void)strlcpy(buf
, meta
->vol
, p
->rmargin
);
974 (void)snprintf(title
, p
->rmargin
, "%s(%d)",
975 meta
->title
, meta
->msec
);
978 p
->rmargin
= (p
->maxrmargin
- strlen(buf
) + 1) / 2;
979 p
->flags
|= TERMP_NOBREAK
| TERMP_NOSPACE
;
984 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
985 p
->offset
= p
->rmargin
;
986 p
->rmargin
= p
->maxrmargin
- strlen(title
);
991 p
->offset
= p
->rmargin
;
992 p
->rmargin
= p
->maxrmargin
;
993 p
->flags
&= ~TERMP_NOBREAK
;
994 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
999 p
->rmargin
= p
->maxrmargin
;
1001 p
->flags
&= ~TERMP_NOSPACE
;