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