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