]> git.cameronkatri.com Git - mandoc.git/blob - macro.c
More correct validation.
[mandoc.git] / macro.c
1 /* $Id: macro.c,v 1.43 2009/01/19 17:51:32 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 #include "private.h"
29
30 /* FIXME: maxlineargs should be per LINE, no per TOKEN. */
31
32 static int rewind_alt(int);
33 static int rewind_dohalt(int, enum mdoc_type,
34 const struct mdoc_node *);
35 #define REWIND_REWIND (1 << 0)
36 #define REWIND_NOHALT (1 << 1)
37 #define REWIND_HALT (1 << 2)
38 static int rewind_dobreak(int, const struct mdoc_node *);
39
40
41 static int rewind_elem(struct mdoc *, int);
42 static int rewind_impblock(struct mdoc *, int, int, int);
43 static int rewind_expblock(struct mdoc *, int, int, int);
44 static int rewind_subblock(enum mdoc_type,
45 struct mdoc *, int, int, int);
46 static int rewind_last(struct mdoc *, struct mdoc_node *);
47 static int append_delims(struct mdoc *, int, int *, char *);
48 static int lookup(struct mdoc *, int, int, int, const char *);
49
50
51 static int
52 lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p)
53 {
54 int res;
55
56 res = mdoc_find(mdoc, p);
57 if (MDOC_PARSED & mdoc_macros[from].flags)
58 return(res);
59 if (MDOC_MAX == res)
60 return(res);
61 if ( ! mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, "macro-like parameter"))
62 return(-1);
63 return(MDOC_MAX);
64 }
65
66
67 static int
68 rewind_last(struct mdoc *mdoc, struct mdoc_node *to)
69 {
70
71 assert(to);
72 mdoc->next = MDOC_NEXT_SIBLING;
73
74 while (mdoc->last != to) {
75 if ( ! mdoc_valid_post(mdoc))
76 return(0);
77 if ( ! mdoc_action_post(mdoc))
78 return(0);
79 mdoc->last = mdoc->last->parent;
80 assert(mdoc->last);
81 }
82
83 if ( ! mdoc_valid_post(mdoc))
84 return(0);
85 return(mdoc_action_post(mdoc));
86 }
87
88
89 static int
90 rewind_alt(int tok)
91 {
92 switch (tok) {
93 case (MDOC_Ac):
94 return(MDOC_Ao);
95 case (MDOC_Bc):
96 return(MDOC_Bo);
97 case (MDOC_Dc):
98 return(MDOC_Do);
99 case (MDOC_Ec):
100 return(MDOC_Eo);
101 case (MDOC_Ed):
102 return(MDOC_Bd);
103 case (MDOC_Ef):
104 return(MDOC_Bf);
105 case (MDOC_Ek):
106 return(MDOC_Bk);
107 case (MDOC_El):
108 return(MDOC_Bl);
109 case (MDOC_Fc):
110 return(MDOC_Fo);
111 case (MDOC_Oc):
112 return(MDOC_Oo);
113 case (MDOC_Pc):
114 return(MDOC_Po);
115 case (MDOC_Qc):
116 return(MDOC_Qo);
117 case (MDOC_Re):
118 return(MDOC_Rs);
119 case (MDOC_Sc):
120 return(MDOC_So);
121 case (MDOC_Xc):
122 return(MDOC_Xo);
123 default:
124 break;
125 }
126 abort();
127 /* NOTREACHED */
128 }
129
130
131 static int
132 rewind_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
133 {
134
135 if (MDOC_ROOT == p->type)
136 return(REWIND_HALT);
137 if (MDOC_VALID & p->flags)
138 return(REWIND_NOHALT);
139
140 switch (tok) {
141 /* One-liner implicit-scope. */
142 case (MDOC_Aq):
143 /* FALLTHROUGH */
144 case (MDOC_Bq):
145 /* FALLTHROUGH */
146 case (MDOC_D1):
147 /* FALLTHROUGH */
148 case (MDOC_Dl):
149 /* FALLTHROUGH */
150 case (MDOC_Dq):
151 /* FALLTHROUGH */
152 case (MDOC_Op):
153 /* FALLTHROUGH */
154 case (MDOC_Pq):
155 /* FALLTHROUGH */
156 case (MDOC_Ql):
157 /* FALLTHROUGH */
158 case (MDOC_Qq):
159 /* FALLTHROUGH */
160 case (MDOC_Sq):
161 assert(MDOC_BODY != type);
162 assert(MDOC_TAIL != type);
163 if (type == p->type && tok == p->tok)
164 return(REWIND_REWIND);
165 break;
166
167 /* Multi-line implicit-scope. */
168 case (MDOC_It):
169 assert(MDOC_TAIL != type);
170 if (type == p->type && tok == p->tok)
171 return(REWIND_REWIND);
172 if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
173 return(REWIND_HALT);
174 break;
175 case (MDOC_Sh):
176 if (type == p->type && tok == p->tok)
177 return(REWIND_REWIND);
178 break;
179 case (MDOC_Ss):
180 assert(MDOC_TAIL != type);
181 if (type == p->type && tok == p->tok)
182 return(REWIND_REWIND);
183 if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
184 return(REWIND_HALT);
185 break;
186
187 /* Multi-line explicit scope start. */
188 case (MDOC_Ao):
189 /* FALLTHROUGH */
190 case (MDOC_Bd):
191 /* FALLTHROUGH */
192 case (MDOC_Bf):
193 /* FALLTHROUGH */
194 case (MDOC_Bk):
195 /* FALLTHROUGH */
196 case (MDOC_Bl):
197 /* FALLTHROUGH */
198 case (MDOC_Bo):
199 /* FALLTHROUGH */
200 case (MDOC_Do):
201 /* FALLTHROUGH */
202 case (MDOC_Eo):
203 /* FALLTHROUGH */
204 case (MDOC_Fo):
205 /* FALLTHROUGH */
206 case (MDOC_Oo):
207 /* FALLTHROUGH */
208 case (MDOC_Po):
209 /* FALLTHROUGH */
210 case (MDOC_Qo):
211 /* FALLTHROUGH */
212 case (MDOC_Rs):
213 /* FALLTHROUGH */
214 case (MDOC_So):
215 /* FALLTHROUGH */
216 case (MDOC_Xo):
217 if (type == p->type && tok == p->tok)
218 return(REWIND_REWIND);
219 break;
220
221 /* Multi-line explicit scope close. */
222 case (MDOC_Ac):
223 /* FALLTHROUGH */
224 case (MDOC_Bc):
225 /* FALLTHROUGH */
226 case (MDOC_Dc):
227 /* FALLTHROUGH */
228 case (MDOC_Ec):
229 /* FALLTHROUGH */
230 case (MDOC_Ed):
231 /* FALLTHROUGH */
232 case (MDOC_Ek):
233 /* FALLTHROUGH */
234 case (MDOC_El):
235 /* FALLTHROUGH */
236 case (MDOC_Fc):
237 /* FALLTHROUGH */
238 case (MDOC_Ef):
239 /* FALLTHROUGH */
240 case (MDOC_Oc):
241 /* FALLTHROUGH */
242 case (MDOC_Pc):
243 /* FALLTHROUGH */
244 case (MDOC_Qc):
245 /* FALLTHROUGH */
246 case (MDOC_Re):
247 /* FALLTHROUGH */
248 case (MDOC_Sc):
249 /* FALLTHROUGH */
250 case (MDOC_Xc):
251 if (type == p->type && rewind_alt(tok) == p->tok)
252 return(REWIND_REWIND);
253 break;
254 default:
255 abort();
256 /* NOTREACHED */
257 }
258
259 return(REWIND_NOHALT);
260 }
261
262
263 static int
264 rewind_dobreak(int tok, const struct mdoc_node *p)
265 {
266
267 assert(MDOC_ROOT != p->type);
268 if (MDOC_ELEM == p->type)
269 return(1);
270 if (MDOC_TEXT == p->type)
271 return(1);
272 if (MDOC_VALID & p->flags)
273 return(1);
274
275 switch (tok) {
276 /* Implicit rules. */
277 case (MDOC_It):
278 return(MDOC_It == p->tok);
279 case (MDOC_Ss):
280 return(MDOC_Ss == p->tok);
281 case (MDOC_Sh):
282 if (MDOC_Ss == p->tok)
283 return(1);
284 return(MDOC_Sh == p->tok);
285
286 /* Extra scope rules. */
287 case (MDOC_El):
288 if (MDOC_It == p->tok)
289 return(1);
290 break;
291 default:
292 break;
293 }
294
295 if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
296 return(p->tok == rewind_alt(tok));
297 else if (MDOC_BLOCK == p->type)
298 return(1);
299
300 return(tok == p->tok);
301 }
302
303
304 static int
305 rewind_elem(struct mdoc *mdoc, int tok)
306 {
307 struct mdoc_node *n;
308
309 n = mdoc->last;
310 if (MDOC_ELEM != n->type)
311 n = n->parent;
312 assert(MDOC_ELEM == n->type);
313 assert(tok == n->tok);
314
315 return(rewind_last(mdoc, n));
316 }
317
318
319 static int
320 rewind_subblock(enum mdoc_type type, struct mdoc *mdoc,
321 int tok, int line, int ppos)
322 {
323 struct mdoc_node *n;
324 int c;
325
326 /* LINTED */
327 for (n = mdoc->last; n; n = n->parent) {
328 c = rewind_dohalt(tok, type, n);
329 if (REWIND_HALT == c)
330 return(1);
331 if (REWIND_REWIND == c)
332 break;
333 else if (rewind_dobreak(tok, n))
334 continue;
335 return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
336 }
337
338 assert(n);
339 return(rewind_last(mdoc, n));
340 }
341
342
343 static int
344 rewind_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
345 {
346 struct mdoc_node *n;
347 int c;
348
349 /* LINTED */
350 for (n = mdoc->last; n; n = n->parent) {
351 c = rewind_dohalt(tok, MDOC_BLOCK, n);
352 if (REWIND_HALT == c)
353 return(mdoc_perr(mdoc, line, ppos, "closing macro has no context"));
354 if (REWIND_REWIND == c)
355 break;
356 else if (rewind_dobreak(tok, n))
357 continue;
358 return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
359 }
360
361 assert(n);
362 return(rewind_last(mdoc, n));
363 }
364
365
366 static int
367 rewind_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
368 {
369 struct mdoc_node *n;
370 int c;
371
372 /* LINTED */
373 for (n = mdoc->last; n; n = n->parent) {
374 c = rewind_dohalt(tok, MDOC_BLOCK, n);
375 if (REWIND_HALT == c)
376 return(1);
377 else if (REWIND_REWIND == c)
378 break;
379 else if (rewind_dobreak(tok, n))
380 continue;
381 return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
382 }
383
384 assert(n);
385 return(rewind_last(mdoc, n));
386 }
387
388
389 static int
390 append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
391 {
392 int c, lastarg;
393 char *p;
394
395 if (0 == buf[*pos])
396 return(1);
397
398 for (;;) {
399 lastarg = *pos;
400 c = mdoc_args(mdoc, line, pos, buf, 0, &p);
401 if (ARGS_ERROR == c)
402 return(0);
403 else if (ARGS_EOLN == c)
404 break;
405 assert(mdoc_isdelim(p));
406 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
407 return(0);
408 mdoc->next = MDOC_NEXT_SIBLING;
409 }
410
411 return(1);
412 }
413
414
415 int
416 macro_scoped_close(MACRO_PROT_ARGS)
417 {
418 int tt, j, c, lastarg, maxargs, flushed;
419 char *p;
420
421 switch (tok) {
422 case (MDOC_Ec):
423 maxargs = 1;
424 break;
425 default:
426 maxargs = 0;
427 break;
428 }
429
430 tt = rewind_alt(tok);
431
432 mdoc_msg(mdoc, "parse: %s closing %s",
433 mdoc_macronames[tok], mdoc_macronames[tt]);
434
435 if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
436 if (0 == buf[*pos]) {
437 if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
438 return(0);
439 return(rewind_expblock(mdoc, tok, line, ppos));
440 }
441 return(mdoc_perr(mdoc, line, ppos, "macro expects no parameters"));
442 }
443
444 if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
445 return(0);
446
447 lastarg = ppos;
448 flushed = 0;
449
450 if (maxargs > 0) {
451 if ( ! mdoc_tail_alloc(mdoc, line, ppos, tt))
452 return(0);
453 mdoc->next = MDOC_NEXT_CHILD;
454 }
455
456 for (j = 0; /* No sentinel. */; j++) {
457 lastarg = *pos;
458
459 if (j == maxargs && ! flushed) {
460 if ( ! rewind_expblock(mdoc, tok, line, ppos))
461 return(0);
462 flushed = 1;
463 }
464
465 c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
466 if (ARGS_ERROR == c)
467 return(0);
468 if (ARGS_PUNCT == c)
469 break;
470 if (ARGS_EOLN == c)
471 break;
472
473 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
474 return(0);
475 else if (MDOC_MAX != c) {
476 if ( ! flushed) {
477 if ( ! rewind_expblock(mdoc, tok, line, ppos))
478 return(0);
479 flushed = 1;
480 }
481 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
482 return(0);
483 break;
484 }
485
486 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
487 return(0);
488 mdoc->next = MDOC_NEXT_SIBLING;
489 }
490
491 if ( ! flushed && ! rewind_expblock(mdoc, tok, line, ppos))
492 return(0);
493
494 if (ppos > 1)
495 return(1);
496 return(append_delims(mdoc, line, pos, buf));
497 }
498
499
500 int
501 macro_text(MACRO_PROT_ARGS)
502 {
503 int la, lastpunct, c, fl, argc;
504 struct mdoc_arg argv[MDOC_LINEARG_MAX];
505 char *p;
506
507 la = ppos;
508 lastpunct = 0;
509
510 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
511 la = *pos;
512 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
513 if (ARGV_EOLN == c)
514 break;
515 if (ARGV_WORD == c) {
516 *pos = la;
517 break;
518 } else if (ARGV_ARG == c)
519 continue;
520
521 mdoc_argv_free(argc, argv);
522 return(0);
523 }
524
525 if (MDOC_LINEARG_MAX == argc) {
526 mdoc_argv_free(argc - 1, argv);
527 return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
528 }
529
530 c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
531
532 if (0 == c) {
533 mdoc_argv_free(argc, argv);
534 return(0);
535 }
536
537 mdoc->next = MDOC_NEXT_CHILD;
538
539 fl = ARGS_DELIM;
540 if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
541 fl |= ARGS_QUOTED;
542
543 lastpunct = 0;
544 for (;;) {
545 la = *pos;
546 c = mdoc_args(mdoc, line, pos, buf, fl, &p);
547 if (ARGS_ERROR == c) {
548 mdoc_argv_free(argc, argv);
549 return(0);
550 }
551
552 if (ARGS_EOLN == c)
553 break;
554 if (ARGS_PUNCT == c)
555 break;
556
557 if (-1 == (c = lookup(mdoc, line, la, tok, p)))
558 return(0);
559 else if (MDOC_MAX != c) {
560 if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
561 mdoc_argv_free(argc, argv);
562 return(0);
563 }
564 mdoc_argv_free(argc, argv);
565
566 c = mdoc_macro(mdoc, c, line, la, pos, buf);
567 if (0 == c)
568 return(0);
569 if (ppos > 1)
570 return(1);
571 return(append_delims(mdoc, line, pos, buf));
572 }
573
574 if (mdoc_isdelim(p)) {
575 if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
576 mdoc_argv_free(argc, argv);
577 return(0);
578 }
579 lastpunct = 1;
580 } else if (lastpunct) {
581 c = mdoc_elem_alloc(mdoc, line,
582 ppos, tok, argc, argv);
583 if (0 == c) {
584 mdoc_argv_free(argc, argv);
585 return(0);
586 }
587 mdoc->next = MDOC_NEXT_CHILD;
588 lastpunct = 0;
589 }
590
591 if ( ! mdoc_word_alloc(mdoc, line, la, p))
592 return(0);
593 mdoc->next = MDOC_NEXT_SIBLING;
594 }
595
596 mdoc_argv_free(argc, argv);
597
598 if (0 == lastpunct && ! rewind_elem(mdoc, tok))
599 return(0);
600 if (ppos > 1)
601 return(1);
602 return(append_delims(mdoc, line, pos, buf));
603 }
604
605
606 int
607 macro_scoped(MACRO_PROT_ARGS)
608 {
609 int c, lastarg, argc, fl;
610 struct mdoc_arg argv[MDOC_LINEARG_MAX];
611 char *p;
612
613 assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
614
615 if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
616 if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
617 return(0);
618 if ( ! rewind_impblock(mdoc, tok, line, ppos))
619 return(0);
620 }
621
622 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
623 lastarg = *pos;
624 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
625 if (ARGV_EOLN == c)
626 break;
627 if (ARGV_WORD == c) {
628 *pos = lastarg;
629 break;
630 } else if (ARGV_ARG == c)
631 continue;
632 mdoc_argv_free(argc, argv);
633 return(0);
634 }
635
636 if (MDOC_LINEARG_MAX == argc) {
637 mdoc_argv_free(argc - 1, argv);
638 return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
639 }
640
641 c = mdoc_block_alloc(mdoc, line, ppos,
642 tok, (size_t)argc, argv);
643 mdoc_argv_free(argc, argv);
644
645 if (0 == c)
646 return(0);
647
648 mdoc->next = MDOC_NEXT_CHILD;
649
650 if (0 == buf[*pos]) {
651 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
652 return(0);
653 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
654 return(0);
655 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
656 return(0);
657 mdoc->next = MDOC_NEXT_CHILD;
658 return(1);
659 }
660
661 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
662 return(0);
663 mdoc->next = MDOC_NEXT_CHILD;
664
665 fl = ARGS_DELIM;
666 if (MDOC_TABSEP & mdoc_macros[tok].flags)
667 fl |= ARGS_TABSEP;
668
669 for (;;) {
670 lastarg = *pos;
671 c = mdoc_args(mdoc, line, pos, buf, fl, &p);
672
673 if (ARGS_ERROR == c)
674 return(0);
675 if (ARGS_PUNCT == c)
676 break;
677 if (ARGS_EOLN == c)
678 break;
679
680 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
681 return(0);
682 else if (MDOC_MAX == c) {
683 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
684 return(0);
685 mdoc->next = MDOC_NEXT_SIBLING;
686 continue;
687 }
688
689 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
690 return(0);
691 break;
692 }
693
694 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
695 return(0);
696 if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
697 return(0);
698
699 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
700 return(0);
701 mdoc->next = MDOC_NEXT_CHILD;
702
703 return(1);
704 }
705
706
707 int
708 macro_scoped_line(MACRO_PROT_ARGS)
709 {
710 int lastarg, c;
711 char *p;
712
713 if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
714 return(0);
715 mdoc->next = MDOC_NEXT_CHILD;
716
717 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
718 return(0);
719 mdoc->next = MDOC_NEXT_CHILD;
720
721 /* XXX - no known argument macros. */
722
723 lastarg = ppos;
724 for (;;) {
725 lastarg = *pos;
726 c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
727
728 if (ARGS_ERROR == c)
729 return(0);
730 if (ARGS_PUNCT == c)
731 break;
732 if (ARGS_EOLN == c)
733 break;
734
735 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
736 return(0);
737 else if (MDOC_MAX == c) {
738 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
739 return(0);
740 mdoc->next = MDOC_NEXT_SIBLING;
741 continue;
742 }
743
744 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
745 return(0);
746 break;
747 }
748
749 if (1 == ppos) {
750 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
751 return(0);
752 if ( ! append_delims(mdoc, line, pos, buf))
753 return(0);
754 } else if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
755 return(0);
756 return(rewind_impblock(mdoc, tok, line, ppos));
757 }
758
759
760 int
761 macro_constant_scoped(MACRO_PROT_ARGS)
762 {
763 int lastarg, flushed, j, c, maxargs;
764 char *p;
765
766 lastarg = ppos;
767 flushed = 0;
768
769 switch (tok) {
770 case (MDOC_Eo):
771 maxargs = 1;
772 break;
773 default:
774 maxargs = 0;
775 break;
776 }
777
778 if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
779 return(0);
780 mdoc->next = MDOC_NEXT_CHILD;
781
782 if (0 == maxargs) {
783 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
784 return(0);
785 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
786 return(0);
787 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
788 return(0);
789 flushed = 1;
790 } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
791 return(0);
792
793 mdoc->next = MDOC_NEXT_CHILD;
794
795 for (j = 0; /* No sentinel. */; j++) {
796 lastarg = *pos;
797
798 if (j == maxargs && ! flushed) {
799 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
800 return(0);
801 flushed = 1;
802 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
803 return(0);
804 mdoc->next = MDOC_NEXT_CHILD;
805 }
806
807 c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
808 if (ARGS_ERROR == c)
809 return(0);
810 if (ARGS_PUNCT == c)
811 break;
812 if (ARGS_EOLN == c)
813 break;
814
815 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
816 return(0);
817 else if (MDOC_MAX != c) {
818 if ( ! flushed) {
819 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
820 return(0);
821 flushed = 1;
822 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
823 return(0);
824 mdoc->next = MDOC_NEXT_CHILD;
825 }
826 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
827 return(0);
828 break;
829 }
830
831 if ( ! flushed && mdoc_isdelim(p)) {
832 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
833 return(0);
834 flushed = 1;
835 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
836 return(0);
837 mdoc->next = MDOC_NEXT_CHILD;
838 }
839
840 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
841 return(0);
842 mdoc->next = MDOC_NEXT_SIBLING;
843 }
844
845 if ( ! flushed) {
846 if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
847 return(0);
848 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
849 return(0);
850 mdoc->next = MDOC_NEXT_CHILD;
851 }
852
853 if (ppos > 1)
854 return(1);
855 return(append_delims(mdoc, line, pos, buf));
856 }
857
858
859 int
860 macro_constant_delimited(MACRO_PROT_ARGS)
861 {
862 int lastarg, flushed, j, c, maxargs, argc;
863 struct mdoc_arg argv[MDOC_LINEARG_MAX];
864 char *p;
865
866 lastarg = ppos;
867 flushed = 0;
868
869 switch (tok) {
870 case (MDOC_No):
871 /* FALLTHROUGH */
872 case (MDOC_Ns):
873 /* FALLTHROUGH */
874 case (MDOC_Pf):
875 /* FALLTHROUGH */
876 case (MDOC_Ux):
877 /* FALLTHROUGH */
878 case (MDOC_St):
879 maxargs = 0;
880 break;
881 default:
882 maxargs = 1;
883 break;
884 }
885
886 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
887 lastarg = *pos;
888 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
889 if (ARGV_EOLN == c)
890 break;
891 if (ARGV_WORD == c) {
892 *pos = lastarg;
893 break;
894 } else if (ARGV_ARG == c)
895 continue;
896 mdoc_argv_free(argc, argv);
897 return(0);
898 }
899
900 if (MDOC_LINEARG_MAX == argc) {
901 mdoc_argv_free(argc - 1, argv);
902 return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
903 }
904
905 c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
906 mdoc_argv_free(argc, argv);
907
908 if (0 == c)
909 return(0);
910
911 mdoc->next = MDOC_NEXT_CHILD;
912
913 for (j = 0; /* No sentinel. */; j++) {
914 lastarg = *pos;
915
916 if (j == maxargs && ! flushed) {
917 if ( ! rewind_elem(mdoc, tok))
918 return(0);
919 flushed = 1;
920 }
921
922 c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
923 if (ARGS_ERROR == c)
924 return(0);
925 if (ARGS_PUNCT == c)
926 break;
927 if (ARGS_EOLN == c)
928 break;
929
930 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
931 return(0);
932 else if (MDOC_MAX != c) {
933 if ( ! flushed && ! rewind_elem(mdoc, tok))
934 return(0);
935 flushed = 1;
936 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
937 return(0);
938 break;
939 }
940
941 if ( ! flushed && mdoc_isdelim(p)) {
942 if ( ! rewind_elem(mdoc, tok))
943 return(0);
944 flushed = 1;
945 }
946
947 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
948 return(0);
949 mdoc->next = MDOC_NEXT_SIBLING;
950 }
951
952 if ( ! flushed && ! rewind_elem(mdoc, tok))
953 return(0);
954
955 if (ppos > 1)
956 return(1);
957 return(append_delims(mdoc, line, pos, buf));
958 }
959
960
961 int
962 macro_constant(MACRO_PROT_ARGS)
963 {
964 int c, lastarg, argc, fl;
965 struct mdoc_arg argv[MDOC_LINEARG_MAX];
966 char *p;
967 struct mdoc_node *n;
968
969 fl = 0;
970 if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
971 fl = ARGS_QUOTED;
972
973 for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
974 lastarg = *pos;
975 c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
976 if (ARGV_EOLN == c)
977 break;
978 if (ARGV_WORD == c) {
979 *pos = lastarg;
980 break;
981 } else if (ARGV_ARG == c)
982 continue;
983
984 mdoc_argv_free(argc, argv);
985 return(0);
986 }
987
988 if (MDOC_LINEARG_MAX == argc) {
989 mdoc_argv_free(argc - 1, argv);
990 return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
991 }
992
993 c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
994 mdoc_argv_free(argc, argv);
995
996 if (0 == c)
997 return(0);
998
999 mdoc->next = MDOC_NEXT_CHILD;
1000
1001 for (;;) {
1002 lastarg = *pos;
1003 c = mdoc_args(mdoc, line, pos, buf, fl, &p);
1004 if (ARGS_ERROR == c)
1005 return(0);
1006 if (ARGS_EOLN == c)
1007 break;
1008
1009 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1010 return(0);
1011 else if (MDOC_MAX != c) {
1012 if ( ! rewind_elem(mdoc, tok))
1013 return(0);
1014 return(mdoc_macro(mdoc, c, line,
1015 lastarg, pos, buf));
1016 }
1017
1018 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1019 return(0);
1020 mdoc->next = MDOC_NEXT_SIBLING;
1021 }
1022
1023 if ( ! rewind_elem(mdoc, tok))
1024 return(0);
1025 if ( ! (MDOC_NOKEEP & mdoc_macros[tok].flags))
1026 return(1);
1027
1028 assert(mdoc->last->tok == tok);
1029 if (mdoc->last->parent->child == mdoc->last)
1030 mdoc->last->parent->child = mdoc->last->prev;
1031 if (mdoc->last->prev)
1032 mdoc->last->prev->next = NULL;
1033
1034 n = mdoc->last;
1035 assert(NULL == mdoc->last->next);
1036
1037 if (mdoc->last->prev) {
1038 mdoc->last = mdoc->last->prev;
1039 mdoc->next = MDOC_NEXT_SIBLING;
1040 } else {
1041 mdoc->last = mdoc->last->parent;
1042 mdoc->next = MDOC_NEXT_CHILD;
1043 }
1044
1045 mdoc_node_freelist(n);
1046
1047 return(1);
1048 }
1049
1050
1051 /* ARGSUSED */
1052 int
1053 macro_obsolete(MACRO_PROT_ARGS)
1054 {
1055
1056 return(mdoc_pwarn(mdoc, line, ppos, WARN_SYNTAX, "macro is obsolete"));
1057 }
1058
1059
1060 int
1061 macro_end(struct mdoc *mdoc)
1062 {
1063 struct mdoc_node *n;
1064
1065 assert(mdoc->first);
1066 assert(mdoc->last);
1067
1068 /* Scan for open explicit scopes. */
1069
1070 n = MDOC_VALID & mdoc->last->flags ?
1071 mdoc->last->parent : mdoc->last;
1072
1073 for ( ; n; n = n->parent) {
1074 if (MDOC_BLOCK != n->type)
1075 continue;
1076 if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
1077 continue;
1078 mdoc_nerr(mdoc, n, "macro scope still open on exit");
1079 return(0);
1080 }
1081
1082 return(rewind_last(mdoc, mdoc->first));
1083 }