1241675Suqs/* $Id: man.c,v 1.115 2012/01/03 15:16:24 kristaps Exp $ */ 2241675Suqs/* 3241675Suqs * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4241675Suqs * 5241675Suqs * Permission to use, copy, modify, and distribute this software for any 6241675Suqs * purpose with or without fee is hereby granted, provided that the above 7241675Suqs * copyright notice and this permission notice appear in all copies. 8241675Suqs * 9241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16241675Suqs */ 17241675Suqs#ifdef HAVE_CONFIG_H 18241675Suqs#include "config.h" 19241675Suqs#endif 20241675Suqs 21241675Suqs#include <sys/types.h> 22241675Suqs 23241675Suqs#include <assert.h> 24241675Suqs#include <stdarg.h> 25241675Suqs#include <stdlib.h> 26241675Suqs#include <stdio.h> 27241675Suqs#include <string.h> 28241675Suqs 29241675Suqs#include "man.h" 30241675Suqs#include "mandoc.h" 31241675Suqs#include "libman.h" 32241675Suqs#include "libmandoc.h" 33241675Suqs 34241675Suqsconst char *const __man_macronames[MAN_MAX] = { 35241675Suqs "br", "TH", "SH", "SS", 36241675Suqs "TP", "LP", "PP", "P", 37241675Suqs "IP", "HP", "SM", "SB", 38241675Suqs "BI", "IB", "BR", "RB", 39241675Suqs "R", "B", "I", "IR", 40241675Suqs "RI", "na", "sp", "nf", 41241675Suqs "fi", "RE", "RS", "DT", 42241675Suqs "UC", "PD", "AT", "in", 43241675Suqs "ft", "OP" 44241675Suqs }; 45241675Suqs 46241675Suqsconst char * const *man_macronames = __man_macronames; 47241675Suqs 48241675Suqsstatic struct man_node *man_node_alloc(struct man *, int, int, 49241675Suqs enum man_type, enum mant); 50241675Suqsstatic int man_node_append(struct man *, 51241675Suqs struct man_node *); 52241675Suqsstatic void man_node_free(struct man_node *); 53241675Suqsstatic void man_node_unlink(struct man *, 54241675Suqs struct man_node *); 55241675Suqsstatic int man_ptext(struct man *, int, char *, int); 56241675Suqsstatic int man_pmacro(struct man *, int, char *, int); 57241675Suqsstatic void man_free1(struct man *); 58241675Suqsstatic void man_alloc1(struct man *); 59241675Suqsstatic int man_descope(struct man *, int, int); 60241675Suqs 61241675Suqs 62241675Suqsconst struct man_node * 63241675Suqsman_node(const struct man *m) 64241675Suqs{ 65241675Suqs 66241675Suqs assert( ! (MAN_HALT & m->flags)); 67241675Suqs return(m->first); 68241675Suqs} 69241675Suqs 70241675Suqs 71241675Suqsconst struct man_meta * 72241675Suqsman_meta(const struct man *m) 73241675Suqs{ 74241675Suqs 75241675Suqs assert( ! (MAN_HALT & m->flags)); 76241675Suqs return(&m->meta); 77241675Suqs} 78241675Suqs 79241675Suqs 80241675Suqsvoid 81241675Suqsman_reset(struct man *man) 82241675Suqs{ 83241675Suqs 84241675Suqs man_free1(man); 85241675Suqs man_alloc1(man); 86241675Suqs} 87241675Suqs 88241675Suqs 89241675Suqsvoid 90241675Suqsman_free(struct man *man) 91241675Suqs{ 92241675Suqs 93241675Suqs man_free1(man); 94241675Suqs free(man); 95241675Suqs} 96241675Suqs 97241675Suqs 98241675Suqsstruct man * 99241675Suqsman_alloc(struct roff *roff, struct mparse *parse) 100241675Suqs{ 101241675Suqs struct man *p; 102241675Suqs 103241675Suqs p = mandoc_calloc(1, sizeof(struct man)); 104241675Suqs 105241675Suqs man_hash_init(); 106241675Suqs p->parse = parse; 107241675Suqs p->roff = roff; 108241675Suqs 109241675Suqs man_alloc1(p); 110241675Suqs return(p); 111241675Suqs} 112241675Suqs 113241675Suqs 114241675Suqsint 115241675Suqsman_endparse(struct man *m) 116241675Suqs{ 117241675Suqs 118241675Suqs assert( ! (MAN_HALT & m->flags)); 119241675Suqs if (man_macroend(m)) 120241675Suqs return(1); 121241675Suqs m->flags |= MAN_HALT; 122241675Suqs return(0); 123241675Suqs} 124241675Suqs 125241675Suqs 126241675Suqsint 127241675Suqsman_parseln(struct man *m, int ln, char *buf, int offs) 128241675Suqs{ 129241675Suqs 130241675Suqs m->flags |= MAN_NEWLINE; 131241675Suqs 132241675Suqs assert( ! (MAN_HALT & m->flags)); 133241675Suqs 134241675Suqs return (mandoc_getcontrol(buf, &offs) ? 135241675Suqs man_pmacro(m, ln, buf, offs) : 136241675Suqs man_ptext(m, ln, buf, offs)); 137241675Suqs} 138241675Suqs 139241675Suqs 140241675Suqsstatic void 141241675Suqsman_free1(struct man *man) 142241675Suqs{ 143241675Suqs 144241675Suqs if (man->first) 145241675Suqs man_node_delete(man, man->first); 146241675Suqs if (man->meta.title) 147241675Suqs free(man->meta.title); 148241675Suqs if (man->meta.source) 149241675Suqs free(man->meta.source); 150241675Suqs if (man->meta.date) 151241675Suqs free(man->meta.date); 152241675Suqs if (man->meta.vol) 153241675Suqs free(man->meta.vol); 154241675Suqs if (man->meta.msec) 155241675Suqs free(man->meta.msec); 156241675Suqs} 157241675Suqs 158241675Suqs 159241675Suqsstatic void 160241675Suqsman_alloc1(struct man *m) 161241675Suqs{ 162241675Suqs 163241675Suqs memset(&m->meta, 0, sizeof(struct man_meta)); 164241675Suqs m->flags = 0; 165241675Suqs m->last = mandoc_calloc(1, sizeof(struct man_node)); 166241675Suqs m->first = m->last; 167241675Suqs m->last->type = MAN_ROOT; 168241675Suqs m->last->tok = MAN_MAX; 169241675Suqs m->next = MAN_NEXT_CHILD; 170241675Suqs} 171241675Suqs 172241675Suqs 173241675Suqsstatic int 174241675Suqsman_node_append(struct man *man, struct man_node *p) 175241675Suqs{ 176241675Suqs 177241675Suqs assert(man->last); 178241675Suqs assert(man->first); 179241675Suqs assert(MAN_ROOT != p->type); 180241675Suqs 181241675Suqs switch (man->next) { 182241675Suqs case (MAN_NEXT_SIBLING): 183241675Suqs man->last->next = p; 184241675Suqs p->prev = man->last; 185241675Suqs p->parent = man->last->parent; 186241675Suqs break; 187241675Suqs case (MAN_NEXT_CHILD): 188241675Suqs man->last->child = p; 189241675Suqs p->parent = man->last; 190241675Suqs break; 191241675Suqs default: 192241675Suqs abort(); 193241675Suqs /* NOTREACHED */ 194241675Suqs } 195241675Suqs 196241675Suqs assert(p->parent); 197241675Suqs p->parent->nchild++; 198241675Suqs 199241675Suqs if ( ! man_valid_pre(man, p)) 200241675Suqs return(0); 201241675Suqs 202241675Suqs switch (p->type) { 203241675Suqs case (MAN_HEAD): 204241675Suqs assert(MAN_BLOCK == p->parent->type); 205241675Suqs p->parent->head = p; 206241675Suqs break; 207241675Suqs case (MAN_TAIL): 208241675Suqs assert(MAN_BLOCK == p->parent->type); 209241675Suqs p->parent->tail = p; 210241675Suqs break; 211241675Suqs case (MAN_BODY): 212241675Suqs assert(MAN_BLOCK == p->parent->type); 213241675Suqs p->parent->body = p; 214241675Suqs break; 215241675Suqs default: 216241675Suqs break; 217241675Suqs } 218241675Suqs 219241675Suqs man->last = p; 220241675Suqs 221241675Suqs switch (p->type) { 222241675Suqs case (MAN_TBL): 223241675Suqs /* FALLTHROUGH */ 224241675Suqs case (MAN_TEXT): 225241675Suqs if ( ! man_valid_post(man)) 226241675Suqs return(0); 227241675Suqs break; 228241675Suqs default: 229241675Suqs break; 230241675Suqs } 231241675Suqs 232241675Suqs return(1); 233241675Suqs} 234241675Suqs 235241675Suqs 236241675Suqsstatic struct man_node * 237241675Suqsman_node_alloc(struct man *m, int line, int pos, 238241675Suqs enum man_type type, enum mant tok) 239241675Suqs{ 240241675Suqs struct man_node *p; 241241675Suqs 242241675Suqs p = mandoc_calloc(1, sizeof(struct man_node)); 243241675Suqs p->line = line; 244241675Suqs p->pos = pos; 245241675Suqs p->type = type; 246241675Suqs p->tok = tok; 247241675Suqs 248241675Suqs if (MAN_NEWLINE & m->flags) 249241675Suqs p->flags |= MAN_LINE; 250241675Suqs m->flags &= ~MAN_NEWLINE; 251241675Suqs return(p); 252241675Suqs} 253241675Suqs 254241675Suqs 255241675Suqsint 256241675Suqsman_elem_alloc(struct man *m, int line, int pos, enum mant tok) 257241675Suqs{ 258241675Suqs struct man_node *p; 259241675Suqs 260241675Suqs p = man_node_alloc(m, line, pos, MAN_ELEM, tok); 261241675Suqs if ( ! man_node_append(m, p)) 262241675Suqs return(0); 263241675Suqs m->next = MAN_NEXT_CHILD; 264241675Suqs return(1); 265241675Suqs} 266241675Suqs 267241675Suqs 268241675Suqsint 269241675Suqsman_tail_alloc(struct man *m, int line, int pos, enum mant tok) 270241675Suqs{ 271241675Suqs struct man_node *p; 272241675Suqs 273241675Suqs p = man_node_alloc(m, line, pos, MAN_TAIL, tok); 274241675Suqs if ( ! man_node_append(m, p)) 275241675Suqs return(0); 276241675Suqs m->next = MAN_NEXT_CHILD; 277241675Suqs return(1); 278241675Suqs} 279241675Suqs 280241675Suqs 281241675Suqsint 282241675Suqsman_head_alloc(struct man *m, int line, int pos, enum mant tok) 283241675Suqs{ 284241675Suqs struct man_node *p; 285241675Suqs 286241675Suqs p = man_node_alloc(m, line, pos, MAN_HEAD, tok); 287241675Suqs if ( ! man_node_append(m, p)) 288241675Suqs return(0); 289241675Suqs m->next = MAN_NEXT_CHILD; 290241675Suqs return(1); 291241675Suqs} 292241675Suqs 293241675Suqs 294241675Suqsint 295241675Suqsman_body_alloc(struct man *m, int line, int pos, enum mant tok) 296241675Suqs{ 297241675Suqs struct man_node *p; 298241675Suqs 299241675Suqs p = man_node_alloc(m, line, pos, MAN_BODY, tok); 300241675Suqs if ( ! man_node_append(m, p)) 301241675Suqs return(0); 302241675Suqs m->next = MAN_NEXT_CHILD; 303241675Suqs return(1); 304241675Suqs} 305241675Suqs 306241675Suqs 307241675Suqsint 308241675Suqsman_block_alloc(struct man *m, int line, int pos, enum mant tok) 309241675Suqs{ 310241675Suqs struct man_node *p; 311241675Suqs 312241675Suqs p = man_node_alloc(m, line, pos, MAN_BLOCK, tok); 313241675Suqs if ( ! man_node_append(m, p)) 314241675Suqs return(0); 315241675Suqs m->next = MAN_NEXT_CHILD; 316241675Suqs return(1); 317241675Suqs} 318241675Suqs 319241675Suqsint 320241675Suqsman_word_alloc(struct man *m, int line, int pos, const char *word) 321241675Suqs{ 322241675Suqs struct man_node *n; 323241675Suqs 324241675Suqs n = man_node_alloc(m, line, pos, MAN_TEXT, MAN_MAX); 325241675Suqs n->string = roff_strdup(m->roff, word); 326241675Suqs 327241675Suqs if ( ! man_node_append(m, n)) 328241675Suqs return(0); 329241675Suqs 330241675Suqs m->next = MAN_NEXT_SIBLING; 331241675Suqs return(1); 332241675Suqs} 333241675Suqs 334241675Suqs 335241675Suqs/* 336241675Suqs * Free all of the resources held by a node. This does NOT unlink a 337241675Suqs * node from its context; for that, see man_node_unlink(). 338241675Suqs */ 339241675Suqsstatic void 340241675Suqsman_node_free(struct man_node *p) 341241675Suqs{ 342241675Suqs 343241675Suqs if (p->string) 344241675Suqs free(p->string); 345241675Suqs free(p); 346241675Suqs} 347241675Suqs 348241675Suqs 349241675Suqsvoid 350241675Suqsman_node_delete(struct man *m, struct man_node *p) 351241675Suqs{ 352241675Suqs 353241675Suqs while (p->child) 354241675Suqs man_node_delete(m, p->child); 355241675Suqs 356241675Suqs man_node_unlink(m, p); 357241675Suqs man_node_free(p); 358241675Suqs} 359241675Suqs 360241675Suqsint 361241675Suqsman_addeqn(struct man *m, const struct eqn *ep) 362241675Suqs{ 363241675Suqs struct man_node *n; 364241675Suqs 365241675Suqs assert( ! (MAN_HALT & m->flags)); 366241675Suqs 367241675Suqs n = man_node_alloc(m, ep->ln, ep->pos, MAN_EQN, MAN_MAX); 368241675Suqs n->eqn = ep; 369241675Suqs 370241675Suqs if ( ! man_node_append(m, n)) 371241675Suqs return(0); 372241675Suqs 373241675Suqs m->next = MAN_NEXT_SIBLING; 374241675Suqs return(man_descope(m, ep->ln, ep->pos)); 375241675Suqs} 376241675Suqs 377241675Suqsint 378241675Suqsman_addspan(struct man *m, const struct tbl_span *sp) 379241675Suqs{ 380241675Suqs struct man_node *n; 381241675Suqs 382241675Suqs assert( ! (MAN_HALT & m->flags)); 383241675Suqs 384241675Suqs n = man_node_alloc(m, sp->line, 0, MAN_TBL, MAN_MAX); 385241675Suqs n->span = sp; 386241675Suqs 387241675Suqs if ( ! man_node_append(m, n)) 388241675Suqs return(0); 389241675Suqs 390241675Suqs m->next = MAN_NEXT_SIBLING; 391241675Suqs return(man_descope(m, sp->line, 0)); 392241675Suqs} 393241675Suqs 394241675Suqsstatic int 395241675Suqsman_descope(struct man *m, int line, int offs) 396241675Suqs{ 397241675Suqs /* 398241675Suqs * Co-ordinate what happens with having a next-line scope open: 399241675Suqs * first close out the element scope (if applicable), then close 400241675Suqs * out the block scope (also if applicable). 401241675Suqs */ 402241675Suqs 403241675Suqs if (MAN_ELINE & m->flags) { 404241675Suqs m->flags &= ~MAN_ELINE; 405241675Suqs if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) 406241675Suqs return(0); 407241675Suqs } 408241675Suqs 409241675Suqs if ( ! (MAN_BLINE & m->flags)) 410241675Suqs return(1); 411241675Suqs m->flags &= ~MAN_BLINE; 412241675Suqs 413241675Suqs if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) 414241675Suqs return(0); 415241675Suqs return(man_body_alloc(m, line, offs, m->last->tok)); 416241675Suqs} 417241675Suqs 418241675Suqsstatic int 419241675Suqsman_ptext(struct man *m, int line, char *buf, int offs) 420241675Suqs{ 421241675Suqs int i; 422241675Suqs 423241675Suqs /* Literal free-form text whitespace is preserved. */ 424241675Suqs 425241675Suqs if (MAN_LITERAL & m->flags) { 426241675Suqs if ( ! man_word_alloc(m, line, offs, buf + offs)) 427241675Suqs return(0); 428241675Suqs return(man_descope(m, line, offs)); 429241675Suqs } 430241675Suqs 431241675Suqs /* Pump blank lines directly into the backend. */ 432241675Suqs 433241675Suqs for (i = offs; ' ' == buf[i]; i++) 434241675Suqs /* Skip leading whitespace. */ ; 435241675Suqs 436241675Suqs if ('\0' == buf[i]) { 437241675Suqs /* Allocate a blank entry. */ 438241675Suqs if ( ! man_word_alloc(m, line, offs, "")) 439241675Suqs return(0); 440241675Suqs return(man_descope(m, line, offs)); 441241675Suqs } 442241675Suqs 443241675Suqs /* 444241675Suqs * Warn if the last un-escaped character is whitespace. Then 445241675Suqs * strip away the remaining spaces (tabs stay!). 446241675Suqs */ 447241675Suqs 448241675Suqs i = (int)strlen(buf); 449241675Suqs assert(i); 450241675Suqs 451241675Suqs if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { 452241675Suqs if (i > 1 && '\\' != buf[i - 2]) 453241675Suqs man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE); 454241675Suqs 455241675Suqs for (--i; i && ' ' == buf[i]; i--) 456241675Suqs /* Spin back to non-space. */ ; 457241675Suqs 458241675Suqs /* Jump ahead of escaped whitespace. */ 459241675Suqs i += '\\' == buf[i] ? 2 : 1; 460241675Suqs 461241675Suqs buf[i] = '\0'; 462241675Suqs } 463241675Suqs 464241675Suqs if ( ! man_word_alloc(m, line, offs, buf + offs)) 465241675Suqs return(0); 466241675Suqs 467241675Suqs /* 468241675Suqs * End-of-sentence check. If the last character is an unescaped 469241675Suqs * EOS character, then flag the node as being the end of a 470241675Suqs * sentence. The front-end will know how to interpret this. 471241675Suqs */ 472241675Suqs 473241675Suqs assert(i); 474241675Suqs if (mandoc_eos(buf, (size_t)i, 0)) 475241675Suqs m->last->flags |= MAN_EOS; 476241675Suqs 477241675Suqs return(man_descope(m, line, offs)); 478241675Suqs} 479241675Suqs 480241675Suqsstatic int 481241675Suqsman_pmacro(struct man *m, int ln, char *buf, int offs) 482241675Suqs{ 483241675Suqs int i, ppos; 484241675Suqs enum mant tok; 485241675Suqs char mac[5]; 486241675Suqs struct man_node *n; 487241675Suqs 488241675Suqs if ('"' == buf[offs]) { 489241675Suqs man_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); 490241675Suqs return(1); 491241675Suqs } else if ('\0' == buf[offs]) 492241675Suqs return(1); 493241675Suqs 494241675Suqs ppos = offs; 495241675Suqs 496241675Suqs /* 497241675Suqs * Copy the first word into a nil-terminated buffer. 498241675Suqs * Stop copying when a tab, space, or eoln is encountered. 499241675Suqs */ 500241675Suqs 501241675Suqs i = 0; 502241675Suqs while (i < 4 && '\0' != buf[offs] && 503241675Suqs ' ' != buf[offs] && '\t' != buf[offs]) 504241675Suqs mac[i++] = buf[offs++]; 505241675Suqs 506241675Suqs mac[i] = '\0'; 507241675Suqs 508241675Suqs tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; 509241675Suqs 510241675Suqs if (MAN_MAX == tok) { 511241675Suqs mandoc_vmsg(MANDOCERR_MACRO, m->parse, ln, 512241675Suqs ppos, "%s", buf + ppos - 1); 513241675Suqs return(1); 514241675Suqs } 515241675Suqs 516241675Suqs /* The macro is sane. Jump to the next word. */ 517241675Suqs 518241675Suqs while (buf[offs] && ' ' == buf[offs]) 519241675Suqs offs++; 520241675Suqs 521241675Suqs /* 522241675Suqs * Trailing whitespace. Note that tabs are allowed to be passed 523241675Suqs * into the parser as "text", so we only warn about spaces here. 524241675Suqs */ 525241675Suqs 526241675Suqs if ('\0' == buf[offs] && ' ' == buf[offs - 1]) 527241675Suqs man_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); 528241675Suqs 529241675Suqs /* 530241675Suqs * Remove prior ELINE macro, as it's being clobbered by a new 531241675Suqs * macro. Note that NSCOPED macros do not close out ELINE 532241675Suqs * macros---they don't print text---so we let those slip by. 533241675Suqs */ 534241675Suqs 535241675Suqs if ( ! (MAN_NSCOPED & man_macros[tok].flags) && 536241675Suqs m->flags & MAN_ELINE) { 537241675Suqs n = m->last; 538241675Suqs assert(MAN_TEXT != n->type); 539241675Suqs 540241675Suqs /* Remove repeated NSCOPED macros causing ELINE. */ 541241675Suqs 542241675Suqs if (MAN_NSCOPED & man_macros[n->tok].flags) 543241675Suqs n = n->parent; 544241675Suqs 545241675Suqs mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, 546241675Suqs n->pos, "%s breaks %s", man_macronames[tok], 547241675Suqs man_macronames[n->tok]); 548241675Suqs 549241675Suqs man_node_delete(m, n); 550241675Suqs m->flags &= ~MAN_ELINE; 551241675Suqs } 552241675Suqs 553241675Suqs /* 554241675Suqs * Remove prior BLINE macro that is being clobbered. 555241675Suqs */ 556241675Suqs if ((m->flags & MAN_BLINE) && 557241675Suqs (MAN_BSCOPE & man_macros[tok].flags)) { 558241675Suqs n = m->last; 559241675Suqs 560241675Suqs /* Might be a text node like 8 in 561241675Suqs * .TP 8 562241675Suqs * .SH foo 563241675Suqs */ 564241675Suqs if (MAN_TEXT == n->type) 565241675Suqs n = n->parent; 566241675Suqs 567241675Suqs /* Remove element that didn't end BLINE, if any. */ 568241675Suqs if ( ! (MAN_BSCOPE & man_macros[n->tok].flags)) 569241675Suqs n = n->parent; 570241675Suqs 571241675Suqs assert(MAN_HEAD == n->type); 572241675Suqs n = n->parent; 573241675Suqs assert(MAN_BLOCK == n->type); 574241675Suqs assert(MAN_SCOPED & man_macros[n->tok].flags); 575241675Suqs 576241675Suqs mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, 577241675Suqs n->pos, "%s breaks %s", man_macronames[tok], 578241675Suqs man_macronames[n->tok]); 579241675Suqs 580241675Suqs man_node_delete(m, n); 581241675Suqs m->flags &= ~MAN_BLINE; 582241675Suqs } 583241675Suqs 584241675Suqs /* 585241675Suqs * Save the fact that we're in the next-line for a block. In 586241675Suqs * this way, embedded roff instructions can "remember" state 587241675Suqs * when they exit. 588241675Suqs */ 589241675Suqs 590241675Suqs if (MAN_BLINE & m->flags) 591241675Suqs m->flags |= MAN_BPLINE; 592241675Suqs 593241675Suqs /* Call to handler... */ 594241675Suqs 595241675Suqs assert(man_macros[tok].fp); 596241675Suqs if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &offs, buf)) 597241675Suqs goto err; 598241675Suqs 599241675Suqs /* 600241675Suqs * We weren't in a block-line scope when entering the 601241675Suqs * above-parsed macro, so return. 602241675Suqs */ 603241675Suqs 604241675Suqs if ( ! (MAN_BPLINE & m->flags)) { 605241675Suqs m->flags &= ~MAN_ILINE; 606241675Suqs return(1); 607241675Suqs } 608241675Suqs m->flags &= ~MAN_BPLINE; 609241675Suqs 610241675Suqs /* 611241675Suqs * If we're in a block scope, then allow this macro to slip by 612241675Suqs * without closing scope around it. 613241675Suqs */ 614241675Suqs 615241675Suqs if (MAN_ILINE & m->flags) { 616241675Suqs m->flags &= ~MAN_ILINE; 617241675Suqs return(1); 618241675Suqs } 619241675Suqs 620241675Suqs /* 621241675Suqs * If we've opened a new next-line element scope, then return 622241675Suqs * now, as the next line will close out the block scope. 623241675Suqs */ 624241675Suqs 625241675Suqs if (MAN_ELINE & m->flags) 626241675Suqs return(1); 627241675Suqs 628241675Suqs /* Close out the block scope opened in the prior line. */ 629241675Suqs 630241675Suqs assert(MAN_BLINE & m->flags); 631241675Suqs m->flags &= ~MAN_BLINE; 632241675Suqs 633241675Suqs if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) 634241675Suqs return(0); 635241675Suqs return(man_body_alloc(m, ln, ppos, m->last->tok)); 636241675Suqs 637241675Suqserr: /* Error out. */ 638241675Suqs 639241675Suqs m->flags |= MAN_HALT; 640241675Suqs return(0); 641241675Suqs} 642241675Suqs 643241675Suqs/* 644241675Suqs * Unlink a node from its context. If "m" is provided, the last parse 645241675Suqs * point will also be adjusted accordingly. 646241675Suqs */ 647241675Suqsstatic void 648241675Suqsman_node_unlink(struct man *m, struct man_node *n) 649241675Suqs{ 650241675Suqs 651241675Suqs /* Adjust siblings. */ 652241675Suqs 653241675Suqs if (n->prev) 654241675Suqs n->prev->next = n->next; 655241675Suqs if (n->next) 656241675Suqs n->next->prev = n->prev; 657241675Suqs 658241675Suqs /* Adjust parent. */ 659241675Suqs 660241675Suqs if (n->parent) { 661241675Suqs n->parent->nchild--; 662241675Suqs if (n->parent->child == n) 663241675Suqs n->parent->child = n->prev ? n->prev : n->next; 664241675Suqs } 665241675Suqs 666241675Suqs /* Adjust parse point, if applicable. */ 667241675Suqs 668241675Suqs if (m && m->last == n) { 669241675Suqs /*XXX: this can occur when bailing from validation. */ 670241675Suqs /*assert(NULL == n->next);*/ 671241675Suqs if (n->prev) { 672241675Suqs m->last = n->prev; 673241675Suqs m->next = MAN_NEXT_SIBLING; 674241675Suqs } else { 675241675Suqs m->last = n->parent; 676241675Suqs m->next = MAN_NEXT_CHILD; 677241675Suqs } 678241675Suqs } 679241675Suqs 680241675Suqs if (m && m->first == n) 681241675Suqs m->first = NULL; 682241675Suqs} 683241675Suqs 684241675Suqsconst struct mparse * 685241675Suqsman_mparse(const struct man *m) 686241675Suqs{ 687241675Suqs 688241675Suqs assert(m && m->parse); 689241675Suqs return(m->parse); 690241675Suqs} 691