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