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