Annotation of mandoc/macro.c, Revision 1.47
1.47 ! kristaps 1: /* $Id: macro.c,v 1.46 2009/01/20 15:06:07 kristaps Exp $ */
1.1 kristaps 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: */
1.2 kristaps 19: #include <assert.h>
20: #include <ctype.h>
1.1 kristaps 21: #include <stdlib.h>
1.2 kristaps 22: #include <stdio.h>
1.5 kristaps 23: #include <string.h>
1.11 kristaps 24: #ifdef __linux__
25: #include <time.h>
26: #endif
1.2 kristaps 27:
1.44 kristaps 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. Macros are parsed according as follows:
32: *
33: * ELEMENT: TEXT | epsilon
34: * BLOCK: HEAD PUNCT BODY PUNCT BLOCK_TAIL PUNCT
35: * BLOCK_TAIL: TAIL | epsilon
36: * HEAD: ELEMENT | TEXT | BLOCK | epsilon
37: * BODY: ELEMENT | TEXT | BLOCK | epsilon
38: * TAIL: TEXT | epsilon
39: * PUNCT: TEXT (delimiters) | epsilon
40: *
41: * These are arranged into a parse tree, an example of which follows:
42: *
43: * ROOT
44: * BLOCK (.Sh)
45: * HEAD
46: * TEXT (`NAME')
47: * BODY
48: * ELEMENT (.Nm)
49: * TEXT (`mdocml')
50: * ELEMENT (.Nd)
51: * TEXT (`mdoc macro compiler')
52: * BLOCK (.Op)
53: * HEAD
54: * ELEMENT (.Fl)
55: * TEXT (`v')
56: * BLOCK (.Op)
57: * HEAD
58: * ELEMENT (.Fl)
59: * TEXT (`v')
60: * ELEMENT (.Fl)
61: * TEXT (`W')
62: * ELEMENT (.Ns)
63: * ELEMENT (.Ar)
64: * TEXT (`err...')
65: *
66: * These types are always per-line except for block bodies, which may
67: * span multiple lines. Macros are assigned a parsing routine, which
68: * corresponds to the type, in the mdoc_macros table.
69: *
70: * Note that types are general: there can be several parsing routines
71: * corresponding to a single type. The macro_text function, for
72: * example, parses an ELEMENT type (see the function definition for
73: * details) that may be interrupted by further macros; the
74: * macro_constant function, on the other hand, parses an ELEMENT type
75: * spanning a single line.
76: */
77:
1.2 kristaps 78: #include "private.h"
79:
1.35 kristaps 80: #define REWIND_REWIND (1 << 0)
81: #define REWIND_NOHALT (1 << 1)
82: #define REWIND_HALT (1 << 2)
1.44 kristaps 83: static int rewind_dohalt(int, enum mdoc_type,
84: const struct mdoc_node *);
85: static int rewind_alt(int);
1.41 kristaps 86: static int rewind_dobreak(int, const struct mdoc_node *);
1.28 kristaps 87: static int rewind_elem(struct mdoc *, int);
1.38 kristaps 88: static int rewind_impblock(struct mdoc *, int, int, int);
89: static int rewind_expblock(struct mdoc *, int, int, int);
1.41 kristaps 90: static int rewind_subblock(enum mdoc_type,
91: struct mdoc *, int, int, int);
92: static int rewind_last(struct mdoc *, struct mdoc_node *);
93: static int append_delims(struct mdoc *, int, int *, char *);
1.30 kristaps 94: static int lookup(struct mdoc *, int, int, int, const char *);
1.24 kristaps 95:
96:
97: static int
1.30 kristaps 98: lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p)
1.24 kristaps 99: {
1.30 kristaps 100: int res;
1.24 kristaps 101:
1.30 kristaps 102: res = mdoc_find(mdoc, p);
103: if (MDOC_PARSED & mdoc_macros[from].flags)
104: return(res);
105: if (MDOC_MAX == res)
106: return(res);
1.38 kristaps 107: if ( ! mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, "macro-like parameter"))
1.30 kristaps 108: return(-1);
109: return(MDOC_MAX);
1.24 kristaps 110: }
1.19 kristaps 111:
112:
113: static int
1.41 kristaps 114: rewind_last(struct mdoc *mdoc, struct mdoc_node *to)
1.25 kristaps 115: {
116:
117: assert(to);
1.30 kristaps 118: mdoc->next = MDOC_NEXT_SIBLING;
1.42 kristaps 119:
120: while (mdoc->last != to) {
1.30 kristaps 121: if ( ! mdoc_valid_post(mdoc))
122: return(0);
123: if ( ! mdoc_action_post(mdoc))
124: return(0);
1.29 kristaps 125: mdoc->last = mdoc->last->parent;
126: assert(mdoc->last);
1.42 kristaps 127: }
1.28 kristaps 128:
1.42 kristaps 129: if ( ! mdoc_valid_post(mdoc))
130: return(0);
131: return(mdoc_action_post(mdoc));
1.25 kristaps 132: }
133:
134:
135: static int
1.35 kristaps 136: rewind_alt(int tok)
137: {
138: switch (tok) {
139: case (MDOC_Ac):
140: return(MDOC_Ao);
141: case (MDOC_Bc):
142: return(MDOC_Bo);
143: case (MDOC_Dc):
144: return(MDOC_Do);
145: case (MDOC_Ec):
146: return(MDOC_Eo);
147: case (MDOC_Ed):
148: return(MDOC_Bd);
149: case (MDOC_Ef):
150: return(MDOC_Bf);
151: case (MDOC_Ek):
152: return(MDOC_Bk);
153: case (MDOC_El):
154: return(MDOC_Bl);
155: case (MDOC_Fc):
156: return(MDOC_Fo);
157: case (MDOC_Oc):
158: return(MDOC_Oo);
159: case (MDOC_Pc):
160: return(MDOC_Po);
161: case (MDOC_Qc):
162: return(MDOC_Qo);
163: case (MDOC_Re):
164: return(MDOC_Rs);
165: case (MDOC_Sc):
166: return(MDOC_So);
167: case (MDOC_Xc):
168: return(MDOC_Xo);
169: default:
170: break;
171: }
172: abort();
173: /* NOTREACHED */
174: }
175:
176:
177: static int
178: rewind_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
179: {
180:
181: if (MDOC_ROOT == p->type)
182: return(REWIND_HALT);
1.42 kristaps 183: if (MDOC_VALID & p->flags)
1.35 kristaps 184: return(REWIND_NOHALT);
185:
186: switch (tok) {
187: /* One-liner implicit-scope. */
188: case (MDOC_Aq):
189: /* FALLTHROUGH */
190: case (MDOC_Bq):
191: /* FALLTHROUGH */
192: case (MDOC_D1):
193: /* FALLTHROUGH */
194: case (MDOC_Dl):
195: /* FALLTHROUGH */
196: case (MDOC_Dq):
197: /* FALLTHROUGH */
198: case (MDOC_Op):
199: /* FALLTHROUGH */
200: case (MDOC_Pq):
201: /* FALLTHROUGH */
202: case (MDOC_Ql):
203: /* FALLTHROUGH */
204: case (MDOC_Qq):
205: /* FALLTHROUGH */
206: case (MDOC_Sq):
1.44 kristaps 207: assert(MDOC_HEAD != type);
1.35 kristaps 208: assert(MDOC_TAIL != type);
209: if (type == p->type && tok == p->tok)
210: return(REWIND_REWIND);
211: break;
212:
213: /* Multi-line implicit-scope. */
214: case (MDOC_It):
215: assert(MDOC_TAIL != type);
216: if (type == p->type && tok == p->tok)
217: return(REWIND_REWIND);
1.36 kristaps 218: if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
1.35 kristaps 219: return(REWIND_HALT);
220: break;
221: case (MDOC_Sh):
1.36 kristaps 222: if (type == p->type && tok == p->tok)
223: return(REWIND_REWIND);
224: break;
1.35 kristaps 225: case (MDOC_Ss):
1.36 kristaps 226: assert(MDOC_TAIL != type);
1.35 kristaps 227: if (type == p->type && tok == p->tok)
228: return(REWIND_REWIND);
1.36 kristaps 229: if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
230: return(REWIND_HALT);
1.35 kristaps 231: break;
232:
233: /* Multi-line explicit scope start. */
234: case (MDOC_Ao):
235: /* FALLTHROUGH */
236: case (MDOC_Bd):
237: /* FALLTHROUGH */
238: case (MDOC_Bf):
239: /* FALLTHROUGH */
240: case (MDOC_Bk):
241: /* FALLTHROUGH */
242: case (MDOC_Bl):
243: /* FALLTHROUGH */
244: case (MDOC_Bo):
245: /* FALLTHROUGH */
246: case (MDOC_Do):
247: /* FALLTHROUGH */
248: case (MDOC_Eo):
249: /* FALLTHROUGH */
250: case (MDOC_Fo):
251: /* FALLTHROUGH */
252: case (MDOC_Oo):
253: /* FALLTHROUGH */
254: case (MDOC_Po):
255: /* FALLTHROUGH */
256: case (MDOC_Qo):
257: /* FALLTHROUGH */
258: case (MDOC_Rs):
259: /* FALLTHROUGH */
260: case (MDOC_So):
261: /* FALLTHROUGH */
262: case (MDOC_Xo):
263: if (type == p->type && tok == p->tok)
264: return(REWIND_REWIND);
265: break;
266:
267: /* Multi-line explicit scope close. */
268: case (MDOC_Ac):
269: /* FALLTHROUGH */
270: case (MDOC_Bc):
271: /* FALLTHROUGH */
272: case (MDOC_Dc):
273: /* FALLTHROUGH */
274: case (MDOC_Ec):
275: /* FALLTHROUGH */
276: case (MDOC_Ed):
277: /* FALLTHROUGH */
278: case (MDOC_Ek):
279: /* FALLTHROUGH */
280: case (MDOC_El):
281: /* FALLTHROUGH */
282: case (MDOC_Fc):
283: /* FALLTHROUGH */
284: case (MDOC_Ef):
285: /* FALLTHROUGH */
286: case (MDOC_Oc):
287: /* FALLTHROUGH */
288: case (MDOC_Pc):
289: /* FALLTHROUGH */
290: case (MDOC_Qc):
291: /* FALLTHROUGH */
292: case (MDOC_Re):
293: /* FALLTHROUGH */
294: case (MDOC_Sc):
295: /* FALLTHROUGH */
296: case (MDOC_Xc):
297: if (type == p->type && rewind_alt(tok) == p->tok)
298: return(REWIND_REWIND);
299: break;
300: default:
301: abort();
302: /* NOTREACHED */
303: }
304:
305: return(REWIND_NOHALT);
306: }
307:
308:
309: static int
1.41 kristaps 310: rewind_dobreak(int tok, const struct mdoc_node *p)
1.35 kristaps 311: {
312:
313: assert(MDOC_ROOT != p->type);
314: if (MDOC_ELEM == p->type)
315: return(1);
316: if (MDOC_TEXT == p->type)
317: return(1);
1.42 kristaps 318: if (MDOC_VALID & p->flags)
319: return(1);
1.35 kristaps 320:
321: switch (tok) {
1.36 kristaps 322: /* Implicit rules. */
1.35 kristaps 323: case (MDOC_It):
324: return(MDOC_It == p->tok);
325: case (MDOC_Ss):
326: return(MDOC_Ss == p->tok);
327: case (MDOC_Sh):
328: if (MDOC_Ss == p->tok)
329: return(1);
330: return(MDOC_Sh == p->tok);
1.36 kristaps 331:
332: /* Extra scope rules. */
333: case (MDOC_El):
334: if (MDOC_It == p->tok)
335: return(1);
336: break;
337: default:
338: break;
1.35 kristaps 339: }
340:
341: if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
342: return(p->tok == rewind_alt(tok));
343: else if (MDOC_BLOCK == p->type)
344: return(1);
345:
346: return(tok == p->tok);
347: }
348:
349:
350: static int
1.28 kristaps 351: rewind_elem(struct mdoc *mdoc, int tok)
1.19 kristaps 352: {
353: struct mdoc_node *n;
1.2 kristaps 354:
1.19 kristaps 355: n = mdoc->last;
356: if (MDOC_ELEM != n->type)
357: n = n->parent;
358: assert(MDOC_ELEM == n->type);
1.32 kristaps 359: assert(tok == n->tok);
1.19 kristaps 360:
1.41 kristaps 361: return(rewind_last(mdoc, n));
1.19 kristaps 362: }
1.6 kristaps 363:
364:
365: static int
1.41 kristaps 366: rewind_subblock(enum mdoc_type type, struct mdoc *mdoc,
367: int tok, int line, int ppos)
1.22 kristaps 368: {
369: struct mdoc_node *n;
1.35 kristaps 370: int c;
1.28 kristaps 371:
1.6 kristaps 372: /* LINTED */
1.42 kristaps 373: for (n = mdoc->last; n; n = n->parent) {
1.36 kristaps 374: c = rewind_dohalt(tok, type, n);
1.35 kristaps 375: if (REWIND_HALT == c)
376: return(1);
377: if (REWIND_REWIND == c)
1.6 kristaps 378: break;
1.41 kristaps 379: else if (rewind_dobreak(tok, n))
1.7 kristaps 380: continue;
1.41 kristaps 381: return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
1.6 kristaps 382: }
383:
1.25 kristaps 384: assert(n);
1.41 kristaps 385: return(rewind_last(mdoc, n));
1.6 kristaps 386: }
387:
388:
389: static int
1.38 kristaps 390: rewind_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.6 kristaps 391: {
1.7 kristaps 392: struct mdoc_node *n;
1.35 kristaps 393: int c;
1.6 kristaps 394:
1.7 kristaps 395: /* LINTED */
1.42 kristaps 396: for (n = mdoc->last; n; n = n->parent) {
1.35 kristaps 397: c = rewind_dohalt(tok, MDOC_BLOCK, n);
398: if (REWIND_HALT == c)
1.38 kristaps 399: return(mdoc_perr(mdoc, line, ppos, "closing macro has no context"));
1.35 kristaps 400: if (REWIND_REWIND == c)
1.16 kristaps 401: break;
1.41 kristaps 402: else if (rewind_dobreak(tok, n))
1.22 kristaps 403: continue;
1.41 kristaps 404: return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
1.16 kristaps 405: }
406:
1.28 kristaps 407: assert(n);
1.41 kristaps 408: return(rewind_last(mdoc, n));
1.21 kristaps 409: }
410:
411:
412: static int
1.38 kristaps 413: rewind_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.21 kristaps 414: {
415: struct mdoc_node *n;
1.35 kristaps 416: int c;
1.21 kristaps 417:
418: /* LINTED */
1.42 kristaps 419: for (n = mdoc->last; n; n = n->parent) {
1.35 kristaps 420: c = rewind_dohalt(tok, MDOC_BLOCK, n);
421: if (REWIND_HALT == c)
422: return(1);
423: else if (REWIND_REWIND == c)
1.21 kristaps 424: break;
1.41 kristaps 425: else if (rewind_dobreak(tok, n))
1.21 kristaps 426: continue;
1.41 kristaps 427: return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
1.21 kristaps 428: }
429:
1.35 kristaps 430: assert(n);
1.41 kristaps 431: return(rewind_last(mdoc, n));
1.16 kristaps 432: }
433:
434:
1.22 kristaps 435: static int
1.41 kristaps 436: append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
1.22 kristaps 437: {
438: int c, lastarg;
439: char *p;
440:
441: if (0 == buf[*pos])
442: return(1);
443:
444: for (;;) {
445: lastarg = *pos;
1.28 kristaps 446: c = mdoc_args(mdoc, line, pos, buf, 0, &p);
1.22 kristaps 447: if (ARGS_ERROR == c)
448: return(0);
449: else if (ARGS_EOLN == c)
450: break;
451: assert(mdoc_isdelim(p));
1.28 kristaps 452: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
453: return(0);
1.22 kristaps 454: mdoc->next = MDOC_NEXT_SIBLING;
455: }
456:
457: return(1);
458: }
459:
460:
1.44 kristaps 461: /*
462: * Close out an explicit scope. This optionally parses a TAIL type with
463: * a set number of TEXT children.
464: */
1.19 kristaps 465: int
1.35 kristaps 466: macro_scoped_close(MACRO_PROT_ARGS)
1.19 kristaps 467: {
1.28 kristaps 468: int tt, j, c, lastarg, maxargs, flushed;
1.22 kristaps 469: char *p;
1.19 kristaps 470:
471: switch (tok) {
1.22 kristaps 472: case (MDOC_Ec):
473: maxargs = 1;
474: break;
475: default:
476: maxargs = 0;
477: break;
478: }
479:
1.35 kristaps 480: tt = rewind_alt(tok);
481:
1.41 kristaps 482: mdoc_msg(mdoc, "parse: %s closing %s",
1.36 kristaps 483: mdoc_macronames[tok], mdoc_macronames[tt]);
484:
1.22 kristaps 485: if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
1.35 kristaps 486: if (0 == buf[*pos]) {
1.41 kristaps 487: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 488: return(0);
1.38 kristaps 489: return(rewind_expblock(mdoc, tok, line, ppos));
1.35 kristaps 490: }
1.38 kristaps 491: return(mdoc_perr(mdoc, line, ppos, "macro expects no parameters"));
1.22 kristaps 492: }
1.19 kristaps 493:
1.41 kristaps 494: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.22 kristaps 495: return(0);
1.19 kristaps 496:
1.22 kristaps 497: lastarg = ppos;
498: flushed = 0;
1.15 kristaps 499:
1.22 kristaps 500: if (maxargs > 0) {
1.28 kristaps 501: if ( ! mdoc_tail_alloc(mdoc, line, ppos, tt))
502: return(0);
1.22 kristaps 503: mdoc->next = MDOC_NEXT_CHILD;
504: }
1.15 kristaps 505:
1.41 kristaps 506: for (j = 0; /* No sentinel. */; j++) {
1.15 kristaps 507: lastarg = *pos;
1.22 kristaps 508:
509: if (j == maxargs && ! flushed) {
1.38 kristaps 510: if ( ! rewind_expblock(mdoc, tok, line, ppos))
1.22 kristaps 511: return(0);
512: flushed = 1;
513: }
514:
1.28 kristaps 515: c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
1.15 kristaps 516: if (ARGS_ERROR == c)
517: return(0);
1.22 kristaps 518: if (ARGS_PUNCT == c)
519: break;
520: if (ARGS_EOLN == c)
521: break;
522:
1.30 kristaps 523: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
524: return(0);
525: else if (MDOC_MAX != c) {
1.22 kristaps 526: if ( ! flushed) {
1.38 kristaps 527: if ( ! rewind_expblock(mdoc, tok, line, ppos))
1.22 kristaps 528: return(0);
529: flushed = 1;
530: }
1.26 kristaps 531: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.22 kristaps 532: return(0);
1.15 kristaps 533: break;
1.30 kristaps 534: }
1.22 kristaps 535:
1.28 kristaps 536: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
537: return(0);
1.16 kristaps 538: mdoc->next = MDOC_NEXT_SIBLING;
1.15 kristaps 539: }
1.2 kristaps 540:
1.38 kristaps 541: if ( ! flushed && ! rewind_expblock(mdoc, tok, line, ppos))
1.28 kristaps 542: return(0);
1.22 kristaps 543:
544: if (ppos > 1)
545: return(1);
1.41 kristaps 546: return(append_delims(mdoc, line, pos, buf));
1.1 kristaps 547: }
548:
1.2 kristaps 549:
1.44 kristaps 550: /*
551: * A general text macro. This is a complex case because of punctuation.
552: * If a text macro is followed by words, then punctuation, the macro is
553: * "stopped" and "reopened" following the punctuation. Thus, the
554: * following arises:
555: *
556: * .Fl a ; b
557: *
558: * ELEMENT (.Fl)
559: * TEXT (`a')
560: * TEXT (`;')
561: * ELEMENT (.Fl)
562: * TEXT (`b')
563: *
564: * This must handle the following situations:
565: *
566: * .Fl Ar b ; ;
567: *
568: * ELEMENT (.Fl)
569: * ELEMENT (.Ar)
570: * TEXT (`b')
571: * TEXT (`;')
572: * TEXT (`;')
573: */
1.19 kristaps 574: int
575: macro_text(MACRO_PROT_ARGS)
1.13 kristaps 576: {
1.45 kristaps 577: int la, lastpunct, c, w, fl, argc;
1.19 kristaps 578: struct mdoc_arg argv[MDOC_LINEARG_MAX];
579: char *p;
1.13 kristaps 580:
1.28 kristaps 581: la = ppos;
1.19 kristaps 582: lastpunct = 0;
1.17 kristaps 583:
1.19 kristaps 584: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1.28 kristaps 585: la = *pos;
586: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38 kristaps 587: if (ARGV_EOLN == c)
1.19 kristaps 588: break;
1.38 kristaps 589: if (ARGV_WORD == c) {
590: *pos = la;
591: break;
592: } else if (ARGV_ARG == c)
1.19 kristaps 593: continue;
1.38 kristaps 594:
1.19 kristaps 595: mdoc_argv_free(argc, argv);
1.14 kristaps 596: return(0);
1.10 kristaps 597: }
598:
1.28 kristaps 599: if (MDOC_LINEARG_MAX == argc) {
1.41 kristaps 600: mdoc_argv_free(argc - 1, argv);
601: return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
1.28 kristaps 602: }
603:
1.40 kristaps 604: c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
1.28 kristaps 605:
606: if (0 == c) {
1.19 kristaps 607: mdoc_argv_free(argc, argv);
608: return(0);
1.7 kristaps 609: }
610:
1.28 kristaps 611: mdoc->next = MDOC_NEXT_CHILD;
612:
1.15 kristaps 613: fl = ARGS_DELIM;
614: if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
615: fl |= ARGS_QUOTED;
1.7 kristaps 616:
1.41 kristaps 617: lastpunct = 0;
618: for (;;) {
1.28 kristaps 619: la = *pos;
1.45 kristaps 620: w = mdoc_args(mdoc, line, pos, buf, fl, &p);
621: if (ARGS_ERROR == w) {
1.19 kristaps 622: mdoc_argv_free(argc, argv);
1.7 kristaps 623: return(0);
1.19 kristaps 624: }
625:
1.45 kristaps 626: if (ARGS_EOLN == w)
1.19 kristaps 627: break;
1.45 kristaps 628: if (ARGS_PUNCT == w)
1.19 kristaps 629: break;
1.2 kristaps 630:
1.45 kristaps 631: c = ARGS_QWORD == w ? MDOC_MAX :
632: lookup(mdoc, line, la, tok, p);
633:
634: if (MDOC_MAX != c && -1 != c) {
1.36 kristaps 635: if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
1.19 kristaps 636: mdoc_argv_free(argc, argv);
637: return(0);
638: }
639: mdoc_argv_free(argc, argv);
1.28 kristaps 640: c = mdoc_macro(mdoc, c, line, la, pos, buf);
641: if (0 == c)
1.19 kristaps 642: return(0);
643: if (ppos > 1)
644: return(1);
1.41 kristaps 645: return(append_delims(mdoc, line, pos, buf));
1.45 kristaps 646: } else if (-1 == c) {
647: mdoc_argv_free(argc, argv);
648: return(0);
1.19 kristaps 649: }
1.2 kristaps 650:
1.45 kristaps 651: if (ARGS_QWORD != w && mdoc_isdelim(p)) {
1.36 kristaps 652: if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
1.19 kristaps 653: mdoc_argv_free(argc, argv);
654: return(0);
655: }
656: lastpunct = 1;
1.36 kristaps 657: } else if (lastpunct) {
658: c = mdoc_elem_alloc(mdoc, line,
1.40 kristaps 659: ppos, tok, argc, argv);
1.36 kristaps 660: if (0 == c) {
661: mdoc_argv_free(argc, argv);
662: return(0);
663: }
664: mdoc->next = MDOC_NEXT_CHILD;
665: lastpunct = 0;
1.19 kristaps 666: }
1.36 kristaps 667:
1.28 kristaps 668: if ( ! mdoc_word_alloc(mdoc, line, la, p))
669: return(0);
1.19 kristaps 670: mdoc->next = MDOC_NEXT_SIBLING;
1.2 kristaps 671: }
672:
1.19 kristaps 673: mdoc_argv_free(argc, argv);
1.2 kristaps 674:
1.36 kristaps 675: if (0 == lastpunct && ! rewind_elem(mdoc, tok))
1.7 kristaps 676: return(0);
1.19 kristaps 677: if (ppos > 1)
678: return(1);
1.41 kristaps 679: return(append_delims(mdoc, line, pos, buf));
1.5 kristaps 680: }
681:
682:
1.44 kristaps 683: /*
684: * Handle explicit-scope (having a different closure token) and implicit
685: * scope (closing out prior scopes when re-invoked) macros. These
686: * constitute the BLOCK type and usually span multiple lines. These
687: * always have HEAD and sometimes have BODY types. In the multi-line
688: * case:
689: *
690: * .Bd -ragged
691: * Text.
692: * .Fl macro
693: * Another.
694: * .Ed
695: *
696: * BLOCK (.Bd)
697: * HEAD
698: * BODY
699: * TEXT (`Text.')
700: * ELEMENT (.Fl)
701: * TEXT (`macro')
702: * TEXT (`Another.')
703: *
704: * Note that the `.It' macro, possibly the most difficult (as it has
705: * embedded scope, etc.) is handled by this routine.
706: */
1.5 kristaps 707: int
1.16 kristaps 708: macro_scoped(MACRO_PROT_ARGS)
1.6 kristaps 709: {
1.41 kristaps 710: int c, lastarg, argc, fl;
1.6 kristaps 711: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.24 kristaps 712: char *p;
1.6 kristaps 713:
1.16 kristaps 714: assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6 kristaps 715:
1.47 ! kristaps 716: /* First rewind extant implicit scope. */
! 717:
1.35 kristaps 718: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1.41 kristaps 719: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 720: return(0);
1.38 kristaps 721: if ( ! rewind_impblock(mdoc, tok, line, ppos))
1.16 kristaps 722: return(0);
1.35 kristaps 723: }
1.2 kristaps 724:
1.47 ! kristaps 725: /* Parse arguments. */
! 726:
1.16 kristaps 727: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
728: lastarg = *pos;
1.28 kristaps 729: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38 kristaps 730: if (ARGV_EOLN == c)
731: break;
732: if (ARGV_WORD == c) {
733: *pos = lastarg;
1.16 kristaps 734: break;
1.38 kristaps 735: } else if (ARGV_ARG == c)
1.16 kristaps 736: continue;
737: mdoc_argv_free(argc, argv);
1.8 kristaps 738: return(0);
1.16 kristaps 739: }
1.2 kristaps 740:
1.28 kristaps 741: if (MDOC_LINEARG_MAX == argc) {
1.41 kristaps 742: mdoc_argv_free(argc - 1, argv);
743: return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
1.28 kristaps 744: }
745:
746: c = mdoc_block_alloc(mdoc, line, ppos,
747: tok, (size_t)argc, argv);
748: mdoc_argv_free(argc, argv);
749:
750: if (0 == c)
1.16 kristaps 751: return(0);
1.8 kristaps 752:
1.19 kristaps 753: mdoc->next = MDOC_NEXT_CHILD;
754:
1.24 kristaps 755: if (0 == buf[*pos]) {
1.28 kristaps 756: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
757: return(0);
1.41 kristaps 758: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 759: return(0);
760: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 761: return(0);
1.19 kristaps 762: mdoc->next = MDOC_NEXT_CHILD;
1.24 kristaps 763: return(1);
764: }
1.19 kristaps 765:
1.28 kristaps 766: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
767: return(0);
1.24 kristaps 768: mdoc->next = MDOC_NEXT_CHILD;
1.7 kristaps 769:
1.33 kristaps 770: fl = ARGS_DELIM;
771: if (MDOC_TABSEP & mdoc_macros[tok].flags)
772: fl |= ARGS_TABSEP;
773:
1.41 kristaps 774: for (;;) {
1.24 kristaps 775: lastarg = *pos;
1.33 kristaps 776: c = mdoc_args(mdoc, line, pos, buf, fl, &p);
1.24 kristaps 777:
778: if (ARGS_ERROR == c)
1.19 kristaps 779: return(0);
1.24 kristaps 780: if (ARGS_PUNCT == c)
781: break;
782: if (ARGS_EOLN == c)
783: break;
784:
1.30 kristaps 785: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
786: return(0);
787: else if (MDOC_MAX == c) {
1.28 kristaps 788: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
789: return(0);
1.24 kristaps 790: mdoc->next = MDOC_NEXT_SIBLING;
791: continue;
1.30 kristaps 792: }
1.2 kristaps 793:
1.26 kristaps 794: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.24 kristaps 795: return(0);
796: break;
1.7 kristaps 797: }
1.1 kristaps 798:
1.41 kristaps 799: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.24 kristaps 800: return(0);
1.41 kristaps 801: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1.24 kristaps 802: return(0);
803:
1.28 kristaps 804: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
805: return(0);
1.16 kristaps 806: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 807:
1.16 kristaps 808: return(1);
1.1 kristaps 809: }
1.5 kristaps 810:
1.7 kristaps 811:
1.44 kristaps 812: /*
813: * This handles a case of implicitly-scoped macro (BLOCK) limited to a
814: * single line. Instead of being closed out by a subsequent call to
815: * another macro, the scope is closed at the end of line. These don't
816: * have BODY or TAIL types. Notice that the punctuation falls outside
817: * of the HEAD type.
818: *
819: * .Qq a Fl b Ar d ; ;
820: *
821: * BLOCK (Qq)
822: * HEAD
823: * TEXT (`a')
824: * ELEMENT (.Fl)
825: * TEXT (`b')
826: * ELEMENT (.Ar)
827: * TEXT (`d')
828: * TEXT (`;')
829: * TEXT (`;')
830: */
1.7 kristaps 831: int
1.16 kristaps 832: macro_scoped_line(MACRO_PROT_ARGS)
1.7 kristaps 833: {
1.41 kristaps 834: int lastarg, c;
1.8 kristaps 835: char *p;
1.7 kristaps 836:
1.28 kristaps 837: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
838: return(0);
1.16 kristaps 839: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 840:
1.28 kristaps 841: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
842: return(0);
1.44 kristaps 843: mdoc->next = MDOC_NEXT_SIBLING;
844: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
845: return(0);
1.16 kristaps 846: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 847:
1.19 kristaps 848: /* XXX - no known argument macros. */
849:
1.41 kristaps 850: lastarg = ppos;
851: for (;;) {
1.19 kristaps 852: lastarg = *pos;
1.28 kristaps 853: c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
1.8 kristaps 854:
1.19 kristaps 855: if (ARGS_ERROR == c)
856: return(0);
857: if (ARGS_PUNCT == c)
858: break;
859: if (ARGS_EOLN == c)
860: break;
1.8 kristaps 861:
1.30 kristaps 862: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
863: return(0);
864: else if (MDOC_MAX == c) {
1.28 kristaps 865: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
866: return(0);
1.19 kristaps 867: mdoc->next = MDOC_NEXT_SIBLING;
868: continue;
1.30 kristaps 869: }
1.8 kristaps 870:
1.26 kristaps 871: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 872: return(0);
1.8 kristaps 873: break;
874: }
875:
1.19 kristaps 876: if (1 == ppos) {
1.44 kristaps 877: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.16 kristaps 878: return(0);
1.41 kristaps 879: if ( ! append_delims(mdoc, line, pos, buf))
1.8 kristaps 880: return(0);
1.44 kristaps 881: } else if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 882: return(0);
1.38 kristaps 883: return(rewind_impblock(mdoc, tok, line, ppos));
1.22 kristaps 884: }
885:
886:
1.44 kristaps 887: /*
888: * A constant-scoped macro is like a simple-scoped macro (mdoc_scoped)
889: * except that it doesn't handle implicit scopes and explicit ones have
890: * a fixed number of TEXT children to the BODY.
891: *
892: * .Fl a So b Sc ;
893: *
894: * ELEMENT (.Fl)
895: * TEXT (`a')
896: * BLOCK (.So)
897: * HEAD
898: * BODY
899: * TEXT (`b')
900: * TEXT (';')
901: */
1.22 kristaps 902: int
903: macro_constant_scoped(MACRO_PROT_ARGS)
904: {
905: int lastarg, flushed, j, c, maxargs;
906: char *p;
907:
908: lastarg = ppos;
909: flushed = 0;
910:
911: switch (tok) {
912: case (MDOC_Eo):
913: maxargs = 1;
914: break;
915: default:
916: maxargs = 0;
917: break;
918: }
919:
1.28 kristaps 920: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
921: return(0);
1.22 kristaps 922: mdoc->next = MDOC_NEXT_CHILD;
923:
924: if (0 == maxargs) {
1.28 kristaps 925: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
926: return(0);
1.41 kristaps 927: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 928: return(0);
929: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 930: return(0);
1.22 kristaps 931: flushed = 1;
1.28 kristaps 932: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
933: return(0);
1.22 kristaps 934:
935: mdoc->next = MDOC_NEXT_CHILD;
936:
1.41 kristaps 937: for (j = 0; /* No sentinel. */; j++) {
1.22 kristaps 938: lastarg = *pos;
939:
940: if (j == maxargs && ! flushed) {
1.41 kristaps 941: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 942: return(0);
943: flushed = 1;
1.28 kristaps 944: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
945: return(0);
1.22 kristaps 946: mdoc->next = MDOC_NEXT_CHILD;
947: }
948:
1.28 kristaps 949: c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
1.22 kristaps 950: if (ARGS_ERROR == c)
951: return(0);
952: if (ARGS_PUNCT == c)
953: break;
954: if (ARGS_EOLN == c)
955: break;
956:
1.30 kristaps 957: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
958: return(0);
959: else if (MDOC_MAX != c) {
1.22 kristaps 960: if ( ! flushed) {
1.41 kristaps 961: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 962: return(0);
963: flushed = 1;
1.28 kristaps 964: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
965: return(0);
1.22 kristaps 966: mdoc->next = MDOC_NEXT_CHILD;
967: }
1.26 kristaps 968: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.22 kristaps 969: return(0);
970: break;
971: }
972:
973: if ( ! flushed && mdoc_isdelim(p)) {
1.41 kristaps 974: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 975: return(0);
976: flushed = 1;
1.28 kristaps 977: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
978: return(0);
1.22 kristaps 979: mdoc->next = MDOC_NEXT_CHILD;
980: }
981:
1.28 kristaps 982: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
983: return(0);
1.22 kristaps 984: mdoc->next = MDOC_NEXT_SIBLING;
985: }
986:
987: if ( ! flushed) {
1.41 kristaps 988: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 989: return(0);
990: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.22 kristaps 991: return(0);
992: mdoc->next = MDOC_NEXT_CHILD;
993: }
994:
995: if (ppos > 1)
996: return(1);
1.41 kristaps 997: return(append_delims(mdoc, line, pos, buf));
1.7 kristaps 998: }
1.8 kristaps 999:
1.10 kristaps 1000:
1.44 kristaps 1001: /*
1002: * A delimited constant is very similar to the macros parsed by
1003: * macro_text except that, in the event of punctuation, the macro isn't
1004: * "re-opened" as it is in macro_text. Also, these macros have a fixed
1005: * number of parameters.
1006: *
1007: * .Fl a No b
1008: *
1009: * ELEMENT (.Fl)
1010: * TEXT (`a')
1011: * ELEMENT (.No)
1012: * TEXT (`b')
1013: */
1.10 kristaps 1014: int
1015: macro_constant_delimited(MACRO_PROT_ARGS)
1016: {
1.24 kristaps 1017: int lastarg, flushed, j, c, maxargs, argc;
1018: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.13 kristaps 1019: char *p;
1.10 kristaps 1020:
1021: lastarg = ppos;
1022: flushed = 0;
1023:
1024: switch (tok) {
1.16 kristaps 1025: case (MDOC_No):
1026: /* FALLTHROUGH */
1027: case (MDOC_Ns):
1028: /* FALLTHROUGH */
1.39 kristaps 1029: case (MDOC_Pf):
1030: /* FALLTHROUGH */
1.10 kristaps 1031: case (MDOC_Ux):
1.24 kristaps 1032: /* FALLTHROUGH */
1033: case (MDOC_St):
1.10 kristaps 1034: maxargs = 0;
1035: break;
1036: default:
1037: maxargs = 1;
1038: break;
1039: }
1040:
1.24 kristaps 1041: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1042: lastarg = *pos;
1.28 kristaps 1043: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38 kristaps 1044: if (ARGV_EOLN == c)
1.24 kristaps 1045: break;
1.38 kristaps 1046: if (ARGV_WORD == c) {
1047: *pos = lastarg;
1048: break;
1049: } else if (ARGV_ARG == c)
1.24 kristaps 1050: continue;
1051: mdoc_argv_free(argc, argv);
1052: return(0);
1053: }
1054:
1.41 kristaps 1055: if (MDOC_LINEARG_MAX == argc) {
1056: mdoc_argv_free(argc - 1, argv);
1057: return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
1058: }
1059:
1.40 kristaps 1060: c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
1.28 kristaps 1061: mdoc_argv_free(argc, argv);
1062:
1063: if (0 == c)
1.24 kristaps 1064: return(0);
1065:
1.19 kristaps 1066: mdoc->next = MDOC_NEXT_CHILD;
1.10 kristaps 1067:
1.41 kristaps 1068: for (j = 0; /* No sentinel. */; j++) {
1.19 kristaps 1069: lastarg = *pos;
1.10 kristaps 1070:
1.19 kristaps 1071: if (j == maxargs && ! flushed) {
1.28 kristaps 1072: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1073: return(0);
1074: flushed = 1;
1075: }
1.11 kristaps 1076:
1.28 kristaps 1077: c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
1.19 kristaps 1078: if (ARGS_ERROR == c)
1.10 kristaps 1079: return(0);
1.19 kristaps 1080: if (ARGS_PUNCT == c)
1081: break;
1082: if (ARGS_EOLN == c)
1083: break;
1084:
1.30 kristaps 1085: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1086: return(0);
1087: else if (MDOC_MAX != c) {
1.28 kristaps 1088: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1089: return(0);
1090: flushed = 1;
1.26 kristaps 1091: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1092: return(0);
1093: break;
1094: }
1.10 kristaps 1095:
1.22 kristaps 1096: if ( ! flushed && mdoc_isdelim(p)) {
1.28 kristaps 1097: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1098: return(0);
1099: flushed = 1;
1100: }
1101:
1.28 kristaps 1102: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1103: return(0);
1.19 kristaps 1104: mdoc->next = MDOC_NEXT_SIBLING;
1.10 kristaps 1105: }
1106:
1.42 kristaps 1107: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1108: return(0);
1.11 kristaps 1109:
1.19 kristaps 1110: if (ppos > 1)
1111: return(1);
1.41 kristaps 1112: return(append_delims(mdoc, line, pos, buf));
1.10 kristaps 1113: }
1.11 kristaps 1114:
1115:
1.44 kristaps 1116: /*
1117: * A constant macro is the simplest classification. It spans an entire
1118: * line.
1119: */
1.11 kristaps 1120: int
1121: macro_constant(MACRO_PROT_ARGS)
1122: {
1.45 kristaps 1123: int c, w, la, argc, fl;
1.43 kristaps 1124: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1125: char *p;
1.44 kristaps 1126:
1127: assert( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.11 kristaps 1128:
1.16 kristaps 1129: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1.45 kristaps 1130: la = *pos;
1.28 kristaps 1131: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.16 kristaps 1132: if (ARGV_EOLN == c)
1133: break;
1.38 kristaps 1134: if (ARGV_WORD == c) {
1.45 kristaps 1135: *pos = la;
1.38 kristaps 1136: break;
1137: } else if (ARGV_ARG == c)
1.16 kristaps 1138: continue;
1.11 kristaps 1139:
1.16 kristaps 1140: mdoc_argv_free(argc, argv);
1.11 kristaps 1141: return(0);
1142: }
1143:
1.41 kristaps 1144: if (MDOC_LINEARG_MAX == argc) {
1145: mdoc_argv_free(argc - 1, argv);
1146: return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
1147: }
1148:
1.28 kristaps 1149: c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
1150: mdoc_argv_free(argc, argv);
1151:
1152: if (0 == c)
1153: return(0);
1.11 kristaps 1154:
1.19 kristaps 1155: mdoc->next = MDOC_NEXT_CHILD;
1156:
1.45 kristaps 1157: fl = 0;
1158: if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
1159: fl = ARGS_QUOTED;
1160:
1.41 kristaps 1161: for (;;) {
1.45 kristaps 1162: la = *pos;
1163: w = mdoc_args(mdoc, line, pos, buf, fl, &p);
1164: if (ARGS_ERROR == w)
1.16 kristaps 1165: return(0);
1.45 kristaps 1166: if (ARGS_EOLN == w)
1.13 kristaps 1167: break;
1.19 kristaps 1168:
1.45 kristaps 1169: c = ARGS_QWORD == w ? MDOC_MAX :
1170: lookup(mdoc, line, la, tok, p);
1171:
1172: if (MDOC_MAX != c && -1 != c) {
1.39 kristaps 1173: if ( ! rewind_elem(mdoc, tok))
1174: return(0);
1.45 kristaps 1175: return(mdoc_macro(mdoc, c, line, la, pos, buf));
1176: } else if (-1 == c)
1177: return(0);
1.39 kristaps 1178:
1.45 kristaps 1179: if ( ! mdoc_word_alloc(mdoc, line, la, p))
1.28 kristaps 1180: return(0);
1.21 kristaps 1181: mdoc->next = MDOC_NEXT_SIBLING;
1.13 kristaps 1182: }
1183:
1.44 kristaps 1184: return(rewind_elem(mdoc, tok));
1.13 kristaps 1185: }
1.15 kristaps 1186:
1187:
1.16 kristaps 1188: /* ARGSUSED */
1.15 kristaps 1189: int
1190: macro_obsolete(MACRO_PROT_ARGS)
1191: {
1192:
1.38 kristaps 1193: return(mdoc_pwarn(mdoc, line, ppos, WARN_SYNTAX, "macro is obsolete"));
1.15 kristaps 1194: }
1.25 kristaps 1195:
1196:
1.44 kristaps 1197: /*
1198: * This is called at the end of parsing. It must traverse up the tree,
1199: * closing out open [implicit] scopes. Obviously, open explicit scopes
1200: * are errors.
1201: */
1.25 kristaps 1202: int
1203: macro_end(struct mdoc *mdoc)
1204: {
1.42 kristaps 1205: struct mdoc_node *n;
1.25 kristaps 1206:
1207: assert(mdoc->first);
1208: assert(mdoc->last);
1.42 kristaps 1209:
1210: /* Scan for open explicit scopes. */
1211:
1212: n = MDOC_VALID & mdoc->last->flags ?
1213: mdoc->last->parent : mdoc->last;
1214:
1215: for ( ; n; n = n->parent) {
1216: if (MDOC_BLOCK != n->type)
1217: continue;
1218: if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
1219: continue;
1.46 kristaps 1220: return(mdoc_nerr(mdoc, n, "macro scope still open on exit"));
1.42 kristaps 1221: }
1222:
1.41 kristaps 1223: return(rewind_last(mdoc, mdoc->first));
1.25 kristaps 1224: }
CVSweb