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