1*95c635efSGarrett D'Amore /* $Id: mdoc.c,v 1.196 2011/09/30 00:13:28 schwarze Exp $ */ 2*95c635efSGarrett D'Amore /* 3*95c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*95c635efSGarrett D'Amore * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> 5*95c635efSGarrett D'Amore * 6*95c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 7*95c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 8*95c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 9*95c635efSGarrett D'Amore * 10*95c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*95c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*95c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*95c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*95c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*95c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*95c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*95c635efSGarrett D'Amore */ 18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 19*95c635efSGarrett D'Amore #include "config.h" 20*95c635efSGarrett D'Amore #endif 21*95c635efSGarrett D'Amore 22*95c635efSGarrett D'Amore #include <sys/types.h> 23*95c635efSGarrett D'Amore 24*95c635efSGarrett D'Amore #include <assert.h> 25*95c635efSGarrett D'Amore #include <stdarg.h> 26*95c635efSGarrett D'Amore #include <stdio.h> 27*95c635efSGarrett D'Amore #include <stdlib.h> 28*95c635efSGarrett D'Amore #include <string.h> 29*95c635efSGarrett D'Amore #include <time.h> 30*95c635efSGarrett D'Amore 31*95c635efSGarrett D'Amore #include "mdoc.h" 32*95c635efSGarrett D'Amore #include "mandoc.h" 33*95c635efSGarrett D'Amore #include "libmdoc.h" 34*95c635efSGarrett D'Amore #include "libmandoc.h" 35*95c635efSGarrett D'Amore 36*95c635efSGarrett D'Amore const char *const __mdoc_macronames[MDOC_MAX] = { 37*95c635efSGarrett D'Amore "Ap", "Dd", "Dt", "Os", 38*95c635efSGarrett D'Amore "Sh", "Ss", "Pp", "D1", 39*95c635efSGarrett D'Amore "Dl", "Bd", "Ed", "Bl", 40*95c635efSGarrett D'Amore "El", "It", "Ad", "An", 41*95c635efSGarrett D'Amore "Ar", "Cd", "Cm", "Dv", 42*95c635efSGarrett D'Amore "Er", "Ev", "Ex", "Fa", 43*95c635efSGarrett D'Amore "Fd", "Fl", "Fn", "Ft", 44*95c635efSGarrett D'Amore "Ic", "In", "Li", "Nd", 45*95c635efSGarrett D'Amore "Nm", "Op", "Ot", "Pa", 46*95c635efSGarrett D'Amore "Rv", "St", "Va", "Vt", 47*95c635efSGarrett D'Amore /* LINTED */ 48*95c635efSGarrett D'Amore "Xr", "%A", "%B", "%D", 49*95c635efSGarrett D'Amore /* LINTED */ 50*95c635efSGarrett D'Amore "%I", "%J", "%N", "%O", 51*95c635efSGarrett D'Amore /* LINTED */ 52*95c635efSGarrett D'Amore "%P", "%R", "%T", "%V", 53*95c635efSGarrett D'Amore "Ac", "Ao", "Aq", "At", 54*95c635efSGarrett D'Amore "Bc", "Bf", "Bo", "Bq", 55*95c635efSGarrett D'Amore "Bsx", "Bx", "Db", "Dc", 56*95c635efSGarrett D'Amore "Do", "Dq", "Ec", "Ef", 57*95c635efSGarrett D'Amore "Em", "Eo", "Fx", "Ms", 58*95c635efSGarrett D'Amore "No", "Ns", "Nx", "Ox", 59*95c635efSGarrett D'Amore "Pc", "Pf", "Po", "Pq", 60*95c635efSGarrett D'Amore "Qc", "Ql", "Qo", "Qq", 61*95c635efSGarrett D'Amore "Re", "Rs", "Sc", "So", 62*95c635efSGarrett D'Amore "Sq", "Sm", "Sx", "Sy", 63*95c635efSGarrett D'Amore "Tn", "Ux", "Xc", "Xo", 64*95c635efSGarrett D'Amore "Fo", "Fc", "Oo", "Oc", 65*95c635efSGarrett D'Amore "Bk", "Ek", "Bt", "Hf", 66*95c635efSGarrett D'Amore "Fr", "Ud", "Lb", "Lp", 67*95c635efSGarrett D'Amore "Lk", "Mt", "Brq", "Bro", 68*95c635efSGarrett D'Amore /* LINTED */ 69*95c635efSGarrett D'Amore "Brc", "%C", "Es", "En", 70*95c635efSGarrett D'Amore /* LINTED */ 71*95c635efSGarrett D'Amore "Dx", "%Q", "br", "sp", 72*95c635efSGarrett D'Amore /* LINTED */ 73*95c635efSGarrett D'Amore "%U", "Ta" 74*95c635efSGarrett D'Amore }; 75*95c635efSGarrett D'Amore 76*95c635efSGarrett D'Amore const char *const __mdoc_argnames[MDOC_ARG_MAX] = { 77*95c635efSGarrett D'Amore "split", "nosplit", "ragged", 78*95c635efSGarrett D'Amore "unfilled", "literal", "file", 79*95c635efSGarrett D'Amore "offset", "bullet", "dash", 80*95c635efSGarrett D'Amore "hyphen", "item", "enum", 81*95c635efSGarrett D'Amore "tag", "diag", "hang", 82*95c635efSGarrett D'Amore "ohang", "inset", "column", 83*95c635efSGarrett D'Amore "width", "compact", "std", 84*95c635efSGarrett D'Amore "filled", "words", "emphasis", 85*95c635efSGarrett D'Amore "symbolic", "nested", "centered" 86*95c635efSGarrett D'Amore }; 87*95c635efSGarrett D'Amore 88*95c635efSGarrett D'Amore const char * const *mdoc_macronames = __mdoc_macronames; 89*95c635efSGarrett D'Amore const char * const *mdoc_argnames = __mdoc_argnames; 90*95c635efSGarrett D'Amore 91*95c635efSGarrett D'Amore static void mdoc_node_free(struct mdoc_node *); 92*95c635efSGarrett D'Amore static void mdoc_node_unlink(struct mdoc *, 93*95c635efSGarrett D'Amore struct mdoc_node *); 94*95c635efSGarrett D'Amore static void mdoc_free1(struct mdoc *); 95*95c635efSGarrett D'Amore static void mdoc_alloc1(struct mdoc *); 96*95c635efSGarrett D'Amore static struct mdoc_node *node_alloc(struct mdoc *, int, int, 97*95c635efSGarrett D'Amore enum mdoct, enum mdoc_type); 98*95c635efSGarrett D'Amore static int node_append(struct mdoc *, 99*95c635efSGarrett D'Amore struct mdoc_node *); 100*95c635efSGarrett D'Amore #if 0 101*95c635efSGarrett D'Amore static int mdoc_preptext(struct mdoc *, int, char *, int); 102*95c635efSGarrett D'Amore #endif 103*95c635efSGarrett D'Amore static int mdoc_ptext(struct mdoc *, int, char *, int); 104*95c635efSGarrett D'Amore static int mdoc_pmacro(struct mdoc *, int, char *, int); 105*95c635efSGarrett D'Amore 106*95c635efSGarrett D'Amore const struct mdoc_node * 107*95c635efSGarrett D'Amore mdoc_node(const struct mdoc *m) 108*95c635efSGarrett D'Amore { 109*95c635efSGarrett D'Amore 110*95c635efSGarrett D'Amore assert( ! (MDOC_HALT & m->flags)); 111*95c635efSGarrett D'Amore return(m->first); 112*95c635efSGarrett D'Amore } 113*95c635efSGarrett D'Amore 114*95c635efSGarrett D'Amore 115*95c635efSGarrett D'Amore const struct mdoc_meta * 116*95c635efSGarrett D'Amore mdoc_meta(const struct mdoc *m) 117*95c635efSGarrett D'Amore { 118*95c635efSGarrett D'Amore 119*95c635efSGarrett D'Amore assert( ! (MDOC_HALT & m->flags)); 120*95c635efSGarrett D'Amore return(&m->meta); 121*95c635efSGarrett D'Amore } 122*95c635efSGarrett D'Amore 123*95c635efSGarrett D'Amore 124*95c635efSGarrett D'Amore /* 125*95c635efSGarrett D'Amore * Frees volatile resources (parse tree, meta-data, fields). 126*95c635efSGarrett D'Amore */ 127*95c635efSGarrett D'Amore static void 128*95c635efSGarrett D'Amore mdoc_free1(struct mdoc *mdoc) 129*95c635efSGarrett D'Amore { 130*95c635efSGarrett D'Amore 131*95c635efSGarrett D'Amore if (mdoc->first) 132*95c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->first); 133*95c635efSGarrett D'Amore if (mdoc->meta.title) 134*95c635efSGarrett D'Amore free(mdoc->meta.title); 135*95c635efSGarrett D'Amore if (mdoc->meta.os) 136*95c635efSGarrett D'Amore free(mdoc->meta.os); 137*95c635efSGarrett D'Amore if (mdoc->meta.name) 138*95c635efSGarrett D'Amore free(mdoc->meta.name); 139*95c635efSGarrett D'Amore if (mdoc->meta.arch) 140*95c635efSGarrett D'Amore free(mdoc->meta.arch); 141*95c635efSGarrett D'Amore if (mdoc->meta.vol) 142*95c635efSGarrett D'Amore free(mdoc->meta.vol); 143*95c635efSGarrett D'Amore if (mdoc->meta.msec) 144*95c635efSGarrett D'Amore free(mdoc->meta.msec); 145*95c635efSGarrett D'Amore if (mdoc->meta.date) 146*95c635efSGarrett D'Amore free(mdoc->meta.date); 147*95c635efSGarrett D'Amore } 148*95c635efSGarrett D'Amore 149*95c635efSGarrett D'Amore 150*95c635efSGarrett D'Amore /* 151*95c635efSGarrett D'Amore * Allocate all volatile resources (parse tree, meta-data, fields). 152*95c635efSGarrett D'Amore */ 153*95c635efSGarrett D'Amore static void 154*95c635efSGarrett D'Amore mdoc_alloc1(struct mdoc *mdoc) 155*95c635efSGarrett D'Amore { 156*95c635efSGarrett D'Amore 157*95c635efSGarrett D'Amore memset(&mdoc->meta, 0, sizeof(struct mdoc_meta)); 158*95c635efSGarrett D'Amore mdoc->flags = 0; 159*95c635efSGarrett D'Amore mdoc->lastnamed = mdoc->lastsec = SEC_NONE; 160*95c635efSGarrett D'Amore mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node)); 161*95c635efSGarrett D'Amore mdoc->first = mdoc->last; 162*95c635efSGarrett D'Amore mdoc->last->type = MDOC_ROOT; 163*95c635efSGarrett D'Amore mdoc->last->tok = MDOC_MAX; 164*95c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 165*95c635efSGarrett D'Amore } 166*95c635efSGarrett D'Amore 167*95c635efSGarrett D'Amore 168*95c635efSGarrett D'Amore /* 169*95c635efSGarrett D'Amore * Free up volatile resources (see mdoc_free1()) then re-initialises the 170*95c635efSGarrett D'Amore * data with mdoc_alloc1(). After invocation, parse data has been reset 171*95c635efSGarrett D'Amore * and the parser is ready for re-invocation on a new tree; however, 172*95c635efSGarrett D'Amore * cross-parse non-volatile data is kept intact. 173*95c635efSGarrett D'Amore */ 174*95c635efSGarrett D'Amore void 175*95c635efSGarrett D'Amore mdoc_reset(struct mdoc *mdoc) 176*95c635efSGarrett D'Amore { 177*95c635efSGarrett D'Amore 178*95c635efSGarrett D'Amore mdoc_free1(mdoc); 179*95c635efSGarrett D'Amore mdoc_alloc1(mdoc); 180*95c635efSGarrett D'Amore } 181*95c635efSGarrett D'Amore 182*95c635efSGarrett D'Amore 183*95c635efSGarrett D'Amore /* 184*95c635efSGarrett D'Amore * Completely free up all volatile and non-volatile parse resources. 185*95c635efSGarrett D'Amore * After invocation, the pointer is no longer usable. 186*95c635efSGarrett D'Amore */ 187*95c635efSGarrett D'Amore void 188*95c635efSGarrett D'Amore mdoc_free(struct mdoc *mdoc) 189*95c635efSGarrett D'Amore { 190*95c635efSGarrett D'Amore 191*95c635efSGarrett D'Amore mdoc_free1(mdoc); 192*95c635efSGarrett D'Amore free(mdoc); 193*95c635efSGarrett D'Amore } 194*95c635efSGarrett D'Amore 195*95c635efSGarrett D'Amore 196*95c635efSGarrett D'Amore /* 197*95c635efSGarrett D'Amore * Allocate volatile and non-volatile parse resources. 198*95c635efSGarrett D'Amore */ 199*95c635efSGarrett D'Amore struct mdoc * 200*95c635efSGarrett D'Amore mdoc_alloc(struct roff *roff, struct mparse *parse) 201*95c635efSGarrett D'Amore { 202*95c635efSGarrett D'Amore struct mdoc *p; 203*95c635efSGarrett D'Amore 204*95c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc)); 205*95c635efSGarrett D'Amore 206*95c635efSGarrett D'Amore p->parse = parse; 207*95c635efSGarrett D'Amore p->roff = roff; 208*95c635efSGarrett D'Amore 209*95c635efSGarrett D'Amore mdoc_hash_init(); 210*95c635efSGarrett D'Amore mdoc_alloc1(p); 211*95c635efSGarrett D'Amore return(p); 212*95c635efSGarrett D'Amore } 213*95c635efSGarrett D'Amore 214*95c635efSGarrett D'Amore 215*95c635efSGarrett D'Amore /* 216*95c635efSGarrett D'Amore * Climb back up the parse tree, validating open scopes. Mostly calls 217*95c635efSGarrett D'Amore * through to macro_end() in macro.c. 218*95c635efSGarrett D'Amore */ 219*95c635efSGarrett D'Amore int 220*95c635efSGarrett D'Amore mdoc_endparse(struct mdoc *m) 221*95c635efSGarrett D'Amore { 222*95c635efSGarrett D'Amore 223*95c635efSGarrett D'Amore assert( ! (MDOC_HALT & m->flags)); 224*95c635efSGarrett D'Amore if (mdoc_macroend(m)) 225*95c635efSGarrett D'Amore return(1); 226*95c635efSGarrett D'Amore m->flags |= MDOC_HALT; 227*95c635efSGarrett D'Amore return(0); 228*95c635efSGarrett D'Amore } 229*95c635efSGarrett D'Amore 230*95c635efSGarrett D'Amore int 231*95c635efSGarrett D'Amore mdoc_addeqn(struct mdoc *m, const struct eqn *ep) 232*95c635efSGarrett D'Amore { 233*95c635efSGarrett D'Amore struct mdoc_node *n; 234*95c635efSGarrett D'Amore 235*95c635efSGarrett D'Amore assert( ! (MDOC_HALT & m->flags)); 236*95c635efSGarrett D'Amore 237*95c635efSGarrett D'Amore /* No text before an initial macro. */ 238*95c635efSGarrett D'Amore 239*95c635efSGarrett D'Amore if (SEC_NONE == m->lastnamed) { 240*95c635efSGarrett D'Amore mdoc_pmsg(m, ep->ln, ep->pos, MANDOCERR_NOTEXT); 241*95c635efSGarrett D'Amore return(1); 242*95c635efSGarrett D'Amore } 243*95c635efSGarrett D'Amore 244*95c635efSGarrett D'Amore n = node_alloc(m, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); 245*95c635efSGarrett D'Amore n->eqn = ep; 246*95c635efSGarrett D'Amore 247*95c635efSGarrett D'Amore if ( ! node_append(m, n)) 248*95c635efSGarrett D'Amore return(0); 249*95c635efSGarrett D'Amore 250*95c635efSGarrett D'Amore m->next = MDOC_NEXT_SIBLING; 251*95c635efSGarrett D'Amore return(1); 252*95c635efSGarrett D'Amore } 253*95c635efSGarrett D'Amore 254*95c635efSGarrett D'Amore int 255*95c635efSGarrett D'Amore mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) 256*95c635efSGarrett D'Amore { 257*95c635efSGarrett D'Amore struct mdoc_node *n; 258*95c635efSGarrett D'Amore 259*95c635efSGarrett D'Amore assert( ! (MDOC_HALT & m->flags)); 260*95c635efSGarrett D'Amore 261*95c635efSGarrett D'Amore /* No text before an initial macro. */ 262*95c635efSGarrett D'Amore 263*95c635efSGarrett D'Amore if (SEC_NONE == m->lastnamed) { 264*95c635efSGarrett D'Amore mdoc_pmsg(m, sp->line, 0, MANDOCERR_NOTEXT); 265*95c635efSGarrett D'Amore return(1); 266*95c635efSGarrett D'Amore } 267*95c635efSGarrett D'Amore 268*95c635efSGarrett D'Amore n = node_alloc(m, sp->line, 0, MDOC_MAX, MDOC_TBL); 269*95c635efSGarrett D'Amore n->span = sp; 270*95c635efSGarrett D'Amore 271*95c635efSGarrett D'Amore if ( ! node_append(m, n)) 272*95c635efSGarrett D'Amore return(0); 273*95c635efSGarrett D'Amore 274*95c635efSGarrett D'Amore m->next = MDOC_NEXT_SIBLING; 275*95c635efSGarrett D'Amore return(1); 276*95c635efSGarrett D'Amore } 277*95c635efSGarrett D'Amore 278*95c635efSGarrett D'Amore 279*95c635efSGarrett D'Amore /* 280*95c635efSGarrett D'Amore * Main parse routine. Parses a single line -- really just hands off to 281*95c635efSGarrett D'Amore * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()). 282*95c635efSGarrett D'Amore */ 283*95c635efSGarrett D'Amore int 284*95c635efSGarrett D'Amore mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs) 285*95c635efSGarrett D'Amore { 286*95c635efSGarrett D'Amore 287*95c635efSGarrett D'Amore assert( ! (MDOC_HALT & m->flags)); 288*95c635efSGarrett D'Amore 289*95c635efSGarrett D'Amore m->flags |= MDOC_NEWLINE; 290*95c635efSGarrett D'Amore 291*95c635efSGarrett D'Amore /* 292*95c635efSGarrett D'Amore * Let the roff nS register switch SYNOPSIS mode early, 293*95c635efSGarrett D'Amore * such that the parser knows at all times 294*95c635efSGarrett D'Amore * whether this mode is on or off. 295*95c635efSGarrett D'Amore * Note that this mode is also switched by the Sh macro. 296*95c635efSGarrett D'Amore */ 297*95c635efSGarrett D'Amore if (roff_regisset(m->roff, REG_nS)) { 298*95c635efSGarrett D'Amore if (roff_regget(m->roff, REG_nS)) 299*95c635efSGarrett D'Amore m->flags |= MDOC_SYNOPSIS; 300*95c635efSGarrett D'Amore else 301*95c635efSGarrett D'Amore m->flags &= ~MDOC_SYNOPSIS; 302*95c635efSGarrett D'Amore } 303*95c635efSGarrett D'Amore 304*95c635efSGarrett D'Amore return(mandoc_getcontrol(buf, &offs) ? 305*95c635efSGarrett D'Amore mdoc_pmacro(m, ln, buf, offs) : 306*95c635efSGarrett D'Amore mdoc_ptext(m, ln, buf, offs)); 307*95c635efSGarrett D'Amore } 308*95c635efSGarrett D'Amore 309*95c635efSGarrett D'Amore int 310*95c635efSGarrett D'Amore mdoc_macro(MACRO_PROT_ARGS) 311*95c635efSGarrett D'Amore { 312*95c635efSGarrett D'Amore assert(tok < MDOC_MAX); 313*95c635efSGarrett D'Amore 314*95c635efSGarrett D'Amore /* If we're in the body, deny prologue calls. */ 315*95c635efSGarrett D'Amore 316*95c635efSGarrett D'Amore if (MDOC_PROLOGUE & mdoc_macros[tok].flags && 317*95c635efSGarrett D'Amore MDOC_PBODY & m->flags) { 318*95c635efSGarrett D'Amore mdoc_pmsg(m, line, ppos, MANDOCERR_BADBODY); 319*95c635efSGarrett D'Amore return(1); 320*95c635efSGarrett D'Amore } 321*95c635efSGarrett D'Amore 322*95c635efSGarrett D'Amore /* If we're in the prologue, deny "body" macros. */ 323*95c635efSGarrett D'Amore 324*95c635efSGarrett D'Amore if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) && 325*95c635efSGarrett D'Amore ! (MDOC_PBODY & m->flags)) { 326*95c635efSGarrett D'Amore mdoc_pmsg(m, line, ppos, MANDOCERR_BADPROLOG); 327*95c635efSGarrett D'Amore if (NULL == m->meta.msec) 328*95c635efSGarrett D'Amore m->meta.msec = mandoc_strdup("1"); 329*95c635efSGarrett D'Amore if (NULL == m->meta.title) 330*95c635efSGarrett D'Amore m->meta.title = mandoc_strdup("UNKNOWN"); 331*95c635efSGarrett D'Amore if (NULL == m->meta.vol) 332*95c635efSGarrett D'Amore m->meta.vol = mandoc_strdup("LOCAL"); 333*95c635efSGarrett D'Amore if (NULL == m->meta.os) 334*95c635efSGarrett D'Amore m->meta.os = mandoc_strdup("LOCAL"); 335*95c635efSGarrett D'Amore if (NULL == m->meta.date) 336*95c635efSGarrett D'Amore m->meta.date = mandoc_normdate 337*95c635efSGarrett D'Amore (m->parse, NULL, line, ppos); 338*95c635efSGarrett D'Amore m->flags |= MDOC_PBODY; 339*95c635efSGarrett D'Amore } 340*95c635efSGarrett D'Amore 341*95c635efSGarrett D'Amore return((*mdoc_macros[tok].fp)(m, tok, line, ppos, pos, buf)); 342*95c635efSGarrett D'Amore } 343*95c635efSGarrett D'Amore 344*95c635efSGarrett D'Amore 345*95c635efSGarrett D'Amore static int 346*95c635efSGarrett D'Amore node_append(struct mdoc *mdoc, struct mdoc_node *p) 347*95c635efSGarrett D'Amore { 348*95c635efSGarrett D'Amore 349*95c635efSGarrett D'Amore assert(mdoc->last); 350*95c635efSGarrett D'Amore assert(mdoc->first); 351*95c635efSGarrett D'Amore assert(MDOC_ROOT != p->type); 352*95c635efSGarrett D'Amore 353*95c635efSGarrett D'Amore switch (mdoc->next) { 354*95c635efSGarrett D'Amore case (MDOC_NEXT_SIBLING): 355*95c635efSGarrett D'Amore mdoc->last->next = p; 356*95c635efSGarrett D'Amore p->prev = mdoc->last; 357*95c635efSGarrett D'Amore p->parent = mdoc->last->parent; 358*95c635efSGarrett D'Amore break; 359*95c635efSGarrett D'Amore case (MDOC_NEXT_CHILD): 360*95c635efSGarrett D'Amore mdoc->last->child = p; 361*95c635efSGarrett D'Amore p->parent = mdoc->last; 362*95c635efSGarrett D'Amore break; 363*95c635efSGarrett D'Amore default: 364*95c635efSGarrett D'Amore abort(); 365*95c635efSGarrett D'Amore /* NOTREACHED */ 366*95c635efSGarrett D'Amore } 367*95c635efSGarrett D'Amore 368*95c635efSGarrett D'Amore p->parent->nchild++; 369*95c635efSGarrett D'Amore 370*95c635efSGarrett D'Amore /* 371*95c635efSGarrett D'Amore * Copy over the normalised-data pointer of our parent. Not 372*95c635efSGarrett D'Amore * everybody has one, but copying a null pointer is fine. 373*95c635efSGarrett D'Amore */ 374*95c635efSGarrett D'Amore 375*95c635efSGarrett D'Amore switch (p->type) { 376*95c635efSGarrett D'Amore case (MDOC_BODY): 377*95c635efSGarrett D'Amore /* FALLTHROUGH */ 378*95c635efSGarrett D'Amore case (MDOC_TAIL): 379*95c635efSGarrett D'Amore /* FALLTHROUGH */ 380*95c635efSGarrett D'Amore case (MDOC_HEAD): 381*95c635efSGarrett D'Amore p->norm = p->parent->norm; 382*95c635efSGarrett D'Amore break; 383*95c635efSGarrett D'Amore default: 384*95c635efSGarrett D'Amore break; 385*95c635efSGarrett D'Amore } 386*95c635efSGarrett D'Amore 387*95c635efSGarrett D'Amore if ( ! mdoc_valid_pre(mdoc, p)) 388*95c635efSGarrett D'Amore return(0); 389*95c635efSGarrett D'Amore 390*95c635efSGarrett D'Amore switch (p->type) { 391*95c635efSGarrett D'Amore case (MDOC_HEAD): 392*95c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 393*95c635efSGarrett D'Amore p->parent->head = p; 394*95c635efSGarrett D'Amore break; 395*95c635efSGarrett D'Amore case (MDOC_TAIL): 396*95c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 397*95c635efSGarrett D'Amore p->parent->tail = p; 398*95c635efSGarrett D'Amore break; 399*95c635efSGarrett D'Amore case (MDOC_BODY): 400*95c635efSGarrett D'Amore if (p->end) 401*95c635efSGarrett D'Amore break; 402*95c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 403*95c635efSGarrett D'Amore p->parent->body = p; 404*95c635efSGarrett D'Amore break; 405*95c635efSGarrett D'Amore default: 406*95c635efSGarrett D'Amore break; 407*95c635efSGarrett D'Amore } 408*95c635efSGarrett D'Amore 409*95c635efSGarrett D'Amore mdoc->last = p; 410*95c635efSGarrett D'Amore 411*95c635efSGarrett D'Amore switch (p->type) { 412*95c635efSGarrett D'Amore case (MDOC_TBL): 413*95c635efSGarrett D'Amore /* FALLTHROUGH */ 414*95c635efSGarrett D'Amore case (MDOC_TEXT): 415*95c635efSGarrett D'Amore if ( ! mdoc_valid_post(mdoc)) 416*95c635efSGarrett D'Amore return(0); 417*95c635efSGarrett D'Amore break; 418*95c635efSGarrett D'Amore default: 419*95c635efSGarrett D'Amore break; 420*95c635efSGarrett D'Amore } 421*95c635efSGarrett D'Amore 422*95c635efSGarrett D'Amore return(1); 423*95c635efSGarrett D'Amore } 424*95c635efSGarrett D'Amore 425*95c635efSGarrett D'Amore 426*95c635efSGarrett D'Amore static struct mdoc_node * 427*95c635efSGarrett D'Amore node_alloc(struct mdoc *m, int line, int pos, 428*95c635efSGarrett D'Amore enum mdoct tok, enum mdoc_type type) 429*95c635efSGarrett D'Amore { 430*95c635efSGarrett D'Amore struct mdoc_node *p; 431*95c635efSGarrett D'Amore 432*95c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc_node)); 433*95c635efSGarrett D'Amore p->sec = m->lastsec; 434*95c635efSGarrett D'Amore p->line = line; 435*95c635efSGarrett D'Amore p->pos = pos; 436*95c635efSGarrett D'Amore p->tok = tok; 437*95c635efSGarrett D'Amore p->type = type; 438*95c635efSGarrett D'Amore 439*95c635efSGarrett D'Amore /* Flag analysis. */ 440*95c635efSGarrett D'Amore 441*95c635efSGarrett D'Amore if (MDOC_SYNOPSIS & m->flags) 442*95c635efSGarrett D'Amore p->flags |= MDOC_SYNPRETTY; 443*95c635efSGarrett D'Amore else 444*95c635efSGarrett D'Amore p->flags &= ~MDOC_SYNPRETTY; 445*95c635efSGarrett D'Amore if (MDOC_NEWLINE & m->flags) 446*95c635efSGarrett D'Amore p->flags |= MDOC_LINE; 447*95c635efSGarrett D'Amore m->flags &= ~MDOC_NEWLINE; 448*95c635efSGarrett D'Amore 449*95c635efSGarrett D'Amore return(p); 450*95c635efSGarrett D'Amore } 451*95c635efSGarrett D'Amore 452*95c635efSGarrett D'Amore 453*95c635efSGarrett D'Amore int 454*95c635efSGarrett D'Amore mdoc_tail_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) 455*95c635efSGarrett D'Amore { 456*95c635efSGarrett D'Amore struct mdoc_node *p; 457*95c635efSGarrett D'Amore 458*95c635efSGarrett D'Amore p = node_alloc(m, line, pos, tok, MDOC_TAIL); 459*95c635efSGarrett D'Amore if ( ! node_append(m, p)) 460*95c635efSGarrett D'Amore return(0); 461*95c635efSGarrett D'Amore m->next = MDOC_NEXT_CHILD; 462*95c635efSGarrett D'Amore return(1); 463*95c635efSGarrett D'Amore } 464*95c635efSGarrett D'Amore 465*95c635efSGarrett D'Amore 466*95c635efSGarrett D'Amore int 467*95c635efSGarrett D'Amore mdoc_head_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) 468*95c635efSGarrett D'Amore { 469*95c635efSGarrett D'Amore struct mdoc_node *p; 470*95c635efSGarrett D'Amore 471*95c635efSGarrett D'Amore assert(m->first); 472*95c635efSGarrett D'Amore assert(m->last); 473*95c635efSGarrett D'Amore 474*95c635efSGarrett D'Amore p = node_alloc(m, line, pos, tok, MDOC_HEAD); 475*95c635efSGarrett D'Amore if ( ! node_append(m, p)) 476*95c635efSGarrett D'Amore return(0); 477*95c635efSGarrett D'Amore m->next = MDOC_NEXT_CHILD; 478*95c635efSGarrett D'Amore return(1); 479*95c635efSGarrett D'Amore } 480*95c635efSGarrett D'Amore 481*95c635efSGarrett D'Amore 482*95c635efSGarrett D'Amore int 483*95c635efSGarrett D'Amore mdoc_body_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) 484*95c635efSGarrett D'Amore { 485*95c635efSGarrett D'Amore struct mdoc_node *p; 486*95c635efSGarrett D'Amore 487*95c635efSGarrett D'Amore p = node_alloc(m, line, pos, tok, MDOC_BODY); 488*95c635efSGarrett D'Amore if ( ! node_append(m, p)) 489*95c635efSGarrett D'Amore return(0); 490*95c635efSGarrett D'Amore m->next = MDOC_NEXT_CHILD; 491*95c635efSGarrett D'Amore return(1); 492*95c635efSGarrett D'Amore } 493*95c635efSGarrett D'Amore 494*95c635efSGarrett D'Amore 495*95c635efSGarrett D'Amore int 496*95c635efSGarrett D'Amore mdoc_endbody_alloc(struct mdoc *m, int line, int pos, enum mdoct tok, 497*95c635efSGarrett D'Amore struct mdoc_node *body, enum mdoc_endbody end) 498*95c635efSGarrett D'Amore { 499*95c635efSGarrett D'Amore struct mdoc_node *p; 500*95c635efSGarrett D'Amore 501*95c635efSGarrett D'Amore p = node_alloc(m, line, pos, tok, MDOC_BODY); 502*95c635efSGarrett D'Amore p->pending = body; 503*95c635efSGarrett D'Amore p->end = end; 504*95c635efSGarrett D'Amore if ( ! node_append(m, p)) 505*95c635efSGarrett D'Amore return(0); 506*95c635efSGarrett D'Amore m->next = MDOC_NEXT_SIBLING; 507*95c635efSGarrett D'Amore return(1); 508*95c635efSGarrett D'Amore } 509*95c635efSGarrett D'Amore 510*95c635efSGarrett D'Amore 511*95c635efSGarrett D'Amore int 512*95c635efSGarrett D'Amore mdoc_block_alloc(struct mdoc *m, int line, int pos, 513*95c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args) 514*95c635efSGarrett D'Amore { 515*95c635efSGarrett D'Amore struct mdoc_node *p; 516*95c635efSGarrett D'Amore 517*95c635efSGarrett D'Amore p = node_alloc(m, line, pos, tok, MDOC_BLOCK); 518*95c635efSGarrett D'Amore p->args = args; 519*95c635efSGarrett D'Amore if (p->args) 520*95c635efSGarrett D'Amore (args->refcnt)++; 521*95c635efSGarrett D'Amore 522*95c635efSGarrett D'Amore switch (tok) { 523*95c635efSGarrett D'Amore case (MDOC_Bd): 524*95c635efSGarrett D'Amore /* FALLTHROUGH */ 525*95c635efSGarrett D'Amore case (MDOC_Bf): 526*95c635efSGarrett D'Amore /* FALLTHROUGH */ 527*95c635efSGarrett D'Amore case (MDOC_Bl): 528*95c635efSGarrett D'Amore /* FALLTHROUGH */ 529*95c635efSGarrett D'Amore case (MDOC_Rs): 530*95c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); 531*95c635efSGarrett D'Amore break; 532*95c635efSGarrett D'Amore default: 533*95c635efSGarrett D'Amore break; 534*95c635efSGarrett D'Amore } 535*95c635efSGarrett D'Amore 536*95c635efSGarrett D'Amore if ( ! node_append(m, p)) 537*95c635efSGarrett D'Amore return(0); 538*95c635efSGarrett D'Amore m->next = MDOC_NEXT_CHILD; 539*95c635efSGarrett D'Amore return(1); 540*95c635efSGarrett D'Amore } 541*95c635efSGarrett D'Amore 542*95c635efSGarrett D'Amore 543*95c635efSGarrett D'Amore int 544*95c635efSGarrett D'Amore mdoc_elem_alloc(struct mdoc *m, int line, int pos, 545*95c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args) 546*95c635efSGarrett D'Amore { 547*95c635efSGarrett D'Amore struct mdoc_node *p; 548*95c635efSGarrett D'Amore 549*95c635efSGarrett D'Amore p = node_alloc(m, line, pos, tok, MDOC_ELEM); 550*95c635efSGarrett D'Amore p->args = args; 551*95c635efSGarrett D'Amore if (p->args) 552*95c635efSGarrett D'Amore (args->refcnt)++; 553*95c635efSGarrett D'Amore 554*95c635efSGarrett D'Amore switch (tok) { 555*95c635efSGarrett D'Amore case (MDOC_An): 556*95c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); 557*95c635efSGarrett D'Amore break; 558*95c635efSGarrett D'Amore default: 559*95c635efSGarrett D'Amore break; 560*95c635efSGarrett D'Amore } 561*95c635efSGarrett D'Amore 562*95c635efSGarrett D'Amore if ( ! node_append(m, p)) 563*95c635efSGarrett D'Amore return(0); 564*95c635efSGarrett D'Amore m->next = MDOC_NEXT_CHILD; 565*95c635efSGarrett D'Amore return(1); 566*95c635efSGarrett D'Amore } 567*95c635efSGarrett D'Amore 568*95c635efSGarrett D'Amore int 569*95c635efSGarrett D'Amore mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p) 570*95c635efSGarrett D'Amore { 571*95c635efSGarrett D'Amore struct mdoc_node *n; 572*95c635efSGarrett D'Amore 573*95c635efSGarrett D'Amore n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT); 574*95c635efSGarrett D'Amore n->string = roff_strdup(m->roff, p); 575*95c635efSGarrett D'Amore 576*95c635efSGarrett D'Amore if ( ! node_append(m, n)) 577*95c635efSGarrett D'Amore return(0); 578*95c635efSGarrett D'Amore 579*95c635efSGarrett D'Amore m->next = MDOC_NEXT_SIBLING; 580*95c635efSGarrett D'Amore return(1); 581*95c635efSGarrett D'Amore } 582*95c635efSGarrett D'Amore 583*95c635efSGarrett D'Amore 584*95c635efSGarrett D'Amore static void 585*95c635efSGarrett D'Amore mdoc_node_free(struct mdoc_node *p) 586*95c635efSGarrett D'Amore { 587*95c635efSGarrett D'Amore 588*95c635efSGarrett D'Amore if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type) 589*95c635efSGarrett D'Amore free(p->norm); 590*95c635efSGarrett D'Amore if (p->string) 591*95c635efSGarrett D'Amore free(p->string); 592*95c635efSGarrett D'Amore if (p->args) 593*95c635efSGarrett D'Amore mdoc_argv_free(p->args); 594*95c635efSGarrett D'Amore free(p); 595*95c635efSGarrett D'Amore } 596*95c635efSGarrett D'Amore 597*95c635efSGarrett D'Amore 598*95c635efSGarrett D'Amore static void 599*95c635efSGarrett D'Amore mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n) 600*95c635efSGarrett D'Amore { 601*95c635efSGarrett D'Amore 602*95c635efSGarrett D'Amore /* Adjust siblings. */ 603*95c635efSGarrett D'Amore 604*95c635efSGarrett D'Amore if (n->prev) 605*95c635efSGarrett D'Amore n->prev->next = n->next; 606*95c635efSGarrett D'Amore if (n->next) 607*95c635efSGarrett D'Amore n->next->prev = n->prev; 608*95c635efSGarrett D'Amore 609*95c635efSGarrett D'Amore /* Adjust parent. */ 610*95c635efSGarrett D'Amore 611*95c635efSGarrett D'Amore if (n->parent) { 612*95c635efSGarrett D'Amore n->parent->nchild--; 613*95c635efSGarrett D'Amore if (n->parent->child == n) 614*95c635efSGarrett D'Amore n->parent->child = n->prev ? n->prev : n->next; 615*95c635efSGarrett D'Amore if (n->parent->last == n) 616*95c635efSGarrett D'Amore n->parent->last = n->prev ? n->prev : NULL; 617*95c635efSGarrett D'Amore } 618*95c635efSGarrett D'Amore 619*95c635efSGarrett D'Amore /* Adjust parse point, if applicable. */ 620*95c635efSGarrett D'Amore 621*95c635efSGarrett D'Amore if (m && m->last == n) { 622*95c635efSGarrett D'Amore if (n->prev) { 623*95c635efSGarrett D'Amore m->last = n->prev; 624*95c635efSGarrett D'Amore m->next = MDOC_NEXT_SIBLING; 625*95c635efSGarrett D'Amore } else { 626*95c635efSGarrett D'Amore m->last = n->parent; 627*95c635efSGarrett D'Amore m->next = MDOC_NEXT_CHILD; 628*95c635efSGarrett D'Amore } 629*95c635efSGarrett D'Amore } 630*95c635efSGarrett D'Amore 631*95c635efSGarrett D'Amore if (m && m->first == n) 632*95c635efSGarrett D'Amore m->first = NULL; 633*95c635efSGarrett D'Amore } 634*95c635efSGarrett D'Amore 635*95c635efSGarrett D'Amore 636*95c635efSGarrett D'Amore void 637*95c635efSGarrett D'Amore mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) 638*95c635efSGarrett D'Amore { 639*95c635efSGarrett D'Amore 640*95c635efSGarrett D'Amore while (p->child) { 641*95c635efSGarrett D'Amore assert(p->nchild); 642*95c635efSGarrett D'Amore mdoc_node_delete(m, p->child); 643*95c635efSGarrett D'Amore } 644*95c635efSGarrett D'Amore assert(0 == p->nchild); 645*95c635efSGarrett D'Amore 646*95c635efSGarrett D'Amore mdoc_node_unlink(m, p); 647*95c635efSGarrett D'Amore mdoc_node_free(p); 648*95c635efSGarrett D'Amore } 649*95c635efSGarrett D'Amore 650*95c635efSGarrett D'Amore #if 0 651*95c635efSGarrett D'Amore /* 652*95c635efSGarrett D'Amore * Pre-treat a text line. 653*95c635efSGarrett D'Amore * Text lines can consist of equations, which must be handled apart from 654*95c635efSGarrett D'Amore * the regular text. 655*95c635efSGarrett D'Amore * Thus, use this function to step through a line checking if it has any 656*95c635efSGarrett D'Amore * equations embedded in it. 657*95c635efSGarrett D'Amore * This must handle multiple equations AND equations that do not end at 658*95c635efSGarrett D'Amore * the end-of-line, i.e., will re-enter in the next roff parse. 659*95c635efSGarrett D'Amore */ 660*95c635efSGarrett D'Amore static int 661*95c635efSGarrett D'Amore mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) 662*95c635efSGarrett D'Amore { 663*95c635efSGarrett D'Amore char *start, *end; 664*95c635efSGarrett D'Amore char delim; 665*95c635efSGarrett D'Amore 666*95c635efSGarrett D'Amore while ('\0' != buf[offs]) { 667*95c635efSGarrett D'Amore /* Mark starting position if eqn is set. */ 668*95c635efSGarrett D'Amore start = NULL; 669*95c635efSGarrett D'Amore if ('\0' != (delim = roff_eqndelim(m->roff))) 670*95c635efSGarrett D'Amore if (NULL != (start = strchr(buf + offs, delim))) 671*95c635efSGarrett D'Amore *start++ = '\0'; 672*95c635efSGarrett D'Amore 673*95c635efSGarrett D'Amore /* Parse text as normal. */ 674*95c635efSGarrett D'Amore if ( ! mdoc_ptext(m, line, buf, offs)) 675*95c635efSGarrett D'Amore return(0); 676*95c635efSGarrett D'Amore 677*95c635efSGarrett D'Amore /* Continue only if an equation exists. */ 678*95c635efSGarrett D'Amore if (NULL == start) 679*95c635efSGarrett D'Amore break; 680*95c635efSGarrett D'Amore 681*95c635efSGarrett D'Amore /* Read past the end of the equation. */ 682*95c635efSGarrett D'Amore offs += start - (buf + offs); 683*95c635efSGarrett D'Amore assert(start == &buf[offs]); 684*95c635efSGarrett D'Amore if (NULL != (end = strchr(buf + offs, delim))) { 685*95c635efSGarrett D'Amore *end++ = '\0'; 686*95c635efSGarrett D'Amore while (' ' == *end) 687*95c635efSGarrett D'Amore end++; 688*95c635efSGarrett D'Amore } 689*95c635efSGarrett D'Amore 690*95c635efSGarrett D'Amore /* Parse the equation itself. */ 691*95c635efSGarrett D'Amore roff_openeqn(m->roff, NULL, line, offs, buf); 692*95c635efSGarrett D'Amore 693*95c635efSGarrett D'Amore /* Process a finished equation? */ 694*95c635efSGarrett D'Amore if (roff_closeeqn(m->roff)) 695*95c635efSGarrett D'Amore if ( ! mdoc_addeqn(m, roff_eqn(m->roff))) 696*95c635efSGarrett D'Amore return(0); 697*95c635efSGarrett D'Amore offs += (end - (buf + offs)); 698*95c635efSGarrett D'Amore } 699*95c635efSGarrett D'Amore 700*95c635efSGarrett D'Amore return(1); 701*95c635efSGarrett D'Amore } 702*95c635efSGarrett D'Amore #endif 703*95c635efSGarrett D'Amore 704*95c635efSGarrett D'Amore /* 705*95c635efSGarrett D'Amore * Parse free-form text, that is, a line that does not begin with the 706*95c635efSGarrett D'Amore * control character. 707*95c635efSGarrett D'Amore */ 708*95c635efSGarrett D'Amore static int 709*95c635efSGarrett D'Amore mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) 710*95c635efSGarrett D'Amore { 711*95c635efSGarrett D'Amore char *c, *ws, *end; 712*95c635efSGarrett D'Amore struct mdoc_node *n; 713*95c635efSGarrett D'Amore 714*95c635efSGarrett D'Amore /* No text before an initial macro. */ 715*95c635efSGarrett D'Amore 716*95c635efSGarrett D'Amore if (SEC_NONE == m->lastnamed) { 717*95c635efSGarrett D'Amore mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT); 718*95c635efSGarrett D'Amore return(1); 719*95c635efSGarrett D'Amore } 720*95c635efSGarrett D'Amore 721*95c635efSGarrett D'Amore assert(m->last); 722*95c635efSGarrett D'Amore n = m->last; 723*95c635efSGarrett D'Amore 724*95c635efSGarrett D'Amore /* 725*95c635efSGarrett D'Amore * Divert directly to list processing if we're encountering a 726*95c635efSGarrett D'Amore * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry 727*95c635efSGarrett D'Amore * (a MDOC_BODY means it's already open, in which case we should 728*95c635efSGarrett D'Amore * process within its context in the normal way). 729*95c635efSGarrett D'Amore */ 730*95c635efSGarrett D'Amore 731*95c635efSGarrett D'Amore if (MDOC_Bl == n->tok && MDOC_BODY == n->type && 732*95c635efSGarrett D'Amore LIST_column == n->norm->Bl.type) { 733*95c635efSGarrett D'Amore /* `Bl' is open without any children. */ 734*95c635efSGarrett D'Amore m->flags |= MDOC_FREECOL; 735*95c635efSGarrett D'Amore return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); 736*95c635efSGarrett D'Amore } 737*95c635efSGarrett D'Amore 738*95c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type && 739*95c635efSGarrett D'Amore NULL != n->parent && 740*95c635efSGarrett D'Amore MDOC_Bl == n->parent->tok && 741*95c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) { 742*95c635efSGarrett D'Amore /* `Bl' has block-level `It' children. */ 743*95c635efSGarrett D'Amore m->flags |= MDOC_FREECOL; 744*95c635efSGarrett D'Amore return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); 745*95c635efSGarrett D'Amore } 746*95c635efSGarrett D'Amore 747*95c635efSGarrett D'Amore /* 748*95c635efSGarrett D'Amore * Search for the beginning of unescaped trailing whitespace (ws) 749*95c635efSGarrett D'Amore * and for the first character not to be output (end). 750*95c635efSGarrett D'Amore */ 751*95c635efSGarrett D'Amore 752*95c635efSGarrett D'Amore /* FIXME: replace with strcspn(). */ 753*95c635efSGarrett D'Amore ws = NULL; 754*95c635efSGarrett D'Amore for (c = end = buf + offs; *c; c++) { 755*95c635efSGarrett D'Amore switch (*c) { 756*95c635efSGarrett D'Amore case ' ': 757*95c635efSGarrett D'Amore if (NULL == ws) 758*95c635efSGarrett D'Amore ws = c; 759*95c635efSGarrett D'Amore continue; 760*95c635efSGarrett D'Amore case '\t': 761*95c635efSGarrett D'Amore /* 762*95c635efSGarrett D'Amore * Always warn about trailing tabs, 763*95c635efSGarrett D'Amore * even outside literal context, 764*95c635efSGarrett D'Amore * where they should be put on the next line. 765*95c635efSGarrett D'Amore */ 766*95c635efSGarrett D'Amore if (NULL == ws) 767*95c635efSGarrett D'Amore ws = c; 768*95c635efSGarrett D'Amore /* 769*95c635efSGarrett D'Amore * Strip trailing tabs in literal context only; 770*95c635efSGarrett D'Amore * outside, they affect the next line. 771*95c635efSGarrett D'Amore */ 772*95c635efSGarrett D'Amore if (MDOC_LITERAL & m->flags) 773*95c635efSGarrett D'Amore continue; 774*95c635efSGarrett D'Amore break; 775*95c635efSGarrett D'Amore case '\\': 776*95c635efSGarrett D'Amore /* Skip the escaped character, too, if any. */ 777*95c635efSGarrett D'Amore if (c[1]) 778*95c635efSGarrett D'Amore c++; 779*95c635efSGarrett D'Amore /* FALLTHROUGH */ 780*95c635efSGarrett D'Amore default: 781*95c635efSGarrett D'Amore ws = NULL; 782*95c635efSGarrett D'Amore break; 783*95c635efSGarrett D'Amore } 784*95c635efSGarrett D'Amore end = c + 1; 785*95c635efSGarrett D'Amore } 786*95c635efSGarrett D'Amore *end = '\0'; 787*95c635efSGarrett D'Amore 788*95c635efSGarrett D'Amore if (ws) 789*95c635efSGarrett D'Amore mdoc_pmsg(m, line, (int)(ws-buf), MANDOCERR_EOLNSPACE); 790*95c635efSGarrett D'Amore 791*95c635efSGarrett D'Amore if ('\0' == buf[offs] && ! (MDOC_LITERAL & m->flags)) { 792*95c635efSGarrett D'Amore mdoc_pmsg(m, line, (int)(c-buf), MANDOCERR_NOBLANKLN); 793*95c635efSGarrett D'Amore 794*95c635efSGarrett D'Amore /* 795*95c635efSGarrett D'Amore * Insert a `sp' in the case of a blank line. Technically, 796*95c635efSGarrett D'Amore * blank lines aren't allowed, but enough manuals assume this 797*95c635efSGarrett D'Amore * behaviour that we want to work around it. 798*95c635efSGarrett D'Amore */ 799*95c635efSGarrett D'Amore if ( ! mdoc_elem_alloc(m, line, offs, MDOC_sp, NULL)) 800*95c635efSGarrett D'Amore return(0); 801*95c635efSGarrett D'Amore 802*95c635efSGarrett D'Amore m->next = MDOC_NEXT_SIBLING; 803*95c635efSGarrett D'Amore return(1); 804*95c635efSGarrett D'Amore } 805*95c635efSGarrett D'Amore 806*95c635efSGarrett D'Amore if ( ! mdoc_word_alloc(m, line, offs, buf+offs)) 807*95c635efSGarrett D'Amore return(0); 808*95c635efSGarrett D'Amore 809*95c635efSGarrett D'Amore if (MDOC_LITERAL & m->flags) 810*95c635efSGarrett D'Amore return(1); 811*95c635efSGarrett D'Amore 812*95c635efSGarrett D'Amore /* 813*95c635efSGarrett D'Amore * End-of-sentence check. If the last character is an unescaped 814*95c635efSGarrett D'Amore * EOS character, then flag the node as being the end of a 815*95c635efSGarrett D'Amore * sentence. The front-end will know how to interpret this. 816*95c635efSGarrett D'Amore */ 817*95c635efSGarrett D'Amore 818*95c635efSGarrett D'Amore assert(buf < end); 819*95c635efSGarrett D'Amore 820*95c635efSGarrett D'Amore if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0)) 821*95c635efSGarrett D'Amore m->last->flags |= MDOC_EOS; 822*95c635efSGarrett D'Amore 823*95c635efSGarrett D'Amore return(1); 824*95c635efSGarrett D'Amore } 825*95c635efSGarrett D'Amore 826*95c635efSGarrett D'Amore 827*95c635efSGarrett D'Amore /* 828*95c635efSGarrett D'Amore * Parse a macro line, that is, a line beginning with the control 829*95c635efSGarrett D'Amore * character. 830*95c635efSGarrett D'Amore */ 831*95c635efSGarrett D'Amore static int 832*95c635efSGarrett D'Amore mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) 833*95c635efSGarrett D'Amore { 834*95c635efSGarrett D'Amore enum mdoct tok; 835*95c635efSGarrett D'Amore int i, sv; 836*95c635efSGarrett D'Amore char mac[5]; 837*95c635efSGarrett D'Amore struct mdoc_node *n; 838*95c635efSGarrett D'Amore 839*95c635efSGarrett D'Amore /* Empty post-control lines are ignored. */ 840*95c635efSGarrett D'Amore 841*95c635efSGarrett D'Amore if ('"' == buf[offs]) { 842*95c635efSGarrett D'Amore mdoc_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); 843*95c635efSGarrett D'Amore return(1); 844*95c635efSGarrett D'Amore } else if ('\0' == buf[offs]) 845*95c635efSGarrett D'Amore return(1); 846*95c635efSGarrett D'Amore 847*95c635efSGarrett D'Amore sv = offs; 848*95c635efSGarrett D'Amore 849*95c635efSGarrett D'Amore /* 850*95c635efSGarrett D'Amore * Copy the first word into a nil-terminated buffer. 851*95c635efSGarrett D'Amore * Stop copying when a tab, space, or eoln is encountered. 852*95c635efSGarrett D'Amore */ 853*95c635efSGarrett D'Amore 854*95c635efSGarrett D'Amore i = 0; 855*95c635efSGarrett D'Amore while (i < 4 && '\0' != buf[offs] && 856*95c635efSGarrett D'Amore ' ' != buf[offs] && '\t' != buf[offs]) 857*95c635efSGarrett D'Amore mac[i++] = buf[offs++]; 858*95c635efSGarrett D'Amore 859*95c635efSGarrett D'Amore mac[i] = '\0'; 860*95c635efSGarrett D'Amore 861*95c635efSGarrett D'Amore tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX; 862*95c635efSGarrett D'Amore 863*95c635efSGarrett D'Amore if (MDOC_MAX == tok) { 864*95c635efSGarrett D'Amore mandoc_vmsg(MANDOCERR_MACRO, m->parse, 865*95c635efSGarrett D'Amore ln, sv, "%s", buf + sv - 1); 866*95c635efSGarrett D'Amore return(1); 867*95c635efSGarrett D'Amore } 868*95c635efSGarrett D'Amore 869*95c635efSGarrett D'Amore /* Disregard the first trailing tab, if applicable. */ 870*95c635efSGarrett D'Amore 871*95c635efSGarrett D'Amore if ('\t' == buf[offs]) 872*95c635efSGarrett D'Amore offs++; 873*95c635efSGarrett D'Amore 874*95c635efSGarrett D'Amore /* Jump to the next non-whitespace word. */ 875*95c635efSGarrett D'Amore 876*95c635efSGarrett D'Amore while (buf[offs] && ' ' == buf[offs]) 877*95c635efSGarrett D'Amore offs++; 878*95c635efSGarrett D'Amore 879*95c635efSGarrett D'Amore /* 880*95c635efSGarrett D'Amore * Trailing whitespace. Note that tabs are allowed to be passed 881*95c635efSGarrett D'Amore * into the parser as "text", so we only warn about spaces here. 882*95c635efSGarrett D'Amore */ 883*95c635efSGarrett D'Amore 884*95c635efSGarrett D'Amore if ('\0' == buf[offs] && ' ' == buf[offs - 1]) 885*95c635efSGarrett D'Amore mdoc_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); 886*95c635efSGarrett D'Amore 887*95c635efSGarrett D'Amore /* 888*95c635efSGarrett D'Amore * If an initial macro or a list invocation, divert directly 889*95c635efSGarrett D'Amore * into macro processing. 890*95c635efSGarrett D'Amore */ 891*95c635efSGarrett D'Amore 892*95c635efSGarrett D'Amore if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) { 893*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) 894*95c635efSGarrett D'Amore goto err; 895*95c635efSGarrett D'Amore return(1); 896*95c635efSGarrett D'Amore } 897*95c635efSGarrett D'Amore 898*95c635efSGarrett D'Amore n = m->last; 899*95c635efSGarrett D'Amore assert(m->last); 900*95c635efSGarrett D'Amore 901*95c635efSGarrett D'Amore /* 902*95c635efSGarrett D'Amore * If the first macro of a `Bl -column', open an `It' block 903*95c635efSGarrett D'Amore * context around the parsed macro. 904*95c635efSGarrett D'Amore */ 905*95c635efSGarrett D'Amore 906*95c635efSGarrett D'Amore if (MDOC_Bl == n->tok && MDOC_BODY == n->type && 907*95c635efSGarrett D'Amore LIST_column == n->norm->Bl.type) { 908*95c635efSGarrett D'Amore m->flags |= MDOC_FREECOL; 909*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) 910*95c635efSGarrett D'Amore goto err; 911*95c635efSGarrett D'Amore return(1); 912*95c635efSGarrett D'Amore } 913*95c635efSGarrett D'Amore 914*95c635efSGarrett D'Amore /* 915*95c635efSGarrett D'Amore * If we're following a block-level `It' within a `Bl -column' 916*95c635efSGarrett D'Amore * context (perhaps opened in the above block or in ptext()), 917*95c635efSGarrett D'Amore * then open an `It' block context around the parsed macro. 918*95c635efSGarrett D'Amore */ 919*95c635efSGarrett D'Amore 920*95c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type && 921*95c635efSGarrett D'Amore NULL != n->parent && 922*95c635efSGarrett D'Amore MDOC_Bl == n->parent->tok && 923*95c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) { 924*95c635efSGarrett D'Amore m->flags |= MDOC_FREECOL; 925*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) 926*95c635efSGarrett D'Amore goto err; 927*95c635efSGarrett D'Amore return(1); 928*95c635efSGarrett D'Amore } 929*95c635efSGarrett D'Amore 930*95c635efSGarrett D'Amore /* Normal processing of a macro. */ 931*95c635efSGarrett D'Amore 932*95c635efSGarrett D'Amore if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) 933*95c635efSGarrett D'Amore goto err; 934*95c635efSGarrett D'Amore 935*95c635efSGarrett D'Amore return(1); 936*95c635efSGarrett D'Amore 937*95c635efSGarrett D'Amore err: /* Error out. */ 938*95c635efSGarrett D'Amore 939*95c635efSGarrett D'Amore m->flags |= MDOC_HALT; 940*95c635efSGarrett D'Amore return(0); 941*95c635efSGarrett D'Amore } 942*95c635efSGarrett D'Amore 943*95c635efSGarrett D'Amore enum mdelim 944*95c635efSGarrett D'Amore mdoc_isdelim(const char *p) 945*95c635efSGarrett D'Amore { 946*95c635efSGarrett D'Amore 947*95c635efSGarrett D'Amore if ('\0' == p[0]) 948*95c635efSGarrett D'Amore return(DELIM_NONE); 949*95c635efSGarrett D'Amore 950*95c635efSGarrett D'Amore if ('\0' == p[1]) 951*95c635efSGarrett D'Amore switch (p[0]) { 952*95c635efSGarrett D'Amore case('('): 953*95c635efSGarrett D'Amore /* FALLTHROUGH */ 954*95c635efSGarrett D'Amore case('['): 955*95c635efSGarrett D'Amore return(DELIM_OPEN); 956*95c635efSGarrett D'Amore case('|'): 957*95c635efSGarrett D'Amore return(DELIM_MIDDLE); 958*95c635efSGarrett D'Amore case('.'): 959*95c635efSGarrett D'Amore /* FALLTHROUGH */ 960*95c635efSGarrett D'Amore case(','): 961*95c635efSGarrett D'Amore /* FALLTHROUGH */ 962*95c635efSGarrett D'Amore case(';'): 963*95c635efSGarrett D'Amore /* FALLTHROUGH */ 964*95c635efSGarrett D'Amore case(':'): 965*95c635efSGarrett D'Amore /* FALLTHROUGH */ 966*95c635efSGarrett D'Amore case('?'): 967*95c635efSGarrett D'Amore /* FALLTHROUGH */ 968*95c635efSGarrett D'Amore case('!'): 969*95c635efSGarrett D'Amore /* FALLTHROUGH */ 970*95c635efSGarrett D'Amore case(')'): 971*95c635efSGarrett D'Amore /* FALLTHROUGH */ 972*95c635efSGarrett D'Amore case(']'): 973*95c635efSGarrett D'Amore return(DELIM_CLOSE); 974*95c635efSGarrett D'Amore default: 975*95c635efSGarrett D'Amore return(DELIM_NONE); 976*95c635efSGarrett D'Amore } 977*95c635efSGarrett D'Amore 978*95c635efSGarrett D'Amore if ('\\' != p[0]) 979*95c635efSGarrett D'Amore return(DELIM_NONE); 980*95c635efSGarrett D'Amore 981*95c635efSGarrett D'Amore if (0 == strcmp(p + 1, ".")) 982*95c635efSGarrett D'Amore return(DELIM_CLOSE); 983*95c635efSGarrett D'Amore if (0 == strcmp(p + 1, "*(Ba")) 984*95c635efSGarrett D'Amore return(DELIM_MIDDLE); 985*95c635efSGarrett D'Amore 986*95c635efSGarrett D'Amore return(DELIM_NONE); 987*95c635efSGarrett D'Amore } 988