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