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