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