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