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