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