1*95c635efSGarrett D'Amore /* $Id: mdoc_macro.c,v 1.115 2012/01/05 00:43:51 schwarze Exp $ */ 2*95c635efSGarrett D'Amore /* 3*95c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*95c635efSGarrett D'Amore * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> 5*95c635efSGarrett D'Amore * 6*95c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 7*95c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 8*95c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 9*95c635efSGarrett D'Amore * 10*95c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*95c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*95c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*95c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*95c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*95c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*95c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*95c635efSGarrett D'Amore */ 18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 19*95c635efSGarrett D'Amore #include "config.h" 20*95c635efSGarrett D'Amore #endif 21*95c635efSGarrett D'Amore 22*95c635efSGarrett D'Amore #include <assert.h> 23*95c635efSGarrett D'Amore #include <ctype.h> 24*95c635efSGarrett D'Amore #include <stdlib.h> 25*95c635efSGarrett D'Amore #include <stdio.h> 26*95c635efSGarrett D'Amore #include <string.h> 27*95c635efSGarrett D'Amore #include <time.h> 28*95c635efSGarrett D'Amore 29*95c635efSGarrett D'Amore #include "mdoc.h" 30*95c635efSGarrett D'Amore #include "mandoc.h" 31*95c635efSGarrett D'Amore #include "libmdoc.h" 32*95c635efSGarrett D'Amore #include "libmandoc.h" 33*95c635efSGarrett D'Amore 34*95c635efSGarrett D'Amore enum rew { /* see rew_dohalt() */ 35*95c635efSGarrett D'Amore REWIND_NONE, 36*95c635efSGarrett D'Amore REWIND_THIS, 37*95c635efSGarrett D'Amore REWIND_MORE, 38*95c635efSGarrett D'Amore REWIND_FORCE, 39*95c635efSGarrett D'Amore REWIND_LATER, 40*95c635efSGarrett D'Amore REWIND_ERROR 41*95c635efSGarrett D'Amore }; 42*95c635efSGarrett D'Amore 43*95c635efSGarrett D'Amore static int blk_full(MACRO_PROT_ARGS); 44*95c635efSGarrett D'Amore static int blk_exp_close(MACRO_PROT_ARGS); 45*95c635efSGarrett D'Amore static int blk_part_exp(MACRO_PROT_ARGS); 46*95c635efSGarrett D'Amore static int blk_part_imp(MACRO_PROT_ARGS); 47*95c635efSGarrett D'Amore static int ctx_synopsis(MACRO_PROT_ARGS); 48*95c635efSGarrett D'Amore static int in_line_eoln(MACRO_PROT_ARGS); 49*95c635efSGarrett D'Amore static int in_line_argn(MACRO_PROT_ARGS); 50*95c635efSGarrett D'Amore static int in_line(MACRO_PROT_ARGS); 51*95c635efSGarrett D'Amore static int obsolete(MACRO_PROT_ARGS); 52*95c635efSGarrett D'Amore static int phrase_ta(MACRO_PROT_ARGS); 53*95c635efSGarrett D'Amore 54*95c635efSGarrett D'Amore static int dword(struct mdoc *, int, int, 55*95c635efSGarrett D'Amore const char *, enum mdelim); 56*95c635efSGarrett D'Amore static int append_delims(struct mdoc *, 57*95c635efSGarrett D'Amore int, int *, char *); 58*95c635efSGarrett D'Amore static enum mdoct lookup(enum mdoct, const char *); 59*95c635efSGarrett D'Amore static enum mdoct lookup_raw(const char *); 60*95c635efSGarrett D'Amore static int make_pending(struct mdoc_node *, enum mdoct, 61*95c635efSGarrett D'Amore struct mdoc *, int, int); 62*95c635efSGarrett D'Amore static int phrase(struct mdoc *, int, int, char *); 63*95c635efSGarrett D'Amore static enum mdoct rew_alt(enum mdoct); 64*95c635efSGarrett D'Amore static enum rew rew_dohalt(enum mdoct, enum mdoc_type, 65*95c635efSGarrett D'Amore const struct mdoc_node *); 66*95c635efSGarrett D'Amore static int rew_elem(struct mdoc *, enum mdoct); 67*95c635efSGarrett D'Amore static int rew_last(struct mdoc *, 68*95c635efSGarrett D'Amore const struct mdoc_node *); 69*95c635efSGarrett D'Amore static int rew_sub(enum mdoc_type, struct mdoc *, 70*95c635efSGarrett D'Amore enum mdoct, int, int); 71*95c635efSGarrett D'Amore 72*95c635efSGarrett D'Amore const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { 73*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */ 74*95c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ 75*95c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ 76*95c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Os */ 77*95c635efSGarrett D'Amore { blk_full, MDOC_PARSED }, /* Sh */ 78*95c635efSGarrett D'Amore { blk_full, MDOC_PARSED }, /* Ss */ 79*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Pp */ 80*95c635efSGarrett D'Amore { blk_part_imp, MDOC_PARSED }, /* D1 */ 81*95c635efSGarrett D'Amore { blk_part_imp, MDOC_PARSED }, /* Dl */ 82*95c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bd */ 83*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT }, /* Ed */ 84*95c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bl */ 85*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT }, /* El */ 86*95c635efSGarrett D'Amore { blk_full, MDOC_PARSED }, /* It */ 87*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ 88*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */ 89*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ 90*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */ 91*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ 92*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ 93*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ 94*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ 95*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Ex */ 96*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ 97*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Fd */ 98*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */ 99*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ 100*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ 101*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */ 102*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ 103*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ 104*95c635efSGarrett D'Amore { blk_full, 0 }, /* Nd */ 105*95c635efSGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ 106*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ 107*95c635efSGarrett D'Amore { obsolete, 0 }, /* Ot */ 108*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ 109*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Rv */ 110*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ 111*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */ 112*95c635efSGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ 113*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */ 114*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %A */ 115*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %B */ 116*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %D */ 117*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %I */ 118*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %J */ 119*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %N */ 120*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %O */ 121*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %P */ 122*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %R */ 123*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %T */ 124*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %V */ 125*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */ 126*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */ 127*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */ 128*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */ 129*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */ 130*95c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bf */ 131*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */ 132*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */ 133*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */ 134*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */ 135*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Db */ 136*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */ 137*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */ 138*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */ 139*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */ 140*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT }, /* Ef */ 141*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */ 142*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */ 143*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */ 144*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */ 145*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* No */ 146*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Ns */ 147*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ 148*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */ 149*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */ 150*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */ 151*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */ 152*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */ 153*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */ 154*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */ 155*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */ 156*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */ 157*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT }, /* Re */ 158*95c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Rs */ 159*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */ 160*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */ 161*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */ 162*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Sm */ 163*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */ 164*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */ 165*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */ 166*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */ 167*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */ 168*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */ 169*95c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ 170*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */ 171*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */ 172*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */ 173*95c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bk */ 174*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT }, /* Ek */ 175*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Bt */ 176*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Hf */ 177*95c635efSGarrett D'Amore { obsolete, 0 }, /* Fr */ 178*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Ud */ 179*95c635efSGarrett D'Amore { in_line, 0 }, /* Lb */ 180*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Lp */ 181*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ 182*95c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ 183*95c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */ 184*95c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */ 185*95c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */ 186*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %C */ 187*95c635efSGarrett D'Amore { obsolete, 0 }, /* Es */ 188*95c635efSGarrett D'Amore { obsolete, 0 }, /* En */ 189*95c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ 190*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %Q */ 191*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* br */ 192*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* sp */ 193*95c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %U */ 194*95c635efSGarrett D'Amore { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */ 195*95c635efSGarrett D'Amore }; 196*95c635efSGarrett D'Amore 197*95c635efSGarrett D'Amore const struct mdoc_macro * const mdoc_macros = __mdoc_macros; 198*95c635efSGarrett D'Amore 199*95c635efSGarrett D'Amore 200*95c635efSGarrett D'Amore /* 201*95c635efSGarrett D'Amore * This is called at the end of parsing. It must traverse up the tree, 202*95c635efSGarrett D'Amore * closing out open [implicit] scopes. Obviously, open explicit scopes 203*95c635efSGarrett D'Amore * are errors. 204*95c635efSGarrett D'Amore */ 205*95c635efSGarrett D'Amore int 206*95c635efSGarrett D'Amore mdoc_macroend(struct mdoc *m) 207*95c635efSGarrett D'Amore { 208*95c635efSGarrett D'Amore struct mdoc_node *n; 209*95c635efSGarrett D'Amore 210*95c635efSGarrett D'Amore /* Scan for open explicit scopes. */ 211*95c635efSGarrett D'Amore 212*95c635efSGarrett D'Amore n = MDOC_VALID & m->last->flags ? m->last->parent : m->last; 213*95c635efSGarrett D'Amore 214*95c635efSGarrett D'Amore for ( ; n; n = n->parent) 215*95c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && 216*95c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[n->tok].flags) 217*95c635efSGarrett D'Amore mdoc_nmsg(m, n, MANDOCERR_SCOPEEXIT); 218*95c635efSGarrett D'Amore 219*95c635efSGarrett D'Amore /* Rewind to the first. */ 220*95c635efSGarrett D'Amore 221*95c635efSGarrett D'Amore return(rew_last(m, m->first)); 222*95c635efSGarrett D'Amore } 223*95c635efSGarrett D'Amore 224*95c635efSGarrett D'Amore 225*95c635efSGarrett D'Amore /* 226*95c635efSGarrett D'Amore * Look up a macro from within a subsequent context. 227*95c635efSGarrett D'Amore */ 228*95c635efSGarrett D'Amore static enum mdoct 229*95c635efSGarrett D'Amore lookup(enum mdoct from, const char *p) 230*95c635efSGarrett D'Amore { 231*95c635efSGarrett D'Amore 232*95c635efSGarrett D'Amore if ( ! (MDOC_PARSED & mdoc_macros[from].flags)) 233*95c635efSGarrett D'Amore return(MDOC_MAX); 234*95c635efSGarrett D'Amore return(lookup_raw(p)); 235*95c635efSGarrett D'Amore } 236*95c635efSGarrett D'Amore 237*95c635efSGarrett D'Amore 238*95c635efSGarrett D'Amore /* 239*95c635efSGarrett D'Amore * Lookup a macro following the initial line macro. 240*95c635efSGarrett D'Amore */ 241*95c635efSGarrett D'Amore static enum mdoct 242*95c635efSGarrett D'Amore lookup_raw(const char *p) 243*95c635efSGarrett D'Amore { 244*95c635efSGarrett D'Amore enum mdoct res; 245*95c635efSGarrett D'Amore 246*95c635efSGarrett D'Amore if (MDOC_MAX == (res = mdoc_hash_find(p))) 247*95c635efSGarrett D'Amore return(MDOC_MAX); 248*95c635efSGarrett D'Amore if (MDOC_CALLABLE & mdoc_macros[res].flags) 249*95c635efSGarrett D'Amore return(res); 250*95c635efSGarrett D'Amore return(MDOC_MAX); 251*95c635efSGarrett D'Amore } 252*95c635efSGarrett D'Amore 253*95c635efSGarrett D'Amore 254*95c635efSGarrett D'Amore static int 255*95c635efSGarrett D'Amore rew_last(struct mdoc *mdoc, const struct mdoc_node *to) 256*95c635efSGarrett D'Amore { 257*95c635efSGarrett D'Amore struct mdoc_node *n, *np; 258*95c635efSGarrett D'Amore 259*95c635efSGarrett D'Amore assert(to); 260*95c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 261*95c635efSGarrett D'Amore 262*95c635efSGarrett D'Amore /* LINTED */ 263*95c635efSGarrett D'Amore while (mdoc->last != to) { 264*95c635efSGarrett D'Amore /* 265*95c635efSGarrett D'Amore * Save the parent here, because we may delete the 266*95c635efSGarrett D'Amore * m->last node in the post-validation phase and reset 267*95c635efSGarrett D'Amore * it to m->last->parent, causing a step in the closing 268*95c635efSGarrett D'Amore * out to be lost. 269*95c635efSGarrett D'Amore */ 270*95c635efSGarrett D'Amore np = mdoc->last->parent; 271*95c635efSGarrett D'Amore if ( ! mdoc_valid_post(mdoc)) 272*95c635efSGarrett D'Amore return(0); 273*95c635efSGarrett D'Amore n = mdoc->last; 274*95c635efSGarrett D'Amore mdoc->last = np; 275*95c635efSGarrett D'Amore assert(mdoc->last); 276*95c635efSGarrett D'Amore mdoc->last->last = n; 277*95c635efSGarrett D'Amore } 278*95c635efSGarrett D'Amore 279*95c635efSGarrett D'Amore return(mdoc_valid_post(mdoc)); 280*95c635efSGarrett D'Amore } 281*95c635efSGarrett D'Amore 282*95c635efSGarrett D'Amore 283*95c635efSGarrett D'Amore /* 284*95c635efSGarrett D'Amore * For a block closing macro, return the corresponding opening one. 285*95c635efSGarrett D'Amore * Otherwise, return the macro itself. 286*95c635efSGarrett D'Amore */ 287*95c635efSGarrett D'Amore static enum mdoct 288*95c635efSGarrett D'Amore rew_alt(enum mdoct tok) 289*95c635efSGarrett D'Amore { 290*95c635efSGarrett D'Amore switch (tok) { 291*95c635efSGarrett D'Amore case (MDOC_Ac): 292*95c635efSGarrett D'Amore return(MDOC_Ao); 293*95c635efSGarrett D'Amore case (MDOC_Bc): 294*95c635efSGarrett D'Amore return(MDOC_Bo); 295*95c635efSGarrett D'Amore case (MDOC_Brc): 296*95c635efSGarrett D'Amore return(MDOC_Bro); 297*95c635efSGarrett D'Amore case (MDOC_Dc): 298*95c635efSGarrett D'Amore return(MDOC_Do); 299*95c635efSGarrett D'Amore case (MDOC_Ec): 300*95c635efSGarrett D'Amore return(MDOC_Eo); 301*95c635efSGarrett D'Amore case (MDOC_Ed): 302*95c635efSGarrett D'Amore return(MDOC_Bd); 303*95c635efSGarrett D'Amore case (MDOC_Ef): 304*95c635efSGarrett D'Amore return(MDOC_Bf); 305*95c635efSGarrett D'Amore case (MDOC_Ek): 306*95c635efSGarrett D'Amore return(MDOC_Bk); 307*95c635efSGarrett D'Amore case (MDOC_El): 308*95c635efSGarrett D'Amore return(MDOC_Bl); 309*95c635efSGarrett D'Amore case (MDOC_Fc): 310*95c635efSGarrett D'Amore return(MDOC_Fo); 311*95c635efSGarrett D'Amore case (MDOC_Oc): 312*95c635efSGarrett D'Amore return(MDOC_Oo); 313*95c635efSGarrett D'Amore case (MDOC_Pc): 314*95c635efSGarrett D'Amore return(MDOC_Po); 315*95c635efSGarrett D'Amore case (MDOC_Qc): 316*95c635efSGarrett D'Amore return(MDOC_Qo); 317*95c635efSGarrett D'Amore case (MDOC_Re): 318*95c635efSGarrett D'Amore return(MDOC_Rs); 319*95c635efSGarrett D'Amore case (MDOC_Sc): 320*95c635efSGarrett D'Amore return(MDOC_So); 321*95c635efSGarrett D'Amore case (MDOC_Xc): 322*95c635efSGarrett D'Amore return(MDOC_Xo); 323*95c635efSGarrett D'Amore default: 324*95c635efSGarrett D'Amore return(tok); 325*95c635efSGarrett D'Amore } 326*95c635efSGarrett D'Amore /* NOTREACHED */ 327*95c635efSGarrett D'Amore } 328*95c635efSGarrett D'Amore 329*95c635efSGarrett D'Amore 330*95c635efSGarrett D'Amore /* 331*95c635efSGarrett D'Amore * Rewinding to tok, how do we have to handle *p? 332*95c635efSGarrett D'Amore * REWIND_NONE: *p would delimit tok, but no tok scope is open 333*95c635efSGarrett D'Amore * inside *p, so there is no need to rewind anything at all. 334*95c635efSGarrett D'Amore * REWIND_THIS: *p matches tok, so rewind *p and nothing else. 335*95c635efSGarrett D'Amore * REWIND_MORE: *p is implicit, rewind it and keep searching for tok. 336*95c635efSGarrett D'Amore * REWIND_FORCE: *p is explicit, but tok is full, force rewinding *p. 337*95c635efSGarrett D'Amore * REWIND_LATER: *p is explicit and still open, postpone rewinding. 338*95c635efSGarrett D'Amore * REWIND_ERROR: No tok block is open at all. 339*95c635efSGarrett D'Amore */ 340*95c635efSGarrett D'Amore static enum rew 341*95c635efSGarrett D'Amore rew_dohalt(enum mdoct tok, enum mdoc_type type, 342*95c635efSGarrett D'Amore const struct mdoc_node *p) 343*95c635efSGarrett D'Amore { 344*95c635efSGarrett D'Amore 345*95c635efSGarrett D'Amore /* 346*95c635efSGarrett D'Amore * No matching token, no delimiting block, no broken block. 347*95c635efSGarrett D'Amore * This can happen when full implicit macros are called for 348*95c635efSGarrett D'Amore * the first time but try to rewind their previous 349*95c635efSGarrett D'Amore * instance anyway. 350*95c635efSGarrett D'Amore */ 351*95c635efSGarrett D'Amore if (MDOC_ROOT == p->type) 352*95c635efSGarrett D'Amore return(MDOC_BLOCK == type && 353*95c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[tok].flags ? 354*95c635efSGarrett D'Amore REWIND_ERROR : REWIND_NONE); 355*95c635efSGarrett D'Amore 356*95c635efSGarrett D'Amore /* 357*95c635efSGarrett D'Amore * When starting to rewind, skip plain text 358*95c635efSGarrett D'Amore * and nodes that have already been rewound. 359*95c635efSGarrett D'Amore */ 360*95c635efSGarrett D'Amore if (MDOC_TEXT == p->type || MDOC_VALID & p->flags) 361*95c635efSGarrett D'Amore return(REWIND_MORE); 362*95c635efSGarrett D'Amore 363*95c635efSGarrett D'Amore /* 364*95c635efSGarrett D'Amore * The easiest case: Found a matching token. 365*95c635efSGarrett D'Amore * This applies to both blocks and elements. 366*95c635efSGarrett D'Amore */ 367*95c635efSGarrett D'Amore tok = rew_alt(tok); 368*95c635efSGarrett D'Amore if (tok == p->tok) 369*95c635efSGarrett D'Amore return(p->end ? REWIND_NONE : 370*95c635efSGarrett D'Amore type == p->type ? REWIND_THIS : REWIND_MORE); 371*95c635efSGarrett D'Amore 372*95c635efSGarrett D'Amore /* 373*95c635efSGarrett D'Amore * While elements do require rewinding for themselves, 374*95c635efSGarrett D'Amore * they never affect rewinding of other nodes. 375*95c635efSGarrett D'Amore */ 376*95c635efSGarrett D'Amore if (MDOC_ELEM == p->type) 377*95c635efSGarrett D'Amore return(REWIND_MORE); 378*95c635efSGarrett D'Amore 379*95c635efSGarrett D'Amore /* 380*95c635efSGarrett D'Amore * Blocks delimited by our target token get REWIND_MORE. 381*95c635efSGarrett D'Amore * Blocks delimiting our target token get REWIND_NONE. 382*95c635efSGarrett D'Amore */ 383*95c635efSGarrett D'Amore switch (tok) { 384*95c635efSGarrett D'Amore case (MDOC_Bl): 385*95c635efSGarrett D'Amore if (MDOC_It == p->tok) 386*95c635efSGarrett D'Amore return(REWIND_MORE); 387*95c635efSGarrett D'Amore break; 388*95c635efSGarrett D'Amore case (MDOC_It): 389*95c635efSGarrett D'Amore if (MDOC_BODY == p->type && MDOC_Bl == p->tok) 390*95c635efSGarrett D'Amore return(REWIND_NONE); 391*95c635efSGarrett D'Amore break; 392*95c635efSGarrett D'Amore /* 393*95c635efSGarrett D'Amore * XXX Badly nested block handling still fails badly 394*95c635efSGarrett D'Amore * when one block is breaking two blocks of the same type. 395*95c635efSGarrett D'Amore * This is an incomplete and extremely ugly workaround, 396*95c635efSGarrett D'Amore * required to let the OpenBSD tree build. 397*95c635efSGarrett D'Amore */ 398*95c635efSGarrett D'Amore case (MDOC_Oo): 399*95c635efSGarrett D'Amore if (MDOC_Op == p->tok) 400*95c635efSGarrett D'Amore return(REWIND_MORE); 401*95c635efSGarrett D'Amore break; 402*95c635efSGarrett D'Amore case (MDOC_Nm): 403*95c635efSGarrett D'Amore return(REWIND_NONE); 404*95c635efSGarrett D'Amore case (MDOC_Nd): 405*95c635efSGarrett D'Amore /* FALLTHROUGH */ 406*95c635efSGarrett D'Amore case (MDOC_Ss): 407*95c635efSGarrett D'Amore if (MDOC_BODY == p->type && MDOC_Sh == p->tok) 408*95c635efSGarrett D'Amore return(REWIND_NONE); 409*95c635efSGarrett D'Amore /* FALLTHROUGH */ 410*95c635efSGarrett D'Amore case (MDOC_Sh): 411*95c635efSGarrett D'Amore if (MDOC_Nd == p->tok || MDOC_Ss == p->tok || 412*95c635efSGarrett D'Amore MDOC_Sh == p->tok) 413*95c635efSGarrett D'Amore return(REWIND_MORE); 414*95c635efSGarrett D'Amore break; 415*95c635efSGarrett D'Amore default: 416*95c635efSGarrett D'Amore break; 417*95c635efSGarrett D'Amore } 418*95c635efSGarrett D'Amore 419*95c635efSGarrett D'Amore /* 420*95c635efSGarrett D'Amore * Default block rewinding rules. 421*95c635efSGarrett D'Amore * In particular, always skip block end markers, 422*95c635efSGarrett D'Amore * and let all blocks rewind Nm children. 423*95c635efSGarrett D'Amore */ 424*95c635efSGarrett D'Amore if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok || 425*95c635efSGarrett D'Amore (MDOC_BLOCK == p->type && 426*95c635efSGarrett D'Amore ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))) 427*95c635efSGarrett D'Amore return(REWIND_MORE); 428*95c635efSGarrett D'Amore 429*95c635efSGarrett D'Amore /* 430*95c635efSGarrett D'Amore * By default, closing out full blocks 431*95c635efSGarrett D'Amore * forces closing of broken explicit blocks, 432*95c635efSGarrett D'Amore * while closing out partial blocks 433*95c635efSGarrett D'Amore * allows delayed rewinding by default. 434*95c635efSGarrett D'Amore */ 435*95c635efSGarrett D'Amore return (&blk_full == mdoc_macros[tok].fp ? 436*95c635efSGarrett D'Amore REWIND_FORCE : REWIND_LATER); 437*95c635efSGarrett D'Amore } 438*95c635efSGarrett D'Amore 439*95c635efSGarrett D'Amore 440*95c635efSGarrett D'Amore static int 441*95c635efSGarrett D'Amore rew_elem(struct mdoc *mdoc, enum mdoct tok) 442*95c635efSGarrett D'Amore { 443*95c635efSGarrett D'Amore struct mdoc_node *n; 444*95c635efSGarrett D'Amore 445*95c635efSGarrett D'Amore n = mdoc->last; 446*95c635efSGarrett D'Amore if (MDOC_ELEM != n->type) 447*95c635efSGarrett D'Amore n = n->parent; 448*95c635efSGarrett D'Amore assert(MDOC_ELEM == n->type); 449*95c635efSGarrett D'Amore assert(tok == n->tok); 450*95c635efSGarrett D'Amore 451*95c635efSGarrett D'Amore return(rew_last(mdoc, n)); 452*95c635efSGarrett D'Amore } 453*95c635efSGarrett D'Amore 454*95c635efSGarrett D'Amore 455*95c635efSGarrett D'Amore /* 456*95c635efSGarrett D'Amore * We are trying to close a block identified by tok, 457*95c635efSGarrett D'Amore * but the child block *broken is still open. 458*95c635efSGarrett D'Amore * Thus, postpone closing the tok block 459*95c635efSGarrett D'Amore * until the rew_sub call closing *broken. 460*95c635efSGarrett D'Amore */ 461*95c635efSGarrett D'Amore static int 462*95c635efSGarrett D'Amore make_pending(struct mdoc_node *broken, enum mdoct tok, 463*95c635efSGarrett D'Amore struct mdoc *m, int line, int ppos) 464*95c635efSGarrett D'Amore { 465*95c635efSGarrett D'Amore struct mdoc_node *breaker; 466*95c635efSGarrett D'Amore 467*95c635efSGarrett D'Amore /* 468*95c635efSGarrett D'Amore * Iterate backwards, searching for the block matching tok, 469*95c635efSGarrett D'Amore * that is, the block breaking the *broken block. 470*95c635efSGarrett D'Amore */ 471*95c635efSGarrett D'Amore for (breaker = broken->parent; breaker; breaker = breaker->parent) { 472*95c635efSGarrett D'Amore 473*95c635efSGarrett D'Amore /* 474*95c635efSGarrett D'Amore * If the *broken block had already been broken before 475*95c635efSGarrett D'Amore * and we encounter its breaker, make the tok block 476*95c635efSGarrett D'Amore * pending on the inner breaker. 477*95c635efSGarrett D'Amore * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]" 478*95c635efSGarrett D'Amore * becomes "[A broken=[B [C->B B] tok=A] C]" 479*95c635efSGarrett D'Amore * and finally "[A [B->A [C->B B] A] C]". 480*95c635efSGarrett D'Amore */ 481*95c635efSGarrett D'Amore if (breaker == broken->pending) { 482*95c635efSGarrett D'Amore broken = breaker; 483*95c635efSGarrett D'Amore continue; 484*95c635efSGarrett D'Amore } 485*95c635efSGarrett D'Amore 486*95c635efSGarrett D'Amore if (REWIND_THIS != rew_dohalt(tok, MDOC_BLOCK, breaker)) 487*95c635efSGarrett D'Amore continue; 488*95c635efSGarrett D'Amore if (MDOC_BODY == broken->type) 489*95c635efSGarrett D'Amore broken = broken->parent; 490*95c635efSGarrett D'Amore 491*95c635efSGarrett D'Amore /* 492*95c635efSGarrett D'Amore * Found the breaker. 493*95c635efSGarrett D'Amore * If another, outer breaker is already pending on 494*95c635efSGarrett D'Amore * the *broken block, we must not clobber the link 495*95c635efSGarrett D'Amore * to the outer breaker, but make it pending on the 496*95c635efSGarrett D'Amore * new, now inner breaker. 497*95c635efSGarrett D'Amore * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]" 498*95c635efSGarrett D'Amore * becomes "[A breaker=[B->A broken=[C A] tok=B] C]" 499*95c635efSGarrett D'Amore * and finally "[A [B->A [C->B A] B] C]". 500*95c635efSGarrett D'Amore */ 501*95c635efSGarrett D'Amore if (broken->pending) { 502*95c635efSGarrett D'Amore struct mdoc_node *taker; 503*95c635efSGarrett D'Amore 504*95c635efSGarrett D'Amore /* 505*95c635efSGarrett D'Amore * If the breaker had also been broken before, 506*95c635efSGarrett D'Amore * it cannot take on the outer breaker itself, 507*95c635efSGarrett D'Amore * but must hand it on to its own breakers. 508*95c635efSGarrett D'Amore * Graphically, this is the following situation: 509*95c635efSGarrett D'Amore * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]" 510*95c635efSGarrett D'Amore * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]" 511*95c635efSGarrett D'Amore */ 512*95c635efSGarrett D'Amore taker = breaker; 513*95c635efSGarrett D'Amore while (taker->pending) 514*95c635efSGarrett D'Amore taker = taker->pending; 515*95c635efSGarrett D'Amore taker->pending = broken->pending; 516*95c635efSGarrett D'Amore } 517*95c635efSGarrett D'Amore broken->pending = breaker; 518*95c635efSGarrett D'Amore mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, 519*95c635efSGarrett D'Amore "%s breaks %s", mdoc_macronames[tok], 520*95c635efSGarrett D'Amore mdoc_macronames[broken->tok]); 521*95c635efSGarrett D'Amore return(1); 522*95c635efSGarrett D'Amore } 523*95c635efSGarrett D'Amore 524*95c635efSGarrett D'Amore /* 525*95c635efSGarrett D'Amore * Found no matching block for tok. 526*95c635efSGarrett D'Amore * Are you trying to close a block that is not open? 527*95c635efSGarrett D'Amore */ 528*95c635efSGarrett D'Amore return(0); 529*95c635efSGarrett D'Amore } 530*95c635efSGarrett D'Amore 531*95c635efSGarrett D'Amore 532*95c635efSGarrett D'Amore static int 533*95c635efSGarrett D'Amore rew_sub(enum mdoc_type t, struct mdoc *m, 534*95c635efSGarrett D'Amore enum mdoct tok, int line, int ppos) 535*95c635efSGarrett D'Amore { 536*95c635efSGarrett D'Amore struct mdoc_node *n; 537*95c635efSGarrett D'Amore 538*95c635efSGarrett D'Amore n = m->last; 539*95c635efSGarrett D'Amore while (n) { 540*95c635efSGarrett D'Amore switch (rew_dohalt(tok, t, n)) { 541*95c635efSGarrett D'Amore case (REWIND_NONE): 542*95c635efSGarrett D'Amore return(1); 543*95c635efSGarrett D'Amore case (REWIND_THIS): 544*95c635efSGarrett D'Amore break; 545*95c635efSGarrett D'Amore case (REWIND_FORCE): 546*95c635efSGarrett D'Amore mandoc_vmsg(MANDOCERR_SCOPEBROKEN, m->parse, 547*95c635efSGarrett D'Amore line, ppos, "%s breaks %s", 548*95c635efSGarrett D'Amore mdoc_macronames[tok], 549*95c635efSGarrett D'Amore mdoc_macronames[n->tok]); 550*95c635efSGarrett D'Amore /* FALLTHROUGH */ 551*95c635efSGarrett D'Amore case (REWIND_MORE): 552*95c635efSGarrett D'Amore n = n->parent; 553*95c635efSGarrett D'Amore continue; 554*95c635efSGarrett D'Amore case (REWIND_LATER): 555*95c635efSGarrett D'Amore if (make_pending(n, tok, m, line, ppos) || 556*95c635efSGarrett D'Amore MDOC_BLOCK != t) 557*95c635efSGarrett D'Amore return(1); 558*95c635efSGarrett D'Amore /* FALLTHROUGH */ 559*95c635efSGarrett D'Amore case (REWIND_ERROR): 560*95c635efSGarrett D'Amore mdoc_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); 561*95c635efSGarrett D'Amore return(1); 562*95c635efSGarrett D'Amore } 563*95c635efSGarrett D'Amore break; 564*95c635efSGarrett D'Amore } 565*95c635efSGarrett D'Amore 566*95c635efSGarrett D'Amore assert(n); 567*95c635efSGarrett D'Amore if ( ! rew_last(m, n)) 568*95c635efSGarrett D'Amore return(0); 569*95c635efSGarrett D'Amore 570*95c635efSGarrett D'Amore /* 571*95c635efSGarrett D'Amore * The current block extends an enclosing block. 572*95c635efSGarrett D'Amore * Now that the current block ends, close the enclosing block, too. 573*95c635efSGarrett D'Amore */ 574*95c635efSGarrett D'Amore while (NULL != (n = n->pending)) { 575*95c635efSGarrett D'Amore if ( ! rew_last(m, n)) 576*95c635efSGarrett D'Amore return(0); 577*95c635efSGarrett D'Amore if (MDOC_HEAD == n->type && 578*95c635efSGarrett D'Amore ! mdoc_body_alloc(m, n->line, n->pos, n->tok)) 579*95c635efSGarrett D'Amore return(0); 580*95c635efSGarrett D'Amore } 581*95c635efSGarrett D'Amore 582*95c635efSGarrett D'Amore return(1); 583*95c635efSGarrett D'Amore } 584*95c635efSGarrett D'Amore 585*95c635efSGarrett D'Amore /* 586*95c635efSGarrett D'Amore * Allocate a word and check whether it's punctuation or not. 587*95c635efSGarrett D'Amore * Punctuation consists of those tokens found in mdoc_isdelim(). 588*95c635efSGarrett D'Amore */ 589*95c635efSGarrett D'Amore static int 590*95c635efSGarrett D'Amore dword(struct mdoc *m, int line, 591*95c635efSGarrett D'Amore int col, const char *p, enum mdelim d) 592*95c635efSGarrett D'Amore { 593*95c635efSGarrett D'Amore 594*95c635efSGarrett D'Amore if (DELIM_MAX == d) 595*95c635efSGarrett D'Amore d = mdoc_isdelim(p); 596*95c635efSGarrett D'Amore 597*95c635efSGarrett D'Amore if ( ! mdoc_word_alloc(m, line, col, p)) 598*95c635efSGarrett D'Amore return(0); 599*95c635efSGarrett D'Amore 600*95c635efSGarrett D'Amore if (DELIM_OPEN == d) 601*95c635efSGarrett D'Amore m->last->flags |= MDOC_DELIMO; 602*95c635efSGarrett D'Amore 603*95c635efSGarrett D'Amore /* 604*95c635efSGarrett D'Amore * Closing delimiters only suppress the preceding space 605*95c635efSGarrett D'Amore * when they follow something, not when they start a new 606*95c635efSGarrett D'Amore * block or element, and not when they follow `No'. 607*95c635efSGarrett D'Amore * 608*95c635efSGarrett D'Amore * XXX Explicitly special-casing MDOC_No here feels 609*95c635efSGarrett D'Amore * like a layering violation. Find a better way 610*95c635efSGarrett D'Amore * and solve this in the code related to `No'! 611*95c635efSGarrett D'Amore */ 612*95c635efSGarrett D'Amore 613*95c635efSGarrett D'Amore else if (DELIM_CLOSE == d && m->last->prev && 614*95c635efSGarrett D'Amore m->last->prev->tok != MDOC_No) 615*95c635efSGarrett D'Amore m->last->flags |= MDOC_DELIMC; 616*95c635efSGarrett D'Amore 617*95c635efSGarrett D'Amore return(1); 618*95c635efSGarrett D'Amore } 619*95c635efSGarrett D'Amore 620*95c635efSGarrett D'Amore static int 621*95c635efSGarrett D'Amore append_delims(struct mdoc *m, int line, int *pos, char *buf) 622*95c635efSGarrett D'Amore { 623*95c635efSGarrett D'Amore int la; 624*95c635efSGarrett D'Amore enum margserr ac; 625*95c635efSGarrett D'Amore char *p; 626*95c635efSGarrett D'Amore 627*95c635efSGarrett D'Amore if ('\0' == buf[*pos]) 628*95c635efSGarrett D'Amore return(1); 629*95c635efSGarrett D'Amore 630*95c635efSGarrett D'Amore for (;;) { 631*95c635efSGarrett D'Amore la = *pos; 632*95c635efSGarrett D'Amore ac = mdoc_zargs(m, line, pos, buf, &p); 633*95c635efSGarrett D'Amore 634*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 635*95c635efSGarrett D'Amore return(0); 636*95c635efSGarrett D'Amore else if (ARGS_EOLN == ac) 637*95c635efSGarrett D'Amore break; 638*95c635efSGarrett D'Amore 639*95c635efSGarrett D'Amore dword(m, line, la, p, DELIM_MAX); 640*95c635efSGarrett D'Amore 641*95c635efSGarrett D'Amore /* 642*95c635efSGarrett D'Amore * If we encounter end-of-sentence symbols, then trigger 643*95c635efSGarrett D'Amore * the double-space. 644*95c635efSGarrett D'Amore * 645*95c635efSGarrett D'Amore * XXX: it's easy to allow this to propagate outward to 646*95c635efSGarrett D'Amore * the last symbol, such that `. )' will cause the 647*95c635efSGarrett D'Amore * correct double-spacing. However, (1) groff isn't 648*95c635efSGarrett D'Amore * smart enough to do this and (2) it would require 649*95c635efSGarrett D'Amore * knowing which symbols break this behaviour, for 650*95c635efSGarrett D'Amore * example, `. ;' shouldn't propagate the double-space. 651*95c635efSGarrett D'Amore */ 652*95c635efSGarrett D'Amore if (mandoc_eos(p, strlen(p), 0)) 653*95c635efSGarrett D'Amore m->last->flags |= MDOC_EOS; 654*95c635efSGarrett D'Amore } 655*95c635efSGarrett D'Amore 656*95c635efSGarrett D'Amore return(1); 657*95c635efSGarrett D'Amore } 658*95c635efSGarrett D'Amore 659*95c635efSGarrett D'Amore 660*95c635efSGarrett D'Amore /* 661*95c635efSGarrett D'Amore * Close out block partial/full explicit. 662*95c635efSGarrett D'Amore */ 663*95c635efSGarrett D'Amore static int 664*95c635efSGarrett D'Amore blk_exp_close(MACRO_PROT_ARGS) 665*95c635efSGarrett D'Amore { 666*95c635efSGarrett D'Amore struct mdoc_node *body; /* Our own body. */ 667*95c635efSGarrett D'Amore struct mdoc_node *later; /* A sub-block starting later. */ 668*95c635efSGarrett D'Amore struct mdoc_node *n; /* For searching backwards. */ 669*95c635efSGarrett D'Amore 670*95c635efSGarrett D'Amore int j, lastarg, maxargs, flushed, nl; 671*95c635efSGarrett D'Amore enum margserr ac; 672*95c635efSGarrett D'Amore enum mdoct atok, ntok; 673*95c635efSGarrett D'Amore char *p; 674*95c635efSGarrett D'Amore 675*95c635efSGarrett D'Amore nl = MDOC_NEWLINE & m->flags; 676*95c635efSGarrett D'Amore 677*95c635efSGarrett D'Amore switch (tok) { 678*95c635efSGarrett D'Amore case (MDOC_Ec): 679*95c635efSGarrett D'Amore maxargs = 1; 680*95c635efSGarrett D'Amore break; 681*95c635efSGarrett D'Amore default: 682*95c635efSGarrett D'Amore maxargs = 0; 683*95c635efSGarrett D'Amore break; 684*95c635efSGarrett D'Amore } 685*95c635efSGarrett D'Amore 686*95c635efSGarrett D'Amore /* 687*95c635efSGarrett D'Amore * Search backwards for beginnings of blocks, 688*95c635efSGarrett D'Amore * both of our own and of pending sub-blocks. 689*95c635efSGarrett D'Amore */ 690*95c635efSGarrett D'Amore atok = rew_alt(tok); 691*95c635efSGarrett D'Amore body = later = NULL; 692*95c635efSGarrett D'Amore for (n = m->last; n; n = n->parent) { 693*95c635efSGarrett D'Amore if (MDOC_VALID & n->flags) 694*95c635efSGarrett D'Amore continue; 695*95c635efSGarrett D'Amore 696*95c635efSGarrett D'Amore /* Remember the start of our own body. */ 697*95c635efSGarrett D'Amore if (MDOC_BODY == n->type && atok == n->tok) { 698*95c635efSGarrett D'Amore if (ENDBODY_NOT == n->end) 699*95c635efSGarrett D'Amore body = n; 700*95c635efSGarrett D'Amore continue; 701*95c635efSGarrett D'Amore } 702*95c635efSGarrett D'Amore 703*95c635efSGarrett D'Amore if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok) 704*95c635efSGarrett D'Amore continue; 705*95c635efSGarrett D'Amore if (atok == n->tok) { 706*95c635efSGarrett D'Amore assert(body); 707*95c635efSGarrett D'Amore 708*95c635efSGarrett D'Amore /* 709*95c635efSGarrett D'Amore * Found the start of our own block. 710*95c635efSGarrett D'Amore * When there is no pending sub block, 711*95c635efSGarrett D'Amore * just proceed to closing out. 712*95c635efSGarrett D'Amore */ 713*95c635efSGarrett D'Amore if (NULL == later) 714*95c635efSGarrett D'Amore break; 715*95c635efSGarrett D'Amore 716*95c635efSGarrett D'Amore /* 717*95c635efSGarrett D'Amore * When there is a pending sub block, 718*95c635efSGarrett D'Amore * postpone closing out the current block 719*95c635efSGarrett D'Amore * until the rew_sub() closing out the sub-block. 720*95c635efSGarrett D'Amore */ 721*95c635efSGarrett D'Amore make_pending(later, tok, m, line, ppos); 722*95c635efSGarrett D'Amore 723*95c635efSGarrett D'Amore /* 724*95c635efSGarrett D'Amore * Mark the place where the formatting - but not 725*95c635efSGarrett D'Amore * the scope - of the current block ends. 726*95c635efSGarrett D'Amore */ 727*95c635efSGarrett D'Amore if ( ! mdoc_endbody_alloc(m, line, ppos, 728*95c635efSGarrett D'Amore atok, body, ENDBODY_SPACE)) 729*95c635efSGarrett D'Amore return(0); 730*95c635efSGarrett D'Amore break; 731*95c635efSGarrett D'Amore } 732*95c635efSGarrett D'Amore 733*95c635efSGarrett D'Amore /* 734*95c635efSGarrett D'Amore * When finding an open sub block, remember the last 735*95c635efSGarrett D'Amore * open explicit block, or, in case there are only 736*95c635efSGarrett D'Amore * implicit ones, the first open implicit block. 737*95c635efSGarrett D'Amore */ 738*95c635efSGarrett D'Amore if (later && 739*95c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[later->tok].flags) 740*95c635efSGarrett D'Amore continue; 741*95c635efSGarrett D'Amore if (MDOC_CALLABLE & mdoc_macros[n->tok].flags) 742*95c635efSGarrett D'Amore later = n; 743*95c635efSGarrett D'Amore } 744*95c635efSGarrett D'Amore 745*95c635efSGarrett D'Amore if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { 746*95c635efSGarrett D'Amore /* FIXME: do this in validate */ 747*95c635efSGarrett D'Amore if (buf[*pos]) 748*95c635efSGarrett D'Amore mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST); 749*95c635efSGarrett D'Amore 750*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 751*95c635efSGarrett D'Amore return(0); 752*95c635efSGarrett D'Amore return(rew_sub(MDOC_BLOCK, m, tok, line, ppos)); 753*95c635efSGarrett D'Amore } 754*95c635efSGarrett D'Amore 755*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 756*95c635efSGarrett D'Amore return(0); 757*95c635efSGarrett D'Amore 758*95c635efSGarrett D'Amore if (NULL == later && maxargs > 0) 759*95c635efSGarrett D'Amore if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok))) 760*95c635efSGarrett D'Amore return(0); 761*95c635efSGarrett D'Amore 762*95c635efSGarrett D'Amore for (flushed = j = 0; ; j++) { 763*95c635efSGarrett D'Amore lastarg = *pos; 764*95c635efSGarrett D'Amore 765*95c635efSGarrett D'Amore if (j == maxargs && ! flushed) { 766*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 767*95c635efSGarrett D'Amore return(0); 768*95c635efSGarrett D'Amore flushed = 1; 769*95c635efSGarrett D'Amore } 770*95c635efSGarrett D'Amore 771*95c635efSGarrett D'Amore ac = mdoc_args(m, line, pos, buf, tok, &p); 772*95c635efSGarrett D'Amore 773*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 774*95c635efSGarrett D'Amore return(0); 775*95c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 776*95c635efSGarrett D'Amore break; 777*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 778*95c635efSGarrett D'Amore break; 779*95c635efSGarrett D'Amore 780*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 781*95c635efSGarrett D'Amore 782*95c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 783*95c635efSGarrett D'Amore if ( ! dword(m, line, lastarg, p, DELIM_MAX)) 784*95c635efSGarrett D'Amore return(0); 785*95c635efSGarrett D'Amore continue; 786*95c635efSGarrett D'Amore } 787*95c635efSGarrett D'Amore 788*95c635efSGarrett D'Amore if ( ! flushed) { 789*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 790*95c635efSGarrett D'Amore return(0); 791*95c635efSGarrett D'Amore flushed = 1; 792*95c635efSGarrett D'Amore } 793*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf)) 794*95c635efSGarrett D'Amore return(0); 795*95c635efSGarrett D'Amore break; 796*95c635efSGarrett D'Amore } 797*95c635efSGarrett D'Amore 798*95c635efSGarrett D'Amore if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 799*95c635efSGarrett D'Amore return(0); 800*95c635efSGarrett D'Amore 801*95c635efSGarrett D'Amore if ( ! nl) 802*95c635efSGarrett D'Amore return(1); 803*95c635efSGarrett D'Amore return(append_delims(m, line, pos, buf)); 804*95c635efSGarrett D'Amore } 805*95c635efSGarrett D'Amore 806*95c635efSGarrett D'Amore 807*95c635efSGarrett D'Amore static int 808*95c635efSGarrett D'Amore in_line(MACRO_PROT_ARGS) 809*95c635efSGarrett D'Amore { 810*95c635efSGarrett D'Amore int la, scope, cnt, nc, nl; 811*95c635efSGarrett D'Amore enum margverr av; 812*95c635efSGarrett D'Amore enum mdoct ntok; 813*95c635efSGarrett D'Amore enum margserr ac; 814*95c635efSGarrett D'Amore enum mdelim d; 815*95c635efSGarrett D'Amore struct mdoc_arg *arg; 816*95c635efSGarrett D'Amore char *p; 817*95c635efSGarrett D'Amore 818*95c635efSGarrett D'Amore nl = MDOC_NEWLINE & m->flags; 819*95c635efSGarrett D'Amore 820*95c635efSGarrett D'Amore /* 821*95c635efSGarrett D'Amore * Whether we allow ignored elements (those without content, 822*95c635efSGarrett D'Amore * usually because of reserved words) to squeak by. 823*95c635efSGarrett D'Amore */ 824*95c635efSGarrett D'Amore 825*95c635efSGarrett D'Amore switch (tok) { 826*95c635efSGarrett D'Amore case (MDOC_An): 827*95c635efSGarrett D'Amore /* FALLTHROUGH */ 828*95c635efSGarrett D'Amore case (MDOC_Ar): 829*95c635efSGarrett D'Amore /* FALLTHROUGH */ 830*95c635efSGarrett D'Amore case (MDOC_Fl): 831*95c635efSGarrett D'Amore /* FALLTHROUGH */ 832*95c635efSGarrett D'Amore case (MDOC_Mt): 833*95c635efSGarrett D'Amore /* FALLTHROUGH */ 834*95c635efSGarrett D'Amore case (MDOC_Nm): 835*95c635efSGarrett D'Amore /* FALLTHROUGH */ 836*95c635efSGarrett D'Amore case (MDOC_Pa): 837*95c635efSGarrett D'Amore nc = 1; 838*95c635efSGarrett D'Amore break; 839*95c635efSGarrett D'Amore default: 840*95c635efSGarrett D'Amore nc = 0; 841*95c635efSGarrett D'Amore break; 842*95c635efSGarrett D'Amore } 843*95c635efSGarrett D'Amore 844*95c635efSGarrett D'Amore for (arg = NULL;; ) { 845*95c635efSGarrett D'Amore la = *pos; 846*95c635efSGarrett D'Amore av = mdoc_argv(m, line, tok, &arg, pos, buf); 847*95c635efSGarrett D'Amore 848*95c635efSGarrett D'Amore if (ARGV_WORD == av) { 849*95c635efSGarrett D'Amore *pos = la; 850*95c635efSGarrett D'Amore break; 851*95c635efSGarrett D'Amore } 852*95c635efSGarrett D'Amore if (ARGV_EOLN == av) 853*95c635efSGarrett D'Amore break; 854*95c635efSGarrett D'Amore if (ARGV_ARG == av) 855*95c635efSGarrett D'Amore continue; 856*95c635efSGarrett D'Amore 857*95c635efSGarrett D'Amore mdoc_argv_free(arg); 858*95c635efSGarrett D'Amore return(0); 859*95c635efSGarrett D'Amore } 860*95c635efSGarrett D'Amore 861*95c635efSGarrett D'Amore for (cnt = scope = 0;; ) { 862*95c635efSGarrett D'Amore la = *pos; 863*95c635efSGarrett D'Amore ac = mdoc_args(m, line, pos, buf, tok, &p); 864*95c635efSGarrett D'Amore 865*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 866*95c635efSGarrett D'Amore return(0); 867*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 868*95c635efSGarrett D'Amore break; 869*95c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 870*95c635efSGarrett D'Amore break; 871*95c635efSGarrett D'Amore 872*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 873*95c635efSGarrett D'Amore 874*95c635efSGarrett D'Amore /* 875*95c635efSGarrett D'Amore * In this case, we've located a submacro and must 876*95c635efSGarrett D'Amore * execute it. Close out scope, if open. If no 877*95c635efSGarrett D'Amore * elements have been generated, either create one (nc) 878*95c635efSGarrett D'Amore * or raise a warning. 879*95c635efSGarrett D'Amore */ 880*95c635efSGarrett D'Amore 881*95c635efSGarrett D'Amore if (MDOC_MAX != ntok) { 882*95c635efSGarrett D'Amore if (scope && ! rew_elem(m, tok)) 883*95c635efSGarrett D'Amore return(0); 884*95c635efSGarrett D'Amore if (nc && 0 == cnt) { 885*95c635efSGarrett D'Amore if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 886*95c635efSGarrett D'Amore return(0); 887*95c635efSGarrett D'Amore if ( ! rew_last(m, m->last)) 888*95c635efSGarrett D'Amore return(0); 889*95c635efSGarrett D'Amore } else if ( ! nc && 0 == cnt) { 890*95c635efSGarrett D'Amore mdoc_argv_free(arg); 891*95c635efSGarrett D'Amore mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); 892*95c635efSGarrett D'Amore } 893*95c635efSGarrett D'Amore 894*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 895*95c635efSGarrett D'Amore return(0); 896*95c635efSGarrett D'Amore if ( ! nl) 897*95c635efSGarrett D'Amore return(1); 898*95c635efSGarrett D'Amore return(append_delims(m, line, pos, buf)); 899*95c635efSGarrett D'Amore } 900*95c635efSGarrett D'Amore 901*95c635efSGarrett D'Amore /* 902*95c635efSGarrett D'Amore * Non-quote-enclosed punctuation. Set up our scope, if 903*95c635efSGarrett D'Amore * a word; rewind the scope, if a delimiter; then append 904*95c635efSGarrett D'Amore * the word. 905*95c635efSGarrett D'Amore */ 906*95c635efSGarrett D'Amore 907*95c635efSGarrett D'Amore d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p); 908*95c635efSGarrett D'Amore 909*95c635efSGarrett D'Amore if (DELIM_NONE != d) { 910*95c635efSGarrett D'Amore /* 911*95c635efSGarrett D'Amore * If we encounter closing punctuation, no word 912*95c635efSGarrett D'Amore * has been omitted, no scope is open, and we're 913*95c635efSGarrett D'Amore * allowed to have an empty element, then start 914*95c635efSGarrett D'Amore * a new scope. `Ar', `Fl', and `Li', only do 915*95c635efSGarrett D'Amore * this once per invocation. There may be more 916*95c635efSGarrett D'Amore * of these (all of them?). 917*95c635efSGarrett D'Amore */ 918*95c635efSGarrett D'Amore if (0 == cnt && (nc || MDOC_Li == tok) && 919*95c635efSGarrett D'Amore DELIM_CLOSE == d && ! scope) { 920*95c635efSGarrett D'Amore if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 921*95c635efSGarrett D'Amore return(0); 922*95c635efSGarrett D'Amore if (MDOC_Ar == tok || MDOC_Li == tok || 923*95c635efSGarrett D'Amore MDOC_Fl == tok) 924*95c635efSGarrett D'Amore cnt++; 925*95c635efSGarrett D'Amore scope = 1; 926*95c635efSGarrett D'Amore } 927*95c635efSGarrett D'Amore /* 928*95c635efSGarrett D'Amore * Close out our scope, if one is open, before 929*95c635efSGarrett D'Amore * any punctuation. 930*95c635efSGarrett D'Amore */ 931*95c635efSGarrett D'Amore if (scope && ! rew_elem(m, tok)) 932*95c635efSGarrett D'Amore return(0); 933*95c635efSGarrett D'Amore scope = 0; 934*95c635efSGarrett D'Amore } else if ( ! scope) { 935*95c635efSGarrett D'Amore if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 936*95c635efSGarrett D'Amore return(0); 937*95c635efSGarrett D'Amore scope = 1; 938*95c635efSGarrett D'Amore } 939*95c635efSGarrett D'Amore 940*95c635efSGarrett D'Amore if (DELIM_NONE == d) 941*95c635efSGarrett D'Amore cnt++; 942*95c635efSGarrett D'Amore 943*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, d)) 944*95c635efSGarrett D'Amore return(0); 945*95c635efSGarrett D'Amore 946*95c635efSGarrett D'Amore /* 947*95c635efSGarrett D'Amore * `Fl' macros have their scope re-opened with each new 948*95c635efSGarrett D'Amore * word so that the `-' can be added to each one without 949*95c635efSGarrett D'Amore * having to parse out spaces. 950*95c635efSGarrett D'Amore */ 951*95c635efSGarrett D'Amore if (scope && MDOC_Fl == tok) { 952*95c635efSGarrett D'Amore if ( ! rew_elem(m, tok)) 953*95c635efSGarrett D'Amore return(0); 954*95c635efSGarrett D'Amore scope = 0; 955*95c635efSGarrett D'Amore } 956*95c635efSGarrett D'Amore } 957*95c635efSGarrett D'Amore 958*95c635efSGarrett D'Amore if (scope && ! rew_elem(m, tok)) 959*95c635efSGarrett D'Amore return(0); 960*95c635efSGarrett D'Amore 961*95c635efSGarrett D'Amore /* 962*95c635efSGarrett D'Amore * If no elements have been collected and we're allowed to have 963*95c635efSGarrett D'Amore * empties (nc), open a scope and close it out. Otherwise, 964*95c635efSGarrett D'Amore * raise a warning. 965*95c635efSGarrett D'Amore */ 966*95c635efSGarrett D'Amore 967*95c635efSGarrett D'Amore if (nc && 0 == cnt) { 968*95c635efSGarrett D'Amore if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 969*95c635efSGarrett D'Amore return(0); 970*95c635efSGarrett D'Amore if ( ! rew_last(m, m->last)) 971*95c635efSGarrett D'Amore return(0); 972*95c635efSGarrett D'Amore } else if ( ! nc && 0 == cnt) { 973*95c635efSGarrett D'Amore mdoc_argv_free(arg); 974*95c635efSGarrett D'Amore mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); 975*95c635efSGarrett D'Amore } 976*95c635efSGarrett D'Amore 977*95c635efSGarrett D'Amore if ( ! nl) 978*95c635efSGarrett D'Amore return(1); 979*95c635efSGarrett D'Amore return(append_delims(m, line, pos, buf)); 980*95c635efSGarrett D'Amore } 981*95c635efSGarrett D'Amore 982*95c635efSGarrett D'Amore 983*95c635efSGarrett D'Amore static int 984*95c635efSGarrett D'Amore blk_full(MACRO_PROT_ARGS) 985*95c635efSGarrett D'Amore { 986*95c635efSGarrett D'Amore int la, nl, nparsed; 987*95c635efSGarrett D'Amore struct mdoc_arg *arg; 988*95c635efSGarrett D'Amore struct mdoc_node *head; /* save of head macro */ 989*95c635efSGarrett D'Amore struct mdoc_node *body; /* save of body macro */ 990*95c635efSGarrett D'Amore struct mdoc_node *n; 991*95c635efSGarrett D'Amore enum mdoc_type mtt; 992*95c635efSGarrett D'Amore enum mdoct ntok; 993*95c635efSGarrett D'Amore enum margserr ac, lac; 994*95c635efSGarrett D'Amore enum margverr av; 995*95c635efSGarrett D'Amore char *p; 996*95c635efSGarrett D'Amore 997*95c635efSGarrett D'Amore nl = MDOC_NEWLINE & m->flags; 998*95c635efSGarrett D'Amore 999*95c635efSGarrett D'Amore /* Close out prior implicit scope. */ 1000*95c635efSGarrett D'Amore 1001*95c635efSGarrett D'Amore if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) { 1002*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1003*95c635efSGarrett D'Amore return(0); 1004*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 1005*95c635efSGarrett D'Amore return(0); 1006*95c635efSGarrett D'Amore } 1007*95c635efSGarrett D'Amore 1008*95c635efSGarrett D'Amore /* 1009*95c635efSGarrett D'Amore * This routine accommodates implicitly- and explicitly-scoped 1010*95c635efSGarrett D'Amore * macro openings. Implicit ones first close out prior scope 1011*95c635efSGarrett D'Amore * (seen above). Delay opening the head until necessary to 1012*95c635efSGarrett D'Amore * allow leading punctuation to print. Special consideration 1013*95c635efSGarrett D'Amore * for `It -column', which has phrase-part syntax instead of 1014*95c635efSGarrett D'Amore * regular child nodes. 1015*95c635efSGarrett D'Amore */ 1016*95c635efSGarrett D'Amore 1017*95c635efSGarrett D'Amore for (arg = NULL;; ) { 1018*95c635efSGarrett D'Amore la = *pos; 1019*95c635efSGarrett D'Amore av = mdoc_argv(m, line, tok, &arg, pos, buf); 1020*95c635efSGarrett D'Amore 1021*95c635efSGarrett D'Amore if (ARGV_WORD == av) { 1022*95c635efSGarrett D'Amore *pos = la; 1023*95c635efSGarrett D'Amore break; 1024*95c635efSGarrett D'Amore } 1025*95c635efSGarrett D'Amore 1026*95c635efSGarrett D'Amore if (ARGV_EOLN == av) 1027*95c635efSGarrett D'Amore break; 1028*95c635efSGarrett D'Amore if (ARGV_ARG == av) 1029*95c635efSGarrett D'Amore continue; 1030*95c635efSGarrett D'Amore 1031*95c635efSGarrett D'Amore mdoc_argv_free(arg); 1032*95c635efSGarrett D'Amore return(0); 1033*95c635efSGarrett D'Amore } 1034*95c635efSGarrett D'Amore 1035*95c635efSGarrett D'Amore if ( ! mdoc_block_alloc(m, line, ppos, tok, arg)) 1036*95c635efSGarrett D'Amore return(0); 1037*95c635efSGarrett D'Amore 1038*95c635efSGarrett D'Amore head = body = NULL; 1039*95c635efSGarrett D'Amore 1040*95c635efSGarrett D'Amore /* 1041*95c635efSGarrett D'Amore * Exception: Heads of `It' macros in `-diag' lists are not 1042*95c635efSGarrett D'Amore * parsed, even though `It' macros in general are parsed. 1043*95c635efSGarrett D'Amore */ 1044*95c635efSGarrett D'Amore nparsed = MDOC_It == tok && 1045*95c635efSGarrett D'Amore MDOC_Bl == m->last->parent->tok && 1046*95c635efSGarrett D'Amore LIST_diag == m->last->parent->norm->Bl.type; 1047*95c635efSGarrett D'Amore 1048*95c635efSGarrett D'Amore /* 1049*95c635efSGarrett D'Amore * The `Nd' macro has all arguments in its body: it's a hybrid 1050*95c635efSGarrett D'Amore * of block partial-explicit and full-implicit. Stupid. 1051*95c635efSGarrett D'Amore */ 1052*95c635efSGarrett D'Amore 1053*95c635efSGarrett D'Amore if (MDOC_Nd == tok) { 1054*95c635efSGarrett D'Amore if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1055*95c635efSGarrett D'Amore return(0); 1056*95c635efSGarrett D'Amore head = m->last; 1057*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1058*95c635efSGarrett D'Amore return(0); 1059*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1060*95c635efSGarrett D'Amore return(0); 1061*95c635efSGarrett D'Amore body = m->last; 1062*95c635efSGarrett D'Amore } 1063*95c635efSGarrett D'Amore 1064*95c635efSGarrett D'Amore ac = ARGS_ERROR; 1065*95c635efSGarrett D'Amore 1066*95c635efSGarrett D'Amore for ( ; ; ) { 1067*95c635efSGarrett D'Amore la = *pos; 1068*95c635efSGarrett D'Amore /* Initialise last-phrase-type with ARGS_PEND. */ 1069*95c635efSGarrett D'Amore lac = ARGS_ERROR == ac ? ARGS_PEND : ac; 1070*95c635efSGarrett D'Amore ac = mdoc_args(m, line, pos, buf, tok, &p); 1071*95c635efSGarrett D'Amore 1072*95c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 1073*95c635efSGarrett D'Amore break; 1074*95c635efSGarrett D'Amore 1075*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 1076*95c635efSGarrett D'Amore return(0); 1077*95c635efSGarrett D'Amore 1078*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) { 1079*95c635efSGarrett D'Amore if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac) 1080*95c635efSGarrett D'Amore break; 1081*95c635efSGarrett D'Amore /* 1082*95c635efSGarrett D'Amore * This is necessary: if the last token on a 1083*95c635efSGarrett D'Amore * line is a `Ta' or tab, then we'll get 1084*95c635efSGarrett D'Amore * ARGS_EOLN, so we must be smart enough to 1085*95c635efSGarrett D'Amore * reopen our scope if the last parse was a 1086*95c635efSGarrett D'Amore * phrase or partial phrase. 1087*95c635efSGarrett D'Amore */ 1088*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1089*95c635efSGarrett D'Amore return(0); 1090*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1091*95c635efSGarrett D'Amore return(0); 1092*95c635efSGarrett D'Amore body = m->last; 1093*95c635efSGarrett D'Amore break; 1094*95c635efSGarrett D'Amore } 1095*95c635efSGarrett D'Amore 1096*95c635efSGarrett D'Amore /* 1097*95c635efSGarrett D'Amore * Emit leading punctuation (i.e., punctuation before 1098*95c635efSGarrett D'Amore * the MDOC_HEAD) for non-phrase types. 1099*95c635efSGarrett D'Amore */ 1100*95c635efSGarrett D'Amore 1101*95c635efSGarrett D'Amore if (NULL == head && 1102*95c635efSGarrett D'Amore ARGS_PEND != ac && 1103*95c635efSGarrett D'Amore ARGS_PHRASE != ac && 1104*95c635efSGarrett D'Amore ARGS_PPHRASE != ac && 1105*95c635efSGarrett D'Amore ARGS_QWORD != ac && 1106*95c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 1107*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_OPEN)) 1108*95c635efSGarrett D'Amore return(0); 1109*95c635efSGarrett D'Amore continue; 1110*95c635efSGarrett D'Amore } 1111*95c635efSGarrett D'Amore 1112*95c635efSGarrett D'Amore /* Open a head if one hasn't been opened. */ 1113*95c635efSGarrett D'Amore 1114*95c635efSGarrett D'Amore if (NULL == head) { 1115*95c635efSGarrett D'Amore if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1116*95c635efSGarrett D'Amore return(0); 1117*95c635efSGarrett D'Amore head = m->last; 1118*95c635efSGarrett D'Amore } 1119*95c635efSGarrett D'Amore 1120*95c635efSGarrett D'Amore if (ARGS_PHRASE == ac || 1121*95c635efSGarrett D'Amore ARGS_PEND == ac || 1122*95c635efSGarrett D'Amore ARGS_PPHRASE == ac) { 1123*95c635efSGarrett D'Amore /* 1124*95c635efSGarrett D'Amore * If we haven't opened a body yet, rewind the 1125*95c635efSGarrett D'Amore * head; if we have, rewind that instead. 1126*95c635efSGarrett D'Amore */ 1127*95c635efSGarrett D'Amore 1128*95c635efSGarrett D'Amore mtt = body ? MDOC_BODY : MDOC_HEAD; 1129*95c635efSGarrett D'Amore if ( ! rew_sub(mtt, m, tok, line, ppos)) 1130*95c635efSGarrett D'Amore return(0); 1131*95c635efSGarrett D'Amore 1132*95c635efSGarrett D'Amore /* Then allocate our body context. */ 1133*95c635efSGarrett D'Amore 1134*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1135*95c635efSGarrett D'Amore return(0); 1136*95c635efSGarrett D'Amore body = m->last; 1137*95c635efSGarrett D'Amore 1138*95c635efSGarrett D'Amore /* 1139*95c635efSGarrett D'Amore * Process phrases: set whether we're in a 1140*95c635efSGarrett D'Amore * partial-phrase (this effects line handling) 1141*95c635efSGarrett D'Amore * then call down into the phrase parser. 1142*95c635efSGarrett D'Amore */ 1143*95c635efSGarrett D'Amore 1144*95c635efSGarrett D'Amore if (ARGS_PPHRASE == ac) 1145*95c635efSGarrett D'Amore m->flags |= MDOC_PPHRASE; 1146*95c635efSGarrett D'Amore if (ARGS_PEND == ac && ARGS_PPHRASE == lac) 1147*95c635efSGarrett D'Amore m->flags |= MDOC_PPHRASE; 1148*95c635efSGarrett D'Amore 1149*95c635efSGarrett D'Amore if ( ! phrase(m, line, la, buf)) 1150*95c635efSGarrett D'Amore return(0); 1151*95c635efSGarrett D'Amore 1152*95c635efSGarrett D'Amore m->flags &= ~MDOC_PPHRASE; 1153*95c635efSGarrett D'Amore continue; 1154*95c635efSGarrett D'Amore } 1155*95c635efSGarrett D'Amore 1156*95c635efSGarrett D'Amore ntok = nparsed || ARGS_QWORD == ac ? 1157*95c635efSGarrett D'Amore MDOC_MAX : lookup(tok, p); 1158*95c635efSGarrett D'Amore 1159*95c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1160*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1161*95c635efSGarrett D'Amore return(0); 1162*95c635efSGarrett D'Amore continue; 1163*95c635efSGarrett D'Amore } 1164*95c635efSGarrett D'Amore 1165*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1166*95c635efSGarrett D'Amore return(0); 1167*95c635efSGarrett D'Amore break; 1168*95c635efSGarrett D'Amore } 1169*95c635efSGarrett D'Amore 1170*95c635efSGarrett D'Amore if (NULL == head) { 1171*95c635efSGarrett D'Amore if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1172*95c635efSGarrett D'Amore return(0); 1173*95c635efSGarrett D'Amore head = m->last; 1174*95c635efSGarrett D'Amore } 1175*95c635efSGarrett D'Amore 1176*95c635efSGarrett D'Amore if (nl && ! append_delims(m, line, pos, buf)) 1177*95c635efSGarrett D'Amore return(0); 1178*95c635efSGarrett D'Amore 1179*95c635efSGarrett D'Amore /* If we've already opened our body, exit now. */ 1180*95c635efSGarrett D'Amore 1181*95c635efSGarrett D'Amore if (NULL != body) 1182*95c635efSGarrett D'Amore goto out; 1183*95c635efSGarrett D'Amore 1184*95c635efSGarrett D'Amore /* 1185*95c635efSGarrett D'Amore * If there is an open (i.e., unvalidated) sub-block requiring 1186*95c635efSGarrett D'Amore * explicit close-out, postpone switching the current block from 1187*95c635efSGarrett D'Amore * head to body until the rew_sub() call closing out that 1188*95c635efSGarrett D'Amore * sub-block. 1189*95c635efSGarrett D'Amore */ 1190*95c635efSGarrett D'Amore for (n = m->last; n && n != head; n = n->parent) { 1191*95c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && 1192*95c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[n->tok].flags && 1193*95c635efSGarrett D'Amore ! (MDOC_VALID & n->flags)) { 1194*95c635efSGarrett D'Amore n->pending = head; 1195*95c635efSGarrett D'Amore return(1); 1196*95c635efSGarrett D'Amore } 1197*95c635efSGarrett D'Amore } 1198*95c635efSGarrett D'Amore 1199*95c635efSGarrett D'Amore /* Close out scopes to remain in a consistent state. */ 1200*95c635efSGarrett D'Amore 1201*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1202*95c635efSGarrett D'Amore return(0); 1203*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1204*95c635efSGarrett D'Amore return(0); 1205*95c635efSGarrett D'Amore 1206*95c635efSGarrett D'Amore out: 1207*95c635efSGarrett D'Amore if ( ! (MDOC_FREECOL & m->flags)) 1208*95c635efSGarrett D'Amore return(1); 1209*95c635efSGarrett D'Amore 1210*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1211*95c635efSGarrett D'Amore return(0); 1212*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 1213*95c635efSGarrett D'Amore return(0); 1214*95c635efSGarrett D'Amore 1215*95c635efSGarrett D'Amore m->flags &= ~MDOC_FREECOL; 1216*95c635efSGarrett D'Amore return(1); 1217*95c635efSGarrett D'Amore } 1218*95c635efSGarrett D'Amore 1219*95c635efSGarrett D'Amore 1220*95c635efSGarrett D'Amore static int 1221*95c635efSGarrett D'Amore blk_part_imp(MACRO_PROT_ARGS) 1222*95c635efSGarrett D'Amore { 1223*95c635efSGarrett D'Amore int la, nl; 1224*95c635efSGarrett D'Amore enum mdoct ntok; 1225*95c635efSGarrett D'Amore enum margserr ac; 1226*95c635efSGarrett D'Amore char *p; 1227*95c635efSGarrett D'Amore struct mdoc_node *blk; /* saved block context */ 1228*95c635efSGarrett D'Amore struct mdoc_node *body; /* saved body context */ 1229*95c635efSGarrett D'Amore struct mdoc_node *n; 1230*95c635efSGarrett D'Amore 1231*95c635efSGarrett D'Amore nl = MDOC_NEWLINE & m->flags; 1232*95c635efSGarrett D'Amore 1233*95c635efSGarrett D'Amore /* 1234*95c635efSGarrett D'Amore * A macro that spans to the end of the line. This is generally 1235*95c635efSGarrett D'Amore * (but not necessarily) called as the first macro. The block 1236*95c635efSGarrett D'Amore * has a head as the immediate child, which is always empty, 1237*95c635efSGarrett D'Amore * followed by zero or more opening punctuation nodes, then the 1238*95c635efSGarrett D'Amore * body (which may be empty, depending on the macro), then zero 1239*95c635efSGarrett D'Amore * or more closing punctuation nodes. 1240*95c635efSGarrett D'Amore */ 1241*95c635efSGarrett D'Amore 1242*95c635efSGarrett D'Amore if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) 1243*95c635efSGarrett D'Amore return(0); 1244*95c635efSGarrett D'Amore 1245*95c635efSGarrett D'Amore blk = m->last; 1246*95c635efSGarrett D'Amore 1247*95c635efSGarrett D'Amore if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1248*95c635efSGarrett D'Amore return(0); 1249*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1250*95c635efSGarrett D'Amore return(0); 1251*95c635efSGarrett D'Amore 1252*95c635efSGarrett D'Amore /* 1253*95c635efSGarrett D'Amore * Open the body scope "on-demand", that is, after we've 1254*95c635efSGarrett D'Amore * processed all our the leading delimiters (open parenthesis, 1255*95c635efSGarrett D'Amore * etc.). 1256*95c635efSGarrett D'Amore */ 1257*95c635efSGarrett D'Amore 1258*95c635efSGarrett D'Amore for (body = NULL; ; ) { 1259*95c635efSGarrett D'Amore la = *pos; 1260*95c635efSGarrett D'Amore ac = mdoc_args(m, line, pos, buf, tok, &p); 1261*95c635efSGarrett D'Amore 1262*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 1263*95c635efSGarrett D'Amore return(0); 1264*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 1265*95c635efSGarrett D'Amore break; 1266*95c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 1267*95c635efSGarrett D'Amore break; 1268*95c635efSGarrett D'Amore 1269*95c635efSGarrett D'Amore if (NULL == body && ARGS_QWORD != ac && 1270*95c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 1271*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_OPEN)) 1272*95c635efSGarrett D'Amore return(0); 1273*95c635efSGarrett D'Amore continue; 1274*95c635efSGarrett D'Amore } 1275*95c635efSGarrett D'Amore 1276*95c635efSGarrett D'Amore if (NULL == body) { 1277*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1278*95c635efSGarrett D'Amore return(0); 1279*95c635efSGarrett D'Amore body = m->last; 1280*95c635efSGarrett D'Amore } 1281*95c635efSGarrett D'Amore 1282*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1283*95c635efSGarrett D'Amore 1284*95c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1285*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1286*95c635efSGarrett D'Amore return(0); 1287*95c635efSGarrett D'Amore continue; 1288*95c635efSGarrett D'Amore } 1289*95c635efSGarrett D'Amore 1290*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1291*95c635efSGarrett D'Amore return(0); 1292*95c635efSGarrett D'Amore break; 1293*95c635efSGarrett D'Amore } 1294*95c635efSGarrett D'Amore 1295*95c635efSGarrett D'Amore /* Clean-ups to leave in a consistent state. */ 1296*95c635efSGarrett D'Amore 1297*95c635efSGarrett D'Amore if (NULL == body) { 1298*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1299*95c635efSGarrett D'Amore return(0); 1300*95c635efSGarrett D'Amore body = m->last; 1301*95c635efSGarrett D'Amore } 1302*95c635efSGarrett D'Amore 1303*95c635efSGarrett D'Amore for (n = body->child; n && n->next; n = n->next) 1304*95c635efSGarrett D'Amore /* Do nothing. */ ; 1305*95c635efSGarrett D'Amore 1306*95c635efSGarrett D'Amore /* 1307*95c635efSGarrett D'Amore * End of sentence spacing: if the last node is a text node and 1308*95c635efSGarrett D'Amore * has a trailing period, then mark it as being end-of-sentence. 1309*95c635efSGarrett D'Amore */ 1310*95c635efSGarrett D'Amore 1311*95c635efSGarrett D'Amore if (n && MDOC_TEXT == n->type && n->string) 1312*95c635efSGarrett D'Amore if (mandoc_eos(n->string, strlen(n->string), 1)) 1313*95c635efSGarrett D'Amore n->flags |= MDOC_EOS; 1314*95c635efSGarrett D'Amore 1315*95c635efSGarrett D'Amore /* Up-propagate the end-of-space flag. */ 1316*95c635efSGarrett D'Amore 1317*95c635efSGarrett D'Amore if (n && (MDOC_EOS & n->flags)) { 1318*95c635efSGarrett D'Amore body->flags |= MDOC_EOS; 1319*95c635efSGarrett D'Amore body->parent->flags |= MDOC_EOS; 1320*95c635efSGarrett D'Amore } 1321*95c635efSGarrett D'Amore 1322*95c635efSGarrett D'Amore /* 1323*95c635efSGarrett D'Amore * If there is an open sub-block requiring explicit close-out, 1324*95c635efSGarrett D'Amore * postpone closing out the current block 1325*95c635efSGarrett D'Amore * until the rew_sub() call closing out the sub-block. 1326*95c635efSGarrett D'Amore */ 1327*95c635efSGarrett D'Amore for (n = m->last; n && n != body && n != blk->parent; n = n->parent) { 1328*95c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && 1329*95c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[n->tok].flags && 1330*95c635efSGarrett D'Amore ! (MDOC_VALID & n->flags)) { 1331*95c635efSGarrett D'Amore make_pending(n, tok, m, line, ppos); 1332*95c635efSGarrett D'Amore if ( ! mdoc_endbody_alloc(m, line, ppos, 1333*95c635efSGarrett D'Amore tok, body, ENDBODY_NOSPACE)) 1334*95c635efSGarrett D'Amore return(0); 1335*95c635efSGarrett D'Amore return(1); 1336*95c635efSGarrett D'Amore } 1337*95c635efSGarrett D'Amore } 1338*95c635efSGarrett D'Amore 1339*95c635efSGarrett D'Amore /* 1340*95c635efSGarrett D'Amore * If we can't rewind to our body, then our scope has already 1341*95c635efSGarrett D'Amore * been closed by another macro (like `Oc' closing `Op'). This 1342*95c635efSGarrett D'Amore * is ugly behaviour nodding its head to OpenBSD's overwhelming 1343*95c635efSGarrett D'Amore * crufty use of `Op' breakage. 1344*95c635efSGarrett D'Amore */ 1345*95c635efSGarrett D'Amore if (n != body) 1346*95c635efSGarrett D'Amore mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, 1347*95c635efSGarrett D'Amore "%s broken", mdoc_macronames[tok]); 1348*95c635efSGarrett D'Amore 1349*95c635efSGarrett D'Amore if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) 1350*95c635efSGarrett D'Amore return(0); 1351*95c635efSGarrett D'Amore 1352*95c635efSGarrett D'Amore /* Standard appending of delimiters. */ 1353*95c635efSGarrett D'Amore 1354*95c635efSGarrett D'Amore if (nl && ! append_delims(m, line, pos, buf)) 1355*95c635efSGarrett D'Amore return(0); 1356*95c635efSGarrett D'Amore 1357*95c635efSGarrett D'Amore /* Rewind scope, if applicable. */ 1358*95c635efSGarrett D'Amore 1359*95c635efSGarrett D'Amore if (n && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) 1360*95c635efSGarrett D'Amore return(0); 1361*95c635efSGarrett D'Amore 1362*95c635efSGarrett D'Amore return(1); 1363*95c635efSGarrett D'Amore } 1364*95c635efSGarrett D'Amore 1365*95c635efSGarrett D'Amore 1366*95c635efSGarrett D'Amore static int 1367*95c635efSGarrett D'Amore blk_part_exp(MACRO_PROT_ARGS) 1368*95c635efSGarrett D'Amore { 1369*95c635efSGarrett D'Amore int la, nl; 1370*95c635efSGarrett D'Amore enum margserr ac; 1371*95c635efSGarrett D'Amore struct mdoc_node *head; /* keep track of head */ 1372*95c635efSGarrett D'Amore struct mdoc_node *body; /* keep track of body */ 1373*95c635efSGarrett D'Amore char *p; 1374*95c635efSGarrett D'Amore enum mdoct ntok; 1375*95c635efSGarrett D'Amore 1376*95c635efSGarrett D'Amore nl = MDOC_NEWLINE & m->flags; 1377*95c635efSGarrett D'Amore 1378*95c635efSGarrett D'Amore /* 1379*95c635efSGarrett D'Amore * The opening of an explicit macro having zero or more leading 1380*95c635efSGarrett D'Amore * punctuation nodes; a head with optional single element (the 1381*95c635efSGarrett D'Amore * case of `Eo'); and a body that may be empty. 1382*95c635efSGarrett D'Amore */ 1383*95c635efSGarrett D'Amore 1384*95c635efSGarrett D'Amore if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) 1385*95c635efSGarrett D'Amore return(0); 1386*95c635efSGarrett D'Amore 1387*95c635efSGarrett D'Amore for (head = body = NULL; ; ) { 1388*95c635efSGarrett D'Amore la = *pos; 1389*95c635efSGarrett D'Amore ac = mdoc_args(m, line, pos, buf, tok, &p); 1390*95c635efSGarrett D'Amore 1391*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 1392*95c635efSGarrett D'Amore return(0); 1393*95c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 1394*95c635efSGarrett D'Amore break; 1395*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 1396*95c635efSGarrett D'Amore break; 1397*95c635efSGarrett D'Amore 1398*95c635efSGarrett D'Amore /* Flush out leading punctuation. */ 1399*95c635efSGarrett D'Amore 1400*95c635efSGarrett D'Amore if (NULL == head && ARGS_QWORD != ac && 1401*95c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 1402*95c635efSGarrett D'Amore assert(NULL == body); 1403*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_OPEN)) 1404*95c635efSGarrett D'Amore return(0); 1405*95c635efSGarrett D'Amore continue; 1406*95c635efSGarrett D'Amore } 1407*95c635efSGarrett D'Amore 1408*95c635efSGarrett D'Amore if (NULL == head) { 1409*95c635efSGarrett D'Amore assert(NULL == body); 1410*95c635efSGarrett D'Amore if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1411*95c635efSGarrett D'Amore return(0); 1412*95c635efSGarrett D'Amore head = m->last; 1413*95c635efSGarrett D'Amore } 1414*95c635efSGarrett D'Amore 1415*95c635efSGarrett D'Amore /* 1416*95c635efSGarrett D'Amore * `Eo' gobbles any data into the head, but most other 1417*95c635efSGarrett D'Amore * macros just immediately close out and begin the body. 1418*95c635efSGarrett D'Amore */ 1419*95c635efSGarrett D'Amore 1420*95c635efSGarrett D'Amore if (NULL == body) { 1421*95c635efSGarrett D'Amore assert(head); 1422*95c635efSGarrett D'Amore /* No check whether it's a macro! */ 1423*95c635efSGarrett D'Amore if (MDOC_Eo == tok) 1424*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1425*95c635efSGarrett D'Amore return(0); 1426*95c635efSGarrett D'Amore 1427*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1428*95c635efSGarrett D'Amore return(0); 1429*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1430*95c635efSGarrett D'Amore return(0); 1431*95c635efSGarrett D'Amore body = m->last; 1432*95c635efSGarrett D'Amore 1433*95c635efSGarrett D'Amore if (MDOC_Eo == tok) 1434*95c635efSGarrett D'Amore continue; 1435*95c635efSGarrett D'Amore } 1436*95c635efSGarrett D'Amore 1437*95c635efSGarrett D'Amore assert(NULL != head && NULL != body); 1438*95c635efSGarrett D'Amore 1439*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1440*95c635efSGarrett D'Amore 1441*95c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1442*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1443*95c635efSGarrett D'Amore return(0); 1444*95c635efSGarrett D'Amore continue; 1445*95c635efSGarrett D'Amore } 1446*95c635efSGarrett D'Amore 1447*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1448*95c635efSGarrett D'Amore return(0); 1449*95c635efSGarrett D'Amore break; 1450*95c635efSGarrett D'Amore } 1451*95c635efSGarrett D'Amore 1452*95c635efSGarrett D'Amore /* Clean-up to leave in a consistent state. */ 1453*95c635efSGarrett D'Amore 1454*95c635efSGarrett D'Amore if (NULL == head) 1455*95c635efSGarrett D'Amore if ( ! mdoc_head_alloc(m, line, ppos, tok)) 1456*95c635efSGarrett D'Amore return(0); 1457*95c635efSGarrett D'Amore 1458*95c635efSGarrett D'Amore if (NULL == body) { 1459*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) 1460*95c635efSGarrett D'Amore return(0); 1461*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, tok)) 1462*95c635efSGarrett D'Amore return(0); 1463*95c635efSGarrett D'Amore } 1464*95c635efSGarrett D'Amore 1465*95c635efSGarrett D'Amore /* Standard appending of delimiters. */ 1466*95c635efSGarrett D'Amore 1467*95c635efSGarrett D'Amore if ( ! nl) 1468*95c635efSGarrett D'Amore return(1); 1469*95c635efSGarrett D'Amore return(append_delims(m, line, pos, buf)); 1470*95c635efSGarrett D'Amore } 1471*95c635efSGarrett D'Amore 1472*95c635efSGarrett D'Amore 1473*95c635efSGarrett D'Amore /* ARGSUSED */ 1474*95c635efSGarrett D'Amore static int 1475*95c635efSGarrett D'Amore in_line_argn(MACRO_PROT_ARGS) 1476*95c635efSGarrett D'Amore { 1477*95c635efSGarrett D'Amore int la, flushed, j, maxargs, nl; 1478*95c635efSGarrett D'Amore enum margserr ac; 1479*95c635efSGarrett D'Amore enum margverr av; 1480*95c635efSGarrett D'Amore struct mdoc_arg *arg; 1481*95c635efSGarrett D'Amore char *p; 1482*95c635efSGarrett D'Amore enum mdoct ntok; 1483*95c635efSGarrett D'Amore 1484*95c635efSGarrett D'Amore nl = MDOC_NEWLINE & m->flags; 1485*95c635efSGarrett D'Amore 1486*95c635efSGarrett D'Amore /* 1487*95c635efSGarrett D'Amore * A line macro that has a fixed number of arguments (maxargs). 1488*95c635efSGarrett D'Amore * Only open the scope once the first non-leading-punctuation is 1489*95c635efSGarrett D'Amore * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then 1490*95c635efSGarrett D'Amore * keep it open until the maximum number of arguments are 1491*95c635efSGarrett D'Amore * exhausted. 1492*95c635efSGarrett D'Amore */ 1493*95c635efSGarrett D'Amore 1494*95c635efSGarrett D'Amore switch (tok) { 1495*95c635efSGarrett D'Amore case (MDOC_Ap): 1496*95c635efSGarrett D'Amore /* FALLTHROUGH */ 1497*95c635efSGarrett D'Amore case (MDOC_No): 1498*95c635efSGarrett D'Amore /* FALLTHROUGH */ 1499*95c635efSGarrett D'Amore case (MDOC_Ns): 1500*95c635efSGarrett D'Amore /* FALLTHROUGH */ 1501*95c635efSGarrett D'Amore case (MDOC_Ux): 1502*95c635efSGarrett D'Amore maxargs = 0; 1503*95c635efSGarrett D'Amore break; 1504*95c635efSGarrett D'Amore case (MDOC_Bx): 1505*95c635efSGarrett D'Amore /* FALLTHROUGH */ 1506*95c635efSGarrett D'Amore case (MDOC_Xr): 1507*95c635efSGarrett D'Amore maxargs = 2; 1508*95c635efSGarrett D'Amore break; 1509*95c635efSGarrett D'Amore default: 1510*95c635efSGarrett D'Amore maxargs = 1; 1511*95c635efSGarrett D'Amore break; 1512*95c635efSGarrett D'Amore } 1513*95c635efSGarrett D'Amore 1514*95c635efSGarrett D'Amore for (arg = NULL; ; ) { 1515*95c635efSGarrett D'Amore la = *pos; 1516*95c635efSGarrett D'Amore av = mdoc_argv(m, line, tok, &arg, pos, buf); 1517*95c635efSGarrett D'Amore 1518*95c635efSGarrett D'Amore if (ARGV_WORD == av) { 1519*95c635efSGarrett D'Amore *pos = la; 1520*95c635efSGarrett D'Amore break; 1521*95c635efSGarrett D'Amore } 1522*95c635efSGarrett D'Amore 1523*95c635efSGarrett D'Amore if (ARGV_EOLN == av) 1524*95c635efSGarrett D'Amore break; 1525*95c635efSGarrett D'Amore if (ARGV_ARG == av) 1526*95c635efSGarrett D'Amore continue; 1527*95c635efSGarrett D'Amore 1528*95c635efSGarrett D'Amore mdoc_argv_free(arg); 1529*95c635efSGarrett D'Amore return(0); 1530*95c635efSGarrett D'Amore } 1531*95c635efSGarrett D'Amore 1532*95c635efSGarrett D'Amore for (flushed = j = 0; ; ) { 1533*95c635efSGarrett D'Amore la = *pos; 1534*95c635efSGarrett D'Amore ac = mdoc_args(m, line, pos, buf, tok, &p); 1535*95c635efSGarrett D'Amore 1536*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 1537*95c635efSGarrett D'Amore return(0); 1538*95c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 1539*95c635efSGarrett D'Amore break; 1540*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 1541*95c635efSGarrett D'Amore break; 1542*95c635efSGarrett D'Amore 1543*95c635efSGarrett D'Amore if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 1544*95c635efSGarrett D'Amore ARGS_QWORD != ac && 0 == j && 1545*95c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 1546*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_OPEN)) 1547*95c635efSGarrett D'Amore return(0); 1548*95c635efSGarrett D'Amore continue; 1549*95c635efSGarrett D'Amore } else if (0 == j) 1550*95c635efSGarrett D'Amore if ( ! mdoc_elem_alloc(m, line, la, tok, arg)) 1551*95c635efSGarrett D'Amore return(0); 1552*95c635efSGarrett D'Amore 1553*95c635efSGarrett D'Amore if (j == maxargs && ! flushed) { 1554*95c635efSGarrett D'Amore if ( ! rew_elem(m, tok)) 1555*95c635efSGarrett D'Amore return(0); 1556*95c635efSGarrett D'Amore flushed = 1; 1557*95c635efSGarrett D'Amore } 1558*95c635efSGarrett D'Amore 1559*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1560*95c635efSGarrett D'Amore 1561*95c635efSGarrett D'Amore if (MDOC_MAX != ntok) { 1562*95c635efSGarrett D'Amore if ( ! flushed && ! rew_elem(m, tok)) 1563*95c635efSGarrett D'Amore return(0); 1564*95c635efSGarrett D'Amore flushed = 1; 1565*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1566*95c635efSGarrett D'Amore return(0); 1567*95c635efSGarrett D'Amore j++; 1568*95c635efSGarrett D'Amore break; 1569*95c635efSGarrett D'Amore } 1570*95c635efSGarrett D'Amore 1571*95c635efSGarrett D'Amore if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 1572*95c635efSGarrett D'Amore ARGS_QWORD != ac && 1573*95c635efSGarrett D'Amore ! flushed && 1574*95c635efSGarrett D'Amore DELIM_NONE != mdoc_isdelim(p)) { 1575*95c635efSGarrett D'Amore if ( ! rew_elem(m, tok)) 1576*95c635efSGarrett D'Amore return(0); 1577*95c635efSGarrett D'Amore flushed = 1; 1578*95c635efSGarrett D'Amore } 1579*95c635efSGarrett D'Amore 1580*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1581*95c635efSGarrett D'Amore return(0); 1582*95c635efSGarrett D'Amore j++; 1583*95c635efSGarrett D'Amore } 1584*95c635efSGarrett D'Amore 1585*95c635efSGarrett D'Amore if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg)) 1586*95c635efSGarrett D'Amore return(0); 1587*95c635efSGarrett D'Amore 1588*95c635efSGarrett D'Amore /* Close out in a consistent state. */ 1589*95c635efSGarrett D'Amore 1590*95c635efSGarrett D'Amore if ( ! flushed && ! rew_elem(m, tok)) 1591*95c635efSGarrett D'Amore return(0); 1592*95c635efSGarrett D'Amore if ( ! nl) 1593*95c635efSGarrett D'Amore return(1); 1594*95c635efSGarrett D'Amore return(append_delims(m, line, pos, buf)); 1595*95c635efSGarrett D'Amore } 1596*95c635efSGarrett D'Amore 1597*95c635efSGarrett D'Amore 1598*95c635efSGarrett D'Amore static int 1599*95c635efSGarrett D'Amore in_line_eoln(MACRO_PROT_ARGS) 1600*95c635efSGarrett D'Amore { 1601*95c635efSGarrett D'Amore int la; 1602*95c635efSGarrett D'Amore enum margserr ac; 1603*95c635efSGarrett D'Amore enum margverr av; 1604*95c635efSGarrett D'Amore struct mdoc_arg *arg; 1605*95c635efSGarrett D'Amore char *p; 1606*95c635efSGarrett D'Amore enum mdoct ntok; 1607*95c635efSGarrett D'Amore 1608*95c635efSGarrett D'Amore assert( ! (MDOC_PARSED & mdoc_macros[tok].flags)); 1609*95c635efSGarrett D'Amore 1610*95c635efSGarrett D'Amore if (tok == MDOC_Pp) 1611*95c635efSGarrett D'Amore rew_sub(MDOC_BLOCK, m, MDOC_Nm, line, ppos); 1612*95c635efSGarrett D'Amore 1613*95c635efSGarrett D'Amore /* Parse macro arguments. */ 1614*95c635efSGarrett D'Amore 1615*95c635efSGarrett D'Amore for (arg = NULL; ; ) { 1616*95c635efSGarrett D'Amore la = *pos; 1617*95c635efSGarrett D'Amore av = mdoc_argv(m, line, tok, &arg, pos, buf); 1618*95c635efSGarrett D'Amore 1619*95c635efSGarrett D'Amore if (ARGV_WORD == av) { 1620*95c635efSGarrett D'Amore *pos = la; 1621*95c635efSGarrett D'Amore break; 1622*95c635efSGarrett D'Amore } 1623*95c635efSGarrett D'Amore if (ARGV_EOLN == av) 1624*95c635efSGarrett D'Amore break; 1625*95c635efSGarrett D'Amore if (ARGV_ARG == av) 1626*95c635efSGarrett D'Amore continue; 1627*95c635efSGarrett D'Amore 1628*95c635efSGarrett D'Amore mdoc_argv_free(arg); 1629*95c635efSGarrett D'Amore return(0); 1630*95c635efSGarrett D'Amore } 1631*95c635efSGarrett D'Amore 1632*95c635efSGarrett D'Amore /* Open element scope. */ 1633*95c635efSGarrett D'Amore 1634*95c635efSGarrett D'Amore if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) 1635*95c635efSGarrett D'Amore return(0); 1636*95c635efSGarrett D'Amore 1637*95c635efSGarrett D'Amore /* Parse argument terms. */ 1638*95c635efSGarrett D'Amore 1639*95c635efSGarrett D'Amore for (;;) { 1640*95c635efSGarrett D'Amore la = *pos; 1641*95c635efSGarrett D'Amore ac = mdoc_args(m, line, pos, buf, tok, &p); 1642*95c635efSGarrett D'Amore 1643*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 1644*95c635efSGarrett D'Amore return(0); 1645*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 1646*95c635efSGarrett D'Amore break; 1647*95c635efSGarrett D'Amore 1648*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 1649*95c635efSGarrett D'Amore 1650*95c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1651*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1652*95c635efSGarrett D'Amore return(0); 1653*95c635efSGarrett D'Amore continue; 1654*95c635efSGarrett D'Amore } 1655*95c635efSGarrett D'Amore 1656*95c635efSGarrett D'Amore if ( ! rew_elem(m, tok)) 1657*95c635efSGarrett D'Amore return(0); 1658*95c635efSGarrett D'Amore return(mdoc_macro(m, ntok, line, la, pos, buf)); 1659*95c635efSGarrett D'Amore } 1660*95c635efSGarrett D'Amore 1661*95c635efSGarrett D'Amore /* Close out (no delimiters). */ 1662*95c635efSGarrett D'Amore 1663*95c635efSGarrett D'Amore return(rew_elem(m, tok)); 1664*95c635efSGarrett D'Amore } 1665*95c635efSGarrett D'Amore 1666*95c635efSGarrett D'Amore 1667*95c635efSGarrett D'Amore /* ARGSUSED */ 1668*95c635efSGarrett D'Amore static int 1669*95c635efSGarrett D'Amore ctx_synopsis(MACRO_PROT_ARGS) 1670*95c635efSGarrett D'Amore { 1671*95c635efSGarrett D'Amore int nl; 1672*95c635efSGarrett D'Amore 1673*95c635efSGarrett D'Amore nl = MDOC_NEWLINE & m->flags; 1674*95c635efSGarrett D'Amore 1675*95c635efSGarrett D'Amore /* If we're not in the SYNOPSIS, go straight to in-line. */ 1676*95c635efSGarrett D'Amore if ( ! (MDOC_SYNOPSIS & m->flags)) 1677*95c635efSGarrett D'Amore return(in_line(m, tok, line, ppos, pos, buf)); 1678*95c635efSGarrett D'Amore 1679*95c635efSGarrett D'Amore /* If we're a nested call, same place. */ 1680*95c635efSGarrett D'Amore if ( ! nl) 1681*95c635efSGarrett D'Amore return(in_line(m, tok, line, ppos, pos, buf)); 1682*95c635efSGarrett D'Amore 1683*95c635efSGarrett D'Amore /* 1684*95c635efSGarrett D'Amore * XXX: this will open a block scope; however, if later we end 1685*95c635efSGarrett D'Amore * up formatting the block scope, then child nodes will inherit 1686*95c635efSGarrett D'Amore * the formatting. Be careful. 1687*95c635efSGarrett D'Amore */ 1688*95c635efSGarrett D'Amore if (MDOC_Nm == tok) 1689*95c635efSGarrett D'Amore return(blk_full(m, tok, line, ppos, pos, buf)); 1690*95c635efSGarrett D'Amore assert(MDOC_Vt == tok); 1691*95c635efSGarrett D'Amore return(blk_part_imp(m, tok, line, ppos, pos, buf)); 1692*95c635efSGarrett D'Amore } 1693*95c635efSGarrett D'Amore 1694*95c635efSGarrett D'Amore 1695*95c635efSGarrett D'Amore /* ARGSUSED */ 1696*95c635efSGarrett D'Amore static int 1697*95c635efSGarrett D'Amore obsolete(MACRO_PROT_ARGS) 1698*95c635efSGarrett D'Amore { 1699*95c635efSGarrett D'Amore 1700*95c635efSGarrett D'Amore mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS); 1701*95c635efSGarrett D'Amore return(1); 1702*95c635efSGarrett D'Amore } 1703*95c635efSGarrett D'Amore 1704*95c635efSGarrett D'Amore 1705*95c635efSGarrett D'Amore /* 1706*95c635efSGarrett D'Amore * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs. 1707*95c635efSGarrett D'Amore * They're unusual because they're basically free-form text until a 1708*95c635efSGarrett D'Amore * macro is encountered. 1709*95c635efSGarrett D'Amore */ 1710*95c635efSGarrett D'Amore static int 1711*95c635efSGarrett D'Amore phrase(struct mdoc *m, int line, int ppos, char *buf) 1712*95c635efSGarrett D'Amore { 1713*95c635efSGarrett D'Amore int la, pos; 1714*95c635efSGarrett D'Amore enum margserr ac; 1715*95c635efSGarrett D'Amore enum mdoct ntok; 1716*95c635efSGarrett D'Amore char *p; 1717*95c635efSGarrett D'Amore 1718*95c635efSGarrett D'Amore for (pos = ppos; ; ) { 1719*95c635efSGarrett D'Amore la = pos; 1720*95c635efSGarrett D'Amore 1721*95c635efSGarrett D'Amore ac = mdoc_zargs(m, line, &pos, buf, &p); 1722*95c635efSGarrett D'Amore 1723*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 1724*95c635efSGarrett D'Amore return(0); 1725*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 1726*95c635efSGarrett D'Amore break; 1727*95c635efSGarrett D'Amore 1728*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); 1729*95c635efSGarrett D'Amore 1730*95c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1731*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1732*95c635efSGarrett D'Amore return(0); 1733*95c635efSGarrett D'Amore continue; 1734*95c635efSGarrett D'Amore } 1735*95c635efSGarrett D'Amore 1736*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, la, &pos, buf)) 1737*95c635efSGarrett D'Amore return(0); 1738*95c635efSGarrett D'Amore return(append_delims(m, line, &pos, buf)); 1739*95c635efSGarrett D'Amore } 1740*95c635efSGarrett D'Amore 1741*95c635efSGarrett D'Amore return(1); 1742*95c635efSGarrett D'Amore } 1743*95c635efSGarrett D'Amore 1744*95c635efSGarrett D'Amore 1745*95c635efSGarrett D'Amore /* ARGSUSED */ 1746*95c635efSGarrett D'Amore static int 1747*95c635efSGarrett D'Amore phrase_ta(MACRO_PROT_ARGS) 1748*95c635efSGarrett D'Amore { 1749*95c635efSGarrett D'Amore int la; 1750*95c635efSGarrett D'Amore enum mdoct ntok; 1751*95c635efSGarrett D'Amore enum margserr ac; 1752*95c635efSGarrett D'Amore char *p; 1753*95c635efSGarrett D'Amore 1754*95c635efSGarrett D'Amore /* 1755*95c635efSGarrett D'Amore * FIXME: this is overly restrictive: if the `Ta' is unexpected, 1756*95c635efSGarrett D'Amore * it should simply error out with ARGSLOST. 1757*95c635efSGarrett D'Amore */ 1758*95c635efSGarrett D'Amore 1759*95c635efSGarrett D'Amore if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos)) 1760*95c635efSGarrett D'Amore return(0); 1761*95c635efSGarrett D'Amore if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It)) 1762*95c635efSGarrett D'Amore return(0); 1763*95c635efSGarrett D'Amore 1764*95c635efSGarrett D'Amore for (;;) { 1765*95c635efSGarrett D'Amore la = *pos; 1766*95c635efSGarrett D'Amore ac = mdoc_zargs(m, line, pos, buf, &p); 1767*95c635efSGarrett D'Amore 1768*95c635efSGarrett D'Amore if (ARGS_ERROR == ac) 1769*95c635efSGarrett D'Amore return(0); 1770*95c635efSGarrett D'Amore if (ARGS_EOLN == ac) 1771*95c635efSGarrett D'Amore break; 1772*95c635efSGarrett D'Amore 1773*95c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); 1774*95c635efSGarrett D'Amore 1775*95c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1776*95c635efSGarrett D'Amore if ( ! dword(m, line, la, p, DELIM_MAX)) 1777*95c635efSGarrett D'Amore return(0); 1778*95c635efSGarrett D'Amore continue; 1779*95c635efSGarrett D'Amore } 1780*95c635efSGarrett D'Amore 1781*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) 1782*95c635efSGarrett D'Amore return(0); 1783*95c635efSGarrett D'Amore return(append_delims(m, line, pos, buf)); 1784*95c635efSGarrett D'Amore } 1785*95c635efSGarrett D'Amore 1786*95c635efSGarrett D'Amore return(1); 1787*95c635efSGarrett D'Amore } 1788