]> git.cameronkatri.com Git - mandoc.git/blob - man_macro.c
Small updates to man.7 (next-line break-exclusions, numerical width example).
[mandoc.git] / man_macro.c
1 /* $Id: man_macro.c,v 1.20 2009/08/18 08:48:30 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
4 *
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.
8 *
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.
16 */
17 #include <assert.h>
18 #include <ctype.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "libman.h"
23
24 #define REW_REWIND (0) /* See rew_scope(). */
25 #define REW_NOHALT (1) /* See rew_scope(). */
26 #define REW_HALT (2) /* See rew_scope(). */
27
28 static int in_line_eoln(MACRO_PROT_ARGS);
29 static int blk_imp(MACRO_PROT_ARGS);
30
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 *);
34
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 */
63 };
64
65 const struct man_macro * const man_macros = __man_macros;
66
67
68 int
69 man_unscope(struct man *m, const struct man_node *n)
70 {
71
72 assert(n);
73 m->next = MAN_NEXT_SIBLING;
74
75 /* LINTED */
76 while (m->last != n) {
77 if ( ! man_valid_post(m))
78 return(0);
79 if ( ! man_action_post(m))
80 return(0);
81 m->last = m->last->parent;
82 assert(m->last);
83 }
84
85 if ( ! man_valid_post(m))
86 return(0);
87 return(man_action_post(m));
88 }
89
90
91 /*
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).
95 */
96 static int
97 rew_dohalt(int tok, enum man_type type, const struct man_node *n)
98 {
99
100 if (MAN_ROOT == n->type)
101 return(REW_HALT);
102 assert(n->parent);
103 if (MAN_ROOT == n->parent->type)
104 return(REW_REWIND);
105 if (MAN_VALID & n->flags)
106 return(REW_NOHALT);
107
108 switch (tok) {
109 case (MAN_SH):
110 /* Rewind to ourselves. */
111 if (type == n->type && tok == n->tok)
112 return(REW_REWIND);
113 break;
114 case (MAN_SS):
115 /* Rewind to ourselves. */
116 if (type == n->type && tok == n->tok)
117 return(REW_REWIND);
118 /* Rewind to a section, if a block. */
119 if (MAN_BLOCK == type && MAN_SH == n->parent->tok &&
120 MAN_BODY == n->parent->type)
121 return(REW_REWIND);
122 /* Don't go beyond a section. */
123 if (MAN_SH == n->tok)
124 return(REW_HALT);
125 break;
126 default:
127 /* Rewind to ourselves. */
128 if (type == n->type && tok == n->tok)
129 return(REW_REWIND);
130 /* Rewind to a subsection, if a block. */
131 if (MAN_BLOCK == type && MAN_SS == n->parent->tok &&
132 MAN_BODY == n->parent->type)
133 return(REW_REWIND);
134 /* Don't go beyond a subsection. */
135 if (MAN_SS == n->tok)
136 return(REW_HALT);
137 /* Rewind to a section, if a block. */
138 if (MAN_BLOCK == type && MAN_SH == n->parent->tok &&
139 MAN_BODY == n->parent->type)
140 return(REW_REWIND);
141 /* Don't go beyond a section. */
142 if (MAN_SH == n->tok)
143 return(REW_HALT);
144 break;
145 }
146
147 return(REW_NOHALT);
148 }
149
150
151 /*
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.
155 */
156 static int
157 rew_scope(enum man_type type, struct man *m, int tok)
158 {
159 struct man_node *n;
160 int c;
161
162 /* LINTED */
163 for (n = m->last; n; n = n->parent) {
164 /*
165 * Whether we should stop immediately (REW_HALT), stop
166 * and rewind until this point (REW_REWIND), or keep
167 * rewinding (REW_NOHALT).
168 */
169 c = rew_dohalt(tok, type, n);
170 if (REW_HALT == c)
171 return(1);
172 if (REW_REWIND == c)
173 break;
174 }
175
176 /* Rewind until the current point. */
177
178 assert(n);
179 return(man_unscope(m, n));
180 }
181
182
183 /*
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
187 * routines.
188 */
189 int
190 blk_imp(MACRO_PROT_ARGS)
191 {
192 int w, la;
193 char *p;
194
195 /* Close out prior scopes. */
196
197 if ( ! rew_scope(MAN_BODY, m, tok))
198 return(0);
199 if ( ! rew_scope(MAN_BLOCK, m, tok))
200 return(0);
201
202 /* Allocate new block & head scope. */
203
204 if ( ! man_block_alloc(m, line, ppos, tok))
205 return(0);
206 if ( ! man_head_alloc(m, line, ppos, tok))
207 return(0);
208
209 /* Add line arguments. */
210
211 for (;;) {
212 la = *pos;
213 w = man_args(m, line, pos, buf, &p);
214
215 if (-1 == w)
216 return(0);
217 if (0 == w)
218 break;
219
220 if ( ! man_word_alloc(m, line, la, p))
221 return(0);
222 m->next = MAN_NEXT_SIBLING;
223 }
224
225 /* Close out head and open body (unless MAN_SCOPE). */
226
227 if (MAN_SCOPED & man_macros[tok].flags) {
228 m->flags |= MAN_BLINE;
229 return(1);
230 } else if ( ! rew_scope(MAN_HEAD, m, tok))
231 return(0);
232
233 return(man_body_alloc(m, line, ppos, tok));
234 }
235
236
237 int
238 in_line_eoln(MACRO_PROT_ARGS)
239 {
240 int w, la;
241 char *p;
242 struct man_node *n;
243
244 if ( ! man_elem_alloc(m, line, ppos, tok))
245 return(0);
246
247 n = m->last;
248 m->next = MAN_NEXT_CHILD;
249
250 for (;;) {
251 la = *pos;
252 w = man_args(m, line, pos, buf, &p);
253
254 if (-1 == w)
255 return(0);
256 if (0 == w)
257 break;
258
259 if ( ! man_word_alloc(m, line, la, p))
260 return(0);
261 m->next = MAN_NEXT_SIBLING;
262 }
263
264 if (n == m->last && (MAN_SCOPED & man_macros[tok].flags)) {
265 m->flags |= MAN_ELINE;
266 return(1);
267 }
268
269 /*
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.
272 */
273
274 /* FIXME: clean this to use man_unscope(). */
275
276 for ( ; m->last; m->last = m->last->parent) {
277 if (m->last == n)
278 break;
279 if (m->last->type == MAN_ROOT)
280 break;
281 if ( ! man_valid_post(m))
282 return(0);
283 if ( ! man_action_post(m))
284 return(0);
285 }
286
287 assert(m->last);
288
289 /*
290 * Same here regarding whether we're back at the root.
291 */
292
293 if (m->last->type != MAN_ROOT && ! man_valid_post(m))
294 return(0);
295 if (m->last->type != MAN_ROOT && ! man_action_post(m))
296 return(0);
297 if (m->last->type != MAN_ROOT)
298 m->next = MAN_NEXT_SIBLING;
299
300 return(1);
301 }
302
303
304 int
305 man_macroend(struct man *m)
306 {
307
308 return(man_unscope(m, m->first));
309 }
310