1241675Suqs/* $Id: mdoc_macro.c,v 1.115 2012/01/05 00:43:51 schwarze Exp $ */ 2241675Suqs/* 3241675Suqs * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4241675Suqs * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> 5241675Suqs * 6241675Suqs * Permission to use, copy, modify, and distribute this software for any 7241675Suqs * purpose with or without fee is hereby granted, provided that the above 8241675Suqs * copyright notice and this permission notice appear in all copies. 9241675Suqs * 10241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17241675Suqs */ 18241675Suqs#ifdef HAVE_CONFIG_H 19241675Suqs#include "config.h" 20241675Suqs#endif 21241675Suqs 22241675Suqs#include <assert.h> 23241675Suqs#include <ctype.h> 24241675Suqs#include <stdlib.h> 25241675Suqs#include <stdio.h> 26241675Suqs#include <string.h> 27241675Suqs#include <time.h> 28241675Suqs 29241675Suqs#include "mdoc.h" 30241675Suqs#include "mandoc.h" 31241675Suqs#include "libmdoc.h" 32241675Suqs#include "libmandoc.h" 33241675Suqs 34241675Suqsenum rew { /* see rew_dohalt() */ 35241675Suqs REWIND_NONE, 36241675Suqs REWIND_THIS, 37241675Suqs REWIND_MORE, 38241675Suqs REWIND_FORCE, 39241675Suqs REWIND_LATER, 40241675Suqs REWIND_ERROR 41241675Suqs}; 42241675Suqs 43241675Suqsstatic int blk_full(MACRO_PROT_ARGS); 44241675Suqsstatic int blk_exp_close(MACRO_PROT_ARGS); 45241675Suqsstatic int blk_part_exp(MACRO_PROT_ARGS); 46241675Suqsstatic int blk_part_imp(MACRO_PROT_ARGS); 47241675Suqsstatic int ctx_synopsis(MACRO_PROT_ARGS); 48241675Suqsstatic int in_line_eoln(MACRO_PROT_ARGS); 49241675Suqsstatic int in_line_argn(MACRO_PROT_ARGS); 50241675Suqsstatic int in_line(MACRO_PROT_ARGS); 51241675Suqsstatic int obsolete(MACRO_PROT_ARGS); 52241675Suqsstatic int phrase_ta(MACRO_PROT_ARGS); 53241675Suqs 54241675Suqsstatic int dword(struct mdoc *, int, int, 55241675Suqs const char *, enum mdelim); 56241675Suqsstatic int append_delims(struct mdoc *, 57241675Suqs int, int *, char *); 58241675Suqsstatic enum mdoct lookup(enum mdoct, const char *); 59241675Suqsstatic enum mdoct lookup_raw(const char *); 60241675Suqsstatic int make_pending(struct mdoc_node *, enum mdoct, 61241675Suqs struct mdoc *, int, int); 62241675Suqsstatic int phrase(struct mdoc *, int, int, char *); 63241675Suqsstatic enum mdoct rew_alt(enum mdoct); 64241675Suqsstatic enum rew rew_dohalt(enum mdoct, enum mdoc_type, 65241675Suqs const struct mdoc_node *); 66241675Suqsstatic int rew_elem(struct mdoc *, enum mdoct); 67241675Suqsstatic int rew_last(struct mdoc *, 68241675Suqs const struct mdoc_node *); 69241675Suqsstatic int rew_sub(enum mdoc_type, struct mdoc *, 70241675Suqs enum mdoct, int, int); 71241675Suqs 72241675Suqsconst struct mdoc_macro __mdoc_macros[MDOC_MAX] = { 73241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */ 74241675Suqs { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ 75241675Suqs { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ 76241675Suqs { in_line_eoln, MDOC_PROLOGUE }, /* Os */ 77241675Suqs { blk_full, MDOC_PARSED }, /* Sh */ 78241675Suqs { blk_full, MDOC_PARSED }, /* Ss */ 79241675Suqs { in_line_eoln, 0 }, /* Pp */ 80241675Suqs { blk_part_imp, MDOC_PARSED }, /* D1 */ 81241675Suqs { blk_part_imp, MDOC_PARSED }, /* Dl */ 82241675Suqs { blk_full, MDOC_EXPLICIT }, /* Bd */ 83241675Suqs { blk_exp_close, MDOC_EXPLICIT }, /* Ed */ 84241675Suqs { blk_full, MDOC_EXPLICIT }, /* Bl */ 85241675Suqs { blk_exp_close, MDOC_EXPLICIT }, /* El */ 86241675Suqs { blk_full, MDOC_PARSED }, /* It */ 87241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ 88241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */ 89241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ 90241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */ 91241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ 92241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ 93241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ 94241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ 95241675Suqs { in_line_eoln, 0 }, /* Ex */ 96241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ 97241675Suqs { in_line_eoln, 0 }, /* Fd */ 98241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */ 99241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ 100241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ 101241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */ 102241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ 103241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ 104241675Suqs { blk_full, 0 }, /* Nd */ 105241675Suqs { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ 106241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ 107241675Suqs { obsolete, 0 }, /* Ot */ 108241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ 109241675Suqs { in_line_eoln, 0 }, /* Rv */ 110241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ 111241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */ 112241675Suqs { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ 113241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */ 114241675Suqs { in_line_eoln, 0 }, /* %A */ 115241675Suqs { in_line_eoln, 0 }, /* %B */ 116241675Suqs { in_line_eoln, 0 }, /* %D */ 117241675Suqs { in_line_eoln, 0 }, /* %I */ 118241675Suqs { in_line_eoln, 0 }, /* %J */ 119241675Suqs { in_line_eoln, 0 }, /* %N */ 120241675Suqs { in_line_eoln, 0 }, /* %O */ 121241675Suqs { in_line_eoln, 0 }, /* %P */ 122241675Suqs { in_line_eoln, 0 }, /* %R */ 123241675Suqs { in_line_eoln, 0 }, /* %T */ 124241675Suqs { in_line_eoln, 0 }, /* %V */ 125241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */ 126241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */ 127241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */ 128241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */ 129241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */ 130241675Suqs { blk_full, MDOC_EXPLICIT }, /* Bf */ 131241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */ 132241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */ 133241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */ 134241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */ 135241675Suqs { in_line_eoln, 0 }, /* Db */ 136241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */ 137241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */ 138241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */ 139241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */ 140241675Suqs { blk_exp_close, MDOC_EXPLICIT }, /* Ef */ 141241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */ 142241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */ 143241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */ 144241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */ 145241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* No */ 146241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Ns */ 147241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ 148241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */ 149241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */ 150241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */ 151241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */ 152241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */ 153241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */ 154241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */ 155241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */ 156241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */ 157241675Suqs { blk_exp_close, MDOC_EXPLICIT }, /* Re */ 158241675Suqs { blk_full, MDOC_EXPLICIT }, /* Rs */ 159241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */ 160241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */ 161241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */ 162241675Suqs { in_line_eoln, 0 }, /* Sm */ 163241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */ 164241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */ 165241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */ 166241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */ 167241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */ 168241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */ 169241675Suqs { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ 170241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */ 171241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */ 172241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */ 173241675Suqs { blk_full, MDOC_EXPLICIT }, /* Bk */ 174241675Suqs { blk_exp_close, MDOC_EXPLICIT }, /* Ek */ 175241675Suqs { in_line_eoln, 0 }, /* Bt */ 176241675Suqs { in_line_eoln, 0 }, /* Hf */ 177241675Suqs { obsolete, 0 }, /* Fr */ 178241675Suqs { in_line_eoln, 0 }, /* Ud */ 179241675Suqs { in_line, 0 }, /* Lb */ 180241675Suqs { in_line_eoln, 0 }, /* Lp */ 181241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ 182241675Suqs { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ 183241675Suqs { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */ 184241675Suqs { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */ 185241675Suqs { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */ 186241675Suqs { in_line_eoln, 0 }, /* %C */ 187241675Suqs { obsolete, 0 }, /* Es */ 188241675Suqs { obsolete, 0 }, /* En */ 189241675Suqs { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ 190241675Suqs { in_line_eoln, 0 }, /* %Q */ 191241675Suqs { in_line_eoln, 0 }, /* br */ 192241675Suqs { in_line_eoln, 0 }, /* sp */ 193241675Suqs { in_line_eoln, 0 }, /* %U */ 194241675Suqs { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */ 195241675Suqs}; 196241675Suqs 197241675Suqsconst struct mdoc_macro * const mdoc_macros = __mdoc_macros; 198241675Suqs 199241675Suqs 200241675Suqs/* 201241675Suqs * This is called at the end of parsing. It must traverse up the tree, 202241675Suqs * closing out open [implicit] scopes. Obviously, open explicit scopes 203241675Suqs * are errors. 204241675Suqs */ 205241675Suqsint 206241675Suqsmdoc_macroend(struct mdoc *m) 207241675Suqs{ 208241675Suqs struct mdoc_node *n; 209241675Suqs 210241675Suqs /* Scan for open explicit scopes. */ 211241675Suqs 212241675Suqs n = MDOC_VALID & m->last->flags ? m->last->parent : m->last; 213241675Suqs 214241675Suqs for ( ; n; n = n->parent) 215241675Suqs if (MDOC_BLOCK == n->type && 216241675Suqs MDOC_EXPLICIT & mdoc_macros[n->tok].flags) 217241675Suqs mdoc_nmsg(m, n, MANDOCERR_SCOPEEXIT); 218241675Suqs 219241675Suqs /* Rewind to the first. */ 220241675Suqs 221241675Suqs return(rew_last(m, m->first)); 222241675Suqs} 223241675Suqs 224241675Suqs 225241675Suqs/* 226241675Suqs * Look up a macro from within a subsequent context. 227241675Suqs */ 228241675Suqsstatic enum mdoct 229241675Suqslookup(enum mdoct from, const char *p) 230241675Suqs{ 231241675Suqs 232241675Suqs if ( ! (MDOC_PARSED & mdoc_macros[from].flags)) 233241675Suqs return(MDOC_MAX); 234241675Suqs return(lookup_raw(p)); 235241675Suqs} 236241675Suqs 237241675Suqs 238241675Suqs/* 239241675Suqs * Lookup a macro following the initial line macro. 240241675Suqs */ 241241675Suqsstatic enum mdoct 242241675Suqslookup_raw(const char *p) 243241675Suqs{ 244241675Suqs enum mdoct res; 245241675Suqs 246241675Suqs if (MDOC_MAX == (res = mdoc_hash_find(p))) 247241675Suqs return(MDOC_MAX); 248241675Suqs if (MDOC_CALLABLE & mdoc_macros[res].flags) 249241675Suqs return(res); 250241675Suqs return(MDOC_MAX); 251241675Suqs} 252241675Suqs 253241675Suqs 254241675Suqsstatic int 255241675Suqsrew_last(struct mdoc *mdoc, const struct mdoc_node *to) 256241675Suqs{ 257241675Suqs struct mdoc_node *n, *np; 258241675Suqs 259241675Suqs assert(to); 260241675Suqs mdoc->next = MDOC_NEXT_SIBLING; 261241675Suqs 262241675Suqs /* LINTED */ 263241675Suqs while (mdoc->last != to) { 264241675Suqs /* 265241675Suqs * Save the parent here, because we may delete the 266241675Suqs * m->last node in the post-validation phase and reset 267241675Suqs * it to m->last->parent, causing a step in the closing 268241675Suqs * out to be lost. 269241675Suqs */ 270241675Suqs np = mdoc->last->parent; 271241675Suqs if ( ! mdoc_valid_post(mdoc)) 272241675Suqs return(0); 273241675Suqs n = mdoc->last; 274241675Suqs mdoc->last = np; 275241675Suqs assert(mdoc->last); 276241675Suqs mdoc->last->last = n; 277241675Suqs } 278241675Suqs 279241675Suqs return(mdoc_valid_post(mdoc)); 280241675Suqs} 281241675Suqs 282241675Suqs 283241675Suqs/* 284241675Suqs * For a block closing macro, return the corresponding opening one. 285241675Suqs * Otherwise, return the macro itself. 286241675Suqs */ 287241675Suqsstatic enum mdoct 288241675Suqsrew_alt(enum mdoct tok) 289241675Suqs{ 290241675Suqs switch (tok) { 291241675Suqs case (MDOC_Ac): 292241675Suqs return(MDOC_Ao); 293241675Suqs case (MDOC_Bc): 294241675Suqs return(MDOC_Bo); 295241675Suqs case (MDOC_Brc): 296241675Suqs return(MDOC_Bro); 297241675Suqs case (MDOC_Dc): 298241675Suqs return(MDOC_Do); 299241675Suqs case (MDOC_Ec): 300241675Suqs return(MDOC_Eo); 301241675Suqs case (MDOC_Ed): 302241675Suqs return(MDOC_Bd); 303241675Suqs case (MDOC_Ef): 304241675Suqs return(MDOC_Bf); 305241675Suqs case (MDOC_Ek): 306241675Suqs return(MDOC_Bk); 307241675Suqs case (MDOC_El): 308241675Suqs return(MDOC_Bl); 309241675Suqs case (MDOC_Fc): 310241675Suqs return(MDOC_Fo); 311241675Suqs case (MDOC_Oc): 312241675Suqs return(MDOC_Oo); 313241675Suqs case (MDOC_Pc): 314241675Suqs return(MDOC_Po); 315241675Suqs case (MDOC_Qc): 316241675Suqs return(MDOC_Qo); 317241675Suqs case (MDOC_Re): 318241675Suqs return(MDOC_Rs); 319241675Suqs case (MDOC_Sc): 320241675Suqs return(MDOC_So); 321241675Suqs case (MDOC_Xc): 322241675Suqs return(MDOC_Xo); 323241675Suqs default: 324241675Suqs return(tok); 325241675Suqs } 326241675Suqs /* NOTREACHED */ 327241675Suqs} 328241675Suqs 329241675Suqs 330241675Suqs/* 331241675Suqs * Rewinding to tok, how do we have to handle *p? 332241675Suqs * REWIND_NONE: *p would delimit tok, but no tok scope is open 333241675Suqs * inside *p, so there is no need to rewind anything at all. 334241675Suqs * REWIND_THIS: *p matches tok, so rewind *p and nothing else. 335241675Suqs * REWIND_MORE: *p is implicit, rewind it and keep searching for tok. 336241675Suqs * REWIND_FORCE: *p is explicit, but tok is full, force rewinding *p. 337241675Suqs * REWIND_LATER: *p is explicit and still open, postpone rewinding. 338241675Suqs * REWIND_ERROR: No tok block is open at all. 339241675Suqs */ 340241675Suqsstatic enum rew 341241675Suqsrew_dohalt(enum mdoct tok, enum mdoc_type type, 342241675Suqs const struct mdoc_node *p) 343241675Suqs{ 344241675Suqs 345241675Suqs /* 346241675Suqs * No matching token, no delimiting block, no broken block. 347241675Suqs * This can happen when full implicit macros are called for 348241675Suqs * the first time but try to rewind their previous 349241675Suqs * instance anyway. 350241675Suqs */ 351241675Suqs if (MDOC_ROOT == p->type) 352241675Suqs return(MDOC_BLOCK == type && 353241675Suqs MDOC_EXPLICIT & mdoc_macros[tok].flags ? 354241675Suqs REWIND_ERROR : REWIND_NONE); 355241675Suqs 356241675Suqs /* 357241675Suqs * When starting to rewind, skip plain text 358241675Suqs * and nodes that have already been rewound. 359241675Suqs */ 360241675Suqs if (MDOC_TEXT == p->type || MDOC_VALID & p->flags) 361241675Suqs return(REWIND_MORE); 362241675Suqs 363241675Suqs /* 364241675Suqs * The easiest case: Found a matching token. 365241675Suqs * This applies to both blocks and elements. 366241675Suqs */ 367241675Suqs tok = rew_alt(tok); 368241675Suqs if (tok == p->tok) 369241675Suqs return(p->end ? REWIND_NONE : 370241675Suqs type == p->type ? REWIND_THIS : REWIND_MORE); 371241675Suqs 372241675Suqs /* 373241675Suqs * While elements do require rewinding for themselves, 374241675Suqs * they never affect rewinding of other nodes. 375241675Suqs */ 376241675Suqs if (MDOC_ELEM == p->type) 377241675Suqs return(REWIND_MORE); 378241675Suqs 379241675Suqs /* 380241675Suqs * Blocks delimited by our target token get REWIND_MORE. 381241675Suqs * Blocks delimiting our target token get REWIND_NONE. 382241675Suqs */ 383241675Suqs switch (tok) { 384241675Suqs case (MDOC_Bl): 385241675Suqs if (MDOC_It == p->tok) 386241675Suqs return(REWIND_MORE); 387241675Suqs break; 388241675Suqs case (MDOC_It): 389241675Suqs if (MDOC_BODY == p->type && MDOC_Bl == p->tok) 390241675Suqs return(REWIND_NONE); 391241675Suqs break; 392241675Suqs /* 393241675Suqs * XXX Badly nested block handling still fails badly 394241675Suqs * when one block is breaking two blocks of the same type. 395241675Suqs * This is an incomplete and extremely ugly workaround, 396241675Suqs * required to let the OpenBSD tree build. 397241675Suqs */ 398241675Suqs case (MDOC_Oo): 399241675Suqs if (MDOC_Op == p->tok) 400241675Suqs return(REWIND_MORE); 401241675Suqs break; 402241675Suqs case (MDOC_Nm): 403241675Suqs return(REWIND_NONE); 404241675Suqs case (MDOC_Nd): 405241675Suqs /* FALLTHROUGH */ 406241675Suqs case (MDOC_Ss): 407241675Suqs if (MDOC_BODY == p->type && MDOC_Sh == p->tok) 408241675Suqs return(REWIND_NONE); 409241675Suqs /* FALLTHROUGH */ 410241675Suqs case (MDOC_Sh): 411241675Suqs if (MDOC_Nd == p->tok || MDOC_Ss == p->tok || 412241675Suqs MDOC_Sh == p->tok) 413241675Suqs return(REWIND_MORE); 414241675Suqs break; 415241675Suqs default: 416241675Suqs break; 417241675Suqs } 418241675Suqs 419241675Suqs /* 420241675Suqs * Default block rewinding rules. 421241675Suqs * In particular, always skip block end markers, 422241675Suqs * and let all blocks rewind Nm children. 423241675Suqs */ 424241675Suqs if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok || 425241675Suqs (MDOC_BLOCK == p->type && 426241675Suqs ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))) 427241675Suqs return(REWIND_MORE); 428241675Suqs 429241675Suqs /* 430241675Suqs * By default, closing out full blocks 431241675Suqs * forces closing of broken explicit blocks, 432241675Suqs * while closing out partial blocks 433241675Suqs * allows delayed rewinding by default. 434241675Suqs */ 435241675Suqs return (&blk_full == mdoc_macros[tok].fp ? 436241675Suqs REWIND_FORCE : REWIND_LATER); 437241675Suqs} 438241675Suqs 439241675Suqs 440241675Suqsstatic int 441241675Suqsrew_elem(struct mdoc *mdoc, enum mdoct tok) 442241675Suqs{ 443241675Suqs struct mdoc_node *n; 444241675Suqs 445241675Suqs n = mdoc->last; 446241675Suqs if (MDOC_ELEM != n->type) 447241675Suqs n = n->parent; 448241675Suqs assert(MDOC_ELEM == n->type); 449241675Suqs assert(tok == n->tok); 450241675Suqs 451241675Suqs return(rew_last(mdoc, n)); 452241675Suqs} 453241675Suqs 454241675Suqs 455241675Suqs/* 456241675Suqs * We are trying to close a block identified by tok, 457241675Suqs * but the child block *broken is still open. 458241675Suqs * Thus, postpone closing the tok block 459241675Suqs * until the rew_sub call closing *broken. 460241675Suqs */ 461241675Suqsstatic int 462241675Suqsmake_pending(struct mdoc_node *broken, enum mdoct tok, 463241675Suqs struct mdoc *m, int line, int ppos) 464241675Suqs{ 465241675Suqs struct mdoc_node *breaker; 466241675Suqs 467241675Suqs /* 468241675Suqs * Iterate backwards, searching for the block matching tok, 469241675Suqs * that is, the block breaking the *broken block. 470241675Suqs */ 471241675Suqs for (breaker = broken->parent; breaker; breaker = breaker->parent) { 472241675Suqs 473241675Suqs /* 474241675Suqs * If the *broken block had already been broken before 475241675Suqs * and we encounter its breaker, make the tok block 476241675Suqs * pending on the inner breaker. 477241675Suqs * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]" 478241675Suqs * becomes "[A broken=[B [C->B B] tok=A] C]" 479241675Suqs * and finally "[A [B->A [C->B B] A] C]". 480241675Suqs */ 481241675Suqs if (breaker == broken->pending) { 482241675Suqs broken = breaker; 483241675Suqs continue; 484241675Suqs } 485241675Suqs 486241675Suqs if (REWIND_THIS != rew_dohalt(tok, MDOC_BLOCK, breaker)) 487241675Suqs continue; 488241675Suqs if (MDOC_BODY == broken->type) 489241675Suqs broken = broken->parent; 490241675Suqs 491241675Suqs /* 492241675Suqs * Found the breaker. 493241675Suqs * If another, outer breaker is already pending on 494241675Suqs * the *broken block, we must not clobber the link 495241675Suqs * to the outer breaker, but make it pending on the 496241675Suqs * new, now inner breaker. 497241675Suqs * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]" 498241675Suqs * becomes "[A breaker=[B->A broken=[C A] tok=B] C]" 499241675Suqs * and finally "[A [B->A [C->B A] B] C]". 500241675Suqs */ 501241675Suqs if (broken->pending) { 502241675Suqs struct mdoc_node *taker; 503241675Suqs 504241675Suqs /* 505241675Suqs * If the breaker had also been broken before, 506241675Suqs * it cannot take on the outer breaker itself, 507241675Suqs * but must hand it on to its own breakers. 508241675Suqs * Graphically, this is the following situation: 509241675Suqs * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]" 510241675Suqs * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]" 511241675Suqs */ 512241675Suqs taker = breaker; 513241675Suqs while (taker->pending) 514241675Suqs taker = taker->pending; 515241675Suqs taker->pending = broken->pending; 516241675Suqs } 517241675Suqs broken->pending = breaker; 518241675Suqs mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, 519241675Suqs "%s breaks %s", mdoc_macronames[tok], 520241675Suqs mdoc_macronames[broken->tok]); 521241675Suqs return(1); 522241675Suqs } 523241675Suqs 524241675Suqs /* 525241675Suqs * Found no matching block for tok. 526241675Suqs * Are you trying to close a block that is not open? 527241675Suqs */ 528241675Suqs return(0); 529241675Suqs} 530241675Suqs 531241675Suqs 532241675Suqsstatic int 533241675Suqsrew_sub(enum mdoc_type t, struct mdoc *m, 534241675Suqs enum mdoct tok, int line, int ppos) 535241675Suqs{ 536241675Suqs struct mdoc_node *n; 537241675Suqs 538241675Suqs n = m->last; 539241675Suqs while (n) { 540241675Suqs switch (rew_dohalt(tok, t, n)) { 541241675Suqs case (REWIND_NONE): 542241675Suqs return(1); 543241675Suqs case (REWIND_THIS): 544241675Suqs break; 545241675Suqs case (REWIND_FORCE): 546241675Suqs mandoc_vmsg(MANDOCERR_SCOPEBROKEN, m->parse, 547241675Suqs line, ppos, "%s breaks %s", 548241675Suqs mdoc_macronames[tok], 549241675Suqs mdoc_macronames[n->tok]); 550241675Suqs /* FALLTHROUGH */ 551241675Suqs case (REWIND_MORE): 552241675Suqs n = n->parent; 553241675Suqs continue; 554241675Suqs case (REWIND_LATER): 555241675Suqs if (make_pending(n, tok, m, line, ppos) || 556241675Suqs MDOC_BLOCK != t) 557241675Suqs return(1); 558241675Suqs /* FALLTHROUGH */ 559241675Suqs case (REWIND_ERROR): 560241675Suqs mdoc_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); 561241675Suqs return(1); 562241675Suqs } 563241675Suqs break; 564241675Suqs } 565241675Suqs 566241675Suqs assert(n); 567241675Suqs if ( ! rew_last(m, n)) 568241675Suqs return(0); 569241675Suqs 570241675Suqs /* 571241675Suqs * The current block extends an enclosing block. 572241675Suqs * Now that the current block ends, close the enclosing block, too. 573241675Suqs */ 574241675Suqs while (NULL != (n = n->pending)) { 575241675Suqs if ( ! rew_last(m, n)) 576241675Suqs return(0); 577241675Suqs if (MDOC_HEAD == n->type && 578241675Suqs ! mdoc_body_alloc(m, n->line, n->pos, n->tok)) 579241675Suqs return(0); 580241675Suqs } 581241675Suqs 582241675Suqs return(1); 583241675Suqs} 584241675Suqs 585241675Suqs/* 586241675Suqs * Allocate a word and check whether it's punctuation or not. 587241675Suqs * Punctuation consists of those tokens found in mdoc_isdelim(). 588241675Suqs */ 589241675Suqsstatic int 590241675Suqsdword(struct mdoc *m, int line, 591241675Suqs int col, const char *p, enum mdelim d) 592241675Suqs{ 593241675Suqs 594241675Suqs if (DELIM_MAX == d) 595241675Suqs d = mdoc_isdelim(p); 596241675Suqs 597241675Suqs if ( ! mdoc_word_alloc(m, line, col, p)) 598241675Suqs return(0); 599241675Suqs 600241675Suqs if (DELIM_OPEN == d) 601241675Suqs m->last->flags |= MDOC_DELIMO; 602241675Suqs 603241675Suqs /* 604241675Suqs * Closing delimiters only suppress the preceding space 605241675Suqs * when they follow something, not when they start a new 606241675Suqs * block or element, and not when they follow `No'. 607241675Suqs * 608241675Suqs * XXX Explicitly special-casing MDOC_No here feels 609241675Suqs * like a layering violation. Find a better way 610241675Suqs * and solve this in the code related to `No'! 611241675Suqs */ 612241675Suqs 613241675Suqs else if (DELIM_CLOSE == d && m->last->prev && 614241675Suqs m->last->prev->tok != MDOC_No) 615241675Suqs m->last->flags |= MDOC_DELIMC; 616241675Suqs 617241675Suqs return(1); 618241675Suqs} 619241675Suqs 620241675Suqsstatic int 621241675Suqsappend_delims(struct mdoc *m, int line, int *pos, char *buf) 622241675Suqs{ 623241675Suqs int la; 624241675Suqs enum margserr ac; 625241675Suqs char *p; 626241675Suqs 627241675Suqs if ('\0' == buf[*pos]) 628241675Suqs return(1); 629241675Suqs 630241675Suqs for (;;) { 631241675Suqs la = *pos; 632241675Suqs ac = mdoc_zargs(m, line, pos, buf, &p); 633241675Suqs 634241675Suqs if (ARGS_ERROR == ac) 635241675Suqs return(0); 636241675Suqs else if (ARGS_EOLN == ac) 637241675Suqs break; 638241675Suqs 639241675Suqs dword(m, line, la, p, DELIM_MAX); 640241675Suqs 641241675Suqs /* 642241675Suqs * If we encounter end-of-sentence symbols, then trigger 643241675Suqs * the double-space. 644241675Suqs * 645241675Suqs * XXX: it's easy to allow this to propagate outward to 646241675Suqs * the last symbol, such that `. )' will cause the 647241675Suqs * correct double-spacing. However, (1) groff isn't 648241675Suqs * smart enough to do this and (2) it would require 649241675Suqs * knowing which symbols break this behaviour, for 650241675Suqs * example, `. ;' shouldn't propagate the double-space. 651241675Suqs */ 652241675Suqs if (mandoc_eos(p, strlen(p), 0)) 653241675Suqs m->last->flags |= MDOC_EOS; 654241675Suqs } 655241675Suqs 656241675Suqs return(1); 657241675Suqs} 658241675Suqs 659241675Suqs 660241675Suqs/* 661241675Suqs * Close out block partial/full explicit. 662241675Suqs */ 663241675Suqsstatic int 664241675Suqsblk_exp_close(MACRO_PROT_ARGS) 665241675Suqs{ 666241675Suqs struct mdoc_node *body; /* Our own body. */ 667241675Suqs struct mdoc_node *later; /* A sub-block starting later. */ 668241675Suqs struct mdoc_node *n; /* For searching backwards. */ 669241675Suqs 670241675Suqs int j, lastarg, maxargs, flushed, nl; 671241675Suqs enum margserr ac; 672241675Suqs enum mdoct atok, ntok; 673241675Suqs char *p; 674241675Suqs 675241675Suqs nl = MDOC_NEWLINE & m->flags; 676241675Suqs 677241675Suqs switch (tok) { 678241675Suqs case (MDOC_Ec): 679241675Suqs maxargs = 1; 680241675Suqs break; 681241675Suqs default: 682241675Suqs maxargs = 0; 683241675Suqs break; 684241675Suqs } 685241675Suqs 686241675Suqs /* 687241675Suqs * Search backwards for beginnings of blocks, 688241675Suqs * both of our own and of pending sub-blocks. 689241675Suqs */ 690241675Suqs atok = rew_alt(tok); 691241675Suqs body = later = NULL; 692241675Suqs for (n = m->last; n; n = n->parent) { 693241675Suqs if (MDOC_VALID & n->flags) 694241675Suqs continue; 695241675Suqs 696241675Suqs /* Remember the start of our own body. */ 697241675Suqs if (MDOC_BODY == n->type && atok == n->tok) { 698241675Suqs if (ENDBODY_NOT == n->end) 699241675Suqs body = n; 700241675Suqs continue; 701241675Suqs } 702241675Suqs 703241675Suqs if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok) 704241675Suqs continue; 705241675Suqs if (atok == n->tok) { 706241675Suqs assert(body); 707241675Suqs 708241675Suqs /* 709241675Suqs * Found the start of our own block. 710241675Suqs * When there is no pending sub block, 711241675Suqs * just proceed to closing out. 712241675Suqs */ 713241675Suqs if (NULL == later) 714241675Suqs break; 715241675Suqs 716241675Suqs /* 717241675Suqs * When there is a pending sub block, 718241675Suqs * postpone closing out the current block 719241675Suqs * until the rew_sub() closing out the sub-block. 720241675Suqs */ 721241675Suqs make_pending(later, tok, m, line, ppos); 722241675Suqs 723241675Suqs /* 724241675Suqs * Mark the place where the formatting - but not 725241675Suqs * the scope - of the current block ends. 726241675Suqs */ 727241675Suqs if ( ! mdoc_endbody_alloc(m, line, ppos, 728241675Suqs atok, body, ENDBODY_SPACE)) 729241675Suqs return(0); 730241675Suqs break; 731241675Suqs } 732241675Suqs 733241675Suqs /* 734241675Suqs * When finding an open sub block, remember the last 735241675Suqs * open explicit block, or, in case there are only 736241675Suqs * implicit ones, the first open implicit block. 737241675Suqs */ 738241675Suqs if (later && 739241675Suqs MDOC_EXPLICIT & mdoc_macros[later->tok].flags) 740241675Suqs continue; 741241675Suqs if (MDOC_CALLABLE & mdoc_macros[n->tok].flags) 742241675Suqs later = n; 743241675Suqs } 744241675Suqs 745241675Suqs if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { 746241675Suqs /* FIXME: do this in validate */ 747241675Suqs if (buf[*pos]) 748241675Suqs mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST); 749241675Suqs 750241675Suqs if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 751241675Suqs return(0); 752241675Suqs return(rew_sub(MDOC_BLOCK, m, tok, line, ppos)); 753241675Suqs } 754241675Suqs 755241675Suqs if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 756241675Suqs return(0); 757241675Suqs 758241675Suqs if (NULL == later && maxargs > 0) 759241675Suqs if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok))) 760241675Suqs return(0); 761241675Suqs 762241675Suqs for (flushed = j = 0; ; j++) { 763241675Suqs lastarg = *pos; 764241675Suqs 765241675Suqs if (j == maxargs && ! flushed) { 766241675Suqs if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 767241675Suqs return(0); 768241675Suqs flushed = 1; 769241675Suqs } 770241675Suqs 771241675Suqs ac = mdoc_args(m, line, pos, buf, tok, &p); 772241675Suqs 773241675Suqs if (ARGS_ERROR == ac) 774241675Suqs return(0); 775241675Suqs if (ARGS_PUNCT == ac) 776241675Suqs break; 777241675Suqs if (ARGS_EOLN == ac) 778241675Suqs break; 779241675Suqs 780241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 781241675Suqs 782241675Suqs if (MDOC_MAX == ntok) { 783241675Suqs if ( ! dword(m, line, lastarg, p, DELIM_MAX)) 784241675Suqs return(0); 785241675Suqs continue; 786241675Suqs } 787241675Suqs 788241675Suqs if ( ! flushed) { 789241675Suqs if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 790241675Suqs return(0); 791241675Suqs flushed = 1; 792241675Suqs } 793241675Suqs if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf)) 794241675Suqs return(0); 795241675Suqs break; 796241675Suqs } 797241675Suqs 798241675Suqs if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 799241675Suqs return(0); 800241675Suqs 801241675Suqs if ( ! nl) 802241675Suqs return(1); 803241675Suqs return(append_delims(m, line, pos, buf)); 804241675Suqs} 805241675Suqs 806241675Suqs 807241675Suqsstatic int 808241675Suqsin_line(MACRO_PROT_ARGS) 809241675Suqs{ 810241675Suqs int la, scope, cnt, nc, nl; 811241675Suqs enum margverr av; 812241675Suqs enum mdoct ntok; 813241675Suqs enum margserr ac; 814241675Suqs enum mdelim d; 815241675Suqs struct mdoc_arg *arg; 816241675Suqs char *p; 817241675Suqs 818241675Suqs nl = MDOC_NEWLINE & m->flags; 819241675Suqs 820241675Suqs /* 821241675Suqs * Whether we allow ignored elements (those without content, 822241675Suqs * usually because of reserved words) to squeak by. 823241675Suqs */ 824241675Suqs 825241675Suqs switch (tok) { 826241675Suqs case (MDOC_An): 827241675Suqs /* FALLTHROUGH */ 828241675Suqs case (MDOC_Ar): 829241675Suqs /* FALLTHROUGH */ 830241675Suqs case (MDOC_Fl): 831241675Suqs /* FALLTHROUGH */ 832241675Suqs case (MDOC_Mt): 833241675Suqs /* FALLTHROUGH */ 834241675Suqs case (MDOC_Nm): 835241675Suqs /* FALLTHROUGH */ 836241675Suqs case (MDOC_Pa): 837241675Suqs nc = 1; 838241675Suqs break; 839241675Suqs default: 840241675Suqs nc = 0; 841241675Suqs break; 842241675Suqs } 843241675Suqs 844241675Suqs for (arg = NULL;; ) { 845241675Suqs la = *pos; 846241675Suqs av = mdoc_argv(m, line, tok, &arg, pos, buf); 847241675Suqs 848241675Suqs if (ARGV_WORD == av) { 849241675Suqs *pos = la; 850241675Suqs break; 851241675Suqs } 852241675Suqs if (ARGV_EOLN == av) 853241675Suqs break; 854241675Suqs if (ARGV_ARG == av) 855241675Suqs continue; 856241675Suqs 857241675Suqs mdoc_argv_free(arg); 858241675Suqs return(0); 859241675Suqs } 860241675Suqs 861241675Suqs for (cnt = scope = 0;; ) { 862241675Suqs la = *pos; 863241675Suqs ac = mdoc_args(m, line, pos, buf, tok, &p); 864241675Suqs 865241675Suqs if (ARGS_ERROR == ac) 866241675Suqs return(0); 867241675Suqs if (ARGS_EOLN == ac) 868241675Suqs break; 869241675Suqs if (ARGS_PUNCT == ac) 870241675Suqs break; 871241675Suqs 872241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 873241675Suqs 874241675Suqs /* 875241675Suqs * In this case, we've located a submacro and must 876241675Suqs * execute it. Close out scope, if open. If no 877241675Suqs * elements have been generated, either create one (nc) 878241675Suqs * or raise a warning. 879241675Suqs */ 880241675Suqs 881241675Suqs if (MDOC_MAX != ntok) { 882241675Suqs if (scope && ! rew_elem(m, tok)) 883241675Suqs return(0); 884241675Suqs if (nc && 0 == cnt) { 885241675Suqs if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 886241675Suqs return(0); 887241675Suqs if ( ! rew_last(m, m->last)) 888241675Suqs return(0); 889241675Suqs } else if ( ! nc && 0 == cnt) { 890241675Suqs mdoc_argv_free(arg); 891241675Suqs mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); 892241675Suqs } 893241675Suqs 894241675Suqs if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 895241675Suqs return(0); 896241675Suqs if ( ! nl) 897241675Suqs return(1); 898241675Suqs return(append_delims(m, line, pos, buf)); 899241675Suqs } 900241675Suqs 901241675Suqs /* 902241675Suqs * Non-quote-enclosed punctuation. Set up our scope, if 903241675Suqs * a word; rewind the scope, if a delimiter; then append 904241675Suqs * the word. 905241675Suqs */ 906241675Suqs 907241675Suqs d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p); 908241675Suqs 909241675Suqs if (DELIM_NONE != d) { 910241675Suqs /* 911241675Suqs * If we encounter closing punctuation, no word 912241675Suqs * has been omitted, no scope is open, and we're 913241675Suqs * allowed to have an empty element, then start 914241675Suqs * a new scope. `Ar', `Fl', and `Li', only do 915241675Suqs * this once per invocation. There may be more 916241675Suqs * of these (all of them?). 917241675Suqs */ 918241675Suqs if (0 == cnt && (nc || MDOC_Li == tok) && 919241675Suqs DELIM_CLOSE == d && ! scope) { 920241675Suqs if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 921241675Suqs return(0); 922241675Suqs if (MDOC_Ar == tok || MDOC_Li == tok || 923241675Suqs MDOC_Fl == tok) 924241675Suqs cnt++; 925241675Suqs scope = 1; 926241675Suqs } 927241675Suqs /* 928241675Suqs * Close out our scope, if one is open, before 929241675Suqs * any punctuation. 930241675Suqs */ 931241675Suqs if (scope && ! rew_elem(m, tok)) 932241675Suqs return(0); 933241675Suqs scope = 0; 934241675Suqs } else if ( ! scope) { 935241675Suqs if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 936241675Suqs return(0); 937241675Suqs scope = 1; 938241675Suqs } 939241675Suqs 940241675Suqs if (DELIM_NONE == d) 941241675Suqs cnt++; 942241675Suqs 943241675Suqs if ( ! dword(m, line, la, p, d)) 944241675Suqs return(0); 945241675Suqs 946241675Suqs /* 947241675Suqs * `Fl' macros have their scope re-opened with each new 948241675Suqs * word so that the `-' can be added to each one without 949241675Suqs * having to parse out spaces. 950241675Suqs */ 951241675Suqs if (scope && MDOC_Fl == tok) { 952241675Suqs if ( ! rew_elem(m, tok)) 953241675Suqs return(0); 954241675Suqs scope = 0; 955241675Suqs } 956241675Suqs } 957241675Suqs 958241675Suqs if (scope && ! rew_elem(m, tok)) 959241675Suqs return(0); 960241675Suqs 961241675Suqs /* 962241675Suqs * If no elements have been collected and we're allowed to have 963241675Suqs * empties (nc), open a scope and close it out. Otherwise, 964241675Suqs * raise a warning. 965241675Suqs */ 966241675Suqs 967241675Suqs if (nc && 0 == cnt) { 968241675Suqs if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 969241675Suqs return(0); 970241675Suqs if ( ! rew_last(m, m->last)) 971241675Suqs return(0); 972241675Suqs } else if ( ! nc && 0 == cnt) { 973241675Suqs mdoc_argv_free(arg); 974241675Suqs mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); 975241675Suqs } 976241675Suqs 977241675Suqs if ( ! nl) 978241675Suqs return(1); 979241675Suqs return(append_delims(m, line, pos, buf)); 980241675Suqs} 981241675Suqs 982241675Suqs 983241675Suqsstatic int 984241675Suqsblk_full(MACRO_PROT_ARGS) 985241675Suqs{ 986241675Suqs int la, nl, nparsed; 987241675Suqs struct mdoc_arg *arg; 988241675Suqs struct mdoc_node *head; /* save of head macro */ 989241675Suqs struct mdoc_node *body; /* save of body macro */ 990241675Suqs struct mdoc_node *n; 991241675Suqs enum mdoc_type mtt; 992241675Suqs enum mdoct ntok; 993241675Suqs enum margserr ac, lac; 994241675Suqs enum margverr av; 995241675Suqs char *p; 996241675Suqs 997241675Suqs nl = MDOC_NEWLINE & m->flags; 998241675Suqs 999241675Suqs /* Close out prior implicit scope. */ 1000241675Suqs 1001241675Suqs if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) { 1002241675Suqs if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1003241675Suqs return(0); 1004241675Suqs if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 1005241675Suqs return(0); 1006241675Suqs } 1007241675Suqs 1008241675Suqs /* 1009241675Suqs * This routine accommodates implicitly- and explicitly-scoped 1010241675Suqs * macro openings. Implicit ones first close out prior scope 1011241675Suqs * (seen above). Delay opening the head until necessary to 1012241675Suqs * allow leading punctuation to print. Special consideration 1013241675Suqs * for `It -column', which has phrase-part syntax instead of 1014241675Suqs * regular child nodes. 1015241675Suqs */ 1016241675Suqs 1017241675Suqs for (arg = NULL;; ) { 1018241675Suqs la = *pos; 1019241675Suqs av = mdoc_argv(m, line, tok, &arg, pos, buf); 1020241675Suqs 1021241675Suqs if (ARGV_WORD == av) { 1022241675Suqs *pos = la; 1023241675Suqs break; 1024241675Suqs } 1025241675Suqs 1026241675Suqs if (ARGV_EOLN == av) 1027241675Suqs break; 1028241675Suqs if (ARGV_ARG == av) 1029241675Suqs continue; 1030241675Suqs 1031241675Suqs mdoc_argv_free(arg); 1032241675Suqs return(0); 1033241675Suqs } 1034241675Suqs 1035241675Suqs if ( ! mdoc_block_alloc(m, line, ppos, tok, arg)) 1036241675Suqs return(0); 1037241675Suqs 1038241675Suqs head = body = NULL; 1039241675Suqs 1040241675Suqs /* 1041241675Suqs * Exception: Heads of `It' macros in `-diag' lists are not 1042241675Suqs * parsed, even though `It' macros in general are parsed. 1043241675Suqs */ 1044241675Suqs nparsed = MDOC_It == tok && 1045241675Suqs MDOC_Bl == m->last->parent->tok && 1046241675Suqs LIST_diag == m->last->parent->norm->Bl.type; 1047241675Suqs 1048241675Suqs /* 1049241675Suqs * The `Nd' macro has all arguments in its body: it's a hybrid 1050241675Suqs * of block partial-explicit and full-implicit. Stupid. 1051241675Suqs */ 1052241675Suqs 1053241675Suqs if (MDOC_Nd == tok) { 1054241675Suqs if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1055241675Suqs return(0); 1056241675Suqs head = m->last; 1057241675Suqs if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1058241675Suqs return(0); 1059241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1060241675Suqs return(0); 1061241675Suqs body = m->last; 1062241675Suqs } 1063241675Suqs 1064241675Suqs ac = ARGS_ERROR; 1065241675Suqs 1066241675Suqs for ( ; ; ) { 1067241675Suqs la = *pos; 1068241675Suqs /* Initialise last-phrase-type with ARGS_PEND. */ 1069241675Suqs lac = ARGS_ERROR == ac ? ARGS_PEND : ac; 1070241675Suqs ac = mdoc_args(m, line, pos, buf, tok, &p); 1071241675Suqs 1072241675Suqs if (ARGS_PUNCT == ac) 1073241675Suqs break; 1074241675Suqs 1075241675Suqs if (ARGS_ERROR == ac) 1076241675Suqs return(0); 1077241675Suqs 1078241675Suqs if (ARGS_EOLN == ac) { 1079241675Suqs if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac) 1080241675Suqs break; 1081241675Suqs /* 1082241675Suqs * This is necessary: if the last token on a 1083241675Suqs * line is a `Ta' or tab, then we'll get 1084241675Suqs * ARGS_EOLN, so we must be smart enough to 1085241675Suqs * reopen our scope if the last parse was a 1086241675Suqs * phrase or partial phrase. 1087241675Suqs */ 1088241675Suqs if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1089241675Suqs return(0); 1090241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1091241675Suqs return(0); 1092241675Suqs body = m->last; 1093241675Suqs break; 1094241675Suqs } 1095241675Suqs 1096241675Suqs /* 1097241675Suqs * Emit leading punctuation (i.e., punctuation before 1098241675Suqs * the MDOC_HEAD) for non-phrase types. 1099241675Suqs */ 1100241675Suqs 1101241675Suqs if (NULL == head && 1102241675Suqs ARGS_PEND != ac && 1103241675Suqs ARGS_PHRASE != ac && 1104241675Suqs ARGS_PPHRASE != ac && 1105241675Suqs ARGS_QWORD != ac && 1106241675Suqs DELIM_OPEN == mdoc_isdelim(p)) { 1107241675Suqs if ( ! dword(m, line, la, p, DELIM_OPEN)) 1108241675Suqs return(0); 1109241675Suqs continue; 1110241675Suqs } 1111241675Suqs 1112241675Suqs /* Open a head if one hasn't been opened. */ 1113241675Suqs 1114241675Suqs if (NULL == head) { 1115241675Suqs if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1116241675Suqs return(0); 1117241675Suqs head = m->last; 1118241675Suqs } 1119241675Suqs 1120241675Suqs if (ARGS_PHRASE == ac || 1121241675Suqs ARGS_PEND == ac || 1122241675Suqs ARGS_PPHRASE == ac) { 1123241675Suqs /* 1124241675Suqs * If we haven't opened a body yet, rewind the 1125241675Suqs * head; if we have, rewind that instead. 1126241675Suqs */ 1127241675Suqs 1128241675Suqs mtt = body ? MDOC_BODY : MDOC_HEAD; 1129241675Suqs if ( ! rew_sub(mtt, m, tok, line, ppos)) 1130241675Suqs return(0); 1131241675Suqs 1132241675Suqs /* Then allocate our body context. */ 1133241675Suqs 1134241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1135241675Suqs return(0); 1136241675Suqs body = m->last; 1137241675Suqs 1138241675Suqs /* 1139241675Suqs * Process phrases: set whether we're in a 1140241675Suqs * partial-phrase (this effects line handling) 1141241675Suqs * then call down into the phrase parser. 1142241675Suqs */ 1143241675Suqs 1144241675Suqs if (ARGS_PPHRASE == ac) 1145241675Suqs m->flags |= MDOC_PPHRASE; 1146241675Suqs if (ARGS_PEND == ac && ARGS_PPHRASE == lac) 1147241675Suqs m->flags |= MDOC_PPHRASE; 1148241675Suqs 1149241675Suqs if ( ! phrase(m, line, la, buf)) 1150241675Suqs return(0); 1151241675Suqs 1152241675Suqs m->flags &= ~MDOC_PPHRASE; 1153241675Suqs continue; 1154241675Suqs } 1155241675Suqs 1156241675Suqs ntok = nparsed || ARGS_QWORD == ac ? 1157241675Suqs MDOC_MAX : lookup(tok, p); 1158241675Suqs 1159241675Suqs if (MDOC_MAX == ntok) { 1160241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1161241675Suqs return(0); 1162241675Suqs continue; 1163241675Suqs } 1164241675Suqs 1165241675Suqs if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1166241675Suqs return(0); 1167241675Suqs break; 1168241675Suqs } 1169241675Suqs 1170241675Suqs if (NULL == head) { 1171241675Suqs if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1172241675Suqs return(0); 1173241675Suqs head = m->last; 1174241675Suqs } 1175241675Suqs 1176241675Suqs if (nl && ! append_delims(m, line, pos, buf)) 1177241675Suqs return(0); 1178241675Suqs 1179241675Suqs /* If we've already opened our body, exit now. */ 1180241675Suqs 1181241675Suqs if (NULL != body) 1182241675Suqs goto out; 1183241675Suqs 1184241675Suqs /* 1185241675Suqs * If there is an open (i.e., unvalidated) sub-block requiring 1186241675Suqs * explicit close-out, postpone switching the current block from 1187241675Suqs * head to body until the rew_sub() call closing out that 1188241675Suqs * sub-block. 1189241675Suqs */ 1190241675Suqs for (n = m->last; n && n != head; n = n->parent) { 1191241675Suqs if (MDOC_BLOCK == n->type && 1192241675Suqs MDOC_EXPLICIT & mdoc_macros[n->tok].flags && 1193241675Suqs ! (MDOC_VALID & n->flags)) { 1194241675Suqs n->pending = head; 1195241675Suqs return(1); 1196241675Suqs } 1197241675Suqs } 1198241675Suqs 1199241675Suqs /* Close out scopes to remain in a consistent state. */ 1200241675Suqs 1201241675Suqs if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1202241675Suqs return(0); 1203241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1204241675Suqs return(0); 1205241675Suqs 1206241675Suqsout: 1207241675Suqs if ( ! (MDOC_FREECOL & m->flags)) 1208241675Suqs return(1); 1209241675Suqs 1210241675Suqs if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1211241675Suqs return(0); 1212241675Suqs if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 1213241675Suqs return(0); 1214241675Suqs 1215241675Suqs m->flags &= ~MDOC_FREECOL; 1216241675Suqs return(1); 1217241675Suqs} 1218241675Suqs 1219241675Suqs 1220241675Suqsstatic int 1221241675Suqsblk_part_imp(MACRO_PROT_ARGS) 1222241675Suqs{ 1223241675Suqs int la, nl; 1224241675Suqs enum mdoct ntok; 1225241675Suqs enum margserr ac; 1226241675Suqs char *p; 1227241675Suqs struct mdoc_node *blk; /* saved block context */ 1228241675Suqs struct mdoc_node *body; /* saved body context */ 1229241675Suqs struct mdoc_node *n; 1230241675Suqs 1231241675Suqs nl = MDOC_NEWLINE & m->flags; 1232241675Suqs 1233241675Suqs /* 1234241675Suqs * A macro that spans to the end of the line. This is generally 1235241675Suqs * (but not necessarily) called as the first macro. The block 1236241675Suqs * has a head as the immediate child, which is always empty, 1237241675Suqs * followed by zero or more opening punctuation nodes, then the 1238241675Suqs * body (which may be empty, depending on the macro), then zero 1239241675Suqs * or more closing punctuation nodes. 1240241675Suqs */ 1241241675Suqs 1242241675Suqs if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) 1243241675Suqs return(0); 1244241675Suqs 1245241675Suqs blk = m->last; 1246241675Suqs 1247241675Suqs if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1248241675Suqs return(0); 1249241675Suqs if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1250241675Suqs return(0); 1251241675Suqs 1252241675Suqs /* 1253241675Suqs * Open the body scope "on-demand", that is, after we've 1254241675Suqs * processed all our the leading delimiters (open parenthesis, 1255241675Suqs * etc.). 1256241675Suqs */ 1257241675Suqs 1258241675Suqs for (body = NULL; ; ) { 1259241675Suqs la = *pos; 1260241675Suqs ac = mdoc_args(m, line, pos, buf, tok, &p); 1261241675Suqs 1262241675Suqs if (ARGS_ERROR == ac) 1263241675Suqs return(0); 1264241675Suqs if (ARGS_EOLN == ac) 1265241675Suqs break; 1266241675Suqs if (ARGS_PUNCT == ac) 1267241675Suqs break; 1268241675Suqs 1269241675Suqs if (NULL == body && ARGS_QWORD != ac && 1270241675Suqs DELIM_OPEN == mdoc_isdelim(p)) { 1271241675Suqs if ( ! dword(m, line, la, p, DELIM_OPEN)) 1272241675Suqs return(0); 1273241675Suqs continue; 1274241675Suqs } 1275241675Suqs 1276241675Suqs if (NULL == body) { 1277241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1278241675Suqs return(0); 1279241675Suqs body = m->last; 1280241675Suqs } 1281241675Suqs 1282241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1283241675Suqs 1284241675Suqs if (MDOC_MAX == ntok) { 1285241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1286241675Suqs return(0); 1287241675Suqs continue; 1288241675Suqs } 1289241675Suqs 1290241675Suqs if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1291241675Suqs return(0); 1292241675Suqs break; 1293241675Suqs } 1294241675Suqs 1295241675Suqs /* Clean-ups to leave in a consistent state. */ 1296241675Suqs 1297241675Suqs if (NULL == body) { 1298241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1299241675Suqs return(0); 1300241675Suqs body = m->last; 1301241675Suqs } 1302241675Suqs 1303241675Suqs for (n = body->child; n && n->next; n = n->next) 1304241675Suqs /* Do nothing. */ ; 1305241675Suqs 1306241675Suqs /* 1307241675Suqs * End of sentence spacing: if the last node is a text node and 1308241675Suqs * has a trailing period, then mark it as being end-of-sentence. 1309241675Suqs */ 1310241675Suqs 1311241675Suqs if (n && MDOC_TEXT == n->type && n->string) 1312241675Suqs if (mandoc_eos(n->string, strlen(n->string), 1)) 1313241675Suqs n->flags |= MDOC_EOS; 1314241675Suqs 1315241675Suqs /* Up-propagate the end-of-space flag. */ 1316241675Suqs 1317241675Suqs if (n && (MDOC_EOS & n->flags)) { 1318241675Suqs body->flags |= MDOC_EOS; 1319241675Suqs body->parent->flags |= MDOC_EOS; 1320241675Suqs } 1321241675Suqs 1322241675Suqs /* 1323241675Suqs * If there is an open sub-block requiring explicit close-out, 1324241675Suqs * postpone closing out the current block 1325241675Suqs * until the rew_sub() call closing out the sub-block. 1326241675Suqs */ 1327241675Suqs for (n = m->last; n && n != body && n != blk->parent; n = n->parent) { 1328241675Suqs if (MDOC_BLOCK == n->type && 1329241675Suqs MDOC_EXPLICIT & mdoc_macros[n->tok].flags && 1330241675Suqs ! (MDOC_VALID & n->flags)) { 1331241675Suqs make_pending(n, tok, m, line, ppos); 1332241675Suqs if ( ! mdoc_endbody_alloc(m, line, ppos, 1333241675Suqs tok, body, ENDBODY_NOSPACE)) 1334241675Suqs return(0); 1335241675Suqs return(1); 1336241675Suqs } 1337241675Suqs } 1338241675Suqs 1339241675Suqs /* 1340241675Suqs * If we can't rewind to our body, then our scope has already 1341241675Suqs * been closed by another macro (like `Oc' closing `Op'). This 1342241675Suqs * is ugly behaviour nodding its head to OpenBSD's overwhelming 1343241675Suqs * crufty use of `Op' breakage. 1344241675Suqs */ 1345241675Suqs if (n != body) 1346241675Suqs mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, 1347241675Suqs "%s broken", mdoc_macronames[tok]); 1348241675Suqs 1349241675Suqs if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1350241675Suqs return(0); 1351241675Suqs 1352241675Suqs /* Standard appending of delimiters. */ 1353241675Suqs 1354241675Suqs if (nl && ! append_delims(m, line, pos, buf)) 1355241675Suqs return(0); 1356241675Suqs 1357241675Suqs /* Rewind scope, if applicable. */ 1358241675Suqs 1359241675Suqs if (n && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 1360241675Suqs return(0); 1361241675Suqs 1362241675Suqs return(1); 1363241675Suqs} 1364241675Suqs 1365241675Suqs 1366241675Suqsstatic int 1367241675Suqsblk_part_exp(MACRO_PROT_ARGS) 1368241675Suqs{ 1369241675Suqs int la, nl; 1370241675Suqs enum margserr ac; 1371241675Suqs struct mdoc_node *head; /* keep track of head */ 1372241675Suqs struct mdoc_node *body; /* keep track of body */ 1373241675Suqs char *p; 1374241675Suqs enum mdoct ntok; 1375241675Suqs 1376241675Suqs nl = MDOC_NEWLINE & m->flags; 1377241675Suqs 1378241675Suqs /* 1379241675Suqs * The opening of an explicit macro having zero or more leading 1380241675Suqs * punctuation nodes; a head with optional single element (the 1381241675Suqs * case of `Eo'); and a body that may be empty. 1382241675Suqs */ 1383241675Suqs 1384241675Suqs if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) 1385241675Suqs return(0); 1386241675Suqs 1387241675Suqs for (head = body = NULL; ; ) { 1388241675Suqs la = *pos; 1389241675Suqs ac = mdoc_args(m, line, pos, buf, tok, &p); 1390241675Suqs 1391241675Suqs if (ARGS_ERROR == ac) 1392241675Suqs return(0); 1393241675Suqs if (ARGS_PUNCT == ac) 1394241675Suqs break; 1395241675Suqs if (ARGS_EOLN == ac) 1396241675Suqs break; 1397241675Suqs 1398241675Suqs /* Flush out leading punctuation. */ 1399241675Suqs 1400241675Suqs if (NULL == head && ARGS_QWORD != ac && 1401241675Suqs DELIM_OPEN == mdoc_isdelim(p)) { 1402241675Suqs assert(NULL == body); 1403241675Suqs if ( ! dword(m, line, la, p, DELIM_OPEN)) 1404241675Suqs return(0); 1405241675Suqs continue; 1406241675Suqs } 1407241675Suqs 1408241675Suqs if (NULL == head) { 1409241675Suqs assert(NULL == body); 1410241675Suqs if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1411241675Suqs return(0); 1412241675Suqs head = m->last; 1413241675Suqs } 1414241675Suqs 1415241675Suqs /* 1416241675Suqs * `Eo' gobbles any data into the head, but most other 1417241675Suqs * macros just immediately close out and begin the body. 1418241675Suqs */ 1419241675Suqs 1420241675Suqs if (NULL == body) { 1421241675Suqs assert(head); 1422241675Suqs /* No check whether it's a macro! */ 1423241675Suqs if (MDOC_Eo == tok) 1424241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1425241675Suqs return(0); 1426241675Suqs 1427241675Suqs if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1428241675Suqs return(0); 1429241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1430241675Suqs return(0); 1431241675Suqs body = m->last; 1432241675Suqs 1433241675Suqs if (MDOC_Eo == tok) 1434241675Suqs continue; 1435241675Suqs } 1436241675Suqs 1437241675Suqs assert(NULL != head && NULL != body); 1438241675Suqs 1439241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1440241675Suqs 1441241675Suqs if (MDOC_MAX == ntok) { 1442241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1443241675Suqs return(0); 1444241675Suqs continue; 1445241675Suqs } 1446241675Suqs 1447241675Suqs if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1448241675Suqs return(0); 1449241675Suqs break; 1450241675Suqs } 1451241675Suqs 1452241675Suqs /* Clean-up to leave in a consistent state. */ 1453241675Suqs 1454241675Suqs if (NULL == head) 1455241675Suqs if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1456241675Suqs return(0); 1457241675Suqs 1458241675Suqs if (NULL == body) { 1459241675Suqs if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1460241675Suqs return(0); 1461241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1462241675Suqs return(0); 1463241675Suqs } 1464241675Suqs 1465241675Suqs /* Standard appending of delimiters. */ 1466241675Suqs 1467241675Suqs if ( ! nl) 1468241675Suqs return(1); 1469241675Suqs return(append_delims(m, line, pos, buf)); 1470241675Suqs} 1471241675Suqs 1472241675Suqs 1473241675Suqs/* ARGSUSED */ 1474241675Suqsstatic int 1475241675Suqsin_line_argn(MACRO_PROT_ARGS) 1476241675Suqs{ 1477241675Suqs int la, flushed, j, maxargs, nl; 1478241675Suqs enum margserr ac; 1479241675Suqs enum margverr av; 1480241675Suqs struct mdoc_arg *arg; 1481241675Suqs char *p; 1482241675Suqs enum mdoct ntok; 1483241675Suqs 1484241675Suqs nl = MDOC_NEWLINE & m->flags; 1485241675Suqs 1486241675Suqs /* 1487241675Suqs * A line macro that has a fixed number of arguments (maxargs). 1488241675Suqs * Only open the scope once the first non-leading-punctuation is 1489241675Suqs * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then 1490241675Suqs * keep it open until the maximum number of arguments are 1491241675Suqs * exhausted. 1492241675Suqs */ 1493241675Suqs 1494241675Suqs switch (tok) { 1495241675Suqs case (MDOC_Ap): 1496241675Suqs /* FALLTHROUGH */ 1497241675Suqs case (MDOC_No): 1498241675Suqs /* FALLTHROUGH */ 1499241675Suqs case (MDOC_Ns): 1500241675Suqs /* FALLTHROUGH */ 1501241675Suqs case (MDOC_Ux): 1502241675Suqs maxargs = 0; 1503241675Suqs break; 1504241675Suqs case (MDOC_Bx): 1505241675Suqs /* FALLTHROUGH */ 1506241675Suqs case (MDOC_Xr): 1507241675Suqs maxargs = 2; 1508241675Suqs break; 1509241675Suqs default: 1510241675Suqs maxargs = 1; 1511241675Suqs break; 1512241675Suqs } 1513241675Suqs 1514241675Suqs for (arg = NULL; ; ) { 1515241675Suqs la = *pos; 1516241675Suqs av = mdoc_argv(m, line, tok, &arg, pos, buf); 1517241675Suqs 1518241675Suqs if (ARGV_WORD == av) { 1519241675Suqs *pos = la; 1520241675Suqs break; 1521241675Suqs } 1522241675Suqs 1523241675Suqs if (ARGV_EOLN == av) 1524241675Suqs break; 1525241675Suqs if (ARGV_ARG == av) 1526241675Suqs continue; 1527241675Suqs 1528241675Suqs mdoc_argv_free(arg); 1529241675Suqs return(0); 1530241675Suqs } 1531241675Suqs 1532241675Suqs for (flushed = j = 0; ; ) { 1533241675Suqs la = *pos; 1534241675Suqs ac = mdoc_args(m, line, pos, buf, tok, &p); 1535241675Suqs 1536241675Suqs if (ARGS_ERROR == ac) 1537241675Suqs return(0); 1538241675Suqs if (ARGS_PUNCT == ac) 1539241675Suqs break; 1540241675Suqs if (ARGS_EOLN == ac) 1541241675Suqs break; 1542241675Suqs 1543241675Suqs if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 1544241675Suqs ARGS_QWORD != ac && 0 == j && 1545241675Suqs DELIM_OPEN == mdoc_isdelim(p)) { 1546241675Suqs if ( ! dword(m, line, la, p, DELIM_OPEN)) 1547241675Suqs return(0); 1548241675Suqs continue; 1549241675Suqs } else if (0 == j) 1550241675Suqs if ( ! mdoc_elem_alloc(m, line, la, tok, arg)) 1551241675Suqs return(0); 1552241675Suqs 1553241675Suqs if (j == maxargs && ! flushed) { 1554241675Suqs if ( ! rew_elem(m, tok)) 1555241675Suqs return(0); 1556241675Suqs flushed = 1; 1557241675Suqs } 1558241675Suqs 1559241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1560241675Suqs 1561241675Suqs if (MDOC_MAX != ntok) { 1562241675Suqs if ( ! flushed && ! rew_elem(m, tok)) 1563241675Suqs return(0); 1564241675Suqs flushed = 1; 1565241675Suqs if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1566241675Suqs return(0); 1567241675Suqs j++; 1568241675Suqs break; 1569241675Suqs } 1570241675Suqs 1571241675Suqs if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 1572241675Suqs ARGS_QWORD != ac && 1573241675Suqs ! flushed && 1574241675Suqs DELIM_NONE != mdoc_isdelim(p)) { 1575241675Suqs if ( ! rew_elem(m, tok)) 1576241675Suqs return(0); 1577241675Suqs flushed = 1; 1578241675Suqs } 1579241675Suqs 1580241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1581241675Suqs return(0); 1582241675Suqs j++; 1583241675Suqs } 1584241675Suqs 1585241675Suqs if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg)) 1586241675Suqs return(0); 1587241675Suqs 1588241675Suqs /* Close out in a consistent state. */ 1589241675Suqs 1590241675Suqs if ( ! flushed && ! rew_elem(m, tok)) 1591241675Suqs return(0); 1592241675Suqs if ( ! nl) 1593241675Suqs return(1); 1594241675Suqs return(append_delims(m, line, pos, buf)); 1595241675Suqs} 1596241675Suqs 1597241675Suqs 1598241675Suqsstatic int 1599241675Suqsin_line_eoln(MACRO_PROT_ARGS) 1600241675Suqs{ 1601241675Suqs int la; 1602241675Suqs enum margserr ac; 1603241675Suqs enum margverr av; 1604241675Suqs struct mdoc_arg *arg; 1605241675Suqs char *p; 1606241675Suqs enum mdoct ntok; 1607241675Suqs 1608241675Suqs assert( ! (MDOC_PARSED & mdoc_macros[tok].flags)); 1609241675Suqs 1610241675Suqs if (tok == MDOC_Pp) 1611241675Suqs rew_sub(MDOC_BLOCK, m, MDOC_Nm, line, ppos); 1612241675Suqs 1613241675Suqs /* Parse macro arguments. */ 1614241675Suqs 1615241675Suqs for (arg = NULL; ; ) { 1616241675Suqs la = *pos; 1617241675Suqs av = mdoc_argv(m, line, tok, &arg, pos, buf); 1618241675Suqs 1619241675Suqs if (ARGV_WORD == av) { 1620241675Suqs *pos = la; 1621241675Suqs break; 1622241675Suqs } 1623241675Suqs if (ARGV_EOLN == av) 1624241675Suqs break; 1625241675Suqs if (ARGV_ARG == av) 1626241675Suqs continue; 1627241675Suqs 1628241675Suqs mdoc_argv_free(arg); 1629241675Suqs return(0); 1630241675Suqs } 1631241675Suqs 1632241675Suqs /* Open element scope. */ 1633241675Suqs 1634241675Suqs if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 1635241675Suqs return(0); 1636241675Suqs 1637241675Suqs /* Parse argument terms. */ 1638241675Suqs 1639241675Suqs for (;;) { 1640241675Suqs la = *pos; 1641241675Suqs ac = mdoc_args(m, line, pos, buf, tok, &p); 1642241675Suqs 1643241675Suqs if (ARGS_ERROR == ac) 1644241675Suqs return(0); 1645241675Suqs if (ARGS_EOLN == ac) 1646241675Suqs break; 1647241675Suqs 1648241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1649241675Suqs 1650241675Suqs if (MDOC_MAX == ntok) { 1651241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1652241675Suqs return(0); 1653241675Suqs continue; 1654241675Suqs } 1655241675Suqs 1656241675Suqs if ( ! rew_elem(m, tok)) 1657241675Suqs return(0); 1658241675Suqs return(mdoc_macro(m, ntok, line, la, pos, buf)); 1659241675Suqs } 1660241675Suqs 1661241675Suqs /* Close out (no delimiters). */ 1662241675Suqs 1663241675Suqs return(rew_elem(m, tok)); 1664241675Suqs} 1665241675Suqs 1666241675Suqs 1667241675Suqs/* ARGSUSED */ 1668241675Suqsstatic int 1669241675Suqsctx_synopsis(MACRO_PROT_ARGS) 1670241675Suqs{ 1671241675Suqs int nl; 1672241675Suqs 1673241675Suqs nl = MDOC_NEWLINE & m->flags; 1674241675Suqs 1675241675Suqs /* If we're not in the SYNOPSIS, go straight to in-line. */ 1676241675Suqs if ( ! (MDOC_SYNOPSIS & m->flags)) 1677241675Suqs return(in_line(m, tok, line, ppos, pos, buf)); 1678241675Suqs 1679241675Suqs /* If we're a nested call, same place. */ 1680241675Suqs if ( ! nl) 1681241675Suqs return(in_line(m, tok, line, ppos, pos, buf)); 1682241675Suqs 1683241675Suqs /* 1684241675Suqs * XXX: this will open a block scope; however, if later we end 1685241675Suqs * up formatting the block scope, then child nodes will inherit 1686241675Suqs * the formatting. Be careful. 1687241675Suqs */ 1688241675Suqs if (MDOC_Nm == tok) 1689241675Suqs return(blk_full(m, tok, line, ppos, pos, buf)); 1690241675Suqs assert(MDOC_Vt == tok); 1691241675Suqs return(blk_part_imp(m, tok, line, ppos, pos, buf)); 1692241675Suqs} 1693241675Suqs 1694241675Suqs 1695241675Suqs/* ARGSUSED */ 1696241675Suqsstatic int 1697241675Suqsobsolete(MACRO_PROT_ARGS) 1698241675Suqs{ 1699241675Suqs 1700241675Suqs mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS); 1701241675Suqs return(1); 1702241675Suqs} 1703241675Suqs 1704241675Suqs 1705241675Suqs/* 1706241675Suqs * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs. 1707241675Suqs * They're unusual because they're basically free-form text until a 1708241675Suqs * macro is encountered. 1709241675Suqs */ 1710241675Suqsstatic int 1711241675Suqsphrase(struct mdoc *m, int line, int ppos, char *buf) 1712241675Suqs{ 1713241675Suqs int la, pos; 1714241675Suqs enum margserr ac; 1715241675Suqs enum mdoct ntok; 1716241675Suqs char *p; 1717241675Suqs 1718241675Suqs for (pos = ppos; ; ) { 1719241675Suqs la = pos; 1720241675Suqs 1721241675Suqs ac = mdoc_zargs(m, line, &pos, buf, &p); 1722241675Suqs 1723241675Suqs if (ARGS_ERROR == ac) 1724241675Suqs return(0); 1725241675Suqs if (ARGS_EOLN == ac) 1726241675Suqs break; 1727241675Suqs 1728241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); 1729241675Suqs 1730241675Suqs if (MDOC_MAX == ntok) { 1731241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1732241675Suqs return(0); 1733241675Suqs continue; 1734241675Suqs } 1735241675Suqs 1736241675Suqs if ( ! mdoc_macro(m, ntok, line, la, &pos, buf)) 1737241675Suqs return(0); 1738241675Suqs return(append_delims(m, line, &pos, buf)); 1739241675Suqs } 1740241675Suqs 1741241675Suqs return(1); 1742241675Suqs} 1743241675Suqs 1744241675Suqs 1745241675Suqs/* ARGSUSED */ 1746241675Suqsstatic int 1747241675Suqsphrase_ta(MACRO_PROT_ARGS) 1748241675Suqs{ 1749241675Suqs int la; 1750241675Suqs enum mdoct ntok; 1751241675Suqs enum margserr ac; 1752241675Suqs char *p; 1753241675Suqs 1754241675Suqs /* 1755241675Suqs * FIXME: this is overly restrictive: if the `Ta' is unexpected, 1756241675Suqs * it should simply error out with ARGSLOST. 1757241675Suqs */ 1758241675Suqs 1759241675Suqs if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos)) 1760241675Suqs return(0); 1761241675Suqs if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It)) 1762241675Suqs return(0); 1763241675Suqs 1764241675Suqs for (;;) { 1765241675Suqs la = *pos; 1766241675Suqs ac = mdoc_zargs(m, line, pos, buf, &p); 1767241675Suqs 1768241675Suqs if (ARGS_ERROR == ac) 1769241675Suqs return(0); 1770241675Suqs if (ARGS_EOLN == ac) 1771241675Suqs break; 1772241675Suqs 1773241675Suqs ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); 1774241675Suqs 1775241675Suqs if (MDOC_MAX == ntok) { 1776241675Suqs if ( ! dword(m, line, la, p, DELIM_MAX)) 1777241675Suqs return(0); 1778241675Suqs continue; 1779241675Suqs } 1780241675Suqs 1781241675Suqs if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1782241675Suqs return(0); 1783241675Suqs return(append_delims(m, line, pos, buf)); 1784241675Suqs } 1785241675Suqs 1786241675Suqs return(1); 1787241675Suqs} 1788