1*260e9a87SYuri Pankov /* $Id: mdoc.c,v 1.238 2015/02/12 13:00:52 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*260e9a87SYuri Pankov * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #include "config.h" 1995c635efSGarrett D'Amore 2095c635efSGarrett D'Amore #include <sys/types.h> 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <assert.h> 23*260e9a87SYuri Pankov #include <ctype.h> 2495c635efSGarrett D'Amore #include <stdarg.h> 2595c635efSGarrett D'Amore #include <stdio.h> 2695c635efSGarrett D'Amore #include <stdlib.h> 2795c635efSGarrett D'Amore #include <string.h> 2895c635efSGarrett D'Amore #include <time.h> 2995c635efSGarrett D'Amore 3095c635efSGarrett D'Amore #include "mdoc.h" 3195c635efSGarrett D'Amore #include "mandoc.h" 32*260e9a87SYuri Pankov #include "mandoc_aux.h" 3395c635efSGarrett D'Amore #include "libmdoc.h" 3495c635efSGarrett D'Amore #include "libmandoc.h" 3595c635efSGarrett D'Amore 36*260e9a87SYuri Pankov const char *const __mdoc_macronames[MDOC_MAX + 1] = { 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 "Xr", "%A", "%B", "%D", 4895c635efSGarrett D'Amore "%I", "%J", "%N", "%O", 4995c635efSGarrett D'Amore "%P", "%R", "%T", "%V", 5095c635efSGarrett D'Amore "Ac", "Ao", "Aq", "At", 5195c635efSGarrett D'Amore "Bc", "Bf", "Bo", "Bq", 5295c635efSGarrett D'Amore "Bsx", "Bx", "Db", "Dc", 5395c635efSGarrett D'Amore "Do", "Dq", "Ec", "Ef", 5495c635efSGarrett D'Amore "Em", "Eo", "Fx", "Ms", 5595c635efSGarrett D'Amore "No", "Ns", "Nx", "Ox", 5695c635efSGarrett D'Amore "Pc", "Pf", "Po", "Pq", 5795c635efSGarrett D'Amore "Qc", "Ql", "Qo", "Qq", 5895c635efSGarrett D'Amore "Re", "Rs", "Sc", "So", 5995c635efSGarrett D'Amore "Sq", "Sm", "Sx", "Sy", 6095c635efSGarrett D'Amore "Tn", "Ux", "Xc", "Xo", 6195c635efSGarrett D'Amore "Fo", "Fc", "Oo", "Oc", 6295c635efSGarrett D'Amore "Bk", "Ek", "Bt", "Hf", 6395c635efSGarrett D'Amore "Fr", "Ud", "Lb", "Lp", 6495c635efSGarrett D'Amore "Lk", "Mt", "Brq", "Bro", 6595c635efSGarrett D'Amore "Brc", "%C", "Es", "En", 6695c635efSGarrett D'Amore "Dx", "%Q", "br", "sp", 67*260e9a87SYuri Pankov "%U", "Ta", "ll", "text", 6895c635efSGarrett D'Amore }; 6995c635efSGarrett D'Amore 7095c635efSGarrett D'Amore const char *const __mdoc_argnames[MDOC_ARG_MAX] = { 7195c635efSGarrett D'Amore "split", "nosplit", "ragged", 7295c635efSGarrett D'Amore "unfilled", "literal", "file", 7395c635efSGarrett D'Amore "offset", "bullet", "dash", 7495c635efSGarrett D'Amore "hyphen", "item", "enum", 7595c635efSGarrett D'Amore "tag", "diag", "hang", 7695c635efSGarrett D'Amore "ohang", "inset", "column", 7795c635efSGarrett D'Amore "width", "compact", "std", 7895c635efSGarrett D'Amore "filled", "words", "emphasis", 7995c635efSGarrett D'Amore "symbolic", "nested", "centered" 8095c635efSGarrett D'Amore }; 8195c635efSGarrett D'Amore 8295c635efSGarrett D'Amore const char * const *mdoc_macronames = __mdoc_macronames; 8395c635efSGarrett D'Amore const char * const *mdoc_argnames = __mdoc_argnames; 8495c635efSGarrett D'Amore 8595c635efSGarrett D'Amore static void mdoc_node_free(struct mdoc_node *); 8695c635efSGarrett D'Amore static void mdoc_node_unlink(struct mdoc *, 8795c635efSGarrett D'Amore struct mdoc_node *); 8895c635efSGarrett D'Amore static void mdoc_free1(struct mdoc *); 8995c635efSGarrett D'Amore static void mdoc_alloc1(struct mdoc *); 9095c635efSGarrett D'Amore static struct mdoc_node *node_alloc(struct mdoc *, int, int, 9195c635efSGarrett D'Amore enum mdoct, enum mdoc_type); 92*260e9a87SYuri Pankov static void node_append(struct mdoc *, struct mdoc_node *); 9395c635efSGarrett D'Amore static int mdoc_ptext(struct mdoc *, int, char *, int); 9495c635efSGarrett D'Amore static int mdoc_pmacro(struct mdoc *, int, char *, int); 9595c635efSGarrett D'Amore 96*260e9a87SYuri Pankov 9795c635efSGarrett D'Amore const struct mdoc_node * 98698f87a4SGarrett D'Amore mdoc_node(const struct mdoc *mdoc) 9995c635efSGarrett D'Amore { 10095c635efSGarrett D'Amore 101698f87a4SGarrett D'Amore return(mdoc->first); 10295c635efSGarrett D'Amore } 10395c635efSGarrett D'Amore 10495c635efSGarrett D'Amore const struct mdoc_meta * 105698f87a4SGarrett D'Amore mdoc_meta(const struct mdoc *mdoc) 10695c635efSGarrett D'Amore { 10795c635efSGarrett D'Amore 108698f87a4SGarrett D'Amore return(&mdoc->meta); 10995c635efSGarrett D'Amore } 11095c635efSGarrett D'Amore 11195c635efSGarrett D'Amore /* 11295c635efSGarrett D'Amore * Frees volatile resources (parse tree, meta-data, fields). 11395c635efSGarrett D'Amore */ 11495c635efSGarrett D'Amore static void 11595c635efSGarrett D'Amore mdoc_free1(struct mdoc *mdoc) 11695c635efSGarrett D'Amore { 11795c635efSGarrett D'Amore 11895c635efSGarrett D'Amore if (mdoc->first) 11995c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->first); 12095c635efSGarrett D'Amore free(mdoc->meta.msec); 121*260e9a87SYuri Pankov free(mdoc->meta.vol); 122*260e9a87SYuri Pankov free(mdoc->meta.arch); 12395c635efSGarrett D'Amore free(mdoc->meta.date); 124*260e9a87SYuri Pankov free(mdoc->meta.title); 125*260e9a87SYuri Pankov free(mdoc->meta.os); 126*260e9a87SYuri Pankov free(mdoc->meta.name); 12795c635efSGarrett D'Amore } 12895c635efSGarrett D'Amore 12995c635efSGarrett D'Amore /* 13095c635efSGarrett D'Amore * Allocate all volatile resources (parse tree, meta-data, fields). 13195c635efSGarrett D'Amore */ 13295c635efSGarrett D'Amore static void 13395c635efSGarrett D'Amore mdoc_alloc1(struct mdoc *mdoc) 13495c635efSGarrett D'Amore { 13595c635efSGarrett D'Amore 13695c635efSGarrett D'Amore memset(&mdoc->meta, 0, sizeof(struct mdoc_meta)); 13795c635efSGarrett D'Amore mdoc->flags = 0; 13895c635efSGarrett D'Amore mdoc->lastnamed = mdoc->lastsec = SEC_NONE; 13995c635efSGarrett D'Amore mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node)); 14095c635efSGarrett D'Amore mdoc->first = mdoc->last; 14195c635efSGarrett D'Amore mdoc->last->type = MDOC_ROOT; 14295c635efSGarrett D'Amore mdoc->last->tok = MDOC_MAX; 14395c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 14495c635efSGarrett D'Amore } 14595c635efSGarrett D'Amore 14695c635efSGarrett D'Amore /* 14795c635efSGarrett D'Amore * Free up volatile resources (see mdoc_free1()) then re-initialises the 14895c635efSGarrett D'Amore * data with mdoc_alloc1(). After invocation, parse data has been reset 14995c635efSGarrett D'Amore * and the parser is ready for re-invocation on a new tree; however, 15095c635efSGarrett D'Amore * cross-parse non-volatile data is kept intact. 15195c635efSGarrett D'Amore */ 15295c635efSGarrett D'Amore void 15395c635efSGarrett D'Amore mdoc_reset(struct mdoc *mdoc) 15495c635efSGarrett D'Amore { 15595c635efSGarrett D'Amore 15695c635efSGarrett D'Amore mdoc_free1(mdoc); 15795c635efSGarrett D'Amore mdoc_alloc1(mdoc); 15895c635efSGarrett D'Amore } 15995c635efSGarrett D'Amore 16095c635efSGarrett D'Amore /* 16195c635efSGarrett D'Amore * Completely free up all volatile and non-volatile parse resources. 16295c635efSGarrett D'Amore * After invocation, the pointer is no longer usable. 16395c635efSGarrett D'Amore */ 16495c635efSGarrett D'Amore void 16595c635efSGarrett D'Amore mdoc_free(struct mdoc *mdoc) 16695c635efSGarrett D'Amore { 16795c635efSGarrett D'Amore 16895c635efSGarrett D'Amore mdoc_free1(mdoc); 16995c635efSGarrett D'Amore free(mdoc); 17095c635efSGarrett D'Amore } 17195c635efSGarrett D'Amore 17295c635efSGarrett D'Amore /* 17395c635efSGarrett D'Amore * Allocate volatile and non-volatile parse resources. 17495c635efSGarrett D'Amore */ 17595c635efSGarrett D'Amore struct mdoc * 176*260e9a87SYuri Pankov mdoc_alloc(struct roff *roff, struct mparse *parse, 177*260e9a87SYuri Pankov const char *defos, int quick) 17895c635efSGarrett D'Amore { 17995c635efSGarrett D'Amore struct mdoc *p; 18095c635efSGarrett D'Amore 18195c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc)); 18295c635efSGarrett D'Amore 18395c635efSGarrett D'Amore p->parse = parse; 184698f87a4SGarrett D'Amore p->defos = defos; 185*260e9a87SYuri Pankov p->quick = quick; 18695c635efSGarrett D'Amore p->roff = roff; 18795c635efSGarrett D'Amore 18895c635efSGarrett D'Amore mdoc_hash_init(); 18995c635efSGarrett D'Amore mdoc_alloc1(p); 19095c635efSGarrett D'Amore return(p); 19195c635efSGarrett D'Amore } 19295c635efSGarrett D'Amore 193*260e9a87SYuri Pankov void 194698f87a4SGarrett D'Amore mdoc_endparse(struct mdoc *mdoc) 19595c635efSGarrett D'Amore { 19695c635efSGarrett D'Amore 197*260e9a87SYuri Pankov mdoc_macroend(mdoc); 19895c635efSGarrett D'Amore } 19995c635efSGarrett D'Amore 200*260e9a87SYuri Pankov void 201698f87a4SGarrett D'Amore mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep) 20295c635efSGarrett D'Amore { 20395c635efSGarrett D'Amore struct mdoc_node *n; 20495c635efSGarrett D'Amore 205698f87a4SGarrett D'Amore n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); 20695c635efSGarrett D'Amore n->eqn = ep; 207*260e9a87SYuri Pankov if (ep->ln > mdoc->last->line) 208*260e9a87SYuri Pankov n->flags |= MDOC_LINE; 209*260e9a87SYuri Pankov node_append(mdoc, n); 210698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 21195c635efSGarrett D'Amore } 21295c635efSGarrett D'Amore 213*260e9a87SYuri Pankov void 214698f87a4SGarrett D'Amore mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp) 21595c635efSGarrett D'Amore { 21695c635efSGarrett D'Amore struct mdoc_node *n; 21795c635efSGarrett D'Amore 218698f87a4SGarrett D'Amore n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL); 21995c635efSGarrett D'Amore n->span = sp; 220*260e9a87SYuri Pankov node_append(mdoc, n); 221698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 22295c635efSGarrett D'Amore } 22395c635efSGarrett D'Amore 22495c635efSGarrett D'Amore /* 22595c635efSGarrett D'Amore * Main parse routine. Parses a single line -- really just hands off to 22695c635efSGarrett D'Amore * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()). 22795c635efSGarrett D'Amore */ 22895c635efSGarrett D'Amore int 229698f87a4SGarrett D'Amore mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs) 23095c635efSGarrett D'Amore { 23195c635efSGarrett D'Amore 232*260e9a87SYuri Pankov if (mdoc->last->type != MDOC_EQN || ln > mdoc->last->line) 233698f87a4SGarrett D'Amore mdoc->flags |= MDOC_NEWLINE; 23495c635efSGarrett D'Amore 23595c635efSGarrett D'Amore /* 23695c635efSGarrett D'Amore * Let the roff nS register switch SYNOPSIS mode early, 23795c635efSGarrett D'Amore * such that the parser knows at all times 23895c635efSGarrett D'Amore * whether this mode is on or off. 23995c635efSGarrett D'Amore * Note that this mode is also switched by the Sh macro. 24095c635efSGarrett D'Amore */ 241698f87a4SGarrett D'Amore if (roff_getreg(mdoc->roff, "nS")) 242698f87a4SGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS; 24395c635efSGarrett D'Amore else 244698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS; 24595c635efSGarrett D'Amore 246698f87a4SGarrett D'Amore return(roff_getcontrol(mdoc->roff, buf, &offs) ? 247698f87a4SGarrett D'Amore mdoc_pmacro(mdoc, ln, buf, offs) : 248698f87a4SGarrett D'Amore mdoc_ptext(mdoc, ln, buf, offs)); 24995c635efSGarrett D'Amore } 25095c635efSGarrett D'Amore 251*260e9a87SYuri Pankov void 25295c635efSGarrett D'Amore mdoc_macro(MACRO_PROT_ARGS) 25395c635efSGarrett D'Amore { 25495c635efSGarrett D'Amore assert(tok < MDOC_MAX); 25595c635efSGarrett D'Amore 256*260e9a87SYuri Pankov if (mdoc->flags & MDOC_PBODY) { 257*260e9a87SYuri Pankov if (tok == MDOC_Dt) { 258*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_DT_LATE, 259*260e9a87SYuri Pankov mdoc->parse, line, ppos, 260*260e9a87SYuri Pankov "Dt %s", buf + *pos); 261*260e9a87SYuri Pankov return; 26295c635efSGarrett D'Amore } 263*260e9a87SYuri Pankov } else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) { 264*260e9a87SYuri Pankov if (mdoc->meta.title == NULL) { 265*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_DT_NOTITLE, 266*260e9a87SYuri Pankov mdoc->parse, line, ppos, "%s %s", 267*260e9a87SYuri Pankov mdoc_macronames[tok], buf + *pos); 268*260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED"); 269*260e9a87SYuri Pankov } 270698f87a4SGarrett D'Amore if (NULL == mdoc->meta.vol) 271698f87a4SGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL"); 272698f87a4SGarrett D'Amore mdoc->flags |= MDOC_PBODY; 27395c635efSGarrett D'Amore } 274*260e9a87SYuri Pankov (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf); 27595c635efSGarrett D'Amore } 27695c635efSGarrett D'Amore 27795c635efSGarrett D'Amore 278*260e9a87SYuri Pankov static void 27995c635efSGarrett D'Amore node_append(struct mdoc *mdoc, struct mdoc_node *p) 28095c635efSGarrett D'Amore { 28195c635efSGarrett D'Amore 28295c635efSGarrett D'Amore assert(mdoc->last); 28395c635efSGarrett D'Amore assert(mdoc->first); 28495c635efSGarrett D'Amore assert(MDOC_ROOT != p->type); 28595c635efSGarrett D'Amore 28695c635efSGarrett D'Amore switch (mdoc->next) { 287*260e9a87SYuri Pankov case MDOC_NEXT_SIBLING: 28895c635efSGarrett D'Amore mdoc->last->next = p; 28995c635efSGarrett D'Amore p->prev = mdoc->last; 29095c635efSGarrett D'Amore p->parent = mdoc->last->parent; 29195c635efSGarrett D'Amore break; 292*260e9a87SYuri Pankov case MDOC_NEXT_CHILD: 29395c635efSGarrett D'Amore mdoc->last->child = p; 29495c635efSGarrett D'Amore p->parent = mdoc->last; 29595c635efSGarrett D'Amore break; 29695c635efSGarrett D'Amore default: 29795c635efSGarrett D'Amore abort(); 29895c635efSGarrett D'Amore /* NOTREACHED */ 29995c635efSGarrett D'Amore } 30095c635efSGarrett D'Amore 30195c635efSGarrett D'Amore p->parent->nchild++; 30295c635efSGarrett D'Amore 30395c635efSGarrett D'Amore /* 30495c635efSGarrett D'Amore * Copy over the normalised-data pointer of our parent. Not 30595c635efSGarrett D'Amore * everybody has one, but copying a null pointer is fine. 30695c635efSGarrett D'Amore */ 30795c635efSGarrett D'Amore 30895c635efSGarrett D'Amore switch (p->type) { 309*260e9a87SYuri Pankov case MDOC_BODY: 310698f87a4SGarrett D'Amore if (ENDBODY_NOT != p->end) 311698f87a4SGarrett D'Amore break; 31295c635efSGarrett D'Amore /* FALLTHROUGH */ 313*260e9a87SYuri Pankov case MDOC_TAIL: 31495c635efSGarrett D'Amore /* FALLTHROUGH */ 315*260e9a87SYuri Pankov case MDOC_HEAD: 31695c635efSGarrett D'Amore p->norm = p->parent->norm; 31795c635efSGarrett D'Amore break; 31895c635efSGarrett D'Amore default: 31995c635efSGarrett D'Amore break; 32095c635efSGarrett D'Amore } 32195c635efSGarrett D'Amore 322*260e9a87SYuri Pankov mdoc_valid_pre(mdoc, p); 32395c635efSGarrett D'Amore 32495c635efSGarrett D'Amore switch (p->type) { 325*260e9a87SYuri Pankov case MDOC_HEAD: 32695c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 32795c635efSGarrett D'Amore p->parent->head = p; 32895c635efSGarrett D'Amore break; 329*260e9a87SYuri Pankov case MDOC_TAIL: 33095c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 33195c635efSGarrett D'Amore p->parent->tail = p; 33295c635efSGarrett D'Amore break; 333*260e9a87SYuri Pankov case MDOC_BODY: 33495c635efSGarrett D'Amore if (p->end) 33595c635efSGarrett D'Amore break; 33695c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type); 33795c635efSGarrett D'Amore p->parent->body = p; 33895c635efSGarrett D'Amore break; 33995c635efSGarrett D'Amore default: 34095c635efSGarrett D'Amore break; 34195c635efSGarrett D'Amore } 34295c635efSGarrett D'Amore 34395c635efSGarrett D'Amore mdoc->last = p; 34495c635efSGarrett D'Amore 34595c635efSGarrett D'Amore switch (p->type) { 346*260e9a87SYuri Pankov case MDOC_TBL: 34795c635efSGarrett D'Amore /* FALLTHROUGH */ 348*260e9a87SYuri Pankov case MDOC_TEXT: 349*260e9a87SYuri Pankov mdoc_valid_post(mdoc); 35095c635efSGarrett D'Amore break; 35195c635efSGarrett D'Amore default: 35295c635efSGarrett D'Amore break; 35395c635efSGarrett D'Amore } 35495c635efSGarrett D'Amore } 35595c635efSGarrett D'Amore 35695c635efSGarrett D'Amore static struct mdoc_node * 357698f87a4SGarrett D'Amore node_alloc(struct mdoc *mdoc, int line, int pos, 35895c635efSGarrett D'Amore enum mdoct tok, enum mdoc_type type) 35995c635efSGarrett D'Amore { 36095c635efSGarrett D'Amore struct mdoc_node *p; 36195c635efSGarrett D'Amore 36295c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc_node)); 363698f87a4SGarrett D'Amore p->sec = mdoc->lastsec; 36495c635efSGarrett D'Amore p->line = line; 36595c635efSGarrett D'Amore p->pos = pos; 36695c635efSGarrett D'Amore p->tok = tok; 36795c635efSGarrett D'Amore p->type = type; 36895c635efSGarrett D'Amore 36995c635efSGarrett D'Amore /* Flag analysis. */ 37095c635efSGarrett D'Amore 371698f87a4SGarrett D'Amore if (MDOC_SYNOPSIS & mdoc->flags) 37295c635efSGarrett D'Amore p->flags |= MDOC_SYNPRETTY; 37395c635efSGarrett D'Amore else 37495c635efSGarrett D'Amore p->flags &= ~MDOC_SYNPRETTY; 375698f87a4SGarrett D'Amore if (MDOC_NEWLINE & mdoc->flags) 37695c635efSGarrett D'Amore p->flags |= MDOC_LINE; 377698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_NEWLINE; 37895c635efSGarrett D'Amore 37995c635efSGarrett D'Amore return(p); 38095c635efSGarrett D'Amore } 38195c635efSGarrett D'Amore 382*260e9a87SYuri Pankov void 383698f87a4SGarrett D'Amore mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) 38495c635efSGarrett D'Amore { 38595c635efSGarrett D'Amore struct mdoc_node *p; 38695c635efSGarrett D'Amore 387698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL); 388*260e9a87SYuri Pankov node_append(mdoc, p); 389698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 39095c635efSGarrett D'Amore } 39195c635efSGarrett D'Amore 392*260e9a87SYuri Pankov struct mdoc_node * 393698f87a4SGarrett D'Amore mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) 39495c635efSGarrett D'Amore { 39595c635efSGarrett D'Amore struct mdoc_node *p; 39695c635efSGarrett D'Amore 397698f87a4SGarrett D'Amore assert(mdoc->first); 398698f87a4SGarrett D'Amore assert(mdoc->last); 399698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD); 400*260e9a87SYuri Pankov node_append(mdoc, p); 401698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 402*260e9a87SYuri Pankov return(p); 40395c635efSGarrett D'Amore } 40495c635efSGarrett D'Amore 405*260e9a87SYuri Pankov struct mdoc_node * 406698f87a4SGarrett D'Amore mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) 40795c635efSGarrett D'Amore { 40895c635efSGarrett D'Amore struct mdoc_node *p; 40995c635efSGarrett D'Amore 410698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); 411*260e9a87SYuri Pankov node_append(mdoc, p); 412698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 413*260e9a87SYuri Pankov return(p); 41495c635efSGarrett D'Amore } 41595c635efSGarrett D'Amore 416*260e9a87SYuri Pankov struct mdoc_node * 417698f87a4SGarrett D'Amore mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, 41895c635efSGarrett D'Amore struct mdoc_node *body, enum mdoc_endbody end) 41995c635efSGarrett D'Amore { 42095c635efSGarrett D'Amore struct mdoc_node *p; 42195c635efSGarrett D'Amore 422*260e9a87SYuri Pankov body->flags |= MDOC_ENDED; 423*260e9a87SYuri Pankov body->parent->flags |= MDOC_ENDED; 424698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); 425*260e9a87SYuri Pankov p->body = body; 426698f87a4SGarrett D'Amore p->norm = body->norm; 42795c635efSGarrett D'Amore p->end = end; 428*260e9a87SYuri Pankov node_append(mdoc, p); 429698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 430*260e9a87SYuri Pankov return(p); 43195c635efSGarrett D'Amore } 43295c635efSGarrett D'Amore 433*260e9a87SYuri Pankov struct mdoc_node * 434698f87a4SGarrett D'Amore mdoc_block_alloc(struct mdoc *mdoc, int line, int pos, 43595c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args) 43695c635efSGarrett D'Amore { 43795c635efSGarrett D'Amore struct mdoc_node *p; 43895c635efSGarrett D'Amore 439698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK); 44095c635efSGarrett D'Amore p->args = args; 44195c635efSGarrett D'Amore if (p->args) 44295c635efSGarrett D'Amore (args->refcnt)++; 44395c635efSGarrett D'Amore 44495c635efSGarrett D'Amore switch (tok) { 445*260e9a87SYuri Pankov case MDOC_Bd: 44695c635efSGarrett D'Amore /* FALLTHROUGH */ 447*260e9a87SYuri Pankov case MDOC_Bf: 44895c635efSGarrett D'Amore /* FALLTHROUGH */ 449*260e9a87SYuri Pankov case MDOC_Bl: 45095c635efSGarrett D'Amore /* FALLTHROUGH */ 451*260e9a87SYuri Pankov case MDOC_En: 452*260e9a87SYuri Pankov /* FALLTHROUGH */ 453*260e9a87SYuri Pankov case MDOC_Rs: 45495c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); 45595c635efSGarrett D'Amore break; 45695c635efSGarrett D'Amore default: 45795c635efSGarrett D'Amore break; 45895c635efSGarrett D'Amore } 459*260e9a87SYuri Pankov node_append(mdoc, p); 460698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 461*260e9a87SYuri Pankov return(p); 46295c635efSGarrett D'Amore } 46395c635efSGarrett D'Amore 464*260e9a87SYuri Pankov void 465698f87a4SGarrett D'Amore mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos, 46695c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args) 46795c635efSGarrett D'Amore { 46895c635efSGarrett D'Amore struct mdoc_node *p; 46995c635efSGarrett D'Amore 470698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM); 47195c635efSGarrett D'Amore p->args = args; 47295c635efSGarrett D'Amore if (p->args) 47395c635efSGarrett D'Amore (args->refcnt)++; 47495c635efSGarrett D'Amore 47595c635efSGarrett D'Amore switch (tok) { 476*260e9a87SYuri Pankov case MDOC_An: 47795c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); 47895c635efSGarrett D'Amore break; 47995c635efSGarrett D'Amore default: 48095c635efSGarrett D'Amore break; 48195c635efSGarrett D'Amore } 482*260e9a87SYuri Pankov node_append(mdoc, p); 483698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 48495c635efSGarrett D'Amore } 48595c635efSGarrett D'Amore 486*260e9a87SYuri Pankov void 487698f87a4SGarrett D'Amore mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p) 48895c635efSGarrett D'Amore { 48995c635efSGarrett D'Amore struct mdoc_node *n; 49095c635efSGarrett D'Amore 491698f87a4SGarrett D'Amore n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT); 492698f87a4SGarrett D'Amore n->string = roff_strdup(mdoc->roff, p); 493*260e9a87SYuri Pankov node_append(mdoc, n); 494698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 49595c635efSGarrett D'Amore } 49695c635efSGarrett D'Amore 497698f87a4SGarrett D'Amore void 498698f87a4SGarrett D'Amore mdoc_word_append(struct mdoc *mdoc, const char *p) 499698f87a4SGarrett D'Amore { 500698f87a4SGarrett D'Amore struct mdoc_node *n; 501698f87a4SGarrett D'Amore char *addstr, *newstr; 502698f87a4SGarrett D'Amore 503698f87a4SGarrett D'Amore n = mdoc->last; 504698f87a4SGarrett D'Amore addstr = roff_strdup(mdoc->roff, p); 505*260e9a87SYuri Pankov mandoc_asprintf(&newstr, "%s %s", n->string, addstr); 506698f87a4SGarrett D'Amore free(addstr); 507698f87a4SGarrett D'Amore free(n->string); 508698f87a4SGarrett D'Amore n->string = newstr; 509698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 510698f87a4SGarrett D'Amore } 51195c635efSGarrett D'Amore 51295c635efSGarrett D'Amore static void 51395c635efSGarrett D'Amore mdoc_node_free(struct mdoc_node *p) 51495c635efSGarrett D'Amore { 51595c635efSGarrett D'Amore 51695c635efSGarrett D'Amore if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type) 51795c635efSGarrett D'Amore free(p->norm); 51895c635efSGarrett D'Amore if (p->string) 51995c635efSGarrett D'Amore free(p->string); 52095c635efSGarrett D'Amore if (p->args) 52195c635efSGarrett D'Amore mdoc_argv_free(p->args); 52295c635efSGarrett D'Amore free(p); 52395c635efSGarrett D'Amore } 52495c635efSGarrett D'Amore 52595c635efSGarrett D'Amore static void 526698f87a4SGarrett D'Amore mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n) 52795c635efSGarrett D'Amore { 52895c635efSGarrett D'Amore 52995c635efSGarrett D'Amore /* Adjust siblings. */ 53095c635efSGarrett D'Amore 53195c635efSGarrett D'Amore if (n->prev) 53295c635efSGarrett D'Amore n->prev->next = n->next; 53395c635efSGarrett D'Amore if (n->next) 53495c635efSGarrett D'Amore n->next->prev = n->prev; 53595c635efSGarrett D'Amore 53695c635efSGarrett D'Amore /* Adjust parent. */ 53795c635efSGarrett D'Amore 53895c635efSGarrett D'Amore if (n->parent) { 53995c635efSGarrett D'Amore n->parent->nchild--; 54095c635efSGarrett D'Amore if (n->parent->child == n) 54195c635efSGarrett D'Amore n->parent->child = n->prev ? n->prev : n->next; 54295c635efSGarrett D'Amore if (n->parent->last == n) 54395c635efSGarrett D'Amore n->parent->last = n->prev ? n->prev : NULL; 54495c635efSGarrett D'Amore } 54595c635efSGarrett D'Amore 54695c635efSGarrett D'Amore /* Adjust parse point, if applicable. */ 54795c635efSGarrett D'Amore 548698f87a4SGarrett D'Amore if (mdoc && mdoc->last == n) { 54995c635efSGarrett D'Amore if (n->prev) { 550698f87a4SGarrett D'Amore mdoc->last = n->prev; 551698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 55295c635efSGarrett D'Amore } else { 553698f87a4SGarrett D'Amore mdoc->last = n->parent; 554698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 55595c635efSGarrett D'Amore } 55695c635efSGarrett D'Amore } 55795c635efSGarrett D'Amore 558698f87a4SGarrett D'Amore if (mdoc && mdoc->first == n) 559698f87a4SGarrett D'Amore mdoc->first = NULL; 56095c635efSGarrett D'Amore } 56195c635efSGarrett D'Amore 56295c635efSGarrett D'Amore void 563698f87a4SGarrett D'Amore mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p) 56495c635efSGarrett D'Amore { 56595c635efSGarrett D'Amore 56695c635efSGarrett D'Amore while (p->child) { 56795c635efSGarrett D'Amore assert(p->nchild); 568698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, p->child); 56995c635efSGarrett D'Amore } 57095c635efSGarrett D'Amore assert(0 == p->nchild); 57195c635efSGarrett D'Amore 572698f87a4SGarrett D'Amore mdoc_node_unlink(mdoc, p); 57395c635efSGarrett D'Amore mdoc_node_free(p); 57495c635efSGarrett D'Amore } 57595c635efSGarrett D'Amore 576*260e9a87SYuri Pankov void 577698f87a4SGarrett D'Amore mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p) 578698f87a4SGarrett D'Amore { 579698f87a4SGarrett D'Amore 580698f87a4SGarrett D'Amore mdoc_node_unlink(mdoc, p); 581*260e9a87SYuri Pankov node_append(mdoc, p); 582698f87a4SGarrett D'Amore } 583698f87a4SGarrett D'Amore 58495c635efSGarrett D'Amore /* 58595c635efSGarrett D'Amore * Parse free-form text, that is, a line that does not begin with the 58695c635efSGarrett D'Amore * control character. 58795c635efSGarrett D'Amore */ 58895c635efSGarrett D'Amore static int 589698f87a4SGarrett D'Amore mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs) 59095c635efSGarrett D'Amore { 59195c635efSGarrett D'Amore char *c, *ws, *end; 59295c635efSGarrett D'Amore struct mdoc_node *n; 59395c635efSGarrett D'Amore 594698f87a4SGarrett D'Amore assert(mdoc->last); 595698f87a4SGarrett D'Amore n = mdoc->last; 59695c635efSGarrett D'Amore 59795c635efSGarrett D'Amore /* 59895c635efSGarrett D'Amore * Divert directly to list processing if we're encountering a 59995c635efSGarrett D'Amore * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry 60095c635efSGarrett D'Amore * (a MDOC_BODY means it's already open, in which case we should 60195c635efSGarrett D'Amore * process within its context in the normal way). 60295c635efSGarrett D'Amore */ 60395c635efSGarrett D'Amore 604*260e9a87SYuri Pankov if (n->tok == MDOC_Bl && n->type == MDOC_BODY && 605*260e9a87SYuri Pankov n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) { 60695c635efSGarrett D'Amore /* `Bl' is open without any children. */ 607698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 608*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf); 609*260e9a87SYuri Pankov return(1); 61095c635efSGarrett D'Amore } 61195c635efSGarrett D'Amore 61295c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type && 61395c635efSGarrett D'Amore NULL != n->parent && 61495c635efSGarrett D'Amore MDOC_Bl == n->parent->tok && 61595c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) { 61695c635efSGarrett D'Amore /* `Bl' has block-level `It' children. */ 617698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 618*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf); 619*260e9a87SYuri Pankov return(1); 62095c635efSGarrett D'Amore } 62195c635efSGarrett D'Amore 62295c635efSGarrett D'Amore /* 62395c635efSGarrett D'Amore * Search for the beginning of unescaped trailing whitespace (ws) 62495c635efSGarrett D'Amore * and for the first character not to be output (end). 62595c635efSGarrett D'Amore */ 62695c635efSGarrett D'Amore 62795c635efSGarrett D'Amore /* FIXME: replace with strcspn(). */ 62895c635efSGarrett D'Amore ws = NULL; 62995c635efSGarrett D'Amore for (c = end = buf + offs; *c; c++) { 63095c635efSGarrett D'Amore switch (*c) { 63195c635efSGarrett D'Amore case ' ': 63295c635efSGarrett D'Amore if (NULL == ws) 63395c635efSGarrett D'Amore ws = c; 63495c635efSGarrett D'Amore continue; 63595c635efSGarrett D'Amore case '\t': 63695c635efSGarrett D'Amore /* 63795c635efSGarrett D'Amore * Always warn about trailing tabs, 63895c635efSGarrett D'Amore * even outside literal context, 63995c635efSGarrett D'Amore * where they should be put on the next line. 64095c635efSGarrett D'Amore */ 64195c635efSGarrett D'Amore if (NULL == ws) 64295c635efSGarrett D'Amore ws = c; 64395c635efSGarrett D'Amore /* 64495c635efSGarrett D'Amore * Strip trailing tabs in literal context only; 64595c635efSGarrett D'Amore * outside, they affect the next line. 64695c635efSGarrett D'Amore */ 647698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags) 64895c635efSGarrett D'Amore continue; 64995c635efSGarrett D'Amore break; 65095c635efSGarrett D'Amore case '\\': 65195c635efSGarrett D'Amore /* Skip the escaped character, too, if any. */ 65295c635efSGarrett D'Amore if (c[1]) 65395c635efSGarrett D'Amore c++; 65495c635efSGarrett D'Amore /* FALLTHROUGH */ 65595c635efSGarrett D'Amore default: 65695c635efSGarrett D'Amore ws = NULL; 65795c635efSGarrett D'Amore break; 65895c635efSGarrett D'Amore } 65995c635efSGarrett D'Amore end = c + 1; 66095c635efSGarrett D'Amore } 66195c635efSGarrett D'Amore *end = '\0'; 66295c635efSGarrett D'Amore 66395c635efSGarrett D'Amore if (ws) 664*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, 665*260e9a87SYuri Pankov line, (int)(ws-buf), NULL); 66695c635efSGarrett D'Amore 667*260e9a87SYuri Pankov if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) { 668*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse, 669*260e9a87SYuri Pankov line, (int)(c - buf), NULL); 67095c635efSGarrett D'Amore 67195c635efSGarrett D'Amore /* 67295c635efSGarrett D'Amore * Insert a `sp' in the case of a blank line. Technically, 67395c635efSGarrett D'Amore * blank lines aren't allowed, but enough manuals assume this 67495c635efSGarrett D'Amore * behaviour that we want to work around it. 67595c635efSGarrett D'Amore */ 676*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL); 677698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING; 678*260e9a87SYuri Pankov mdoc_valid_post(mdoc); 679*260e9a87SYuri Pankov return(1); 68095c635efSGarrett D'Amore } 68195c635efSGarrett D'Amore 682*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, line, offs, buf+offs); 68395c635efSGarrett D'Amore 684*260e9a87SYuri Pankov if (mdoc->flags & MDOC_LITERAL) 68595c635efSGarrett D'Amore return(1); 68695c635efSGarrett D'Amore 68795c635efSGarrett D'Amore /* 68895c635efSGarrett D'Amore * End-of-sentence check. If the last character is an unescaped 68995c635efSGarrett D'Amore * EOS character, then flag the node as being the end of a 69095c635efSGarrett D'Amore * sentence. The front-end will know how to interpret this. 69195c635efSGarrett D'Amore */ 69295c635efSGarrett D'Amore 69395c635efSGarrett D'Amore assert(buf < end); 69495c635efSGarrett D'Amore 695*260e9a87SYuri Pankov if (mandoc_eos(buf+offs, (size_t)(end-buf-offs))) 696698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_EOS; 69795c635efSGarrett D'Amore return(1); 69895c635efSGarrett D'Amore } 69995c635efSGarrett D'Amore 70095c635efSGarrett D'Amore /* 70195c635efSGarrett D'Amore * Parse a macro line, that is, a line beginning with the control 70295c635efSGarrett D'Amore * character. 70395c635efSGarrett D'Amore */ 70495c635efSGarrett D'Amore static int 705698f87a4SGarrett D'Amore mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs) 70695c635efSGarrett D'Amore { 707*260e9a87SYuri Pankov struct mdoc_node *n; 708*260e9a87SYuri Pankov const char *cp; 70995c635efSGarrett D'Amore enum mdoct tok; 71095c635efSGarrett D'Amore int i, sv; 71195c635efSGarrett D'Amore char mac[5]; 71295c635efSGarrett D'Amore 71395c635efSGarrett D'Amore sv = offs; 71495c635efSGarrett D'Amore 71595c635efSGarrett D'Amore /* 71695c635efSGarrett D'Amore * Copy the first word into a nil-terminated buffer. 717*260e9a87SYuri Pankov * Stop when a space, tab, escape, or eoln is encountered. 71895c635efSGarrett D'Amore */ 71995c635efSGarrett D'Amore 72095c635efSGarrett D'Amore i = 0; 721*260e9a87SYuri Pankov while (i < 4 && strchr(" \t\\", buf[offs]) == NULL) 72295c635efSGarrett D'Amore mac[i++] = buf[offs++]; 72395c635efSGarrett D'Amore 72495c635efSGarrett D'Amore mac[i] = '\0'; 72595c635efSGarrett D'Amore 726*260e9a87SYuri Pankov tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX; 72795c635efSGarrett D'Amore 728*260e9a87SYuri Pankov if (tok == MDOC_MAX) { 729*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO, mdoc->parse, 730*260e9a87SYuri Pankov ln, sv, buf + sv - 1); 73195c635efSGarrett D'Amore return(1); 73295c635efSGarrett D'Amore } 73395c635efSGarrett D'Amore 734*260e9a87SYuri Pankov /* Skip a leading escape sequence or tab. */ 73595c635efSGarrett D'Amore 736*260e9a87SYuri Pankov switch (buf[offs]) { 737*260e9a87SYuri Pankov case '\\': 738*260e9a87SYuri Pankov cp = buf + offs + 1; 739*260e9a87SYuri Pankov mandoc_escape(&cp, NULL, NULL); 740*260e9a87SYuri Pankov offs = cp - buf; 741*260e9a87SYuri Pankov break; 742*260e9a87SYuri Pankov case '\t': 74395c635efSGarrett D'Amore offs++; 744*260e9a87SYuri Pankov break; 745*260e9a87SYuri Pankov default: 746*260e9a87SYuri Pankov break; 747*260e9a87SYuri Pankov } 74895c635efSGarrett D'Amore 74995c635efSGarrett D'Amore /* Jump to the next non-whitespace word. */ 75095c635efSGarrett D'Amore 75195c635efSGarrett D'Amore while (buf[offs] && ' ' == buf[offs]) 75295c635efSGarrett D'Amore offs++; 75395c635efSGarrett D'Amore 75495c635efSGarrett D'Amore /* 75595c635efSGarrett D'Amore * Trailing whitespace. Note that tabs are allowed to be passed 75695c635efSGarrett D'Amore * into the parser as "text", so we only warn about spaces here. 75795c635efSGarrett D'Amore */ 75895c635efSGarrett D'Amore 75995c635efSGarrett D'Amore if ('\0' == buf[offs] && ' ' == buf[offs - 1]) 760*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, 761*260e9a87SYuri Pankov ln, offs - 1, NULL); 76295c635efSGarrett D'Amore 76395c635efSGarrett D'Amore /* 76495c635efSGarrett D'Amore * If an initial macro or a list invocation, divert directly 76595c635efSGarrett D'Amore * into macro processing. 76695c635efSGarrett D'Amore */ 76795c635efSGarrett D'Amore 768698f87a4SGarrett D'Amore if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) { 769*260e9a87SYuri Pankov mdoc_macro(mdoc, tok, ln, sv, &offs, buf); 77095c635efSGarrett D'Amore return(1); 77195c635efSGarrett D'Amore } 77295c635efSGarrett D'Amore 773698f87a4SGarrett D'Amore n = mdoc->last; 774698f87a4SGarrett D'Amore assert(mdoc->last); 77595c635efSGarrett D'Amore 77695c635efSGarrett D'Amore /* 77795c635efSGarrett D'Amore * If the first macro of a `Bl -column', open an `It' block 77895c635efSGarrett D'Amore * context around the parsed macro. 77995c635efSGarrett D'Amore */ 78095c635efSGarrett D'Amore 781*260e9a87SYuri Pankov if (n->tok == MDOC_Bl && n->type == MDOC_BODY && 782*260e9a87SYuri Pankov n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) { 783698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 784*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf); 78595c635efSGarrett D'Amore return(1); 78695c635efSGarrett D'Amore } 78795c635efSGarrett D'Amore 78895c635efSGarrett D'Amore /* 78995c635efSGarrett D'Amore * If we're following a block-level `It' within a `Bl -column' 79095c635efSGarrett D'Amore * context (perhaps opened in the above block or in ptext()), 79195c635efSGarrett D'Amore * then open an `It' block context around the parsed macro. 79295c635efSGarrett D'Amore */ 79395c635efSGarrett D'Amore 79495c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type && 79595c635efSGarrett D'Amore NULL != n->parent && 79695c635efSGarrett D'Amore MDOC_Bl == n->parent->tok && 79795c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) { 798698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL; 799*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf); 80095c635efSGarrett D'Amore return(1); 80195c635efSGarrett D'Amore } 80295c635efSGarrett D'Amore 80395c635efSGarrett D'Amore /* Normal processing of a macro. */ 80495c635efSGarrett D'Amore 805*260e9a87SYuri Pankov mdoc_macro(mdoc, tok, ln, sv, &offs, buf); 806*260e9a87SYuri Pankov 807*260e9a87SYuri Pankov /* In quick mode (for mandocdb), abort after the NAME section. */ 808*260e9a87SYuri Pankov 809*260e9a87SYuri Pankov if (mdoc->quick && MDOC_Sh == tok && 810*260e9a87SYuri Pankov SEC_NAME != mdoc->last->sec) 811*260e9a87SYuri Pankov return(2); 81295c635efSGarrett D'Amore 81395c635efSGarrett D'Amore return(1); 81495c635efSGarrett D'Amore } 81595c635efSGarrett D'Amore 81695c635efSGarrett D'Amore enum mdelim 81795c635efSGarrett D'Amore mdoc_isdelim(const char *p) 81895c635efSGarrett D'Amore { 81995c635efSGarrett D'Amore 82095c635efSGarrett D'Amore if ('\0' == p[0]) 82195c635efSGarrett D'Amore return(DELIM_NONE); 82295c635efSGarrett D'Amore 82395c635efSGarrett D'Amore if ('\0' == p[1]) 82495c635efSGarrett D'Amore switch (p[0]) { 825*260e9a87SYuri Pankov case '(': 82695c635efSGarrett D'Amore /* FALLTHROUGH */ 827*260e9a87SYuri Pankov case '[': 82895c635efSGarrett D'Amore return(DELIM_OPEN); 829*260e9a87SYuri Pankov case '|': 83095c635efSGarrett D'Amore return(DELIM_MIDDLE); 831*260e9a87SYuri Pankov case '.': 83295c635efSGarrett D'Amore /* FALLTHROUGH */ 833*260e9a87SYuri Pankov case ',': 83495c635efSGarrett D'Amore /* FALLTHROUGH */ 835*260e9a87SYuri Pankov case ';': 83695c635efSGarrett D'Amore /* FALLTHROUGH */ 837*260e9a87SYuri Pankov case ':': 83895c635efSGarrett D'Amore /* FALLTHROUGH */ 839*260e9a87SYuri Pankov case '?': 84095c635efSGarrett D'Amore /* FALLTHROUGH */ 841*260e9a87SYuri Pankov case '!': 84295c635efSGarrett D'Amore /* FALLTHROUGH */ 843*260e9a87SYuri Pankov case ')': 84495c635efSGarrett D'Amore /* FALLTHROUGH */ 845*260e9a87SYuri Pankov case ']': 84695c635efSGarrett D'Amore return(DELIM_CLOSE); 84795c635efSGarrett D'Amore default: 84895c635efSGarrett D'Amore return(DELIM_NONE); 84995c635efSGarrett D'Amore } 85095c635efSGarrett D'Amore 85195c635efSGarrett D'Amore if ('\\' != p[0]) 85295c635efSGarrett D'Amore return(DELIM_NONE); 85395c635efSGarrett D'Amore 85495c635efSGarrett D'Amore if (0 == strcmp(p + 1, ".")) 85595c635efSGarrett D'Amore return(DELIM_CLOSE); 856698f87a4SGarrett D'Amore if (0 == strcmp(p + 1, "fR|\\fP")) 85795c635efSGarrett D'Amore return(DELIM_MIDDLE); 85895c635efSGarrett D'Amore 85995c635efSGarrett D'Amore return(DELIM_NONE); 86095c635efSGarrett D'Amore } 861*260e9a87SYuri Pankov 862*260e9a87SYuri Pankov void 863*260e9a87SYuri Pankov mdoc_deroff(char **dest, const struct mdoc_node *n) 864*260e9a87SYuri Pankov { 865*260e9a87SYuri Pankov char *cp; 866*260e9a87SYuri Pankov size_t sz; 867*260e9a87SYuri Pankov 868*260e9a87SYuri Pankov if (MDOC_TEXT != n->type) { 869*260e9a87SYuri Pankov for (n = n->child; n; n = n->next) 870*260e9a87SYuri Pankov mdoc_deroff(dest, n); 871*260e9a87SYuri Pankov return; 872*260e9a87SYuri Pankov } 873*260e9a87SYuri Pankov 874*260e9a87SYuri Pankov /* Skip leading whitespace. */ 875*260e9a87SYuri Pankov 876*260e9a87SYuri Pankov for (cp = n->string; '\0' != *cp; cp++) 877*260e9a87SYuri Pankov if (0 == isspace((unsigned char)*cp)) 878*260e9a87SYuri Pankov break; 879*260e9a87SYuri Pankov 880*260e9a87SYuri Pankov /* Skip trailing whitespace. */ 881*260e9a87SYuri Pankov 882*260e9a87SYuri Pankov for (sz = strlen(cp); sz; sz--) 883*260e9a87SYuri Pankov if (0 == isspace((unsigned char)cp[sz-1])) 884*260e9a87SYuri Pankov break; 885*260e9a87SYuri Pankov 886*260e9a87SYuri Pankov /* Skip empty strings. */ 887*260e9a87SYuri Pankov 888*260e9a87SYuri Pankov if (0 == sz) 889*260e9a87SYuri Pankov return; 890*260e9a87SYuri Pankov 891*260e9a87SYuri Pankov if (NULL == *dest) { 892*260e9a87SYuri Pankov *dest = mandoc_strndup(cp, sz); 893*260e9a87SYuri Pankov return; 894*260e9a87SYuri Pankov } 895*260e9a87SYuri Pankov 896*260e9a87SYuri Pankov mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp); 897*260e9a87SYuri Pankov free(*dest); 898*260e9a87SYuri Pankov *dest = cp; 899*260e9a87SYuri Pankov } 900