]> git.cameronkatri.com Git - mandoc.git/blob - man_macro.c
Open explicit scope on libman exit now only generates warning.
[mandoc.git] / man_macro.c
1 /* $Id: man_macro.c,v 1.26 2009/08/21 12:12:12 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 static int blk_close(MACRO_PROT_ARGS);
31
32 static int rew_scope(enum man_type, struct man *, int);
33 static int rew_dohalt(int, enum man_type,
34 const struct man_node *);
35 static int rew_block(int, enum man_type,
36 const struct man_node *);
37
38 const struct man_macro __man_macros[MAN_MAX] = {
39 { in_line_eoln, 0 }, /* br */
40 { in_line_eoln, 0 }, /* TH */
41 { blk_imp, MAN_SCOPED }, /* SH */
42 { blk_imp, MAN_SCOPED }, /* SS */
43 { blk_imp, MAN_SCOPED }, /* TP */
44 { blk_imp, 0 }, /* LP */
45 { blk_imp, 0 }, /* PP */
46 { blk_imp, 0 }, /* P */
47 { blk_imp, 0 }, /* IP */
48 { blk_imp, 0 }, /* HP */
49 { in_line_eoln, MAN_SCOPED }, /* SM */
50 { in_line_eoln, MAN_SCOPED }, /* SB */
51 { in_line_eoln, 0 }, /* BI */
52 { in_line_eoln, 0 }, /* IB */
53 { in_line_eoln, 0 }, /* BR */
54 { in_line_eoln, 0 }, /* RB */
55 { in_line_eoln, MAN_SCOPED }, /* R */
56 { in_line_eoln, MAN_SCOPED }, /* B */
57 { in_line_eoln, MAN_SCOPED }, /* I */
58 { in_line_eoln, 0 }, /* IR */
59 { in_line_eoln, 0 }, /* RI */
60 { in_line_eoln, 0 }, /* na */
61 { in_line_eoln, 0 }, /* i */
62 { in_line_eoln, 0 }, /* sp */
63 { in_line_eoln, 0 }, /* nf */
64 { in_line_eoln, 0 }, /* fi */
65 { in_line_eoln, 0 }, /* r */
66 { blk_close, 0 }, /* RE */
67 { blk_imp, MAN_EXPLICIT }, /* RS */
68 { in_line_eoln, 0 }, /* DT */
69 };
70
71 const struct man_macro * const man_macros = __man_macros;
72
73
74 int
75 man_unscope(struct man *m, const struct man_node *n)
76 {
77
78 assert(n);
79 m->next = MAN_NEXT_SIBLING;
80
81 /* LINTED */
82 while (m->last != n) {
83 if ( ! man_valid_post(m))
84 return(0);
85 if ( ! man_action_post(m))
86 return(0);
87 m->last = m->last->parent;
88 assert(m->last);
89 }
90
91 if ( ! man_valid_post(m))
92 return(0);
93 return(man_action_post(m));
94 }
95
96
97 static int
98 rew_block(int ntok, enum man_type type, const struct man_node *n)
99 {
100
101 if (MAN_BLOCK == type && ntok == n->parent->tok &&
102 MAN_BODY == n->parent->type)
103 return(REW_REWIND);
104 return(ntok == n->tok ? REW_HALT : REW_NOHALT);
105 }
106
107
108 /*
109 * There are three scope levels: scoped to the root (all), scoped to the
110 * section (all less sections), and scoped to subsections (all less
111 * sections and subsections).
112 */
113 static int
114 rew_dohalt(int tok, enum man_type type, const struct man_node *n)
115 {
116 int c;
117
118 if (MAN_ROOT == n->type)
119 return(REW_HALT);
120 assert(n->parent);
121 if (MAN_ROOT == n->parent->type)
122 return(REW_REWIND);
123 if (MAN_VALID & n->flags)
124 return(REW_NOHALT);
125
126 /* Rewind to ourselves, first. */
127 if (type == n->type && tok == n->tok)
128 return(REW_REWIND);
129
130 switch (tok) {
131 case (MAN_SH):
132 break;
133 case (MAN_SS):
134 /* Rewind to a section, if a block. */
135 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
136 return(c);
137 break;
138 case (MAN_RS):
139 /* Rewind to a subsection, if a block. */
140 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
141 return(c);
142 /* Rewind to a section, if a block. */
143 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
144 return(c);
145 break;
146 default:
147 /* Rewind to an offsetter, if a block. */
148 if (REW_NOHALT != (c = rew_block(MAN_RS, type, n)))
149 return(c);
150 /* Rewind to a subsection, if a block. */
151 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
152 return(c);
153 /* Rewind to a section, if a block. */
154 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
155 return(c);
156 break;
157 }
158
159 return(REW_NOHALT);
160 }
161
162
163 /*
164 * Rewinding entails ascending the parse tree until a coherent point,
165 * for example, the `SH' macro will close out any intervening `SS'
166 * scopes. When a scope is closed, it must be validated and actioned.
167 */
168 static int
169 rew_scope(enum man_type type, struct man *m, int tok)
170 {
171 struct man_node *n;
172 int c;
173
174 /* LINTED */
175 for (n = m->last; n; n = n->parent) {
176 /*
177 * Whether we should stop immediately (REW_HALT), stop
178 * and rewind until this point (REW_REWIND), or keep
179 * rewinding (REW_NOHALT).
180 */
181 c = rew_dohalt(tok, type, n);
182 if (REW_HALT == c)
183 return(1);
184 if (REW_REWIND == c)
185 break;
186 }
187
188 /* Rewind until the current point. */
189
190 assert(n);
191 return(man_unscope(m, n));
192 }
193
194
195 /* ARGSUSED */
196 int
197 blk_close(MACRO_PROT_ARGS)
198 {
199 int ntok;
200 const struct man_node *nn;
201
202 switch (tok) {
203 case (MAN_RE):
204 ntok = MAN_RS;
205 break;
206 default:
207 abort();
208 /* NOTREACHED */
209 }
210
211 for (nn = m->last->parent; nn; nn = nn->parent)
212 if (ntok == nn->tok)
213 break;
214
215 if (NULL == nn)
216 if ( ! man_pwarn(m, line, ppos, WNOSCOPE))
217 return(0);
218
219 if ( ! rew_scope(MAN_BODY, m, ntok))
220 return(0);
221 if ( ! rew_scope(MAN_BLOCK, m, ntok))
222 return(0);
223 m->next = MAN_NEXT_SIBLING;
224 return(1);
225 }
226
227
228 /*
229 * Parse an implicit-block macro. These contain a MAN_HEAD and a
230 * MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
231 * scopes, such as `SH' closing out an `SS', are defined in the rew
232 * routines.
233 */
234 int
235 blk_imp(MACRO_PROT_ARGS)
236 {
237 int w, la;
238 char *p;
239 struct man_node *n;
240
241 /* Close out prior scopes. */
242
243 if ( ! rew_scope(MAN_BODY, m, tok))
244 return(0);
245 if ( ! rew_scope(MAN_BLOCK, m, tok))
246 return(0);
247
248 /* Allocate new block & head scope. */
249
250 if ( ! man_block_alloc(m, line, ppos, tok))
251 return(0);
252 if ( ! man_head_alloc(m, line, ppos, tok))
253 return(0);
254
255 n = m->last;
256
257 /* Add line arguments. */
258
259 for (;;) {
260 la = *pos;
261 w = man_args(m, line, pos, buf, &p);
262
263 if (-1 == w)
264 return(0);
265 if (0 == w)
266 break;
267
268 if ( ! man_word_alloc(m, line, la, p))
269 return(0);
270 }
271
272 /* Close out head and open body (unless MAN_SCOPE). */
273
274 if (n == m->last && MAN_SCOPED & man_macros[tok].flags) {
275 m->flags |= MAN_BLINE;
276 return(1);
277 } else if ( ! rew_scope(MAN_HEAD, m, tok))
278 return(0);
279
280 return(man_body_alloc(m, line, ppos, tok));
281 }
282
283
284 int
285 in_line_eoln(MACRO_PROT_ARGS)
286 {
287 int w, la;
288 char *p;
289 struct man_node *n;
290
291 if ( ! man_elem_alloc(m, line, ppos, tok))
292 return(0);
293
294 n = m->last;
295
296 for (;;) {
297 la = *pos;
298 w = man_args(m, line, pos, buf, &p);
299
300 if (-1 == w)
301 return(0);
302 if (0 == w)
303 break;
304
305 if ( ! man_word_alloc(m, line, la, p))
306 return(0);
307 }
308
309 if (n == m->last && MAN_SCOPED & man_macros[tok].flags) {
310 m->flags |= MAN_ELINE;
311 return(1);
312 }
313
314 /*
315 * Note that when TH is pruned, we'll be back at the root, so
316 * make sure that we don't clobber as its sibling.
317 */
318
319 for ( ; m->last; m->last = m->last->parent) {
320 if (m->last == n)
321 break;
322 if (m->last->type == MAN_ROOT)
323 break;
324 if ( ! man_valid_post(m))
325 return(0);
326 if ( ! man_action_post(m))
327 return(0);
328 }
329
330 assert(m->last);
331
332 /*
333 * Same here regarding whether we're back at the root.
334 */
335
336 if (m->last->type != MAN_ROOT && ! man_valid_post(m))
337 return(0);
338 if (m->last->type != MAN_ROOT && ! man_action_post(m))
339 return(0);
340 if (m->last->type != MAN_ROOT)
341 m->next = MAN_NEXT_SIBLING;
342
343 return(1);
344 }
345
346
347 int
348 man_macroend(struct man *m)
349 {
350 struct man_node *n;
351
352 n = MAN_VALID & m->last->flags ?
353 m->last->parent : m->last;
354
355 for ( ; n; n = n->parent) {
356 if (MAN_BLOCK != n->type)
357 continue;
358 if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
359 continue;
360 if ( ! man_nwarn(m, n, WEXITSCOPE))
361 return(0);
362 }
363
364 return(man_unscope(m, m->first));
365 }
366