Annotation of mandoc/macro.c, Revision 1.75
1.75 ! kristaps 1: /* $Id: macro.c,v 1.74 2009/03/21 09:20:15 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:
1.74 kristaps 409: /*
410: * Rewind rules. This indicates whether to stop rewinding
411: * (REWIND_HALT) without touching our current scope, stop rewinding and
412: * close our current scope (REWIND_REWIND), or continue (REWIND_NOHALT).
413: * The scope-closing and so on occurs in the various rew_* routines.
414: */
415: static int
1.72 kristaps 416: rew_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
1.35 kristaps 417: {
418:
419: if (MDOC_ROOT == p->type)
420: return(REWIND_HALT);
1.42 kristaps 421: if (MDOC_VALID & p->flags)
1.35 kristaps 422: return(REWIND_NOHALT);
423:
424: switch (tok) {
425: case (MDOC_Aq):
426: /* FALLTHROUGH */
427: case (MDOC_Bq):
428: /* FALLTHROUGH */
1.66 kristaps 429: case (MDOC_Brq):
430: /* FALLTHROUGH */
1.35 kristaps 431: case (MDOC_D1):
432: /* FALLTHROUGH */
433: case (MDOC_Dl):
434: /* FALLTHROUGH */
435: case (MDOC_Dq):
436: /* FALLTHROUGH */
437: case (MDOC_Op):
438: /* FALLTHROUGH */
439: case (MDOC_Pq):
440: /* FALLTHROUGH */
441: case (MDOC_Ql):
442: /* FALLTHROUGH */
443: case (MDOC_Qq):
444: /* FALLTHROUGH */
445: case (MDOC_Sq):
1.44 kristaps 446: assert(MDOC_HEAD != type);
1.35 kristaps 447: assert(MDOC_TAIL != type);
448: if (type == p->type && tok == p->tok)
449: return(REWIND_REWIND);
450: break;
451: case (MDOC_It):
452: assert(MDOC_TAIL != type);
453: if (type == p->type && tok == p->tok)
454: return(REWIND_REWIND);
1.36 kristaps 455: if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
1.35 kristaps 456: return(REWIND_HALT);
457: break;
458: case (MDOC_Sh):
1.36 kristaps 459: if (type == p->type && tok == p->tok)
460: return(REWIND_REWIND);
461: break;
1.35 kristaps 462: case (MDOC_Ss):
1.36 kristaps 463: assert(MDOC_TAIL != type);
1.35 kristaps 464: if (type == p->type && tok == p->tok)
465: return(REWIND_REWIND);
1.36 kristaps 466: if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
467: return(REWIND_HALT);
1.35 kristaps 468: break;
469: case (MDOC_Ao):
470: /* FALLTHROUGH */
471: case (MDOC_Bd):
472: /* FALLTHROUGH */
473: case (MDOC_Bf):
474: /* FALLTHROUGH */
475: case (MDOC_Bk):
476: /* FALLTHROUGH */
477: case (MDOC_Bl):
478: /* FALLTHROUGH */
479: case (MDOC_Bo):
480: /* FALLTHROUGH */
1.66 kristaps 481: case (MDOC_Bro):
482: /* FALLTHROUGH */
1.35 kristaps 483: case (MDOC_Do):
484: /* FALLTHROUGH */
485: case (MDOC_Eo):
486: /* FALLTHROUGH */
487: case (MDOC_Fo):
488: /* FALLTHROUGH */
489: case (MDOC_Oo):
490: /* FALLTHROUGH */
491: case (MDOC_Po):
492: /* FALLTHROUGH */
493: case (MDOC_Qo):
494: /* FALLTHROUGH */
495: case (MDOC_Rs):
496: /* FALLTHROUGH */
497: case (MDOC_So):
498: /* FALLTHROUGH */
499: case (MDOC_Xo):
500: if (type == p->type && tok == p->tok)
501: return(REWIND_REWIND);
502: break;
503:
504: /* Multi-line explicit scope close. */
505: case (MDOC_Ac):
506: /* FALLTHROUGH */
507: case (MDOC_Bc):
508: /* FALLTHROUGH */
1.66 kristaps 509: case (MDOC_Brc):
510: /* FALLTHROUGH */
1.35 kristaps 511: case (MDOC_Dc):
512: /* FALLTHROUGH */
513: case (MDOC_Ec):
514: /* FALLTHROUGH */
515: case (MDOC_Ed):
516: /* FALLTHROUGH */
517: case (MDOC_Ek):
518: /* FALLTHROUGH */
519: case (MDOC_El):
520: /* FALLTHROUGH */
521: case (MDOC_Fc):
522: /* FALLTHROUGH */
523: case (MDOC_Ef):
524: /* FALLTHROUGH */
525: case (MDOC_Oc):
526: /* FALLTHROUGH */
527: case (MDOC_Pc):
528: /* FALLTHROUGH */
529: case (MDOC_Qc):
530: /* FALLTHROUGH */
531: case (MDOC_Re):
532: /* FALLTHROUGH */
533: case (MDOC_Sc):
534: /* FALLTHROUGH */
535: case (MDOC_Xc):
1.72 kristaps 536: if (type == p->type && rew_alt(tok) == p->tok)
1.35 kristaps 537: return(REWIND_REWIND);
538: break;
539: default:
540: abort();
541: /* NOTREACHED */
542: }
543:
544: return(REWIND_NOHALT);
545: }
546:
547:
1.74 kristaps 548: /*
549: * See if we can break an encountered scope (the rew_dohalt has returned
550: * REWIND_NOHALT).
551: */
1.35 kristaps 552: static int
1.72 kristaps 553: rew_dobreak(int tok, const struct mdoc_node *p)
1.35 kristaps 554: {
555:
556: assert(MDOC_ROOT != p->type);
557: if (MDOC_ELEM == p->type)
558: return(1);
559: if (MDOC_TEXT == p->type)
560: return(1);
1.42 kristaps 561: if (MDOC_VALID & p->flags)
562: return(1);
1.35 kristaps 563:
564: switch (tok) {
565: case (MDOC_It):
566: return(MDOC_It == p->tok);
567: case (MDOC_Ss):
568: return(MDOC_Ss == p->tok);
569: case (MDOC_Sh):
570: if (MDOC_Ss == p->tok)
571: return(1);
572: return(MDOC_Sh == p->tok);
1.36 kristaps 573: case (MDOC_El):
574: if (MDOC_It == p->tok)
575: return(1);
576: break;
1.74 kristaps 577: case (MDOC_Oc):
578: /* XXX - experimental! */
579: if (MDOC_Op == p->tok)
580: return(1);
581: break;
1.36 kristaps 582: default:
583: break;
1.35 kristaps 584: }
585:
586: if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
1.72 kristaps 587: return(p->tok == rew_alt(tok));
1.35 kristaps 588: else if (MDOC_BLOCK == p->type)
589: return(1);
590:
591: return(tok == p->tok);
592: }
593:
594:
595: static int
1.72 kristaps 596: rew_elem(struct mdoc *mdoc, int tok)
1.19 kristaps 597: {
598: struct mdoc_node *n;
1.2 kristaps 599:
1.19 kristaps 600: n = mdoc->last;
601: if (MDOC_ELEM != n->type)
602: n = n->parent;
603: assert(MDOC_ELEM == n->type);
1.32 kristaps 604: assert(tok == n->tok);
1.19 kristaps 605:
1.72 kristaps 606: return(rew_last(mdoc, n));
1.19 kristaps 607: }
1.6 kristaps 608:
609:
610: static int
1.72 kristaps 611: rew_subblock(enum mdoc_type type, struct mdoc *mdoc,
1.41 kristaps 612: int tok, int line, int ppos)
1.22 kristaps 613: {
614: struct mdoc_node *n;
1.35 kristaps 615: int c;
1.28 kristaps 616:
1.6 kristaps 617: /* LINTED */
1.42 kristaps 618: for (n = mdoc->last; n; n = n->parent) {
1.72 kristaps 619: c = rew_dohalt(tok, type, n);
1.35 kristaps 620: if (REWIND_HALT == c)
621: return(1);
622: if (REWIND_REWIND == c)
1.6 kristaps 623: break;
1.72 kristaps 624: else if (rew_dobreak(tok, n))
1.7 kristaps 625: continue;
1.72 kristaps 626: if ( ! swarn(mdoc, type, line, ppos, n))
1.59 kristaps 627: return(0);
1.6 kristaps 628: }
629:
1.25 kristaps 630: assert(n);
1.72 kristaps 631: return(rew_last(mdoc, n));
1.6 kristaps 632: }
633:
634:
635: static int
1.72 kristaps 636: rew_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.6 kristaps 637: {
1.7 kristaps 638: struct mdoc_node *n;
1.35 kristaps 639: int c;
1.6 kristaps 640:
1.7 kristaps 641: /* LINTED */
1.42 kristaps 642: for (n = mdoc->last; n; n = n->parent) {
1.72 kristaps 643: c = rew_dohalt(tok, MDOC_BLOCK, n);
1.35 kristaps 644: if (REWIND_HALT == c)
1.49 kristaps 645: return(perr(mdoc, line, ppos, ENOCTX));
1.35 kristaps 646: if (REWIND_REWIND == c)
1.16 kristaps 647: break;
1.72 kristaps 648: else if (rew_dobreak(tok, n))
1.22 kristaps 649: continue;
1.72 kristaps 650: if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n))
1.59 kristaps 651: return(0);
1.16 kristaps 652: }
653:
1.28 kristaps 654: assert(n);
1.72 kristaps 655: return(rew_last(mdoc, n));
1.21 kristaps 656: }
657:
658:
659: static int
1.72 kristaps 660: rew_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.21 kristaps 661: {
662: struct mdoc_node *n;
1.35 kristaps 663: int c;
1.21 kristaps 664:
665: /* LINTED */
1.42 kristaps 666: for (n = mdoc->last; n; n = n->parent) {
1.72 kristaps 667: c = rew_dohalt(tok, MDOC_BLOCK, n);
1.35 kristaps 668: if (REWIND_HALT == c)
669: return(1);
670: else if (REWIND_REWIND == c)
1.21 kristaps 671: break;
1.72 kristaps 672: else if (rew_dobreak(tok, n))
1.21 kristaps 673: continue;
1.72 kristaps 674: if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n))
1.59 kristaps 675: return(0);
1.21 kristaps 676: }
677:
1.35 kristaps 678: assert(n);
1.72 kristaps 679: return(rew_last(mdoc, n));
1.16 kristaps 680: }
681:
682:
1.22 kristaps 683: static int
1.41 kristaps 684: append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
1.22 kristaps 685: {
686: int c, lastarg;
687: char *p;
688:
689: if (0 == buf[*pos])
690: return(1);
691:
692: for (;;) {
693: lastarg = *pos;
1.28 kristaps 694: c = mdoc_args(mdoc, line, pos, buf, 0, &p);
1.49 kristaps 695: assert(ARGS_PHRASE != c);
696:
1.22 kristaps 697: if (ARGS_ERROR == c)
698: return(0);
699: else if (ARGS_EOLN == c)
700: break;
701: assert(mdoc_isdelim(p));
1.28 kristaps 702: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
703: return(0);
1.22 kristaps 704: mdoc->next = MDOC_NEXT_SIBLING;
705: }
706:
707: return(1);
708: }
709:
710:
1.44 kristaps 711: /*
1.72 kristaps 712: * Close out block partial/full explicit.
1.44 kristaps 713: */
1.51 kristaps 714: static int
1.72 kristaps 715: blk_exp_close(MACRO_PROT_ARGS)
1.19 kristaps 716: {
1.72 kristaps 717: int j, c, lastarg, maxargs, flushed;
1.22 kristaps 718: char *p;
1.19 kristaps 719:
720: switch (tok) {
1.22 kristaps 721: case (MDOC_Ec):
722: maxargs = 1;
723: break;
724: default:
725: maxargs = 0;
726: break;
727: }
728:
729: if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
1.35 kristaps 730: if (0 == buf[*pos]) {
1.72 kristaps 731: if ( ! rew_subblock(MDOC_BODY, mdoc,
1.51 kristaps 732: tok, line, ppos))
1.35 kristaps 733: return(0);
1.72 kristaps 734: return(rew_expblock(mdoc, tok, line, ppos));
1.35 kristaps 735: }
1.49 kristaps 736: return(perr(mdoc, line, ppos, ENOPARMS));
1.22 kristaps 737: }
1.19 kristaps 738:
1.72 kristaps 739: if ( ! rew_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.22 kristaps 740: return(0);
1.19 kristaps 741:
1.22 kristaps 742: if (maxargs > 0) {
1.72 kristaps 743: if ( ! mdoc_tail_alloc(mdoc, line,
744: ppos, rew_alt(tok)))
1.28 kristaps 745: return(0);
1.22 kristaps 746: mdoc->next = MDOC_NEXT_CHILD;
747: }
1.15 kristaps 748:
1.72 kristaps 749: for (lastarg = ppos, flushed = j = 0; ; j++) {
1.15 kristaps 750: lastarg = *pos;
1.22 kristaps 751:
752: if (j == maxargs && ! flushed) {
1.72 kristaps 753: if ( ! rew_expblock(mdoc, tok, line, ppos))
1.22 kristaps 754: return(0);
755: flushed = 1;
756: }
757:
1.48 kristaps 758: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 759:
1.15 kristaps 760: if (ARGS_ERROR == c)
761: return(0);
1.22 kristaps 762: if (ARGS_PUNCT == c)
763: break;
764: if (ARGS_EOLN == c)
765: break;
766:
1.30 kristaps 767: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
768: return(0);
769: else if (MDOC_MAX != c) {
1.22 kristaps 770: if ( ! flushed) {
1.72 kristaps 771: if ( ! rew_expblock(mdoc, tok,
1.51 kristaps 772: line, ppos))
1.22 kristaps 773: return(0);
774: flushed = 1;
775: }
1.26 kristaps 776: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.22 kristaps 777: return(0);
1.15 kristaps 778: break;
1.30 kristaps 779: }
1.22 kristaps 780:
1.28 kristaps 781: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
782: return(0);
1.16 kristaps 783: mdoc->next = MDOC_NEXT_SIBLING;
1.15 kristaps 784: }
1.2 kristaps 785:
1.72 kristaps 786: if ( ! flushed && ! rew_expblock(mdoc, tok, line, ppos))
1.28 kristaps 787: return(0);
1.22 kristaps 788:
789: if (ppos > 1)
790: return(1);
1.41 kristaps 791: return(append_delims(mdoc, line, pos, buf));
1.1 kristaps 792: }
793:
1.2 kristaps 794:
1.44 kristaps 795: /*
1.72 kristaps 796: * In-line macros where reserved words cause scope close-reopen.
1.44 kristaps 797: */
1.51 kristaps 798: static int
1.72 kristaps 799: in_line(MACRO_PROT_ARGS)
1.13 kristaps 800: {
1.58 kristaps 801: int la, lastpunct, c, w;
802: struct mdoc_arg *arg;
1.19 kristaps 803: char *p;
1.13 kristaps 804:
1.72 kristaps 805: for (la = ppos, arg = NULL;; ) {
1.28 kristaps 806: la = *pos;
1.58 kristaps 807: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.72 kristaps 808:
1.38 kristaps 809: if (ARGV_WORD == c) {
810: *pos = la;
811: break;
1.72 kristaps 812: }
813:
814: if (ARGV_EOLN == c)
815: break;
816: if (ARGV_ARG == c)
1.19 kristaps 817: continue;
1.72 kristaps 818:
1.58 kristaps 819: mdoc_argv_free(arg);
1.14 kristaps 820: return(0);
1.10 kristaps 821: }
822:
1.58 kristaps 823: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1.19 kristaps 824: return(0);
1.28 kristaps 825: mdoc->next = MDOC_NEXT_CHILD;
826:
1.72 kristaps 827: for (lastpunct = 0;; ) {
1.28 kristaps 828: la = *pos;
1.48 kristaps 829: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 830:
1.58 kristaps 831: if (ARGS_ERROR == w)
1.7 kristaps 832: return(0);
1.45 kristaps 833: if (ARGS_EOLN == w)
1.19 kristaps 834: break;
1.45 kristaps 835: if (ARGS_PUNCT == w)
1.19 kristaps 836: break;
1.2 kristaps 837:
1.65 kristaps 838: /* Quoted words shouldn't be looked-up. */
839:
1.45 kristaps 840: c = ARGS_QWORD == w ? MDOC_MAX :
841: lookup(mdoc, line, la, tok, p);
842:
1.65 kristaps 843: /* MDOC_MAX (not a macro) or -1 (error). */
844:
1.45 kristaps 845: if (MDOC_MAX != c && -1 != c) {
1.72 kristaps 846: if (0 == lastpunct && ! rew_elem(mdoc, tok))
1.19 kristaps 847: return(0);
1.28 kristaps 848: c = mdoc_macro(mdoc, c, line, la, pos, buf);
849: if (0 == c)
1.19 kristaps 850: return(0);
851: if (ppos > 1)
852: return(1);
1.41 kristaps 853: return(append_delims(mdoc, line, pos, buf));
1.58 kristaps 854: } else if (-1 == c)
1.45 kristaps 855: return(0);
1.2 kristaps 856:
1.65 kristaps 857: /* Non-quote-enclosed punctuation. */
1.55 kristaps 858:
1.45 kristaps 859: if (ARGS_QWORD != w && mdoc_isdelim(p)) {
1.72 kristaps 860: if (0 == lastpunct && ! rew_elem(mdoc, tok))
1.19 kristaps 861: return(0);
862: lastpunct = 1;
1.36 kristaps 863: } else if (lastpunct) {
1.58 kristaps 864: c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
865:
866: if (0 == c)
1.36 kristaps 867: return(0);
1.58 kristaps 868:
1.36 kristaps 869: mdoc->next = MDOC_NEXT_CHILD;
870: lastpunct = 0;
1.19 kristaps 871: }
1.36 kristaps 872:
1.28 kristaps 873: if ( ! mdoc_word_alloc(mdoc, line, la, p))
874: return(0);
1.19 kristaps 875: mdoc->next = MDOC_NEXT_SIBLING;
1.2 kristaps 876: }
877:
1.72 kristaps 878: if (0 == lastpunct && ! rew_elem(mdoc, tok))
1.7 kristaps 879: return(0);
1.19 kristaps 880: if (ppos > 1)
881: return(1);
1.41 kristaps 882: return(append_delims(mdoc, line, pos, buf));
1.5 kristaps 883: }
884:
885:
1.44 kristaps 886: /*
1.72 kristaps 887: * Block full-explicit and full-implicit.
1.44 kristaps 888: */
1.51 kristaps 889: static int
1.72 kristaps 890: blk_full(MACRO_PROT_ARGS)
1.6 kristaps 891: {
1.67 kristaps 892: int c, lastarg, reopen;
1.58 kristaps 893: struct mdoc_arg *arg;
1.24 kristaps 894: char *p;
1.6 kristaps 895:
1.35 kristaps 896: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1.72 kristaps 897: if ( ! rew_subblock(MDOC_BODY, mdoc,
898: tok, line, ppos))
1.35 kristaps 899: return(0);
1.72 kristaps 900: if ( ! rew_impblock(mdoc, tok, line, ppos))
1.16 kristaps 901: return(0);
1.35 kristaps 902: }
1.2 kristaps 903:
1.72 kristaps 904: for (arg = NULL;; ) {
1.16 kristaps 905: lastarg = *pos;
1.58 kristaps 906: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.72 kristaps 907:
1.38 kristaps 908: if (ARGV_WORD == c) {
909: *pos = lastarg;
1.16 kristaps 910: break;
1.72 kristaps 911: }
912:
913: if (ARGV_EOLN == c)
914: break;
915: if (ARGV_ARG == c)
1.16 kristaps 916: continue;
1.72 kristaps 917:
1.58 kristaps 918: mdoc_argv_free(arg);
1.8 kristaps 919: return(0);
1.16 kristaps 920: }
1.2 kristaps 921:
1.58 kristaps 922: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
1.16 kristaps 923: return(0);
1.19 kristaps 924: mdoc->next = MDOC_NEXT_CHILD;
925:
1.24 kristaps 926: if (0 == buf[*pos]) {
1.28 kristaps 927: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
928: return(0);
1.72 kristaps 929: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1.51 kristaps 930: tok, line, ppos))
1.28 kristaps 931: return(0);
932: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 933: return(0);
1.19 kristaps 934: mdoc->next = MDOC_NEXT_CHILD;
1.24 kristaps 935: return(1);
936: }
1.19 kristaps 937:
1.28 kristaps 938: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
939: return(0);
1.24 kristaps 940: mdoc->next = MDOC_NEXT_CHILD;
1.7 kristaps 941:
1.72 kristaps 942: for (reopen = 0;; ) {
1.24 kristaps 943: lastarg = *pos;
1.48 kristaps 944: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 945:
1.24 kristaps 946: if (ARGS_ERROR == c)
1.19 kristaps 947: return(0);
1.24 kristaps 948: if (ARGS_EOLN == c)
949: break;
1.49 kristaps 950: if (ARGS_PHRASE == c) {
1.72 kristaps 951: if (reopen && ! mdoc_head_alloc
952: (mdoc, line, ppos, tok))
1.67 kristaps 953: return(0);
954: mdoc->next = MDOC_NEXT_CHILD;
1.49 kristaps 955: /*
1.67 kristaps 956: * Phrases are self-contained macro phrases used
957: * in the columnar output of a macro. They need
958: * special handling.
959: */
1.72 kristaps 960: if ( ! phrase(mdoc, line, lastarg, buf))
1.67 kristaps 961: return(0);
1.72 kristaps 962: if ( ! rew_subblock(MDOC_HEAD, mdoc,
963: tok, line, ppos))
1.49 kristaps 964: return(0);
1.67 kristaps 965:
966: reopen = 1;
1.49 kristaps 967: continue;
968: }
969:
1.30 kristaps 970: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
971: return(0);
1.48 kristaps 972:
973: if (MDOC_MAX == c) {
1.28 kristaps 974: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
975: return(0);
1.24 kristaps 976: mdoc->next = MDOC_NEXT_SIBLING;
977: continue;
1.30 kristaps 978: }
1.2 kristaps 979:
1.26 kristaps 980: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.24 kristaps 981: return(0);
982: break;
1.7 kristaps 983: }
1.48 kristaps 984:
1.53 kristaps 985: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
986: return(0);
1.72 kristaps 987: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.24 kristaps 988: return(0);
989:
1.28 kristaps 990: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
991: return(0);
1.16 kristaps 992: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 993:
1.16 kristaps 994: return(1);
1.1 kristaps 995: }
1.5 kristaps 996:
1.7 kristaps 997:
1.44 kristaps 998: /*
1.72 kristaps 999: * Block partial-imnplicit scope.
1.44 kristaps 1000: */
1.51 kristaps 1001: static int
1.72 kristaps 1002: blk_part_imp(MACRO_PROT_ARGS)
1.7 kristaps 1003: {
1.41 kristaps 1004: int lastarg, c;
1.74 kristaps 1005: char *p;
1006: struct mdoc_node *blk, *body, *n;
1.7 kristaps 1007:
1.58 kristaps 1008: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1.28 kristaps 1009: return(0);
1.16 kristaps 1010: mdoc->next = MDOC_NEXT_CHILD;
1.74 kristaps 1011: blk = mdoc->last;
1.8 kristaps 1012:
1.28 kristaps 1013: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1014: return(0);
1.44 kristaps 1015: mdoc->next = MDOC_NEXT_SIBLING;
1.74 kristaps 1016:
1.44 kristaps 1017: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1018: return(0);
1.16 kristaps 1019: mdoc->next = MDOC_NEXT_CHILD;
1.74 kristaps 1020: body = mdoc->last;
1.8 kristaps 1021:
1.19 kristaps 1022: /* XXX - no known argument macros. */
1023:
1.72 kristaps 1024: for (lastarg = ppos;; ) {
1.19 kristaps 1025: lastarg = *pos;
1.48 kristaps 1026: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1027: assert(ARGS_PHRASE != c);
1.8 kristaps 1028:
1.19 kristaps 1029: if (ARGS_ERROR == c)
1030: return(0);
1031: if (ARGS_PUNCT == c)
1032: break;
1033: if (ARGS_EOLN == c)
1034: break;
1.8 kristaps 1035:
1.30 kristaps 1036: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1037: return(0);
1038: else if (MDOC_MAX == c) {
1.28 kristaps 1039: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1040: return(0);
1.19 kristaps 1041: mdoc->next = MDOC_NEXT_SIBLING;
1042: continue;
1.30 kristaps 1043: }
1.8 kristaps 1044:
1.26 kristaps 1045: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1046: return(0);
1.8 kristaps 1047: break;
1048: }
1049:
1.74 kristaps 1050: /*
1051: * Since we know what our context is, we can rewind directly to
1052: * it. This allows us to accomodate for our scope being
1053: * violated by another token.
1054: */
1055:
1056: for (n = mdoc->last; n; n = n->parent)
1057: if (body == n)
1058: break;
1059:
1.75 ! kristaps 1060: if (n && ! rew_last(mdoc, body))
! 1061: return(0);
1.74 kristaps 1062:
1063: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1.35 kristaps 1064: return(0);
1.74 kristaps 1065:
1.75 ! kristaps 1066: if (n && ! rew_last(mdoc, blk))
! 1067: return(0);
! 1068:
1.74 kristaps 1069: return(1);
1.22 kristaps 1070: }
1071:
1072:
1.44 kristaps 1073: /*
1.72 kristaps 1074: * Block partial-explicit macros.
1.44 kristaps 1075: */
1.51 kristaps 1076: static int
1.72 kristaps 1077: blk_part_exp(MACRO_PROT_ARGS)
1.22 kristaps 1078: {
1079: int lastarg, flushed, j, c, maxargs;
1080: char *p;
1081:
1082: lastarg = ppos;
1083: flushed = 0;
1084:
1.72 kristaps 1085: /*
1086: * Number of arguments (head arguments). Only `Eo' has these,
1087: */
1088:
1.22 kristaps 1089: switch (tok) {
1090: case (MDOC_Eo):
1091: maxargs = 1;
1092: break;
1093: default:
1094: maxargs = 0;
1095: break;
1096: }
1097:
1.58 kristaps 1098: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1.28 kristaps 1099: return(0);
1.22 kristaps 1100: mdoc->next = MDOC_NEXT_CHILD;
1101:
1102: if (0 == maxargs) {
1.28 kristaps 1103: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1104: return(0);
1.72 kristaps 1105: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1106: tok, line, ppos))
1.28 kristaps 1107: return(0);
1108: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 1109: return(0);
1.22 kristaps 1110: flushed = 1;
1.28 kristaps 1111: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1112: return(0);
1.22 kristaps 1113:
1114: mdoc->next = MDOC_NEXT_CHILD;
1115:
1.72 kristaps 1116: for (j = 0; ; j++) {
1.22 kristaps 1117: lastarg = *pos;
1118: if (j == maxargs && ! flushed) {
1.72 kristaps 1119: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1120: tok, line, ppos))
1.22 kristaps 1121: return(0);
1122: flushed = 1;
1.28 kristaps 1123: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1124: return(0);
1.22 kristaps 1125: mdoc->next = MDOC_NEXT_CHILD;
1126: }
1127:
1.48 kristaps 1128: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1129: assert(ARGS_PHRASE != c);
1130:
1.22 kristaps 1131: if (ARGS_ERROR == c)
1132: return(0);
1133: if (ARGS_PUNCT == c)
1134: break;
1135: if (ARGS_EOLN == c)
1136: break;
1137:
1.30 kristaps 1138: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1139: return(0);
1140: else if (MDOC_MAX != c) {
1.22 kristaps 1141: if ( ! flushed) {
1.72 kristaps 1142: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1.51 kristaps 1143: tok, line, ppos))
1.22 kristaps 1144: return(0);
1145: flushed = 1;
1.51 kristaps 1146: if ( ! mdoc_body_alloc(mdoc, line,
1147: ppos, tok))
1.28 kristaps 1148: return(0);
1.22 kristaps 1149: mdoc->next = MDOC_NEXT_CHILD;
1150: }
1.51 kristaps 1151: if ( ! mdoc_macro(mdoc, c, line, lastarg,
1152: pos, buf))
1.22 kristaps 1153: return(0);
1154: break;
1155: }
1156:
1157: if ( ! flushed && mdoc_isdelim(p)) {
1.72 kristaps 1158: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1.51 kristaps 1159: tok, line, ppos))
1.22 kristaps 1160: return(0);
1161: flushed = 1;
1.28 kristaps 1162: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1163: return(0);
1.22 kristaps 1164: mdoc->next = MDOC_NEXT_CHILD;
1165: }
1166:
1.28 kristaps 1167: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1168: return(0);
1.22 kristaps 1169: mdoc->next = MDOC_NEXT_SIBLING;
1170: }
1171:
1172: if ( ! flushed) {
1.72 kristaps 1173: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 1174: return(0);
1175: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.22 kristaps 1176: return(0);
1177: mdoc->next = MDOC_NEXT_CHILD;
1178: }
1179:
1180: if (ppos > 1)
1181: return(1);
1.41 kristaps 1182: return(append_delims(mdoc, line, pos, buf));
1.7 kristaps 1183: }
1.8 kristaps 1184:
1.10 kristaps 1185:
1.44 kristaps 1186: /*
1.72 kristaps 1187: * In-line macros where reserved words signal closure of the macro.
1188: * Macros also have a fixed number of arguments.
1.44 kristaps 1189: */
1.51 kristaps 1190: static int
1.72 kristaps 1191: in_line_argn(MACRO_PROT_ARGS)
1.10 kristaps 1192: {
1.72 kristaps 1193: int lastarg, flushed, j, c, maxargs;
1.58 kristaps 1194: struct mdoc_arg *arg;
1.13 kristaps 1195: char *p;
1.10 kristaps 1196:
1.57 kristaps 1197:
1198: /*
1.72 kristaps 1199: * Fixed maximum arguments per macro. Some of these have none
1200: * and close as soon as the invocation is parsed.
1.57 kristaps 1201: */
1202:
1.10 kristaps 1203: switch (tok) {
1.61 kristaps 1204: case (MDOC_Ap):
1205: /* FALLTHROUGH */
1.16 kristaps 1206: case (MDOC_No):
1207: /* FALLTHROUGH */
1208: case (MDOC_Ns):
1209: /* FALLTHROUGH */
1.10 kristaps 1210: case (MDOC_Ux):
1211: maxargs = 0;
1212: break;
1213: default:
1214: maxargs = 1;
1215: break;
1216: }
1217:
1.72 kristaps 1218: for (lastarg = ppos, arg = NULL;; ) {
1219: lastarg = *pos;
1220: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.57 kristaps 1221:
1.72 kristaps 1222: if (ARGV_WORD == c) {
1223: *pos = lastarg;
1224: break;
1225: }
1.50 kristaps 1226:
1.72 kristaps 1227: if (ARGV_EOLN == c)
1228: break;
1229: if (ARGV_ARG == c)
1230: continue;
1.57 kristaps 1231:
1.72 kristaps 1232: mdoc_argv_free(arg);
1233: return(0);
1.24 kristaps 1234: }
1235:
1.58 kristaps 1236: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1.24 kristaps 1237: return(0);
1.19 kristaps 1238: mdoc->next = MDOC_NEXT_CHILD;
1.10 kristaps 1239:
1.72 kristaps 1240: for (flushed = j = 0; ; j++) {
1.19 kristaps 1241: lastarg = *pos;
1.10 kristaps 1242:
1.19 kristaps 1243: if (j == maxargs && ! flushed) {
1.72 kristaps 1244: if ( ! rew_elem(mdoc, tok))
1.19 kristaps 1245: return(0);
1246: flushed = 1;
1247: }
1.11 kristaps 1248:
1.48 kristaps 1249: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1250:
1.19 kristaps 1251: if (ARGS_ERROR == c)
1.10 kristaps 1252: return(0);
1.19 kristaps 1253: if (ARGS_PUNCT == c)
1254: break;
1255: if (ARGS_EOLN == c)
1256: break;
1257:
1.30 kristaps 1258: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1259: return(0);
1260: else if (MDOC_MAX != c) {
1.72 kristaps 1261: if ( ! flushed && ! rew_elem(mdoc, tok))
1.19 kristaps 1262: return(0);
1263: flushed = 1;
1.26 kristaps 1264: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1265: return(0);
1266: break;
1267: }
1.10 kristaps 1268:
1.72 kristaps 1269: if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1270: ! flushed && mdoc_isdelim(p)) {
1271: if ( ! rew_elem(mdoc, tok))
1.19 kristaps 1272: return(0);
1273: flushed = 1;
1274: }
1275:
1.28 kristaps 1276: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1277: return(0);
1.19 kristaps 1278: mdoc->next = MDOC_NEXT_SIBLING;
1.10 kristaps 1279: }
1280:
1.72 kristaps 1281: if ( ! flushed && ! rew_elem(mdoc, tok))
1.19 kristaps 1282: return(0);
1.11 kristaps 1283:
1.19 kristaps 1284: if (ppos > 1)
1285: return(1);
1.41 kristaps 1286: return(append_delims(mdoc, line, pos, buf));
1.10 kristaps 1287: }
1.11 kristaps 1288:
1289:
1.44 kristaps 1290: /*
1.72 kristaps 1291: * In-line macro that spans an entire line. May be callable, but has no
1292: * subsequent parsed arguments.
1.44 kristaps 1293: */
1.51 kristaps 1294: static int
1.72 kristaps 1295: in_line_eoln(MACRO_PROT_ARGS)
1.11 kristaps 1296: {
1.58 kristaps 1297: int c, w, la;
1298: struct mdoc_arg *arg;
1.43 kristaps 1299: char *p;
1.44 kristaps 1300:
1.72 kristaps 1301: assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1302:
1.58 kristaps 1303: arg = NULL;
1304:
1305: for (;;) {
1.45 kristaps 1306: la = *pos;
1.58 kristaps 1307: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.72 kristaps 1308:
1.38 kristaps 1309: if (ARGV_WORD == c) {
1.45 kristaps 1310: *pos = la;
1.38 kristaps 1311: break;
1.72 kristaps 1312: }
1313: if (ARGV_EOLN == c)
1314: break;
1315: if (ARGV_ARG == c)
1.16 kristaps 1316: continue;
1.72 kristaps 1317:
1.58 kristaps 1318: mdoc_argv_free(arg);
1.11 kristaps 1319: return(0);
1320: }
1321:
1.58 kristaps 1322: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1.28 kristaps 1323: return(0);
1.11 kristaps 1324:
1.19 kristaps 1325: mdoc->next = MDOC_NEXT_CHILD;
1326:
1.41 kristaps 1327: for (;;) {
1.45 kristaps 1328: la = *pos;
1.48 kristaps 1329: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1330:
1.45 kristaps 1331: if (ARGS_ERROR == w)
1.16 kristaps 1332: return(0);
1.45 kristaps 1333: if (ARGS_EOLN == w)
1.13 kristaps 1334: break;
1.19 kristaps 1335:
1.45 kristaps 1336: c = ARGS_QWORD == w ? MDOC_MAX :
1337: lookup(mdoc, line, la, tok, p);
1338:
1339: if (MDOC_MAX != c && -1 != c) {
1.72 kristaps 1340: if ( ! rew_elem(mdoc, tok))
1.39 kristaps 1341: return(0);
1.45 kristaps 1342: return(mdoc_macro(mdoc, c, line, la, pos, buf));
1343: } else if (-1 == c)
1344: return(0);
1.39 kristaps 1345:
1.45 kristaps 1346: if ( ! mdoc_word_alloc(mdoc, line, la, p))
1.28 kristaps 1347: return(0);
1.21 kristaps 1348: mdoc->next = MDOC_NEXT_SIBLING;
1.13 kristaps 1349: }
1350:
1.72 kristaps 1351: return(rew_elem(mdoc, tok));
1.13 kristaps 1352: }
1.15 kristaps 1353:
1354:
1.16 kristaps 1355: /* ARGSUSED */
1.51 kristaps 1356: static int
1.72 kristaps 1357: obsolete(MACRO_PROT_ARGS)
1.15 kristaps 1358: {
1359:
1.49 kristaps 1360: return(pwarn(mdoc, line, ppos, WOBS));
1.15 kristaps 1361: }
1.25 kristaps 1362:
1363:
1.67 kristaps 1364: static int
1.72 kristaps 1365: phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
1.25 kristaps 1366: {
1.72 kristaps 1367: int i, la, c, quoted;
1368:
1369: /*
1370: * Parse over words in a phrase. We have to handle this
1371: * specially because we assume no calling context -- in normal
1372: * circumstances, we switch argument parsing based on whether
1373: * the parent macro accepts quotes, tabs, etc. Here, anything
1374: * goes.
1375: */
1.67 kristaps 1376:
1.68 kristaps 1377: for (i = ppos; buf[i]; ) {
1378: assert(' ' != buf[i]);
1.72 kristaps 1379: la = i;
1380: quoted = 0;
1.25 kristaps 1381:
1.72 kristaps 1382: /*
1383: * Read to next token. If quoted (check not escaped),
1384: * scan ahead to next unescaped quote. If not quoted or
1385: * escape-quoted, then scan ahead to next space.
1386: */
1387:
1388: if ((i && '\"' == buf[i] && '\\' != buf[i - 1]) ||
1389: (0 == i && '\"' == buf[i])) {
1390: for (la = ++i; buf[i]; i++)
1391: if ('\"' != buf[i])
1392: continue;
1393: else if ('\\' != buf[i - 1])
1394: break;
1.68 kristaps 1395: if (0 == buf[i])
1.72 kristaps 1396: return(perr(mdoc, line, la, EQUOT));
1397: quoted = 1;
1.68 kristaps 1398: } else
1.72 kristaps 1399: for ( ; buf[i]; i++)
1400: if (i && ' ' == buf[i]) {
1401: if ('\\' != buf[i - 1])
1402: break;
1403: } else if (' ' == buf[i])
1404: break;
1405:
1406: /* If not end-of-line, terminate argument. */
1.42 kristaps 1407:
1.68 kristaps 1408: if (buf[i])
1409: buf[i++] = 0;
1.42 kristaps 1410:
1.72 kristaps 1411: /* Read to next argument. */
1.42 kristaps 1412:
1.72 kristaps 1413: for ( ; buf[i] && ' ' == buf[i]; i++)
1414: /* Spin. */ ;
1415:
1416: /*
1417: * If we're a non-quoted string, try to look up the
1418: * value as a macro and execute it, if found.
1419: */
1420:
1421: c = quoted ? MDOC_MAX :
1422: mdoc_tokhash_find(mdoc->htab, &buf[la]);
1423:
1424: if (MDOC_MAX != c) {
1.68 kristaps 1425: if ( ! mdoc_macro(mdoc, c, line, la, &i, buf))
1426: return(0);
1.69 kristaps 1427: return(append_delims(mdoc, line, &i, buf));
1.68 kristaps 1428: }
1429:
1.72 kristaps 1430: /* A regular word or quoted string. */
1431:
1.68 kristaps 1432: if ( ! mdoc_word_alloc(mdoc, line, la, &buf[la]))
1433: return(0);
1434: mdoc->next = MDOC_NEXT_SIBLING;
1.42 kristaps 1435: }
1.68 kristaps 1436:
1437: return(1);
1.25 kristaps 1438: }
CVSweb