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