]>
git.cameronkatri.com Git - mandoc.git/blob - man_term.c
1 /* $Id: man_term.c,v 1.12 2009/06/11 13:18:42 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.
27 extern size_t strlcpy(char *, const char *, size_t);
28 extern size_t strlcat(char *, const char *, size_t);
31 #define DECL_ARGS struct termp *p, \
32 const struct man_node *n, \
33 const struct man_meta *m
36 int (*pre
)(DECL_ARGS
);
37 void (*post
)(DECL_ARGS
);
40 static int pre_B(DECL_ARGS
);
41 static int pre_BI(DECL_ARGS
);
42 static int pre_BR(DECL_ARGS
);
43 static int pre_I(DECL_ARGS
);
44 static int pre_IB(DECL_ARGS
);
45 static int pre_IP(DECL_ARGS
);
46 static int pre_IR(DECL_ARGS
);
47 static int pre_PP(DECL_ARGS
);
48 static int pre_RB(DECL_ARGS
);
49 static int pre_RI(DECL_ARGS
);
50 static int pre_SH(DECL_ARGS
);
51 static int pre_SS(DECL_ARGS
);
52 static int pre_TP(DECL_ARGS
);
54 static void post_B(DECL_ARGS
);
55 static void post_I(DECL_ARGS
);
56 static void post_SH(DECL_ARGS
);
57 static void post_SS(DECL_ARGS
);
59 static const struct termact termacts
[MAN_MAX
] = {
60 { NULL
, NULL
}, /* __ */
61 { NULL
, NULL
}, /* TH */
62 { pre_SH
, post_SH
}, /* SH */
63 { pre_SS
, post_SS
}, /* SS */
64 { pre_TP
, NULL
}, /* TP */
65 { pre_PP
, NULL
}, /* LP */
66 { pre_PP
, NULL
}, /* PP */
67 { pre_PP
, NULL
}, /* P */
68 { pre_IP
, NULL
}, /* IP */
69 { pre_PP
, NULL
}, /* HP */ /* FIXME */
70 { NULL
, NULL
}, /* SM */
71 { pre_B
, post_B
}, /* SB */
72 { pre_BI
, NULL
}, /* BI */
73 { pre_IB
, NULL
}, /* IB */
74 { pre_BR
, NULL
}, /* BR */
75 { pre_RB
, NULL
}, /* RB */
76 { NULL
, NULL
}, /* R */
77 { pre_B
, post_B
}, /* B */
78 { pre_I
, post_I
}, /* I */
79 { pre_IR
, NULL
}, /* IR */
80 { pre_RI
, NULL
}, /* RI */
81 { pre_PP
, NULL
}, /* br */
82 { NULL
, NULL
}, /* na */
83 { pre_I
, post_I
}, /* i */
86 static void print_head(struct termp
*,
87 const struct man_meta
*);
88 static void print_body(DECL_ARGS
);
89 static void print_node(DECL_ARGS
);
90 static void print_foot(struct termp
*,
91 const struct man_meta
*);
95 man_run(struct termp
*p
, const struct man
*m
)
98 print_head(p
, man_meta(m
));
99 p
->flags
|= TERMP_NOSPACE
;
100 print_body(p
, man_node(m
), man_meta(m
));
101 print_foot(p
, man_meta(m
));
112 p
->flags
|= TERMP_UNDER
;
122 p
->flags
&= ~TERMP_UNDER
;
130 const struct man_node
*nn
;
133 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
135 p
->flags
|= TERMP_UNDER
;
137 p
->flags
|= TERMP_NOSPACE
;
138 print_node(p
, nn
, m
);
140 p
->flags
&= ~TERMP_UNDER
;
150 const struct man_node
*nn
;
153 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
154 p
->flags
|= i
% 2 ? TERMP_BOLD
: TERMP_UNDER
;
156 p
->flags
|= TERMP_NOSPACE
;
157 print_node(p
, nn
, m
);
158 p
->flags
&= i
% 2 ? ~TERMP_BOLD
: ~TERMP_UNDER
;
168 const struct man_node
*nn
;
171 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
173 p
->flags
|= TERMP_BOLD
;
175 p
->flags
|= TERMP_NOSPACE
;
176 print_node(p
, nn
, m
);
178 p
->flags
&= ~TERMP_BOLD
;
188 const struct man_node
*nn
;
191 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
193 p
->flags
|= TERMP_UNDER
;
195 p
->flags
|= TERMP_NOSPACE
;
196 print_node(p
, nn
, m
);
198 p
->flags
&= ~TERMP_UNDER
;
208 const struct man_node
*nn
;
211 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
213 p
->flags
|= TERMP_BOLD
;
215 p
->flags
|= TERMP_NOSPACE
;
216 print_node(p
, nn
, m
);
218 p
->flags
&= ~TERMP_BOLD
;
228 const struct man_node
*nn
;
231 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
232 p
->flags
|= i
% 2 ? TERMP_UNDER
: TERMP_BOLD
;
234 p
->flags
|= TERMP_NOSPACE
;
235 print_node(p
, nn
, m
);
236 p
->flags
&= i
% 2 ? ~TERMP_UNDER
: ~TERMP_BOLD
;
247 p
->flags
|= TERMP_BOLD
;
257 p
->flags
&= ~TERMP_BOLD
;
277 const struct man_node
*nn
;
285 if (NULL
== (nn
= n
->child
))
287 if (MAN_TEXT
!= nn
->type
)
288 errx(1, "expected text line argument");
291 if (MAN_TEXT
!= nn
->next
->type
)
292 errx(1, "expected text line argument");
293 offs
= (size_t)atoi(nn
->next
->string
);
295 offs
= strlen(nn
->string
);
297 p
->flags
|= TERMP_NOSPACE
;
299 if ((p
->offset
+= offs
) > p
->rmargin
)
300 errx(1, "line too long");
311 const struct man_node
*nn
;
317 if (NULL
== (nn
= n
->child
))
320 if (nn
->line
== n
->line
) {
321 if (MAN_TEXT
!= nn
->type
)
322 errx(1, "expected text line argument");
323 offs
= (size_t)atoi(nn
->string
);
328 for ( ; nn
; nn
= nn
->next
)
329 print_node(p
, nn
, m
);
332 p
->flags
|= TERMP_NOSPACE
;
344 p
->flags
|= TERMP_BOLD
;
355 p
->flags
&= ~TERMP_BOLD
;
356 p
->flags
|= TERMP_NOSPACE
;
367 p
->flags
|= TERMP_BOLD
;
379 p
->flags
&= ~TERMP_BOLD
;
380 p
->flags
|= TERMP_NOSPACE
;
385 print_node(DECL_ARGS
)
393 if (termacts
[n
->tok
].pre
)
394 c
= (*termacts
[n
->tok
].pre
)(p
, n
, m
);
397 if (0 == *n
->string
) {
402 * Note! This is hacky. Here, we recognise the `\c'
403 * escape embedded in so many -man pages. It's supposed
404 * to remove the subsequent space, so we mark NOSPACE if
405 * it's encountered in the string.
407 sz
= (int)strlen(n
->string
);
408 term_word(p
, n
->string
);
409 if (sz
>= 2 && n
->string
[sz
- 1] == 'c' &&
410 n
->string
[sz
- 2] == '\\')
411 p
->flags
|= TERMP_NOSPACE
;
418 print_body(p
, n
->child
, m
);
422 if (termacts
[n
->tok
].post
)
423 (*termacts
[n
->tok
].post
)(p
, n
, m
);
432 print_body(DECL_ARGS
)
437 print_body(p
, n
->next
, m
);
442 print_foot(struct termp
*p
, const struct man_meta
*meta
)
447 if (NULL
== (buf
= malloc(p
->rmargin
)))
450 tm
= localtime(&meta
->date
);
453 if (NULL
== strftime(buf
, p
->rmargin
, "%B %d, %Y", tm
))
455 if (0 == strftime(buf
, p
->rmargin
, "%B %d, %Y", tm
))
461 p
->flags
|= TERMP_NOSPACE
| TERMP_NOBREAK
;
462 p
->rmargin
= p
->maxrmargin
- strlen(buf
);
466 term_word(p
, meta
->source
);
471 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
472 p
->offset
= p
->rmargin
;
473 p
->rmargin
= p
->maxrmargin
;
474 p
->flags
&= ~TERMP_NOBREAK
;
484 print_head(struct termp
*p
, const struct man_meta
*meta
)
488 p
->rmargin
= p
->maxrmargin
;
491 if (NULL
== (buf
= malloc(p
->rmargin
)))
493 if (NULL
== (title
= malloc(p
->rmargin
)))
497 (void)strlcpy(buf
, meta
->vol
, p
->rmargin
);
501 (void)snprintf(title
, p
->rmargin
, "%s(%d)",
502 meta
->title
, meta
->msec
);
505 p
->rmargin
= (p
->maxrmargin
- strlen(buf
) + 1) / 2;
506 p
->flags
|= TERMP_NOBREAK
| TERMP_NOSPACE
;
511 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
512 p
->offset
= p
->rmargin
;
513 p
->rmargin
= p
->maxrmargin
- strlen(title
);
518 p
->offset
= p
->rmargin
;
519 p
->rmargin
= p
->maxrmargin
;
520 p
->flags
&= ~TERMP_NOBREAK
;
521 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
526 p
->rmargin
= p
->maxrmargin
;
528 p
->flags
&= ~TERMP_NOSPACE
;