1*260e9a87SYuri Pankov /* $Id: mdoc_macro.c,v 1.183 2015/02/12 12:24:33 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*260e9a87SYuri Pankov * Copyright (c) 2010, 2012-2015 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 #include "config.h" 19*260e9a87SYuri Pankov 20*260e9a87SYuri Pankov #include <sys/types.h> 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 34*260e9a87SYuri Pankov static void blk_full(MACRO_PROT_ARGS); 35*260e9a87SYuri Pankov static void blk_exp_close(MACRO_PROT_ARGS); 36*260e9a87SYuri Pankov static void blk_part_exp(MACRO_PROT_ARGS); 37*260e9a87SYuri Pankov static void blk_part_imp(MACRO_PROT_ARGS); 38*260e9a87SYuri Pankov static void ctx_synopsis(MACRO_PROT_ARGS); 39*260e9a87SYuri Pankov static void in_line_eoln(MACRO_PROT_ARGS); 40*260e9a87SYuri Pankov static void in_line_argn(MACRO_PROT_ARGS); 41*260e9a87SYuri Pankov static void in_line(MACRO_PROT_ARGS); 42*260e9a87SYuri Pankov static void phrase_ta(MACRO_PROT_ARGS); 4395c635efSGarrett D'Amore 44*260e9a87SYuri Pankov static void dword(struct mdoc *, int, int, const char *, 45698f87a4SGarrett D'Amore enum mdelim, int); 46*260e9a87SYuri Pankov static void append_delims(struct mdoc *, int, int *, char *); 47*260e9a87SYuri Pankov static enum mdoct lookup(struct mdoc *, enum mdoct, 48*260e9a87SYuri Pankov int, int, const char *); 49*260e9a87SYuri Pankov static int macro_or_word(MACRO_PROT_ARGS, int); 50*260e9a87SYuri Pankov static int parse_rest(struct mdoc *, enum mdoct, 5195c635efSGarrett D'Amore int, int *, char *); 5295c635efSGarrett D'Amore static enum mdoct rew_alt(enum mdoct); 53*260e9a87SYuri Pankov static void rew_elem(struct mdoc *, enum mdoct); 54*260e9a87SYuri Pankov static void rew_last(struct mdoc *, const struct mdoc_node *); 55*260e9a87SYuri Pankov static void rew_pending(struct mdoc *, const struct mdoc_node *); 5695c635efSGarrett D'Amore 5795c635efSGarrett D'Amore const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { 58698f87a4SGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ 5995c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ 6095c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ 6195c635efSGarrett D'Amore { in_line_eoln, MDOC_PROLOGUE }, /* Os */ 62698f87a4SGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */ 63698f87a4SGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Ss */ 6495c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Pp */ 65698f87a4SGarrett D'Amore { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* D1 */ 66698f87a4SGarrett D'Amore { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* Dl */ 6795c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bd */ 68698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */ 6995c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bl */ 70698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* El */ 71698f87a4SGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */ 7295c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ 73698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */ 7495c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ 75*260e9a87SYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */ 7695c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ 7795c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ 7895c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ 7995c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ 8095c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Ex */ 8195c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ 8295c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Fd */ 8395c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */ 8495c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ 8595c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ 86*260e9a87SYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ic */ 8795c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ 88698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */ 89698f87a4SGarrett D'Amore { blk_full, MDOC_JOIN }, /* Nd */ 9095c635efSGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ 9195c635efSGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ 92*260e9a87SYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ot */ 9395c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ 9495c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Rv */ 9595c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ 9695c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */ 9795c635efSGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ 9895c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */ 99698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %A */ 100698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %B */ 101698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %D */ 102698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %I */ 103698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %J */ 10495c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %N */ 105698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %O */ 10695c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %P */ 107698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %R */ 108698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %T */ 10995c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %V */ 110698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 111698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Ac */ 112698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 113698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Ao */ 114698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Aq */ 11595c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */ 116698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 117698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Bc */ 11895c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bf */ 119698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 120698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Bo */ 121698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Bq */ 12295c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */ 12395c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */ 12495c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Db */ 125698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 126698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Dc */ 127698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 128698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Do */ 129698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Dq */ 130698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ec */ 131698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ef */ 132698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Em */ 13395c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */ 13495c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */ 13595c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */ 136*260e9a87SYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* No */ 137698f87a4SGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | 138698f87a4SGarrett D'Amore MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */ 13995c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ 14095c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */ 141698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 142698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Pc */ 14395c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */ 144698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 145698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Po */ 146698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Pq */ 147698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 148698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Qc */ 149698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ql */ 150698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 151698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Qo */ 152698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Qq */ 153698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Re */ 15495c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Rs */ 155698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 156698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Sc */ 157698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 158698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* So */ 159698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */ 160*260e9a87SYuri Pankov { in_line_argn, 0 }, /* Sm */ 161698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */ 162698f87a4SGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */ 16395c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */ 164698f87a4SGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ux */ 16595c635efSGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */ 16695c635efSGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */ 16795c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ 168698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 169698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Fc */ 170698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 171698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Oo */ 172698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 173698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Oc */ 17495c635efSGarrett D'Amore { blk_full, MDOC_EXPLICIT }, /* Bk */ 175698f87a4SGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */ 17695c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Bt */ 17795c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Hf */ 178*260e9a87SYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fr */ 17995c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Ud */ 18095c635efSGarrett D'Amore { in_line, 0 }, /* Lb */ 18195c635efSGarrett D'Amore { in_line_eoln, 0 }, /* Lp */ 18295c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ 18395c635efSGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ 184698f87a4SGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */ 185698f87a4SGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | 186698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Bro */ 187698f87a4SGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | 188698f87a4SGarrett D'Amore MDOC_EXPLICIT | MDOC_JOIN }, /* Brc */ 189698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %C */ 190*260e9a87SYuri Pankov { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Es */ 191*260e9a87SYuri Pankov { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */ 19295c635efSGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ 193698f87a4SGarrett D'Amore { in_line_eoln, MDOC_JOIN }, /* %Q */ 19495c635efSGarrett D'Amore { in_line_eoln, 0 }, /* br */ 19595c635efSGarrett D'Amore { in_line_eoln, 0 }, /* sp */ 19695c635efSGarrett D'Amore { in_line_eoln, 0 }, /* %U */ 197698f87a4SGarrett D'Amore { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ 198*260e9a87SYuri Pankov { in_line_eoln, MDOC_PROLOGUE }, /* ll */ 19995c635efSGarrett D'Amore }; 20095c635efSGarrett D'Amore 20195c635efSGarrett D'Amore const struct mdoc_macro * const mdoc_macros = __mdoc_macros; 20295c635efSGarrett D'Amore 20395c635efSGarrett D'Amore 20495c635efSGarrett D'Amore /* 20595c635efSGarrett D'Amore * This is called at the end of parsing. It must traverse up the tree, 20695c635efSGarrett D'Amore * closing out open [implicit] scopes. Obviously, open explicit scopes 20795c635efSGarrett D'Amore * are errors. 20895c635efSGarrett D'Amore */ 209*260e9a87SYuri Pankov void 210698f87a4SGarrett D'Amore mdoc_macroend(struct mdoc *mdoc) 21195c635efSGarrett D'Amore { 21295c635efSGarrett D'Amore struct mdoc_node *n; 21395c635efSGarrett D'Amore 21495c635efSGarrett D'Amore /* Scan for open explicit scopes. */ 21595c635efSGarrett D'Amore 216*260e9a87SYuri Pankov n = mdoc->last->flags & MDOC_VALID ? 217698f87a4SGarrett D'Amore mdoc->last->parent : mdoc->last; 21895c635efSGarrett D'Amore 21995c635efSGarrett D'Amore for ( ; n; n = n->parent) 220*260e9a87SYuri Pankov if (n->type == MDOC_BLOCK && 221*260e9a87SYuri Pankov mdoc_macros[n->tok].flags & MDOC_EXPLICIT) 222*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse, 223*260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 22495c635efSGarrett D'Amore 22595c635efSGarrett D'Amore /* Rewind to the first. */ 22695c635efSGarrett D'Amore 227*260e9a87SYuri Pankov rew_last(mdoc, mdoc->first); 22895c635efSGarrett D'Amore } 22995c635efSGarrett D'Amore 23095c635efSGarrett D'Amore /* 231*260e9a87SYuri Pankov * Look up the macro at *p called by "from", 232*260e9a87SYuri Pankov * or as a line macro if from == MDOC_MAX. 23395c635efSGarrett D'Amore */ 23495c635efSGarrett D'Amore static enum mdoct 235*260e9a87SYuri Pankov lookup(struct mdoc *mdoc, enum mdoct from, int line, int ppos, const char *p) 23695c635efSGarrett D'Amore { 23795c635efSGarrett D'Amore enum mdoct res; 23895c635efSGarrett D'Amore 239*260e9a87SYuri Pankov if (from == MDOC_MAX || mdoc_macros[from].flags & MDOC_PARSED) { 240*260e9a87SYuri Pankov res = mdoc_hash_find(p); 241*260e9a87SYuri Pankov if (res != MDOC_MAX) { 242*260e9a87SYuri Pankov if (mdoc_macros[res].flags & MDOC_CALLABLE) 24395c635efSGarrett D'Amore return(res); 244*260e9a87SYuri Pankov if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll) 245*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_CALL, 246*260e9a87SYuri Pankov mdoc->parse, line, ppos, p); 247*260e9a87SYuri Pankov } 248*260e9a87SYuri Pankov } 24995c635efSGarrett D'Amore return(MDOC_MAX); 25095c635efSGarrett D'Amore } 25195c635efSGarrett D'Amore 252*260e9a87SYuri Pankov /* 253*260e9a87SYuri Pankov * Rewind up to and including a specific node. 254*260e9a87SYuri Pankov */ 255*260e9a87SYuri Pankov static void 25695c635efSGarrett D'Amore rew_last(struct mdoc *mdoc, const struct mdoc_node *to) 25795c635efSGarrett D'Amore { 25895c635efSGarrett D'Amore struct mdoc_node *n, *np; 25995c635efSGarrett D'Amore 26095c635efSGarrett D'Amore assert(to); 26195c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 26295c635efSGarrett D'Amore while (mdoc->last != to) { 26395c635efSGarrett D'Amore /* 26495c635efSGarrett D'Amore * Save the parent here, because we may delete the 265698f87a4SGarrett D'Amore * mdoc->last node in the post-validation phase and reset 266698f87a4SGarrett D'Amore * it to mdoc->last->parent, causing a step in the closing 26795c635efSGarrett D'Amore * out to be lost. 26895c635efSGarrett D'Amore */ 26995c635efSGarrett D'Amore np = mdoc->last->parent; 270*260e9a87SYuri Pankov mdoc_valid_post(mdoc); 27195c635efSGarrett D'Amore n = mdoc->last; 27295c635efSGarrett D'Amore mdoc->last = np; 27395c635efSGarrett D'Amore assert(mdoc->last); 27495c635efSGarrett D'Amore mdoc->last->last = n; 27595c635efSGarrett D'Amore } 276*260e9a87SYuri Pankov mdoc_valid_post(mdoc); 27795c635efSGarrett D'Amore } 27895c635efSGarrett D'Amore 279*260e9a87SYuri Pankov /* 280*260e9a87SYuri Pankov * Rewind up to a specific block, including all blocks that broke it. 281*260e9a87SYuri Pankov */ 282*260e9a87SYuri Pankov static void 283*260e9a87SYuri Pankov rew_pending(struct mdoc *mdoc, const struct mdoc_node *n) 284*260e9a87SYuri Pankov { 285*260e9a87SYuri Pankov 286*260e9a87SYuri Pankov for (;;) { 287*260e9a87SYuri Pankov rew_last(mdoc, n); 288*260e9a87SYuri Pankov 289*260e9a87SYuri Pankov switch (n->type) { 290*260e9a87SYuri Pankov case MDOC_HEAD: 291*260e9a87SYuri Pankov mdoc_body_alloc(mdoc, n->line, n->pos, n->tok); 292*260e9a87SYuri Pankov return; 293*260e9a87SYuri Pankov case MDOC_BLOCK: 294*260e9a87SYuri Pankov break; 295*260e9a87SYuri Pankov default: 296*260e9a87SYuri Pankov return; 297*260e9a87SYuri Pankov } 298*260e9a87SYuri Pankov 299*260e9a87SYuri Pankov if ( ! (n->flags & MDOC_BROKEN)) 300*260e9a87SYuri Pankov return; 301*260e9a87SYuri Pankov 302*260e9a87SYuri Pankov for (;;) { 303*260e9a87SYuri Pankov if ((n = n->parent) == NULL) 304*260e9a87SYuri Pankov return; 305*260e9a87SYuri Pankov 306*260e9a87SYuri Pankov if (n->type == MDOC_BLOCK || 307*260e9a87SYuri Pankov n->type == MDOC_HEAD) { 308*260e9a87SYuri Pankov if (n->flags & MDOC_ENDED) 309*260e9a87SYuri Pankov break; 310*260e9a87SYuri Pankov else 311*260e9a87SYuri Pankov return; 312*260e9a87SYuri Pankov } 313*260e9a87SYuri Pankov } 314*260e9a87SYuri Pankov } 315*260e9a87SYuri Pankov } 31695c635efSGarrett D'Amore 31795c635efSGarrett D'Amore /* 31895c635efSGarrett D'Amore * For a block closing macro, return the corresponding opening one. 31995c635efSGarrett D'Amore * Otherwise, return the macro itself. 32095c635efSGarrett D'Amore */ 32195c635efSGarrett D'Amore static enum mdoct 32295c635efSGarrett D'Amore rew_alt(enum mdoct tok) 32395c635efSGarrett D'Amore { 32495c635efSGarrett D'Amore switch (tok) { 325*260e9a87SYuri Pankov case MDOC_Ac: 32695c635efSGarrett D'Amore return(MDOC_Ao); 327*260e9a87SYuri Pankov case MDOC_Bc: 32895c635efSGarrett D'Amore return(MDOC_Bo); 329*260e9a87SYuri Pankov case MDOC_Brc: 33095c635efSGarrett D'Amore return(MDOC_Bro); 331*260e9a87SYuri Pankov case MDOC_Dc: 33295c635efSGarrett D'Amore return(MDOC_Do); 333*260e9a87SYuri Pankov case MDOC_Ec: 33495c635efSGarrett D'Amore return(MDOC_Eo); 335*260e9a87SYuri Pankov case MDOC_Ed: 33695c635efSGarrett D'Amore return(MDOC_Bd); 337*260e9a87SYuri Pankov case MDOC_Ef: 33895c635efSGarrett D'Amore return(MDOC_Bf); 339*260e9a87SYuri Pankov case MDOC_Ek: 34095c635efSGarrett D'Amore return(MDOC_Bk); 341*260e9a87SYuri Pankov case MDOC_El: 34295c635efSGarrett D'Amore return(MDOC_Bl); 343*260e9a87SYuri Pankov case MDOC_Fc: 34495c635efSGarrett D'Amore return(MDOC_Fo); 345*260e9a87SYuri Pankov case MDOC_Oc: 34695c635efSGarrett D'Amore return(MDOC_Oo); 347*260e9a87SYuri Pankov case MDOC_Pc: 34895c635efSGarrett D'Amore return(MDOC_Po); 349*260e9a87SYuri Pankov case MDOC_Qc: 35095c635efSGarrett D'Amore return(MDOC_Qo); 351*260e9a87SYuri Pankov case MDOC_Re: 35295c635efSGarrett D'Amore return(MDOC_Rs); 353*260e9a87SYuri Pankov case MDOC_Sc: 35495c635efSGarrett D'Amore return(MDOC_So); 355*260e9a87SYuri Pankov case MDOC_Xc: 35695c635efSGarrett D'Amore return(MDOC_Xo); 35795c635efSGarrett D'Amore default: 35895c635efSGarrett D'Amore return(tok); 35995c635efSGarrett D'Amore } 36095c635efSGarrett D'Amore /* NOTREACHED */ 36195c635efSGarrett D'Amore } 36295c635efSGarrett D'Amore 363*260e9a87SYuri Pankov static void 36495c635efSGarrett D'Amore rew_elem(struct mdoc *mdoc, enum mdoct tok) 36595c635efSGarrett D'Amore { 36695c635efSGarrett D'Amore struct mdoc_node *n; 36795c635efSGarrett D'Amore 36895c635efSGarrett D'Amore n = mdoc->last; 36995c635efSGarrett D'Amore if (MDOC_ELEM != n->type) 37095c635efSGarrett D'Amore n = n->parent; 37195c635efSGarrett D'Amore assert(MDOC_ELEM == n->type); 37295c635efSGarrett D'Amore assert(tok == n->tok); 373*260e9a87SYuri Pankov rew_last(mdoc, n); 37495c635efSGarrett D'Amore } 37595c635efSGarrett D'Amore 37695c635efSGarrett D'Amore /* 37795c635efSGarrett D'Amore * Allocate a word and check whether it's punctuation or not. 37895c635efSGarrett D'Amore * Punctuation consists of those tokens found in mdoc_isdelim(). 37995c635efSGarrett D'Amore */ 380*260e9a87SYuri Pankov static void 381698f87a4SGarrett D'Amore dword(struct mdoc *mdoc, int line, int col, const char *p, 382698f87a4SGarrett D'Amore enum mdelim d, int may_append) 38395c635efSGarrett D'Amore { 38495c635efSGarrett D'Amore 385*260e9a87SYuri Pankov if (d == DELIM_MAX) 38695c635efSGarrett D'Amore d = mdoc_isdelim(p); 38795c635efSGarrett D'Amore 388698f87a4SGarrett D'Amore if (may_append && 389*260e9a87SYuri Pankov ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) && 390*260e9a87SYuri Pankov d == DELIM_NONE && mdoc->last->type == MDOC_TEXT && 391*260e9a87SYuri Pankov mdoc_isdelim(mdoc->last->string) == DELIM_NONE) { 392698f87a4SGarrett D'Amore mdoc_word_append(mdoc, p); 393*260e9a87SYuri Pankov return; 394698f87a4SGarrett D'Amore } 395698f87a4SGarrett D'Amore 396*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, line, col, p); 39795c635efSGarrett D'Amore 39895c635efSGarrett D'Amore /* 399*260e9a87SYuri Pankov * If the word consists of a bare delimiter, 400*260e9a87SYuri Pankov * flag the new node accordingly, 401*260e9a87SYuri Pankov * unless doing so was vetoed by the invoking macro. 402*260e9a87SYuri Pankov * Always clear the veto, it is only valid for one word. 40395c635efSGarrett D'Amore */ 40495c635efSGarrett D'Amore 405*260e9a87SYuri Pankov if (d == DELIM_OPEN) 406*260e9a87SYuri Pankov mdoc->last->flags |= MDOC_DELIMO; 407*260e9a87SYuri Pankov else if (d == DELIM_CLOSE && 408*260e9a87SYuri Pankov ! (mdoc->flags & MDOC_NODELIMC) && 409698f87a4SGarrett D'Amore mdoc->last->parent->tok != MDOC_Fd) 410698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_DELIMC; 411*260e9a87SYuri Pankov mdoc->flags &= ~MDOC_NODELIMC; 41295c635efSGarrett D'Amore } 41395c635efSGarrett D'Amore 414*260e9a87SYuri Pankov static void 415698f87a4SGarrett D'Amore append_delims(struct mdoc *mdoc, int line, int *pos, char *buf) 41695c635efSGarrett D'Amore { 41795c635efSGarrett D'Amore char *p; 418*260e9a87SYuri Pankov int la; 41995c635efSGarrett D'Amore 420*260e9a87SYuri Pankov if (buf[*pos] == '\0') 421*260e9a87SYuri Pankov return; 42295c635efSGarrett D'Amore 42395c635efSGarrett D'Amore for (;;) { 42495c635efSGarrett D'Amore la = *pos; 425*260e9a87SYuri Pankov if (mdoc_args(mdoc, line, pos, buf, MDOC_MAX, &p) == ARGS_EOLN) 42695c635efSGarrett D'Amore break; 427698f87a4SGarrett D'Amore dword(mdoc, line, la, p, DELIM_MAX, 1); 42895c635efSGarrett D'Amore 42995c635efSGarrett D'Amore /* 43095c635efSGarrett D'Amore * If we encounter end-of-sentence symbols, then trigger 43195c635efSGarrett D'Amore * the double-space. 43295c635efSGarrett D'Amore * 43395c635efSGarrett D'Amore * XXX: it's easy to allow this to propagate outward to 43495c635efSGarrett D'Amore * the last symbol, such that `. )' will cause the 43595c635efSGarrett D'Amore * correct double-spacing. However, (1) groff isn't 43695c635efSGarrett D'Amore * smart enough to do this and (2) it would require 43795c635efSGarrett D'Amore * knowing which symbols break this behaviour, for 43895c635efSGarrett D'Amore * example, `. ;' shouldn't propagate the double-space. 43995c635efSGarrett D'Amore */ 440*260e9a87SYuri Pankov 441*260e9a87SYuri Pankov if (mandoc_eos(p, strlen(p))) 442698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_EOS; 44395c635efSGarrett D'Amore } 44495c635efSGarrett D'Amore } 44595c635efSGarrett D'Amore 446*260e9a87SYuri Pankov /* 447*260e9a87SYuri Pankov * Parse one word. 448*260e9a87SYuri Pankov * If it is a macro, call it and return 1. 449*260e9a87SYuri Pankov * Otherwise, allocate it and return 0. 450*260e9a87SYuri Pankov */ 451*260e9a87SYuri Pankov static int 452*260e9a87SYuri Pankov macro_or_word(MACRO_PROT_ARGS, int parsed) 453*260e9a87SYuri Pankov { 454*260e9a87SYuri Pankov char *p; 455*260e9a87SYuri Pankov enum mdoct ntok; 456*260e9a87SYuri Pankov 457*260e9a87SYuri Pankov p = buf + ppos; 458*260e9a87SYuri Pankov ntok = MDOC_MAX; 459*260e9a87SYuri Pankov if (*p == '"') 460*260e9a87SYuri Pankov p++; 461*260e9a87SYuri Pankov else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT)) 462*260e9a87SYuri Pankov ntok = lookup(mdoc, tok, line, ppos, p); 463*260e9a87SYuri Pankov 464*260e9a87SYuri Pankov if (ntok == MDOC_MAX) { 465*260e9a87SYuri Pankov dword(mdoc, line, ppos, p, DELIM_MAX, tok == MDOC_MAX || 466*260e9a87SYuri Pankov mdoc_macros[tok].flags & MDOC_JOIN); 467*260e9a87SYuri Pankov return(0); 468*260e9a87SYuri Pankov } else { 469*260e9a87SYuri Pankov if (mdoc_macros[tok].fp == in_line_eoln) 470*260e9a87SYuri Pankov rew_elem(mdoc, tok); 471*260e9a87SYuri Pankov mdoc_macro(mdoc, ntok, line, ppos, pos, buf); 472*260e9a87SYuri Pankov if (tok == MDOC_MAX) 473*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 474*260e9a87SYuri Pankov return(1); 475*260e9a87SYuri Pankov } 476*260e9a87SYuri Pankov } 47795c635efSGarrett D'Amore 47895c635efSGarrett D'Amore /* 47995c635efSGarrett D'Amore * Close out block partial/full explicit. 48095c635efSGarrett D'Amore */ 481*260e9a87SYuri Pankov static void 48295c635efSGarrett D'Amore blk_exp_close(MACRO_PROT_ARGS) 48395c635efSGarrett D'Amore { 48495c635efSGarrett D'Amore struct mdoc_node *body; /* Our own body. */ 485*260e9a87SYuri Pankov struct mdoc_node *endbody; /* Our own end marker. */ 486*260e9a87SYuri Pankov struct mdoc_node *itblk; /* An It block starting later. */ 48795c635efSGarrett D'Amore struct mdoc_node *later; /* A sub-block starting later. */ 488*260e9a87SYuri Pankov struct mdoc_node *n; /* Search back to our block. */ 48995c635efSGarrett D'Amore 490*260e9a87SYuri Pankov int j, lastarg, maxargs, nl; 49195c635efSGarrett D'Amore enum margserr ac; 49295c635efSGarrett D'Amore enum mdoct atok, ntok; 49395c635efSGarrett D'Amore char *p; 49495c635efSGarrett D'Amore 495698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 49695c635efSGarrett D'Amore 49795c635efSGarrett D'Amore switch (tok) { 498*260e9a87SYuri Pankov case MDOC_Ec: 49995c635efSGarrett D'Amore maxargs = 1; 50095c635efSGarrett D'Amore break; 501*260e9a87SYuri Pankov case MDOC_Ek: 502698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_KEEP; 503*260e9a87SYuri Pankov /* FALLTHROUGH */ 50495c635efSGarrett D'Amore default: 50595c635efSGarrett D'Amore maxargs = 0; 50695c635efSGarrett D'Amore break; 50795c635efSGarrett D'Amore } 50895c635efSGarrett D'Amore 50995c635efSGarrett D'Amore /* 51095c635efSGarrett D'Amore * Search backwards for beginnings of blocks, 51195c635efSGarrett D'Amore * both of our own and of pending sub-blocks. 51295c635efSGarrett D'Amore */ 513*260e9a87SYuri Pankov 51495c635efSGarrett D'Amore atok = rew_alt(tok); 515*260e9a87SYuri Pankov body = endbody = itblk = later = NULL; 516698f87a4SGarrett D'Amore for (n = mdoc->last; n; n = n->parent) { 517*260e9a87SYuri Pankov if (n->flags & MDOC_ENDED) { 518*260e9a87SYuri Pankov if ( ! (n->flags & MDOC_VALID)) 519*260e9a87SYuri Pankov n->flags |= MDOC_BROKEN; 52095c635efSGarrett D'Amore continue; 521*260e9a87SYuri Pankov } 52295c635efSGarrett D'Amore 52395c635efSGarrett D'Amore /* Remember the start of our own body. */ 524*260e9a87SYuri Pankov 525*260e9a87SYuri Pankov if (n->type == MDOC_BODY && atok == n->tok) { 526*260e9a87SYuri Pankov if (n->end == ENDBODY_NOT) 52795c635efSGarrett D'Amore body = n; 52895c635efSGarrett D'Amore continue; 52995c635efSGarrett D'Amore } 53095c635efSGarrett D'Amore 531*260e9a87SYuri Pankov if (n->type != MDOC_BLOCK || n->tok == MDOC_Nm) 53295c635efSGarrett D'Amore continue; 533*260e9a87SYuri Pankov 534*260e9a87SYuri Pankov if (n->tok == MDOC_It) { 535*260e9a87SYuri Pankov itblk = n; 536*260e9a87SYuri Pankov continue; 537*260e9a87SYuri Pankov } 538*260e9a87SYuri Pankov 53995c635efSGarrett D'Amore if (atok == n->tok) { 54095c635efSGarrett D'Amore assert(body); 54195c635efSGarrett D'Amore 54295c635efSGarrett D'Amore /* 54395c635efSGarrett D'Amore * Found the start of our own block. 54495c635efSGarrett D'Amore * When there is no pending sub block, 54595c635efSGarrett D'Amore * just proceed to closing out. 54695c635efSGarrett D'Amore */ 547*260e9a87SYuri Pankov 548*260e9a87SYuri Pankov if (later == NULL || 549*260e9a87SYuri Pankov (tok == MDOC_El && itblk == NULL)) 55095c635efSGarrett D'Amore break; 55195c635efSGarrett D'Amore 55295c635efSGarrett D'Amore /* 553*260e9a87SYuri Pankov * When there is a pending sub block, postpone 554*260e9a87SYuri Pankov * closing out the current block until the 555*260e9a87SYuri Pankov * rew_pending() closing out the sub-block. 55695c635efSGarrett D'Amore * Mark the place where the formatting - but not 55795c635efSGarrett D'Amore * the scope - of the current block ends. 55895c635efSGarrett D'Amore */ 559*260e9a87SYuri Pankov 560*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, 561*260e9a87SYuri Pankov line, ppos, "%s breaks %s", 562*260e9a87SYuri Pankov mdoc_macronames[atok], 563*260e9a87SYuri Pankov mdoc_macronames[later->tok]); 564*260e9a87SYuri Pankov 565*260e9a87SYuri Pankov endbody = mdoc_endbody_alloc(mdoc, line, ppos, 566*260e9a87SYuri Pankov atok, body, ENDBODY_SPACE); 567*260e9a87SYuri Pankov 568*260e9a87SYuri Pankov if (tok == MDOC_El) 569*260e9a87SYuri Pankov itblk->flags |= MDOC_ENDED | MDOC_BROKEN; 570*260e9a87SYuri Pankov 571*260e9a87SYuri Pankov /* 572*260e9a87SYuri Pankov * If a block closing macro taking arguments 573*260e9a87SYuri Pankov * breaks another block, put the arguments 574*260e9a87SYuri Pankov * into the end marker. 575*260e9a87SYuri Pankov */ 576*260e9a87SYuri Pankov 577*260e9a87SYuri Pankov if (maxargs) 578*260e9a87SYuri Pankov mdoc->next = MDOC_NEXT_CHILD; 57995c635efSGarrett D'Amore break; 58095c635efSGarrett D'Amore } 58195c635efSGarrett D'Amore 582*260e9a87SYuri Pankov /* Explicit blocks close out description lines. */ 583*260e9a87SYuri Pankov 584*260e9a87SYuri Pankov if (n->tok == MDOC_Nd) { 585*260e9a87SYuri Pankov rew_last(mdoc, n); 58695c635efSGarrett D'Amore continue; 587*260e9a87SYuri Pankov } 588*260e9a87SYuri Pankov 589*260e9a87SYuri Pankov /* Breaking an open sub block. */ 590*260e9a87SYuri Pankov 591*260e9a87SYuri Pankov n->flags |= MDOC_BROKEN; 592*260e9a87SYuri Pankov if (later == NULL) 59395c635efSGarrett D'Amore later = n; 59495c635efSGarrett D'Amore } 59595c635efSGarrett D'Amore 596*260e9a87SYuri Pankov if (body == NULL) { 597*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse, 598*260e9a87SYuri Pankov line, ppos, mdoc_macronames[tok]); 599*260e9a87SYuri Pankov if (maxargs && endbody == NULL) { 600*260e9a87SYuri Pankov /* 601*260e9a87SYuri Pankov * Stray .Ec without previous .Eo: 602*260e9a87SYuri Pankov * Break the output line, keep the arguments. 603*260e9a87SYuri Pankov */ 604*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL); 605*260e9a87SYuri Pankov rew_elem(mdoc, MDOC_br); 606*260e9a87SYuri Pankov } 607*260e9a87SYuri Pankov } else if (endbody == NULL) { 608*260e9a87SYuri Pankov rew_last(mdoc, body); 609*260e9a87SYuri Pankov if (maxargs) 610*260e9a87SYuri Pankov mdoc_tail_alloc(mdoc, line, ppos, atok); 61195c635efSGarrett D'Amore } 61295c635efSGarrett D'Amore 613*260e9a87SYuri Pankov if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) { 614*260e9a87SYuri Pankov if (buf[*pos] != '\0') 615*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, 616*260e9a87SYuri Pankov mdoc->parse, line, ppos, 617*260e9a87SYuri Pankov "%s %s", mdoc_macronames[tok], 618*260e9a87SYuri Pankov buf + *pos); 619*260e9a87SYuri Pankov if (endbody == NULL && n != NULL) 620*260e9a87SYuri Pankov rew_pending(mdoc, n); 621*260e9a87SYuri Pankov return; 622*260e9a87SYuri Pankov } 62395c635efSGarrett D'Amore 624*260e9a87SYuri Pankov if (endbody != NULL) 625*260e9a87SYuri Pankov n = endbody; 626*260e9a87SYuri Pankov for (j = 0; ; j++) { 62795c635efSGarrett D'Amore lastarg = *pos; 62895c635efSGarrett D'Amore 629*260e9a87SYuri Pankov if (j == maxargs && n != NULL) { 630*260e9a87SYuri Pankov rew_pending(mdoc, n); 631*260e9a87SYuri Pankov n = NULL; 63295c635efSGarrett D'Amore } 63395c635efSGarrett D'Amore 634698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 635*260e9a87SYuri Pankov if (ac == ARGS_PUNCT || ac == ARGS_EOLN) 63695c635efSGarrett D'Amore break; 63795c635efSGarrett D'Amore 638*260e9a87SYuri Pankov ntok = ac == ARGS_QWORD ? MDOC_MAX : 639*260e9a87SYuri Pankov lookup(mdoc, tok, line, lastarg, p); 64095c635efSGarrett D'Amore 641*260e9a87SYuri Pankov if (ntok == MDOC_MAX) { 642*260e9a87SYuri Pankov dword(mdoc, line, lastarg, p, DELIM_MAX, 643*260e9a87SYuri Pankov MDOC_JOIN & mdoc_macros[tok].flags); 64495c635efSGarrett D'Amore continue; 64595c635efSGarrett D'Amore } 64695c635efSGarrett D'Amore 647*260e9a87SYuri Pankov if (n != NULL) { 648*260e9a87SYuri Pankov rew_pending(mdoc, n); 649*260e9a87SYuri Pankov n = NULL; 65095c635efSGarrett D'Amore } 651698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_NEWLINE; 652*260e9a87SYuri Pankov mdoc_macro(mdoc, ntok, line, lastarg, pos, buf); 65395c635efSGarrett D'Amore break; 65495c635efSGarrett D'Amore } 65595c635efSGarrett D'Amore 656*260e9a87SYuri Pankov if (n != NULL) 657*260e9a87SYuri Pankov rew_pending(mdoc, n); 658*260e9a87SYuri Pankov if (nl) 659*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 66095c635efSGarrett D'Amore } 66195c635efSGarrett D'Amore 662*260e9a87SYuri Pankov static void 66395c635efSGarrett D'Amore in_line(MACRO_PROT_ARGS) 66495c635efSGarrett D'Amore { 665*260e9a87SYuri Pankov int la, scope, cnt, firstarg, mayopen, nc, nl; 66695c635efSGarrett D'Amore enum mdoct ntok; 66795c635efSGarrett D'Amore enum margserr ac; 66895c635efSGarrett D'Amore enum mdelim d; 66995c635efSGarrett D'Amore struct mdoc_arg *arg; 67095c635efSGarrett D'Amore char *p; 67195c635efSGarrett D'Amore 672698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 67395c635efSGarrett D'Amore 67495c635efSGarrett D'Amore /* 67595c635efSGarrett D'Amore * Whether we allow ignored elements (those without content, 67695c635efSGarrett D'Amore * usually because of reserved words) to squeak by. 67795c635efSGarrett D'Amore */ 67895c635efSGarrett D'Amore 67995c635efSGarrett D'Amore switch (tok) { 680*260e9a87SYuri Pankov case MDOC_An: 68195c635efSGarrett D'Amore /* FALLTHROUGH */ 682*260e9a87SYuri Pankov case MDOC_Ar: 68395c635efSGarrett D'Amore /* FALLTHROUGH */ 684*260e9a87SYuri Pankov case MDOC_Fl: 68595c635efSGarrett D'Amore /* FALLTHROUGH */ 686*260e9a87SYuri Pankov case MDOC_Mt: 68795c635efSGarrett D'Amore /* FALLTHROUGH */ 688*260e9a87SYuri Pankov case MDOC_Nm: 68995c635efSGarrett D'Amore /* FALLTHROUGH */ 690*260e9a87SYuri Pankov case MDOC_Pa: 69195c635efSGarrett D'Amore nc = 1; 69295c635efSGarrett D'Amore break; 69395c635efSGarrett D'Amore default: 69495c635efSGarrett D'Amore nc = 0; 69595c635efSGarrett D'Amore break; 69695c635efSGarrett D'Amore } 69795c635efSGarrett D'Amore 698*260e9a87SYuri Pankov mdoc_argv(mdoc, line, tok, &arg, pos, buf); 69995c635efSGarrett D'Amore 700*260e9a87SYuri Pankov d = DELIM_NONE; 701*260e9a87SYuri Pankov firstarg = 1; 702*260e9a87SYuri Pankov mayopen = 1; 70395c635efSGarrett D'Amore for (cnt = scope = 0;; ) { 70495c635efSGarrett D'Amore la = *pos; 705698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 70695c635efSGarrett D'Amore 707*260e9a87SYuri Pankov /* 708*260e9a87SYuri Pankov * At the end of a macro line, 709*260e9a87SYuri Pankov * opening delimiters do not suppress spacing. 710*260e9a87SYuri Pankov */ 71195c635efSGarrett D'Amore 712*260e9a87SYuri Pankov if (ac == ARGS_EOLN) { 713*260e9a87SYuri Pankov if (d == DELIM_OPEN) 714*260e9a87SYuri Pankov mdoc->last->flags &= ~MDOC_DELIMO; 715*260e9a87SYuri Pankov break; 716*260e9a87SYuri Pankov } 717*260e9a87SYuri Pankov 718*260e9a87SYuri Pankov /* 719*260e9a87SYuri Pankov * The rest of the macro line is only punctuation, 720*260e9a87SYuri Pankov * to be handled by append_delims(). 721*260e9a87SYuri Pankov * If there were no other arguments, 722*260e9a87SYuri Pankov * do not allow the first one to suppress spacing, 723*260e9a87SYuri Pankov * even if it turns out to be a closing one. 724*260e9a87SYuri Pankov */ 725*260e9a87SYuri Pankov 726*260e9a87SYuri Pankov if (ac == ARGS_PUNCT) { 727*260e9a87SYuri Pankov if (cnt == 0 && (nc == 0 || tok == MDOC_An)) 728*260e9a87SYuri Pankov mdoc->flags |= MDOC_NODELIMC; 729*260e9a87SYuri Pankov break; 730*260e9a87SYuri Pankov } 731*260e9a87SYuri Pankov 732*260e9a87SYuri Pankov ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ? 733*260e9a87SYuri Pankov MDOC_MAX : lookup(mdoc, tok, line, la, p); 73495c635efSGarrett D'Amore 73595c635efSGarrett D'Amore /* 73695c635efSGarrett D'Amore * In this case, we've located a submacro and must 73795c635efSGarrett D'Amore * execute it. Close out scope, if open. If no 73895c635efSGarrett D'Amore * elements have been generated, either create one (nc) 73995c635efSGarrett D'Amore * or raise a warning. 74095c635efSGarrett D'Amore */ 74195c635efSGarrett D'Amore 742*260e9a87SYuri Pankov if (ntok != MDOC_MAX) { 743*260e9a87SYuri Pankov if (scope) 744*260e9a87SYuri Pankov rew_elem(mdoc, tok); 745*260e9a87SYuri Pankov if (nc && ! cnt) { 746*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, tok, arg); 747*260e9a87SYuri Pankov rew_last(mdoc, mdoc->last); 748*260e9a87SYuri Pankov } else if ( ! nc && ! cnt) { 74995c635efSGarrett D'Amore mdoc_argv_free(arg); 750*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, 751*260e9a87SYuri Pankov mdoc->parse, line, ppos, 752*260e9a87SYuri Pankov mdoc_macronames[tok]); 75395c635efSGarrett D'Amore } 754*260e9a87SYuri Pankov mdoc_macro(mdoc, ntok, line, la, pos, buf); 755*260e9a87SYuri Pankov if (nl) 756*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 757*260e9a87SYuri Pankov return; 75895c635efSGarrett D'Amore } 75995c635efSGarrett D'Amore 76095c635efSGarrett D'Amore /* 76195c635efSGarrett D'Amore * Non-quote-enclosed punctuation. Set up our scope, if 76295c635efSGarrett D'Amore * a word; rewind the scope, if a delimiter; then append 76395c635efSGarrett D'Amore * the word. 76495c635efSGarrett D'Amore */ 76595c635efSGarrett D'Amore 766*260e9a87SYuri Pankov d = ac == ARGS_QWORD ? DELIM_NONE : mdoc_isdelim(p); 76795c635efSGarrett D'Amore 76895c635efSGarrett D'Amore if (DELIM_NONE != d) { 76995c635efSGarrett D'Amore /* 77095c635efSGarrett D'Amore * If we encounter closing punctuation, no word 771*260e9a87SYuri Pankov * has been emitted, no scope is open, and we're 77295c635efSGarrett D'Amore * allowed to have an empty element, then start 773*260e9a87SYuri Pankov * a new scope. 77495c635efSGarrett D'Amore */ 775*260e9a87SYuri Pankov if ((d == DELIM_CLOSE || 776*260e9a87SYuri Pankov (d == DELIM_MIDDLE && tok == MDOC_Fl)) && 777*260e9a87SYuri Pankov !cnt && !scope && nc && mayopen) { 778*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, tok, arg); 77995c635efSGarrett D'Amore scope = 1; 780*260e9a87SYuri Pankov cnt++; 781*260e9a87SYuri Pankov if (tok == MDOC_Nm) 782*260e9a87SYuri Pankov mayopen = 0; 78395c635efSGarrett D'Amore } 78495c635efSGarrett D'Amore /* 78595c635efSGarrett D'Amore * Close out our scope, if one is open, before 78695c635efSGarrett D'Amore * any punctuation. 78795c635efSGarrett D'Amore */ 788*260e9a87SYuri Pankov if (scope) 789*260e9a87SYuri Pankov rew_elem(mdoc, tok); 79095c635efSGarrett D'Amore scope = 0; 791*260e9a87SYuri Pankov if (tok == MDOC_Fn) 792*260e9a87SYuri Pankov mayopen = 0; 793*260e9a87SYuri Pankov } else if (mayopen && !scope) { 794*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, tok, arg); 79595c635efSGarrett D'Amore scope = 1; 796*260e9a87SYuri Pankov cnt++; 79795c635efSGarrett D'Amore } 79895c635efSGarrett D'Amore 799*260e9a87SYuri Pankov dword(mdoc, line, la, p, d, 800*260e9a87SYuri Pankov MDOC_JOIN & mdoc_macros[tok].flags); 80195c635efSGarrett D'Amore 802*260e9a87SYuri Pankov /* 803*260e9a87SYuri Pankov * If the first argument is a closing delimiter, 804*260e9a87SYuri Pankov * do not suppress spacing before it. 805*260e9a87SYuri Pankov */ 806*260e9a87SYuri Pankov 807*260e9a87SYuri Pankov if (firstarg && d == DELIM_CLOSE && !nc) 808*260e9a87SYuri Pankov mdoc->last->flags &= ~MDOC_DELIMC; 809*260e9a87SYuri Pankov firstarg = 0; 81095c635efSGarrett D'Amore 81195c635efSGarrett D'Amore /* 81295c635efSGarrett D'Amore * `Fl' macros have their scope re-opened with each new 81395c635efSGarrett D'Amore * word so that the `-' can be added to each one without 81495c635efSGarrett D'Amore * having to parse out spaces. 81595c635efSGarrett D'Amore */ 816*260e9a87SYuri Pankov if (scope && tok == MDOC_Fl) { 817*260e9a87SYuri Pankov rew_elem(mdoc, tok); 81895c635efSGarrett D'Amore scope = 0; 81995c635efSGarrett D'Amore } 82095c635efSGarrett D'Amore } 82195c635efSGarrett D'Amore 822*260e9a87SYuri Pankov if (scope) 823*260e9a87SYuri Pankov rew_elem(mdoc, tok); 82495c635efSGarrett D'Amore 82595c635efSGarrett D'Amore /* 82695c635efSGarrett D'Amore * If no elements have been collected and we're allowed to have 82795c635efSGarrett D'Amore * empties (nc), open a scope and close it out. Otherwise, 82895c635efSGarrett D'Amore * raise a warning. 82995c635efSGarrett D'Amore */ 83095c635efSGarrett D'Amore 831*260e9a87SYuri Pankov if ( ! cnt) { 832*260e9a87SYuri Pankov if (nc) { 833*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, tok, arg); 834*260e9a87SYuri Pankov rew_last(mdoc, mdoc->last); 835*260e9a87SYuri Pankov } else { 83695c635efSGarrett D'Amore mdoc_argv_free(arg); 837*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 838*260e9a87SYuri Pankov line, ppos, mdoc_macronames[tok]); 839*260e9a87SYuri Pankov } 840*260e9a87SYuri Pankov } 841*260e9a87SYuri Pankov if (nl) 842*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 84395c635efSGarrett D'Amore } 84495c635efSGarrett D'Amore 845*260e9a87SYuri Pankov static void 84695c635efSGarrett D'Amore blk_full(MACRO_PROT_ARGS) 84795c635efSGarrett D'Amore { 848*260e9a87SYuri Pankov int la, nl, parsed; 84995c635efSGarrett D'Amore struct mdoc_arg *arg; 850*260e9a87SYuri Pankov struct mdoc_node *blk; /* Our own or a broken block. */ 851*260e9a87SYuri Pankov struct mdoc_node *head; /* Our own head. */ 852*260e9a87SYuri Pankov struct mdoc_node *body; /* Our own body. */ 85395c635efSGarrett D'Amore struct mdoc_node *n; 85495c635efSGarrett D'Amore enum margserr ac, lac; 85595c635efSGarrett D'Amore char *p; 85695c635efSGarrett D'Amore 857698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 85895c635efSGarrett D'Amore 859*260e9a87SYuri Pankov if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { 860*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 861*260e9a87SYuri Pankov line, ppos, mdoc_macronames[tok]); 862*260e9a87SYuri Pankov return; 863*260e9a87SYuri Pankov } 86495c635efSGarrett D'Amore 865*260e9a87SYuri Pankov if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) { 866*260e9a87SYuri Pankov 867*260e9a87SYuri Pankov /* Here, tok is one of Sh Ss Nm Nd It. */ 868*260e9a87SYuri Pankov 869*260e9a87SYuri Pankov blk = NULL; 870*260e9a87SYuri Pankov for (n = mdoc->last; n != NULL; n = n->parent) { 871*260e9a87SYuri Pankov if (n->flags & MDOC_ENDED) { 872*260e9a87SYuri Pankov if ( ! (n->flags & MDOC_VALID)) 873*260e9a87SYuri Pankov n->flags |= MDOC_BROKEN; 874*260e9a87SYuri Pankov continue; 875*260e9a87SYuri Pankov } 876*260e9a87SYuri Pankov if (n->type != MDOC_BLOCK) 877*260e9a87SYuri Pankov continue; 878*260e9a87SYuri Pankov 879*260e9a87SYuri Pankov if (tok == MDOC_It && n->tok == MDOC_Bl) { 880*260e9a87SYuri Pankov if (blk != NULL) { 881*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BLK_BROKEN, 882*260e9a87SYuri Pankov mdoc->parse, line, ppos, 883*260e9a87SYuri Pankov "It breaks %s", 884*260e9a87SYuri Pankov mdoc_macronames[blk->tok]); 885*260e9a87SYuri Pankov rew_pending(mdoc, blk); 886*260e9a87SYuri Pankov } 887*260e9a87SYuri Pankov break; 888*260e9a87SYuri Pankov } 889*260e9a87SYuri Pankov 890*260e9a87SYuri Pankov if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { 891*260e9a87SYuri Pankov switch (tok) { 892*260e9a87SYuri Pankov case MDOC_Sh: 893*260e9a87SYuri Pankov /* FALLTHROUGH */ 894*260e9a87SYuri Pankov case MDOC_Ss: 895*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BLK_BROKEN, 896*260e9a87SYuri Pankov mdoc->parse, line, ppos, 897*260e9a87SYuri Pankov "%s breaks %s", 898*260e9a87SYuri Pankov mdoc_macronames[tok], 899*260e9a87SYuri Pankov mdoc_macronames[n->tok]); 900*260e9a87SYuri Pankov rew_pending(mdoc, n); 901*260e9a87SYuri Pankov n = mdoc->last; 902*260e9a87SYuri Pankov continue; 903*260e9a87SYuri Pankov case MDOC_It: 904*260e9a87SYuri Pankov /* Delay in case it's astray. */ 905*260e9a87SYuri Pankov blk = n; 906*260e9a87SYuri Pankov continue; 907*260e9a87SYuri Pankov default: 908*260e9a87SYuri Pankov break; 909*260e9a87SYuri Pankov } 910*260e9a87SYuri Pankov break; 911*260e9a87SYuri Pankov } 912*260e9a87SYuri Pankov 913*260e9a87SYuri Pankov /* Here, n is one of Sh Ss Nm Nd It. */ 914*260e9a87SYuri Pankov 915*260e9a87SYuri Pankov if (tok != MDOC_Sh && (n->tok == MDOC_Sh || 916*260e9a87SYuri Pankov (tok != MDOC_Ss && (n->tok == MDOC_Ss || 917*260e9a87SYuri Pankov (tok != MDOC_It && n->tok == MDOC_It))))) 918*260e9a87SYuri Pankov break; 919*260e9a87SYuri Pankov 920*260e9a87SYuri Pankov /* Item breaking an explicit block. */ 921*260e9a87SYuri Pankov 922*260e9a87SYuri Pankov if (blk != NULL) { 923*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BLK_BROKEN, 924*260e9a87SYuri Pankov mdoc->parse, line, ppos, 925*260e9a87SYuri Pankov "It breaks %s", 926*260e9a87SYuri Pankov mdoc_macronames[blk->tok]); 927*260e9a87SYuri Pankov rew_pending(mdoc, blk); 928*260e9a87SYuri Pankov blk = NULL; 929*260e9a87SYuri Pankov } 930*260e9a87SYuri Pankov 931*260e9a87SYuri Pankov /* Close out prior implicit scopes. */ 932*260e9a87SYuri Pankov 933*260e9a87SYuri Pankov rew_last(mdoc, n); 934*260e9a87SYuri Pankov } 935*260e9a87SYuri Pankov 936*260e9a87SYuri Pankov /* Skip items outside lists. */ 937*260e9a87SYuri Pankov 938*260e9a87SYuri Pankov if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) { 939*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, 940*260e9a87SYuri Pankov line, ppos, "It %s", buf + *pos); 941*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL); 942*260e9a87SYuri Pankov rew_elem(mdoc, MDOC_br); 943*260e9a87SYuri Pankov return; 944*260e9a87SYuri Pankov } 94595c635efSGarrett D'Amore } 94695c635efSGarrett D'Amore 94795c635efSGarrett D'Amore /* 94895c635efSGarrett D'Amore * This routine accommodates implicitly- and explicitly-scoped 94995c635efSGarrett D'Amore * macro openings. Implicit ones first close out prior scope 95095c635efSGarrett D'Amore * (seen above). Delay opening the head until necessary to 95195c635efSGarrett D'Amore * allow leading punctuation to print. Special consideration 95295c635efSGarrett D'Amore * for `It -column', which has phrase-part syntax instead of 95395c635efSGarrett D'Amore * regular child nodes. 95495c635efSGarrett D'Amore */ 95595c635efSGarrett D'Amore 956*260e9a87SYuri Pankov mdoc_argv(mdoc, line, tok, &arg, pos, buf); 957*260e9a87SYuri Pankov blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg); 95895c635efSGarrett D'Amore head = body = NULL; 95995c635efSGarrett D'Amore 96095c635efSGarrett D'Amore /* 96195c635efSGarrett D'Amore * Exception: Heads of `It' macros in `-diag' lists are not 96295c635efSGarrett D'Amore * parsed, even though `It' macros in general are parsed. 96395c635efSGarrett D'Amore */ 964*260e9a87SYuri Pankov 965*260e9a87SYuri Pankov parsed = tok != MDOC_It || 966*260e9a87SYuri Pankov mdoc->last->parent->tok != MDOC_Bl || 967*260e9a87SYuri Pankov mdoc->last->parent->norm->Bl.type != LIST_diag; 96895c635efSGarrett D'Amore 96995c635efSGarrett D'Amore /* 97095c635efSGarrett D'Amore * The `Nd' macro has all arguments in its body: it's a hybrid 97195c635efSGarrett D'Amore * of block partial-explicit and full-implicit. Stupid. 97295c635efSGarrett D'Amore */ 97395c635efSGarrett D'Amore 974*260e9a87SYuri Pankov if (tok == MDOC_Nd) { 975*260e9a87SYuri Pankov head = mdoc_head_alloc(mdoc, line, ppos, tok); 976*260e9a87SYuri Pankov rew_last(mdoc, head); 977*260e9a87SYuri Pankov body = mdoc_body_alloc(mdoc, line, ppos, tok); 97895c635efSGarrett D'Amore } 97995c635efSGarrett D'Amore 980*260e9a87SYuri Pankov if (tok == MDOC_Bk) 981698f87a4SGarrett D'Amore mdoc->flags |= MDOC_KEEP; 982698f87a4SGarrett D'Amore 983*260e9a87SYuri Pankov ac = ARGS_PEND; 98495c635efSGarrett D'Amore for (;;) { 98595c635efSGarrett D'Amore la = *pos; 986*260e9a87SYuri Pankov lac = ac; 987698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 988*260e9a87SYuri Pankov if (ac == ARGS_EOLN) { 989*260e9a87SYuri Pankov if (lac != ARGS_PPHRASE && lac != ARGS_PHRASE) 99095c635efSGarrett D'Amore break; 99195c635efSGarrett D'Amore /* 99295c635efSGarrett D'Amore * This is necessary: if the last token on a 99395c635efSGarrett D'Amore * line is a `Ta' or tab, then we'll get 99495c635efSGarrett D'Amore * ARGS_EOLN, so we must be smart enough to 99595c635efSGarrett D'Amore * reopen our scope if the last parse was a 99695c635efSGarrett D'Amore * phrase or partial phrase. 99795c635efSGarrett D'Amore */ 998*260e9a87SYuri Pankov if (body != NULL) 999*260e9a87SYuri Pankov rew_last(mdoc, body); 1000*260e9a87SYuri Pankov body = mdoc_body_alloc(mdoc, line, ppos, tok); 100195c635efSGarrett D'Amore break; 100295c635efSGarrett D'Amore } 1003*260e9a87SYuri Pankov if (tok == MDOC_Bd || tok == MDOC_Bk) { 1004*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, 1005*260e9a87SYuri Pankov mdoc->parse, line, la, "%s ... %s", 1006*260e9a87SYuri Pankov mdoc_macronames[tok], buf + la); 1007*260e9a87SYuri Pankov break; 1008*260e9a87SYuri Pankov } 1009*260e9a87SYuri Pankov if (tok == MDOC_Rs) { 1010*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, 1011*260e9a87SYuri Pankov line, la, "Rs %s", buf + la); 1012*260e9a87SYuri Pankov break; 1013*260e9a87SYuri Pankov } 1014*260e9a87SYuri Pankov if (ac == ARGS_PUNCT) 1015*260e9a87SYuri Pankov break; 101695c635efSGarrett D'Amore 101795c635efSGarrett D'Amore /* 101895c635efSGarrett D'Amore * Emit leading punctuation (i.e., punctuation before 101995c635efSGarrett D'Amore * the MDOC_HEAD) for non-phrase types. 102095c635efSGarrett D'Amore */ 102195c635efSGarrett D'Amore 1022*260e9a87SYuri Pankov if (head == NULL && 1023*260e9a87SYuri Pankov ac != ARGS_PEND && 1024*260e9a87SYuri Pankov ac != ARGS_PHRASE && 1025*260e9a87SYuri Pankov ac != ARGS_PPHRASE && 1026*260e9a87SYuri Pankov ac != ARGS_QWORD && 1027*260e9a87SYuri Pankov mdoc_isdelim(p) == DELIM_OPEN) { 1028*260e9a87SYuri Pankov dword(mdoc, line, la, p, DELIM_OPEN, 0); 102995c635efSGarrett D'Amore continue; 103095c635efSGarrett D'Amore } 103195c635efSGarrett D'Amore 103295c635efSGarrett D'Amore /* Open a head if one hasn't been opened. */ 103395c635efSGarrett D'Amore 1034*260e9a87SYuri Pankov if (head == NULL) 1035*260e9a87SYuri Pankov head = mdoc_head_alloc(mdoc, line, ppos, tok); 103695c635efSGarrett D'Amore 1037*260e9a87SYuri Pankov if (ac == ARGS_PHRASE || 1038*260e9a87SYuri Pankov ac == ARGS_PEND || 1039*260e9a87SYuri Pankov ac == ARGS_PPHRASE) { 1040*260e9a87SYuri Pankov 104195c635efSGarrett D'Amore /* 104295c635efSGarrett D'Amore * If we haven't opened a body yet, rewind the 104395c635efSGarrett D'Amore * head; if we have, rewind that instead. 104495c635efSGarrett D'Amore */ 104595c635efSGarrett D'Amore 1046*260e9a87SYuri Pankov rew_last(mdoc, body == NULL ? head : body); 1047*260e9a87SYuri Pankov body = mdoc_body_alloc(mdoc, line, ppos, tok); 104895c635efSGarrett D'Amore 104995c635efSGarrett D'Amore /* 105095c635efSGarrett D'Amore * Process phrases: set whether we're in a 105195c635efSGarrett D'Amore * partial-phrase (this effects line handling) 105295c635efSGarrett D'Amore * then call down into the phrase parser. 105395c635efSGarrett D'Amore */ 105495c635efSGarrett D'Amore 1055*260e9a87SYuri Pankov if (ac == ARGS_PPHRASE) 1056698f87a4SGarrett D'Amore mdoc->flags |= MDOC_PPHRASE; 1057*260e9a87SYuri Pankov if (ac == ARGS_PEND && lac == ARGS_PPHRASE) 1058698f87a4SGarrett D'Amore mdoc->flags |= MDOC_PPHRASE; 1059*260e9a87SYuri Pankov parse_rest(mdoc, MDOC_MAX, line, &la, buf); 1060698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_PPHRASE; 106195c635efSGarrett D'Amore continue; 106295c635efSGarrett D'Amore } 106395c635efSGarrett D'Amore 1064*260e9a87SYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed)) 106595c635efSGarrett D'Amore break; 106695c635efSGarrett D'Amore } 106795c635efSGarrett D'Amore 1068*260e9a87SYuri Pankov if (blk->flags & MDOC_VALID) 1069*260e9a87SYuri Pankov return; 1070*260e9a87SYuri Pankov if (head == NULL) 1071*260e9a87SYuri Pankov head = mdoc_head_alloc(mdoc, line, ppos, tok); 1072*260e9a87SYuri Pankov if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs) 1073*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 1074*260e9a87SYuri Pankov if (body != NULL) 107595c635efSGarrett D'Amore goto out; 107695c635efSGarrett D'Amore 107795c635efSGarrett D'Amore /* 107895c635efSGarrett D'Amore * If there is an open (i.e., unvalidated) sub-block requiring 107995c635efSGarrett D'Amore * explicit close-out, postpone switching the current block from 1080*260e9a87SYuri Pankov * head to body until the rew_pending() call closing out that 108195c635efSGarrett D'Amore * sub-block. 108295c635efSGarrett D'Amore */ 1083698f87a4SGarrett D'Amore for (n = mdoc->last; n && n != head; n = n->parent) { 1084*260e9a87SYuri Pankov if (n->flags & MDOC_ENDED) { 1085*260e9a87SYuri Pankov if ( ! (n->flags & MDOC_VALID)) 1086*260e9a87SYuri Pankov n->flags |= MDOC_BROKEN; 1087*260e9a87SYuri Pankov continue; 1088*260e9a87SYuri Pankov } 1089*260e9a87SYuri Pankov if (n->type == MDOC_BLOCK && 1090*260e9a87SYuri Pankov mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { 1091*260e9a87SYuri Pankov n->flags = MDOC_BROKEN; 1092*260e9a87SYuri Pankov head->flags = MDOC_ENDED; 109395c635efSGarrett D'Amore } 109495c635efSGarrett D'Amore } 1095*260e9a87SYuri Pankov if (head->flags & MDOC_ENDED) 1096*260e9a87SYuri Pankov return; 109795c635efSGarrett D'Amore 109895c635efSGarrett D'Amore /* Close out scopes to remain in a consistent state. */ 109995c635efSGarrett D'Amore 1100*260e9a87SYuri Pankov rew_last(mdoc, head); 1101*260e9a87SYuri Pankov body = mdoc_body_alloc(mdoc, line, ppos, tok); 110295c635efSGarrett D'Amore out: 1103*260e9a87SYuri Pankov if (mdoc->flags & MDOC_FREECOL) { 1104*260e9a87SYuri Pankov rew_last(mdoc, body); 1105*260e9a87SYuri Pankov rew_last(mdoc, blk); 1106698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_FREECOL; 1107*260e9a87SYuri Pankov } 110895c635efSGarrett D'Amore } 110995c635efSGarrett D'Amore 1110*260e9a87SYuri Pankov static void 111195c635efSGarrett D'Amore blk_part_imp(MACRO_PROT_ARGS) 111295c635efSGarrett D'Amore { 111395c635efSGarrett D'Amore int la, nl; 111495c635efSGarrett D'Amore enum margserr ac; 111595c635efSGarrett D'Amore char *p; 111695c635efSGarrett D'Amore struct mdoc_node *blk; /* saved block context */ 111795c635efSGarrett D'Amore struct mdoc_node *body; /* saved body context */ 111895c635efSGarrett D'Amore struct mdoc_node *n; 111995c635efSGarrett D'Amore 1120698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 112195c635efSGarrett D'Amore 112295c635efSGarrett D'Amore /* 112395c635efSGarrett D'Amore * A macro that spans to the end of the line. This is generally 112495c635efSGarrett D'Amore * (but not necessarily) called as the first macro. The block 112595c635efSGarrett D'Amore * has a head as the immediate child, which is always empty, 112695c635efSGarrett D'Amore * followed by zero or more opening punctuation nodes, then the 112795c635efSGarrett D'Amore * body (which may be empty, depending on the macro), then zero 112895c635efSGarrett D'Amore * or more closing punctuation nodes. 112995c635efSGarrett D'Amore */ 113095c635efSGarrett D'Amore 1131*260e9a87SYuri Pankov blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL); 1132*260e9a87SYuri Pankov rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok)); 113395c635efSGarrett D'Amore 113495c635efSGarrett D'Amore /* 113595c635efSGarrett D'Amore * Open the body scope "on-demand", that is, after we've 113695c635efSGarrett D'Amore * processed all our the leading delimiters (open parenthesis, 113795c635efSGarrett D'Amore * etc.). 113895c635efSGarrett D'Amore */ 113995c635efSGarrett D'Amore 114095c635efSGarrett D'Amore for (body = NULL; ; ) { 114195c635efSGarrett D'Amore la = *pos; 1142698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 1143*260e9a87SYuri Pankov if (ac == ARGS_EOLN || ac == ARGS_PUNCT) 114495c635efSGarrett D'Amore break; 114595c635efSGarrett D'Amore 1146*260e9a87SYuri Pankov if (body == NULL && ac != ARGS_QWORD && 1147*260e9a87SYuri Pankov mdoc_isdelim(p) == DELIM_OPEN) { 1148*260e9a87SYuri Pankov dword(mdoc, line, la, p, DELIM_OPEN, 0); 114995c635efSGarrett D'Amore continue; 115095c635efSGarrett D'Amore } 115195c635efSGarrett D'Amore 1152*260e9a87SYuri Pankov if (body == NULL) 1153*260e9a87SYuri Pankov body = mdoc_body_alloc(mdoc, line, ppos, tok); 115495c635efSGarrett D'Amore 1155*260e9a87SYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) 115695c635efSGarrett D'Amore break; 115795c635efSGarrett D'Amore } 1158*260e9a87SYuri Pankov if (body == NULL) 1159*260e9a87SYuri Pankov body = mdoc_body_alloc(mdoc, line, ppos, tok); 116095c635efSGarrett D'Amore 116195c635efSGarrett D'Amore /* 116295c635efSGarrett D'Amore * If there is an open sub-block requiring explicit close-out, 1163*260e9a87SYuri Pankov * postpone closing out the current block until the 1164*260e9a87SYuri Pankov * rew_pending() call closing out the sub-block. 116595c635efSGarrett D'Amore */ 1166*260e9a87SYuri Pankov 1167698f87a4SGarrett D'Amore for (n = mdoc->last; n && n != body && n != blk->parent; 1168698f87a4SGarrett D'Amore n = n->parent) { 1169*260e9a87SYuri Pankov if (n->flags & MDOC_ENDED) { 1170*260e9a87SYuri Pankov if ( ! (n->flags & MDOC_VALID)) 1171*260e9a87SYuri Pankov n->flags |= MDOC_BROKEN; 1172*260e9a87SYuri Pankov continue; 1173*260e9a87SYuri Pankov } 1174*260e9a87SYuri Pankov if (n->type == MDOC_BLOCK && 1175*260e9a87SYuri Pankov mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { 1176*260e9a87SYuri Pankov n->flags |= MDOC_BROKEN; 1177*260e9a87SYuri Pankov if ( ! (body->flags & MDOC_ENDED)) { 1178*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BLK_NEST, 1179*260e9a87SYuri Pankov mdoc->parse, line, ppos, 1180*260e9a87SYuri Pankov "%s breaks %s", mdoc_macronames[tok], 1181*260e9a87SYuri Pankov mdoc_macronames[n->tok]); 1182*260e9a87SYuri Pankov mdoc_endbody_alloc(mdoc, line, ppos, 1183*260e9a87SYuri Pankov tok, body, ENDBODY_NOSPACE); 118495c635efSGarrett D'Amore } 118595c635efSGarrett D'Amore } 1186*260e9a87SYuri Pankov } 1187*260e9a87SYuri Pankov assert(n == body); 1188*260e9a87SYuri Pankov if (body->flags & MDOC_ENDED) 1189*260e9a87SYuri Pankov return; 119095c635efSGarrett D'Amore 1191*260e9a87SYuri Pankov rew_last(mdoc, body); 1192*260e9a87SYuri Pankov if (nl) 1193*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 1194*260e9a87SYuri Pankov rew_pending(mdoc, blk); 119595c635efSGarrett D'Amore 1196698f87a4SGarrett D'Amore /* Move trailing .Ns out of scope. */ 1197698f87a4SGarrett D'Amore 1198698f87a4SGarrett D'Amore for (n = body->child; n && n->next; n = n->next) 1199698f87a4SGarrett D'Amore /* Do nothing. */ ; 1200*260e9a87SYuri Pankov if (n && n->tok == MDOC_Ns) 1201698f87a4SGarrett D'Amore mdoc_node_relink(mdoc, n); 120295c635efSGarrett D'Amore } 120395c635efSGarrett D'Amore 1204*260e9a87SYuri Pankov static void 120595c635efSGarrett D'Amore blk_part_exp(MACRO_PROT_ARGS) 120695c635efSGarrett D'Amore { 120795c635efSGarrett D'Amore int la, nl; 120895c635efSGarrett D'Amore enum margserr ac; 120995c635efSGarrett D'Amore struct mdoc_node *head; /* keep track of head */ 121095c635efSGarrett D'Amore char *p; 121195c635efSGarrett D'Amore 1212698f87a4SGarrett D'Amore nl = MDOC_NEWLINE & mdoc->flags; 121395c635efSGarrett D'Amore 121495c635efSGarrett D'Amore /* 121595c635efSGarrett D'Amore * The opening of an explicit macro having zero or more leading 121695c635efSGarrett D'Amore * punctuation nodes; a head with optional single element (the 121795c635efSGarrett D'Amore * case of `Eo'); and a body that may be empty. 121895c635efSGarrett D'Amore */ 121995c635efSGarrett D'Amore 1220*260e9a87SYuri Pankov mdoc_block_alloc(mdoc, line, ppos, tok, NULL); 1221*260e9a87SYuri Pankov head = NULL; 1222*260e9a87SYuri Pankov for (;;) { 122395c635efSGarrett D'Amore la = *pos; 1224698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 1225*260e9a87SYuri Pankov if (ac == ARGS_PUNCT || ac == ARGS_EOLN) 122695c635efSGarrett D'Amore break; 122795c635efSGarrett D'Amore 122895c635efSGarrett D'Amore /* Flush out leading punctuation. */ 122995c635efSGarrett D'Amore 1230*260e9a87SYuri Pankov if (head == NULL && ac != ARGS_QWORD && 1231*260e9a87SYuri Pankov mdoc_isdelim(p) == DELIM_OPEN) { 1232*260e9a87SYuri Pankov dword(mdoc, line, la, p, DELIM_OPEN, 0); 123395c635efSGarrett D'Amore continue; 123495c635efSGarrett D'Amore } 123595c635efSGarrett D'Amore 1236*260e9a87SYuri Pankov if (head == NULL) { 1237*260e9a87SYuri Pankov head = mdoc_head_alloc(mdoc, line, ppos, tok); 1238*260e9a87SYuri Pankov if (tok == MDOC_Eo) /* Not parsed. */ 1239*260e9a87SYuri Pankov dword(mdoc, line, la, p, DELIM_MAX, 0); 1240*260e9a87SYuri Pankov rew_last(mdoc, head); 1241*260e9a87SYuri Pankov mdoc_body_alloc(mdoc, line, ppos, tok); 1242*260e9a87SYuri Pankov if (tok == MDOC_Eo) 124395c635efSGarrett D'Amore continue; 124495c635efSGarrett D'Amore } 124595c635efSGarrett D'Amore 1246*260e9a87SYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) 124795c635efSGarrett D'Amore break; 124895c635efSGarrett D'Amore } 124995c635efSGarrett D'Amore 125095c635efSGarrett D'Amore /* Clean-up to leave in a consistent state. */ 125195c635efSGarrett D'Amore 1252*260e9a87SYuri Pankov if (head == NULL) { 1253*260e9a87SYuri Pankov rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok)); 1254*260e9a87SYuri Pankov mdoc_body_alloc(mdoc, line, ppos, tok); 1255*260e9a87SYuri Pankov } 1256*260e9a87SYuri Pankov if (nl) 1257*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 125895c635efSGarrett D'Amore } 125995c635efSGarrett D'Amore 1260*260e9a87SYuri Pankov static void 126195c635efSGarrett D'Amore in_line_argn(MACRO_PROT_ARGS) 126295c635efSGarrett D'Amore { 126395c635efSGarrett D'Amore struct mdoc_arg *arg; 126495c635efSGarrett D'Amore char *p; 1265*260e9a87SYuri Pankov enum margserr ac; 126695c635efSGarrett D'Amore enum mdoct ntok; 1267*260e9a87SYuri Pankov int state; /* arg#; -1: not yet open; -2: closed */ 1268*260e9a87SYuri Pankov int la, maxargs, nl; 126995c635efSGarrett D'Amore 1270*260e9a87SYuri Pankov nl = mdoc->flags & MDOC_NEWLINE; 127195c635efSGarrett D'Amore 127295c635efSGarrett D'Amore /* 127395c635efSGarrett D'Amore * A line macro that has a fixed number of arguments (maxargs). 127495c635efSGarrett D'Amore * Only open the scope once the first non-leading-punctuation is 127595c635efSGarrett D'Amore * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then 127695c635efSGarrett D'Amore * keep it open until the maximum number of arguments are 127795c635efSGarrett D'Amore * exhausted. 127895c635efSGarrett D'Amore */ 127995c635efSGarrett D'Amore 128095c635efSGarrett D'Amore switch (tok) { 1281*260e9a87SYuri Pankov case MDOC_Ap: 128295c635efSGarrett D'Amore /* FALLTHROUGH */ 1283*260e9a87SYuri Pankov case MDOC_Ns: 128495c635efSGarrett D'Amore /* FALLTHROUGH */ 1285*260e9a87SYuri Pankov case MDOC_Ux: 128695c635efSGarrett D'Amore maxargs = 0; 128795c635efSGarrett D'Amore break; 1288*260e9a87SYuri Pankov case MDOC_Bx: 128995c635efSGarrett D'Amore /* FALLTHROUGH */ 1290*260e9a87SYuri Pankov case MDOC_Es: 1291*260e9a87SYuri Pankov /* FALLTHROUGH */ 1292*260e9a87SYuri Pankov case MDOC_Xr: 129395c635efSGarrett D'Amore maxargs = 2; 129495c635efSGarrett D'Amore break; 129595c635efSGarrett D'Amore default: 129695c635efSGarrett D'Amore maxargs = 1; 129795c635efSGarrett D'Amore break; 129895c635efSGarrett D'Amore } 129995c635efSGarrett D'Amore 1300*260e9a87SYuri Pankov mdoc_argv(mdoc, line, tok, &arg, pos, buf); 130195c635efSGarrett D'Amore 1302*260e9a87SYuri Pankov state = -1; 1303*260e9a87SYuri Pankov p = NULL; 130495c635efSGarrett D'Amore for (;;) { 130595c635efSGarrett D'Amore la = *pos; 1306698f87a4SGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p); 130795c635efSGarrett D'Amore 1308*260e9a87SYuri Pankov if (ac == ARGS_WORD && state == -1 && 1309*260e9a87SYuri Pankov ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) && 1310*260e9a87SYuri Pankov mdoc_isdelim(p) == DELIM_OPEN) { 1311*260e9a87SYuri Pankov dword(mdoc, line, la, p, DELIM_OPEN, 0); 131295c635efSGarrett D'Amore continue; 131395c635efSGarrett D'Amore } 131495c635efSGarrett D'Amore 1315*260e9a87SYuri Pankov if (state == -1 && tok != MDOC_In && 1316*260e9a87SYuri Pankov tok != MDOC_St && tok != MDOC_Xr) { 1317*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, tok, arg); 1318*260e9a87SYuri Pankov state = 0; 131995c635efSGarrett D'Amore } 132095c635efSGarrett D'Amore 1321*260e9a87SYuri Pankov if (ac == ARGS_PUNCT || ac == ARGS_EOLN) { 1322*260e9a87SYuri Pankov if (abs(state) < 2 && tok == MDOC_Pf) 1323*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PF_SKIP, 1324*260e9a87SYuri Pankov mdoc->parse, line, ppos, "Pf %s", 1325*260e9a87SYuri Pankov p == NULL ? "at eol" : p); 1326*260e9a87SYuri Pankov break; 132795c635efSGarrett D'Amore } 132895c635efSGarrett D'Amore 1329*260e9a87SYuri Pankov if (state == maxargs) { 1330*260e9a87SYuri Pankov rew_elem(mdoc, tok); 1331*260e9a87SYuri Pankov state = -2; 1332*260e9a87SYuri Pankov } 133395c635efSGarrett D'Amore 1334*260e9a87SYuri Pankov ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ? 1335*260e9a87SYuri Pankov MDOC_MAX : lookup(mdoc, tok, line, la, p); 1336*260e9a87SYuri Pankov 1337*260e9a87SYuri Pankov if (ntok != MDOC_MAX) { 1338*260e9a87SYuri Pankov if (state >= 0) { 1339*260e9a87SYuri Pankov rew_elem(mdoc, tok); 1340*260e9a87SYuri Pankov state = -2; 1341*260e9a87SYuri Pankov } 1342*260e9a87SYuri Pankov mdoc_macro(mdoc, ntok, line, la, pos, buf); 1343*260e9a87SYuri Pankov break; 1344*260e9a87SYuri Pankov } 1345*260e9a87SYuri Pankov 1346*260e9a87SYuri Pankov if (ac == ARGS_QWORD || 1347*260e9a87SYuri Pankov mdoc_macros[tok].flags & MDOC_IGNDELIM || 1348*260e9a87SYuri Pankov mdoc_isdelim(p) == DELIM_NONE) { 1349*260e9a87SYuri Pankov if (state == -1) { 1350*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, tok, arg); 1351*260e9a87SYuri Pankov state = 1; 1352*260e9a87SYuri Pankov } else if (state >= 0) 1353*260e9a87SYuri Pankov state++; 1354*260e9a87SYuri Pankov } else if (state >= 0) { 1355*260e9a87SYuri Pankov rew_elem(mdoc, tok); 1356*260e9a87SYuri Pankov state = -2; 1357*260e9a87SYuri Pankov } 1358*260e9a87SYuri Pankov 1359*260e9a87SYuri Pankov dword(mdoc, line, la, p, DELIM_MAX, 1360*260e9a87SYuri Pankov MDOC_JOIN & mdoc_macros[tok].flags); 1361*260e9a87SYuri Pankov } 1362*260e9a87SYuri Pankov 1363*260e9a87SYuri Pankov if (state == -1) { 1364*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1365*260e9a87SYuri Pankov line, ppos, mdoc_macronames[tok]); 1366*260e9a87SYuri Pankov return; 1367*260e9a87SYuri Pankov } 1368*260e9a87SYuri Pankov 1369*260e9a87SYuri Pankov if (state == 0 && tok == MDOC_Pf) 1370*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 1371*260e9a87SYuri Pankov if (state >= 0) 1372*260e9a87SYuri Pankov rew_elem(mdoc, tok); 1373*260e9a87SYuri Pankov if (nl) 1374*260e9a87SYuri Pankov append_delims(mdoc, line, pos, buf); 1375*260e9a87SYuri Pankov } 1376*260e9a87SYuri Pankov 1377*260e9a87SYuri Pankov static void 1378*260e9a87SYuri Pankov in_line_eoln(MACRO_PROT_ARGS) 137995c635efSGarrett D'Amore { 1380*260e9a87SYuri Pankov struct mdoc_node *n; 1381*260e9a87SYuri Pankov struct mdoc_arg *arg; 138295c635efSGarrett D'Amore 1383*260e9a87SYuri Pankov if ((tok == MDOC_Pp || tok == MDOC_Lp) && 1384*260e9a87SYuri Pankov ! (mdoc->flags & MDOC_SYNOPSIS)) { 1385*260e9a87SYuri Pankov n = mdoc->last; 1386*260e9a87SYuri Pankov if (mdoc->next == MDOC_NEXT_SIBLING) 1387*260e9a87SYuri Pankov n = n->parent; 1388*260e9a87SYuri Pankov if (n->tok == MDOC_Nm) 1389*260e9a87SYuri Pankov rew_last(mdoc, mdoc->last->parent); 1390*260e9a87SYuri Pankov } 139195c635efSGarrett D'Amore 1392*260e9a87SYuri Pankov if (buf[*pos] == '\0' && 1393*260e9a87SYuri Pankov (tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) { 1394*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1395*260e9a87SYuri Pankov line, ppos, mdoc_macronames[tok]); 1396*260e9a87SYuri Pankov return; 1397*260e9a87SYuri Pankov } 139895c635efSGarrett D'Amore 1399*260e9a87SYuri Pankov mdoc_argv(mdoc, line, tok, &arg, pos, buf); 1400*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, ppos, tok, arg); 1401*260e9a87SYuri Pankov if (parse_rest(mdoc, tok, line, pos, buf)) 1402*260e9a87SYuri Pankov return; 1403*260e9a87SYuri Pankov rew_elem(mdoc, tok); 1404*260e9a87SYuri Pankov } 140595c635efSGarrett D'Amore 140695c635efSGarrett D'Amore /* 1407*260e9a87SYuri Pankov * The simplest argument parser available: Parse the remaining 1408*260e9a87SYuri Pankov * words until the end of the phrase or line and return 0 1409*260e9a87SYuri Pankov * or until the next macro, call that macro, and return 1. 141095c635efSGarrett D'Amore */ 141195c635efSGarrett D'Amore static int 1412*260e9a87SYuri Pankov parse_rest(struct mdoc *mdoc, enum mdoct tok, int line, int *pos, char *buf) 141395c635efSGarrett D'Amore { 1414*260e9a87SYuri Pankov int la; 141595c635efSGarrett D'Amore 1416*260e9a87SYuri Pankov for (;;) { 1417*260e9a87SYuri Pankov la = *pos; 1418*260e9a87SYuri Pankov if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN) 1419*260e9a87SYuri Pankov return(0); 1420*260e9a87SYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) 142195c635efSGarrett D'Amore return(1); 142295c635efSGarrett D'Amore } 1423*260e9a87SYuri Pankov } 142495c635efSGarrett D'Amore 1425*260e9a87SYuri Pankov static void 1426*260e9a87SYuri Pankov ctx_synopsis(MACRO_PROT_ARGS) 1427*260e9a87SYuri Pankov { 1428*260e9a87SYuri Pankov 1429*260e9a87SYuri Pankov if (~mdoc->flags & (MDOC_SYNOPSIS | MDOC_NEWLINE)) 1430*260e9a87SYuri Pankov in_line(mdoc, tok, line, ppos, pos, buf); 1431*260e9a87SYuri Pankov else if (tok == MDOC_Nm) 1432*260e9a87SYuri Pankov blk_full(mdoc, tok, line, ppos, pos, buf); 1433*260e9a87SYuri Pankov else { 1434*260e9a87SYuri Pankov assert(tok == MDOC_Vt); 1435*260e9a87SYuri Pankov blk_part_imp(mdoc, tok, line, ppos, pos, buf); 1436*260e9a87SYuri Pankov } 1437*260e9a87SYuri Pankov } 143895c635efSGarrett D'Amore 143995c635efSGarrett D'Amore /* 144095c635efSGarrett D'Amore * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs. 144195c635efSGarrett D'Amore * They're unusual because they're basically free-form text until a 144295c635efSGarrett D'Amore * macro is encountered. 144395c635efSGarrett D'Amore */ 1444*260e9a87SYuri Pankov static void 144595c635efSGarrett D'Amore phrase_ta(MACRO_PROT_ARGS) 144695c635efSGarrett D'Amore { 1447*260e9a87SYuri Pankov struct mdoc_node *body, *n; 144895c635efSGarrett D'Amore 1449698f87a4SGarrett D'Amore /* Make sure we are in a column list or ignore this macro. */ 1450*260e9a87SYuri Pankov 1451*260e9a87SYuri Pankov body = NULL; 1452*260e9a87SYuri Pankov for (n = mdoc->last; n != NULL; n = n->parent) { 1453*260e9a87SYuri Pankov if (n->flags & MDOC_ENDED) 1454*260e9a87SYuri Pankov continue; 1455*260e9a87SYuri Pankov if (n->tok == MDOC_It && n->type == MDOC_BODY) 1456*260e9a87SYuri Pankov body = n; 1457*260e9a87SYuri Pankov if (n->tok == MDOC_Bl) 1458*260e9a87SYuri Pankov break; 1459*260e9a87SYuri Pankov } 1460*260e9a87SYuri Pankov 1461*260e9a87SYuri Pankov if (n == NULL || n->norm->Bl.type != LIST_column) { 1462*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse, 1463*260e9a87SYuri Pankov line, ppos, "Ta"); 1464*260e9a87SYuri Pankov return; 1465698f87a4SGarrett D'Amore } 146695c635efSGarrett D'Amore 1467698f87a4SGarrett D'Amore /* Advance to the next column. */ 146895c635efSGarrett D'Amore 1469*260e9a87SYuri Pankov rew_last(mdoc, body); 1470*260e9a87SYuri Pankov mdoc_body_alloc(mdoc, line, ppos, MDOC_It); 1471*260e9a87SYuri Pankov parse_rest(mdoc, MDOC_MAX, line, pos, buf); 147295c635efSGarrett D'Amore } 1473