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