1*698f87a4SGarrett D'Amore /* $Id: mdoc_macro.c,v 1.125 2013/12/24 20:45:27 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3*698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*698f87a4SGarrett D'Amore * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 1995c635efSGarrett D'Amore #include "config.h" 2095c635efSGarrett D'Amore #endif 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <assert.h> 2395c635efSGarrett D'Amore #include <ctype.h> 2495c635efSGarrett D'Amore #include <stdlib.h> 2595c635efSGarrett D'Amore #include <stdio.h> 2695c635efSGarrett D'Amore #include <string.h> 2795c635efSGarrett D'Amore #include <time.h> 2895c635efSGarrett D'Amore 2995c635efSGarrett D'Amore #include "mdoc.h" 3095c635efSGarrett D'Amore #include "mandoc.h" 3195c635efSGarrett D'Amore #include "libmdoc.h" 3295c635efSGarrett D'Amore #include "libmandoc.h" 3395c635efSGarrett D'Amore 3495c635efSGarrett D'Amore enum rew { /* see rew_dohalt() */ 3595c635efSGarrett D'Amore REWIND_NONE, 3695c635efSGarrett D'Amore REWIND_THIS, 3795c635efSGarrett D'Amore REWIND_MORE, 3895c635efSGarrett D'Amore REWIND_FORCE, 3995c635efSGarrett D'Amore REWIND_LATER, 4095c635efSGarrett D'Amore REWIND_ERROR 4195c635efSGarrett D'Amore }; 4295c635efSGarrett D'Amore 4395c635efSGarrett D'Amore static int blk_full(MACRO_PROT_ARGS); 4495c635efSGarrett D'Amore static int blk_exp_close(MACRO_PROT_ARGS); 4595c635efSGarrett D'Amore static int blk_part_exp(MACRO_PROT_ARGS); 4695c635efSGarrett D'Amore static int blk_part_imp(MACRO_PROT_ARGS); 4795c635efSGarrett D'Amore static int ctx_synopsis(MACRO_PROT_ARGS); 4895c635efSGarrett D'Amore static int in_line_eoln(MACRO_PROT_ARGS); 4995c635efSGarrett D'Amore static int in_line_argn(MACRO_PROT_ARGS); 5095c635efSGarrett D'Amore static int in_line(MACRO_PROT_ARGS); 5195c635efSGarrett D'Amore static int obsolete(MACRO_PROT_ARGS); 5295c635efSGarrett D'Amore static int phrase_ta(MACRO_PROT_ARGS); 5395c635efSGarrett D'Amore 54*698f87a4SGarrett D'Amore static int dword(struct mdoc *, int, int, const char *, 55*698f87a4SGarrett D'Amore enum mdelim, int); 5695c635efSGarrett D'Amore static int append_delims(struct mdoc *, 5795c635efSGarrett D'Amore int, int *, char *); 5895c635efSGarrett D'Amore static enum mdoct lookup(enum mdoct, const char *); 5995c635efSGarrett D'Amore static enum mdoct lookup_raw(const char *); 6095c635efSGarrett D'Amore static int make_pending(struct mdoc_node *, enum mdoct, 6195c635efSGarrett D'Amore struct mdoc *, int, int); 6295c635efSGarrett D'Amore static int phrase(struct mdoc *, int, int, char *); 6395c635efSGarrett D'Amore static enum mdoct rew_alt(enum mdoct); 6495c635efSGarrett D'Amore static enum rew rew_dohalt(enum mdoct, enum mdoc_type, 6595c635efSGarrett D'Amore const struct mdoc_node *); 6695c635efSGarrett D'Amore static int rew_elem(struct mdoc *, enum mdoct); 6795c635efSGarrett D'Amore static int rew_last(struct mdoc *, 6895c635efSGarrett D'Amore const struct mdoc_node *); 6995c635efSGarrett D'Amore static int rew_sub(enum mdoc_type, struct mdoc *, 7095c635efSGarrett D'Amore enum mdoct, int, int); 7195c635efSGarrett D'Amore 7295c635efSGarrett D'Amore const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { 73*698f87a4SGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ 7495c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ 7595c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ 7695c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Os */ 77*698f87a4SGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */ 78*698f87a4SGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Ss */ 7995c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Pp */ 80*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* D1 */ 81*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* Dl */ 8295c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bd */ 83*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */ 8495c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bl */ 85*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* El */ 86*698f87a4SGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */ 8795c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ 88*698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */ 8995c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ 9095c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */ 9195c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ 9295c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ 9395c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ 9495c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ 9595c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Ex */ 9695c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ 9795c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Fd */ 9895c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */ 9995c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ 10095c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ 10195c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */ 10295c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ 103*698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */ 104*698f87a4SGarrett D'Amore { blk_full, MDOC_JOIN }, /* Nd */ 10595c635efSGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ 10695c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ 10795c635efSGarrett D'Amore { obsolete, 0 }, /* Ot */ 10895c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ 10995c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Rv */ 11095c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ 11195c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */ 11295c635efSGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ 11395c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */ 114*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %A */ 115*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %B */ 116*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %D */ 117*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %I */ 118*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %J */ 11995c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %N */ 120*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %O */ 12195c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %P */ 122*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %R */ 123*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %T */ 12495c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %V */ 125*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 126*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Ac */ 127*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 128*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Ao */ 129*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Aq */ 13095c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */ 131*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 132*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Bc */ 13395c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bf */ 134*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 135*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Bo */ 136*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Bq */ 13795c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */ 13895c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */ 13995c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Db */ 140*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 141*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Dc */ 142*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 143*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Do */ 144*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Dq */ 145*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ec */ 146*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ef */ 147*698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Em */ 14895c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */ 14995c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */ 15095c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */ 151*698f87a4SGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | 152*698f87a4SGarrett D'Amore MDOC_IGNDELIM | MDOC_JOIN }, /* No */ 153*698f87a4SGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | 154*698f87a4SGarrett D'Amore MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */ 15595c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ 15695c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */ 157*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 158*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Pc */ 15995c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */ 160*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 161*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Po */ 162*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Pq */ 163*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 164*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Qc */ 165*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ql */ 166*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 167*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Qo */ 168*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Qq */ 169*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Re */ 17095c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Rs */ 171*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 172*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Sc */ 173*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 174*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* So */ 175*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */ 17695c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Sm */ 177*698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */ 178*698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */ 17995c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */ 180*698f87a4SGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ux */ 18195c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */ 18295c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */ 18395c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ 184*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 185*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Fc */ 186*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 187*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Oo */ 188*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 189*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Oc */ 19095c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bk */ 191*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */ 19295c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Bt */ 19395c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Hf */ 19495c635efSGarrett D'Amore { obsolete, 0 }, /* Fr */ 19595c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Ud */ 19695c635efSGarrett D'Amore { in_line, 0 }, /* Lb */ 19795c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Lp */ 19895c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ 19995c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ 200*698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */ 201*698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 202*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Bro */ 203*698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 204*698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Brc */ 205*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %C */ 20695c635efSGarrett D'Amore { obsolete, 0 }, /* Es */ 20795c635efSGarrett D'Amore { obsolete, 0 }, /* En */ 20895c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ 209*698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %Q */ 21095c635efSGarrett D'Amore { in_line_eoln, 0 }, /* br */ 21195c635efSGarrett D'Amore { in_line_eoln, 0 }, /* sp */ 21295c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %U */ 213*698f87a4SGarrett D'Amore { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ 21495c635efSGarrett D'Amore }; 21595c635efSGarrett D'Amore 21695c635efSGarrett D'Amore const struct mdoc_macro * const mdoc_macros = __mdoc_macros; 21795c635efSGarrett D'Amore 21895c635efSGarrett D'Amore 21995c635efSGarrett D'Amore /* 22095c635efSGarrett D'Amore * This is called at the end of parsing. It must traverse up the tree, 22195c635efSGarrett D'Amore * closing out open [implicit] scopes. Obviously, open explicit scopes 22295c635efSGarrett D'Amore * are errors. 22395c635efSGarrett D'Amore */ 22495c635efSGarrett D'Amore int 225*698f87a4SGarrett D'Amore mdoc_macroend(struct mdoc *mdoc) 22695c635efSGarrett D'Amore { 22795c635efSGarrett D'Amore struct mdoc_node *n; 22895c635efSGarrett D'Amore 22995c635efSGarrett D'Amore /* Scan for open explicit scopes. */ 23095c635efSGarrett D'Amore 231*698f87a4SGarrett D'Amore n = MDOC_VALID & mdoc->last->flags ? 232*698f87a4SGarrett D'Amore mdoc->last->parent : mdoc->last; 23395c635efSGarrett D'Amore 23495c635efSGarrett D'Amore for ( ; n; n = n->parent) 23595c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && 23695c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[n->tok].flags) 237*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_SCOPEEXIT); 23895c635efSGarrett D'Amore 23995c635efSGarrett D'Amore /* Rewind to the first. */ 24095c635efSGarrett D'Amore 241*698f87a4SGarrett D'Amore return(rew_last(mdoc, mdoc->first)); 24295c635efSGarrett D'Amore } 24395c635efSGarrett D'Amore 24495c635efSGarrett D'Amore 24595c635efSGarrett D'Amore /* 24695c635efSGarrett D'Amore * Look up a macro from within a subsequent context. 24795c635efSGarrett D'Amore */ 24895c635efSGarrett D'Amore static enum mdoct 24995c635efSGarrett D'Amore lookup(enum mdoct from, const char *p) 25095c635efSGarrett D'Amore { 25195c635efSGarrett D'Amore 25295c635efSGarrett D'Amore if ( ! (MDOC_PARSED & mdoc_macros[from].flags)) 25395c635efSGarrett D'Amore return(MDOC_MAX); 25495c635efSGarrett D'Amore return(lookup_raw(p)); 25595c635efSGarrett D'Amore } 25695c635efSGarrett D'Amore 25795c635efSGarrett D'Amore 25895c635efSGarrett D'Amore /* 25995c635efSGarrett D'Amore * Lookup a macro following the initial line macro. 26095c635efSGarrett D'Amore */ 26195c635efSGarrett D'Amore static enum mdoct 26295c635efSGarrett D'Amore lookup_raw(const char *p) 26395c635efSGarrett D'Amore { 26495c635efSGarrett D'Amore enum mdoct res; 26595c635efSGarrett D'Amore 26695c635efSGarrett D'Amore if (MDOC_MAX == (res = mdoc_hash_find(p))) 26795c635efSGarrett D'Amore return(MDOC_MAX); 26895c635efSGarrett D'Amore if (MDOC_CALLABLE & mdoc_macros[res].flags) 26995c635efSGarrett D'Amore return(res); 27095c635efSGarrett D'Amore return(MDOC_MAX); 27195c635efSGarrett D'Amore } 27295c635efSGarrett D'Amore 27395c635efSGarrett D'Amore 27495c635efSGarrett D'Amore static int 27595c635efSGarrett D'Amore rew_last(struct mdoc *mdoc, const struct mdoc_node *to) 27695c635efSGarrett D'Amore { 27795c635efSGarrett D'Amore struct mdoc_node *n, *np; 27895c635efSGarrett D'Amore 27995c635efSGarrett D'Amore assert(to); 28095c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 28195c635efSGarrett D'Amore 28295c635efSGarrett D'Amore /* LINTED */ 28395c635efSGarrett D'Amore while (mdoc->last != to) { 28495c635efSGarrett D'Amore /* 28595c635efSGarrett D'Amore * Save the parent here, because we may delete the 286*698f87a4SGarrett D'Amore * mdoc->last node in the post-validation phase and reset 287*698f87a4SGarrett D'Amore * it to mdoc->last->parent, causing a step in the closing 28895c635efSGarrett D'Amore * out to be lost. 28995c635efSGarrett D'Amore */ 29095c635efSGarrett D'Amore np = mdoc->last->parent; 29195c635efSGarrett D'Amore if ( ! mdoc_valid_post(mdoc)) 29295c635efSGarrett D'Amore return(0); 29395c635efSGarrett D'Amore n = mdoc->last; 29495c635efSGarrett D'Amore mdoc->last = np; 29595c635efSGarrett D'Amore assert(mdoc->last); 29695c635efSGarrett D'Amore mdoc->last->last = n; 29795c635efSGarrett D'Amore } 29895c635efSGarrett D'Amore 29995c635efSGarrett D'Amore return(mdoc_valid_post(mdoc)); 30095c635efSGarrett D'Amore } 30195c635efSGarrett D'Amore 30295c635efSGarrett D'Amore 30395c635efSGarrett D'Amore /* 30495c635efSGarrett D'Amore * For a block closing macro, return the corresponding opening one. 30595c635efSGarrett D'Amore * Otherwise, return the macro itself. 30695c635efSGarrett D'Amore */ 30795c635efSGarrett D'Amore static enum mdoct 30895c635efSGarrett D'Amore rew_alt(enum mdoct tok) 30995c635efSGarrett D'Amore { 31095c635efSGarrett D'Amore switch (tok) { 31195c635efSGarrett D'Amore case (MDOC_Ac): 31295c635efSGarrett D'Amore return(MDOC_Ao); 31395c635efSGarrett D'Amore case (MDOC_Bc): 31495c635efSGarrett D'Amore return(MDOC_Bo); 31595c635efSGarrett D'Amore case (MDOC_Brc): 31695c635efSGarrett D'Amore return(MDOC_Bro); 31795c635efSGarrett D'Amore case (MDOC_Dc): 31895c635efSGarrett D'Amore return(MDOC_Do); 31995c635efSGarrett D'Amore case (MDOC_Ec): 32095c635efSGarrett D'Amore return(MDOC_Eo); 32195c635efSGarrett D'Amore case (MDOC_Ed): 32295c635efSGarrett D'Amore return(MDOC_Bd); 32395c635efSGarrett D'Amore case (MDOC_Ef): 32495c635efSGarrett D'Amore return(MDOC_Bf); 32595c635efSGarrett D'Amore case (MDOC_Ek): 32695c635efSGarrett D'Amore return(MDOC_Bk); 32795c635efSGarrett D'Amore case (MDOC_El): 32895c635efSGarrett D'Amore return(MDOC_Bl); 32995c635efSGarrett D'Amore case (MDOC_Fc): 33095c635efSGarrett D'Amore return(MDOC_Fo); 33195c635efSGarrett D'Amore case (MDOC_Oc): 33295c635efSGarrett D'Amore return(MDOC_Oo); 33395c635efSGarrett D'Amore case (MDOC_Pc): 33495c635efSGarrett D'Amore return(MDOC_Po); 33595c635efSGarrett D'Amore case (MDOC_Qc): 33695c635efSGarrett D'Amore return(MDOC_Qo); 33795c635efSGarrett D'Amore case (MDOC_Re): 33895c635efSGarrett D'Amore return(MDOC_Rs); 33995c635efSGarrett D'Amore case (MDOC_Sc): 34095c635efSGarrett D'Amore return(MDOC_So); 34195c635efSGarrett D'Amore case (MDOC_Xc): 34295c635efSGarrett D'Amore return(MDOC_Xo); 34395c635efSGarrett D'Amore default: 34495c635efSGarrett D'Amore return(tok); 34595c635efSGarrett D'Amore } 34695c635efSGarrett D'Amore /* NOTREACHED */ 34795c635efSGarrett D'Amore } 34895c635efSGarrett D'Amore 34995c635efSGarrett D'Amore 35095c635efSGarrett D'Amore /* 35195c635efSGarrett D'Amore * Rewinding to tok, how do we have to handle *p? 35295c635efSGarrett D'Amore * REWIND_NONE: *p would delimit tok, but no tok scope is open 35395c635efSGarrett D'Amore * inside *p, so there is no need to rewind anything at all. 35495c635efSGarrett D'Amore * REWIND_THIS: *p matches tok, so rewind *p and nothing else. 35595c635efSGarrett D'Amore * REWIND_MORE: *p is implicit, rewind it and keep searching for tok. 35695c635efSGarrett D'Amore * REWIND_FORCE: *p is explicit, but tok is full, force rewinding *p. 35795c635efSGarrett D'Amore * REWIND_LATER: *p is explicit and still open, postpone rewinding. 35895c635efSGarrett D'Amore * REWIND_ERROR: No tok block is open at all. 35995c635efSGarrett D'Amore */ 36095c635efSGarrett D'Amore static enum rew 36195c635efSGarrett D'Amore rew_dohalt(enum mdoct tok, enum mdoc_type type, 36295c635efSGarrett D'Amore const struct mdoc_node *p) 36395c635efSGarrett D'Amore { 36495c635efSGarrett D'Amore 36595c635efSGarrett D'Amore /* 36695c635efSGarrett D'Amore * No matching token, no delimiting block, no broken block. 36795c635efSGarrett D'Amore * This can happen when full implicit macros are called for 36895c635efSGarrett D'Amore * the first time but try to rewind their previous 36995c635efSGarrett D'Amore * instance anyway. 37095c635efSGarrett D'Amore */ 37195c635efSGarrett D'Amore if (MDOC_ROOT == p->type) 37295c635efSGarrett D'Amore return(MDOC_BLOCK == type && 37395c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[tok].flags ? 37495c635efSGarrett D'Amore REWIND_ERROR : REWIND_NONE); 37595c635efSGarrett D'Amore 37695c635efSGarrett D'Amore /* 37795c635efSGarrett D'Amore * When starting to rewind, skip plain text 37895c635efSGarrett D'Amore * and nodes that have already been rewound. 37995c635efSGarrett D'Amore */ 38095c635efSGarrett D'Amore if (MDOC_TEXT == p->type || MDOC_VALID & p->flags) 38195c635efSGarrett D'Amore return(REWIND_MORE); 38295c635efSGarrett D'Amore 38395c635efSGarrett D'Amore /* 38495c635efSGarrett D'Amore * The easiest case: Found a matching token. 38595c635efSGarrett D'Amore * This applies to both blocks and elements. 38695c635efSGarrett D'Amore */ 38795c635efSGarrett D'Amore tok = rew_alt(tok); 38895c635efSGarrett D'Amore if (tok == p->tok) 38995c635efSGarrett D'Amore return(p->end ? REWIND_NONE : 39095c635efSGarrett D'Amore type == p->type ? REWIND_THIS : REWIND_MORE); 39195c635efSGarrett D'Amore 39295c635efSGarrett D'Amore /* 39395c635efSGarrett D'Amore * While elements do require rewinding for themselves, 39495c635efSGarrett D'Amore * they never affect rewinding of other nodes. 39595c635efSGarrett D'Amore */ 39695c635efSGarrett D'Amore if (MDOC_ELEM == p->type) 39795c635efSGarrett D'Amore return(REWIND_MORE); 39895c635efSGarrett D'Amore 39995c635efSGarrett D'Amore /* 40095c635efSGarrett D'Amore * Blocks delimited by our target token get REWIND_MORE. 40195c635efSGarrett D'Amore * Blocks delimiting our target token get REWIND_NONE. 40295c635efSGarrett D'Amore */ 40395c635efSGarrett D'Amore switch (tok) { 40495c635efSGarrett D'Amore case (MDOC_Bl): 40595c635efSGarrett D'Amore if (MDOC_It == p->tok) 40695c635efSGarrett D'Amore return(REWIND_MORE); 40795c635efSGarrett D'Amore break; 40895c635efSGarrett D'Amore case (MDOC_It): 40995c635efSGarrett D'Amore if (MDOC_BODY == p->type && MDOC_Bl == p->tok) 41095c635efSGarrett D'Amore return(REWIND_NONE); 41195c635efSGarrett D'Amore break; 41295c635efSGarrett D'Amore /* 41395c635efSGarrett D'Amore * XXX Badly nested block handling still fails badly 41495c635efSGarrett D'Amore * when one block is breaking two blocks of the same type. 41595c635efSGarrett D'Amore * This is an incomplete and extremely ugly workaround, 41695c635efSGarrett D'Amore * required to let the OpenBSD tree build. 41795c635efSGarrett D'Amore */ 41895c635efSGarrett D'Amore case (MDOC_Oo): 41995c635efSGarrett D'Amore if (MDOC_Op == p->tok) 42095c635efSGarrett D'Amore return(REWIND_MORE); 42195c635efSGarrett D'Amore break; 42295c635efSGarrett D'Amore case (MDOC_Nm): 42395c635efSGarrett D'Amore return(REWIND_NONE); 42495c635efSGarrett D'Amore case (MDOC_Nd): 42595c635efSGarrett D'Amore /* FALLTHROUGH */ 42695c635efSGarrett D'Amore case (MDOC_Ss): 42795c635efSGarrett D'Amore if (MDOC_BODY == p->type && MDOC_Sh == p->tok) 42895c635efSGarrett D'Amore return(REWIND_NONE); 42995c635efSGarrett D'Amore /* FALLTHROUGH */ 43095c635efSGarrett D'Amore case (MDOC_Sh): 43195c635efSGarrett D'Amore if (MDOC_Nd == p->tok || MDOC_Ss == p->tok || 43295c635efSGarrett D'Amore MDOC_Sh == p->tok) 43395c635efSGarrett D'Amore return(REWIND_MORE); 43495c635efSGarrett D'Amore break; 43595c635efSGarrett D'Amore default: 43695c635efSGarrett D'Amore break; 43795c635efSGarrett D'Amore } 43895c635efSGarrett D'Amore 43995c635efSGarrett D'Amore /* 44095c635efSGarrett D'Amore * Default block rewinding rules. 44195c635efSGarrett D'Amore * In particular, always skip block end markers, 44295c635efSGarrett D'Amore * and let all blocks rewind Nm children. 44395c635efSGarrett D'Amore */ 44495c635efSGarrett D'Amore if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok || 44595c635efSGarrett D'Amore (MDOC_BLOCK == p->type && 44695c635efSGarrett D'Amore ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))) 44795c635efSGarrett D'Amore return(REWIND_MORE); 44895c635efSGarrett D'Amore 44995c635efSGarrett D'Amore /* 45095c635efSGarrett D'Amore * By default, closing out full blocks 45195c635efSGarrett D'Amore * forces closing of broken explicit blocks, 45295c635efSGarrett D'Amore * while closing out partial blocks 45395c635efSGarrett D'Amore * allows delayed rewinding by default. 45495c635efSGarrett D'Amore */ 45595c635efSGarrett D'Amore return (&blk_full == mdoc_macros[tok].fp ? 45695c635efSGarrett D'Amore REWIND_FORCE : REWIND_LATER); 45795c635efSGarrett D'Amore } 45895c635efSGarrett D'Amore 45995c635efSGarrett D'Amore 46095c635efSGarrett D'Amore static int 46195c635efSGarrett D'Amore rew_elem(struct mdoc *mdoc, enum mdoct tok) 46295c635efSGarrett D'Amore { 46395c635efSGarrett D'Amore struct mdoc_node *n; 46495c635efSGarrett D'Amore 46595c635efSGarrett D'Amore n = mdoc->last; 46695c635efSGarrett D'Amore if (MDOC_ELEM != n->type) 46795c635efSGarrett D'Amore n = n->parent; 46895c635efSGarrett D'Amore assert(MDOC_ELEM == n->type); 46995c635efSGarrett D'Amore assert(tok == n->tok); 47095c635efSGarrett D'Amore 47195c635efSGarrett D'Amore return(rew_last(mdoc, n)); 47295c635efSGarrett D'Amore } 47395c635efSGarrett D'Amore 47495c635efSGarrett D'Amore 47595c635efSGarrett D'Amore /* 47695c635efSGarrett D'Amore * We are trying to close a block identified by tok, 47795c635efSGarrett D'Amore * but the child block *broken is still open. 47895c635efSGarrett D'Amore * Thus, postpone closing the tok block 47995c635efSGarrett D'Amore * until the rew_sub call closing *broken. 48095c635efSGarrett D'Amore */ 48195c635efSGarrett D'Amore static int 48295c635efSGarrett D'Amore make_pending(struct mdoc_node *broken, enum mdoct tok, 483*698f87a4SGarrett D'Amore struct mdoc *mdoc, int line, int ppos) 48495c635efSGarrett D'Amore { 48595c635efSGarrett D'Amore struct mdoc_node *breaker; 48695c635efSGarrett D'Amore 48795c635efSGarrett D'Amore /* 48895c635efSGarrett D'Amore * Iterate backwards, searching for the block matching tok, 48995c635efSGarrett D'Amore * that is, the block breaking the *broken block. 49095c635efSGarrett D'Amore */ 49195c635efSGarrett D'Amore for (breaker = broken->parent; breaker; breaker = breaker->parent) { 49295c635efSGarrett D'Amore 49395c635efSGarrett D'Amore /* 49495c635efSGarrett D'Amore * If the *broken block had already been broken before 49595c635efSGarrett D'Amore * and we encounter its breaker, make the tok block 49695c635efSGarrett D'Amore * pending on the inner breaker. 49795c635efSGarrett D'Amore * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]" 49895c635efSGarrett D'Amore * becomes "[A broken=[B [C->B B] tok=A] C]" 49995c635efSGarrett D'Amore * and finally "[A [B->A [C->B B] A] C]". 50095c635efSGarrett D'Amore */ 50195c635efSGarrett D'Amore if (breaker == broken->pending) { 50295c635efSGarrett D'Amore broken = breaker; 50395c635efSGarrett D'Amore continue; 50495c635efSGarrett D'Amore } 50595c635efSGarrett D'Amore 50695c635efSGarrett D'Amore if (REWIND_THIS != rew_dohalt(tok, MDOC_BLOCK, breaker)) 50795c635efSGarrett D'Amore continue; 50895c635efSGarrett D'Amore if (MDOC_BODY == broken->type) 50995c635efSGarrett D'Amore broken = broken->parent; 51095c635efSGarrett D'Amore 51195c635efSGarrett D'Amore /* 51295c635efSGarrett D'Amore * Found the breaker. 51395c635efSGarrett D'Amore * If another, outer breaker is already pending on 51495c635efSGarrett D'Amore * the *broken block, we must not clobber the link 51595c635efSGarrett D'Amore * to the outer breaker, but make it pending on the 51695c635efSGarrett D'Amore * new, now inner breaker. 51795c635efSGarrett D'Amore * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]" 51895c635efSGarrett D'Amore * becomes "[A breaker=[B->A broken=[C A] tok=B] C]" 51995c635efSGarrett D'Amore * and finally "[A [B->A [C->B A] B] C]". 52095c635efSGarrett D'Amore */ 52195c635efSGarrett D'Amore if (broken->pending) { 52295c635efSGarrett D'Amore struct mdoc_node *taker; 52395c635efSGarrett D'Amore 52495c635efSGarrett D'Amore /* 52595c635efSGarrett D'Amore * If the breaker had also been broken before, 52695c635efSGarrett D'Amore * it cannot take on the outer breaker itself, 52795c635efSGarrett D'Amore * but must hand it on to its own breakers. 52895c635efSGarrett D'Amore * Graphically, this is the following situation: 52995c635efSGarrett D'Amore * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]" 53095c635efSGarrett D'Amore * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]" 53195c635efSGarrett D'Amore */ 53295c635efSGarrett D'Amore taker = breaker; 53395c635efSGarrett D'Amore while (taker->pending) 53495c635efSGarrett D'Amore taker = taker->pending; 53595c635efSGarrett D'Amore taker->pending = broken->pending; 53695c635efSGarrett D'Amore } 53795c635efSGarrett D'Amore broken->pending = breaker; 538*698f87a4SGarrett D'Amore mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos, 53995c635efSGarrett D'Amore "%s breaks %s", mdoc_macronames[tok], 54095c635efSGarrett D'Amore mdoc_macronames[broken->tok]); 54195c635efSGarrett D'Amore return(1); 54295c635efSGarrett D'Amore } 54395c635efSGarrett D'Amore 54495c635efSGarrett D'Amore /* 54595c635efSGarrett D'Amore * Found no matching block for tok. 54695c635efSGarrett D'Amore * Are you trying to close a block that is not open? 54795c635efSGarrett D'Amore */ 54895c635efSGarrett D'Amore return(0); 54995c635efSGarrett D'Amore } 55095c635efSGarrett D'Amore 55195c635efSGarrett D'Amore 55295c635efSGarrett D'Amore static int 553*698f87a4SGarrett D'Amore rew_sub(enum mdoc_type t, struct mdoc *mdoc, 55495c635efSGarrett D'Amore enum mdoct tok, int line, int ppos) 55595c635efSGarrett D'Amore { 55695c635efSGarrett D'Amore struct mdoc_node *n; 55795c635efSGarrett D'Amore 558*698f87a4SGarrett D'Amore n = mdoc->last; 55995c635efSGarrett D'Amore while (n) { 56095c635efSGarrett D'Amore switch (rew_dohalt(tok, t, n)) { 56195c635efSGarrett D'Amore case (REWIND_NONE): 56295c635efSGarrett D'Amore return(1); 56395c635efSGarrett D'Amore case (REWIND_THIS): 564*698f87a4SGarrett D'Amore n->lastline = line - 565*698f87a4SGarrett D'Amore (MDOC_NEWLINE & mdoc->flags && 566*698f87a4SGarrett D'Amore ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)); 56795c635efSGarrett D'Amore break; 56895c635efSGarrett D'Amore case (REWIND_FORCE): 569*698f87a4SGarrett D'Amore mandoc_vmsg(MANDOCERR_SCOPEBROKEN, mdoc->parse, 57095c635efSGarrett D'Amore line, ppos, "%s breaks %s", 57195c635efSGarrett D'Amore mdoc_macronames[tok], 57295c635efSGarrett D'Amore mdoc_macronames[n->tok]); 57395c635efSGarrett D'Amore /* FALLTHROUGH */ 57495c635efSGarrett D'Amore case (REWIND_MORE): 575*698f87a4SGarrett D'Amore n->lastline = line - 576*698f87a4SGarrett D'Amore (MDOC_NEWLINE & mdoc->flags ? 1 : 0); 57795c635efSGarrett D'Amore n = n->parent; 57895c635efSGarrett D'Amore continue; 57995c635efSGarrett D'Amore case (REWIND_LATER): 580*698f87a4SGarrett D'Amore if (make_pending(n, tok, mdoc, line, ppos) || 58195c635efSGarrett D'Amore MDOC_BLOCK != t) 58295c635efSGarrett D'Amore return(1); 58395c635efSGarrett D'Amore /* FALLTHROUGH */ 58495c635efSGarrett D'Amore case (REWIND_ERROR): 585*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, MANDOCERR_NOSCOPE); 58695c635efSGarrett D'Amore return(1); 58795c635efSGarrett D'Amore } 58895c635efSGarrett D'Amore break; 58995c635efSGarrett D'Amore } 59095c635efSGarrett D'Amore 59195c635efSGarrett D'Amore assert(n); 592*698f87a4SGarrett D'Amore if ( ! rew_last(mdoc, n)) 59395c635efSGarrett D'Amore return(0); 59495c635efSGarrett D'Amore 59595c635efSGarrett D'Amore /* 59695c635efSGarrett D'Amore * The current block extends an enclosing block. 59795c635efSGarrett D'Amore * Now that the current block ends, close the enclosing block, too. 59895c635efSGarrett D'Amore */ 59995c635efSGarrett D'Amore while (NULL != (n = n->pending)) { 600*698f87a4SGarrett D'Amore if ( ! rew_last(mdoc, n)) 60195c635efSGarrett D'Amore return(0); 60295c635efSGarrett D'Amore if (MDOC_HEAD == n->type && 603*698f87a4SGarrett D'Amore ! mdoc_body_alloc(mdoc, n->line, n->pos, n->tok)) 60495c635efSGarrett D'Amore return(0); 60595c635efSGarrett D'Amore } 60695c635efSGarrett D'Amore 60795c635efSGarrett D'Amore return(1); 60895c635efSGarrett D'Amore } 60995c635efSGarrett D'Amore 61095c635efSGarrett D'Amore /* 61195c635efSGarrett D'Amore * Allocate a word and check whether it's punctuation or not. 61295c635efSGarrett D'Amore * Punctuation consists of those tokens found in mdoc_isdelim(). 61395c635efSGarrett D'Amore */ 61495c635efSGarrett D'Amore static int 615*698f87a4SGarrett D'Amore dword(struct mdoc *mdoc, int line, int col, const char *p, 616*698f87a4SGarrett D'Amore enum mdelim d, int may_append) 61795c635efSGarrett D'Amore { 61895c635efSGarrett D'Amore 61995c635efSGarrett D'Amore if (DELIM_MAX == d) 62095c635efSGarrett D'Amore d = mdoc_isdelim(p); 62195c635efSGarrett D'Amore 622*698f87a4SGarrett D'Amore if (may_append && 623*698f87a4SGarrett D'Amore ! ((MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF) & mdoc->flags) && 624*698f87a4SGarrett D'Amore DELIM_NONE == d && MDOC_TEXT == mdoc->last->type && 625*698f87a4SGarrett D'Amore DELIM_NONE == mdoc_isdelim(mdoc->last->string)) { 626*698f87a4SGarrett D'Amore mdoc_word_append(mdoc, p); 627*698f87a4SGarrett D'Amore return(1); 628*698f87a4SGarrett D'Amore } 629*698f87a4SGarrett D'Amore 630*698f87a4SGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, line, col, p)) 63195c635efSGarrett D'Amore return(0); 63295c635efSGarrett D'Amore 63395c635efSGarrett D'Amore if (DELIM_OPEN == d) 634*698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_DELIMO; 63595c635efSGarrett D'Amore 63695c635efSGarrett D'Amore /* 63795c635efSGarrett D'Amore * Closing delimiters only suppress the preceding space 63895c635efSGarrett D'Amore * when they follow something, not when they start a new 63995c635efSGarrett D'Amore * block or element, and not when they follow `No'. 64095c635efSGarrett D'Amore * 64195c635efSGarrett D'Amore * XXX Explicitly special-casing MDOC_No here feels 64295c635efSGarrett D'Amore * like a layering violation. Find a better way 64395c635efSGarrett D'Amore * and solve this in the code related to `No'! 64495c635efSGarrett D'Amore */ 64595c635efSGarrett D'Amore 646*698f87a4SGarrett D'Amore else if (DELIM_CLOSE == d && mdoc->last->prev && 647*698f87a4SGarrett D'Amore mdoc->last->prev->tok != MDOC_No && 648*698f87a4SGarrett D'Amore mdoc->last->parent->tok != MDOC_Fd) 649*698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_DELIMC; 65095c635efSGarrett D'Amore 65195c635efSGarrett D'Amore return(1); 65295c635efSGarrett D'Amore } 65395c635efSGarrett D'Amore 65495c635efSGarrett D'Amore static int 655*698f87a4SGarrett D'Amore append_delims(struct mdoc *mdoc, int line, int *pos, char *buf) 65695c635efSGarrett D'Amore { 65795c635efSGarrett D'Amore int la; 65895c635efSGarrett D'Amore enum margserr ac; 65995c635efSGarrett D'Amore char *p; 66095c635efSGarrett D'Amore 66195c635efSGarrett D'Amore if ('\0' == buf[*pos]) 66295c635efSGarrett D'Amore return(1); 66395c635efSGarrett D'Amore 66495c635efSGarrett D'Amore for (;;) { 66595c635efSGarrett D'Amore la = *pos; 666*698f87a4SGarrett D'Amore ac = mdoc_zargs(mdoc, line, pos, buf, &p); 66795c635efSGarrett D'Amore 66895c635efSGarrett D'Amore if (ARGS_ERROR == ac) 66995c635efSGarrett D'Amore return(0); 67095c635efSGarrett D'Amore else if (ARGS_EOLN == ac) 67195c635efSGarrett D'Amore break; 67295c635efSGarrett D'Amore 673*698f87a4SGarrett D'Amore dword(mdoc, line, la, p, DELIM_MAX, 1); 67495c635efSGarrett D'Amore 67595c635efSGarrett D'Amore /* 67695c635efSGarrett D'Amore * If we encounter end-of-sentence symbols, then trigger 67795c635efSGarrett D'Amore * the double-space. 67895c635efSGarrett D'Amore * 67995c635efSGarrett D'Amore * XXX: it's easy to allow this to propagate outward to 68095c635efSGarrett D'Amore * the last symbol, such that `. )' will cause the 68195c635efSGarrett D'Amore * correct double-spacing. However, (1) groff isn't 68295c635efSGarrett D'Amore * smart enough to do this and (2) it would require 68395c635efSGarrett D'Amore * knowing which symbols break this behaviour, for 68495c635efSGarrett D'Amore * example, `. ;' shouldn't propagate the double-space. 68595c635efSGarrett D'Amore */ 68695c635efSGarrett D'Amore if (mandoc_eos(p, strlen(p), 0)) 687*698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_EOS; 68895c635efSGarrett D'Amore } 68995c635efSGarrett D'Amore 69095c635efSGarrett D'Amore return(1); 69195c635efSGarrett D'Amore } 69295c635efSGarrett D'Amore 69395c635efSGarrett D'Amore 69495c635efSGarrett D'Amore /* 69595c635efSGarrett D'Amore * Close out block partial/full explicit. 69695c635efSGarrett D'Amore */ 69795c635efSGarrett D'Amore static int 69895c635efSGarrett D'Amore blk_exp_close(MACRO_PROT_ARGS) 69995c635efSGarrett D'Amore { 70095c635efSGarrett D'Amore struct mdoc_node *body; /* Our own body. */ 70195c635efSGarrett D'Amore struct mdoc_node *later; /* A sub-block starting later. */ 70295c635efSGarrett D'Amore struct mdoc_node *n; /* For searching backwards. */ 70395c635efSGarrett D'Amore 70495c635efSGarrett D'Amore int j, lastarg, maxargs, flushed, nl; 70595c635efSGarrett D'Amore enum margserr ac; 70695c635efSGarrett D'Amore enum mdoct atok, ntok; 70795c635efSGarrett D'Amore char *p; 70895c635efSGarrett D'Amore 709*698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 71095c635efSGarrett D'Amore 71195c635efSGarrett D'Amore switch (tok) { 71295c635efSGarrett D'Amore case (MDOC_Ec): 71395c635efSGarrett D'Amore maxargs = 1; 71495c635efSGarrett D'Amore break; 715*698f87a4SGarrett D'Amore case (MDOC_Ek): 716*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_KEEP; 71795c635efSGarrett D'Amore default: 71895c635efSGarrett D'Amore maxargs = 0; 71995c635efSGarrett D'Amore break; 72095c635efSGarrett D'Amore } 72195c635efSGarrett D'Amore 72295c635efSGarrett D'Amore /* 72395c635efSGarrett D'Amore * Search backwards for beginnings of blocks, 72495c635efSGarrett D'Amore * both of our own and of pending sub-blocks. 72595c635efSGarrett D'Amore */ 72695c635efSGarrett D'Amore atok = rew_alt(tok); 72795c635efSGarrett D'Amore body = later = NULL; 728*698f87a4SGarrett D'Amore for (n = mdoc->last; n; n = n->parent) { 72995c635efSGarrett D'Amore if (MDOC_VALID & n->flags) 73095c635efSGarrett D'Amore continue; 73195c635efSGarrett D'Amore 73295c635efSGarrett D'Amore /* Remember the start of our own body. */ 73395c635efSGarrett D'Amore if (MDOC_BODY == n->type && atok == n->tok) { 73495c635efSGarrett D'Amore if (ENDBODY_NOT == n->end) 73595c635efSGarrett D'Amore body = n; 73695c635efSGarrett D'Amore continue; 73795c635efSGarrett D'Amore } 73895c635efSGarrett D'Amore 73995c635efSGarrett D'Amore if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok) 74095c635efSGarrett D'Amore continue; 74195c635efSGarrett D'Amore if (atok == n->tok) { 74295c635efSGarrett D'Amore assert(body); 74395c635efSGarrett D'Amore 74495c635efSGarrett D'Amore /* 74595c635efSGarrett D'Amore * Found the start of our own block. 74695c635efSGarrett D'Amore * When there is no pending sub block, 74795c635efSGarrett D'Amore * just proceed to closing out. 74895c635efSGarrett D'Amore */ 74995c635efSGarrett D'Amore if (NULL == later) 75095c635efSGarrett D'Amore break; 75195c635efSGarrett D'Amore 75295c635efSGarrett D'Amore /* 75395c635efSGarrett D'Amore * When there is a pending sub block, 75495c635efSGarrett D'Amore * postpone closing out the current block 75595c635efSGarrett D'Amore * until the rew_sub() closing out the sub-block. 75695c635efSGarrett D'Amore */ 757*698f87a4SGarrett D'Amore make_pending(later, tok, mdoc, line, ppos); 75895c635efSGarrett D'Amore 75995c635efSGarrett D'Amore /* 76095c635efSGarrett D'Amore * Mark the place where the formatting - but not 76195c635efSGarrett D'Amore * the scope - of the current block ends. 76295c635efSGarrett D'Amore */ 763*698f87a4SGarrett D'Amore if ( ! mdoc_endbody_alloc(mdoc, line, ppos, 76495c635efSGarrett D'Amore atok, body, ENDBODY_SPACE)) 76595c635efSGarrett D'Amore return(0); 76695c635efSGarrett D'Amore break; 76795c635efSGarrett D'Amore } 76895c635efSGarrett D'Amore 76995c635efSGarrett D'Amore /* 77095c635efSGarrett D'Amore * When finding an open sub block, remember the last 77195c635efSGarrett D'Amore * open explicit block, or, in case there are only 77295c635efSGarrett D'Amore * implicit ones, the first open implicit block. 77395c635efSGarrett D'Amore */ 77495c635efSGarrett D'Amore if (later && 77595c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[later->tok].flags) 77695c635efSGarrett D'Amore continue; 777*698f87a4SGarrett D'Amore if (MDOC_It != n->tok) 77895c635efSGarrett D'Amore later = n; 77995c635efSGarrett D'Amore } 78095c635efSGarrett D'Amore 78195c635efSGarrett D'Amore if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { 78295c635efSGarrett D'Amore /* FIXME: do this in validate */ 78395c635efSGarrett D'Amore if (buf[*pos]) 784*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, MANDOCERR_ARGSLOST); 78595c635efSGarrett D'Amore 786*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) 78795c635efSGarrett D'Amore return(0); 788*698f87a4SGarrett D'Amore return(rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)); 78995c635efSGarrett D'Amore } 79095c635efSGarrett D'Amore 791*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) 79295c635efSGarrett D'Amore return(0); 79395c635efSGarrett D'Amore 79495c635efSGarrett D'Amore if (NULL == later && maxargs > 0) 795*698f87a4SGarrett D'Amore if ( ! mdoc_tail_alloc(mdoc, line, ppos, rew_alt(tok))) 79695c635efSGarrett D'Amore return(0); 79795c635efSGarrett D'Amore 79895c635efSGarrett D'Amore for (flushed = j = 0; ; j++) { 79995c635efSGarrett D'Amore lastarg = *pos; 80095c635efSGarrett D'Amore 80195c635efSGarrett D'Amore if (j == maxargs && ! flushed) { 802*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) 80395c635efSGarrett D'Amore return(0); 80495c635efSGarrett D'Amore flushed = 1; 80595c635efSGarrett D'Amore } 80695c635efSGarrett D'Amore 807*698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 80895c635efSGarrett D'Amore 80995c635efSGarrett D'Amore if (ARGS_ERROR == ac) 81095c635efSGarrett D'Amore return(0); 81195c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 81295c635efSGarrett D'Amore break; 81395c635efSGarrett D'Amore if (ARGS_EOLN == ac) 81495c635efSGarrett D'Amore break; 81595c635efSGarrett D'Amore 81695c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 81795c635efSGarrett D'Amore 81895c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 819*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, lastarg, p, DELIM_MAX, 820*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 82195c635efSGarrett D'Amore return(0); 82295c635efSGarrett D'Amore continue; 82395c635efSGarrett D'Amore } 82495c635efSGarrett D'Amore 82595c635efSGarrett D'Amore if ( ! flushed) { 826*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) 82795c635efSGarrett D'Amore return(0); 82895c635efSGarrett D'Amore flushed = 1; 82995c635efSGarrett D'Amore } 830*698f87a4SGarrett D'Amore 831*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_NEWLINE; 832*698f87a4SGarrett D'Amore 833*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, lastarg, pos, buf)) 83495c635efSGarrett D'Amore return(0); 83595c635efSGarrett D'Amore break; 83695c635efSGarrett D'Amore } 83795c635efSGarrett D'Amore 838*698f87a4SGarrett D'Amore if ( ! flushed && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) 83995c635efSGarrett D'Amore return(0); 84095c635efSGarrett D'Amore 84195c635efSGarrett D'Amore if ( ! nl) 84295c635efSGarrett D'Amore return(1); 843*698f87a4SGarrett D'Amore return(append_delims(mdoc, line, pos, buf)); 84495c635efSGarrett D'Amore } 84595c635efSGarrett D'Amore 84695c635efSGarrett D'Amore 84795c635efSGarrett D'Amore static int 84895c635efSGarrett D'Amore in_line(MACRO_PROT_ARGS) 84995c635efSGarrett D'Amore { 85095c635efSGarrett D'Amore int la, scope, cnt, nc, nl; 85195c635efSGarrett D'Amore enum margverr av; 85295c635efSGarrett D'Amore enum mdoct ntok; 85395c635efSGarrett D'Amore enum margserr ac; 85495c635efSGarrett D'Amore enum mdelim d; 85595c635efSGarrett D'Amore struct mdoc_arg *arg; 85695c635efSGarrett D'Amore char *p; 85795c635efSGarrett D'Amore 858*698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 85995c635efSGarrett D'Amore 86095c635efSGarrett D'Amore /* 86195c635efSGarrett D'Amore * Whether we allow ignored elements (those without content, 86295c635efSGarrett D'Amore * usually because of reserved words) to squeak by. 86395c635efSGarrett D'Amore */ 86495c635efSGarrett D'Amore 86595c635efSGarrett D'Amore switch (tok) { 86695c635efSGarrett D'Amore case (MDOC_An): 86795c635efSGarrett D'Amore /* FALLTHROUGH */ 86895c635efSGarrett D'Amore case (MDOC_Ar): 86995c635efSGarrett D'Amore /* FALLTHROUGH */ 87095c635efSGarrett D'Amore case (MDOC_Fl): 87195c635efSGarrett D'Amore /* FALLTHROUGH */ 87295c635efSGarrett D'Amore case (MDOC_Mt): 87395c635efSGarrett D'Amore /* FALLTHROUGH */ 87495c635efSGarrett D'Amore case (MDOC_Nm): 87595c635efSGarrett D'Amore /* FALLTHROUGH */ 87695c635efSGarrett D'Amore case (MDOC_Pa): 87795c635efSGarrett D'Amore nc = 1; 87895c635efSGarrett D'Amore break; 87995c635efSGarrett D'Amore default: 88095c635efSGarrett D'Amore nc = 0; 88195c635efSGarrett D'Amore break; 88295c635efSGarrett D'Amore } 88395c635efSGarrett D'Amore 88495c635efSGarrett D'Amore for (arg = NULL;; ) { 88595c635efSGarrett D'Amore la = *pos; 886*698f87a4SGarrett D'Amore av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); 88795c635efSGarrett D'Amore 88895c635efSGarrett D'Amore if (ARGV_WORD == av) { 88995c635efSGarrett D'Amore *pos = la; 89095c635efSGarrett D'Amore break; 89195c635efSGarrett D'Amore } 89295c635efSGarrett D'Amore if (ARGV_EOLN == av) 89395c635efSGarrett D'Amore break; 89495c635efSGarrett D'Amore if (ARGV_ARG == av) 89595c635efSGarrett D'Amore continue; 89695c635efSGarrett D'Amore 89795c635efSGarrett D'Amore mdoc_argv_free(arg); 89895c635efSGarrett D'Amore return(0); 89995c635efSGarrett D'Amore } 90095c635efSGarrett D'Amore 90195c635efSGarrett D'Amore for (cnt = scope = 0;; ) { 90295c635efSGarrett D'Amore la = *pos; 903*698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 90495c635efSGarrett D'Amore 90595c635efSGarrett D'Amore if (ARGS_ERROR == ac) 90695c635efSGarrett D'Amore return(0); 90795c635efSGarrett D'Amore if (ARGS_EOLN == ac) 90895c635efSGarrett D'Amore break; 90995c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 91095c635efSGarrett D'Amore break; 91195c635efSGarrett D'Amore 91295c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 91395c635efSGarrett D'Amore 91495c635efSGarrett D'Amore /* 91595c635efSGarrett D'Amore * In this case, we've located a submacro and must 91695c635efSGarrett D'Amore * execute it. Close out scope, if open. If no 91795c635efSGarrett D'Amore * elements have been generated, either create one (nc) 91895c635efSGarrett D'Amore * or raise a warning. 91995c635efSGarrett D'Amore */ 92095c635efSGarrett D'Amore 92195c635efSGarrett D'Amore if (MDOC_MAX != ntok) { 922*698f87a4SGarrett D'Amore if (scope && ! rew_elem(mdoc, tok)) 92395c635efSGarrett D'Amore return(0); 92495c635efSGarrett D'Amore if (nc && 0 == cnt) { 925*698f87a4SGarrett D'Amore if ( ! mdoc_elem_alloc(mdoc, line, 926*698f87a4SGarrett D'Amore ppos, tok, arg)) 92795c635efSGarrett D'Amore return(0); 928*698f87a4SGarrett D'Amore if ( ! rew_last(mdoc, mdoc->last)) 92995c635efSGarrett D'Amore return(0); 93095c635efSGarrett D'Amore } else if ( ! nc && 0 == cnt) { 93195c635efSGarrett D'Amore mdoc_argv_free(arg); 932*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, 933*698f87a4SGarrett D'Amore MANDOCERR_MACROEMPTY); 93495c635efSGarrett D'Amore } 93595c635efSGarrett D'Amore 936*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) 93795c635efSGarrett D'Amore return(0); 93895c635efSGarrett D'Amore if ( ! nl) 93995c635efSGarrett D'Amore return(1); 940*698f87a4SGarrett D'Amore return(append_delims(mdoc, line, pos, buf)); 94195c635efSGarrett D'Amore } 94295c635efSGarrett D'Amore 94395c635efSGarrett D'Amore /* 94495c635efSGarrett D'Amore * Non-quote-enclosed punctuation. Set up our scope, if 94595c635efSGarrett D'Amore * a word; rewind the scope, if a delimiter; then append 94695c635efSGarrett D'Amore * the word. 94795c635efSGarrett D'Amore */ 94895c635efSGarrett D'Amore 94995c635efSGarrett D'Amore d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p); 95095c635efSGarrett D'Amore 95195c635efSGarrett D'Amore if (DELIM_NONE != d) { 95295c635efSGarrett D'Amore /* 95395c635efSGarrett D'Amore * If we encounter closing punctuation, no word 95495c635efSGarrett D'Amore * has been omitted, no scope is open, and we're 95595c635efSGarrett D'Amore * allowed to have an empty element, then start 95695c635efSGarrett D'Amore * a new scope. `Ar', `Fl', and `Li', only do 95795c635efSGarrett D'Amore * this once per invocation. There may be more 95895c635efSGarrett D'Amore * of these (all of them?). 95995c635efSGarrett D'Amore */ 96095c635efSGarrett D'Amore if (0 == cnt && (nc || MDOC_Li == tok) && 96195c635efSGarrett D'Amore DELIM_CLOSE == d && ! scope) { 962*698f87a4SGarrett D'Amore if ( ! mdoc_elem_alloc(mdoc, line, 963*698f87a4SGarrett D'Amore ppos, tok, arg)) 96495c635efSGarrett D'Amore return(0); 96595c635efSGarrett D'Amore if (MDOC_Ar == tok || MDOC_Li == tok || 96695c635efSGarrett D'Amore MDOC_Fl == tok) 96795c635efSGarrett D'Amore cnt++; 96895c635efSGarrett D'Amore scope = 1; 96995c635efSGarrett D'Amore } 97095c635efSGarrett D'Amore /* 97195c635efSGarrett D'Amore * Close out our scope, if one is open, before 97295c635efSGarrett D'Amore * any punctuation. 97395c635efSGarrett D'Amore */ 974*698f87a4SGarrett D'Amore if (scope && ! rew_elem(mdoc, tok)) 97595c635efSGarrett D'Amore return(0); 97695c635efSGarrett D'Amore scope = 0; 97795c635efSGarrett D'Amore } else if ( ! scope) { 978*698f87a4SGarrett D'Amore if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) 97995c635efSGarrett D'Amore return(0); 98095c635efSGarrett D'Amore scope = 1; 98195c635efSGarrett D'Amore } 98295c635efSGarrett D'Amore 98395c635efSGarrett D'Amore if (DELIM_NONE == d) 98495c635efSGarrett D'Amore cnt++; 98595c635efSGarrett D'Amore 986*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, d, 987*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 98895c635efSGarrett D'Amore return(0); 98995c635efSGarrett D'Amore 99095c635efSGarrett D'Amore /* 99195c635efSGarrett D'Amore * `Fl' macros have their scope re-opened with each new 99295c635efSGarrett D'Amore * word so that the `-' can be added to each one without 99395c635efSGarrett D'Amore * having to parse out spaces. 99495c635efSGarrett D'Amore */ 99595c635efSGarrett D'Amore if (scope && MDOC_Fl == tok) { 996*698f87a4SGarrett D'Amore if ( ! rew_elem(mdoc, tok)) 99795c635efSGarrett D'Amore return(0); 99895c635efSGarrett D'Amore scope = 0; 99995c635efSGarrett D'Amore } 100095c635efSGarrett D'Amore } 100195c635efSGarrett D'Amore 1002*698f87a4SGarrett D'Amore if (scope && ! rew_elem(mdoc, tok)) 100395c635efSGarrett D'Amore return(0); 100495c635efSGarrett D'Amore 100595c635efSGarrett D'Amore /* 100695c635efSGarrett D'Amore * If no elements have been collected and we're allowed to have 100795c635efSGarrett D'Amore * empties (nc), open a scope and close it out. Otherwise, 100895c635efSGarrett D'Amore * raise a warning. 100995c635efSGarrett D'Amore */ 101095c635efSGarrett D'Amore 101195c635efSGarrett D'Amore if (nc && 0 == cnt) { 1012*698f87a4SGarrett D'Amore if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) 101395c635efSGarrett D'Amore return(0); 1014*698f87a4SGarrett D'Amore if ( ! rew_last(mdoc, mdoc->last)) 101595c635efSGarrett D'Amore return(0); 101695c635efSGarrett D'Amore } else if ( ! nc && 0 == cnt) { 101795c635efSGarrett D'Amore mdoc_argv_free(arg); 1018*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROEMPTY); 101995c635efSGarrett D'Amore } 102095c635efSGarrett D'Amore 102195c635efSGarrett D'Amore if ( ! nl) 102295c635efSGarrett D'Amore return(1); 1023*698f87a4SGarrett D'Amore return(append_delims(mdoc, line, pos, buf)); 102495c635efSGarrett D'Amore } 102595c635efSGarrett D'Amore 102695c635efSGarrett D'Amore 102795c635efSGarrett D'Amore static int 102895c635efSGarrett D'Amore blk_full(MACRO_PROT_ARGS) 102995c635efSGarrett D'Amore { 103095c635efSGarrett D'Amore int la, nl, nparsed; 103195c635efSGarrett D'Amore struct mdoc_arg *arg; 103295c635efSGarrett D'Amore struct mdoc_node *head; /* save of head macro */ 103395c635efSGarrett D'Amore struct mdoc_node *body; /* save of body macro */ 103495c635efSGarrett D'Amore struct mdoc_node *n; 103595c635efSGarrett D'Amore enum mdoc_type mtt; 103695c635efSGarrett D'Amore enum mdoct ntok; 103795c635efSGarrett D'Amore enum margserr ac, lac; 103895c635efSGarrett D'Amore enum margverr av; 103995c635efSGarrett D'Amore char *p; 104095c635efSGarrett D'Amore 1041*698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 104295c635efSGarrett D'Amore 104395c635efSGarrett D'Amore /* Close out prior implicit scope. */ 104495c635efSGarrett D'Amore 104595c635efSGarrett D'Amore if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) { 1046*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) 104795c635efSGarrett D'Amore return(0); 1048*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) 104995c635efSGarrett D'Amore return(0); 105095c635efSGarrett D'Amore } 105195c635efSGarrett D'Amore 105295c635efSGarrett D'Amore /* 105395c635efSGarrett D'Amore * This routine accommodates implicitly- and explicitly-scoped 105495c635efSGarrett D'Amore * macro openings. Implicit ones first close out prior scope 105595c635efSGarrett D'Amore * (seen above). Delay opening the head until necessary to 105695c635efSGarrett D'Amore * allow leading punctuation to print. Special consideration 105795c635efSGarrett D'Amore * for `It -column', which has phrase-part syntax instead of 105895c635efSGarrett D'Amore * regular child nodes. 105995c635efSGarrett D'Amore */ 106095c635efSGarrett D'Amore 106195c635efSGarrett D'Amore for (arg = NULL;; ) { 106295c635efSGarrett D'Amore la = *pos; 1063*698f87a4SGarrett D'Amore av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); 106495c635efSGarrett D'Amore 106595c635efSGarrett D'Amore if (ARGV_WORD == av) { 106695c635efSGarrett D'Amore *pos = la; 106795c635efSGarrett D'Amore break; 106895c635efSGarrett D'Amore } 106995c635efSGarrett D'Amore 107095c635efSGarrett D'Amore if (ARGV_EOLN == av) 107195c635efSGarrett D'Amore break; 107295c635efSGarrett D'Amore if (ARGV_ARG == av) 107395c635efSGarrett D'Amore continue; 107495c635efSGarrett D'Amore 107595c635efSGarrett D'Amore mdoc_argv_free(arg); 107695c635efSGarrett D'Amore return(0); 107795c635efSGarrett D'Amore } 107895c635efSGarrett D'Amore 1079*698f87a4SGarrett D'Amore if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg)) 108095c635efSGarrett D'Amore return(0); 108195c635efSGarrett D'Amore 108295c635efSGarrett D'Amore head = body = NULL; 108395c635efSGarrett D'Amore 108495c635efSGarrett D'Amore /* 108595c635efSGarrett D'Amore * Exception: Heads of `It' macros in `-diag' lists are not 108695c635efSGarrett D'Amore * parsed, even though `It' macros in general are parsed. 108795c635efSGarrett D'Amore */ 108895c635efSGarrett D'Amore nparsed = MDOC_It == tok && 1089*698f87a4SGarrett D'Amore MDOC_Bl == mdoc->last->parent->tok && 1090*698f87a4SGarrett D'Amore LIST_diag == mdoc->last->parent->norm->Bl.type; 109195c635efSGarrett D'Amore 109295c635efSGarrett D'Amore /* 109395c635efSGarrett D'Amore * The `Nd' macro has all arguments in its body: it's a hybrid 109495c635efSGarrett D'Amore * of block partial-explicit and full-implicit. Stupid. 109595c635efSGarrett D'Amore */ 109695c635efSGarrett D'Amore 109795c635efSGarrett D'Amore if (MDOC_Nd == tok) { 1098*698f87a4SGarrett D'Amore if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) 109995c635efSGarrett D'Amore return(0); 1100*698f87a4SGarrett D'Amore head = mdoc->last; 1101*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) 110295c635efSGarrett D'Amore return(0); 1103*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 110495c635efSGarrett D'Amore return(0); 1105*698f87a4SGarrett D'Amore body = mdoc->last; 110695c635efSGarrett D'Amore } 110795c635efSGarrett D'Amore 1108*698f87a4SGarrett D'Amore if (MDOC_Bk == tok) 1109*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_KEEP; 1110*698f87a4SGarrett D'Amore 111195c635efSGarrett D'Amore ac = ARGS_ERROR; 111295c635efSGarrett D'Amore 111395c635efSGarrett D'Amore for ( ; ; ) { 111495c635efSGarrett D'Amore la = *pos; 111595c635efSGarrett D'Amore /* Initialise last-phrase-type with ARGS_PEND. */ 111695c635efSGarrett D'Amore lac = ARGS_ERROR == ac ? ARGS_PEND : ac; 1117*698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 111895c635efSGarrett D'Amore 111995c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 112095c635efSGarrett D'Amore break; 112195c635efSGarrett D'Amore 112295c635efSGarrett D'Amore if (ARGS_ERROR == ac) 112395c635efSGarrett D'Amore return(0); 112495c635efSGarrett D'Amore 112595c635efSGarrett D'Amore if (ARGS_EOLN == ac) { 112695c635efSGarrett D'Amore if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac) 112795c635efSGarrett D'Amore break; 112895c635efSGarrett D'Amore /* 112995c635efSGarrett D'Amore * This is necessary: if the last token on a 113095c635efSGarrett D'Amore * line is a `Ta' or tab, then we'll get 113195c635efSGarrett D'Amore * ARGS_EOLN, so we must be smart enough to 113295c635efSGarrett D'Amore * reopen our scope if the last parse was a 113395c635efSGarrett D'Amore * phrase or partial phrase. 113495c635efSGarrett D'Amore */ 1135*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) 113695c635efSGarrett D'Amore return(0); 1137*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 113895c635efSGarrett D'Amore return(0); 1139*698f87a4SGarrett D'Amore body = mdoc->last; 114095c635efSGarrett D'Amore break; 114195c635efSGarrett D'Amore } 114295c635efSGarrett D'Amore 114395c635efSGarrett D'Amore /* 114495c635efSGarrett D'Amore * Emit leading punctuation (i.e., punctuation before 114595c635efSGarrett D'Amore * the MDOC_HEAD) for non-phrase types. 114695c635efSGarrett D'Amore */ 114795c635efSGarrett D'Amore 114895c635efSGarrett D'Amore if (NULL == head && 114995c635efSGarrett D'Amore ARGS_PEND != ac && 115095c635efSGarrett D'Amore ARGS_PHRASE != ac && 115195c635efSGarrett D'Amore ARGS_PPHRASE != ac && 115295c635efSGarrett D'Amore ARGS_QWORD != ac && 115395c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 1154*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) 115595c635efSGarrett D'Amore return(0); 115695c635efSGarrett D'Amore continue; 115795c635efSGarrett D'Amore } 115895c635efSGarrett D'Amore 115995c635efSGarrett D'Amore /* Open a head if one hasn't been opened. */ 116095c635efSGarrett D'Amore 116195c635efSGarrett D'Amore if (NULL == head) { 1162*698f87a4SGarrett D'Amore if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) 116395c635efSGarrett D'Amore return(0); 1164*698f87a4SGarrett D'Amore head = mdoc->last; 116595c635efSGarrett D'Amore } 116695c635efSGarrett D'Amore 116795c635efSGarrett D'Amore if (ARGS_PHRASE == ac || 116895c635efSGarrett D'Amore ARGS_PEND == ac || 116995c635efSGarrett D'Amore ARGS_PPHRASE == ac) { 117095c635efSGarrett D'Amore /* 117195c635efSGarrett D'Amore * If we haven't opened a body yet, rewind the 117295c635efSGarrett D'Amore * head; if we have, rewind that instead. 117395c635efSGarrett D'Amore */ 117495c635efSGarrett D'Amore 117595c635efSGarrett D'Amore mtt = body ? MDOC_BODY : MDOC_HEAD; 1176*698f87a4SGarrett D'Amore if ( ! rew_sub(mtt, mdoc, tok, line, ppos)) 117795c635efSGarrett D'Amore return(0); 117895c635efSGarrett D'Amore 117995c635efSGarrett D'Amore /* Then allocate our body context. */ 118095c635efSGarrett D'Amore 1181*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 118295c635efSGarrett D'Amore return(0); 1183*698f87a4SGarrett D'Amore body = mdoc->last; 118495c635efSGarrett D'Amore 118595c635efSGarrett D'Amore /* 118695c635efSGarrett D'Amore * Process phrases: set whether we're in a 118795c635efSGarrett D'Amore * partial-phrase (this effects line handling) 118895c635efSGarrett D'Amore * then call down into the phrase parser. 118995c635efSGarrett D'Amore */ 119095c635efSGarrett D'Amore 119195c635efSGarrett D'Amore if (ARGS_PPHRASE == ac) 1192*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_PPHRASE; 119395c635efSGarrett D'Amore if (ARGS_PEND == ac && ARGS_PPHRASE == lac) 1194*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_PPHRASE; 119595c635efSGarrett D'Amore 1196*698f87a4SGarrett D'Amore if ( ! phrase(mdoc, line, la, buf)) 119795c635efSGarrett D'Amore return(0); 119895c635efSGarrett D'Amore 1199*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_PPHRASE; 120095c635efSGarrett D'Amore continue; 120195c635efSGarrett D'Amore } 120295c635efSGarrett D'Amore 120395c635efSGarrett D'Amore ntok = nparsed || ARGS_QWORD == ac ? 120495c635efSGarrett D'Amore MDOC_MAX : lookup(tok, p); 120595c635efSGarrett D'Amore 120695c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1207*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1208*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 120995c635efSGarrett D'Amore return(0); 121095c635efSGarrett D'Amore continue; 121195c635efSGarrett D'Amore } 121295c635efSGarrett D'Amore 1213*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) 121495c635efSGarrett D'Amore return(0); 121595c635efSGarrett D'Amore break; 121695c635efSGarrett D'Amore } 121795c635efSGarrett D'Amore 121895c635efSGarrett D'Amore if (NULL == head) { 1219*698f87a4SGarrett D'Amore if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) 122095c635efSGarrett D'Amore return(0); 1221*698f87a4SGarrett D'Amore head = mdoc->last; 122295c635efSGarrett D'Amore } 122395c635efSGarrett D'Amore 1224*698f87a4SGarrett D'Amore if (nl && ! append_delims(mdoc, line, pos, buf)) 122595c635efSGarrett D'Amore return(0); 122695c635efSGarrett D'Amore 122795c635efSGarrett D'Amore /* If we've already opened our body, exit now. */ 122895c635efSGarrett D'Amore 122995c635efSGarrett D'Amore if (NULL != body) 123095c635efSGarrett D'Amore goto out; 123195c635efSGarrett D'Amore 123295c635efSGarrett D'Amore /* 123395c635efSGarrett D'Amore * If there is an open (i.e., unvalidated) sub-block requiring 123495c635efSGarrett D'Amore * explicit close-out, postpone switching the current block from 123595c635efSGarrett D'Amore * head to body until the rew_sub() call closing out that 123695c635efSGarrett D'Amore * sub-block. 123795c635efSGarrett D'Amore */ 1238*698f87a4SGarrett D'Amore for (n = mdoc->last; n && n != head; n = n->parent) { 123995c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && 124095c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[n->tok].flags && 124195c635efSGarrett D'Amore ! (MDOC_VALID & n->flags)) { 124295c635efSGarrett D'Amore n->pending = head; 124395c635efSGarrett D'Amore return(1); 124495c635efSGarrett D'Amore } 124595c635efSGarrett D'Amore } 124695c635efSGarrett D'Amore 124795c635efSGarrett D'Amore /* Close out scopes to remain in a consistent state. */ 124895c635efSGarrett D'Amore 1249*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) 125095c635efSGarrett D'Amore return(0); 1251*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 125295c635efSGarrett D'Amore return(0); 125395c635efSGarrett D'Amore 125495c635efSGarrett D'Amore out: 1255*698f87a4SGarrett D'Amore if ( ! (MDOC_FREECOL & mdoc->flags)) 125695c635efSGarrett D'Amore return(1); 125795c635efSGarrett D'Amore 1258*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) 125995c635efSGarrett D'Amore return(0); 1260*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) 126195c635efSGarrett D'Amore return(0); 126295c635efSGarrett D'Amore 1263*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_FREECOL; 126495c635efSGarrett D'Amore return(1); 126595c635efSGarrett D'Amore } 126695c635efSGarrett D'Amore 126795c635efSGarrett D'Amore 126895c635efSGarrett D'Amore static int 126995c635efSGarrett D'Amore blk_part_imp(MACRO_PROT_ARGS) 127095c635efSGarrett D'Amore { 127195c635efSGarrett D'Amore int la, nl; 127295c635efSGarrett D'Amore enum mdoct ntok; 127395c635efSGarrett D'Amore enum margserr ac; 127495c635efSGarrett D'Amore char *p; 127595c635efSGarrett D'Amore struct mdoc_node *blk; /* saved block context */ 127695c635efSGarrett D'Amore struct mdoc_node *body; /* saved body context */ 127795c635efSGarrett D'Amore struct mdoc_node *n; 127895c635efSGarrett D'Amore 1279*698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 128095c635efSGarrett D'Amore 128195c635efSGarrett D'Amore /* 128295c635efSGarrett D'Amore * A macro that spans to the end of the line. This is generally 128395c635efSGarrett D'Amore * (but not necessarily) called as the first macro. The block 128495c635efSGarrett D'Amore * has a head as the immediate child, which is always empty, 128595c635efSGarrett D'Amore * followed by zero or more opening punctuation nodes, then the 128695c635efSGarrett D'Amore * body (which may be empty, depending on the macro), then zero 128795c635efSGarrett D'Amore * or more closing punctuation nodes. 128895c635efSGarrett D'Amore */ 128995c635efSGarrett D'Amore 1290*698f87a4SGarrett D'Amore if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) 129195c635efSGarrett D'Amore return(0); 129295c635efSGarrett D'Amore 1293*698f87a4SGarrett D'Amore blk = mdoc->last; 129495c635efSGarrett D'Amore 1295*698f87a4SGarrett D'Amore if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) 129695c635efSGarrett D'Amore return(0); 1297*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) 129895c635efSGarrett D'Amore return(0); 129995c635efSGarrett D'Amore 130095c635efSGarrett D'Amore /* 130195c635efSGarrett D'Amore * Open the body scope "on-demand", that is, after we've 130295c635efSGarrett D'Amore * processed all our the leading delimiters (open parenthesis, 130395c635efSGarrett D'Amore * etc.). 130495c635efSGarrett D'Amore */ 130595c635efSGarrett D'Amore 130695c635efSGarrett D'Amore for (body = NULL; ; ) { 130795c635efSGarrett D'Amore la = *pos; 1308*698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 130995c635efSGarrett D'Amore 131095c635efSGarrett D'Amore if (ARGS_ERROR == ac) 131195c635efSGarrett D'Amore return(0); 131295c635efSGarrett D'Amore if (ARGS_EOLN == ac) 131395c635efSGarrett D'Amore break; 131495c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 131595c635efSGarrett D'Amore break; 131695c635efSGarrett D'Amore 131795c635efSGarrett D'Amore if (NULL == body && ARGS_QWORD != ac && 131895c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 1319*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) 132095c635efSGarrett D'Amore return(0); 132195c635efSGarrett D'Amore continue; 132295c635efSGarrett D'Amore } 132395c635efSGarrett D'Amore 132495c635efSGarrett D'Amore if (NULL == body) { 1325*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 132695c635efSGarrett D'Amore return(0); 1327*698f87a4SGarrett D'Amore body = mdoc->last; 132895c635efSGarrett D'Amore } 132995c635efSGarrett D'Amore 133095c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 133195c635efSGarrett D'Amore 133295c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1333*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1334*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 133595c635efSGarrett D'Amore return(0); 133695c635efSGarrett D'Amore continue; 133795c635efSGarrett D'Amore } 133895c635efSGarrett D'Amore 1339*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) 134095c635efSGarrett D'Amore return(0); 134195c635efSGarrett D'Amore break; 134295c635efSGarrett D'Amore } 134395c635efSGarrett D'Amore 134495c635efSGarrett D'Amore /* Clean-ups to leave in a consistent state. */ 134595c635efSGarrett D'Amore 134695c635efSGarrett D'Amore if (NULL == body) { 1347*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 134895c635efSGarrett D'Amore return(0); 1349*698f87a4SGarrett D'Amore body = mdoc->last; 135095c635efSGarrett D'Amore } 135195c635efSGarrett D'Amore 135295c635efSGarrett D'Amore for (n = body->child; n && n->next; n = n->next) 135395c635efSGarrett D'Amore /* Do nothing. */ ; 135495c635efSGarrett D'Amore 135595c635efSGarrett D'Amore /* 135695c635efSGarrett D'Amore * End of sentence spacing: if the last node is a text node and 135795c635efSGarrett D'Amore * has a trailing period, then mark it as being end-of-sentence. 135895c635efSGarrett D'Amore */ 135995c635efSGarrett D'Amore 136095c635efSGarrett D'Amore if (n && MDOC_TEXT == n->type && n->string) 136195c635efSGarrett D'Amore if (mandoc_eos(n->string, strlen(n->string), 1)) 136295c635efSGarrett D'Amore n->flags |= MDOC_EOS; 136395c635efSGarrett D'Amore 136495c635efSGarrett D'Amore /* Up-propagate the end-of-space flag. */ 136595c635efSGarrett D'Amore 136695c635efSGarrett D'Amore if (n && (MDOC_EOS & n->flags)) { 136795c635efSGarrett D'Amore body->flags |= MDOC_EOS; 136895c635efSGarrett D'Amore body->parent->flags |= MDOC_EOS; 136995c635efSGarrett D'Amore } 137095c635efSGarrett D'Amore 137195c635efSGarrett D'Amore /* 137295c635efSGarrett D'Amore * If there is an open sub-block requiring explicit close-out, 137395c635efSGarrett D'Amore * postpone closing out the current block 137495c635efSGarrett D'Amore * until the rew_sub() call closing out the sub-block. 137595c635efSGarrett D'Amore */ 1376*698f87a4SGarrett D'Amore for (n = mdoc->last; n && n != body && n != blk->parent; 1377*698f87a4SGarrett D'Amore n = n->parent) { 137895c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && 137995c635efSGarrett D'Amore MDOC_EXPLICIT & mdoc_macros[n->tok].flags && 138095c635efSGarrett D'Amore ! (MDOC_VALID & n->flags)) { 1381*698f87a4SGarrett D'Amore make_pending(n, tok, mdoc, line, ppos); 1382*698f87a4SGarrett D'Amore if ( ! mdoc_endbody_alloc(mdoc, line, ppos, 138395c635efSGarrett D'Amore tok, body, ENDBODY_NOSPACE)) 138495c635efSGarrett D'Amore return(0); 138595c635efSGarrett D'Amore return(1); 138695c635efSGarrett D'Amore } 138795c635efSGarrett D'Amore } 138895c635efSGarrett D'Amore 138995c635efSGarrett D'Amore /* 139095c635efSGarrett D'Amore * If we can't rewind to our body, then our scope has already 139195c635efSGarrett D'Amore * been closed by another macro (like `Oc' closing `Op'). This 139295c635efSGarrett D'Amore * is ugly behaviour nodding its head to OpenBSD's overwhelming 139395c635efSGarrett D'Amore * crufty use of `Op' breakage. 139495c635efSGarrett D'Amore */ 139595c635efSGarrett D'Amore if (n != body) 1396*698f87a4SGarrett D'Amore mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos, 139795c635efSGarrett D'Amore "%s broken", mdoc_macronames[tok]); 139895c635efSGarrett D'Amore 1399*698f87a4SGarrett D'Amore if (n && ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) 140095c635efSGarrett D'Amore return(0); 140195c635efSGarrett D'Amore 140295c635efSGarrett D'Amore /* Standard appending of delimiters. */ 140395c635efSGarrett D'Amore 1404*698f87a4SGarrett D'Amore if (nl && ! append_delims(mdoc, line, pos, buf)) 140595c635efSGarrett D'Amore return(0); 140695c635efSGarrett D'Amore 140795c635efSGarrett D'Amore /* Rewind scope, if applicable. */ 140895c635efSGarrett D'Amore 1409*698f87a4SGarrett D'Amore if (n && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) 141095c635efSGarrett D'Amore return(0); 141195c635efSGarrett D'Amore 1412*698f87a4SGarrett D'Amore /* Move trailing .Ns out of scope. */ 1413*698f87a4SGarrett D'Amore 1414*698f87a4SGarrett D'Amore for (n = body->child; n && n->next; n = n->next) 1415*698f87a4SGarrett D'Amore /* Do nothing. */ ; 1416*698f87a4SGarrett D'Amore if (n && MDOC_Ns == n->tok) 1417*698f87a4SGarrett D'Amore mdoc_node_relink(mdoc, n); 1418*698f87a4SGarrett D'Amore 141995c635efSGarrett D'Amore return(1); 142095c635efSGarrett D'Amore } 142195c635efSGarrett D'Amore 142295c635efSGarrett D'Amore 142395c635efSGarrett D'Amore static int 142495c635efSGarrett D'Amore blk_part_exp(MACRO_PROT_ARGS) 142595c635efSGarrett D'Amore { 142695c635efSGarrett D'Amore int la, nl; 142795c635efSGarrett D'Amore enum margserr ac; 142895c635efSGarrett D'Amore struct mdoc_node *head; /* keep track of head */ 142995c635efSGarrett D'Amore struct mdoc_node *body; /* keep track of body */ 143095c635efSGarrett D'Amore char *p; 143195c635efSGarrett D'Amore enum mdoct ntok; 143295c635efSGarrett D'Amore 1433*698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 143495c635efSGarrett D'Amore 143595c635efSGarrett D'Amore /* 143695c635efSGarrett D'Amore * The opening of an explicit macro having zero or more leading 143795c635efSGarrett D'Amore * punctuation nodes; a head with optional single element (the 143895c635efSGarrett D'Amore * case of `Eo'); and a body that may be empty. 143995c635efSGarrett D'Amore */ 144095c635efSGarrett D'Amore 1441*698f87a4SGarrett D'Amore if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) 144295c635efSGarrett D'Amore return(0); 144395c635efSGarrett D'Amore 144495c635efSGarrett D'Amore for (head = body = NULL; ; ) { 144595c635efSGarrett D'Amore la = *pos; 1446*698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 144795c635efSGarrett D'Amore 144895c635efSGarrett D'Amore if (ARGS_ERROR == ac) 144995c635efSGarrett D'Amore return(0); 145095c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 145195c635efSGarrett D'Amore break; 145295c635efSGarrett D'Amore if (ARGS_EOLN == ac) 145395c635efSGarrett D'Amore break; 145495c635efSGarrett D'Amore 145595c635efSGarrett D'Amore /* Flush out leading punctuation. */ 145695c635efSGarrett D'Amore 145795c635efSGarrett D'Amore if (NULL == head && ARGS_QWORD != ac && 145895c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 145995c635efSGarrett D'Amore assert(NULL == body); 1460*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) 146195c635efSGarrett D'Amore return(0); 146295c635efSGarrett D'Amore continue; 146395c635efSGarrett D'Amore } 146495c635efSGarrett D'Amore 146595c635efSGarrett D'Amore if (NULL == head) { 146695c635efSGarrett D'Amore assert(NULL == body); 1467*698f87a4SGarrett D'Amore if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) 146895c635efSGarrett D'Amore return(0); 1469*698f87a4SGarrett D'Amore head = mdoc->last; 147095c635efSGarrett D'Amore } 147195c635efSGarrett D'Amore 147295c635efSGarrett D'Amore /* 147395c635efSGarrett D'Amore * `Eo' gobbles any data into the head, but most other 147495c635efSGarrett D'Amore * macros just immediately close out and begin the body. 147595c635efSGarrett D'Amore */ 147695c635efSGarrett D'Amore 147795c635efSGarrett D'Amore if (NULL == body) { 147895c635efSGarrett D'Amore assert(head); 147995c635efSGarrett D'Amore /* No check whether it's a macro! */ 148095c635efSGarrett D'Amore if (MDOC_Eo == tok) 1481*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 0)) 148295c635efSGarrett D'Amore return(0); 148395c635efSGarrett D'Amore 1484*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) 148595c635efSGarrett D'Amore return(0); 1486*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 148795c635efSGarrett D'Amore return(0); 1488*698f87a4SGarrett D'Amore body = mdoc->last; 148995c635efSGarrett D'Amore 149095c635efSGarrett D'Amore if (MDOC_Eo == tok) 149195c635efSGarrett D'Amore continue; 149295c635efSGarrett D'Amore } 149395c635efSGarrett D'Amore 149495c635efSGarrett D'Amore assert(NULL != head && NULL != body); 149595c635efSGarrett D'Amore 149695c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 149795c635efSGarrett D'Amore 149895c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1499*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1500*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 150195c635efSGarrett D'Amore return(0); 150295c635efSGarrett D'Amore continue; 150395c635efSGarrett D'Amore } 150495c635efSGarrett D'Amore 1505*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) 150695c635efSGarrett D'Amore return(0); 150795c635efSGarrett D'Amore break; 150895c635efSGarrett D'Amore } 150995c635efSGarrett D'Amore 151095c635efSGarrett D'Amore /* Clean-up to leave in a consistent state. */ 151195c635efSGarrett D'Amore 151295c635efSGarrett D'Amore if (NULL == head) 1513*698f87a4SGarrett D'Amore if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) 151495c635efSGarrett D'Amore return(0); 151595c635efSGarrett D'Amore 151695c635efSGarrett D'Amore if (NULL == body) { 1517*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) 151895c635efSGarrett D'Amore return(0); 1519*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) 152095c635efSGarrett D'Amore return(0); 152195c635efSGarrett D'Amore } 152295c635efSGarrett D'Amore 152395c635efSGarrett D'Amore /* Standard appending of delimiters. */ 152495c635efSGarrett D'Amore 152595c635efSGarrett D'Amore if ( ! nl) 152695c635efSGarrett D'Amore return(1); 1527*698f87a4SGarrett D'Amore return(append_delims(mdoc, line, pos, buf)); 152895c635efSGarrett D'Amore } 152995c635efSGarrett D'Amore 153095c635efSGarrett D'Amore 153195c635efSGarrett D'Amore /* ARGSUSED */ 153295c635efSGarrett D'Amore static int 153395c635efSGarrett D'Amore in_line_argn(MACRO_PROT_ARGS) 153495c635efSGarrett D'Amore { 153595c635efSGarrett D'Amore int la, flushed, j, maxargs, nl; 153695c635efSGarrett D'Amore enum margserr ac; 153795c635efSGarrett D'Amore enum margverr av; 153895c635efSGarrett D'Amore struct mdoc_arg *arg; 153995c635efSGarrett D'Amore char *p; 154095c635efSGarrett D'Amore enum mdoct ntok; 154195c635efSGarrett D'Amore 1542*698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 154395c635efSGarrett D'Amore 154495c635efSGarrett D'Amore /* 154595c635efSGarrett D'Amore * A line macro that has a fixed number of arguments (maxargs). 154695c635efSGarrett D'Amore * Only open the scope once the first non-leading-punctuation is 154795c635efSGarrett D'Amore * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then 154895c635efSGarrett D'Amore * keep it open until the maximum number of arguments are 154995c635efSGarrett D'Amore * exhausted. 155095c635efSGarrett D'Amore */ 155195c635efSGarrett D'Amore 155295c635efSGarrett D'Amore switch (tok) { 155395c635efSGarrett D'Amore case (MDOC_Ap): 155495c635efSGarrett D'Amore /* FALLTHROUGH */ 155595c635efSGarrett D'Amore case (MDOC_No): 155695c635efSGarrett D'Amore /* FALLTHROUGH */ 155795c635efSGarrett D'Amore case (MDOC_Ns): 155895c635efSGarrett D'Amore /* FALLTHROUGH */ 155995c635efSGarrett D'Amore case (MDOC_Ux): 156095c635efSGarrett D'Amore maxargs = 0; 156195c635efSGarrett D'Amore break; 156295c635efSGarrett D'Amore case (MDOC_Bx): 156395c635efSGarrett D'Amore /* FALLTHROUGH */ 156495c635efSGarrett D'Amore case (MDOC_Xr): 156595c635efSGarrett D'Amore maxargs = 2; 156695c635efSGarrett D'Amore break; 156795c635efSGarrett D'Amore default: 156895c635efSGarrett D'Amore maxargs = 1; 156995c635efSGarrett D'Amore break; 157095c635efSGarrett D'Amore } 157195c635efSGarrett D'Amore 157295c635efSGarrett D'Amore for (arg = NULL; ; ) { 157395c635efSGarrett D'Amore la = *pos; 1574*698f87a4SGarrett D'Amore av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); 157595c635efSGarrett D'Amore 157695c635efSGarrett D'Amore if (ARGV_WORD == av) { 157795c635efSGarrett D'Amore *pos = la; 157895c635efSGarrett D'Amore break; 157995c635efSGarrett D'Amore } 158095c635efSGarrett D'Amore 158195c635efSGarrett D'Amore if (ARGV_EOLN == av) 158295c635efSGarrett D'Amore break; 158395c635efSGarrett D'Amore if (ARGV_ARG == av) 158495c635efSGarrett D'Amore continue; 158595c635efSGarrett D'Amore 158695c635efSGarrett D'Amore mdoc_argv_free(arg); 158795c635efSGarrett D'Amore return(0); 158895c635efSGarrett D'Amore } 158995c635efSGarrett D'Amore 159095c635efSGarrett D'Amore for (flushed = j = 0; ; ) { 159195c635efSGarrett D'Amore la = *pos; 1592*698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 159395c635efSGarrett D'Amore 159495c635efSGarrett D'Amore if (ARGS_ERROR == ac) 159595c635efSGarrett D'Amore return(0); 159695c635efSGarrett D'Amore if (ARGS_PUNCT == ac) 159795c635efSGarrett D'Amore break; 159895c635efSGarrett D'Amore if (ARGS_EOLN == ac) 159995c635efSGarrett D'Amore break; 160095c635efSGarrett D'Amore 160195c635efSGarrett D'Amore if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 160295c635efSGarrett D'Amore ARGS_QWORD != ac && 0 == j && 160395c635efSGarrett D'Amore DELIM_OPEN == mdoc_isdelim(p)) { 1604*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) 160595c635efSGarrett D'Amore return(0); 160695c635efSGarrett D'Amore continue; 160795c635efSGarrett D'Amore } else if (0 == j) 1608*698f87a4SGarrett D'Amore if ( ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) 160995c635efSGarrett D'Amore return(0); 161095c635efSGarrett D'Amore 161195c635efSGarrett D'Amore if (j == maxargs && ! flushed) { 1612*698f87a4SGarrett D'Amore if ( ! rew_elem(mdoc, tok)) 161395c635efSGarrett D'Amore return(0); 161495c635efSGarrett D'Amore flushed = 1; 161595c635efSGarrett D'Amore } 161695c635efSGarrett D'Amore 161795c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 161895c635efSGarrett D'Amore 161995c635efSGarrett D'Amore if (MDOC_MAX != ntok) { 1620*698f87a4SGarrett D'Amore if ( ! flushed && ! rew_elem(mdoc, tok)) 162195c635efSGarrett D'Amore return(0); 162295c635efSGarrett D'Amore flushed = 1; 1623*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) 162495c635efSGarrett D'Amore return(0); 162595c635efSGarrett D'Amore j++; 162695c635efSGarrett D'Amore break; 162795c635efSGarrett D'Amore } 162895c635efSGarrett D'Amore 162995c635efSGarrett D'Amore if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 163095c635efSGarrett D'Amore ARGS_QWORD != ac && 163195c635efSGarrett D'Amore ! flushed && 163295c635efSGarrett D'Amore DELIM_NONE != mdoc_isdelim(p)) { 1633*698f87a4SGarrett D'Amore if ( ! rew_elem(mdoc, tok)) 163495c635efSGarrett D'Amore return(0); 163595c635efSGarrett D'Amore flushed = 1; 163695c635efSGarrett D'Amore } 163795c635efSGarrett D'Amore 1638*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1639*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 164095c635efSGarrett D'Amore return(0); 164195c635efSGarrett D'Amore j++; 164295c635efSGarrett D'Amore } 164395c635efSGarrett D'Amore 1644*698f87a4SGarrett D'Amore if (0 == j && ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) 164595c635efSGarrett D'Amore return(0); 164695c635efSGarrett D'Amore 164795c635efSGarrett D'Amore /* Close out in a consistent state. */ 164895c635efSGarrett D'Amore 1649*698f87a4SGarrett D'Amore if ( ! flushed && ! rew_elem(mdoc, tok)) 165095c635efSGarrett D'Amore return(0); 165195c635efSGarrett D'Amore if ( ! nl) 165295c635efSGarrett D'Amore return(1); 1653*698f87a4SGarrett D'Amore return(append_delims(mdoc, line, pos, buf)); 165495c635efSGarrett D'Amore } 165595c635efSGarrett D'Amore 165695c635efSGarrett D'Amore 165795c635efSGarrett D'Amore static int 165895c635efSGarrett D'Amore in_line_eoln(MACRO_PROT_ARGS) 165995c635efSGarrett D'Amore { 166095c635efSGarrett D'Amore int la; 166195c635efSGarrett D'Amore enum margserr ac; 166295c635efSGarrett D'Amore enum margverr av; 166395c635efSGarrett D'Amore struct mdoc_arg *arg; 166495c635efSGarrett D'Amore char *p; 166595c635efSGarrett D'Amore enum mdoct ntok; 166695c635efSGarrett D'Amore 166795c635efSGarrett D'Amore assert( ! (MDOC_PARSED & mdoc_macros[tok].flags)); 166895c635efSGarrett D'Amore 166995c635efSGarrett D'Amore if (tok == MDOC_Pp) 1670*698f87a4SGarrett D'Amore rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos); 167195c635efSGarrett D'Amore 167295c635efSGarrett D'Amore /* Parse macro arguments. */ 167395c635efSGarrett D'Amore 167495c635efSGarrett D'Amore for (arg = NULL; ; ) { 167595c635efSGarrett D'Amore la = *pos; 1676*698f87a4SGarrett D'Amore av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); 167795c635efSGarrett D'Amore 167895c635efSGarrett D'Amore if (ARGV_WORD == av) { 167995c635efSGarrett D'Amore *pos = la; 168095c635efSGarrett D'Amore break; 168195c635efSGarrett D'Amore } 168295c635efSGarrett D'Amore if (ARGV_EOLN == av) 168395c635efSGarrett D'Amore break; 168495c635efSGarrett D'Amore if (ARGV_ARG == av) 168595c635efSGarrett D'Amore continue; 168695c635efSGarrett D'Amore 168795c635efSGarrett D'Amore mdoc_argv_free(arg); 168895c635efSGarrett D'Amore return(0); 168995c635efSGarrett D'Amore } 169095c635efSGarrett D'Amore 169195c635efSGarrett D'Amore /* Open element scope. */ 169295c635efSGarrett D'Amore 1693*698f87a4SGarrett D'Amore if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) 169495c635efSGarrett D'Amore return(0); 169595c635efSGarrett D'Amore 169695c635efSGarrett D'Amore /* Parse argument terms. */ 169795c635efSGarrett D'Amore 169895c635efSGarrett D'Amore for (;;) { 169995c635efSGarrett D'Amore la = *pos; 1700*698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 170195c635efSGarrett D'Amore 170295c635efSGarrett D'Amore if (ARGS_ERROR == ac) 170395c635efSGarrett D'Amore return(0); 170495c635efSGarrett D'Amore if (ARGS_EOLN == ac) 170595c635efSGarrett D'Amore break; 170695c635efSGarrett D'Amore 170795c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); 170895c635efSGarrett D'Amore 170995c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1710*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1711*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 171295c635efSGarrett D'Amore return(0); 171395c635efSGarrett D'Amore continue; 171495c635efSGarrett D'Amore } 171595c635efSGarrett D'Amore 1716*698f87a4SGarrett D'Amore if ( ! rew_elem(mdoc, tok)) 171795c635efSGarrett D'Amore return(0); 1718*698f87a4SGarrett D'Amore return(mdoc_macro(mdoc, ntok, line, la, pos, buf)); 171995c635efSGarrett D'Amore } 172095c635efSGarrett D'Amore 172195c635efSGarrett D'Amore /* Close out (no delimiters). */ 172295c635efSGarrett D'Amore 1723*698f87a4SGarrett D'Amore return(rew_elem(mdoc, tok)); 172495c635efSGarrett D'Amore } 172595c635efSGarrett D'Amore 172695c635efSGarrett D'Amore 172795c635efSGarrett D'Amore /* ARGSUSED */ 172895c635efSGarrett D'Amore static int 172995c635efSGarrett D'Amore ctx_synopsis(MACRO_PROT_ARGS) 173095c635efSGarrett D'Amore { 173195c635efSGarrett D'Amore int nl; 173295c635efSGarrett D'Amore 1733*698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 173495c635efSGarrett D'Amore 173595c635efSGarrett D'Amore /* If we're not in the SYNOPSIS, go straight to in-line. */ 1736*698f87a4SGarrett D'Amore if ( ! (MDOC_SYNOPSIS & mdoc->flags)) 1737*698f87a4SGarrett D'Amore return(in_line(mdoc, tok, line, ppos, pos, buf)); 173895c635efSGarrett D'Amore 173995c635efSGarrett D'Amore /* If we're a nested call, same place. */ 174095c635efSGarrett D'Amore if ( ! nl) 1741*698f87a4SGarrett D'Amore return(in_line(mdoc, tok, line, ppos, pos, buf)); 174295c635efSGarrett D'Amore 174395c635efSGarrett D'Amore /* 174495c635efSGarrett D'Amore * XXX: this will open a block scope; however, if later we end 174595c635efSGarrett D'Amore * up formatting the block scope, then child nodes will inherit 174695c635efSGarrett D'Amore * the formatting. Be careful. 174795c635efSGarrett D'Amore */ 174895c635efSGarrett D'Amore if (MDOC_Nm == tok) 1749*698f87a4SGarrett D'Amore return(blk_full(mdoc, tok, line, ppos, pos, buf)); 175095c635efSGarrett D'Amore assert(MDOC_Vt == tok); 1751*698f87a4SGarrett D'Amore return(blk_part_imp(mdoc, tok, line, ppos, pos, buf)); 175295c635efSGarrett D'Amore } 175395c635efSGarrett D'Amore 175495c635efSGarrett D'Amore 175595c635efSGarrett D'Amore /* ARGSUSED */ 175695c635efSGarrett D'Amore static int 175795c635efSGarrett D'Amore obsolete(MACRO_PROT_ARGS) 175895c635efSGarrett D'Amore { 175995c635efSGarrett D'Amore 1760*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROOBS); 176195c635efSGarrett D'Amore return(1); 176295c635efSGarrett D'Amore } 176395c635efSGarrett D'Amore 176495c635efSGarrett D'Amore 176595c635efSGarrett D'Amore /* 176695c635efSGarrett D'Amore * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs. 176795c635efSGarrett D'Amore * They're unusual because they're basically free-form text until a 176895c635efSGarrett D'Amore * macro is encountered. 176995c635efSGarrett D'Amore */ 177095c635efSGarrett D'Amore static int 1771*698f87a4SGarrett D'Amore phrase(struct mdoc *mdoc, int line, int ppos, char *buf) 177295c635efSGarrett D'Amore { 177395c635efSGarrett D'Amore int la, pos; 177495c635efSGarrett D'Amore enum margserr ac; 177595c635efSGarrett D'Amore enum mdoct ntok; 177695c635efSGarrett D'Amore char *p; 177795c635efSGarrett D'Amore 177895c635efSGarrett D'Amore for (pos = ppos; ; ) { 177995c635efSGarrett D'Amore la = pos; 178095c635efSGarrett D'Amore 1781*698f87a4SGarrett D'Amore ac = mdoc_zargs(mdoc, line, &pos, buf, &p); 178295c635efSGarrett D'Amore 178395c635efSGarrett D'Amore if (ARGS_ERROR == ac) 178495c635efSGarrett D'Amore return(0); 178595c635efSGarrett D'Amore if (ARGS_EOLN == ac) 178695c635efSGarrett D'Amore break; 178795c635efSGarrett D'Amore 178895c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); 178995c635efSGarrett D'Amore 179095c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1791*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1)) 179295c635efSGarrett D'Amore return(0); 179395c635efSGarrett D'Amore continue; 179495c635efSGarrett D'Amore } 179595c635efSGarrett D'Amore 1796*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, la, &pos, buf)) 179795c635efSGarrett D'Amore return(0); 1798*698f87a4SGarrett D'Amore return(append_delims(mdoc, line, &pos, buf)); 179995c635efSGarrett D'Amore } 180095c635efSGarrett D'Amore 180195c635efSGarrett D'Amore return(1); 180295c635efSGarrett D'Amore } 180395c635efSGarrett D'Amore 180495c635efSGarrett D'Amore 180595c635efSGarrett D'Amore /* ARGSUSED */ 180695c635efSGarrett D'Amore static int 180795c635efSGarrett D'Amore phrase_ta(MACRO_PROT_ARGS) 180895c635efSGarrett D'Amore { 1809*698f87a4SGarrett D'Amore struct mdoc_node *n; 181095c635efSGarrett D'Amore int la; 181195c635efSGarrett D'Amore enum mdoct ntok; 181295c635efSGarrett D'Amore enum margserr ac; 181395c635efSGarrett D'Amore char *p; 181495c635efSGarrett D'Amore 1815*698f87a4SGarrett D'Amore /* Make sure we are in a column list or ignore this macro. */ 1816*698f87a4SGarrett D'Amore n = mdoc->last; 1817*698f87a4SGarrett D'Amore while (NULL != n && MDOC_Bl != n->tok) 1818*698f87a4SGarrett D'Amore n = n->parent; 1819*698f87a4SGarrett D'Amore if (NULL == n || LIST_column != n->norm->Bl.type) { 1820*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, MANDOCERR_STRAYTA); 1821*698f87a4SGarrett D'Amore return(1); 1822*698f87a4SGarrett D'Amore } 182395c635efSGarrett D'Amore 1824*698f87a4SGarrett D'Amore /* Advance to the next column. */ 1825*698f87a4SGarrett D'Amore if ( ! rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos)) 182695c635efSGarrett D'Amore return(0); 1827*698f87a4SGarrett D'Amore if ( ! mdoc_body_alloc(mdoc, line, ppos, MDOC_It)) 182895c635efSGarrett D'Amore return(0); 182995c635efSGarrett D'Amore 183095c635efSGarrett D'Amore for (;;) { 183195c635efSGarrett D'Amore la = *pos; 1832*698f87a4SGarrett D'Amore ac = mdoc_zargs(mdoc, line, pos, buf, &p); 183395c635efSGarrett D'Amore 183495c635efSGarrett D'Amore if (ARGS_ERROR == ac) 183595c635efSGarrett D'Amore return(0); 183695c635efSGarrett D'Amore if (ARGS_EOLN == ac) 183795c635efSGarrett D'Amore break; 183895c635efSGarrett D'Amore 183995c635efSGarrett D'Amore ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); 184095c635efSGarrett D'Amore 184195c635efSGarrett D'Amore if (MDOC_MAX == ntok) { 1842*698f87a4SGarrett D'Amore if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1843*698f87a4SGarrett D'Amore MDOC_JOIN & mdoc_macros[tok].flags)) 184495c635efSGarrett D'Amore return(0); 184595c635efSGarrett D'Amore continue; 184695c635efSGarrett D'Amore } 184795c635efSGarrett D'Amore 1848*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) 184995c635efSGarrett D'Amore return(0); 1850*698f87a4SGarrett D'Amore return(append_delims(mdoc, line, pos, buf)); 185195c635efSGarrett D'Amore } 185295c635efSGarrett D'Amore 185395c635efSGarrett D'Amore return(1); 185495c635efSGarrett D'Amore } 1855