]>
git.cameronkatri.com Git - mandoc.git/blob - man_term.c
1 /* $Id: man_term.c,v 1.16 2009/06/18 20:46:19 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_br(DECL_ARGS
);
44 static int pre_I(DECL_ARGS
);
45 static int pre_IB(DECL_ARGS
);
46 static int pre_IP(DECL_ARGS
);
47 static int pre_IR(DECL_ARGS
);
48 static int pre_PP(DECL_ARGS
);
49 static int pre_RB(DECL_ARGS
);
50 static int pre_RI(DECL_ARGS
);
51 static int pre_SH(DECL_ARGS
);
52 static int pre_SS(DECL_ARGS
);
53 static int pre_TP(DECL_ARGS
);
55 static void post_B(DECL_ARGS
);
56 static void post_I(DECL_ARGS
);
57 static void post_SH(DECL_ARGS
);
58 static void post_SS(DECL_ARGS
);
60 static const struct termact termacts
[MAN_MAX
] = {
61 { pre_br
, NULL
}, /* br */
62 { NULL
, NULL
}, /* TH */
63 { pre_SH
, post_SH
}, /* SH */
64 { pre_SS
, post_SS
}, /* SS */
65 { pre_TP
, NULL
}, /* TP */
66 { pre_PP
, NULL
}, /* LP */
67 { pre_PP
, NULL
}, /* PP */
68 { pre_PP
, NULL
}, /* P */
69 { pre_IP
, NULL
}, /* IP */
70 { pre_PP
, NULL
}, /* HP */ /* FIXME */
71 { NULL
, NULL
}, /* SM */
72 { pre_B
, post_B
}, /* SB */
73 { pre_BI
, NULL
}, /* BI */
74 { pre_IB
, NULL
}, /* IB */
75 { pre_BR
, NULL
}, /* BR */
76 { pre_RB
, NULL
}, /* RB */
77 { NULL
, NULL
}, /* R */
78 { pre_B
, post_B
}, /* B */
79 { pre_I
, post_I
}, /* I */
80 { pre_IR
, NULL
}, /* IR */
81 { pre_RI
, NULL
}, /* RI */
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
;
101 assert(MAN_ROOT
== man_node(m
)->type
);
102 if (man_node(m
)->child
)
103 print_body(p
, man_node(m
)->child
, man_meta(m
));
104 print_foot(p
, man_meta(m
));
115 p
->flags
|= TERMP_UNDER
;
125 p
->flags
&= ~TERMP_UNDER
;
133 const struct man_node
*nn
;
136 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
138 p
->flags
|= TERMP_UNDER
;
140 p
->flags
|= TERMP_NOSPACE
;
141 print_node(p
, nn
, m
);
143 p
->flags
&= ~TERMP_UNDER
;
153 const struct man_node
*nn
;
156 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
157 p
->flags
|= i
% 2 ? TERMP_BOLD
: TERMP_UNDER
;
159 p
->flags
|= TERMP_NOSPACE
;
160 print_node(p
, nn
, m
);
161 p
->flags
&= i
% 2 ? ~TERMP_BOLD
: ~TERMP_UNDER
;
171 const struct man_node
*nn
;
174 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
176 p
->flags
|= TERMP_BOLD
;
178 p
->flags
|= TERMP_NOSPACE
;
179 print_node(p
, nn
, m
);
181 p
->flags
&= ~TERMP_BOLD
;
191 const struct man_node
*nn
;
194 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
196 p
->flags
|= TERMP_UNDER
;
198 p
->flags
|= TERMP_NOSPACE
;
199 print_node(p
, nn
, m
);
201 p
->flags
&= ~TERMP_UNDER
;
211 const struct man_node
*nn
;
214 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
216 p
->flags
|= TERMP_BOLD
;
218 p
->flags
|= TERMP_NOSPACE
;
219 print_node(p
, nn
, m
);
221 p
->flags
&= ~TERMP_BOLD
;
231 const struct man_node
*nn
;
234 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
235 p
->flags
|= i
% 2 ? TERMP_UNDER
: TERMP_BOLD
;
237 p
->flags
|= TERMP_NOSPACE
;
238 print_node(p
, nn
, m
);
239 p
->flags
&= i
% 2 ? ~TERMP_UNDER
: ~TERMP_BOLD
;
250 p
->flags
|= TERMP_BOLD
;
260 p
->flags
&= ~TERMP_BOLD
;
290 const struct man_node
*nn
;
298 if (NULL
== (nn
= n
->child
))
300 if (MAN_TEXT
!= nn
->type
)
301 errx(1, "expected text line argument");
304 if (MAN_TEXT
!= nn
->next
->type
)
305 errx(1, "expected text line argument");
306 offs
= (size_t)atoi(nn
->next
->string
);
308 offs
= strlen(nn
->string
);
310 p
->flags
|= TERMP_NOSPACE
;
312 if ((p
->offset
+= offs
) > p
->rmargin
)
313 errx(1, "line too long");
324 const struct man_node
*nn
;
331 if (NULL
== (nn
= n
->child
))
334 if (nn
->line
== n
->line
) {
335 if (MAN_TEXT
!= nn
->type
)
336 errx(1, "expected text line argument");
337 offs
= (size_t)atoi(nn
->string
);
342 for ( ; nn
; nn
= nn
->next
)
343 print_node(p
, nn
, m
);
346 p
->flags
|= TERMP_NOSPACE
;
358 p
->flags
|= TERMP_BOLD
;
369 p
->flags
&= ~TERMP_BOLD
;
370 p
->flags
|= TERMP_NOSPACE
;
381 p
->flags
|= TERMP_BOLD
;
393 p
->flags
&= ~TERMP_BOLD
;
394 p
->flags
|= TERMP_NOSPACE
;
399 print_node(DECL_ARGS
)
407 if (termacts
[n
->tok
].pre
)
408 c
= (*termacts
[n
->tok
].pre
)(p
, n
, m
);
411 if (0 == *n
->string
) {
416 * Note! This is hacky. Here, we recognise the `\c'
417 * escape embedded in so many -man pages. It's supposed
418 * to remove the subsequent space, so we mark NOSPACE if
419 * it's encountered in the string.
421 sz
= (int)strlen(n
->string
);
422 term_word(p
, n
->string
);
423 if (sz
>= 2 && n
->string
[sz
- 1] == 'c' &&
424 n
->string
[sz
- 2] == '\\')
425 p
->flags
|= TERMP_NOSPACE
;
432 print_body(p
, n
->child
, m
);
436 if (termacts
[n
->tok
].post
)
437 (*termacts
[n
->tok
].post
)(p
, n
, m
);
446 print_body(DECL_ARGS
)
451 print_body(p
, n
->next
, m
);
456 print_foot(struct termp
*p
, const struct man_meta
*meta
)
461 if (NULL
== (buf
= malloc(p
->rmargin
)))
464 tm
= localtime(&meta
->date
);
466 if (0 == strftime(buf
, p
->rmargin
, "%B %d, %Y", tm
))
471 p
->flags
|= TERMP_NOSPACE
| TERMP_NOBREAK
;
472 p
->rmargin
= p
->maxrmargin
- strlen(buf
);
476 term_word(p
, meta
->source
);
481 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
482 p
->offset
= p
->rmargin
;
483 p
->rmargin
= p
->maxrmargin
;
484 p
->flags
&= ~TERMP_NOBREAK
;
494 print_head(struct termp
*p
, const struct man_meta
*meta
)
498 p
->rmargin
= p
->maxrmargin
;
501 if (NULL
== (buf
= malloc(p
->rmargin
)))
503 if (NULL
== (title
= malloc(p
->rmargin
)))
507 (void)strlcpy(buf
, meta
->vol
, p
->rmargin
);
511 (void)snprintf(title
, p
->rmargin
, "%s(%d)",
512 meta
->title
, meta
->msec
);
515 p
->rmargin
= (p
->maxrmargin
- strlen(buf
) + 1) / 2;
516 p
->flags
|= TERMP_NOBREAK
| TERMP_NOSPACE
;
521 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
522 p
->offset
= p
->rmargin
;
523 p
->rmargin
= p
->maxrmargin
- strlen(title
);
528 p
->offset
= p
->rmargin
;
529 p
->rmargin
= p
->maxrmargin
;
530 p
->flags
&= ~TERMP_NOBREAK
;
531 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
536 p
->rmargin
= p
->maxrmargin
;
538 p
->flags
&= ~TERMP_NOSPACE
;