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