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