]>
git.cameronkatri.com Git - mandoc.git/blob - man_term.c
1 /* $Id: man_term.c,v 1.17 2009/07/24 20:22: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.
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 */
84 { NULL
, NULL
}, /* sp */
87 static void print_head(struct termp
*,
88 const struct man_meta
*);
89 static void print_body(DECL_ARGS
);
90 static void print_node(DECL_ARGS
);
91 static void print_foot(struct termp
*,
92 const struct man_meta
*);
96 man_run(struct termp
*p
, const struct man
*m
)
99 print_head(p
, man_meta(m
));
100 p
->flags
|= TERMP_NOSPACE
;
102 assert(MAN_ROOT
== man_node(m
)->type
);
103 if (man_node(m
)->child
)
104 print_body(p
, man_node(m
)->child
, man_meta(m
));
105 print_foot(p
, man_meta(m
));
116 p
->flags
|= TERMP_UNDER
;
126 p
->flags
&= ~TERMP_UNDER
;
134 const struct man_node
*nn
;
137 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
139 p
->flags
|= TERMP_UNDER
;
141 p
->flags
|= TERMP_NOSPACE
;
142 print_node(p
, nn
, m
);
144 p
->flags
&= ~TERMP_UNDER
;
154 const struct man_node
*nn
;
157 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
158 p
->flags
|= i
% 2 ? TERMP_BOLD
: TERMP_UNDER
;
160 p
->flags
|= TERMP_NOSPACE
;
161 print_node(p
, nn
, m
);
162 p
->flags
&= i
% 2 ? ~TERMP_BOLD
: ~TERMP_UNDER
;
172 const struct man_node
*nn
;
175 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
177 p
->flags
|= TERMP_BOLD
;
179 p
->flags
|= TERMP_NOSPACE
;
180 print_node(p
, nn
, m
);
182 p
->flags
&= ~TERMP_BOLD
;
192 const struct man_node
*nn
;
195 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
197 p
->flags
|= TERMP_UNDER
;
199 p
->flags
|= TERMP_NOSPACE
;
200 print_node(p
, nn
, m
);
202 p
->flags
&= ~TERMP_UNDER
;
212 const struct man_node
*nn
;
215 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
217 p
->flags
|= TERMP_BOLD
;
219 p
->flags
|= TERMP_NOSPACE
;
220 print_node(p
, nn
, m
);
222 p
->flags
&= ~TERMP_BOLD
;
232 const struct man_node
*nn
;
235 for (i
= 0, nn
= n
->child
; nn
; nn
= nn
->next
, i
++) {
236 p
->flags
|= i
% 2 ? TERMP_UNDER
: TERMP_BOLD
;
238 p
->flags
|= TERMP_NOSPACE
;
239 print_node(p
, nn
, m
);
240 p
->flags
&= i
% 2 ? ~TERMP_UNDER
: ~TERMP_BOLD
;
251 p
->flags
|= TERMP_BOLD
;
261 p
->flags
&= ~TERMP_BOLD
;
291 const struct man_node
*nn
;
299 if (NULL
== (nn
= n
->child
))
301 if (MAN_TEXT
!= nn
->type
)
302 errx(1, "expected text line argument");
305 if (MAN_TEXT
!= nn
->next
->type
)
306 errx(1, "expected text line argument");
307 offs
= (size_t)atoi(nn
->next
->string
);
309 offs
= strlen(nn
->string
);
311 p
->flags
|= TERMP_NOSPACE
;
313 if ((p
->offset
+= offs
) > p
->rmargin
)
314 errx(1, "line too long");
325 const struct man_node
*nn
;
332 if (NULL
== (nn
= n
->child
))
335 if (nn
->line
== n
->line
) {
336 if (MAN_TEXT
!= nn
->type
)
337 errx(1, "expected text line argument");
338 offs
= (size_t)atoi(nn
->string
);
343 for ( ; nn
; nn
= nn
->next
)
344 print_node(p
, nn
, m
);
347 p
->flags
|= TERMP_NOSPACE
;
359 p
->flags
|= TERMP_BOLD
;
370 p
->flags
&= ~TERMP_BOLD
;
371 p
->flags
|= TERMP_NOSPACE
;
382 p
->flags
|= TERMP_BOLD
;
394 p
->flags
&= ~TERMP_BOLD
;
395 p
->flags
|= TERMP_NOSPACE
;
400 print_node(DECL_ARGS
)
408 if (termacts
[n
->tok
].pre
)
409 c
= (*termacts
[n
->tok
].pre
)(p
, n
, m
);
412 if (0 == *n
->string
) {
417 * Note! This is hacky. Here, we recognise the `\c'
418 * escape embedded in so many -man pages. It's supposed
419 * to remove the subsequent space, so we mark NOSPACE if
420 * it's encountered in the string.
422 sz
= (int)strlen(n
->string
);
423 term_word(p
, n
->string
);
424 if (sz
>= 2 && n
->string
[sz
- 1] == 'c' &&
425 n
->string
[sz
- 2] == '\\')
426 p
->flags
|= TERMP_NOSPACE
;
433 print_body(p
, n
->child
, m
);
437 if (termacts
[n
->tok
].post
)
438 (*termacts
[n
->tok
].post
)(p
, n
, m
);
447 print_body(DECL_ARGS
)
452 print_body(p
, n
->next
, m
);
457 print_foot(struct termp
*p
, const struct man_meta
*meta
)
462 if (NULL
== (buf
= malloc(p
->rmargin
)))
465 tm
= localtime(&meta
->date
);
467 if (0 == strftime(buf
, p
->rmargin
, "%B %d, %Y", tm
))
472 p
->flags
|= TERMP_NOSPACE
| TERMP_NOBREAK
;
473 p
->rmargin
= p
->maxrmargin
- strlen(buf
);
477 term_word(p
, meta
->source
);
482 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
483 p
->offset
= p
->rmargin
;
484 p
->rmargin
= p
->maxrmargin
;
485 p
->flags
&= ~TERMP_NOBREAK
;
495 print_head(struct termp
*p
, const struct man_meta
*meta
)
499 p
->rmargin
= p
->maxrmargin
;
502 if (NULL
== (buf
= malloc(p
->rmargin
)))
504 if (NULL
== (title
= malloc(p
->rmargin
)))
508 (void)strlcpy(buf
, meta
->vol
, p
->rmargin
);
512 (void)snprintf(title
, p
->rmargin
, "%s(%d)",
513 meta
->title
, meta
->msec
);
516 p
->rmargin
= (p
->maxrmargin
- strlen(buf
) + 1) / 2;
517 p
->flags
|= TERMP_NOBREAK
| TERMP_NOSPACE
;
522 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
523 p
->offset
= p
->rmargin
;
524 p
->rmargin
= p
->maxrmargin
- strlen(title
);
529 p
->offset
= p
->rmargin
;
530 p
->rmargin
= p
->maxrmargin
;
531 p
->flags
&= ~TERMP_NOBREAK
;
532 p
->flags
|= TERMP_NOLPAD
| TERMP_NOSPACE
;
537 p
->rmargin
= p
->maxrmargin
;
539 p
->flags
&= ~TERMP_NOSPACE
;