1 /* $Id: roff.c,v 1.130 2011/03/29 09:00:48 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2010, 2011 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 AUTHORS DISCLAIM ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 #ifdef HAVE_CONFIG_H 19 #include "config.h" 20 #endif 21 22 #include <assert.h> 23 #include <errno.h> 24 #include <ctype.h> 25 #include <limits.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <stdio.h> 29 30 #include "mandoc.h" 31 #include "libroff.h" 32 #include "libmandoc.h" 33 34 #define RSTACK_MAX 128 35 36 enum rofft { 37 ROFF_ad, 38 ROFF_am, 39 ROFF_ami, 40 ROFF_am1, 41 ROFF_de, 42 ROFF_dei, 43 ROFF_de1, 44 ROFF_ds, 45 ROFF_el, 46 ROFF_hy, 47 ROFF_ie, 48 ROFF_if, 49 ROFF_ig, 50 ROFF_it, 51 ROFF_ne, 52 ROFF_nh, 53 ROFF_nr, 54 ROFF_ns, 55 ROFF_ps, 56 ROFF_rm, 57 ROFF_so, 58 ROFF_ta, 59 ROFF_tr, 60 ROFF_TS, 61 ROFF_TE, 62 ROFF_T_, 63 ROFF_EQ, 64 ROFF_EN, 65 ROFF_cblock, 66 ROFF_ccond, /* FIXME: remove this. */ 67 ROFF_USERDEF, 68 ROFF_MAX 69 }; 70 71 enum roffrule { 72 ROFFRULE_ALLOW, 73 ROFFRULE_DENY 74 }; 75 76 struct roffstr { 77 char *name; /* key of symbol */ 78 char *string; /* current value */ 79 struct roffstr *next; /* next in list */ 80 }; 81 82 struct roff { 83 struct mparse *parse; /* parse point */ 84 struct roffnode *last; /* leaf of stack */ 85 enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ 86 int rstackpos; /* position in rstack */ 87 struct regset *regs; /* read/writable registers */ 88 struct roffstr *first_string; /* user-defined strings & macros */ 89 const char *current_string; /* value of last called user macro */ 90 struct tbl_node *first_tbl; /* first table parsed */ 91 struct tbl_node *last_tbl; /* last table parsed */ 92 struct tbl_node *tbl; /* current table being parsed */ 93 struct eqn_node *last_eqn; /* last equation parsed */ 94 struct eqn_node *first_eqn; /* first equation parsed */ 95 struct eqn_node *eqn; /* current equation being parsed */ 96 }; 97 98 struct roffnode { 99 enum rofft tok; /* type of node */ 100 struct roffnode *parent; /* up one in stack */ 101 int line; /* parse line */ 102 int col; /* parse col */ 103 char *name; /* node name, e.g. macro name */ 104 char *end; /* end-rules: custom token */ 105 int endspan; /* end-rules: next-line or infty */ 106 enum roffrule rule; /* current evaluation rule */ 107 }; 108 109 #define ROFF_ARGS struct roff *r, /* parse ctx */ \ 110 enum rofft tok, /* tok of macro */ \ 111 char **bufp, /* input buffer */ \ 112 size_t *szp, /* size of input buffer */ \ 113 int ln, /* parse line */ \ 114 int ppos, /* original pos in buffer */ \ 115 int pos, /* current pos in buffer */ \ 116 int *offs /* reset offset of buffer data */ 117 118 typedef enum rofferr (*roffproc)(ROFF_ARGS); 119 120 struct roffmac { 121 const char *name; /* macro name */ 122 roffproc proc; /* process new macro */ 123 roffproc text; /* process as child text of macro */ 124 roffproc sub; /* process as child of macro */ 125 int flags; 126 #define ROFFMAC_STRUCT (1 << 0) /* always interpret */ 127 struct roffmac *next; 128 }; 129 130 static enum rofferr roff_block(ROFF_ARGS); 131 static enum rofferr roff_block_text(ROFF_ARGS); 132 static enum rofferr roff_block_sub(ROFF_ARGS); 133 static enum rofferr roff_cblock(ROFF_ARGS); 134 static enum rofferr roff_ccond(ROFF_ARGS); 135 static enum rofferr roff_cond(ROFF_ARGS); 136 static enum rofferr roff_cond_text(ROFF_ARGS); 137 static enum rofferr roff_cond_sub(ROFF_ARGS); 138 static enum rofferr roff_ds(ROFF_ARGS); 139 static enum roffrule roff_evalcond(const char *, int *); 140 static void roff_freestr(struct roff *); 141 static char *roff_getname(struct roff *, char **, int, int); 142 static const char *roff_getstrn(const struct roff *, 143 const char *, size_t); 144 static enum rofferr roff_line_ignore(ROFF_ARGS); 145 static enum rofferr roff_nr(ROFF_ARGS); 146 static int roff_res(struct roff *, 147 char **, size_t *, int); 148 static enum rofferr roff_rm(ROFF_ARGS); 149 static void roff_setstr(struct roff *, 150 const char *, const char *, int); 151 static enum rofferr roff_so(ROFF_ARGS); 152 static enum rofferr roff_TE(ROFF_ARGS); 153 static enum rofferr roff_TS(ROFF_ARGS); 154 static enum rofferr roff_EQ(ROFF_ARGS); 155 static enum rofferr roff_EN(ROFF_ARGS); 156 static enum rofferr roff_T_(ROFF_ARGS); 157 static enum rofferr roff_userdef(ROFF_ARGS); 158 159 /* See roff_hash_find() */ 160 161 #define ASCII_HI 126 162 #define ASCII_LO 33 163 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1) 164 165 static struct roffmac *hash[HASHWIDTH]; 166 167 static struct roffmac roffs[ROFF_MAX] = { 168 { "ad", roff_line_ignore, NULL, NULL, 0, NULL }, 169 { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 170 { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 171 { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 172 { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 173 { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 174 { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 175 { "ds", roff_ds, NULL, NULL, 0, NULL }, 176 { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, 177 { "hy", roff_line_ignore, NULL, NULL, 0, NULL }, 178 { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, 179 { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, 180 { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, 181 { "it", roff_line_ignore, NULL, NULL, 0, NULL }, 182 { "ne", roff_line_ignore, NULL, NULL, 0, NULL }, 183 { "nh", roff_line_ignore, NULL, NULL, 0, NULL }, 184 { "nr", roff_nr, NULL, NULL, 0, NULL }, 185 { "ns", roff_line_ignore, NULL, NULL, 0, NULL }, 186 { "ps", roff_line_ignore, NULL, NULL, 0, NULL }, 187 { "rm", roff_rm, NULL, NULL, 0, NULL }, 188 { "so", roff_so, NULL, NULL, 0, NULL }, 189 { "ta", roff_line_ignore, NULL, NULL, 0, NULL }, 190 { "tr", roff_line_ignore, NULL, NULL, 0, NULL }, 191 { "TS", roff_TS, NULL, NULL, 0, NULL }, 192 { "TE", roff_TE, NULL, NULL, 0, NULL }, 193 { "T&", roff_T_, NULL, NULL, 0, NULL }, 194 { "EQ", roff_EQ, NULL, NULL, 0, NULL }, 195 { "EN", roff_EN, NULL, NULL, 0, NULL }, 196 { ".", roff_cblock, NULL, NULL, 0, NULL }, 197 { "\\}", roff_ccond, NULL, NULL, 0, NULL }, 198 { NULL, roff_userdef, NULL, NULL, 0, NULL }, 199 }; 200 201 static void roff_free1(struct roff *); 202 static enum rofft roff_hash_find(const char *, size_t); 203 static void roff_hash_init(void); 204 static void roffnode_cleanscope(struct roff *); 205 static void roffnode_push(struct roff *, enum rofft, 206 const char *, int, int); 207 static void roffnode_pop(struct roff *); 208 static enum rofft roff_parse(struct roff *, const char *, int *); 209 static int roff_parse_nat(const char *, unsigned int *); 210 211 /* See roff_hash_find() */ 212 #define ROFF_HASH(p) (p[0] - ASCII_LO) 213 214 static void 215 roff_hash_init(void) 216 { 217 struct roffmac *n; 218 int buc, i; 219 220 for (i = 0; i < (int)ROFF_USERDEF; i++) { 221 assert(roffs[i].name[0] >= ASCII_LO); 222 assert(roffs[i].name[0] <= ASCII_HI); 223 224 buc = ROFF_HASH(roffs[i].name); 225 226 if (NULL != (n = hash[buc])) { 227 for ( ; n->next; n = n->next) 228 /* Do nothing. */ ; 229 n->next = &roffs[i]; 230 } else 231 hash[buc] = &roffs[i]; 232 } 233 } 234 235 236 /* 237 * Look up a roff token by its name. Returns ROFF_MAX if no macro by 238 * the nil-terminated string name could be found. 239 */ 240 static enum rofft 241 roff_hash_find(const char *p, size_t s) 242 { 243 int buc; 244 struct roffmac *n; 245 246 /* 247 * libroff has an extremely simple hashtable, for the time 248 * being, which simply keys on the first character, which must 249 * be printable, then walks a chain. It works well enough until 250 * optimised. 251 */ 252 253 if (p[0] < ASCII_LO || p[0] > ASCII_HI) 254 return(ROFF_MAX); 255 256 buc = ROFF_HASH(p); 257 258 if (NULL == (n = hash[buc])) 259 return(ROFF_MAX); 260 for ( ; n; n = n->next) 261 if (0 == strncmp(n->name, p, s) && '\0' == n->name[(int)s]) 262 return((enum rofft)(n - roffs)); 263 264 return(ROFF_MAX); 265 } 266 267 268 /* 269 * Pop the current node off of the stack of roff instructions currently 270 * pending. 271 */ 272 static void 273 roffnode_pop(struct roff *r) 274 { 275 struct roffnode *p; 276 277 assert(r->last); 278 p = r->last; 279 280 if (ROFF_el == p->tok) 281 if (r->rstackpos > -1) 282 r->rstackpos--; 283 284 r->last = r->last->parent; 285 free(p->name); 286 free(p->end); 287 free(p); 288 } 289 290 291 /* 292 * Push a roff node onto the instruction stack. This must later be 293 * removed with roffnode_pop(). 294 */ 295 static void 296 roffnode_push(struct roff *r, enum rofft tok, const char *name, 297 int line, int col) 298 { 299 struct roffnode *p; 300 301 p = mandoc_calloc(1, sizeof(struct roffnode)); 302 p->tok = tok; 303 if (name) 304 p->name = mandoc_strdup(name); 305 p->parent = r->last; 306 p->line = line; 307 p->col = col; 308 p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY; 309 310 r->last = p; 311 } 312 313 314 static void 315 roff_free1(struct roff *r) 316 { 317 struct tbl_node *t; 318 struct eqn_node *e; 319 320 while (NULL != (t = r->first_tbl)) { 321 r->first_tbl = t->next; 322 tbl_free(t); 323 } 324 325 r->first_tbl = r->last_tbl = r->tbl = NULL; 326 327 while (NULL != (e = r->first_eqn)) { 328 r->first_eqn = e->next; 329 eqn_free(e); 330 } 331 332 r->first_eqn = r->last_eqn = r->eqn = NULL; 333 334 while (r->last) 335 roffnode_pop(r); 336 337 roff_freestr(r); 338 } 339 340 341 void 342 roff_reset(struct roff *r) 343 { 344 345 roff_free1(r); 346 } 347 348 349 void 350 roff_free(struct roff *r) 351 { 352 353 roff_free1(r); 354 free(r); 355 } 356 357 358 struct roff * 359 roff_alloc(struct regset *regs, struct mparse *parse) 360 { 361 struct roff *r; 362 363 r = mandoc_calloc(1, sizeof(struct roff)); 364 r->regs = regs; 365 r->parse = parse; 366 r->rstackpos = -1; 367 368 roff_hash_init(); 369 return(r); 370 } 371 372 373 /* 374 * Pre-filter each and every line for reserved words (one beginning with 375 * `\*', e.g., `\*(ab'). These must be handled before the actual line 376 * is processed. 377 */ 378 static int 379 roff_res(struct roff *r, char **bufp, size_t *szp, int pos) 380 { 381 const char *stesc; /* start of an escape sequence ('\\') */ 382 const char *stnam; /* start of the name, after "[(*" */ 383 const char *cp; /* end of the name, e.g. before ']' */ 384 const char *res; /* the string to be substituted */ 385 int i, maxl; 386 size_t nsz; 387 char *n; 388 389 /* Search for a leading backslash and save a pointer to it. */ 390 391 cp = *bufp + pos; 392 while (NULL != (cp = strchr(cp, '\\'))) { 393 stesc = cp++; 394 395 /* 396 * The second character must be an asterisk. 397 * If it isn't, skip it anyway: It is escaped, 398 * so it can't start another escape sequence. 399 */ 400 401 if ('\0' == *cp) 402 return(1); 403 if ('*' != *cp++) 404 continue; 405 406 /* 407 * The third character decides the length 408 * of the name of the string. 409 * Save a pointer to the name. 410 */ 411 412 switch (*cp) { 413 case ('\0'): 414 return(1); 415 case ('('): 416 cp++; 417 maxl = 2; 418 break; 419 case ('['): 420 cp++; 421 maxl = 0; 422 break; 423 default: 424 maxl = 1; 425 break; 426 } 427 stnam = cp; 428 429 /* Advance to the end of the name. */ 430 431 for (i = 0; 0 == maxl || i < maxl; i++, cp++) { 432 if ('\0' == *cp) 433 return(1); /* Error. */ 434 if (0 == maxl && ']' == *cp) 435 break; 436 } 437 438 /* 439 * Retrieve the replacement string; if it is 440 * undefined, resume searching for escapes. 441 */ 442 443 res = roff_getstrn(r, stnam, (size_t)i); 444 445 if (NULL == res) { 446 cp -= maxl ? 1 : 0; 447 continue; 448 } 449 450 /* Replace the escape sequence by the string. */ 451 452 nsz = *szp + strlen(res) + 1; 453 n = mandoc_malloc(nsz); 454 455 strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1)); 456 strlcat(n, res, nsz); 457 strlcat(n, cp + (maxl ? 0 : 1), nsz); 458 459 free(*bufp); 460 461 *bufp = n; 462 *szp = nsz; 463 return(0); 464 } 465 466 return(1); 467 } 468 469 470 enum rofferr 471 roff_parseln(struct roff *r, int ln, char **bufp, 472 size_t *szp, int pos, int *offs) 473 { 474 enum rofft t; 475 enum rofferr e; 476 int ppos, ctl; 477 478 /* 479 * Run the reserved-word filter only if we have some reserved 480 * words to fill in. 481 */ 482 483 if (r->first_string && ! roff_res(r, bufp, szp, pos)) 484 return(ROFF_REPARSE); 485 486 ppos = pos; 487 ctl = mandoc_getcontrol(*bufp, &pos); 488 489 /* 490 * First, if a scope is open and we're not a macro, pass the 491 * text through the macro's filter. If a scope isn't open and 492 * we're not a macro, just let it through. 493 * Finally, if there's an equation scope open, divert it into it 494 * no matter our state. 495 */ 496 497 if (r->last && ! ctl) { 498 t = r->last->tok; 499 assert(roffs[t].text); 500 e = (*roffs[t].text) 501 (r, t, bufp, szp, ln, pos, pos, offs); 502 assert(ROFF_IGN == e || ROFF_CONT == e); 503 if (ROFF_CONT != e) 504 return(e); 505 if (r->eqn) 506 return(eqn_read(&r->eqn, ln, *bufp, pos)); 507 if (r->tbl) 508 return(tbl_read(r->tbl, ln, *bufp, pos)); 509 return(ROFF_CONT); 510 } else if ( ! ctl) { 511 if (r->eqn) 512 return(eqn_read(&r->eqn, ln, *bufp, pos)); 513 if (r->tbl) 514 return(tbl_read(r->tbl, ln, *bufp, pos)); 515 return(ROFF_CONT); 516 } else if (r->eqn) 517 return(eqn_read(&r->eqn, ln, *bufp, ppos)); 518 519 /* 520 * If a scope is open, go to the child handler for that macro, 521 * as it may want to preprocess before doing anything with it. 522 * Don't do so if an equation is open. 523 */ 524 525 if (r->last) { 526 t = r->last->tok; 527 assert(roffs[t].sub); 528 return((*roffs[t].sub) 529 (r, t, bufp, szp, 530 ln, ppos, pos, offs)); 531 } 532 533 /* 534 * Lastly, as we've no scope open, try to look up and execute 535 * the new macro. If no macro is found, simply return and let 536 * the compilers handle it. 537 */ 538 539 if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) 540 return(ROFF_CONT); 541 542 assert(roffs[t].proc); 543 return((*roffs[t].proc) 544 (r, t, bufp, szp, 545 ln, ppos, pos, offs)); 546 } 547 548 549 void 550 roff_endparse(struct roff *r) 551 { 552 553 if (r->last) 554 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 555 r->last->line, r->last->col, NULL); 556 557 if (r->eqn) { 558 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 559 r->eqn->eqn.line, r->eqn->eqn.pos, NULL); 560 eqn_end(r->eqn); 561 r->eqn = NULL; 562 } 563 564 if (r->tbl) { 565 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 566 r->tbl->line, r->tbl->pos, NULL); 567 tbl_end(r->tbl); 568 r->tbl = NULL; 569 } 570 } 571 572 /* 573 * Parse a roff node's type from the input buffer. This must be in the 574 * form of ".foo xxx" in the usual way. 575 */ 576 static enum rofft 577 roff_parse(struct roff *r, const char *buf, int *pos) 578 { 579 const char *mac; 580 size_t maclen; 581 enum rofft t; 582 583 if ('\0' == buf[*pos] || '"' == buf[*pos]) 584 return(ROFF_MAX); 585 586 mac = buf + *pos; 587 maclen = strcspn(mac, " \\\t\0"); 588 589 t = (r->current_string = roff_getstrn(r, mac, maclen)) 590 ? ROFF_USERDEF : roff_hash_find(mac, maclen); 591 592 *pos += (int)maclen; 593 594 while (buf[*pos] && ' ' == buf[*pos]) 595 (*pos)++; 596 597 return(t); 598 } 599 600 601 static int 602 roff_parse_nat(const char *buf, unsigned int *res) 603 { 604 char *ep; 605 long lval; 606 607 errno = 0; 608 lval = strtol(buf, &ep, 10); 609 if (buf[0] == '\0' || *ep != '\0') 610 return(0); 611 if ((errno == ERANGE && 612 (lval == LONG_MAX || lval == LONG_MIN)) || 613 (lval > INT_MAX || lval < 0)) 614 return(0); 615 616 *res = (unsigned int)lval; 617 return(1); 618 } 619 620 621 /* ARGSUSED */ 622 static enum rofferr 623 roff_cblock(ROFF_ARGS) 624 { 625 626 /* 627 * A block-close `..' should only be invoked as a child of an 628 * ignore macro, otherwise raise a warning and just ignore it. 629 */ 630 631 if (NULL == r->last) { 632 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 633 return(ROFF_IGN); 634 } 635 636 switch (r->last->tok) { 637 case (ROFF_am): 638 /* FALLTHROUGH */ 639 case (ROFF_ami): 640 /* FALLTHROUGH */ 641 case (ROFF_am1): 642 /* FALLTHROUGH */ 643 case (ROFF_de): 644 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */ 645 /* FALLTHROUGH */ 646 case (ROFF_dei): 647 /* FALLTHROUGH */ 648 case (ROFF_ig): 649 break; 650 default: 651 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 652 return(ROFF_IGN); 653 } 654 655 if ((*bufp)[pos]) 656 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); 657 658 roffnode_pop(r); 659 roffnode_cleanscope(r); 660 return(ROFF_IGN); 661 662 } 663 664 665 static void 666 roffnode_cleanscope(struct roff *r) 667 { 668 669 while (r->last) { 670 if (--r->last->endspan < 0) 671 break; 672 roffnode_pop(r); 673 } 674 } 675 676 677 /* ARGSUSED */ 678 static enum rofferr 679 roff_ccond(ROFF_ARGS) 680 { 681 682 if (NULL == r->last) { 683 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 684 return(ROFF_IGN); 685 } 686 687 switch (r->last->tok) { 688 case (ROFF_el): 689 /* FALLTHROUGH */ 690 case (ROFF_ie): 691 /* FALLTHROUGH */ 692 case (ROFF_if): 693 break; 694 default: 695 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 696 return(ROFF_IGN); 697 } 698 699 if (r->last->endspan > -1) { 700 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 701 return(ROFF_IGN); 702 } 703 704 if ((*bufp)[pos]) 705 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); 706 707 roffnode_pop(r); 708 roffnode_cleanscope(r); 709 return(ROFF_IGN); 710 } 711 712 713 /* ARGSUSED */ 714 static enum rofferr 715 roff_block(ROFF_ARGS) 716 { 717 int sv; 718 size_t sz; 719 char *name; 720 721 name = NULL; 722 723 if (ROFF_ig != tok) { 724 if ('\0' == (*bufp)[pos]) { 725 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); 726 return(ROFF_IGN); 727 } 728 729 /* 730 * Re-write `de1', since we don't really care about 731 * groff's strange compatibility mode, into `de'. 732 */ 733 734 if (ROFF_de1 == tok) 735 tok = ROFF_de; 736 if (ROFF_de == tok) 737 name = *bufp + pos; 738 else 739 mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, 740 roffs[tok].name); 741 742 while ((*bufp)[pos] && ' ' != (*bufp)[pos]) 743 pos++; 744 745 while (' ' == (*bufp)[pos]) 746 (*bufp)[pos++] = '\0'; 747 } 748 749 roffnode_push(r, tok, name, ln, ppos); 750 751 /* 752 * At the beginning of a `de' macro, clear the existing string 753 * with the same name, if there is one. New content will be 754 * added from roff_block_text() in multiline mode. 755 */ 756 757 if (ROFF_de == tok) 758 roff_setstr(r, name, "", 0); 759 760 if ('\0' == (*bufp)[pos]) 761 return(ROFF_IGN); 762 763 /* If present, process the custom end-of-line marker. */ 764 765 sv = pos; 766 while ((*bufp)[pos] && 767 ' ' != (*bufp)[pos] && 768 '\t' != (*bufp)[pos]) 769 pos++; 770 771 /* 772 * Note: groff does NOT like escape characters in the input. 773 * Instead of detecting this, we're just going to let it fly and 774 * to hell with it. 775 */ 776 777 assert(pos > sv); 778 sz = (size_t)(pos - sv); 779 780 if (1 == sz && '.' == (*bufp)[sv]) 781 return(ROFF_IGN); 782 783 r->last->end = mandoc_malloc(sz + 1); 784 785 memcpy(r->last->end, *bufp + sv, sz); 786 r->last->end[(int)sz] = '\0'; 787 788 if ((*bufp)[pos]) 789 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); 790 791 return(ROFF_IGN); 792 } 793 794 795 /* ARGSUSED */ 796 static enum rofferr 797 roff_block_sub(ROFF_ARGS) 798 { 799 enum rofft t; 800 int i, j; 801 802 /* 803 * First check whether a custom macro exists at this level. If 804 * it does, then check against it. This is some of groff's 805 * stranger behaviours. If we encountered a custom end-scope 806 * tag and that tag also happens to be a "real" macro, then we 807 * need to try interpreting it again as a real macro. If it's 808 * not, then return ignore. Else continue. 809 */ 810 811 if (r->last->end) { 812 for (i = pos, j = 0; r->last->end[j]; j++, i++) 813 if ((*bufp)[i] != r->last->end[j]) 814 break; 815 816 if ('\0' == r->last->end[j] && 817 ('\0' == (*bufp)[i] || 818 ' ' == (*bufp)[i] || 819 '\t' == (*bufp)[i])) { 820 roffnode_pop(r); 821 roffnode_cleanscope(r); 822 823 while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) 824 i++; 825 826 pos = i; 827 if (ROFF_MAX != roff_parse(r, *bufp, &pos)) 828 return(ROFF_RERUN); 829 return(ROFF_IGN); 830 } 831 } 832 833 /* 834 * If we have no custom end-query or lookup failed, then try 835 * pulling it out of the hashtable. 836 */ 837 838 if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) 839 return(ROFF_IGN); 840 841 /* 842 * Macros other than block-end are only significant 843 * in `de' blocks; elsewhere, simply throw them away. 844 */ 845 if (ROFF_cblock != t) { 846 if (ROFF_de == tok) 847 roff_setstr(r, r->last->name, *bufp + ppos, 1); 848 return(ROFF_IGN); 849 } 850 851 assert(roffs[t].proc); 852 return((*roffs[t].proc)(r, t, bufp, szp, 853 ln, ppos, pos, offs)); 854 } 855 856 857 /* ARGSUSED */ 858 static enum rofferr 859 roff_block_text(ROFF_ARGS) 860 { 861 862 if (ROFF_de == tok) 863 roff_setstr(r, r->last->name, *bufp + pos, 1); 864 865 return(ROFF_IGN); 866 } 867 868 869 /* ARGSUSED */ 870 static enum rofferr 871 roff_cond_sub(ROFF_ARGS) 872 { 873 enum rofft t; 874 enum roffrule rr; 875 876 rr = r->last->rule; 877 878 /* 879 * Clean out scope. If we've closed ourselves, then don't 880 * continue. 881 */ 882 883 roffnode_cleanscope(r); 884 885 if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { 886 if ('\\' == (*bufp)[pos] && '}' == (*bufp)[pos + 1]) 887 return(roff_ccond 888 (r, ROFF_ccond, bufp, szp, 889 ln, pos, pos + 2, offs)); 890 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); 891 } 892 893 /* 894 * A denied conditional must evaluate its children if and only 895 * if they're either structurally required (such as loops and 896 * conditionals) or a closing macro. 897 */ 898 if (ROFFRULE_DENY == rr) 899 if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) 900 if (ROFF_ccond != t) 901 return(ROFF_IGN); 902 903 assert(roffs[t].proc); 904 return((*roffs[t].proc)(r, t, bufp, szp, 905 ln, ppos, pos, offs)); 906 } 907 908 909 /* ARGSUSED */ 910 static enum rofferr 911 roff_cond_text(ROFF_ARGS) 912 { 913 char *ep, *st; 914 enum roffrule rr; 915 916 rr = r->last->rule; 917 918 /* 919 * We display the value of the text if out current evaluation 920 * scope permits us to do so. 921 */ 922 923 /* FIXME: use roff_ccond? */ 924 925 st = &(*bufp)[pos]; 926 if (NULL == (ep = strstr(st, "\\}"))) { 927 roffnode_cleanscope(r); 928 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); 929 } 930 931 if (ep == st || (ep > st && '\\' != *(ep - 1))) 932 roffnode_pop(r); 933 934 roffnode_cleanscope(r); 935 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); 936 } 937 938 939 static enum roffrule 940 roff_evalcond(const char *v, int *pos) 941 { 942 943 switch (v[*pos]) { 944 case ('n'): 945 (*pos)++; 946 return(ROFFRULE_ALLOW); 947 case ('e'): 948 /* FALLTHROUGH */ 949 case ('o'): 950 /* FALLTHROUGH */ 951 case ('t'): 952 (*pos)++; 953 return(ROFFRULE_DENY); 954 default: 955 break; 956 } 957 958 while (v[*pos] && ' ' != v[*pos]) 959 (*pos)++; 960 return(ROFFRULE_DENY); 961 } 962 963 /* ARGSUSED */ 964 static enum rofferr 965 roff_line_ignore(ROFF_ARGS) 966 { 967 968 if (ROFF_it == tok) 969 mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); 970 971 return(ROFF_IGN); 972 } 973 974 /* ARGSUSED */ 975 static enum rofferr 976 roff_cond(ROFF_ARGS) 977 { 978 int sv; 979 enum roffrule rule; 980 981 /* Stack overflow! */ 982 983 if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) { 984 mandoc_msg(MANDOCERR_MEM, r->parse, ln, ppos, NULL); 985 return(ROFF_ERR); 986 } 987 988 /* First, evaluate the conditional. */ 989 990 if (ROFF_el == tok) { 991 /* 992 * An `.el' will get the value of the current rstack 993 * entry set in prior `ie' calls or defaults to DENY. 994 */ 995 if (r->rstackpos < 0) 996 rule = ROFFRULE_DENY; 997 else 998 rule = r->rstack[r->rstackpos]; 999 } else 1000 rule = roff_evalcond(*bufp, &pos); 1001 1002 sv = pos; 1003 1004 while (' ' == (*bufp)[pos]) 1005 pos++; 1006 1007 /* 1008 * Roff is weird. If we have just white-space after the 1009 * conditional, it's considered the BODY and we exit without 1010 * really doing anything. Warn about this. It's probably 1011 * wrong. 1012 */ 1013 1014 if ('\0' == (*bufp)[pos] && sv != pos) { 1015 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); 1016 return(ROFF_IGN); 1017 } 1018 1019 roffnode_push(r, tok, NULL, ln, ppos); 1020 1021 r->last->rule = rule; 1022 1023 if (ROFF_ie == tok) { 1024 /* 1025 * An if-else will put the NEGATION of the current 1026 * evaluated conditional into the stack. 1027 */ 1028 r->rstackpos++; 1029 if (ROFFRULE_DENY == r->last->rule) 1030 r->rstack[r->rstackpos] = ROFFRULE_ALLOW; 1031 else 1032 r->rstack[r->rstackpos] = ROFFRULE_DENY; 1033 } 1034 1035 /* If the parent has false as its rule, then so do we. */ 1036 1037 if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) 1038 r->last->rule = ROFFRULE_DENY; 1039 1040 /* 1041 * Determine scope. If we're invoked with "\{" trailing the 1042 * conditional, then we're in a multiline scope. Else our scope 1043 * expires on the next line. 1044 */ 1045 1046 r->last->endspan = 1; 1047 1048 if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { 1049 r->last->endspan = -1; 1050 pos += 2; 1051 } 1052 1053 /* 1054 * If there are no arguments on the line, the next-line scope is 1055 * assumed. 1056 */ 1057 1058 if ('\0' == (*bufp)[pos]) 1059 return(ROFF_IGN); 1060 1061 /* Otherwise re-run the roff parser after recalculating. */ 1062 1063 *offs = pos; 1064 return(ROFF_RERUN); 1065 } 1066 1067 1068 /* ARGSUSED */ 1069 static enum rofferr 1070 roff_ds(ROFF_ARGS) 1071 { 1072 char *name, *string; 1073 1074 /* 1075 * A symbol is named by the first word following the macro 1076 * invocation up to a space. Its value is anything after the 1077 * name's trailing whitespace and optional double-quote. Thus, 1078 * 1079 * [.ds foo "bar " ] 1080 * 1081 * will have `bar " ' as its value. 1082 */ 1083 1084 string = *bufp + pos; 1085 name = roff_getname(r, &string, ln, pos); 1086 if ('\0' == *name) 1087 return(ROFF_IGN); 1088 1089 /* Read past initial double-quote. */ 1090 if ('"' == *string) 1091 string++; 1092 1093 /* The rest is the value. */ 1094 roff_setstr(r, name, string, 0); 1095 return(ROFF_IGN); 1096 } 1097 1098 1099 /* ARGSUSED */ 1100 static enum rofferr 1101 roff_nr(ROFF_ARGS) 1102 { 1103 const char *key; 1104 char *val; 1105 struct reg *rg; 1106 1107 val = *bufp + pos; 1108 key = roff_getname(r, &val, ln, pos); 1109 rg = r->regs->regs; 1110 1111 if (0 == strcmp(key, "nS")) { 1112 rg[(int)REG_nS].set = 1; 1113 if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u)) 1114 rg[(int)REG_nS].v.u = 0; 1115 } 1116 1117 return(ROFF_IGN); 1118 } 1119 1120 /* ARGSUSED */ 1121 static enum rofferr 1122 roff_rm(ROFF_ARGS) 1123 { 1124 const char *name; 1125 char *cp; 1126 1127 cp = *bufp + pos; 1128 while ('\0' != *cp) { 1129 name = roff_getname(r, &cp, ln, (int)(cp - *bufp)); 1130 if ('\0' != *name) 1131 roff_setstr(r, name, NULL, 0); 1132 } 1133 return(ROFF_IGN); 1134 } 1135 1136 /* ARGSUSED */ 1137 static enum rofferr 1138 roff_TE(ROFF_ARGS) 1139 { 1140 1141 if (NULL == r->tbl) 1142 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 1143 else 1144 tbl_end(r->tbl); 1145 1146 r->tbl = NULL; 1147 return(ROFF_IGN); 1148 } 1149 1150 /* ARGSUSED */ 1151 static enum rofferr 1152 roff_T_(ROFF_ARGS) 1153 { 1154 1155 if (NULL == r->tbl) 1156 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 1157 else 1158 tbl_restart(ppos, ln, r->tbl); 1159 1160 return(ROFF_IGN); 1161 } 1162 1163 /* ARGSUSED */ 1164 static enum rofferr 1165 roff_EQ(ROFF_ARGS) 1166 { 1167 struct eqn_node *e; 1168 1169 assert(NULL == r->eqn); 1170 e = eqn_alloc(ppos, ln); 1171 1172 if (r->last_eqn) 1173 r->last_eqn->next = e; 1174 else 1175 r->first_eqn = r->last_eqn = e; 1176 1177 r->eqn = r->last_eqn = e; 1178 return(ROFF_IGN); 1179 } 1180 1181 /* ARGSUSED */ 1182 static enum rofferr 1183 roff_EN(ROFF_ARGS) 1184 { 1185 1186 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); 1187 return(ROFF_IGN); 1188 } 1189 1190 /* ARGSUSED */ 1191 static enum rofferr 1192 roff_TS(ROFF_ARGS) 1193 { 1194 struct tbl_node *t; 1195 1196 if (r->tbl) { 1197 mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); 1198 tbl_end(r->tbl); 1199 } 1200 1201 t = tbl_alloc(ppos, ln, r->parse); 1202 1203 if (r->last_tbl) 1204 r->last_tbl->next = t; 1205 else 1206 r->first_tbl = r->last_tbl = t; 1207 1208 r->tbl = r->last_tbl = t; 1209 return(ROFF_IGN); 1210 } 1211 1212 /* ARGSUSED */ 1213 static enum rofferr 1214 roff_so(ROFF_ARGS) 1215 { 1216 char *name; 1217 1218 mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL); 1219 1220 /* 1221 * Handle `so'. Be EXTREMELY careful, as we shouldn't be 1222 * opening anything that's not in our cwd or anything beneath 1223 * it. Thus, explicitly disallow traversing up the file-system 1224 * or using absolute paths. 1225 */ 1226 1227 name = *bufp + pos; 1228 if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) { 1229 mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL); 1230 return(ROFF_ERR); 1231 } 1232 1233 *offs = pos; 1234 return(ROFF_SO); 1235 } 1236 1237 /* ARGSUSED */ 1238 static enum rofferr 1239 roff_userdef(ROFF_ARGS) 1240 { 1241 const char *arg[9]; 1242 char *cp, *n1, *n2; 1243 int i; 1244 1245 /* 1246 * Collect pointers to macro argument strings 1247 * and null-terminate them. 1248 */ 1249 cp = *bufp + pos; 1250 for (i = 0; i < 9; i++) 1251 arg[i] = '\0' == *cp ? "" : 1252 mandoc_getarg(r->parse, &cp, ln, &pos); 1253 1254 /* 1255 * Expand macro arguments. 1256 */ 1257 *szp = 0; 1258 n1 = cp = mandoc_strdup(r->current_string); 1259 while (NULL != (cp = strstr(cp, "\\$"))) { 1260 i = cp[2] - '1'; 1261 if (0 > i || 8 < i) { 1262 /* Not an argument invocation. */ 1263 cp += 2; 1264 continue; 1265 } 1266 1267 *szp = strlen(n1) - 3 + strlen(arg[i]) + 1; 1268 n2 = mandoc_malloc(*szp); 1269 1270 strlcpy(n2, n1, (size_t)(cp - n1 + 1)); 1271 strlcat(n2, arg[i], *szp); 1272 strlcat(n2, cp + 3, *szp); 1273 1274 cp = n2 + (cp - n1); 1275 free(n1); 1276 n1 = n2; 1277 } 1278 1279 /* 1280 * Replace the macro invocation 1281 * by the expanded macro. 1282 */ 1283 free(*bufp); 1284 *bufp = n1; 1285 if (0 == *szp) 1286 *szp = strlen(*bufp) + 1; 1287 1288 return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ? 1289 ROFF_REPARSE : ROFF_APPEND); 1290 } 1291 1292 static char * 1293 roff_getname(struct roff *r, char **cpp, int ln, int pos) 1294 { 1295 char *name, *cp; 1296 1297 name = *cpp; 1298 if ('\0' == *name) 1299 return(name); 1300 1301 /* Read until end of name. */ 1302 for (cp = name; '\0' != *cp && ' ' != *cp; cp++) { 1303 if ('\\' != *cp) 1304 continue; 1305 cp++; 1306 if ('\\' == *cp) 1307 continue; 1308 mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL); 1309 *cp = '\0'; 1310 name = cp; 1311 } 1312 1313 /* Nil-terminate name. */ 1314 if ('\0' != *cp) 1315 *(cp++) = '\0'; 1316 1317 /* Read past spaces. */ 1318 while (' ' == *cp) 1319 cp++; 1320 1321 *cpp = cp; 1322 return(name); 1323 } 1324 1325 /* 1326 * Store *string into the user-defined string called *name. 1327 * In multiline mode, append to an existing entry and append '\n'; 1328 * else replace the existing entry, if there is one. 1329 * To clear an existing entry, call with (*r, *name, NULL, 0). 1330 */ 1331 static void 1332 roff_setstr(struct roff *r, const char *name, const char *string, 1333 int multiline) 1334 { 1335 struct roffstr *n; 1336 char *c; 1337 size_t oldch, newch; 1338 1339 /* Search for an existing string with the same name. */ 1340 n = r->first_string; 1341 while (n && strcmp(name, n->name)) 1342 n = n->next; 1343 1344 if (NULL == n) { 1345 /* Create a new string table entry. */ 1346 n = mandoc_malloc(sizeof(struct roffstr)); 1347 n->name = mandoc_strdup(name); 1348 n->string = NULL; 1349 n->next = r->first_string; 1350 r->first_string = n; 1351 } else if (0 == multiline) { 1352 /* In multiline mode, append; else replace. */ 1353 free(n->string); 1354 n->string = NULL; 1355 } 1356 1357 if (NULL == string) 1358 return; 1359 1360 /* 1361 * One additional byte for the '\n' in multiline mode, 1362 * and one for the terminating '\0'. 1363 */ 1364 newch = strlen(string) + (multiline ? 2u : 1u); 1365 if (NULL == n->string) { 1366 n->string = mandoc_malloc(newch); 1367 *n->string = '\0'; 1368 oldch = 0; 1369 } else { 1370 oldch = strlen(n->string); 1371 n->string = mandoc_realloc(n->string, oldch + newch); 1372 } 1373 1374 /* Skip existing content in the destination buffer. */ 1375 c = n->string + (int)oldch; 1376 1377 /* Append new content to the destination buffer. */ 1378 while (*string) { 1379 /* 1380 * Rudimentary roff copy mode: 1381 * Handle escaped backslashes. 1382 */ 1383 if ('\\' == *string && '\\' == *(string + 1)) 1384 string++; 1385 *c++ = *string++; 1386 } 1387 1388 /* Append terminating bytes. */ 1389 if (multiline) 1390 *c++ = '\n'; 1391 *c = '\0'; 1392 } 1393 1394 static const char * 1395 roff_getstrn(const struct roff *r, const char *name, size_t len) 1396 { 1397 const struct roffstr *n; 1398 1399 n = r->first_string; 1400 while (n && (strncmp(name, n->name, len) || '\0' != n->name[(int)len])) 1401 n = n->next; 1402 1403 return(n ? n->string : NULL); 1404 } 1405 1406 static void 1407 roff_freestr(struct roff *r) 1408 { 1409 struct roffstr *n, *nn; 1410 1411 for (n = r->first_string; n; n = nn) { 1412 free(n->name); 1413 free(n->string); 1414 nn = n->next; 1415 free(n); 1416 } 1417 1418 r->first_string = NULL; 1419 } 1420 1421 const struct tbl_span * 1422 roff_span(const struct roff *r) 1423 { 1424 1425 return(r->tbl ? tbl_span(r->tbl) : NULL); 1426 } 1427 1428 const struct eqn * 1429 roff_eqn(const struct roff *r) 1430 { 1431 1432 return(r->last_eqn ? &r->last_eqn->eqn : NULL); 1433 } 1434