]> git.cameronkatri.com Git - mandoc.git/blob - macro.c
White-space churn.
[mandoc.git] / macro.c
1 /* $Id: macro.c,v 1.55 2009/02/28 20:13:06 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 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
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #ifdef __linux__
25 #include <time.h>
26 #endif
27
28 /*
29 * This has scanning/parsing routines, each of which extract a macro and
30 * its arguments and parameters, then know how to progress to the next
31 * macro.
32 */
33
34 #include "private.h"
35
36 static int macro_obsolete(MACRO_PROT_ARGS);
37 static int macro_constant(MACRO_PROT_ARGS);
38 static int macro_constant_scoped(MACRO_PROT_ARGS);
39 static int macro_constant_delimited(MACRO_PROT_ARGS);
40 static int macro_text(MACRO_PROT_ARGS);
41 static int macro_scoped(MACRO_PROT_ARGS);
42 static int macro_scoped_close(MACRO_PROT_ARGS);
43 static int macro_scoped_line(MACRO_PROT_ARGS);
44
45 #define REWIND_REWIND (1 << 0)
46 #define REWIND_NOHALT (1 << 1)
47 #define REWIND_HALT (1 << 2)
48
49 static int rewind_dohalt(int, enum mdoc_type,
50 const struct mdoc_node *);
51 static int rewind_alt(int);
52 static int rewind_dobreak(int, const struct mdoc_node *);
53 static int rewind_elem(struct mdoc *, int);
54 static int rewind_impblock(struct mdoc *, int, int, int);
55 static int rewind_expblock(struct mdoc *, int, int, int);
56 static int rewind_subblock(enum mdoc_type,
57 struct mdoc *, int, int, int);
58 static int rewind_last(struct mdoc *, struct mdoc_node *);
59 static int append_delims(struct mdoc *, int, int *, char *);
60 static int lookup(struct mdoc *, int, int, int, const char *);
61 static int pwarn(struct mdoc *, int, int, int);
62 static int perr(struct mdoc *, int, int, int);
63
64 #define WMACPARM (1)
65 #define WOBS (2)
66
67 #define ENOCTX (1)
68 #define ENOPARMS (2)
69 #define EARGVLIM (3)
70
71 /* Central table of library: who gets parsed how. */
72
73 const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
74 { NULL, 0 }, /* \" */
75 { macro_constant, MDOC_PROLOGUE }, /* Dd */
76 { macro_constant, MDOC_PROLOGUE }, /* Dt */
77 { macro_constant, MDOC_PROLOGUE }, /* Os */
78 { macro_scoped, 0 }, /* Sh */
79 { macro_scoped, 0 }, /* Ss */
80 { macro_text, 0 }, /* Pp */
81 { macro_scoped_line, MDOC_PARSED }, /* D1 */
82 { macro_scoped_line, MDOC_PARSED }, /* Dl */
83 { macro_scoped, MDOC_EXPLICIT }, /* Bd */
84 { macro_scoped_close, MDOC_EXPLICIT }, /* Ed */
85 { macro_scoped, MDOC_EXPLICIT }, /* Bl */
86 { macro_scoped_close, MDOC_EXPLICIT }, /* El */
87 { macro_scoped, MDOC_PARSED }, /* It */
88 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
89 { macro_text, MDOC_PARSED }, /* An */
90 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
91 { macro_constant, 0 }, /* Cd */
92 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
93 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
94 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
95 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
96 { macro_constant, 0 }, /* Ex */
97 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
98 { macro_constant, 0 }, /* Fd */
99 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
100 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
101 { macro_text, MDOC_PARSED }, /* Ft */
102 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
103 { macro_constant, 0 }, /* In */
104 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
105 { macro_constant, 0 }, /* Nd */
106 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
107 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
108 { macro_obsolete, 0 }, /* Ot */
109 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
110 { macro_constant, 0 }, /* Rv */
111 /* XXX - .St supposed to be (but isn't) callable. */
112 { macro_constant_delimited, MDOC_PARSED }, /* St */
113 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
114 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
115 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
116 { macro_constant, 0 }, /* %A */
117 { macro_constant, 0 }, /* %B */
118 { macro_constant, 0 }, /* %D */
119 { macro_constant, 0 }, /* %I */
120 { macro_constant, 0 }, /* %J */
121 { macro_constant, 0 }, /* %N */
122 { macro_constant, 0 }, /* %O */
123 { macro_constant, 0 }, /* %P */
124 { macro_constant, 0 }, /* %R */
125 { macro_constant, 0 }, /* %T */
126 { macro_constant, 0 }, /* %V */
127 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
128 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
129 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
130 { macro_constant_delimited, 0 }, /* At */
131 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
132 { macro_scoped, MDOC_EXPLICIT }, /* Bf */
133 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
134 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
135 { macro_constant_delimited, MDOC_PARSED }, /* Bsx */
136 { macro_constant_delimited, MDOC_PARSED }, /* Bx */
137 { macro_constant, 0 }, /* Db */
138 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
139 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
140 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
141 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
142 { macro_scoped_close, MDOC_EXPLICIT }, /* Ef */
143 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
144 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
145 { macro_constant_delimited, MDOC_PARSED }, /* Fx */
146 { macro_text, MDOC_PARSED }, /* Ms */
147 { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* No */
148 { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
149 { macro_constant_delimited, MDOC_PARSED }, /* Nx */
150 { macro_constant_delimited, MDOC_PARSED }, /* Ox */
151 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
152 { macro_constant_delimited, MDOC_PARSED }, /* Pf */
153 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
154 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
155 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
156 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
157 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
158 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
159 { macro_scoped_close, MDOC_EXPLICIT }, /* Re */
160 { macro_scoped, MDOC_EXPLICIT }, /* Rs */
161 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
162 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
163 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
164 { macro_constant, 0 }, /* Sm */
165 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
166 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
167 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
168 { macro_constant_delimited, MDOC_PARSED }, /* Ux */
169 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
170 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
171 /* XXX - .Fo supposed to be (but isn't) callable. */
172 { macro_scoped, MDOC_EXPLICIT }, /* Fo */
173 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
174 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
175 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
176 { macro_scoped, MDOC_EXPLICIT }, /* Bk */
177 { macro_scoped_close, MDOC_EXPLICIT }, /* Ek */
178 { macro_constant, 0 }, /* Bt */
179 { macro_constant, 0 }, /* Hf */
180 { macro_obsolete, 0 }, /* Fr */
181 { macro_constant, 0 }, /* Ud */
182 };
183
184 const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
185
186
187 static int
188 perr(struct mdoc *mdoc, int line, int pos, int type)
189 {
190 int c;
191
192 switch (type) {
193 case (ENOCTX):
194 c = mdoc_perr(mdoc, line, pos,
195 "closing macro has prior context");
196 break;
197 case (ENOPARMS):
198 c = mdoc_perr(mdoc, line, pos,
199 "macro doesn't expect parameters");
200 break;
201 case (EARGVLIM):
202 c = mdoc_perr(mdoc, line, pos,
203 "argument hard-limit %d reached",
204 MDOC_LINEARG_MAX);
205 break;
206 default:
207 abort();
208 /* NOTREACHED */
209 }
210 return(c);
211 }
212
213 static int
214 pwarn(struct mdoc *mdoc, int line, int pos, int type)
215 {
216 int c;
217
218 switch (type) {
219 case (WMACPARM):
220 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
221 "macro-like parameter");
222 break;
223 case (WOBS):
224 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
225 "macro is marked obsolete");
226 break;
227 default:
228 abort();
229 /* NOTREACHED */
230 }
231 return(c);
232 }
233
234
235 static int
236 lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p)
237 {
238 int res;
239
240 res = mdoc_find(mdoc, p);
241 if (MDOC_PARSED & mdoc_macros[from].flags)
242 return(res);
243 if (MDOC_MAX == res)
244 return(res);
245 if ( ! pwarn(mdoc, line, pos, WMACPARM))
246 return(-1);
247 return(MDOC_MAX);
248 }
249
250
251 static int
252 rewind_last(struct mdoc *mdoc, struct mdoc_node *to)
253 {
254
255 assert(to);
256 mdoc->next = MDOC_NEXT_SIBLING;
257
258 /* LINTED */
259 while (mdoc->last != to) {
260 if ( ! mdoc_valid_post(mdoc))
261 return(0);
262 if ( ! mdoc_action_post(mdoc))
263 return(0);
264 mdoc->last = mdoc->last->parent;
265 assert(mdoc->last);
266 }
267
268 if ( ! mdoc_valid_post(mdoc))
269 return(0);
270 return(mdoc_action_post(mdoc));
271 }
272
273
274 static int
275 rewind_alt(int tok)
276 {
277 switch (tok) {
278 case (MDOC_Ac):
279 return(MDOC_Ao);
280 case (MDOC_Bc):
281 return(MDOC_Bo);
282 case (MDOC_Dc):
283 return(MDOC_Do);
284 case (MDOC_Ec):
285 return(MDOC_Eo);
286 case (MDOC_Ed):
287 return(MDOC_Bd);
288 case (MDOC_Ef):
289 return(MDOC_Bf);
290 case (MDOC_Ek):
291 return(MDOC_Bk);
292 case (MDOC_El):
293 return(MDOC_Bl);
294 case (MDOC_Fc):
295 return(MDOC_Fo);
296 case (MDOC_Oc):
297 return(MDOC_Oo);
298 case (MDOC_Pc):
299 return(MDOC_Po);
300 case (MDOC_Qc):
301 return(MDOC_Qo);
302 case (MDOC_Re):
303 return(MDOC_Rs);
304 case (MDOC_Sc):
305 return(MDOC_So);
306 case (MDOC_Xc):
307 return(MDOC_Xo);
308 default:
309 break;
310 }
311 abort();
312 /* NOTREACHED */
313 }
314
315
316 static int
317 rewind_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
318 {
319
320 if (MDOC_ROOT == p->type)
321 return(REWIND_HALT);
322 if (MDOC_VALID & p->flags)
323 return(REWIND_NOHALT);
324
325 switch (tok) {
326 /* One-liner implicit-scope. */
327 case (MDOC_Aq):
328 /* FALLTHROUGH */
329 case (MDOC_Bq):
330 /* FALLTHROUGH */
331 case (MDOC_D1):
332 /* FALLTHROUGH */
333 case (MDOC_Dl):
334 /* FALLTHROUGH */
335 case (MDOC_Dq):
336 /* FALLTHROUGH */
337 case (MDOC_Op):
338 /* FALLTHROUGH */
339 case (MDOC_Pq):
340 /* FALLTHROUGH */
341 case (MDOC_Ql):
342 /* FALLTHROUGH */
343 case (MDOC_Qq):
344 /* FALLTHROUGH */
345 case (MDOC_Sq):
346 assert(MDOC_HEAD != type);
347 assert(MDOC_TAIL != type);
348 if (type == p->type && tok == p->tok)
349 return(REWIND_REWIND);
350 break;
351
352 /* Multi-line implicit-scope. */
353 case (MDOC_It):
354 assert(MDOC_TAIL != type);
355 if (type == p->type && tok == p->tok)
356 return(REWIND_REWIND);
357 if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
358 return(REWIND_HALT);
359 break;
360 case (MDOC_Sh):
361 if (type == p->type && tok == p->tok)
362 return(REWIND_REWIND);
363 break;
364 case (MDOC_Ss):
365 assert(MDOC_TAIL != type);
366 if (type == p->type && tok == p->tok)
367 return(REWIND_REWIND);
368 if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
369 return(REWIND_HALT);
370 break;
371
372 /* Multi-line explicit scope start. */
373 case (MDOC_Ao):
374 /* FALLTHROUGH */
375 case (MDOC_Bd):
376 /* FALLTHROUGH */
377 case (MDOC_Bf):
378 /* FALLTHROUGH */
379 case (MDOC_Bk):
380 /* FALLTHROUGH */
381 case (MDOC_Bl):
382 /* FALLTHROUGH */
383 case (MDOC_Bo):
384 /* FALLTHROUGH */
385 case (MDOC_Do):
386 /* FALLTHROUGH */
387 case (MDOC_Eo):
388 /* FALLTHROUGH */
389 case (MDOC_Fo):
390 /* FALLTHROUGH */
391 case (MDOC_Oo):
392 /* FALLTHROUGH */
393 case (MDOC_Po):
394 /* FALLTHROUGH */
395 case (MDOC_Qo):
396 /* FALLTHROUGH */
397 case (MDOC_Rs):
398 /* FALLTHROUGH */
399 case (MDOC_So):
400 /* FALLTHROUGH */
401 case (MDOC_Xo):
402 if (type == p->type && tok == p->tok)
403 return(REWIND_REWIND);
404 break;
405
406 /* Multi-line explicit scope close. */
407 case (MDOC_Ac):
408 /* FALLTHROUGH */
409 case (MDOC_Bc):
410 /* FALLTHROUGH */
411 case (MDOC_Dc):
412 /* FALLTHROUGH */
413 case (MDOC_Ec):
414 /* FALLTHROUGH */
415 case (MDOC_Ed):
416 /* FALLTHROUGH */
417 case (MDOC_Ek):
418 /* FALLTHROUGH */
419 case (MDOC_El):
420 /* FALLTHROUGH */
421 case (MDOC_Fc):
422 /* FALLTHROUGH */
423 case (MDOC_Ef):
424 /* FALLTHROUGH */
425 case (MDOC_Oc):
426 /* FALLTHROUGH */
427 case (MDOC_Pc):
428 /* FALLTHROUGH */
429 case (MDOC_Qc):
430 /* FALLTHROUGH */
431 case (MDOC_Re):
432 /* FALLTHROUGH */
433 case (MDOC_Sc):
434 /* FALLTHROUGH */
435 case (MDOC_Xc):
436 if (type == p->type && rewind_alt(tok) == p->tok)
437 return(REWIND_REWIND);
438 break;
439 default:
440 abort();
441 /* NOTREACHED */
442 }
443
444 return(REWIND_NOHALT);
445 }
446
447
448 static int
449 rewind_dobreak(int tok, const struct mdoc_node *p)
450 {
451
452 assert(MDOC_ROOT != p->type);
453 if (MDOC_ELEM == p->type)
454 return(1);
455 if (MDOC_TEXT == p->type)
456 return(1);
457 if (MDOC_VALID & p->flags)
458 return(1);
459
460 switch (tok) {
461 /* Implicit rules. */
462 case (MDOC_It):
463 return(MDOC_It == p->tok);
464 case (MDOC_Ss):
465 return(MDOC_Ss == p->tok);
466 case (MDOC_Sh):
467 if (MDOC_Ss == p->tok)
468 return(1);
469 return(MDOC_Sh == p->tok);
470
471 /* Extra scope rules. */
472 case (MDOC_El):
473 if (MDOC_It == p->tok)
474 return(1);
475 break;
476 default:
477 break;
478 }
479
480 if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
481 return(p->tok == rewind_alt(tok));
482 else if (MDOC_BLOCK == p->type)
483 return(1);
484
485 return(tok == p->tok);
486 }
487
488
489 static int
490 rewind_elem(struct mdoc *mdoc, int tok)
491 {
492 struct mdoc_node *n;
493
494 n = mdoc->last;
495 if (MDOC_ELEM != n->type)
496 n = n->parent;
497 assert(MDOC_ELEM == n->type);
498 assert(tok == n->tok);
499
500 return(rewind_last(mdoc, n));
501 }
502
503
504 static int
505 rewind_subblock(enum mdoc_type type, struct mdoc *mdoc,
506 int tok, int line, int ppos)
507 {
508 struct mdoc_node *n;
509 int c;
510
511 /* LINTED */
512 for (n = mdoc->last; n; n = n->parent) {
513 c = rewind_dohalt(tok, type, n);
514 if (REWIND_HALT == c)
515 return(1);
516 if (REWIND_REWIND == c)
517 break;
518 else if (rewind_dobreak(tok, n))
519 continue;
520 return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
521 }
522
523 assert(n);
524 return(rewind_last(mdoc, n));
525 }
526
527
528 static int
529 rewind_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
530 {
531 struct mdoc_node *n;
532 int c;
533
534 /* LINTED */
535 for (n = mdoc->last; n; n = n->parent) {
536 c = rewind_dohalt(tok, MDOC_BLOCK, n);
537 if (REWIND_HALT == c)
538 return(perr(mdoc, line, ppos, ENOCTX));
539 if (REWIND_REWIND == c)
540 break;
541 else if (rewind_dobreak(tok, n))
542 continue;
543 return(mdoc_perr(mdoc, line, ppos,
544 "scope breaks prior %s",
545 mdoc_node2a(n)));
546 }
547
548 assert(n);
549 return(rewind_last(mdoc, n));
550 }
551
552
553 static int
554 rewind_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
555 {
556 struct mdoc_node *n;
557 int c;
558
559 /* LINTED */
560 for (n = mdoc->last; n; n = n->parent) {
561 c = rewind_dohalt(tok, MDOC_BLOCK, n);
562 if (REWIND_HALT == c)
563 return(1);
564 else if (REWIND_REWIND == c)
565 break;
566 else if (rewind_dobreak(tok, n))
567 continue;
568 return(mdoc_perr(mdoc, line, ppos,
569 "scope breaks prior %s",
570 mdoc_node2a(n)));
571 }
572
573 assert(n);
574 return(rewind_last(mdoc, n));
575 }
576
577
578 static int
579 append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
580 {
581 int c, lastarg;
582 char *p;
583
584 if (0 == buf[*pos])
585 return(1);
586
587 for (;;) {
588 lastarg = *pos;
589 c = mdoc_args(mdoc, line, pos, buf, 0, &p);
590 assert(ARGS_PHRASE != c);
591
592 if (ARGS_ERROR == c)
593 return(0);
594 else if (ARGS_EOLN == c)
595 break;
596 assert(mdoc_isdelim(p));
597 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
598 return(0);
599 mdoc->next = MDOC_NEXT_SIBLING;
600 }
601
602 return(1);
603 }
604
605
606 /*
607 * Close out an explicit scope. This optionally parses a TAIL type with
608 * a set number of TEXT children.
609 */
610 static int
611 macro_scoped_close(MACRO_PROT_ARGS)
612 {
613 int tt, j, c, lastarg, maxargs, flushed;
614 char *p;
615
616 switch (tok) {
617 case (MDOC_Ec):
618 maxargs = 1;
619 break;
620 default:
621 maxargs = 0;
622 break;
623 }
624
625 tt = rewind_alt(tok);
626
627 mdoc_msg(mdoc, "parse: %s closing %s",
628 mdoc_macronames[tok], mdoc_macronames[tt]);
629
630 if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
631 if (0 == buf[*pos]) {
632 if ( ! rewind_subblock(MDOC_BODY, mdoc,
633 tok, line, ppos))
634 return(0);
635 return(rewind_expblock(mdoc, tok, line, ppos));
636 }
637 return(perr(mdoc, line, ppos, ENOPARMS));
638 }
639
640 if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
641 return(0);
642
643 lastarg = ppos;
644 flushed = 0;
645
646 if (maxargs > 0) {
647 if ( ! mdoc_tail_alloc(mdoc, line, ppos, tt))
648 return(0);
649 mdoc->next = MDOC_NEXT_CHILD;
650 }
651
652 for (j = 0; /* No sentinel. */; j++) {
653 lastarg = *pos;
654
655 if (j == maxargs && ! flushed) {
656 if ( ! rewind_expblock(mdoc, tok, line, ppos))
657 return(0);
658 flushed = 1;
659 }
660
661 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
662 assert(ARGS_PHRASE != c);
663
664 if (ARGS_ERROR == c)
665 return(0);
666 if (ARGS_PUNCT == c)
667 break;
668 if (ARGS_EOLN == c)
669 break;
670
671 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
672 return(0);
673 else if (MDOC_MAX != c) {
674 if ( ! flushed) {
675 if ( ! rewind_expblock(mdoc, tok,
676 line, ppos))
677 return(0);
678 flushed = 1;
679 }
680 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
681 return(0);
682 break;
683 }
684
685 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
686 return(0);
687 mdoc->next = MDOC_NEXT_SIBLING;
688 }
689
690 if ( ! flushed && ! rewind_expblock(mdoc, tok, line, ppos))
691 return(0);
692
693 if (ppos > 1)
694 return(1);
695 return(append_delims(mdoc, line, pos, buf));
696 }
697
698
699 /*
700 * A general text macro. This is a complex case because of punctuation.
701 * If a text macro is followed by words, then punctuation, the macro is
702 * "stopped" and "reopened" following the punctuation. Thus, the
703 * following arises:
704 *
705 * .Fl a ; b
706 *
707 * ELEMENT (.Fl)
708 * TEXT (`a')
709 * TEXT (`;')
710 * ELEMENT (.Fl)
711 * TEXT (`b')
712 *
713 * This must handle the following situations:
714 *
715 * .Fl Ar b ; ;
716 *
717 * ELEMENT (.Fl)
718 * ELEMENT (.Ar)
719 * TEXT (`b')
720 * TEXT (`;')
721 * TEXT (`;')
722 */
723 static int
724 macro_text(MACRO_PROT_ARGS)
725 {
726 int la, lastpunct, c, w, argc;
727 struct mdoc_arg argv[MDOC_LINEARG_MAX];
728 char *p;
729
730 la = ppos;
731 lastpunct = 0;
732
733 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
734 la = *pos;
735 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
736 if (ARGV_EOLN == c)
737 break;
738 if (ARGV_WORD == c) {
739 *pos = la;
740 break;
741 } else if (ARGV_ARG == c)
742 continue;
743
744 mdoc_argv_free(argc, argv);
745 return(0);
746 }
747
748 if (MDOC_LINEARG_MAX == argc) {
749 mdoc_argv_free(argc - 1, argv);
750 return(perr(mdoc, line, ppos, EARGVLIM));
751 }
752
753 c = mdoc_elem_alloc(mdoc, line, ppos,
754 tok, (size_t)argc, argv);
755
756 if (0 == c) {
757 mdoc_argv_free(argc, argv);
758 return(0);
759 }
760
761 mdoc->next = MDOC_NEXT_CHILD;
762
763 lastpunct = 0;
764 for (;;) {
765 la = *pos;
766 w = mdoc_args(mdoc, line, pos, buf, tok, &p);
767 assert(ARGS_PHRASE != c);
768
769 if (ARGS_ERROR == w) {
770 mdoc_argv_free(argc, argv);
771 return(0);
772 }
773
774 if (ARGS_EOLN == w)
775 break;
776 if (ARGS_PUNCT == w)
777 break;
778
779 c = ARGS_QWORD == w ? MDOC_MAX :
780 lookup(mdoc, line, la, tok, p);
781
782 if (MDOC_MAX != c && -1 != c) {
783 if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
784 mdoc_argv_free(argc, argv);
785 return(0);
786 }
787 mdoc_argv_free(argc, argv);
788 c = mdoc_macro(mdoc, c, line, la, pos, buf);
789 if (0 == c)
790 return(0);
791 if (ppos > 1)
792 return(1);
793 return(append_delims(mdoc, line, pos, buf));
794 } else if (-1 == c) {
795 mdoc_argv_free(argc, argv);
796 return(0);
797 }
798
799 /* FIXME: .Fl and .Ar handling of `|'. */
800
801 if (ARGS_QWORD != w && mdoc_isdelim(p)) {
802 if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
803 mdoc_argv_free(argc, argv);
804 return(0);
805 }
806 lastpunct = 1;
807 } else if (lastpunct) {
808 c = mdoc_elem_alloc(mdoc, line, ppos,
809 tok, (size_t)argc, argv);
810 if (0 == c) {
811 mdoc_argv_free(argc, argv);
812 return(0);
813 }
814 mdoc->next = MDOC_NEXT_CHILD;
815 lastpunct = 0;
816 }
817
818 if ( ! mdoc_word_alloc(mdoc, line, la, p))
819 return(0);
820 mdoc->next = MDOC_NEXT_SIBLING;
821 }
822
823 mdoc_argv_free(argc, argv);
824
825 if (0 == lastpunct && ! rewind_elem(mdoc, tok))
826 return(0);
827 if (ppos > 1)
828 return(1);
829 return(append_delims(mdoc, line, pos, buf));
830 }
831
832
833 /*
834 * Handle explicit-scope (having a different closure token) and implicit
835 * scope (closing out prior scopes when re-invoked) macros. These
836 * constitute the BLOCK type and usually span multiple lines. These
837 * always have HEAD and sometimes have BODY types. In the multi-line
838 * case:
839 *
840 * .Bd -ragged
841 * Text.
842 * .Fl macro
843 * Another.
844 * .Ed
845 *
846 * BLOCK (.Bd)
847 * HEAD
848 * BODY
849 * TEXT (`Text.')
850 * ELEMENT (.Fl)
851 * TEXT (`macro')
852 * TEXT (`Another.')
853 *
854 * Note that the `.It' macro, possibly the most difficult (as it has
855 * embedded scope, etc.) is handled by this routine.
856 */
857 static int
858 macro_scoped(MACRO_PROT_ARGS)
859 {
860 int c, lastarg, argc;
861 struct mdoc_arg argv[MDOC_LINEARG_MAX];
862 char *p;
863
864 assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
865
866 /* First rewind extant implicit scope. */
867
868 if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
869 if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
870 return(0);
871 if ( ! rewind_impblock(mdoc, tok, line, ppos))
872 return(0);
873 }
874
875 /* Parse arguments. */
876
877 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
878 lastarg = *pos;
879 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
880 if (ARGV_EOLN == c)
881 break;
882 if (ARGV_WORD == c) {
883 *pos = lastarg;
884 break;
885 } else if (ARGV_ARG == c)
886 continue;
887 mdoc_argv_free(argc, argv);
888 return(0);
889 }
890
891 if (MDOC_LINEARG_MAX == argc) {
892 mdoc_argv_free(argc - 1, argv);
893 return(perr(mdoc, line, ppos, EARGVLIM));
894 }
895
896 c = mdoc_block_alloc(mdoc, line, ppos,
897 tok, (size_t)argc, argv);
898 mdoc_argv_free(argc, argv);
899
900 if (0 == c)
901 return(0);
902
903 mdoc->next = MDOC_NEXT_CHILD;
904
905 if (0 == buf[*pos]) {
906 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
907 return(0);
908 if ( ! rewind_subblock(MDOC_HEAD, mdoc,
909 tok, line, ppos))
910 return(0);
911 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
912 return(0);
913 mdoc->next = MDOC_NEXT_CHILD;
914 return(1);
915 }
916
917 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
918 return(0);
919 mdoc->next = MDOC_NEXT_CHILD;
920
921 for (;;) {
922 lastarg = *pos;
923 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
924
925 if (ARGS_ERROR == c)
926 return(0);
927 if (ARGS_EOLN == c)
928 break;
929 if (ARGS_PHRASE == c) {
930 /*
931 if ( ! mdoc_phrase(mdoc, line, lastarg, buf))
932 return(0);
933 */
934 continue;
935 }
936
937 /* FIXME: if .It -column, the lookup must be for a
938 * sub-line component. BLAH. */
939
940 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
941 return(0);
942
943 if (MDOC_MAX == c) {
944 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
945 return(0);
946 mdoc->next = MDOC_NEXT_SIBLING;
947 continue;
948 }
949
950 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
951 return(0);
952 break;
953 }
954
955 if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
956 return(0);
957 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
958 return(0);
959
960 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
961 return(0);
962 mdoc->next = MDOC_NEXT_CHILD;
963
964 return(1);
965 }
966
967
968 /*
969 * This handles a case of implicitly-scoped macro (BLOCK) limited to a
970 * single line. Instead of being closed out by a subsequent call to
971 * another macro, the scope is closed at the end of line. These don't
972 * have BODY or TAIL types. Notice that the punctuation falls outside
973 * of the HEAD type.
974 *
975 * .Qq a Fl b Ar d ; ;
976 *
977 * BLOCK (Qq)
978 * HEAD
979 * TEXT (`a')
980 * ELEMENT (.Fl)
981 * TEXT (`b')
982 * ELEMENT (.Ar)
983 * TEXT (`d')
984 * TEXT (`;')
985 * TEXT (`;')
986 */
987 static int
988 macro_scoped_line(MACRO_PROT_ARGS)
989 {
990 int lastarg, c;
991 char *p;
992
993 if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
994 return(0);
995 mdoc->next = MDOC_NEXT_CHILD;
996
997 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
998 return(0);
999 mdoc->next = MDOC_NEXT_SIBLING;
1000 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1001 return(0);
1002 mdoc->next = MDOC_NEXT_CHILD;
1003
1004 /* XXX - no known argument macros. */
1005
1006 lastarg = ppos;
1007 for (;;) {
1008 lastarg = *pos;
1009 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1010 assert(ARGS_PHRASE != c);
1011
1012 if (ARGS_ERROR == c)
1013 return(0);
1014 if (ARGS_PUNCT == c)
1015 break;
1016 if (ARGS_EOLN == c)
1017 break;
1018
1019 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1020 return(0);
1021 else if (MDOC_MAX == c) {
1022 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1023 return(0);
1024 mdoc->next = MDOC_NEXT_SIBLING;
1025 continue;
1026 }
1027
1028 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1029 return(0);
1030 break;
1031 }
1032
1033 if (1 == ppos) {
1034 if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1035 return(0);
1036 if ( ! append_delims(mdoc, line, pos, buf))
1037 return(0);
1038 } else if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1039 return(0);
1040 return(rewind_impblock(mdoc, tok, line, ppos));
1041 }
1042
1043
1044 /*
1045 * A constant-scoped macro is like a simple-scoped macro (mdoc_scoped)
1046 * except that it doesn't handle implicit scopes and explicit ones have
1047 * a fixed number of TEXT children to the BODY.
1048 *
1049 * .Fl a So b Sc ;
1050 *
1051 * ELEMENT (.Fl)
1052 * TEXT (`a')
1053 * BLOCK (.So)
1054 * HEAD
1055 * BODY
1056 * TEXT (`b')
1057 * TEXT (';')
1058 */
1059 static int
1060 macro_constant_scoped(MACRO_PROT_ARGS)
1061 {
1062 int lastarg, flushed, j, c, maxargs;
1063 char *p;
1064
1065 lastarg = ppos;
1066 flushed = 0;
1067
1068 switch (tok) {
1069 case (MDOC_Eo):
1070 maxargs = 1;
1071 break;
1072 default:
1073 maxargs = 0;
1074 break;
1075 }
1076
1077 if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
1078 return(0);
1079 mdoc->next = MDOC_NEXT_CHILD;
1080
1081 if (0 == maxargs) {
1082 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1083 return(0);
1084 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1085 return(0);
1086 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1087 return(0);
1088 flushed = 1;
1089 } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1090 return(0);
1091
1092 mdoc->next = MDOC_NEXT_CHILD;
1093
1094 for (j = 0; /* No sentinel. */; j++) {
1095 lastarg = *pos;
1096
1097 if (j == maxargs && ! flushed) {
1098 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1099 return(0);
1100 flushed = 1;
1101 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1102 return(0);
1103 mdoc->next = MDOC_NEXT_CHILD;
1104 }
1105
1106 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1107 assert(ARGS_PHRASE != c);
1108
1109 if (ARGS_ERROR == c)
1110 return(0);
1111 if (ARGS_PUNCT == c)
1112 break;
1113 if (ARGS_EOLN == c)
1114 break;
1115
1116 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1117 return(0);
1118 else if (MDOC_MAX != c) {
1119 if ( ! flushed) {
1120 if ( ! rewind_subblock(MDOC_HEAD, mdoc,
1121 tok, line, ppos))
1122 return(0);
1123 flushed = 1;
1124 if ( ! mdoc_body_alloc(mdoc, line,
1125 ppos, tok))
1126 return(0);
1127 mdoc->next = MDOC_NEXT_CHILD;
1128 }
1129 if ( ! mdoc_macro(mdoc, c, line, lastarg,
1130 pos, buf))
1131 return(0);
1132 break;
1133 }
1134
1135 if ( ! flushed && mdoc_isdelim(p)) {
1136 if ( ! rewind_subblock(MDOC_HEAD, mdoc,
1137 tok, line, ppos))
1138 return(0);
1139 flushed = 1;
1140 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1141 return(0);
1142 mdoc->next = MDOC_NEXT_CHILD;
1143 }
1144
1145 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1146 return(0);
1147 mdoc->next = MDOC_NEXT_SIBLING;
1148 }
1149
1150 if ( ! flushed) {
1151 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1152 return(0);
1153 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1154 return(0);
1155 mdoc->next = MDOC_NEXT_CHILD;
1156 }
1157
1158 if (ppos > 1)
1159 return(1);
1160 return(append_delims(mdoc, line, pos, buf));
1161 }
1162
1163
1164 /*
1165 * A delimited constant is very similar to the macros parsed by
1166 * macro_text except that, in the event of punctuation, the macro isn't
1167 * "re-opened" as it is in macro_text. Also, these macros have a fixed
1168 * number of parameters.
1169 *
1170 * .Fl a No b
1171 *
1172 * ELEMENT (.Fl)
1173 * TEXT (`a')
1174 * ELEMENT (.No)
1175 * TEXT (`b')
1176 */
1177 static int
1178 macro_constant_delimited(MACRO_PROT_ARGS)
1179 {
1180 int lastarg, flushed, j, c, maxargs, argc,
1181 igndelim;
1182 struct mdoc_arg argv[MDOC_LINEARG_MAX];
1183 char *p;
1184
1185 lastarg = ppos;
1186 flushed = 0;
1187
1188 switch (tok) {
1189 case (MDOC_No):
1190 /* FALLTHROUGH */
1191 case (MDOC_Ns):
1192 /* FALLTHROUGH */
1193 case (MDOC_Ux):
1194 /* FALLTHROUGH */
1195 case (MDOC_St):
1196 maxargs = 0;
1197 break;
1198 default:
1199 maxargs = 1;
1200 break;
1201 }
1202
1203 switch (tok) {
1204 case (MDOC_Pf):
1205 igndelim = 1;
1206 break;
1207 default:
1208 igndelim = 0;
1209 break;
1210 }
1211
1212 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1213 lastarg = *pos;
1214 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1215 if (ARGV_EOLN == c)
1216 break;
1217 if (ARGV_WORD == c) {
1218 *pos = lastarg;
1219 break;
1220 } else if (ARGV_ARG == c)
1221 continue;
1222 mdoc_argv_free(argc, argv);
1223 return(0);
1224 }
1225
1226 if (MDOC_LINEARG_MAX == argc) {
1227 mdoc_argv_free(argc - 1, argv);
1228 return(perr(mdoc, line, ppos, EARGVLIM));
1229 }
1230
1231 c = mdoc_elem_alloc(mdoc, line, ppos,
1232 tok, (size_t)argc, argv);
1233
1234 mdoc_argv_free(argc, argv);
1235
1236 if (0 == c)
1237 return(0);
1238
1239 mdoc->next = MDOC_NEXT_CHILD;
1240
1241 for (j = 0; /* No sentinel. */; j++) {
1242 lastarg = *pos;
1243
1244 if (j == maxargs && ! flushed) {
1245 if ( ! rewind_elem(mdoc, tok))
1246 return(0);
1247 flushed = 1;
1248 }
1249
1250 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1251 assert(ARGS_PHRASE != c);
1252
1253 if (ARGS_ERROR == c)
1254 return(0);
1255 if (ARGS_PUNCT == c)
1256 break;
1257 if (ARGS_EOLN == c)
1258 break;
1259
1260 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1261 return(0);
1262 else if (MDOC_MAX != c) {
1263 if ( ! flushed && ! rewind_elem(mdoc, tok))
1264 return(0);
1265 flushed = 1;
1266 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1267 return(0);
1268 break;
1269 }
1270
1271 if ( ! flushed && mdoc_isdelim(p) && ! igndelim) {
1272 if ( ! rewind_elem(mdoc, tok))
1273 return(0);
1274 flushed = 1;
1275 }
1276
1277 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1278 return(0);
1279 mdoc->next = MDOC_NEXT_SIBLING;
1280 }
1281
1282 if ( ! flushed && ! rewind_elem(mdoc, tok))
1283 return(0);
1284
1285 if (ppos > 1)
1286 return(1);
1287 return(append_delims(mdoc, line, pos, buf));
1288 }
1289
1290
1291 /*
1292 * A constant macro is the simplest classification. It spans an entire
1293 * line.
1294 */
1295 static int
1296 macro_constant(MACRO_PROT_ARGS)
1297 {
1298 int c, w, la, argc;
1299 struct mdoc_arg argv[MDOC_LINEARG_MAX];
1300 char *p;
1301
1302 assert( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1303
1304 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1305 la = *pos;
1306 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1307 if (ARGV_EOLN == c)
1308 break;
1309 if (ARGV_WORD == c) {
1310 *pos = la;
1311 break;
1312 } else if (ARGV_ARG == c)
1313 continue;
1314
1315 mdoc_argv_free(argc, argv);
1316 return(0);
1317 }
1318
1319 if (MDOC_LINEARG_MAX == argc) {
1320 mdoc_argv_free(argc - 1, argv);
1321 return(perr(mdoc, line, ppos, EARGVLIM));
1322 }
1323
1324 c = mdoc_elem_alloc(mdoc, line, ppos,
1325 tok, (size_t)argc, argv);
1326
1327 mdoc_argv_free(argc, argv);
1328
1329 if (0 == c)
1330 return(0);
1331
1332 mdoc->next = MDOC_NEXT_CHILD;
1333
1334 for (;;) {
1335 la = *pos;
1336 w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1337 assert(ARGS_PHRASE != c);
1338
1339 if (ARGS_ERROR == w)
1340 return(0);
1341 if (ARGS_EOLN == w)
1342 break;
1343
1344 c = ARGS_QWORD == w ? MDOC_MAX :
1345 lookup(mdoc, line, la, tok, p);
1346
1347 if (MDOC_MAX != c && -1 != c) {
1348 if ( ! rewind_elem(mdoc, tok))
1349 return(0);
1350 return(mdoc_macro(mdoc, c, line, la, pos, buf));
1351 } else if (-1 == c)
1352 return(0);
1353
1354 if ( ! mdoc_word_alloc(mdoc, line, la, p))
1355 return(0);
1356 mdoc->next = MDOC_NEXT_SIBLING;
1357 }
1358
1359 return(rewind_elem(mdoc, tok));
1360 }
1361
1362
1363 /* ARGSUSED */
1364 static int
1365 macro_obsolete(MACRO_PROT_ARGS)
1366 {
1367
1368 return(pwarn(mdoc, line, ppos, WOBS));
1369 }
1370
1371
1372 /*
1373 * This is called at the end of parsing. It must traverse up the tree,
1374 * closing out open [implicit] scopes. Obviously, open explicit scopes
1375 * are errors.
1376 */
1377 int
1378 macro_end(struct mdoc *mdoc)
1379 {
1380 struct mdoc_node *n;
1381
1382 assert(mdoc->first);
1383 assert(mdoc->last);
1384
1385 /* Scan for open explicit scopes. */
1386
1387 n = MDOC_VALID & mdoc->last->flags ?
1388 mdoc->last->parent : mdoc->last;
1389
1390 for ( ; n; n = n->parent) {
1391 if (MDOC_BLOCK != n->type)
1392 continue;
1393 if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
1394 continue;
1395 return(mdoc_nerr(mdoc, n,
1396 "macro scope still open on exit"));
1397 }
1398
1399 return(rewind_last(mdoc, mdoc->first));
1400 }