]>
git.cameronkatri.com Git - mandoc.git/blob - termact.c
1 /* $Id: termact.c,v 1.6 2009/02/22 19:23:48 kristaps Exp $ */
3 * Copyright (c) 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
7 * above copyright notice and this permission notice appear in all
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
28 * Performs actions on nodes of the abstract syntax tree. Both pre- and
29 * post-fix operations are defined here.
33 #define TTYPE_CMD_FLAG 1
34 #define TTYPE_CMD_ARG 2
35 #define TTYPE_SECTION 3
36 #define TTYPE_FUNC_DECL 4
37 #define TTYPE_VAR_DECL 5
38 #define TTYPE_FUNC_TYPE 6
39 #define TTYPE_FUNC_NAME 7
40 #define TTYPE_FUNC_ARG 8
45 * These define "styles" for element types, like command arguments or
46 * executable names. This is useful when multiple macros must decorate
47 * the same thing (like .Ex -std cmd and .Nm cmd).
50 const int ttypes
[TTYPE_NMAX
] = {
51 TERMP_BOLD
, /* TTYPE_PROG */
52 TERMP_BOLD
, /* TTYPE_CMD_FLAG */
53 TERMP_UNDERLINE
, /* TTYPE_CMD_ARG */
54 TERMP_BOLD
, /* TTYPE_SECTION */
55 TERMP_BOLD
, /* TTYPE_FUNC_DECL */
56 TERMP_UNDERLINE
, /* TTYPE_VAR_DECL */
57 TERMP_UNDERLINE
, /* TTYPE_FUNC_TYPE */
58 TERMP_BOLD
, /* TTYPE_FUNC_NAME */
59 TERMP_UNDERLINE
, /* TTYPE_FUNC_ARG */
60 TERMP_UNDERLINE
/* TTYPE_LINK */
63 static int arg_hasattr(int, size_t,
64 const struct mdoc_arg
*);
65 static int arg_getattr(int, size_t,
66 const struct mdoc_arg
*);
67 static size_t arg_offset(const char *);
70 * What follows describes prefix and postfix operations for the abstract
71 * syntax tree descent.
76 const struct mdoc_meta *meta, \
77 const struct mdoc_node *node
79 #define DECL_PRE(name) \
80 static int name##_pre(DECL_ARGS)
81 #define DECL_POST(name) \
82 static void name##_post(DECL_ARGS)
134 const struct termact __termacts
[MDOC_MAX
] = {
135 { NULL
, NULL
}, /* \" */
136 { NULL
, NULL
}, /* Dd */
137 { NULL
, NULL
}, /* Dt */
138 { NULL
, NULL
}, /* Os */
139 { termp_sh_pre
, termp_sh_post
}, /* Sh */
140 { NULL
, NULL
}, /* Ss */
141 { termp_pp_pre
, NULL
}, /* Pp */
142 { termp_d1_pre
, termp_d1_post
}, /* D1 */
143 { NULL
, NULL
}, /* Dl */
144 { termp_bd_pre
, NULL
}, /* Bd */
145 { NULL
, NULL
}, /* Ed */
146 { NULL
, termp_bl_post
}, /* Bl */
147 { NULL
, NULL
}, /* El */
148 { termp_it_pre
, termp_it_post
}, /* It */
149 { NULL
, NULL
}, /* Ad */
150 { NULL
, NULL
}, /* An */
151 { termp_ar_pre
, termp_ar_post
}, /* Ar */
152 { NULL
, NULL
}, /* Cd */
153 { NULL
, NULL
}, /* Cm */
154 { NULL
, NULL
}, /* Dv */
155 { NULL
, NULL
}, /* Er */
156 { NULL
, NULL
}, /* Ev */
157 { termp_ex_pre
, NULL
}, /* Ex */
158 { termp_fa_pre
, termp_fa_post
}, /* Fa */
159 { termp_fd_pre
, termp_fd_post
}, /* Fd */
160 { termp_fl_pre
, termp_fl_post
}, /* Fl */
161 { termp_fn_pre
, termp_fn_post
}, /* Fn */
162 { termp_ft_pre
, termp_ft_post
}, /* Ft */
163 { NULL
, NULL
}, /* Ic */
164 { NULL
, NULL
}, /* In */
165 { NULL
, NULL
}, /* Li */
166 { termp_nd_pre
, NULL
}, /* Nd */
167 { termp_nm_pre
, termp_nm_post
}, /* Nm */
168 { termp_op_pre
, termp_op_post
}, /* Op */
169 { NULL
, NULL
}, /* Ot */
170 { NULL
, NULL
}, /* Pa */
171 { NULL
, NULL
}, /* Rv */
172 { NULL
, NULL
}, /* St */
173 { termp_va_pre
, termp_va_post
}, /* Va */
174 { termp_vt_pre
, termp_vt_post
}, /* Vt */
175 { termp_xr_pre
, NULL
}, /* Xr */
176 { NULL
, NULL
}, /* %A */
177 { NULL
, NULL
}, /* %B */
178 { NULL
, NULL
}, /* %D */
179 { NULL
, NULL
}, /* %I */
180 { NULL
, NULL
}, /* %J */
181 { NULL
, NULL
}, /* %N */
182 { NULL
, NULL
}, /* %O */
183 { NULL
, NULL
}, /* %P */
184 { NULL
, NULL
}, /* %R */
185 { NULL
, NULL
}, /* %T */
186 { NULL
, NULL
}, /* %V */
187 { NULL
, NULL
}, /* Ac */
188 { NULL
, NULL
}, /* Ao */
189 { termp_aq_pre
, termp_aq_post
}, /* Aq */
190 { NULL
, NULL
}, /* At */
191 { NULL
, NULL
}, /* Bc */
192 { NULL
, NULL
}, /* Bf */
193 { NULL
, NULL
}, /* Bo */
194 { NULL
, NULL
}, /* Bq */
195 { NULL
, NULL
}, /* Bsx */
196 { NULL
, NULL
}, /* Bx */
197 { NULL
, NULL
}, /* Db */
198 { NULL
, NULL
}, /* Dc */
199 { NULL
, NULL
}, /* Do */
200 { termp_dq_pre
, termp_dq_post
}, /* Dq */
201 { NULL
, NULL
}, /* Ec */
202 { NULL
, NULL
}, /* Ef */
203 { NULL
, NULL
}, /* Em */
204 { NULL
, NULL
}, /* Eo */
205 { NULL
, NULL
}, /* Fx */
206 { NULL
, NULL
}, /* Ms */
207 { NULL
, NULL
}, /* No */
208 { termp_ns_pre
, NULL
}, /* Ns */
209 { termp_nx_pre
, NULL
}, /* Nx */
210 { termp_ox_pre
, NULL
}, /* Ox */
211 { NULL
, NULL
}, /* Pc */
212 { termp_pf_pre
, termp_pf_post
}, /* Pf */
213 { NULL
, NULL
}, /* Po */
214 { NULL
, NULL
}, /* Pq */
215 { NULL
, NULL
}, /* Qc */
216 { NULL
, NULL
}, /* Ql */
217 { NULL
, NULL
}, /* Qo */
218 { termp_qq_pre
, termp_qq_post
}, /* Qq */
219 { NULL
, NULL
}, /* Re */
220 { NULL
, NULL
}, /* Rs */
221 { NULL
, NULL
}, /* Sc */
222 { NULL
, NULL
}, /* So */
223 { termp_sq_pre
, termp_sq_post
}, /* Sq */
224 { NULL
, NULL
}, /* Sm */
225 { termp_sx_pre
, termp_sx_post
}, /* Sx */
226 { NULL
, NULL
}, /* Sy */
227 { NULL
, NULL
}, /* Tn */
228 { NULL
, NULL
}, /* Ux */
229 { NULL
, NULL
}, /* Xc */
230 { NULL
, NULL
}, /* Xo */
231 { NULL
, NULL
}, /* Fo */
232 { NULL
, NULL
}, /* Fc */
233 { NULL
, NULL
}, /* Oo */
234 { NULL
, NULL
}, /* Oc */
235 { NULL
, NULL
}, /* Bk */
236 { NULL
, NULL
}, /* Ek */
237 { NULL
, NULL
}, /* Bt */
238 { NULL
, NULL
}, /* Hf */
239 { NULL
, NULL
}, /* Fr */
240 { termp_ud_pre
, NULL
}, /* Ud */
243 const struct termact
*termacts
= __termacts
;
247 arg_offset(const char *v
)
249 if (0 == strcmp(v
, "indent"))
251 if (0 == strcmp(v
, "indent-two"))
260 arg_hasattr(int arg
, size_t argc
, const struct mdoc_arg
*argv
)
263 return(-1 != arg_getattr(arg
, argc
, argv
));
268 arg_getattr(int arg
, size_t argc
, const struct mdoc_arg
*argv
)
272 for (i
= 0; i
< (int)argc
; i
++)
273 if (argv
[i
].arg
== arg
)
281 termp_dq_pre(DECL_ARGS
)
284 if (MDOC_BODY
!= node
->type
)
288 p
->flags
|= TERMP_NOSPACE
;
295 termp_dq_post(DECL_ARGS
)
298 if (MDOC_BODY
!= node
->type
)
301 p
->flags
|= TERMP_NOSPACE
;
308 termp_it_post(DECL_ARGS
)
310 const struct mdoc_node
*n
, *it
;
311 const struct mdoc_block
*bl
;
316 * This (and termp_it_pre()) are the most complicated functions
317 * here. They must account for a considerable number of
318 * switches that completely change the output behaviour, like
319 * -tag versus -column. Yech.
322 switch (node
->type
) {
332 assert(MDOC_BLOCK
== it
->type
);
333 assert(MDOC_It
== it
->tok
);
336 assert(MDOC_BODY
== n
->type
);
337 assert(MDOC_Bl
== n
->tok
);
341 /* If `-tag', adjust our margins accordingly. */
343 if (arg_hasattr(MDOC_Tag
, bl
->argc
, bl
->argv
)) {
344 i
= arg_getattr(MDOC_Width
, bl
->argc
, bl
->argv
);
346 assert(1 == bl
->argv
[i
].sz
);
347 width
= strlen(*bl
->argv
[i
].value
); /* XXX */
349 if (MDOC_HEAD
== node
->type
) {
351 /* FIXME: nested lists. */
352 p
->rmargin
= p
->maxrmargin
;
353 p
->flags
&= ~TERMP_NOBREAK
;
356 p
->offset
-= width
+ 1;
357 p
->flags
&= ~TERMP_NOLPAD
;
362 if (arg_hasattr(MDOC_Ohang
, bl
->argc
, bl
->argv
)) {
363 i
= arg_getattr(MDOC_Offset
, bl
->argc
, bl
->argv
);
365 assert(1 == bl
->argv
[i
].sz
);
366 width
= arg_offset(*bl
->argv
[i
].value
);
369 p
->offset
-= width
+ 1;
377 termp_it_pre(DECL_ARGS
)
379 const struct mdoc_node
*n
, *it
;
380 const struct mdoc_block
*bl
;
385 * Also see termp_it_post() for general comments.
388 switch (node
->type
) {
401 assert(MDOC_BLOCK
== it
->type
);
402 assert(MDOC_It
== it
->tok
);
405 assert(MDOC_BODY
== n
->type
);
406 assert(MDOC_Bl
== n
->tok
);
410 /* If `-compact', don't assert vertical space. */
412 if (MDOC_BLOCK
== node
->type
) {
413 if (arg_hasattr(MDOC_Compact
, bl
->argc
, bl
->argv
))
420 assert(MDOC_HEAD
== node
->type
421 || MDOC_BODY
== node
->type
);
423 /* If `-tag', adjust our margins accordingly. */
425 if (arg_hasattr(MDOC_Tag
, bl
->argc
, bl
->argv
)) {
426 i
= arg_getattr(MDOC_Width
, bl
->argc
, bl
->argv
);
427 assert(i
>= 0); /* XXX */
428 assert(1 == bl
->argv
[i
].sz
);
429 width
= strlen(*bl
->argv
[i
].value
); /* XXX */
431 /* FIXME: nested lists. */
433 if (MDOC_HEAD
== node
->type
) {
434 p
->flags
|= TERMP_NOBREAK
;
435 p
->flags
|= TERMP_NOSPACE
;
436 p
->rmargin
= p
->offset
+ width
;
438 p
->flags
|= TERMP_NOSPACE
;
439 p
->flags
|= TERMP_NOLPAD
;
440 p
->offset
+= width
+ 1;
445 /* If `-ohang', adjust left-margin. */
447 if (arg_hasattr(MDOC_Ohang
, bl
->argc
, bl
->argv
)) {
448 i
= arg_getattr(MDOC_Offset
, bl
->argc
, bl
->argv
);
450 assert(1 == bl
->argv
[i
].sz
);
451 width
= arg_offset(*bl
->argv
[i
].value
);
453 p
->flags
|= TERMP_NOSPACE
;
454 p
->offset
+= width
+ 1;
464 termp_nm_post(DECL_ARGS
)
467 p
->flags
&= ~ttypes
[TTYPE_PROG
];
473 termp_fl_post(DECL_ARGS
)
476 p
->flags
&= ~ttypes
[TTYPE_CMD_FLAG
];
482 termp_ar_pre(DECL_ARGS
)
485 p
->flags
|= ttypes
[TTYPE_CMD_ARG
];
486 if (NULL
== node
->child
)
494 termp_nm_pre(DECL_ARGS
)
497 p
->flags
|= ttypes
[TTYPE_PROG
];
498 if (NULL
== node
->child
)
506 termp_ns_pre(DECL_ARGS
)
509 p
->flags
|= TERMP_NOSPACE
;
516 termp_pp_pre(DECL_ARGS
)
526 termp_ar_post(DECL_ARGS
)
529 p
->flags
&= ~ttypes
[TTYPE_CMD_ARG
];
535 termp_ex_pre(DECL_ARGS
)
539 i
= arg_getattr(MDOC_Std
, node
->data
.elem
.argc
,
540 node
->data
.elem
.argv
);
544 p
->flags
|= ttypes
[TTYPE_PROG
];
545 word(p
, *node
->data
.elem
.argv
[i
].value
);
546 p
->flags
&= ~ttypes
[TTYPE_PROG
];
547 word(p
, "utility exits 0 on success, and >0 if an error occurs.");
555 termp_nd_pre(DECL_ARGS
)
565 termp_bl_post(DECL_ARGS
)
568 if (MDOC_BLOCK
== node
->type
)
575 termp_op_post(DECL_ARGS
)
578 if (MDOC_BODY
!= node
->type
)
580 p
->flags
|= TERMP_NOSPACE
;
587 termp_sh_post(DECL_ARGS
)
590 switch (node
->type
) {
592 p
->flags
&= ~ttypes
[TTYPE_SECTION
];
607 termp_xr_pre(DECL_ARGS
)
609 const struct mdoc_node
*n
;
614 assert(MDOC_TEXT
== n
->type
);
615 word(p
, n
->data
.text
.string
);
617 if (NULL
== (n
= n
->next
))
620 assert(MDOC_TEXT
== n
->type
);
621 p
->flags
|= TERMP_NOSPACE
;
623 p
->flags
|= TERMP_NOSPACE
;
624 word(p
, n
->data
.text
.string
);
625 p
->flags
|= TERMP_NOSPACE
;
634 termp_vt_pre(DECL_ARGS
)
637 /* FIXME: this can be "type name". */
638 p
->flags
|= ttypes
[TTYPE_VAR_DECL
];
645 termp_vt_post(DECL_ARGS
)
648 p
->flags
&= ~ttypes
[TTYPE_VAR_DECL
];
649 if (node
->sec
== SEC_SYNOPSIS
)
656 termp_fd_pre(DECL_ARGS
)
660 * FIXME: this naming is bad. This value is used, in general,
661 * for the #include header or other preprocessor statement.
663 p
->flags
|= ttypes
[TTYPE_FUNC_DECL
];
670 termp_fd_post(DECL_ARGS
)
673 p
->flags
&= ~ttypes
[TTYPE_FUNC_DECL
];
674 if (node
->sec
== SEC_SYNOPSIS
)
682 termp_sh_pre(DECL_ARGS
)
685 switch (node
->type
) {
688 p
->flags
|= ttypes
[TTYPE_SECTION
];
702 termp_op_pre(DECL_ARGS
)
705 switch (node
->type
) {
708 p
->flags
|= TERMP_NOSPACE
;
719 termp_ud_pre(DECL_ARGS
)
722 word(p
, "currently under development.");
729 termp_fl_pre(DECL_ARGS
)
732 p
->flags
|= ttypes
[TTYPE_CMD_FLAG
];
734 p
->flags
|= TERMP_NOSPACE
;
741 termp_d1_pre(DECL_ARGS
)
744 if (MDOC_BODY
!= node
->type
)
754 termp_d1_post(DECL_ARGS
)
757 if (MDOC_BODY
!= node
->type
)
766 termp_aq_pre(DECL_ARGS
)
769 if (MDOC_BODY
!= node
->type
)
772 p
->flags
|= TERMP_NOSPACE
;
779 termp_aq_post(DECL_ARGS
)
782 if (MDOC_BODY
!= node
->type
)
784 p
->flags
|= TERMP_NOSPACE
;
791 termp_ft_pre(DECL_ARGS
)
794 p
->flags
|= ttypes
[TTYPE_FUNC_TYPE
];
801 termp_ft_post(DECL_ARGS
)
804 p
->flags
&= ~ttypes
[TTYPE_FUNC_TYPE
];
805 if (node
->sec
== SEC_SYNOPSIS
)
813 termp_fn_pre(DECL_ARGS
)
815 const struct mdoc_node
*n
;
818 assert(MDOC_TEXT
== node
->child
->type
);
820 /* FIXME: can be "type funcname" "type varname"... */
822 p
->flags
|= ttypes
[TTYPE_FUNC_NAME
];
823 word(p
, node
->child
->data
.text
.string
);
824 p
->flags
&= ~ttypes
[TTYPE_FUNC_NAME
];
826 p
->flags
|= TERMP_NOSPACE
;
829 p
->flags
|= TERMP_NOSPACE
;
830 for (n
= node
->child
->next
; n
; n
= n
->next
) {
831 assert(MDOC_TEXT
== n
->type
);
832 p
->flags
|= ttypes
[TTYPE_FUNC_ARG
];
833 word(p
, n
->data
.text
.string
);
834 p
->flags
&= ~ttypes
[TTYPE_FUNC_ARG
];
839 p
->flags
|= TERMP_NOSPACE
;
842 if (SEC_SYNOPSIS
== node
->sec
)
851 termp_fn_post(DECL_ARGS
)
854 if (node
->sec
== SEC_SYNOPSIS
)
862 termp_sx_pre(DECL_ARGS
)
865 p
->flags
|= ttypes
[TTYPE_LINK
];
872 termp_sx_post(DECL_ARGS
)
875 p
->flags
&= ~ttypes
[TTYPE_LINK
];
881 termp_fa_pre(DECL_ARGS
)
884 p
->flags
|= ttypes
[TTYPE_FUNC_ARG
];
891 termp_fa_post(DECL_ARGS
)
894 p
->flags
&= ~ttypes
[TTYPE_FUNC_ARG
];
900 termp_va_pre(DECL_ARGS
)
903 p
->flags
|= ttypes
[TTYPE_VAR_DECL
];
910 termp_va_post(DECL_ARGS
)
913 p
->flags
&= ~ttypes
[TTYPE_VAR_DECL
];
919 termp_bd_pre(DECL_ARGS
)
921 const struct mdoc_block
*bl
;
922 const struct mdoc_node
*n
;
924 if (MDOC_BLOCK
== node
->type
) {
927 } else if (MDOC_BODY
!= node
->type
)
930 assert(MDOC_BLOCK
== node
->parent
->type
);
932 bl
= &node
->parent
->data
.block
;
933 if ( ! arg_hasattr(MDOC_Literal
, bl
->argc
, bl
->argv
))
936 p
->flags
|= TERMP_LITERAL
;
938 for (n
= node
->child
; n
; n
= n
->next
) {
939 assert(MDOC_TEXT
== n
->type
); /* FIXME */
940 if ((*n
->data
.text
.string
)) {
941 word(p
, n
->data
.text
.string
);
948 p
->flags
&= ~TERMP_LITERAL
;
955 termp_qq_pre(DECL_ARGS
)
958 if (MDOC_BODY
!= node
->type
)
961 p
->flags
|= TERMP_NOSPACE
;
968 termp_qq_post(DECL_ARGS
)
971 if (MDOC_BODY
!= node
->type
)
973 p
->flags
|= TERMP_NOSPACE
;
980 termp_ox_pre(DECL_ARGS
)
990 termp_nx_pre(DECL_ARGS
)
1000 termp_sq_pre(DECL_ARGS
)
1003 if (MDOC_BODY
!= node
->type
)
1006 p
->flags
|= TERMP_NOSPACE
;
1013 termp_sq_post(DECL_ARGS
)
1016 if (MDOC_BODY
!= node
->type
)
1018 p
->flags
|= TERMP_NOSPACE
;
1025 termp_pf_pre(DECL_ARGS
)
1028 p
->flags
|= TERMP_IGNDELIM
;
1035 termp_pf_post(DECL_ARGS
)
1038 p
->flags
&= ~TERMP_IGNDELIM
;
1039 p
->flags
|= TERMP_NOSPACE
;