Annotation of mandoc/macro.c, Revision 1.44
1.44 ! kristaps 1: /* $Id: macro.c,v 1.43 2009/01/19 17:51:32 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.41 kristaps 577: int la, lastpunct, c, 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;
620: c = mdoc_args(mdoc, line, pos, buf, fl, &p);
1.19 kristaps 621: if (ARGS_ERROR == c) {
622: mdoc_argv_free(argc, argv);
1.7 kristaps 623: return(0);
1.19 kristaps 624: }
625:
626: if (ARGS_EOLN == c)
627: break;
628: if (ARGS_PUNCT == c)
629: break;
1.2 kristaps 630:
1.30 kristaps 631: if (-1 == (c = lookup(mdoc, line, la, tok, p)))
632: return(0);
633: else if (MDOC_MAX != c) {
1.36 kristaps 634: if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
1.19 kristaps 635: mdoc_argv_free(argc, argv);
636: return(0);
637: }
638: mdoc_argv_free(argc, argv);
1.28 kristaps 639:
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.19 kristaps 646: }
1.2 kristaps 647:
1.19 kristaps 648: if (mdoc_isdelim(p)) {
1.36 kristaps 649: if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
1.19 kristaps 650: mdoc_argv_free(argc, argv);
651: return(0);
652: }
653: lastpunct = 1;
1.36 kristaps 654: } else if (lastpunct) {
655: c = mdoc_elem_alloc(mdoc, line,
1.40 kristaps 656: ppos, tok, argc, argv);
1.36 kristaps 657: if (0 == c) {
658: mdoc_argv_free(argc, argv);
659: return(0);
660: }
661: mdoc->next = MDOC_NEXT_CHILD;
662: lastpunct = 0;
1.19 kristaps 663: }
1.36 kristaps 664:
1.28 kristaps 665: if ( ! mdoc_word_alloc(mdoc, line, la, p))
666: return(0);
1.19 kristaps 667: mdoc->next = MDOC_NEXT_SIBLING;
1.2 kristaps 668: }
669:
1.19 kristaps 670: mdoc_argv_free(argc, argv);
1.2 kristaps 671:
1.36 kristaps 672: if (0 == lastpunct && ! rewind_elem(mdoc, tok))
1.7 kristaps 673: return(0);
1.19 kristaps 674: if (ppos > 1)
675: return(1);
1.41 kristaps 676: return(append_delims(mdoc, line, pos, buf));
1.5 kristaps 677: }
678:
679:
1.44 ! kristaps 680: /*
! 681: * Handle explicit-scope (having a different closure token) and implicit
! 682: * scope (closing out prior scopes when re-invoked) macros. These
! 683: * constitute the BLOCK type and usually span multiple lines. These
! 684: * always have HEAD and sometimes have BODY types. In the multi-line
! 685: * case:
! 686: *
! 687: * .Bd -ragged
! 688: * Text.
! 689: * .Fl macro
! 690: * Another.
! 691: * .Ed
! 692: *
! 693: * BLOCK (.Bd)
! 694: * HEAD
! 695: * BODY
! 696: * TEXT (`Text.')
! 697: * ELEMENT (.Fl)
! 698: * TEXT (`macro')
! 699: * TEXT (`Another.')
! 700: *
! 701: * Note that the `.It' macro, possibly the most difficult (as it has
! 702: * embedded scope, etc.) is handled by this routine.
! 703: */
1.5 kristaps 704: int
1.16 kristaps 705: macro_scoped(MACRO_PROT_ARGS)
1.6 kristaps 706: {
1.41 kristaps 707: int c, lastarg, argc, fl;
1.6 kristaps 708: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.24 kristaps 709: char *p;
1.6 kristaps 710:
1.16 kristaps 711: assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6 kristaps 712:
1.35 kristaps 713: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1.41 kristaps 714: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 715: return(0);
1.38 kristaps 716: if ( ! rewind_impblock(mdoc, tok, line, ppos))
1.16 kristaps 717: return(0);
1.35 kristaps 718: }
1.2 kristaps 719:
1.16 kristaps 720: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
721: lastarg = *pos;
1.28 kristaps 722: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38 kristaps 723: if (ARGV_EOLN == c)
724: break;
725: if (ARGV_WORD == c) {
726: *pos = lastarg;
1.16 kristaps 727: break;
1.38 kristaps 728: } else if (ARGV_ARG == c)
1.16 kristaps 729: continue;
730: mdoc_argv_free(argc, argv);
1.8 kristaps 731: return(0);
1.16 kristaps 732: }
1.2 kristaps 733:
1.28 kristaps 734: if (MDOC_LINEARG_MAX == argc) {
1.41 kristaps 735: mdoc_argv_free(argc - 1, argv);
736: return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
1.28 kristaps 737: }
738:
739: c = mdoc_block_alloc(mdoc, line, ppos,
740: tok, (size_t)argc, argv);
741: mdoc_argv_free(argc, argv);
742:
743: if (0 == c)
1.16 kristaps 744: return(0);
1.8 kristaps 745:
1.19 kristaps 746: mdoc->next = MDOC_NEXT_CHILD;
747:
1.24 kristaps 748: if (0 == buf[*pos]) {
1.28 kristaps 749: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
750: return(0);
1.41 kristaps 751: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 752: return(0);
753: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 754: return(0);
1.19 kristaps 755: mdoc->next = MDOC_NEXT_CHILD;
1.24 kristaps 756: return(1);
757: }
1.19 kristaps 758:
1.28 kristaps 759: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
760: return(0);
1.24 kristaps 761: mdoc->next = MDOC_NEXT_CHILD;
1.7 kristaps 762:
1.33 kristaps 763: fl = ARGS_DELIM;
764: if (MDOC_TABSEP & mdoc_macros[tok].flags)
765: fl |= ARGS_TABSEP;
766:
1.41 kristaps 767: for (;;) {
1.24 kristaps 768: lastarg = *pos;
1.33 kristaps 769: c = mdoc_args(mdoc, line, pos, buf, fl, &p);
1.24 kristaps 770:
771: if (ARGS_ERROR == c)
1.19 kristaps 772: return(0);
1.24 kristaps 773: if (ARGS_PUNCT == c)
774: break;
775: if (ARGS_EOLN == c)
776: break;
777:
1.30 kristaps 778: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
779: return(0);
780: else if (MDOC_MAX == c) {
1.28 kristaps 781: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
782: return(0);
1.24 kristaps 783: mdoc->next = MDOC_NEXT_SIBLING;
784: continue;
1.30 kristaps 785: }
1.2 kristaps 786:
1.26 kristaps 787: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.24 kristaps 788: return(0);
789: break;
1.7 kristaps 790: }
1.1 kristaps 791:
1.41 kristaps 792: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.24 kristaps 793: return(0);
1.41 kristaps 794: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1.24 kristaps 795: return(0);
796:
1.28 kristaps 797: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
798: return(0);
1.16 kristaps 799: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 800:
1.16 kristaps 801: return(1);
1.1 kristaps 802: }
1.5 kristaps 803:
1.7 kristaps 804:
1.44 ! kristaps 805: /*
! 806: * This handles a case of implicitly-scoped macro (BLOCK) limited to a
! 807: * single line. Instead of being closed out by a subsequent call to
! 808: * another macro, the scope is closed at the end of line. These don't
! 809: * have BODY or TAIL types. Notice that the punctuation falls outside
! 810: * of the HEAD type.
! 811: *
! 812: * .Qq a Fl b Ar d ; ;
! 813: *
! 814: * BLOCK (Qq)
! 815: * HEAD
! 816: * TEXT (`a')
! 817: * ELEMENT (.Fl)
! 818: * TEXT (`b')
! 819: * ELEMENT (.Ar)
! 820: * TEXT (`d')
! 821: * TEXT (`;')
! 822: * TEXT (`;')
! 823: */
1.7 kristaps 824: int
1.16 kristaps 825: macro_scoped_line(MACRO_PROT_ARGS)
1.7 kristaps 826: {
1.41 kristaps 827: int lastarg, c;
1.8 kristaps 828: char *p;
1.7 kristaps 829:
1.28 kristaps 830: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
831: return(0);
1.16 kristaps 832: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 833:
1.28 kristaps 834: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
835: return(0);
1.44 ! kristaps 836: mdoc->next = MDOC_NEXT_SIBLING;
! 837: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
! 838: return(0);
1.16 kristaps 839: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 840:
1.19 kristaps 841: /* XXX - no known argument macros. */
842:
1.41 kristaps 843: lastarg = ppos;
844: for (;;) {
1.19 kristaps 845: lastarg = *pos;
1.28 kristaps 846: c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
1.8 kristaps 847:
1.19 kristaps 848: if (ARGS_ERROR == c)
849: return(0);
850: if (ARGS_PUNCT == c)
851: break;
852: if (ARGS_EOLN == c)
853: break;
1.8 kristaps 854:
1.30 kristaps 855: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
856: return(0);
857: else if (MDOC_MAX == c) {
1.28 kristaps 858: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
859: return(0);
1.19 kristaps 860: mdoc->next = MDOC_NEXT_SIBLING;
861: continue;
1.30 kristaps 862: }
1.8 kristaps 863:
1.26 kristaps 864: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 865: return(0);
1.8 kristaps 866: break;
867: }
868:
1.19 kristaps 869: if (1 == ppos) {
1.44 ! kristaps 870: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.16 kristaps 871: return(0);
1.41 kristaps 872: if ( ! append_delims(mdoc, line, pos, buf))
1.8 kristaps 873: return(0);
1.44 ! kristaps 874: } else if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 875: return(0);
1.38 kristaps 876: return(rewind_impblock(mdoc, tok, line, ppos));
1.22 kristaps 877: }
878:
879:
1.44 ! kristaps 880: /*
! 881: * A constant-scoped macro is like a simple-scoped macro (mdoc_scoped)
! 882: * except that it doesn't handle implicit scopes and explicit ones have
! 883: * a fixed number of TEXT children to the BODY.
! 884: *
! 885: * .Fl a So b Sc ;
! 886: *
! 887: * ELEMENT (.Fl)
! 888: * TEXT (`a')
! 889: * BLOCK (.So)
! 890: * HEAD
! 891: * BODY
! 892: * TEXT (`b')
! 893: * TEXT (';')
! 894: */
1.22 kristaps 895: int
896: macro_constant_scoped(MACRO_PROT_ARGS)
897: {
898: int lastarg, flushed, j, c, maxargs;
899: char *p;
900:
901: lastarg = ppos;
902: flushed = 0;
903:
904: switch (tok) {
905: case (MDOC_Eo):
906: maxargs = 1;
907: break;
908: default:
909: maxargs = 0;
910: break;
911: }
912:
1.28 kristaps 913: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
914: return(0);
1.22 kristaps 915: mdoc->next = MDOC_NEXT_CHILD;
916:
917: if (0 == maxargs) {
1.28 kristaps 918: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
919: return(0);
1.41 kristaps 920: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 921: return(0);
922: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 923: return(0);
1.22 kristaps 924: flushed = 1;
1.28 kristaps 925: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
926: return(0);
1.22 kristaps 927:
928: mdoc->next = MDOC_NEXT_CHILD;
929:
1.41 kristaps 930: for (j = 0; /* No sentinel. */; j++) {
1.22 kristaps 931: lastarg = *pos;
932:
933: if (j == maxargs && ! flushed) {
1.41 kristaps 934: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 935: return(0);
936: flushed = 1;
1.28 kristaps 937: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
938: return(0);
1.22 kristaps 939: mdoc->next = MDOC_NEXT_CHILD;
940: }
941:
1.28 kristaps 942: c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
1.22 kristaps 943: if (ARGS_ERROR == c)
944: return(0);
945: if (ARGS_PUNCT == c)
946: break;
947: if (ARGS_EOLN == c)
948: break;
949:
1.30 kristaps 950: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
951: return(0);
952: else if (MDOC_MAX != c) {
1.22 kristaps 953: if ( ! flushed) {
1.41 kristaps 954: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 955: return(0);
956: flushed = 1;
1.28 kristaps 957: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
958: return(0);
1.22 kristaps 959: mdoc->next = MDOC_NEXT_CHILD;
960: }
1.26 kristaps 961: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.22 kristaps 962: return(0);
963: break;
964: }
965:
966: if ( ! flushed && mdoc_isdelim(p)) {
1.41 kristaps 967: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 968: return(0);
969: flushed = 1;
1.28 kristaps 970: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
971: return(0);
1.22 kristaps 972: mdoc->next = MDOC_NEXT_CHILD;
973: }
974:
1.28 kristaps 975: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
976: return(0);
1.22 kristaps 977: mdoc->next = MDOC_NEXT_SIBLING;
978: }
979:
980: if ( ! flushed) {
1.41 kristaps 981: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 982: return(0);
983: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.22 kristaps 984: return(0);
985: mdoc->next = MDOC_NEXT_CHILD;
986: }
987:
988: if (ppos > 1)
989: return(1);
1.41 kristaps 990: return(append_delims(mdoc, line, pos, buf));
1.7 kristaps 991: }
1.8 kristaps 992:
1.10 kristaps 993:
1.44 ! kristaps 994: /*
! 995: * A delimited constant is very similar to the macros parsed by
! 996: * macro_text except that, in the event of punctuation, the macro isn't
! 997: * "re-opened" as it is in macro_text. Also, these macros have a fixed
! 998: * number of parameters.
! 999: *
! 1000: * .Fl a No b
! 1001: *
! 1002: * ELEMENT (.Fl)
! 1003: * TEXT (`a')
! 1004: * ELEMENT (.No)
! 1005: * TEXT (`b')
! 1006: */
1.10 kristaps 1007: int
1008: macro_constant_delimited(MACRO_PROT_ARGS)
1009: {
1.24 kristaps 1010: int lastarg, flushed, j, c, maxargs, argc;
1011: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.13 kristaps 1012: char *p;
1.10 kristaps 1013:
1014: lastarg = ppos;
1015: flushed = 0;
1016:
1017: switch (tok) {
1.16 kristaps 1018: case (MDOC_No):
1019: /* FALLTHROUGH */
1020: case (MDOC_Ns):
1021: /* FALLTHROUGH */
1.39 kristaps 1022: case (MDOC_Pf):
1023: /* FALLTHROUGH */
1.10 kristaps 1024: case (MDOC_Ux):
1.24 kristaps 1025: /* FALLTHROUGH */
1026: case (MDOC_St):
1.10 kristaps 1027: maxargs = 0;
1028: break;
1029: default:
1030: maxargs = 1;
1031: break;
1032: }
1033:
1.24 kristaps 1034: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1035: lastarg = *pos;
1.28 kristaps 1036: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38 kristaps 1037: if (ARGV_EOLN == c)
1.24 kristaps 1038: break;
1.38 kristaps 1039: if (ARGV_WORD == c) {
1040: *pos = lastarg;
1041: break;
1042: } else if (ARGV_ARG == c)
1.24 kristaps 1043: continue;
1044: mdoc_argv_free(argc, argv);
1045: return(0);
1046: }
1047:
1.41 kristaps 1048: if (MDOC_LINEARG_MAX == argc) {
1049: mdoc_argv_free(argc - 1, argv);
1050: return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
1051: }
1052:
1.40 kristaps 1053: c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
1.28 kristaps 1054: mdoc_argv_free(argc, argv);
1055:
1056: if (0 == c)
1.24 kristaps 1057: return(0);
1058:
1.19 kristaps 1059: mdoc->next = MDOC_NEXT_CHILD;
1.10 kristaps 1060:
1.41 kristaps 1061: for (j = 0; /* No sentinel. */; j++) {
1.19 kristaps 1062: lastarg = *pos;
1.10 kristaps 1063:
1.19 kristaps 1064: if (j == maxargs && ! flushed) {
1.28 kristaps 1065: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1066: return(0);
1067: flushed = 1;
1068: }
1.11 kristaps 1069:
1.28 kristaps 1070: c = mdoc_args(mdoc, line, pos, buf, ARGS_DELIM, &p);
1.19 kristaps 1071: if (ARGS_ERROR == c)
1.10 kristaps 1072: return(0);
1.19 kristaps 1073: if (ARGS_PUNCT == c)
1074: break;
1075: if (ARGS_EOLN == c)
1076: break;
1077:
1.30 kristaps 1078: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1079: return(0);
1080: else if (MDOC_MAX != c) {
1.28 kristaps 1081: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1082: return(0);
1083: flushed = 1;
1.26 kristaps 1084: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1085: return(0);
1086: break;
1087: }
1.10 kristaps 1088:
1.22 kristaps 1089: if ( ! flushed && mdoc_isdelim(p)) {
1.28 kristaps 1090: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1091: return(0);
1092: flushed = 1;
1093: }
1094:
1.28 kristaps 1095: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1096: return(0);
1.19 kristaps 1097: mdoc->next = MDOC_NEXT_SIBLING;
1.10 kristaps 1098: }
1099:
1.42 kristaps 1100: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1101: return(0);
1.11 kristaps 1102:
1.19 kristaps 1103: if (ppos > 1)
1104: return(1);
1.41 kristaps 1105: return(append_delims(mdoc, line, pos, buf));
1.10 kristaps 1106: }
1.11 kristaps 1107:
1108:
1.44 ! kristaps 1109: /*
! 1110: * A constant macro is the simplest classification. It spans an entire
! 1111: * line.
! 1112: */
1.11 kristaps 1113: int
1114: macro_constant(MACRO_PROT_ARGS)
1115: {
1.43 kristaps 1116: int c, lastarg, argc, fl;
1117: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1118: char *p;
1.44 ! kristaps 1119:
! 1120: assert( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.11 kristaps 1121:
1.16 kristaps 1122: fl = 0;
1.15 kristaps 1123: if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
1124: fl = ARGS_QUOTED;
1.11 kristaps 1125:
1.16 kristaps 1126: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1127: lastarg = *pos;
1.28 kristaps 1128: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.16 kristaps 1129: if (ARGV_EOLN == c)
1130: break;
1.38 kristaps 1131: if (ARGV_WORD == c) {
1132: *pos = lastarg;
1133: break;
1134: } else if (ARGV_ARG == c)
1.16 kristaps 1135: continue;
1.11 kristaps 1136:
1.16 kristaps 1137: mdoc_argv_free(argc, argv);
1.11 kristaps 1138: return(0);
1139: }
1140:
1.41 kristaps 1141: if (MDOC_LINEARG_MAX == argc) {
1142: mdoc_argv_free(argc - 1, argv);
1143: return(mdoc_perr(mdoc, line, ppos, "parameter hard-limit exceeded"));
1144: }
1145:
1.28 kristaps 1146: c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
1147: mdoc_argv_free(argc, argv);
1148:
1149: if (0 == c)
1150: return(0);
1.11 kristaps 1151:
1.19 kristaps 1152: mdoc->next = MDOC_NEXT_CHILD;
1153:
1.41 kristaps 1154: for (;;) {
1.13 kristaps 1155: lastarg = *pos;
1.28 kristaps 1156: c = mdoc_args(mdoc, line, pos, buf, fl, &p);
1.16 kristaps 1157: if (ARGS_ERROR == c)
1158: return(0);
1159: if (ARGS_EOLN == c)
1.13 kristaps 1160: break;
1.19 kristaps 1161:
1.39 kristaps 1162: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1163: return(0);
1164: else if (MDOC_MAX != c) {
1165: if ( ! rewind_elem(mdoc, tok))
1166: return(0);
1167: return(mdoc_macro(mdoc, c, line,
1168: lastarg, pos, buf));
1169: }
1170:
1.28 kristaps 1171: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1172: return(0);
1.21 kristaps 1173: mdoc->next = MDOC_NEXT_SIBLING;
1.13 kristaps 1174: }
1175:
1.44 ! kristaps 1176: return(rewind_elem(mdoc, tok));
1.13 kristaps 1177: }
1.15 kristaps 1178:
1179:
1.16 kristaps 1180: /* ARGSUSED */
1.15 kristaps 1181: int
1182: macro_obsolete(MACRO_PROT_ARGS)
1183: {
1184:
1.38 kristaps 1185: return(mdoc_pwarn(mdoc, line, ppos, WARN_SYNTAX, "macro is obsolete"));
1.15 kristaps 1186: }
1.25 kristaps 1187:
1188:
1.44 ! kristaps 1189: /*
! 1190: * This is called at the end of parsing. It must traverse up the tree,
! 1191: * closing out open [implicit] scopes. Obviously, open explicit scopes
! 1192: * are errors.
! 1193: */
1.25 kristaps 1194: int
1195: macro_end(struct mdoc *mdoc)
1196: {
1.42 kristaps 1197: struct mdoc_node *n;
1.25 kristaps 1198:
1199: assert(mdoc->first);
1200: assert(mdoc->last);
1.42 kristaps 1201:
1202: /* Scan for open explicit scopes. */
1203:
1204: n = MDOC_VALID & mdoc->last->flags ?
1205: mdoc->last->parent : mdoc->last;
1206:
1207: for ( ; n; n = n->parent) {
1208: if (MDOC_BLOCK != n->type)
1209: continue;
1210: if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
1211: continue;
1212: mdoc_nerr(mdoc, n, "macro scope still open on exit");
1213: return(0);
1214: }
1215:
1.41 kristaps 1216: return(rewind_last(mdoc, mdoc->first));
1.25 kristaps 1217: }
CVSweb