Annotation of mandoc/macro.c, Revision 1.55
1.55 ! kristaps 1: /* $Id: macro.c,v 1.54 2009/02/27 09:39:40 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.55 ! kristaps 799: /* FIXME: .Fl and .Ar handling of `|'. */
! 800:
1.45 kristaps 801: if (ARGS_QWORD != w && mdoc_isdelim(p)) {
1.36 kristaps 802: if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
1.19 kristaps 803: mdoc_argv_free(argc, argv);
804: return(0);
805: }
806: lastpunct = 1;
1.36 kristaps 807: } else if (lastpunct) {
1.54 kristaps 808: c = mdoc_elem_alloc(mdoc, line, ppos,
809: tok, (size_t)argc, argv);
1.36 kristaps 810: if (0 == c) {
811: mdoc_argv_free(argc, argv);
812: return(0);
813: }
814: mdoc->next = MDOC_NEXT_CHILD;
815: lastpunct = 0;
1.19 kristaps 816: }
1.36 kristaps 817:
1.28 kristaps 818: if ( ! mdoc_word_alloc(mdoc, line, la, p))
819: return(0);
1.19 kristaps 820: mdoc->next = MDOC_NEXT_SIBLING;
1.2 kristaps 821: }
822:
1.19 kristaps 823: mdoc_argv_free(argc, argv);
1.2 kristaps 824:
1.36 kristaps 825: if (0 == lastpunct && ! rewind_elem(mdoc, tok))
1.7 kristaps 826: return(0);
1.19 kristaps 827: if (ppos > 1)
828: return(1);
1.41 kristaps 829: return(append_delims(mdoc, line, pos, buf));
1.5 kristaps 830: }
831:
832:
1.44 kristaps 833: /*
834: * Handle explicit-scope (having a different closure token) and implicit
835: * scope (closing out prior scopes when re-invoked) macros. These
836: * constitute the BLOCK type and usually span multiple lines. These
837: * always have HEAD and sometimes have BODY types. In the multi-line
838: * case:
839: *
840: * .Bd -ragged
841: * Text.
842: * .Fl macro
843: * Another.
844: * .Ed
845: *
846: * BLOCK (.Bd)
847: * HEAD
848: * BODY
849: * TEXT (`Text.')
850: * ELEMENT (.Fl)
851: * TEXT (`macro')
852: * TEXT (`Another.')
853: *
854: * Note that the `.It' macro, possibly the most difficult (as it has
855: * embedded scope, etc.) is handled by this routine.
856: */
1.51 kristaps 857: static int
1.16 kristaps 858: macro_scoped(MACRO_PROT_ARGS)
1.6 kristaps 859: {
1.48 kristaps 860: int c, lastarg, argc;
1.6 kristaps 861: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.24 kristaps 862: char *p;
1.6 kristaps 863:
1.16 kristaps 864: assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6 kristaps 865:
1.47 kristaps 866: /* First rewind extant implicit scope. */
867:
1.35 kristaps 868: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1.41 kristaps 869: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 870: return(0);
1.38 kristaps 871: if ( ! rewind_impblock(mdoc, tok, line, ppos))
1.16 kristaps 872: return(0);
1.35 kristaps 873: }
1.2 kristaps 874:
1.47 kristaps 875: /* Parse arguments. */
876:
1.16 kristaps 877: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
878: lastarg = *pos;
1.28 kristaps 879: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38 kristaps 880: if (ARGV_EOLN == c)
881: break;
882: if (ARGV_WORD == c) {
883: *pos = lastarg;
1.16 kristaps 884: break;
1.38 kristaps 885: } else if (ARGV_ARG == c)
1.16 kristaps 886: continue;
887: mdoc_argv_free(argc, argv);
1.8 kristaps 888: return(0);
1.16 kristaps 889: }
1.2 kristaps 890:
1.28 kristaps 891: if (MDOC_LINEARG_MAX == argc) {
1.41 kristaps 892: mdoc_argv_free(argc - 1, argv);
1.49 kristaps 893: return(perr(mdoc, line, ppos, EARGVLIM));
1.28 kristaps 894: }
895:
896: c = mdoc_block_alloc(mdoc, line, ppos,
897: tok, (size_t)argc, argv);
898: mdoc_argv_free(argc, argv);
899:
900: if (0 == c)
1.16 kristaps 901: return(0);
1.8 kristaps 902:
1.19 kristaps 903: mdoc->next = MDOC_NEXT_CHILD;
904:
1.24 kristaps 905: if (0 == buf[*pos]) {
1.28 kristaps 906: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
907: return(0);
1.51 kristaps 908: if ( ! rewind_subblock(MDOC_HEAD, mdoc,
909: tok, line, ppos))
1.28 kristaps 910: return(0);
911: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 912: return(0);
1.19 kristaps 913: mdoc->next = MDOC_NEXT_CHILD;
1.24 kristaps 914: return(1);
915: }
1.19 kristaps 916:
1.28 kristaps 917: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
918: return(0);
1.24 kristaps 919: mdoc->next = MDOC_NEXT_CHILD;
1.7 kristaps 920:
1.41 kristaps 921: for (;;) {
1.24 kristaps 922: lastarg = *pos;
1.48 kristaps 923: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 924:
1.24 kristaps 925: if (ARGS_ERROR == c)
1.19 kristaps 926: return(0);
1.24 kristaps 927: if (ARGS_EOLN == c)
928: break;
1.49 kristaps 929: if (ARGS_PHRASE == c) {
930: /*
931: if ( ! mdoc_phrase(mdoc, line, lastarg, buf))
932: return(0);
933: */
934: continue;
935: }
936:
1.48 kristaps 937: /* FIXME: if .It -column, the lookup must be for a
938: * sub-line component. BLAH. */
1.24 kristaps 939:
1.30 kristaps 940: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
941: return(0);
1.48 kristaps 942:
943: if (MDOC_MAX == c) {
1.28 kristaps 944: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
945: return(0);
1.24 kristaps 946: mdoc->next = MDOC_NEXT_SIBLING;
947: continue;
1.30 kristaps 948: }
1.2 kristaps 949:
1.26 kristaps 950: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.24 kristaps 951: return(0);
952: break;
1.7 kristaps 953: }
1.48 kristaps 954:
1.53 kristaps 955: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
956: return(0);
1.41 kristaps 957: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.24 kristaps 958: return(0);
959:
1.28 kristaps 960: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
961: return(0);
1.16 kristaps 962: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 963:
1.16 kristaps 964: return(1);
1.1 kristaps 965: }
1.5 kristaps 966:
1.7 kristaps 967:
1.44 kristaps 968: /*
969: * This handles a case of implicitly-scoped macro (BLOCK) limited to a
970: * single line. Instead of being closed out by a subsequent call to
971: * another macro, the scope is closed at the end of line. These don't
972: * have BODY or TAIL types. Notice that the punctuation falls outside
973: * of the HEAD type.
974: *
975: * .Qq a Fl b Ar d ; ;
976: *
977: * BLOCK (Qq)
978: * HEAD
979: * TEXT (`a')
980: * ELEMENT (.Fl)
981: * TEXT (`b')
982: * ELEMENT (.Ar)
983: * TEXT (`d')
984: * TEXT (`;')
985: * TEXT (`;')
986: */
1.51 kristaps 987: static int
1.16 kristaps 988: macro_scoped_line(MACRO_PROT_ARGS)
1.7 kristaps 989: {
1.41 kristaps 990: int lastarg, c;
1.8 kristaps 991: char *p;
1.7 kristaps 992:
1.28 kristaps 993: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
994: return(0);
1.16 kristaps 995: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 996:
1.28 kristaps 997: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
998: return(0);
1.44 kristaps 999: mdoc->next = MDOC_NEXT_SIBLING;
1000: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1001: return(0);
1.16 kristaps 1002: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 1003:
1.19 kristaps 1004: /* XXX - no known argument macros. */
1005:
1.41 kristaps 1006: lastarg = ppos;
1007: for (;;) {
1.19 kristaps 1008: lastarg = *pos;
1.48 kristaps 1009: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1010: assert(ARGS_PHRASE != c);
1.8 kristaps 1011:
1.19 kristaps 1012: if (ARGS_ERROR == c)
1013: return(0);
1014: if (ARGS_PUNCT == c)
1015: break;
1016: if (ARGS_EOLN == c)
1017: break;
1.8 kristaps 1018:
1.30 kristaps 1019: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1020: return(0);
1021: else if (MDOC_MAX == c) {
1.28 kristaps 1022: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1023: return(0);
1.19 kristaps 1024: mdoc->next = MDOC_NEXT_SIBLING;
1025: continue;
1.30 kristaps 1026: }
1.8 kristaps 1027:
1.26 kristaps 1028: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1029: return(0);
1.8 kristaps 1030: break;
1031: }
1032:
1.19 kristaps 1033: if (1 == ppos) {
1.44 kristaps 1034: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.16 kristaps 1035: return(0);
1.41 kristaps 1036: if ( ! append_delims(mdoc, line, pos, buf))
1.8 kristaps 1037: return(0);
1.44 kristaps 1038: } else if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 1039: return(0);
1.38 kristaps 1040: return(rewind_impblock(mdoc, tok, line, ppos));
1.22 kristaps 1041: }
1042:
1043:
1.44 kristaps 1044: /*
1045: * A constant-scoped macro is like a simple-scoped macro (mdoc_scoped)
1046: * except that it doesn't handle implicit scopes and explicit ones have
1047: * a fixed number of TEXT children to the BODY.
1048: *
1049: * .Fl a So b Sc ;
1050: *
1051: * ELEMENT (.Fl)
1052: * TEXT (`a')
1053: * BLOCK (.So)
1054: * HEAD
1055: * BODY
1056: * TEXT (`b')
1057: * TEXT (';')
1058: */
1.51 kristaps 1059: static int
1.22 kristaps 1060: macro_constant_scoped(MACRO_PROT_ARGS)
1061: {
1062: int lastarg, flushed, j, c, maxargs;
1063: char *p;
1064:
1065: lastarg = ppos;
1066: flushed = 0;
1067:
1068: switch (tok) {
1069: case (MDOC_Eo):
1070: maxargs = 1;
1071: break;
1072: default:
1073: maxargs = 0;
1074: break;
1075: }
1076:
1.28 kristaps 1077: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
1078: return(0);
1.22 kristaps 1079: mdoc->next = MDOC_NEXT_CHILD;
1080:
1081: if (0 == maxargs) {
1.28 kristaps 1082: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1083: return(0);
1.41 kristaps 1084: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 1085: return(0);
1086: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 1087: return(0);
1.22 kristaps 1088: flushed = 1;
1.28 kristaps 1089: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1090: return(0);
1.22 kristaps 1091:
1092: mdoc->next = MDOC_NEXT_CHILD;
1093:
1.41 kristaps 1094: for (j = 0; /* No sentinel. */; j++) {
1.22 kristaps 1095: lastarg = *pos;
1096:
1097: if (j == maxargs && ! flushed) {
1.41 kristaps 1098: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 1099: return(0);
1100: flushed = 1;
1.28 kristaps 1101: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1102: return(0);
1.22 kristaps 1103: mdoc->next = MDOC_NEXT_CHILD;
1104: }
1105:
1.48 kristaps 1106: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1107: assert(ARGS_PHRASE != c);
1108:
1.22 kristaps 1109: if (ARGS_ERROR == c)
1110: return(0);
1111: if (ARGS_PUNCT == c)
1112: break;
1113: if (ARGS_EOLN == c)
1114: break;
1115:
1.30 kristaps 1116: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1117: return(0);
1118: else if (MDOC_MAX != c) {
1.22 kristaps 1119: if ( ! flushed) {
1.51 kristaps 1120: if ( ! rewind_subblock(MDOC_HEAD, mdoc,
1121: tok, line, ppos))
1.22 kristaps 1122: return(0);
1123: flushed = 1;
1.51 kristaps 1124: if ( ! mdoc_body_alloc(mdoc, line,
1125: ppos, tok))
1.28 kristaps 1126: return(0);
1.22 kristaps 1127: mdoc->next = MDOC_NEXT_CHILD;
1128: }
1.51 kristaps 1129: if ( ! mdoc_macro(mdoc, c, line, lastarg,
1130: pos, buf))
1.22 kristaps 1131: return(0);
1132: break;
1133: }
1134:
1135: if ( ! flushed && mdoc_isdelim(p)) {
1.51 kristaps 1136: if ( ! rewind_subblock(MDOC_HEAD, mdoc,
1137: tok, line, ppos))
1.22 kristaps 1138: return(0);
1139: flushed = 1;
1.28 kristaps 1140: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1141: return(0);
1.22 kristaps 1142: mdoc->next = MDOC_NEXT_CHILD;
1143: }
1144:
1.28 kristaps 1145: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1146: return(0);
1.22 kristaps 1147: mdoc->next = MDOC_NEXT_SIBLING;
1148: }
1149:
1150: if ( ! flushed) {
1.41 kristaps 1151: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 1152: return(0);
1153: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.22 kristaps 1154: return(0);
1155: mdoc->next = MDOC_NEXT_CHILD;
1156: }
1157:
1158: if (ppos > 1)
1159: return(1);
1.41 kristaps 1160: return(append_delims(mdoc, line, pos, buf));
1.7 kristaps 1161: }
1.8 kristaps 1162:
1.10 kristaps 1163:
1.44 kristaps 1164: /*
1165: * A delimited constant is very similar to the macros parsed by
1166: * macro_text except that, in the event of punctuation, the macro isn't
1167: * "re-opened" as it is in macro_text. Also, these macros have a fixed
1168: * number of parameters.
1169: *
1170: * .Fl a No b
1171: *
1172: * ELEMENT (.Fl)
1173: * TEXT (`a')
1174: * ELEMENT (.No)
1175: * TEXT (`b')
1176: */
1.51 kristaps 1177: static int
1.10 kristaps 1178: macro_constant_delimited(MACRO_PROT_ARGS)
1179: {
1.50 kristaps 1180: int lastarg, flushed, j, c, maxargs, argc,
1181: igndelim;
1.24 kristaps 1182: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.13 kristaps 1183: char *p;
1.10 kristaps 1184:
1185: lastarg = ppos;
1186: flushed = 0;
1187:
1188: switch (tok) {
1.16 kristaps 1189: case (MDOC_No):
1190: /* FALLTHROUGH */
1191: case (MDOC_Ns):
1192: /* FALLTHROUGH */
1.10 kristaps 1193: case (MDOC_Ux):
1.24 kristaps 1194: /* FALLTHROUGH */
1195: case (MDOC_St):
1.10 kristaps 1196: maxargs = 0;
1197: break;
1198: default:
1199: maxargs = 1;
1200: break;
1201: }
1202:
1.50 kristaps 1203: switch (tok) {
1204: case (MDOC_Pf):
1205: igndelim = 1;
1206: break;
1207: default:
1208: igndelim = 0;
1209: break;
1210: }
1211:
1.24 kristaps 1212: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1213: lastarg = *pos;
1.28 kristaps 1214: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38 kristaps 1215: if (ARGV_EOLN == c)
1.24 kristaps 1216: break;
1.38 kristaps 1217: if (ARGV_WORD == c) {
1218: *pos = lastarg;
1219: break;
1220: } else if (ARGV_ARG == c)
1.24 kristaps 1221: continue;
1222: mdoc_argv_free(argc, argv);
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.54 kristaps 1231: c = mdoc_elem_alloc(mdoc, line, ppos,
1232: tok, (size_t)argc, argv);
1233:
1.28 kristaps 1234: mdoc_argv_free(argc, argv);
1235:
1236: if (0 == c)
1.24 kristaps 1237: return(0);
1238:
1.19 kristaps 1239: mdoc->next = MDOC_NEXT_CHILD;
1.10 kristaps 1240:
1.41 kristaps 1241: for (j = 0; /* No sentinel. */; j++) {
1.19 kristaps 1242: lastarg = *pos;
1.10 kristaps 1243:
1.19 kristaps 1244: if (j == maxargs && ! flushed) {
1.28 kristaps 1245: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1246: return(0);
1247: flushed = 1;
1248: }
1.11 kristaps 1249:
1.48 kristaps 1250: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1251: assert(ARGS_PHRASE != c);
1252:
1.19 kristaps 1253: if (ARGS_ERROR == c)
1.10 kristaps 1254: return(0);
1.19 kristaps 1255: if (ARGS_PUNCT == c)
1256: break;
1257: if (ARGS_EOLN == c)
1258: break;
1259:
1.30 kristaps 1260: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1261: return(0);
1262: else if (MDOC_MAX != c) {
1.28 kristaps 1263: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1264: return(0);
1265: flushed = 1;
1.26 kristaps 1266: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1267: return(0);
1268: break;
1269: }
1.10 kristaps 1270:
1.50 kristaps 1271: if ( ! flushed && mdoc_isdelim(p) && ! igndelim) {
1.28 kristaps 1272: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1273: return(0);
1274: flushed = 1;
1275: }
1276:
1.28 kristaps 1277: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1278: return(0);
1.19 kristaps 1279: mdoc->next = MDOC_NEXT_SIBLING;
1.10 kristaps 1280: }
1281:
1.42 kristaps 1282: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1283: return(0);
1.11 kristaps 1284:
1.19 kristaps 1285: if (ppos > 1)
1286: return(1);
1.41 kristaps 1287: return(append_delims(mdoc, line, pos, buf));
1.10 kristaps 1288: }
1.11 kristaps 1289:
1290:
1.44 kristaps 1291: /*
1292: * A constant macro is the simplest classification. It spans an entire
1293: * line.
1294: */
1.51 kristaps 1295: static int
1.11 kristaps 1296: macro_constant(MACRO_PROT_ARGS)
1297: {
1.48 kristaps 1298: int c, w, la, argc;
1.43 kristaps 1299: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1300: char *p;
1.44 kristaps 1301:
1302: assert( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.11 kristaps 1303:
1.16 kristaps 1304: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1.45 kristaps 1305: la = *pos;
1.28 kristaps 1306: c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.16 kristaps 1307: if (ARGV_EOLN == c)
1308: break;
1.38 kristaps 1309: if (ARGV_WORD == c) {
1.45 kristaps 1310: *pos = la;
1.38 kristaps 1311: break;
1312: } else if (ARGV_ARG == c)
1.16 kristaps 1313: continue;
1.11 kristaps 1314:
1.16 kristaps 1315: mdoc_argv_free(argc, argv);
1.11 kristaps 1316: return(0);
1317: }
1318:
1.41 kristaps 1319: if (MDOC_LINEARG_MAX == argc) {
1320: mdoc_argv_free(argc - 1, argv);
1.49 kristaps 1321: return(perr(mdoc, line, ppos, EARGVLIM));
1.41 kristaps 1322: }
1323:
1.54 kristaps 1324: c = mdoc_elem_alloc(mdoc, line, ppos,
1325: tok, (size_t)argc, argv);
1326:
1.28 kristaps 1327: mdoc_argv_free(argc, argv);
1328:
1329: if (0 == c)
1330: return(0);
1.11 kristaps 1331:
1.19 kristaps 1332: mdoc->next = MDOC_NEXT_CHILD;
1333:
1.41 kristaps 1334: for (;;) {
1.45 kristaps 1335: la = *pos;
1.48 kristaps 1336: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1337: assert(ARGS_PHRASE != c);
1338:
1.45 kristaps 1339: if (ARGS_ERROR == w)
1.16 kristaps 1340: return(0);
1.45 kristaps 1341: if (ARGS_EOLN == w)
1.13 kristaps 1342: break;
1.19 kristaps 1343:
1.45 kristaps 1344: c = ARGS_QWORD == w ? MDOC_MAX :
1345: lookup(mdoc, line, la, tok, p);
1346:
1347: if (MDOC_MAX != c && -1 != c) {
1.39 kristaps 1348: if ( ! rewind_elem(mdoc, tok))
1349: return(0);
1.45 kristaps 1350: return(mdoc_macro(mdoc, c, line, la, pos, buf));
1351: } else if (-1 == c)
1352: return(0);
1.39 kristaps 1353:
1.45 kristaps 1354: if ( ! mdoc_word_alloc(mdoc, line, la, p))
1.28 kristaps 1355: return(0);
1.21 kristaps 1356: mdoc->next = MDOC_NEXT_SIBLING;
1.13 kristaps 1357: }
1358:
1.44 kristaps 1359: return(rewind_elem(mdoc, tok));
1.13 kristaps 1360: }
1.15 kristaps 1361:
1362:
1.16 kristaps 1363: /* ARGSUSED */
1.51 kristaps 1364: static int
1.15 kristaps 1365: macro_obsolete(MACRO_PROT_ARGS)
1366: {
1367:
1.49 kristaps 1368: return(pwarn(mdoc, line, ppos, WOBS));
1.15 kristaps 1369: }
1.25 kristaps 1370:
1371:
1.44 kristaps 1372: /*
1373: * This is called at the end of parsing. It must traverse up the tree,
1374: * closing out open [implicit] scopes. Obviously, open explicit scopes
1375: * are errors.
1376: */
1.25 kristaps 1377: int
1378: macro_end(struct mdoc *mdoc)
1379: {
1.42 kristaps 1380: struct mdoc_node *n;
1.25 kristaps 1381:
1382: assert(mdoc->first);
1383: assert(mdoc->last);
1.42 kristaps 1384:
1385: /* Scan for open explicit scopes. */
1386:
1387: n = MDOC_VALID & mdoc->last->flags ?
1388: mdoc->last->parent : mdoc->last;
1389:
1390: for ( ; n; n = n->parent) {
1391: if (MDOC_BLOCK != n->type)
1392: continue;
1393: if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
1394: continue;
1.51 kristaps 1395: return(mdoc_nerr(mdoc, n,
1396: "macro scope still open on exit"));
1.42 kristaps 1397: }
1398:
1.41 kristaps 1399: return(rewind_last(mdoc, mdoc->first));
1.25 kristaps 1400: }
CVSweb