1*698f87a4SGarrett D'Amore /* $Id: mdoc.c,v 1.206 2013/12/24 19:11:46 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*698f87a4SGarrett D'Amore * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 1995c635efSGarrett D'Amore #include "config.h" 2095c635efSGarrett D'Amore #endif 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <sys/types.h> 2395c635efSGarrett D'Amore 2495c635efSGarrett D'Amore #include <assert.h> 2595c635efSGarrett D'Amore #include <stdarg.h> 2695c635efSGarrett D'Amore #include <stdio.h> 2795c635efSGarrett D'Amore #include <stdlib.h> 2895c635efSGarrett D'Amore #include <string.h> 2995c635efSGarrett D'Amore #include <time.h> 3095c635efSGarrett D'Amore 3195c635efSGarrett D'Amore #include "mdoc.h" 3295c635efSGarrett D'Amore #include "mandoc.h" 3395c635efSGarrett D'Amore #include "libmdoc.h" 3495c635efSGarrett D'Amore #include "libmandoc.h" 3595c635efSGarrett D'Amore 3695c635efSGarrett D'Amore const char *const __mdoc_macronames[MDOC_MAX] = { 3795c635efSGarrett D'Amore "Ap", "Dd", "Dt", "Os", 3895c635efSGarrett D'Amore "Sh", "Ss", "Pp", "D1", 3995c635efSGarrett D'Amore "Dl", "Bd", "Ed", "Bl", 4095c635efSGarrett D'Amore "El", "It", "Ad", "An", 4195c635efSGarrett D'Amore "Ar", "Cd", "Cm", "Dv", 4295c635efSGarrett D'Amore "Er", "Ev", "Ex", "Fa", 4395c635efSGarrett D'Amore "Fd", "Fl", "Fn", "Ft", 4495c635efSGarrett D'Amore "Ic", "In", "Li", "Nd", 4595c635efSGarrett D'Amore "Nm", "Op", "Ot", "Pa", 4695c635efSGarrett D'Amore "Rv", "St", "Va", "Vt", 4795c635efSGarrett D'Amore /* LINTED */ 4895c635efSGarrett D'Amore "Xr", "%A", "%B", "%D", 4995c635efSGarrett D'Amore /* LINTED */ 5095c635efSGarrett D'Amore "%I", "%J", "%N", "%O", 5195c635efSGarrett D'Amore /* LINTED */ 5295c635efSGarrett D'Amore "%P", "%R", "%T", "%V", 5395c635efSGarrett D'Amore "Ac", "Ao", "Aq", "At", 5495c635efSGarrett D'Amore "Bc", "Bf", "Bo", "Bq", 5595c635efSGarrett D'Amore "Bsx", "Bx", "Db", "Dc", 5695c635efSGarrett D'Amore "Do", "Dq", "Ec", "Ef", 5795c635efSGarrett D'Amore "Em", "Eo", "Fx", "Ms", 5895c635efSGarrett D'Amore "No", "Ns", "Nx", "Ox", 5995c635efSGarrett D'Amore "Pc", "Pf", "Po", "Pq", 6095c635efSGarrett D'Amore "Qc", "Ql", "Qo", "Qq", 6195c635efSGarrett D'Amore "Re", "Rs", "Sc", "So", 6295c635efSGarrett D'Amore "Sq", "Sm", "Sx", "Sy", 6395c635efSGarrett D'Amore "Tn", "Ux", "Xc", "Xo", 6495c635efSGarrett D'Amore "Fo", "Fc", "Oo", "Oc", 6595c635efSGarrett D'Amore "Bk", "Ek", "Bt", "Hf", 6695c635efSGarrett D'Amore "Fr", "Ud", "Lb", "Lp", 6795c635efSGarrett D'Amore "Lk", "Mt", "Brq", "Bro", 6895c635efSGarrett D'Amore /* LINTED */ 6995c635efSGarrett D'Amore "Brc", "%C", "Es", "En", 7095c635efSGarrett D'Amore /* LINTED */ 7195c635efSGarrett D'Amore "Dx", "%Q", "br", "sp", 7295c635efSGarrett D'Amore /* LINTED */ 7395c635efSGarrett D'Amore "%U", "Ta" 7495c635efSGarrett D'Amore }; 7595c635efSGarrett D'Amore 7695c635efSGarrett D'Amore const char *const __mdoc_argnames[MDOC_ARG_MAX] = { 7795c635efSGarrett D'Amore "split", "nosplit", "ragged", 7895c635efSGarrett D'Amore "unfilled", "literal", "file", 7995c635efSGarrett D'Amore "offset", "bullet", "dash", 8095c635efSGarrett D'Amore "hyphen", "item", "enum", 8195c635efSGarrett D'Amore "tag", "diag", "hang", 8295c635efSGarrett D'Amore "ohang", "inset", "column", 8395c635efSGarrett D'Amore "width", "compact", "std", 8495c635efSGarrett D'Amore "filled", "words", "emphasis", 8595c635efSGarrett D'Amore "symbolic", "nested", "centered" 8695c635efSGarrett D'Amore }; 8795c635efSGarrett D'Amore 8895c635efSGarrett D'Amore const char * const *mdoc_macronames = __mdoc_macronames; 8995c635efSGarrett D'Amore const char * const *mdoc_argnames = __mdoc_argnames; 9095c635efSGarrett D'Amore 9195c635efSGarrett D'Amore static void mdoc_node_free(struct mdoc_node *); 9295c635efSGarrett D'Amore static void mdoc_node_unlink(struct mdoc *, 9395c635efSGarrett D'Amore struct mdoc_node *); 9495c635efSGarrett D'Amore static void mdoc_free1(struct mdoc *); 9595c635efSGarrett D'Amore static void mdoc_alloc1(struct mdoc *); 9695c635efSGarrett D'Amore static struct mdoc_node *node_alloc(struct mdoc *, int, int, 9795c635efSGarrett D'Amore enum mdoct, enum mdoc_type); 9895c635efSGarrett D'Amore static int node_append(struct mdoc *, 9995c635efSGarrett D'Amore struct mdoc_node *); 10095c635efSGarrett D'Amore #if 0 10195c635efSGarrett D'Amore static int mdoc_preptext(struct mdoc *, int, char *, int); 10295c635efSGarrett D'Amore #endif 10395c635efSGarrett D'Amore static int mdoc_ptext(struct mdoc *, int, char *, int); 10495c635efSGarrett D'Amore static int mdoc_pmacro(struct mdoc *, int, char *, int); 10595c635efSGarrett D'Amore 10695c635efSGarrett D'Amore const struct mdoc_node * 107*698f87a4SGarrett D'Amore mdoc_node(const struct mdoc *mdoc) 10895c635efSGarrett D'Amore { 10995c635efSGarrett D'Amore 110*698f87a4SGarrett D'Amore assert( ! (MDOC_HALT & mdoc->flags)); 111*698f87a4SGarrett D'Amore return(mdoc->first); 11295c635efSGarrett D'Amore } 11395c635efSGarrett D'Amore 11495c635efSGarrett D'Amore 11595c635efSGarrett D'Amore const struct mdoc_meta * 116*698f87a4SGarrett D'Amore mdoc_meta(const struct mdoc *mdoc) 11795c635efSGarrett D'Amore { 11895c635efSGarrett D'Amore 119*698f87a4SGarrett D'Amore assert( ! (MDOC_HALT & mdoc->flags)); 120*698f87a4SGarrett D'Amore return(&mdoc->meta); 12195c635efSGarrett D'Amore } 12295c635efSGarrett D'Amore 12395c635efSGarrett D'Amore 12495c635efSGarrett D'Amore /* 12595c635efSGarrett D'Amore * Frees volatile resources (parse tree, meta-data, fields). 12695c635efSGarrett D'Amore */ 12795c635efSGarrett D'Amore static void 12895c635efSGarrett D'Amore mdoc_free1(struct mdoc *mdoc) 12995c635efSGarrett D'Amore { 13095c635efSGarrett D'Amore 13195c635efSGarrett D'Amore if (mdoc->first) 13295c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->first); 13395c635efSGarrett D'Amore if (mdoc->meta.title) 13495c635efSGarrett D'Amore free(mdoc->meta.title); 13595c635efSGarrett D'Amore if (mdoc->meta.os) 13695c635efSGarrett D'Amore free(mdoc->meta.os); 13795c635efSGarrett D'Amore if (mdoc->meta.name) 13895c635efSGarrett D'Amore free(mdoc->meta.name); 13995c635efSGarrett D'Amore if (mdoc->meta.arch) 14095c635efSGarrett D'Amore free(mdoc->meta.arch); 14195c635efSGarrett D'Amore if (mdoc->meta.vol) 14295c635efSGarrett D'Amore free(mdoc->meta.vol); 14395c635efSGarrett D'Amore if (mdoc->meta.msec) 14495c635efSGarrett D'Amore free(mdoc->meta.msec); 14595c635efSGarrett D'Amore if (mdoc->meta.date) 14695c635efSGarrett D'Amore free(mdoc->meta.date); 14795c635efSGarrett D'Amore } 14895c635efSGarrett D'Amore 14995c635efSGarrett D'Amore 15095c635efSGarrett D'Amore /* 15195c635efSGarrett D'Amore * Allocate all volatile resources (parse tree, meta-data, fields). 15295c635efSGarrett D'Amore */ 15395c635efSGarrett D'Amore static void 15495c635efSGarrett D'Amore mdoc_alloc1(struct mdoc *mdoc) 15595c635efSGarrett D'Amore { 15695c635efSGarrett D'Amore 15795c635efSGarrett D'Amore memset(&mdoc->meta, 0, sizeof(struct mdoc_meta)); 15895c635efSGarrett D'Amore mdoc->flags = 0; 15995c635efSGarrett D'Amore mdoc->lastnamed = mdoc->lastsec = SEC_NONE; 16095c635efSGarrett D'Amore mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node)); 16195c635efSGarrett D'Amore mdoc->first = mdoc->last; 16295c635efSGarrett D'Amore mdoc->last->type = MDOC_ROOT; 16395c635efSGarrett D'Amore mdoc->last->tok = MDOC_MAX; 16495c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 16595c635efSGarrett D'Amore } 16695c635efSGarrett D'Amore 16795c635efSGarrett D'Amore 16895c635efSGarrett D'Amore /* 16995c635efSGarrett D'Amore * Free up volatile resources (see mdoc_free1()) then re-initialises the 17095c635efSGarrett D'Amore * data with mdoc_alloc1(). After invocation, parse data has been reset 17195c635efSGarrett D'Amore * and the parser is ready for re-invocation on a new tree; however, 17295c635efSGarrett D'Amore * cross-parse non-volatile data is kept intact. 17395c635efSGarrett D'Amore */ 17495c635efSGarrett D'Amore void 17595c635efSGarrett D'Amore mdoc_reset(struct mdoc *mdoc) 17695c635efSGarrett D'Amore { 17795c635efSGarrett D'Amore 17895c635efSGarrett D'Amore mdoc_free1(mdoc); 17995c635efSGarrett D'Amore mdoc_alloc1(mdoc); 18095c635efSGarrett D'Amore } 18195c635efSGarrett D'Amore 18295c635efSGarrett D'Amore 18395c635efSGarrett D'Amore /* 18495c635efSGarrett D'Amore * Completely free up all volatile and non-volatile parse resources. 18595c635efSGarrett D'Amore * After invocation, the pointer is no longer usable. 18695c635efSGarrett D'Amore */ 18795c635efSGarrett D'Amore void 18895c635efSGarrett D'Amore mdoc_free(struct mdoc *mdoc) 18995c635efSGarrett D'Amore { 19095c635efSGarrett D'Amore 19195c635efSGarrett D'Amore mdoc_free1(mdoc); 19295c635efSGarrett D'Amore free(mdoc); 19395c635efSGarrett D'Amore } 19495c635efSGarrett D'Amore 19595c635efSGarrett D'Amore 19695c635efSGarrett D'Amore /* 19795c635efSGarrett D'Amore * Allocate volatile and non-volatile parse resources. 19895c635efSGarrett D'Amore */ 19995c635efSGarrett D'Amore struct mdoc * 200*698f87a4SGarrett D'Amore mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos) 20195c635efSGarrett D'Amore { 20295c635efSGarrett D'Amore struct mdoc *p; 20395c635efSGarrett D'Amore 20495c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc)); 20595c635efSGarrett D'Amore 20695c635efSGarrett D'Amore p->parse = parse; 207*698f87a4SGarrett D'Amore p->defos = defos; 20895c635efSGarrett D'Amore p->roff = roff; 20995c635efSGarrett D'Amore 21095c635efSGarrett D'Amore mdoc_hash_init(); 21195c635efSGarrett D'Amore mdoc_alloc1(p); 21295c635efSGarrett D'Amore return(p); 21395c635efSGarrett D'Amore } 21495c635efSGarrett D'Amore 21595c635efSGarrett D'Amore 21695c635efSGarrett D'Amore /* 21795c635efSGarrett D'Amore * Climb back up the parse tree, validating open scopes. Mostly calls 21895c635efSGarrett D'Amore * through to macro_end() in macro.c. 21995c635efSGarrett D'Amore */ 22095c635efSGarrett D'Amore int 221*698f87a4SGarrett D'Amore mdoc_endparse(struct mdoc *mdoc) 22295c635efSGarrett D'Amore { 22395c635efSGarrett D'Amore 224*698f87a4SGarrett D'Amore assert( ! (MDOC_HALT & mdoc->flags)); 225*698f87a4SGarrett D'Amore if (mdoc_macroend(mdoc)) 22695c635efSGarrett D'Amore return(1); 227*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_HALT; 22895c635efSGarrett D'Amore return(0); 22995c635efSGarrett D'Amore } 23095c635efSGarrett D'Amore 23195c635efSGarrett D'Amore int 232*698f87a4SGarrett D'Amore mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep) 23395c635efSGarrett D'Amore { 23495c635efSGarrett D'Amore struct mdoc_node *n; 23595c635efSGarrett D'Amore 236*698f87a4SGarrett D'Amore assert( ! (MDOC_HALT & mdoc->flags)); 23795c635efSGarrett D'Amore 23895c635efSGarrett D'Amore /* No text before an initial macro. */ 23995c635efSGarrett D'Amore 240*698f87a4SGarrett D'Amore if (SEC_NONE == mdoc->lastnamed) { 241*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, ep->ln, ep->pos, MANDOCERR_NOTEXT); 24295c635efSGarrett D'Amore return(1); 24395c635efSGarrett D'Amore } 24495c635efSGarrett D'Amore 245*698f87a4SGarrett D'Amore n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); 24695c635efSGarrett D'Amore n->eqn = ep; 24795c635efSGarrett D'Amore 248*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, n)) 24995c635efSGarrett D'Amore return(0); 25095c635efSGarrett D'Amore 251*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 25295c635efSGarrett D'Amore return(1); 25395c635efSGarrett D'Amore } 25495c635efSGarrett D'Amore 25595c635efSGarrett D'Amore int 256*698f87a4SGarrett D'Amore mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp) 25795c635efSGarrett D'Amore { 25895c635efSGarrett D'Amore struct mdoc_node *n; 25995c635efSGarrett D'Amore 260*698f87a4SGarrett D'Amore assert( ! (MDOC_HALT & mdoc->flags)); 26195c635efSGarrett D'Amore 26295c635efSGarrett D'Amore /* No text before an initial macro. */ 26395c635efSGarrett D'Amore 264*698f87a4SGarrett D'Amore if (SEC_NONE == mdoc->lastnamed) { 265*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, sp->line, 0, MANDOCERR_NOTEXT); 26695c635efSGarrett D'Amore return(1); 26795c635efSGarrett D'Amore } 26895c635efSGarrett D'Amore 269*698f87a4SGarrett D'Amore n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL); 27095c635efSGarrett D'Amore n->span = sp; 27195c635efSGarrett D'Amore 272*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, n)) 27395c635efSGarrett D'Amore return(0); 27495c635efSGarrett D'Amore 275*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 27695c635efSGarrett D'Amore return(1); 27795c635efSGarrett D'Amore } 27895c635efSGarrett D'Amore 27995c635efSGarrett D'Amore 28095c635efSGarrett D'Amore /* 28195c635efSGarrett D'Amore * Main parse routine. Parses a single line -- really just hands off to 28295c635efSGarrett D'Amore * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()). 28395c635efSGarrett D'Amore */ 28495c635efSGarrett D'Amore int 285*698f87a4SGarrett D'Amore mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs) 28695c635efSGarrett D'Amore { 28795c635efSGarrett D'Amore 288*698f87a4SGarrett D'Amore assert( ! (MDOC_HALT & mdoc->flags)); 28995c635efSGarrett D'Amore 290*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_NEWLINE; 29195c635efSGarrett D'Amore 29295c635efSGarrett D'Amore /* 29395c635efSGarrett D'Amore * Let the roff nS register switch SYNOPSIS mode early, 29495c635efSGarrett D'Amore * such that the parser knows at all times 29595c635efSGarrett D'Amore * whether this mode is on or off. 29695c635efSGarrett D'Amore * Note that this mode is also switched by the Sh macro. 29795c635efSGarrett D'Amore */ 298*698f87a4SGarrett D'Amore if (roff_getreg(mdoc->roff, "nS")) 299*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS; 30095c635efSGarrett D'Amore else 301*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS; 30295c635efSGarrett D'Amore 303*698f87a4SGarrett D'Amore return(roff_getcontrol(mdoc->roff, buf, &offs) ? 304*698f87a4SGarrett D'Amore mdoc_pmacro(mdoc, ln, buf, offs) : 305*698f87a4SGarrett D'Amore mdoc_ptext(mdoc, ln, buf, offs)); 30695c635efSGarrett D'Amore } 30795c635efSGarrett D'Amore 30895c635efSGarrett D'Amore int 30995c635efSGarrett D'Amore mdoc_macro(MACRO_PROT_ARGS) 31095c635efSGarrett D'Amore { 31195c635efSGarrett D'Amore assert(tok < MDOC_MAX); 31295c635efSGarrett D'Amore 31395c635efSGarrett D'Amore /* If we're in the body, deny prologue calls. */ 31495c635efSGarrett D'Amore 31595c635efSGarrett D'Amore if (MDOC_PROLOGUE & mdoc_macros[tok].flags && 316*698f87a4SGarrett D'Amore MDOC_PBODY & mdoc->flags) { 317*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADBODY); 31895c635efSGarrett D'Amore return(1); 31995c635efSGarrett D'Amore } 32095c635efSGarrett D'Amore 32195c635efSGarrett D'Amore /* If we're in the prologue, deny "body" macros. */ 32295c635efSGarrett D'Amore 32395c635efSGarrett D'Amore if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) && 324*698f87a4SGarrett D'Amore ! (MDOC_PBODY & mdoc->flags)) { 325*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADPROLOG); 326*698f87a4SGarrett D'Amore if (NULL == mdoc->meta.msec) 327*698f87a4SGarrett D'Amore mdoc->meta.msec = mandoc_strdup("1"); 328*698f87a4SGarrett D'Amore if (NULL == mdoc->meta.title) 329*698f87a4SGarrett D'Amore mdoc->meta.title = mandoc_strdup("UNKNOWN"); 330*698f87a4SGarrett D'Amore if (NULL == mdoc->meta.vol) 331*698f87a4SGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL"); 332*698f87a4SGarrett D'Amore if (NULL == mdoc->meta.os) 333*698f87a4SGarrett D'Amore mdoc->meta.os = mandoc_strdup("LOCAL"); 334*698f87a4SGarrett D'Amore if (NULL == mdoc->meta.date) 335*698f87a4SGarrett D'Amore mdoc->meta.date = mandoc_normdate 336*698f87a4SGarrett D'Amore (mdoc->parse, NULL, line, ppos); 337*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_PBODY; 33895c635efSGarrett D'Amore } 33995c635efSGarrett D'Amore 340*698f87a4SGarrett D'Amore return((*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf)); 34195c635efSGarrett D'Amore } 34295c635efSGarrett D'Amore 34395c635efSGarrett D'Amore 34495c635efSGarrett D'Amore static int 34595c635efSGarrett D'Amore node_append(struct mdoc *mdoc, struct mdoc_node *p) 34695c635efSGarrett D'Amore { 34795c635efSGarrett D'Amore 34895c635efSGarrett D'Amore assert(mdoc->last); 34995c635efSGarrett D'Amore assert(mdoc->first); 35095c635efSGarrett D'Amore assert(MDOC_ROOT != p->type); 35195c635efSGarrett D'Amore 35295c635efSGarrett D'Amore switch (mdoc->next) { 35395c635efSGarrett D'Amore case (MDOC_NEXT_SIBLING): 35495c635efSGarrett D'Amore mdoc->last->next = p; 35595c635efSGarrett D'Amore p->prev = mdoc->last; 35695c635efSGarrett D'Amore p->parent = mdoc->last->parent; 35795c635efSGarrett D'Amore break; 35895c635efSGarrett D'Amore case (MDOC_NEXT_CHILD): 35995c635efSGarrett D'Amore mdoc->last->child = p; 36095c635efSGarrett D'Amore p->parent = mdoc->last; 36195c635efSGarrett D'Amore break; 36295c635efSGarrett D'Amore default: 36395c635efSGarrett D'Amore abort(); 36495c635efSGarrett D'Amore /* NOTREACHED */ 36595c635efSGarrett D'Amore } 36695c635efSGarrett D'Amore 36795c635efSGarrett D'Amore p->parent->nchild++; 36895c635efSGarrett D'Amore 36995c635efSGarrett D'Amore /* 37095c635efSGarrett D'Amore * Copy over the normalised-data pointer of our parent. Not 37195c635efSGarrett D'Amore * everybody has one, but copying a null pointer is fine. 37295c635efSGarrett D'Amore */ 37395c635efSGarrett D'Amore 37495c635efSGarrett D'Amore switch (p->type) { 37595c635efSGarrett D'Amore case (MDOC_BODY): 376*698f87a4SGarrett D'Amore if (ENDBODY_NOT != p->end) 377*698f87a4SGarrett D'Amore break; 37895c635efSGarrett D'Amore /* FALLTHROUGH */ 37995c635efSGarrett D'Amore case (MDOC_TAIL): 38095c635efSGarrett D'Amore /* FALLTHROUGH */ 38195c635efSGarrett D'Amore case (MDOC_HEAD): 38295c635efSGarrett D'Amore p->norm = p->parent->norm; 38395c635efSGarrett D'Amore break; 38495c635efSGarrett D'Amore default: 38595c635efSGarrett D'Amore break; 38695c635efSGarrett D'Amore } 38795c635efSGarrett D'Amore 38895c635efSGarrett D'Amore if ( ! mdoc_valid_pre(mdoc, p)) 38995c635efSGarrett D'Amore return(0); 39095c635efSGarrett D'Amore 39195c635efSGarrett D'Amore switch (p->type) { 39295c635efSGarrett D'Amore case (MDOC_HEAD): 39395c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 39495c635efSGarrett D'Amore p->parent->head = p; 39595c635efSGarrett D'Amore break; 39695c635efSGarrett D'Amore case (MDOC_TAIL): 39795c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 39895c635efSGarrett D'Amore p->parent->tail = p; 39995c635efSGarrett D'Amore break; 40095c635efSGarrett D'Amore case (MDOC_BODY): 40195c635efSGarrett D'Amore if (p->end) 40295c635efSGarrett D'Amore break; 40395c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 40495c635efSGarrett D'Amore p->parent->body = p; 40595c635efSGarrett D'Amore break; 40695c635efSGarrett D'Amore default: 40795c635efSGarrett D'Amore break; 40895c635efSGarrett D'Amore } 40995c635efSGarrett D'Amore 41095c635efSGarrett D'Amore mdoc->last = p; 41195c635efSGarrett D'Amore 41295c635efSGarrett D'Amore switch (p->type) { 41395c635efSGarrett D'Amore case (MDOC_TBL): 41495c635efSGarrett D'Amore /* FALLTHROUGH */ 41595c635efSGarrett D'Amore case (MDOC_TEXT): 41695c635efSGarrett D'Amore if ( ! mdoc_valid_post(mdoc)) 41795c635efSGarrett D'Amore return(0); 41895c635efSGarrett D'Amore break; 41995c635efSGarrett D'Amore default: 42095c635efSGarrett D'Amore break; 42195c635efSGarrett D'Amore } 42295c635efSGarrett D'Amore 42395c635efSGarrett D'Amore return(1); 42495c635efSGarrett D'Amore } 42595c635efSGarrett D'Amore 42695c635efSGarrett D'Amore 42795c635efSGarrett D'Amore static struct mdoc_node * 428*698f87a4SGarrett D'Amore node_alloc(struct mdoc *mdoc, int line, int pos, 42995c635efSGarrett D'Amore enum mdoct tok, enum mdoc_type type) 43095c635efSGarrett D'Amore { 43195c635efSGarrett D'Amore struct mdoc_node *p; 43295c635efSGarrett D'Amore 43395c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc_node)); 434*698f87a4SGarrett D'Amore p->sec = mdoc->lastsec; 43595c635efSGarrett D'Amore p->line = line; 43695c635efSGarrett D'Amore p->pos = pos; 437*698f87a4SGarrett D'Amore p->lastline = line; 43895c635efSGarrett D'Amore p->tok = tok; 43995c635efSGarrett D'Amore p->type = type; 44095c635efSGarrett D'Amore 44195c635efSGarrett D'Amore /* Flag analysis. */ 44295c635efSGarrett D'Amore 443*698f87a4SGarrett D'Amore if (MDOC_SYNOPSIS & mdoc->flags) 44495c635efSGarrett D'Amore p->flags |= MDOC_SYNPRETTY; 44595c635efSGarrett D'Amore else 44695c635efSGarrett D'Amore p->flags &= ~MDOC_SYNPRETTY; 447*698f87a4SGarrett D'Amore if (MDOC_NEWLINE & mdoc->flags) 44895c635efSGarrett D'Amore p->flags |= MDOC_LINE; 449*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_NEWLINE; 45095c635efSGarrett D'Amore 45195c635efSGarrett D'Amore return(p); 45295c635efSGarrett D'Amore } 45395c635efSGarrett D'Amore 45495c635efSGarrett D'Amore 45595c635efSGarrett D'Amore int 456*698f87a4SGarrett D'Amore mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) 45795c635efSGarrett D'Amore { 45895c635efSGarrett D'Amore struct mdoc_node *p; 45995c635efSGarrett D'Amore 460*698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL); 461*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, p)) 46295c635efSGarrett D'Amore return(0); 463*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 46495c635efSGarrett D'Amore return(1); 46595c635efSGarrett D'Amore } 46695c635efSGarrett D'Amore 46795c635efSGarrett D'Amore 46895c635efSGarrett D'Amore int 469*698f87a4SGarrett D'Amore mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) 47095c635efSGarrett D'Amore { 47195c635efSGarrett D'Amore struct mdoc_node *p; 47295c635efSGarrett D'Amore 473*698f87a4SGarrett D'Amore assert(mdoc->first); 474*698f87a4SGarrett D'Amore assert(mdoc->last); 47595c635efSGarrett D'Amore 476*698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD); 477*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, p)) 47895c635efSGarrett D'Amore return(0); 479*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 48095c635efSGarrett D'Amore return(1); 48195c635efSGarrett D'Amore } 48295c635efSGarrett D'Amore 48395c635efSGarrett D'Amore 48495c635efSGarrett D'Amore int 485*698f87a4SGarrett D'Amore mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) 48695c635efSGarrett D'Amore { 48795c635efSGarrett D'Amore struct mdoc_node *p; 48895c635efSGarrett D'Amore 489*698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); 490*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, p)) 49195c635efSGarrett D'Amore return(0); 492*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 49395c635efSGarrett D'Amore return(1); 49495c635efSGarrett D'Amore } 49595c635efSGarrett D'Amore 49695c635efSGarrett D'Amore 49795c635efSGarrett D'Amore int 498*698f87a4SGarrett D'Amore mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, 49995c635efSGarrett D'Amore struct mdoc_node *body, enum mdoc_endbody end) 50095c635efSGarrett D'Amore { 50195c635efSGarrett D'Amore struct mdoc_node *p; 50295c635efSGarrett D'Amore 503*698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); 50495c635efSGarrett D'Amore p->pending = body; 505*698f87a4SGarrett D'Amore p->norm = body->norm; 50695c635efSGarrett D'Amore p->end = end; 507*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, p)) 50895c635efSGarrett D'Amore return(0); 509*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 51095c635efSGarrett D'Amore return(1); 51195c635efSGarrett D'Amore } 51295c635efSGarrett D'Amore 51395c635efSGarrett D'Amore 51495c635efSGarrett D'Amore int 515*698f87a4SGarrett D'Amore mdoc_block_alloc(struct mdoc *mdoc, int line, int pos, 51695c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args) 51795c635efSGarrett D'Amore { 51895c635efSGarrett D'Amore struct mdoc_node *p; 51995c635efSGarrett D'Amore 520*698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK); 52195c635efSGarrett D'Amore p->args = args; 52295c635efSGarrett D'Amore if (p->args) 52395c635efSGarrett D'Amore (args->refcnt)++; 52495c635efSGarrett D'Amore 52595c635efSGarrett D'Amore switch (tok) { 52695c635efSGarrett D'Amore case (MDOC_Bd): 52795c635efSGarrett D'Amore /* FALLTHROUGH */ 52895c635efSGarrett D'Amore case (MDOC_Bf): 52995c635efSGarrett D'Amore /* FALLTHROUGH */ 53095c635efSGarrett D'Amore case (MDOC_Bl): 53195c635efSGarrett D'Amore /* FALLTHROUGH */ 53295c635efSGarrett D'Amore case (MDOC_Rs): 53395c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); 53495c635efSGarrett D'Amore break; 53595c635efSGarrett D'Amore default: 53695c635efSGarrett D'Amore break; 53795c635efSGarrett D'Amore } 53895c635efSGarrett D'Amore 539*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, p)) 54095c635efSGarrett D'Amore return(0); 541*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 54295c635efSGarrett D'Amore return(1); 54395c635efSGarrett D'Amore } 54495c635efSGarrett D'Amore 54595c635efSGarrett D'Amore 54695c635efSGarrett D'Amore int 547*698f87a4SGarrett D'Amore mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos, 54895c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args) 54995c635efSGarrett D'Amore { 55095c635efSGarrett D'Amore struct mdoc_node *p; 55195c635efSGarrett D'Amore 552*698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM); 55395c635efSGarrett D'Amore p->args = args; 55495c635efSGarrett D'Amore if (p->args) 55595c635efSGarrett D'Amore (args->refcnt)++; 55695c635efSGarrett D'Amore 55795c635efSGarrett D'Amore switch (tok) { 55895c635efSGarrett D'Amore case (MDOC_An): 55995c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); 56095c635efSGarrett D'Amore break; 56195c635efSGarrett D'Amore default: 56295c635efSGarrett D'Amore break; 56395c635efSGarrett D'Amore } 56495c635efSGarrett D'Amore 565*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, p)) 56695c635efSGarrett D'Amore return(0); 567*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 56895c635efSGarrett D'Amore return(1); 56995c635efSGarrett D'Amore } 57095c635efSGarrett D'Amore 57195c635efSGarrett D'Amore int 572*698f87a4SGarrett D'Amore mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p) 57395c635efSGarrett D'Amore { 57495c635efSGarrett D'Amore struct mdoc_node *n; 57595c635efSGarrett D'Amore 576*698f87a4SGarrett D'Amore n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT); 577*698f87a4SGarrett D'Amore n->string = roff_strdup(mdoc->roff, p); 57895c635efSGarrett D'Amore 579*698f87a4SGarrett D'Amore if ( ! node_append(mdoc, n)) 58095c635efSGarrett D'Amore return(0); 58195c635efSGarrett D'Amore 582*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 58395c635efSGarrett D'Amore return(1); 58495c635efSGarrett D'Amore } 58595c635efSGarrett D'Amore 586*698f87a4SGarrett D'Amore void 587*698f87a4SGarrett D'Amore mdoc_word_append(struct mdoc *mdoc, const char *p) 588*698f87a4SGarrett D'Amore { 589*698f87a4SGarrett D'Amore struct mdoc_node *n; 590*698f87a4SGarrett D'Amore char *addstr, *newstr; 591*698f87a4SGarrett D'Amore 592*698f87a4SGarrett D'Amore n = mdoc->last; 593*698f87a4SGarrett D'Amore addstr = roff_strdup(mdoc->roff, p); 594*698f87a4SGarrett D'Amore if (-1 == asprintf(&newstr, "%s %s", n->string, addstr)) { 595*698f87a4SGarrett D'Amore perror(NULL); 596*698f87a4SGarrett D'Amore exit((int)MANDOCLEVEL_SYSERR); 597*698f87a4SGarrett D'Amore } 598*698f87a4SGarrett D'Amore free(addstr); 599*698f87a4SGarrett D'Amore free(n->string); 600*698f87a4SGarrett D'Amore n->string = newstr; 601*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 602*698f87a4SGarrett D'Amore } 60395c635efSGarrett D'Amore 60495c635efSGarrett D'Amore static void 60595c635efSGarrett D'Amore mdoc_node_free(struct mdoc_node *p) 60695c635efSGarrett D'Amore { 60795c635efSGarrett D'Amore 60895c635efSGarrett D'Amore if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type) 60995c635efSGarrett D'Amore free(p->norm); 61095c635efSGarrett D'Amore if (p->string) 61195c635efSGarrett D'Amore free(p->string); 61295c635efSGarrett D'Amore if (p->args) 61395c635efSGarrett D'Amore mdoc_argv_free(p->args); 61495c635efSGarrett D'Amore free(p); 61595c635efSGarrett D'Amore } 61695c635efSGarrett D'Amore 61795c635efSGarrett D'Amore 61895c635efSGarrett D'Amore static void 619*698f87a4SGarrett D'Amore mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n) 62095c635efSGarrett D'Amore { 62195c635efSGarrett D'Amore 62295c635efSGarrett D'Amore /* Adjust siblings. */ 62395c635efSGarrett D'Amore 62495c635efSGarrett D'Amore if (n->prev) 62595c635efSGarrett D'Amore n->prev->next = n->next; 62695c635efSGarrett D'Amore if (n->next) 62795c635efSGarrett D'Amore n->next->prev = n->prev; 62895c635efSGarrett D'Amore 62995c635efSGarrett D'Amore /* Adjust parent. */ 63095c635efSGarrett D'Amore 63195c635efSGarrett D'Amore if (n->parent) { 63295c635efSGarrett D'Amore n->parent->nchild--; 63395c635efSGarrett D'Amore if (n->parent->child == n) 63495c635efSGarrett D'Amore n->parent->child = n->prev ? n->prev : n->next; 63595c635efSGarrett D'Amore if (n->parent->last == n) 63695c635efSGarrett D'Amore n->parent->last = n->prev ? n->prev : NULL; 63795c635efSGarrett D'Amore } 63895c635efSGarrett D'Amore 63995c635efSGarrett D'Amore /* Adjust parse point, if applicable. */ 64095c635efSGarrett D'Amore 641*698f87a4SGarrett D'Amore if (mdoc && mdoc->last == n) { 64295c635efSGarrett D'Amore if (n->prev) { 643*698f87a4SGarrett D'Amore mdoc->last = n->prev; 644*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 64595c635efSGarrett D'Amore } else { 646*698f87a4SGarrett D'Amore mdoc->last = n->parent; 647*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 64895c635efSGarrett D'Amore } 64995c635efSGarrett D'Amore } 65095c635efSGarrett D'Amore 651*698f87a4SGarrett D'Amore if (mdoc && mdoc->first == n) 652*698f87a4SGarrett D'Amore mdoc->first = NULL; 65395c635efSGarrett D'Amore } 65495c635efSGarrett D'Amore 65595c635efSGarrett D'Amore 65695c635efSGarrett D'Amore void 657*698f87a4SGarrett D'Amore mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p) 65895c635efSGarrett D'Amore { 65995c635efSGarrett D'Amore 66095c635efSGarrett D'Amore while (p->child) { 66195c635efSGarrett D'Amore assert(p->nchild); 662*698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, p->child); 66395c635efSGarrett D'Amore } 66495c635efSGarrett D'Amore assert(0 == p->nchild); 66595c635efSGarrett D'Amore 666*698f87a4SGarrett D'Amore mdoc_node_unlink(mdoc, p); 66795c635efSGarrett D'Amore mdoc_node_free(p); 66895c635efSGarrett D'Amore } 66995c635efSGarrett D'Amore 670*698f87a4SGarrett D'Amore int 671*698f87a4SGarrett D'Amore mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p) 672*698f87a4SGarrett D'Amore { 673*698f87a4SGarrett D'Amore 674*698f87a4SGarrett D'Amore mdoc_node_unlink(mdoc, p); 675*698f87a4SGarrett D'Amore return(node_append(mdoc, p)); 676*698f87a4SGarrett D'Amore } 677*698f87a4SGarrett D'Amore 67895c635efSGarrett D'Amore #if 0 67995c635efSGarrett D'Amore /* 68095c635efSGarrett D'Amore * Pre-treat a text line. 68195c635efSGarrett D'Amore * Text lines can consist of equations, which must be handled apart from 68295c635efSGarrett D'Amore * the regular text. 68395c635efSGarrett D'Amore * Thus, use this function to step through a line checking if it has any 68495c635efSGarrett D'Amore * equations embedded in it. 68595c635efSGarrett D'Amore * This must handle multiple equations AND equations that do not end at 68695c635efSGarrett D'Amore * the end-of-line, i.e., will re-enter in the next roff parse. 68795c635efSGarrett D'Amore */ 68895c635efSGarrett D'Amore static int 689*698f87a4SGarrett D'Amore mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs) 69095c635efSGarrett D'Amore { 69195c635efSGarrett D'Amore char *start, *end; 69295c635efSGarrett D'Amore char delim; 69395c635efSGarrett D'Amore 69495c635efSGarrett D'Amore while ('\0' != buf[offs]) { 69595c635efSGarrett D'Amore /* Mark starting position if eqn is set. */ 69695c635efSGarrett D'Amore start = NULL; 697*698f87a4SGarrett D'Amore if ('\0' != (delim = roff_eqndelim(mdoc->roff))) 69895c635efSGarrett D'Amore if (NULL != (start = strchr(buf + offs, delim))) 69995c635efSGarrett D'Amore *start++ = '\0'; 70095c635efSGarrett D'Amore 70195c635efSGarrett D'Amore /* Parse text as normal. */ 702*698f87a4SGarrett D'Amore if ( ! mdoc_ptext(mdoc, line, buf, offs)) 70395c635efSGarrett D'Amore return(0); 70495c635efSGarrett D'Amore 70595c635efSGarrett D'Amore /* Continue only if an equation exists. */ 70695c635efSGarrett D'Amore if (NULL == start) 70795c635efSGarrett D'Amore break; 70895c635efSGarrett D'Amore 70995c635efSGarrett D'Amore /* Read past the end of the equation. */ 71095c635efSGarrett D'Amore offs += start - (buf + offs); 71195c635efSGarrett D'Amore assert(start == &buf[offs]); 71295c635efSGarrett D'Amore if (NULL != (end = strchr(buf + offs, delim))) { 71395c635efSGarrett D'Amore *end++ = '\0'; 71495c635efSGarrett D'Amore while (' ' == *end) 71595c635efSGarrett D'Amore end++; 71695c635efSGarrett D'Amore } 71795c635efSGarrett D'Amore 71895c635efSGarrett D'Amore /* Parse the equation itself. */ 719*698f87a4SGarrett D'Amore roff_openeqn(mdoc->roff, NULL, line, offs, buf); 72095c635efSGarrett D'Amore 72195c635efSGarrett D'Amore /* Process a finished equation? */ 722*698f87a4SGarrett D'Amore if (roff_closeeqn(mdoc->roff)) 723*698f87a4SGarrett D'Amore if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff))) 72495c635efSGarrett D'Amore return(0); 72595c635efSGarrett D'Amore offs += (end - (buf + offs)); 72695c635efSGarrett D'Amore } 72795c635efSGarrett D'Amore 72895c635efSGarrett D'Amore return(1); 72995c635efSGarrett D'Amore } 73095c635efSGarrett D'Amore #endif 73195c635efSGarrett D'Amore 73295c635efSGarrett D'Amore /* 73395c635efSGarrett D'Amore * Parse free-form text, that is, a line that does not begin with the 73495c635efSGarrett D'Amore * control character. 73595c635efSGarrett D'Amore */ 73695c635efSGarrett D'Amore static int 737*698f87a4SGarrett D'Amore mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs) 73895c635efSGarrett D'Amore { 73995c635efSGarrett D'Amore char *c, *ws, *end; 74095c635efSGarrett D'Amore struct mdoc_node *n; 74195c635efSGarrett D'Amore 74295c635efSGarrett D'Amore /* No text before an initial macro. */ 74395c635efSGarrett D'Amore 744*698f87a4SGarrett D'Amore if (SEC_NONE == mdoc->lastnamed) { 745*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, offs, MANDOCERR_NOTEXT); 74695c635efSGarrett D'Amore return(1); 74795c635efSGarrett D'Amore } 74895c635efSGarrett D'Amore 749*698f87a4SGarrett D'Amore assert(mdoc->last); 750*698f87a4SGarrett D'Amore n = mdoc->last; 75195c635efSGarrett D'Amore 75295c635efSGarrett D'Amore /* 75395c635efSGarrett D'Amore * Divert directly to list processing if we're encountering a 75495c635efSGarrett D'Amore * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry 75595c635efSGarrett D'Amore * (a MDOC_BODY means it's already open, in which case we should 75695c635efSGarrett D'Amore * process within its context in the normal way). 75795c635efSGarrett D'Amore */ 75895c635efSGarrett D'Amore 75995c635efSGarrett D'Amore if (MDOC_Bl == n->tok && MDOC_BODY == n->type && 76095c635efSGarrett D'Amore LIST_column == n->norm->Bl.type) { 76195c635efSGarrett D'Amore /* `Bl' is open without any children. */ 762*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 763*698f87a4SGarrett D'Amore return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf)); 76495c635efSGarrett D'Amore } 76595c635efSGarrett D'Amore 76695c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type && 76795c635efSGarrett D'Amore NULL != n->parent && 76895c635efSGarrett D'Amore MDOC_Bl == n->parent->tok && 76995c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) { 77095c635efSGarrett D'Amore /* `Bl' has block-level `It' children. */ 771*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 772*698f87a4SGarrett D'Amore return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf)); 77395c635efSGarrett D'Amore } 77495c635efSGarrett D'Amore 77595c635efSGarrett D'Amore /* 77695c635efSGarrett D'Amore * Search for the beginning of unescaped trailing whitespace (ws) 77795c635efSGarrett D'Amore * and for the first character not to be output (end). 77895c635efSGarrett D'Amore */ 77995c635efSGarrett D'Amore 78095c635efSGarrett D'Amore /* FIXME: replace with strcspn(). */ 78195c635efSGarrett D'Amore ws = NULL; 78295c635efSGarrett D'Amore for (c = end = buf + offs; *c; c++) { 78395c635efSGarrett D'Amore switch (*c) { 78495c635efSGarrett D'Amore case ' ': 78595c635efSGarrett D'Amore if (NULL == ws) 78695c635efSGarrett D'Amore ws = c; 78795c635efSGarrett D'Amore continue; 78895c635efSGarrett D'Amore case '\t': 78995c635efSGarrett D'Amore /* 79095c635efSGarrett D'Amore * Always warn about trailing tabs, 79195c635efSGarrett D'Amore * even outside literal context, 79295c635efSGarrett D'Amore * where they should be put on the next line. 79395c635efSGarrett D'Amore */ 79495c635efSGarrett D'Amore if (NULL == ws) 79595c635efSGarrett D'Amore ws = c; 79695c635efSGarrett D'Amore /* 79795c635efSGarrett D'Amore * Strip trailing tabs in literal context only; 79895c635efSGarrett D'Amore * outside, they affect the next line. 79995c635efSGarrett D'Amore */ 800*698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags) 80195c635efSGarrett D'Amore continue; 80295c635efSGarrett D'Amore break; 80395c635efSGarrett D'Amore case '\\': 80495c635efSGarrett D'Amore /* Skip the escaped character, too, if any. */ 80595c635efSGarrett D'Amore if (c[1]) 80695c635efSGarrett D'Amore c++; 80795c635efSGarrett D'Amore /* FALLTHROUGH */ 80895c635efSGarrett D'Amore default: 80995c635efSGarrett D'Amore ws = NULL; 81095c635efSGarrett D'Amore break; 81195c635efSGarrett D'Amore } 81295c635efSGarrett D'Amore end = c + 1; 81395c635efSGarrett D'Amore } 81495c635efSGarrett D'Amore *end = '\0'; 81595c635efSGarrett D'Amore 81695c635efSGarrett D'Amore if (ws) 817*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, (int)(ws-buf), MANDOCERR_EOLNSPACE); 81895c635efSGarrett D'Amore 819*698f87a4SGarrett D'Amore if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) { 820*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, line, (int)(c-buf), MANDOCERR_NOBLANKLN); 82195c635efSGarrett D'Amore 82295c635efSGarrett D'Amore /* 82395c635efSGarrett D'Amore * Insert a `sp' in the case of a blank line. Technically, 82495c635efSGarrett D'Amore * blank lines aren't allowed, but enough manuals assume this 82595c635efSGarrett D'Amore * behaviour that we want to work around it. 82695c635efSGarrett D'Amore */ 827*698f87a4SGarrett D'Amore if ( ! mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL)) 82895c635efSGarrett D'Amore return(0); 82995c635efSGarrett D'Amore 830*698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 831*698f87a4SGarrett D'Amore 832*698f87a4SGarrett D'Amore return(mdoc_valid_post(mdoc)); 83395c635efSGarrett D'Amore } 83495c635efSGarrett D'Amore 835*698f87a4SGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, line, offs, buf+offs)) 83695c635efSGarrett D'Amore return(0); 83795c635efSGarrett D'Amore 838*698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags) 83995c635efSGarrett D'Amore return(1); 84095c635efSGarrett D'Amore 84195c635efSGarrett D'Amore /* 84295c635efSGarrett D'Amore * End-of-sentence check. If the last character is an unescaped 84395c635efSGarrett D'Amore * EOS character, then flag the node as being the end of a 84495c635efSGarrett D'Amore * sentence. The front-end will know how to interpret this. 84595c635efSGarrett D'Amore */ 84695c635efSGarrett D'Amore 84795c635efSGarrett D'Amore assert(buf < end); 84895c635efSGarrett D'Amore 84995c635efSGarrett D'Amore if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0)) 850*698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_EOS; 85195c635efSGarrett D'Amore 85295c635efSGarrett D'Amore return(1); 85395c635efSGarrett D'Amore } 85495c635efSGarrett D'Amore 85595c635efSGarrett D'Amore 85695c635efSGarrett D'Amore /* 85795c635efSGarrett D'Amore * Parse a macro line, that is, a line beginning with the control 85895c635efSGarrett D'Amore * character. 85995c635efSGarrett D'Amore */ 86095c635efSGarrett D'Amore static int 861*698f87a4SGarrett D'Amore mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs) 86295c635efSGarrett D'Amore { 86395c635efSGarrett D'Amore enum mdoct tok; 86495c635efSGarrett D'Amore int i, sv; 86595c635efSGarrett D'Amore char mac[5]; 86695c635efSGarrett D'Amore struct mdoc_node *n; 86795c635efSGarrett D'Amore 86895c635efSGarrett D'Amore /* Empty post-control lines are ignored. */ 86995c635efSGarrett D'Amore 87095c635efSGarrett D'Amore if ('"' == buf[offs]) { 871*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, ln, offs, MANDOCERR_BADCOMMENT); 87295c635efSGarrett D'Amore return(1); 87395c635efSGarrett D'Amore } else if ('\0' == buf[offs]) 87495c635efSGarrett D'Amore return(1); 87595c635efSGarrett D'Amore 87695c635efSGarrett D'Amore sv = offs; 87795c635efSGarrett D'Amore 87895c635efSGarrett D'Amore /* 87995c635efSGarrett D'Amore * Copy the first word into a nil-terminated buffer. 88095c635efSGarrett D'Amore * Stop copying when a tab, space, or eoln is encountered. 88195c635efSGarrett D'Amore */ 88295c635efSGarrett D'Amore 88395c635efSGarrett D'Amore i = 0; 88495c635efSGarrett D'Amore while (i < 4 && '\0' != buf[offs] && 88595c635efSGarrett D'Amore ' ' != buf[offs] && '\t' != buf[offs]) 88695c635efSGarrett D'Amore mac[i++] = buf[offs++]; 88795c635efSGarrett D'Amore 88895c635efSGarrett D'Amore mac[i] = '\0'; 88995c635efSGarrett D'Amore 89095c635efSGarrett D'Amore tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX; 89195c635efSGarrett D'Amore 89295c635efSGarrett D'Amore if (MDOC_MAX == tok) { 893*698f87a4SGarrett D'Amore mandoc_vmsg(MANDOCERR_MACRO, mdoc->parse, 89495c635efSGarrett D'Amore ln, sv, "%s", buf + sv - 1); 89595c635efSGarrett D'Amore return(1); 89695c635efSGarrett D'Amore } 89795c635efSGarrett D'Amore 89895c635efSGarrett D'Amore /* Disregard the first trailing tab, if applicable. */ 89995c635efSGarrett D'Amore 90095c635efSGarrett D'Amore if ('\t' == buf[offs]) 90195c635efSGarrett D'Amore offs++; 90295c635efSGarrett D'Amore 90395c635efSGarrett D'Amore /* Jump to the next non-whitespace word. */ 90495c635efSGarrett D'Amore 90595c635efSGarrett D'Amore while (buf[offs] && ' ' == buf[offs]) 90695c635efSGarrett D'Amore offs++; 90795c635efSGarrett D'Amore 90895c635efSGarrett D'Amore /* 90995c635efSGarrett D'Amore * Trailing whitespace. Note that tabs are allowed to be passed 91095c635efSGarrett D'Amore * into the parser as "text", so we only warn about spaces here. 91195c635efSGarrett D'Amore */ 91295c635efSGarrett D'Amore 91395c635efSGarrett D'Amore if ('\0' == buf[offs] && ' ' == buf[offs - 1]) 914*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, ln, offs - 1, MANDOCERR_EOLNSPACE); 91595c635efSGarrett D'Amore 91695c635efSGarrett D'Amore /* 91795c635efSGarrett D'Amore * If an initial macro or a list invocation, divert directly 91895c635efSGarrett D'Amore * into macro processing. 91995c635efSGarrett D'Amore */ 92095c635efSGarrett D'Amore 921*698f87a4SGarrett D'Amore if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) { 922*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf)) 92395c635efSGarrett D'Amore goto err; 92495c635efSGarrett D'Amore return(1); 92595c635efSGarrett D'Amore } 92695c635efSGarrett D'Amore 927*698f87a4SGarrett D'Amore n = mdoc->last; 928*698f87a4SGarrett D'Amore assert(mdoc->last); 92995c635efSGarrett D'Amore 93095c635efSGarrett D'Amore /* 93195c635efSGarrett D'Amore * If the first macro of a `Bl -column', open an `It' block 93295c635efSGarrett D'Amore * context around the parsed macro. 93395c635efSGarrett D'Amore */ 93495c635efSGarrett D'Amore 93595c635efSGarrett D'Amore if (MDOC_Bl == n->tok && MDOC_BODY == n->type && 93695c635efSGarrett D'Amore LIST_column == n->norm->Bl.type) { 937*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 938*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf)) 93995c635efSGarrett D'Amore goto err; 94095c635efSGarrett D'Amore return(1); 94195c635efSGarrett D'Amore } 94295c635efSGarrett D'Amore 94395c635efSGarrett D'Amore /* 94495c635efSGarrett D'Amore * If we're following a block-level `It' within a `Bl -column' 94595c635efSGarrett D'Amore * context (perhaps opened in the above block or in ptext()), 94695c635efSGarrett D'Amore * then open an `It' block context around the parsed macro. 94795c635efSGarrett D'Amore */ 94895c635efSGarrett D'Amore 94995c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type && 95095c635efSGarrett D'Amore NULL != n->parent && 95195c635efSGarrett D'Amore MDOC_Bl == n->parent->tok && 95295c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) { 953*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 954*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf)) 95595c635efSGarrett D'Amore goto err; 95695c635efSGarrett D'Amore return(1); 95795c635efSGarrett D'Amore } 95895c635efSGarrett D'Amore 95995c635efSGarrett D'Amore /* Normal processing of a macro. */ 96095c635efSGarrett D'Amore 961*698f87a4SGarrett D'Amore if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf)) 96295c635efSGarrett D'Amore goto err; 96395c635efSGarrett D'Amore 96495c635efSGarrett D'Amore return(1); 96595c635efSGarrett D'Amore 96695c635efSGarrett D'Amore err: /* Error out. */ 96795c635efSGarrett D'Amore 968*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_HALT; 96995c635efSGarrett D'Amore return(0); 97095c635efSGarrett D'Amore } 97195c635efSGarrett D'Amore 97295c635efSGarrett D'Amore enum mdelim 97395c635efSGarrett D'Amore mdoc_isdelim(const char *p) 97495c635efSGarrett D'Amore { 97595c635efSGarrett D'Amore 97695c635efSGarrett D'Amore if ('\0' == p[0]) 97795c635efSGarrett D'Amore return(DELIM_NONE); 97895c635efSGarrett D'Amore 97995c635efSGarrett D'Amore if ('\0' == p[1]) 98095c635efSGarrett D'Amore switch (p[0]) { 98195c635efSGarrett D'Amore case('('): 98295c635efSGarrett D'Amore /* FALLTHROUGH */ 98395c635efSGarrett D'Amore case('['): 98495c635efSGarrett D'Amore return(DELIM_OPEN); 98595c635efSGarrett D'Amore case('|'): 98695c635efSGarrett D'Amore return(DELIM_MIDDLE); 98795c635efSGarrett D'Amore case('.'): 98895c635efSGarrett D'Amore /* FALLTHROUGH */ 98995c635efSGarrett D'Amore case(','): 99095c635efSGarrett D'Amore /* FALLTHROUGH */ 99195c635efSGarrett D'Amore case(';'): 99295c635efSGarrett D'Amore /* FALLTHROUGH */ 99395c635efSGarrett D'Amore case(':'): 99495c635efSGarrett D'Amore /* FALLTHROUGH */ 99595c635efSGarrett D'Amore case('?'): 99695c635efSGarrett D'Amore /* FALLTHROUGH */ 99795c635efSGarrett D'Amore case('!'): 99895c635efSGarrett D'Amore /* FALLTHROUGH */ 99995c635efSGarrett D'Amore case(')'): 100095c635efSGarrett D'Amore /* FALLTHROUGH */ 100195c635efSGarrett D'Amore case(']'): 100295c635efSGarrett D'Amore return(DELIM_CLOSE); 100395c635efSGarrett D'Amore default: 100495c635efSGarrett D'Amore return(DELIM_NONE); 100595c635efSGarrett D'Amore } 100695c635efSGarrett D'Amore 100795c635efSGarrett D'Amore if ('\\' != p[0]) 100895c635efSGarrett D'Amore return(DELIM_NONE); 100995c635efSGarrett D'Amore 101095c635efSGarrett D'Amore if (0 == strcmp(p + 1, ".")) 101195c635efSGarrett D'Amore return(DELIM_CLOSE); 1012*698f87a4SGarrett D'Amore if (0 == strcmp(p + 1, "fR|\\fP")) 101395c635efSGarrett D'Amore return(DELIM_MIDDLE); 101495c635efSGarrett D'Amore 101595c635efSGarrett D'Amore return(DELIM_NONE); 101695c635efSGarrett D'Amore } 1017