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