]>
git.cameronkatri.com Git - mandoc.git/blob - man_macro.c
1 /* $Id: man_macro.c,v 1.20 2009/08/18 08:48:30 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.
24 #define REW_REWIND (0) /* See rew_scope(). */
25 #define REW_NOHALT (1) /* See rew_scope(). */
26 #define REW_HALT (2) /* See rew_scope(). */
28 static int in_line_eoln(MACRO_PROT_ARGS
);
29 static int blk_imp(MACRO_PROT_ARGS
);
31 static int rew_scope(enum man_type
, struct man
*, int);
32 static int rew_dohalt(int, enum man_type
,
33 const struct man_node
*);
35 const struct man_macro __man_macros
[MAN_MAX
] = {
36 { in_line_eoln
, 0 }, /* br */
37 { in_line_eoln
, 0 }, /* TH */
38 { blk_imp
, 0 }, /* SH */
39 { blk_imp
, 0 }, /* SS */
40 { blk_imp
, MAN_SCOPED
}, /* TP */
41 { blk_imp
, 0 }, /* LP */
42 { blk_imp
, 0 }, /* PP */
43 { blk_imp
, 0 }, /* P */
44 { blk_imp
, 0 }, /* IP */
45 { blk_imp
, 0 }, /* HP */
46 { in_line_eoln
, MAN_SCOPED
}, /* SM */
47 { in_line_eoln
, MAN_SCOPED
}, /* SB */
48 { in_line_eoln
, 0 }, /* BI */
49 { in_line_eoln
, 0 }, /* IB */
50 { in_line_eoln
, 0 }, /* BR */
51 { in_line_eoln
, 0 }, /* RB */
52 { in_line_eoln
, MAN_SCOPED
}, /* R */
53 { in_line_eoln
, MAN_SCOPED
}, /* B */
54 { in_line_eoln
, MAN_SCOPED
}, /* I */
55 { in_line_eoln
, 0 }, /* IR */
56 { in_line_eoln
, 0 }, /* RI */
57 { in_line_eoln
, 0 }, /* na */
58 { in_line_eoln
, 0 }, /* i */
59 { in_line_eoln
, 0 }, /* sp */
60 { in_line_eoln
, 0 }, /* nf */
61 { in_line_eoln
, 0 }, /* fi */
62 { in_line_eoln
, 0 }, /* r */
65 const struct man_macro
* const man_macros
= __man_macros
;
69 man_unscope(struct man
*m
, const struct man_node
*n
)
73 m
->next
= MAN_NEXT_SIBLING
;
76 while (m
->last
!= n
) {
77 if ( ! man_valid_post(m
))
79 if ( ! man_action_post(m
))
81 m
->last
= m
->last
->parent
;
85 if ( ! man_valid_post(m
))
87 return(man_action_post(m
));
92 * There are three scope levels: scoped to the root (all), scoped to the
93 * section (all less sections), and scoped to subsections (all less
94 * sections and subsections).
97 rew_dohalt(int tok
, enum man_type type
, const struct man_node
*n
)
100 if (MAN_ROOT
== n
->type
)
103 if (MAN_ROOT
== n
->parent
->type
)
105 if (MAN_VALID
& n
->flags
)
110 /* Rewind to ourselves. */
111 if (type
== n
->type
&& tok
== n
->tok
)
115 /* Rewind to ourselves. */
116 if (type
== n
->type
&& tok
== n
->tok
)
118 /* Rewind to a section, if a block. */
119 if (MAN_BLOCK
== type
&& MAN_SH
== n
->parent
->tok
&&
120 MAN_BODY
== n
->parent
->type
)
122 /* Don't go beyond a section. */
123 if (MAN_SH
== n
->tok
)
127 /* Rewind to ourselves. */
128 if (type
== n
->type
&& tok
== n
->tok
)
130 /* Rewind to a subsection, if a block. */
131 if (MAN_BLOCK
== type
&& MAN_SS
== n
->parent
->tok
&&
132 MAN_BODY
== n
->parent
->type
)
134 /* Don't go beyond a subsection. */
135 if (MAN_SS
== n
->tok
)
137 /* Rewind to a section, if a block. */
138 if (MAN_BLOCK
== type
&& MAN_SH
== n
->parent
->tok
&&
139 MAN_BODY
== n
->parent
->type
)
141 /* Don't go beyond a section. */
142 if (MAN_SH
== n
->tok
)
152 * Rewinding entails ascending the parse tree until a coherent point,
153 * for example, the `SH' macro will close out any intervening `SS'
154 * scopes. When a scope is closed, it must be validated and actioned.
157 rew_scope(enum man_type type
, struct man
*m
, int tok
)
163 for (n
= m
->last
; n
; n
= n
->parent
) {
165 * Whether we should stop immediately (REW_HALT), stop
166 * and rewind until this point (REW_REWIND), or keep
167 * rewinding (REW_NOHALT).
169 c
= rew_dohalt(tok
, type
, n
);
176 /* Rewind until the current point. */
179 return(man_unscope(m
, n
));
184 * Parse an implicit-block macro. These contain a MAN_HEAD and a
185 * MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
186 * scopes, such as `SH' closing out an `SS', are defined in the rew
190 blk_imp(MACRO_PROT_ARGS
)
195 /* Close out prior scopes. */
197 if ( ! rew_scope(MAN_BODY
, m
, tok
))
199 if ( ! rew_scope(MAN_BLOCK
, m
, tok
))
202 /* Allocate new block & head scope. */
204 if ( ! man_block_alloc(m
, line
, ppos
, tok
))
206 if ( ! man_head_alloc(m
, line
, ppos
, tok
))
209 /* Add line arguments. */
213 w
= man_args(m
, line
, pos
, buf
, &p
);
220 if ( ! man_word_alloc(m
, line
, la
, p
))
222 m
->next
= MAN_NEXT_SIBLING
;
225 /* Close out head and open body (unless MAN_SCOPE). */
227 if (MAN_SCOPED
& man_macros
[tok
].flags
) {
228 m
->flags
|= MAN_BLINE
;
230 } else if ( ! rew_scope(MAN_HEAD
, m
, tok
))
233 return(man_body_alloc(m
, line
, ppos
, tok
));
238 in_line_eoln(MACRO_PROT_ARGS
)
244 if ( ! man_elem_alloc(m
, line
, ppos
, tok
))
248 m
->next
= MAN_NEXT_CHILD
;
252 w
= man_args(m
, line
, pos
, buf
, &p
);
259 if ( ! man_word_alloc(m
, line
, la
, p
))
261 m
->next
= MAN_NEXT_SIBLING
;
264 if (n
== m
->last
&& (MAN_SCOPED
& man_macros
[tok
].flags
)) {
265 m
->flags
|= MAN_ELINE
;
270 * Note that when TH is pruned, we'll be back at the root, so
271 * make sure that we don't clobber as its sibling.
274 /* FIXME: clean this to use man_unscope(). */
276 for ( ; m
->last
; m
->last
= m
->last
->parent
) {
279 if (m
->last
->type
== MAN_ROOT
)
281 if ( ! man_valid_post(m
))
283 if ( ! man_action_post(m
))
290 * Same here regarding whether we're back at the root.
293 if (m
->last
->type
!= MAN_ROOT
&& ! man_valid_post(m
))
295 if (m
->last
->type
!= MAN_ROOT
&& ! man_action_post(m
))
297 if (m
->last
->type
!= MAN_ROOT
)
298 m
->next
= MAN_NEXT_SIBLING
;
305 man_macroend(struct man
*m
)
308 return(man_unscope(m
, m
->first
));