]> git.cameronkatri.com Git - mandoc.git/blob - man_macro.c
update after recent code changes
[mandoc.git] / man_macro.c
1 /* $Id: man_macro.c,v 1.85 2014/07/09 11:28:26 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
5 * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "man.h"
29 #include "mandoc.h"
30 #include "libmandoc.h"
31 #include "libman.h"
32
33 enum rew {
34 REW_REWIND,
35 REW_NOHALT,
36 REW_HALT
37 };
38
39 static int blk_close(MACRO_PROT_ARGS);
40 static int blk_exp(MACRO_PROT_ARGS);
41 static int blk_imp(MACRO_PROT_ARGS);
42 static int in_line_eoln(MACRO_PROT_ARGS);
43 static int man_args(struct man *, int,
44 int *, char *, char **);
45
46 static int rew_scope(enum man_type,
47 struct man *, enum mant);
48 static enum rew rew_dohalt(enum mant, enum man_type,
49 const struct man_node *);
50 static enum rew rew_block(enum mant, enum man_type,
51 const struct man_node *);
52
53 const struct man_macro __man_macros[MAN_MAX] = {
54 { in_line_eoln, MAN_NSCOPED }, /* br */
55 { in_line_eoln, MAN_BSCOPE }, /* TH */
56 { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
57 { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
58 { blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */
59 { blk_imp, MAN_BSCOPE }, /* LP */
60 { blk_imp, MAN_BSCOPE }, /* PP */
61 { blk_imp, MAN_BSCOPE }, /* P */
62 { blk_imp, MAN_BSCOPE }, /* IP */
63 { blk_imp, MAN_BSCOPE }, /* HP */
64 { in_line_eoln, MAN_SCOPED }, /* SM */
65 { in_line_eoln, MAN_SCOPED }, /* SB */
66 { in_line_eoln, 0 }, /* BI */
67 { in_line_eoln, 0 }, /* IB */
68 { in_line_eoln, 0 }, /* BR */
69 { in_line_eoln, 0 }, /* RB */
70 { in_line_eoln, MAN_SCOPED }, /* R */
71 { in_line_eoln, MAN_SCOPED }, /* B */
72 { in_line_eoln, MAN_SCOPED }, /* I */
73 { in_line_eoln, 0 }, /* IR */
74 { in_line_eoln, 0 }, /* RI */
75 { in_line_eoln, MAN_NSCOPED }, /* na */
76 { in_line_eoln, MAN_NSCOPED }, /* sp */
77 { in_line_eoln, MAN_BSCOPE }, /* nf */
78 { in_line_eoln, MAN_BSCOPE }, /* fi */
79 { blk_close, 0 }, /* RE */
80 { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */
81 { in_line_eoln, 0 }, /* DT */
82 { in_line_eoln, 0 }, /* UC */
83 { in_line_eoln, 0 }, /* PD */
84 { in_line_eoln, 0 }, /* AT */
85 { in_line_eoln, 0 }, /* in */
86 { in_line_eoln, 0 }, /* ft */
87 { in_line_eoln, 0 }, /* OP */
88 { in_line_eoln, MAN_BSCOPE }, /* EX */
89 { in_line_eoln, MAN_BSCOPE }, /* EE */
90 { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
91 { blk_close, 0 }, /* UE */
92 { in_line_eoln, 0 }, /* ll */
93 };
94
95 const struct man_macro * const man_macros = __man_macros;
96
97
98 int
99 man_unscope(struct man *man, const struct man_node *to)
100 {
101 struct man_node *n;
102
103 man->next = MAN_NEXT_SIBLING;
104 to = to->parent;
105 n = man->last;
106 while (n != to) {
107 if (NULL == to &&
108 MAN_BLOCK == n->type &&
109 0 == (MAN_VALID & n->flags) &&
110 MAN_EXPLICIT & man_macros[n->tok].flags)
111 mandoc_msg(MANDOCERR_BLK_NOEND,
112 man->parse, n->line, n->pos,
113 man_macronames[n->tok]);
114 /*
115 * We might delete the man->last node
116 * in the post-validation phase.
117 * Save a pointer to the parent such that
118 * we know where to continue the iteration.
119 */
120 man->last = n;
121 n = n->parent;
122 if ( ! man_valid_post(man))
123 return(0);
124 }
125 return(1);
126 }
127
128 static enum rew
129 rew_block(enum mant ntok, enum man_type type, const struct man_node *n)
130 {
131
132 if (MAN_BLOCK == type && ntok == n->parent->tok &&
133 MAN_BODY == n->parent->type)
134 return(REW_REWIND);
135 return(ntok == n->tok ? REW_HALT : REW_NOHALT);
136 }
137
138 /*
139 * There are three scope levels: scoped to the root (all), scoped to the
140 * section (all less sections), and scoped to subsections (all less
141 * sections and subsections).
142 */
143 static enum rew
144 rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
145 {
146 enum rew c;
147
148 /* We cannot progress beyond the root ever. */
149 if (MAN_ROOT == n->type)
150 return(REW_HALT);
151
152 assert(n->parent);
153
154 /* Normal nodes shouldn't go to the level of the root. */
155 if (MAN_ROOT == n->parent->type)
156 return(REW_REWIND);
157
158 /* Already-validated nodes should be closed out. */
159 if (MAN_VALID & n->flags)
160 return(REW_NOHALT);
161
162 /* First: rewind to ourselves. */
163 if (type == n->type && tok == n->tok) {
164 if (MAN_EXPLICIT & man_macros[n->tok].flags)
165 return(REW_HALT);
166 else
167 return(REW_REWIND);
168 }
169
170 /*
171 * Next follow the implicit scope-smashings as defined by man.7:
172 * section, sub-section, etc.
173 */
174
175 switch (tok) {
176 case MAN_SH:
177 break;
178 case MAN_SS:
179 /* Rewind to a section, if a block. */
180 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
181 return(c);
182 break;
183 case MAN_RS:
184 /* Preserve empty paragraphs before RS. */
185 if (0 == n->nchild && (MAN_P == n->tok ||
186 MAN_PP == n->tok || MAN_LP == n->tok))
187 return(REW_HALT);
188 /* Rewind to a subsection, if a block. */
189 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
190 return(c);
191 /* Rewind to a section, if a block. */
192 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
193 return(c);
194 break;
195 default:
196 /* Rewind to an offsetter, if a block. */
197 if (REW_NOHALT != (c = rew_block(MAN_RS, type, n)))
198 return(c);
199 /* Rewind to a subsection, if a block. */
200 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
201 return(c);
202 /* Rewind to a section, if a block. */
203 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
204 return(c);
205 break;
206 }
207
208 return(REW_NOHALT);
209 }
210
211 /*
212 * Rewinding entails ascending the parse tree until a coherent point,
213 * for example, the `SH' macro will close out any intervening `SS'
214 * scopes. When a scope is closed, it must be validated and actioned.
215 */
216 static int
217 rew_scope(enum man_type type, struct man *man, enum mant tok)
218 {
219 struct man_node *n;
220 enum rew c;
221
222 for (n = man->last; n; n = n->parent) {
223 /*
224 * Whether we should stop immediately (REW_HALT), stop
225 * and rewind until this point (REW_REWIND), or keep
226 * rewinding (REW_NOHALT).
227 */
228 c = rew_dohalt(tok, type, n);
229 if (REW_HALT == c)
230 return(1);
231 if (REW_REWIND == c)
232 break;
233 }
234
235 /*
236 * Rewind until the current point. Warn if we're a roff
237 * instruction that's mowing over explicit scopes.
238 */
239 assert(n);
240
241 return(man_unscope(man, n));
242 }
243
244
245 /*
246 * Close out a generic explicit macro.
247 */
248 int
249 blk_close(MACRO_PROT_ARGS)
250 {
251 enum mant ntok;
252 const struct man_node *nn;
253
254 switch (tok) {
255 case MAN_RE:
256 ntok = MAN_RS;
257 break;
258 case MAN_UE:
259 ntok = MAN_UR;
260 break;
261 default:
262 abort();
263 /* NOTREACHED */
264 }
265
266 for (nn = man->last->parent; nn; nn = nn->parent)
267 if (ntok == nn->tok && MAN_BLOCK == nn->type)
268 break;
269
270 if (NULL == nn) {
271 mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
272 line, ppos, man_macronames[tok]);
273 if ( ! rew_scope(MAN_BLOCK, man, MAN_PP))
274 return(0);
275 } else
276 man_unscope(man, nn);
277
278 return(1);
279 }
280
281 int
282 blk_exp(MACRO_PROT_ARGS)
283 {
284 struct man_node *n;
285 int la;
286 char *p;
287
288 /* Close out prior implicit scopes. */
289
290 if ( ! rew_scope(MAN_BLOCK, man, tok))
291 return(0);
292
293 if ( ! man_block_alloc(man, line, ppos, tok))
294 return(0);
295 if ( ! man_head_alloc(man, line, ppos, tok))
296 return(0);
297
298 for (;;) {
299 la = *pos;
300 if ( ! man_args(man, line, pos, buf, &p))
301 break;
302 if ( ! man_word_alloc(man, line, la, p))
303 return(0);
304 }
305
306 assert(man);
307 assert(tok != MAN_MAX);
308
309 for (n = man->last; n; n = n->parent) {
310 if (n->tok != tok)
311 continue;
312 assert(MAN_HEAD == n->type);
313 man_unscope(man, n);
314 break;
315 }
316
317 return(man_body_alloc(man, line, ppos, tok));
318 }
319
320 /*
321 * Parse an implicit-block macro. These contain a MAN_HEAD and a
322 * MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
323 * scopes, such as `SH' closing out an `SS', are defined in the rew
324 * routines.
325 */
326 int
327 blk_imp(MACRO_PROT_ARGS)
328 {
329 int la;
330 char *p;
331 struct man_node *n;
332
333 /* Close out prior scopes. */
334
335 if ( ! rew_scope(MAN_BODY, man, tok))
336 return(0);
337 if ( ! rew_scope(MAN_BLOCK, man, tok))
338 return(0);
339
340 /* Allocate new block & head scope. */
341
342 if ( ! man_block_alloc(man, line, ppos, tok))
343 return(0);
344 if ( ! man_head_alloc(man, line, ppos, tok))
345 return(0);
346
347 n = man->last;
348
349 /* Add line arguments. */
350
351 for (;;) {
352 la = *pos;
353 if ( ! man_args(man, line, pos, buf, &p))
354 break;
355 if ( ! man_word_alloc(man, line, la, p))
356 return(0);
357 }
358
359 /* Close out head and open body (unless MAN_SCOPE). */
360
361 if (MAN_SCOPED & man_macros[tok].flags) {
362 /* If we're forcing scope (`TP'), keep it open. */
363 if (MAN_FSCOPED & man_macros[tok].flags) {
364 man->flags |= MAN_BLINE;
365 return(1);
366 } else if (n == man->last) {
367 man->flags |= MAN_BLINE;
368 return(1);
369 }
370 }
371
372 if ( ! rew_scope(MAN_HEAD, man, tok))
373 return(0);
374 return(man_body_alloc(man, line, ppos, tok));
375 }
376
377 int
378 in_line_eoln(MACRO_PROT_ARGS)
379 {
380 int la;
381 char *p;
382 struct man_node *n;
383
384 if ( ! man_elem_alloc(man, line, ppos, tok))
385 return(0);
386
387 n = man->last;
388
389 for (;;) {
390 la = *pos;
391 if ( ! man_args(man, line, pos, buf, &p))
392 break;
393 if ( ! man_word_alloc(man, line, la, p))
394 return(0);
395 }
396
397 /*
398 * Append MAN_EOS in case the last snipped argument
399 * ends with a dot, e.g. `.IR syslog (3).'
400 */
401
402 if (n != man->last &&
403 mandoc_eos(man->last->string, strlen(man->last->string)))
404 man->last->flags |= MAN_EOS;
405
406 /*
407 * If no arguments are specified and this is MAN_SCOPED (i.e.,
408 * next-line scoped), then set our mode to indicate that we're
409 * waiting for terms to load into our context.
410 */
411
412 if (n == man->last && MAN_SCOPED & man_macros[tok].flags) {
413 assert( ! (MAN_NSCOPED & man_macros[tok].flags));
414 man->flags |= MAN_ELINE;
415 return(1);
416 }
417
418 /* Set ignorable context, if applicable. */
419
420 if (MAN_NSCOPED & man_macros[tok].flags) {
421 assert( ! (MAN_SCOPED & man_macros[tok].flags));
422 man->flags |= MAN_ILINE;
423 }
424
425 assert(MAN_ROOT != man->last->type);
426 man->next = MAN_NEXT_SIBLING;
427
428 /*
429 * Rewind our element scope. Note that when TH is pruned, we'll
430 * be back at the root, so make sure that we don't clobber as
431 * its sibling.
432 */
433
434 for ( ; man->last; man->last = man->last->parent) {
435 if (man->last == n)
436 break;
437 if (man->last->type == MAN_ROOT)
438 break;
439 if ( ! man_valid_post(man))
440 return(0);
441 }
442
443 assert(man->last);
444
445 /*
446 * Same here regarding whether we're back at the root.
447 */
448
449 if (man->last->type != MAN_ROOT && ! man_valid_post(man))
450 return(0);
451
452 return(1);
453 }
454
455
456 int
457 man_macroend(struct man *man)
458 {
459
460 return(man_unscope(man, man->first));
461 }
462
463 static int
464 man_args(struct man *man, int line, int *pos, char *buf, char **v)
465 {
466 char *start;
467
468 assert(*pos);
469 *v = start = buf + *pos;
470 assert(' ' != *start);
471
472 if ('\0' == *start)
473 return(0);
474
475 *v = mandoc_getarg(man->parse, v, line, pos);
476 return(1);
477 }