Print this page
5051 import mdocml-1.12.3
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Approved by: TBD
   1 /*      $Id: roff.c,v 1.172 2011/10/24 21:41:45 schwarze 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 <ctype.h>

  24 #include <stdlib.h>
  25 #include <string.h>
  26 
  27 #include "mandoc.h"
  28 #include "libroff.h"
  29 #include "libmandoc.h"
  30 
  31 /* Maximum number of nested if-else conditionals. */
  32 #define RSTACK_MAX      128
  33 
  34 /* Maximum number of string expansions per line, to break infinite loops. */
  35 #define EXPAND_LIMIT    1000
  36 
  37 enum    rofft {
  38         ROFF_ad,
  39         ROFF_am,
  40         ROFF_ami,
  41         ROFF_am1,

  42         ROFF_de,
  43         ROFF_dei,
  44         ROFF_de1,
  45         ROFF_ds,
  46         ROFF_el,


  47         ROFF_hy,
  48         ROFF_ie,
  49         ROFF_if,
  50         ROFF_ig,
  51         ROFF_it,
  52         ROFF_ne,
  53         ROFF_nh,
  54         ROFF_nr,
  55         ROFF_ns,
  56         ROFF_ps,
  57         ROFF_rm,
  58         ROFF_so,
  59         ROFF_ta,
  60         ROFF_tr,


  61         ROFF_TS,
  62         ROFF_TE,
  63         ROFF_T_,
  64         ROFF_EQ,
  65         ROFF_EN,
  66         ROFF_cblock,
  67         ROFF_ccond,
  68         ROFF_USERDEF,
  69         ROFF_MAX
  70 };
  71 
  72 enum    roffrule {
  73         ROFFRULE_ALLOW,
  74         ROFFRULE_DENY
  75 };
  76 
  77 /*
  78  * A single register entity.  If "set" is zero, the value of the
  79  * register should be the default one, which is per-register.
  80  * Registers are assumed to be unsigned ints for now.
  81  */
  82 struct  reg {
  83         int              set; /* whether set or not */
  84         unsigned int     u; /* unsigned integer */
  85 };
  86 
  87 /*
  88  * An incredibly-simple string buffer.
  89  */
  90 struct  roffstr {
  91         char            *p; /* nil-terminated buffer */
  92         size_t           sz; /* saved strlen(p) */
  93 };
  94 
  95 /*
  96  * A key-value roffstr pair as part of a singly-linked list.
  97  */
  98 struct  roffkv {
  99         struct roffstr   key;
 100         struct roffstr   val;
 101         struct roffkv   *next; /* next in list */
 102 };
 103 









 104 struct  roff {

 105         struct mparse   *parse; /* parse point */
 106         struct roffnode *last; /* leaf of stack */
 107         enum roffrule    rstack[RSTACK_MAX]; /* stack of !`ie' rules */

 108         int              rstackpos; /* position in rstack */
 109         struct reg       regs[REG__MAX];
 110         struct roffkv   *strtab; /* user-defined strings & macros */
 111         struct roffkv   *xmbtab; /* multi-byte trans table (`tr') */
 112         struct roffstr  *xtab; /* single-byte trans table (`tr') */
 113         const char      *current_string; /* value of last called user macro */
 114         struct tbl_node *first_tbl; /* first table parsed */
 115         struct tbl_node *last_tbl; /* last table parsed */
 116         struct tbl_node *tbl; /* current table being parsed */
 117         struct eqn_node *last_eqn; /* last equation parsed */
 118         struct eqn_node *first_eqn; /* first equation parsed */
 119         struct eqn_node *eqn; /* current equation being parsed */
 120 };
 121 
 122 struct  roffnode {
 123         enum rofft       tok; /* type of node */
 124         struct roffnode *parent; /* up one in stack */
 125         int              line; /* parse line */
 126         int              col; /* parse col */
 127         char            *name; /* node name, e.g. macro name */
 128         char            *end; /* end-rules: custom token */
 129         int              endspan; /* end-rules: next-line or infty */


 152 };
 153 
 154 struct  predef {
 155         const char      *name; /* predefined input name */
 156         const char      *str; /* replacement symbol */
 157 };
 158 
 159 #define PREDEF(__name, __str) \
 160         { (__name), (__str) },
 161 
 162 static  enum rofft       roffhash_find(const char *, size_t);
 163 static  void             roffhash_init(void);
 164 static  void             roffnode_cleanscope(struct roff *);
 165 static  void             roffnode_pop(struct roff *);
 166 static  void             roffnode_push(struct roff *, enum rofft,
 167                                 const char *, int, int);
 168 static  enum rofferr     roff_block(ROFF_ARGS);
 169 static  enum rofferr     roff_block_text(ROFF_ARGS);
 170 static  enum rofferr     roff_block_sub(ROFF_ARGS);
 171 static  enum rofferr     roff_cblock(ROFF_ARGS);

 172 static  enum rofferr     roff_ccond(ROFF_ARGS);
 173 static  enum rofferr     roff_cond(ROFF_ARGS);
 174 static  enum rofferr     roff_cond_text(ROFF_ARGS);
 175 static  enum rofferr     roff_cond_sub(ROFF_ARGS);
 176 static  enum rofferr     roff_ds(ROFF_ARGS);
 177 static  enum roffrule    roff_evalcond(const char *, int *);
 178 static  void             roff_free1(struct roff *);

 179 static  void             roff_freestr(struct roffkv *);
 180 static  char            *roff_getname(struct roff *, char **, int, int);




 181 static  const char      *roff_getstrn(const struct roff *, 
 182                                 const char *, size_t);

 183 static  enum rofferr     roff_line_ignore(ROFF_ARGS);
 184 static  enum rofferr     roff_nr(ROFF_ARGS);
 185 static  void             roff_openeqn(struct roff *, const char *,
 186                                 int, int, const char *);
 187 static  enum rofft       roff_parse(struct roff *, const char *, int *);
 188 static  enum rofferr     roff_parsetext(char *);
 189 static  enum rofferr     roff_res(struct roff *, 
 190                                 char **, size_t *, int, int);
 191 static  enum rofferr     roff_rm(ROFF_ARGS);
 192 static  void             roff_setstr(struct roff *,
 193                                 const char *, const char *, int);
 194 static  void             roff_setstrn(struct roffkv **, const char *, 
 195                                 size_t, const char *, size_t, int);
 196 static  enum rofferr     roff_so(ROFF_ARGS);
 197 static  enum rofferr     roff_tr(ROFF_ARGS);


 198 static  enum rofferr     roff_TE(ROFF_ARGS);
 199 static  enum rofferr     roff_TS(ROFF_ARGS);
 200 static  enum rofferr     roff_EQ(ROFF_ARGS);
 201 static  enum rofferr     roff_EN(ROFF_ARGS);
 202 static  enum rofferr     roff_T_(ROFF_ARGS);
 203 static  enum rofferr     roff_userdef(ROFF_ARGS);
 204 
 205 /* See roffhash_find() */
 206 
 207 #define ASCII_HI         126
 208 #define ASCII_LO         33
 209 #define HASHWIDTH       (ASCII_HI - ASCII_LO + 1)
 210 
 211 static  struct roffmac  *hash[HASHWIDTH];
 212 
 213 static  struct roffmac   roffs[ROFF_MAX] = {
 214         { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
 215         { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 216         { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 217         { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },

 218         { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 219         { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 220         { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 221         { "ds", roff_ds, NULL, NULL, 0, NULL },
 222         { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },


 223         { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
 224         { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
 225         { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
 226         { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 227         { "it", roff_line_ignore, NULL, NULL, 0, NULL },
 228         { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
 229         { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
 230         { "nr", roff_nr, NULL, NULL, 0, NULL },
 231         { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
 232         { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
 233         { "rm", roff_rm, NULL, NULL, 0, NULL },
 234         { "so", roff_so, NULL, NULL, 0, NULL },
 235         { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
 236         { "tr", roff_tr, NULL, NULL, 0, NULL },


 237         { "TS", roff_TS, NULL, NULL, 0, NULL },
 238         { "TE", roff_TE, NULL, NULL, 0, NULL },
 239         { "T&", roff_T_, NULL, NULL, 0, NULL },
 240         { "EQ", roff_EQ, NULL, NULL, 0, NULL },
 241         { "EN", roff_EN, NULL, NULL, 0, NULL },
 242         { ".", roff_cblock, NULL, NULL, 0, NULL },
 243         { "\\}", roff_ccond, NULL, NULL, 0, NULL },
 244         { NULL, roff_userdef, NULL, NULL, 0, NULL },
 245 };
 246 































 247 /* Array of injected predefined strings. */
 248 #define PREDEFS_MAX      38
 249 static  const struct predef predefs[PREDEFS_MAX] = {
 250 #include "predefs.in"
 251 };
 252 
 253 /* See roffhash_find() */
 254 #define ROFF_HASH(p)    (p[0] - ASCII_LO)
 255 



 256 static void
 257 roffhash_init(void)
 258 {
 259         struct roffmac   *n;
 260         int               buc, i;
 261 
 262         for (i = 0; i < (int)ROFF_USERDEF; i++) {
 263                 assert(roffs[i].name[0] >= ASCII_LO);
 264                 assert(roffs[i].name[0] <= ASCII_HI);
 265 
 266                 buc = ROFF_HASH(roffs[i].name);
 267 
 268                 if (NULL != (n = hash[buc])) {
 269                         for ( ; n->next; n = n->next)
 270                                 /* Do nothing. */ ;
 271                         n->next = &roffs[i];
 272                 } else
 273                         hash[buc] = &roffs[i];
 274         }
 275 }


 334                 int line, int col)
 335 {
 336         struct roffnode *p;
 337 
 338         p = mandoc_calloc(1, sizeof(struct roffnode));
 339         p->tok = tok;
 340         if (name)
 341                 p->name = mandoc_strdup(name);
 342         p->parent = r->last;
 343         p->line = line;
 344         p->col = col;
 345         p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
 346 
 347         r->last = p;
 348 }
 349 
 350 
 351 static void
 352 roff_free1(struct roff *r)
 353 {
 354         struct tbl_node *t;
 355         struct eqn_node *e;
 356         int              i;
 357 
 358         while (NULL != (t = r->first_tbl)) {
 359                 r->first_tbl = t->next;
 360                 tbl_free(t);
 361         }
 362 
 363         r->first_tbl = r->last_tbl = r->tbl = NULL;
 364 
 365         while (NULL != (e = r->first_eqn)) {
 366                 r->first_eqn = e->next;
 367                 eqn_free(e);
 368         }
 369 
 370         r->first_eqn = r->last_eqn = r->eqn = NULL;
 371 
 372         while (r->last)
 373                 roffnode_pop(r);
 374 
 375         roff_freestr(r->strtab);
 376         roff_freestr(r->xmbtab);
 377 
 378         r->strtab = r->xmbtab = NULL;
 379 




 380         if (r->xtab)
 381                 for (i = 0; i < 128; i++)
 382                         free(r->xtab[i].p);
 383 
 384         free(r->xtab);
 385         r->xtab = NULL;
 386 }
 387 
 388 void
 389 roff_reset(struct roff *r)
 390 {
 391         int              i;
 392 
 393         roff_free1(r);
 394 
 395         memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);
 396 
 397         for (i = 0; i < PREDEFS_MAX; i++) 
 398                 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
 399 }
 400 
 401 
 402 void
 403 roff_free(struct roff *r)
 404 {
 405 
 406         roff_free1(r);
 407         free(r);
 408 }
 409 
 410 
 411 struct roff *
 412 roff_alloc(struct mparse *parse)
 413 {
 414         struct roff     *r;
 415         int              i;
 416 
 417         r = mandoc_calloc(1, sizeof(struct roff));

 418         r->parse = parse;
 419         r->rstackpos = -1;
 420         
 421         roffhash_init();
 422 
 423         for (i = 0; i < PREDEFS_MAX; i++) 
 424                 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
 425 
 426         return(r);
 427 }
 428 
 429 /*
 430  * Pre-filter each and every line for reserved words (one beginning with
 431  * `\*', e.g., `\*(ab').  These must be handled before the actual line
 432  * is processed. 
 433  * This also checks the syntax of regular escapes.
 434  */
 435 static enum rofferr
 436 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 437 {
 438         enum mandoc_esc  esc;
 439         const char      *stesc; /* start of an escape sequence ('\\') */
 440         const char      *stnam; /* start of the name, after "[(*" */
 441         const char      *cp;    /* end of the name, e.g. before ']' */
 442         const char      *res;   /* the string to be substituted */
 443         int              i, maxl, expand_count;
 444         size_t           nsz;
 445         char            *n;


 446 
 447         expand_count = 0;
 448 
 449 again:
 450         cp = *bufp + pos;
 451         while (NULL != (cp = strchr(cp, '\\'))) {
 452                 stesc = cp++;
 453 
 454                 /*
 455                  * The second character must be an asterisk.
 456                  * If it isn't, skip it anyway:  It is escaped,
 457                  * so it can't start another escape sequence.
 458                  */
 459 
 460                 if ('\0' == *cp)
 461                         return(ROFF_CONT);
 462 
 463                 if ('*' != *cp) {
 464                         res = cp;
 465                         esc = mandoc_escape(&cp, NULL, NULL);
 466                         if (ESCAPE_ERROR != esc)





 467                                 continue;
 468                         cp = res;
 469                         mandoc_msg
 470                                 (MANDOCERR_BADESCAPE, r->parse, 
 471                                  ln, (int)(stesc - *bufp), NULL);
 472                         return(ROFF_CONT);
 473                 }
 474 
 475                 cp++;
 476 
 477                 /*
 478                  * The third character decides the length
 479                  * of the name of the string.
 480                  * Save a pointer to the name.
 481                  */
 482 
 483                 switch (*cp) {
 484                 case ('\0'):
 485                         return(ROFF_CONT);
 486                 case ('('):
 487                         cp++;
 488                         maxl = 2;
 489                         break;
 490                 case ('['):
 491                         cp++;
 492                         maxl = 0;
 493                         break;
 494                 default:
 495                         maxl = 1;
 496                         break;
 497                 }
 498                 stnam = cp;
 499 
 500                 /* Advance to the end of the name. */
 501 
 502                 for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
 503                         if ('\0' == *cp) {
 504                                 mandoc_msg
 505                                         (MANDOCERR_BADESCAPE, 
 506                                          r->parse, ln, 
 507                                          (int)(stesc - *bufp), NULL);
 508                                 return(ROFF_CONT);
 509                         }
 510                         if (0 == maxl && ']' == *cp)
 511                                 break;
 512                 }
 513 
 514                 /*
 515                  * Retrieve the replacement string; if it is
 516                  * undefined, resume searching for escapes.
 517                  */
 518 
 519                 res = roff_getstrn(r, stnam, (size_t)i);




 520 
 521                 if (NULL == res) {
 522                         mandoc_msg
 523                                 (MANDOCERR_BADESCAPE, r->parse, 
 524                                  ln, (int)(stesc - *bufp), NULL);
 525                         res = "";
 526                 }
 527 
 528                 /* Replace the escape sequence by the string. */
 529 
 530                 pos = stesc - *bufp;
 531 
 532                 nsz = *szp + strlen(res) + 1;
 533                 n = mandoc_malloc(nsz);
 534 
 535                 strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1));
 536                 strlcat(n, res, nsz);
 537                 strlcat(n, cp + (maxl ? 0 : 1), nsz);
 538 
 539                 free(*bufp);
 540 
 541                 *bufp = n;
 542                 *szp = nsz;
 543 
 544                 if (EXPAND_LIMIT >= ++expand_count)
 545                         goto again;
 546 
 547                 /* Just leave the string unexpanded. */
 548                 mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
 549                 return(ROFF_IGN);
 550         }
 551         return(ROFF_CONT);
 552 }
 553 
 554 /*
 555  * Process text streams: convert all breakable hyphens into ASCII_HYPH.


 556  */
 557 static enum rofferr
 558 roff_parsetext(char *p)
 559 {
 560         size_t           sz;
 561         const char      *start;


 562         enum mandoc_esc  esc;
 563 
 564         start = p;
 565 
 566         while ('\0' != *p) {
 567                 sz = strcspn(p, "-\\");
 568                 p += sz;
 569 
 570                 if ('\0' == *p)
 571                         break;
 572 
 573                 if ('\\' == *p) {
 574                         /* Skip over escapes. */
 575                         p++;
 576                         esc = mandoc_escape
 577                                 ((const char **)&p, NULL, NULL);
 578                         if (ESCAPE_ERROR == esc)
 579                                 break;
 580                         continue;
 581                 } else if (p == start) {
 582                         p++;
 583                         continue;
 584                 }
 585 
 586                 if (isalpha((unsigned char)p[-1]) &&
 587                     isalpha((unsigned char)p[1]))
 588                         *p = ASCII_HYPH;
 589                 p++;
 590         }
 591 
















 592         return(ROFF_CONT);
 593 }
 594 
 595 enum rofferr
 596 roff_parseln(struct roff *r, int ln, char **bufp, 
 597                 size_t *szp, int pos, int *offs)
 598 {
 599         enum rofft       t;
 600         enum rofferr     e;
 601         int              ppos, ctl;
 602 
 603         /*
 604          * Run the reserved-word filter only if we have some reserved
 605          * words to fill in.
 606          */
 607 
 608         e = roff_res(r, bufp, szp, ln, pos);
 609         if (ROFF_IGN == e)
 610                 return(e);
 611         assert(ROFF_CONT == e);
 612 
 613         ppos = pos;
 614         ctl = mandoc_getcontrol(*bufp, &pos);
 615 
 616         /*
 617          * First, if a scope is open and we're not a macro, pass the
 618          * text through the macro's filter.  If a scope isn't open and
 619          * we're not a macro, just let it through.
 620          * Finally, if there's an equation scope open, divert it into it
 621          * no matter our state.
 622          */
 623 
 624         if (r->last && ! ctl) {
 625                 t = r->last->tok;
 626                 assert(roffs[t].text);
 627                 e = (*roffs[t].text)
 628                         (r, t, bufp, szp, ln, pos, pos, offs);
 629                 assert(ROFF_IGN == e || ROFF_CONT == e);
 630                 if (ROFF_CONT != e)
 631                         return(e);

 632                 if (r->eqn)
 633                         return(eqn_read(&r->eqn, ln, *bufp, pos, offs));

 634                 if (r->tbl)
 635                         return(tbl_read(r->tbl, ln, *bufp, pos));
 636                 return(roff_parsetext(*bufp + pos));
 637         } else if ( ! ctl) {
 638                 if (r->eqn)
 639                         return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
 640                 if (r->tbl)
 641                         return(tbl_read(r->tbl, ln, *bufp, pos));
 642                 return(roff_parsetext(*bufp + pos));
 643         } else if (r->eqn)
 644                 return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
 645 
 646         /*
 647          * If a scope is open, go to the child handler for that macro,
 648          * as it may want to preprocess before doing anything with it.
 649          * Don't do so if an equation is open.
 650          */
 651 
 652         if (r->last) {
 653                 t = r->last->tok;
 654                 assert(roffs[t].sub);
 655                 return((*roffs[t].sub)
 656                                 (r, t, bufp, szp, 
 657                                  ln, ppos, pos, offs));
 658         }
 659 
 660         /*
 661          * Lastly, as we've no scope open, try to look up and execute
 662          * the new macro.  If no macro is found, simply return and let
 663          * the compilers handle it.
 664          */


 761         default:
 762                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
 763                 return(ROFF_IGN);
 764         }
 765 
 766         if ((*bufp)[pos])
 767                 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
 768 
 769         roffnode_pop(r);
 770         roffnode_cleanscope(r);
 771         return(ROFF_IGN);
 772 
 773 }
 774 
 775 
 776 static void
 777 roffnode_cleanscope(struct roff *r)
 778 {
 779 
 780         while (r->last) {
 781                 if (--r->last->endspan < 0)
 782                         break;
 783                 roffnode_pop(r);
 784         }
 785 }
 786 
 787 
 788 /* ARGSUSED */
 789 static enum rofferr
 790 roff_ccond(ROFF_ARGS)
 791 {
 792 
 793         if (NULL == r->last) {
 794                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
 795                 return(ROFF_IGN);
 796         }
 797 
 798         switch (r->last->tok) {
 799         case (ROFF_el):
 800                 /* FALLTHROUGH */
 801         case (ROFF_ie):


 967 roff_block_text(ROFF_ARGS)
 968 {
 969 
 970         if (ROFF_de == tok)
 971                 roff_setstr(r, r->last->name, *bufp + pos, 1);
 972 
 973         return(ROFF_IGN);
 974 }
 975 
 976 
 977 /* ARGSUSED */
 978 static enum rofferr
 979 roff_cond_sub(ROFF_ARGS)
 980 {
 981         enum rofft       t;
 982         enum roffrule    rr;
 983         char            *ep;
 984 
 985         rr = r->last->rule;
 986         roffnode_cleanscope(r);

 987 
 988         /*
 989          * If the macro is unknown, first check if it contains a closing
 990          * delimiter `\}'.  If it does, close out our scope and return
 991          * the currently-scoped rule (ignore or continue).  Else, drop
 992          * into the currently-scoped rule.
 993          */
 994 
 995         if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) {









 996                 ep = &(*bufp)[pos];
 997                 for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
 998                         ep++;
 999                         if ('}' != *ep)
1000                                 continue;
1001 
1002                         /*
1003                          * Make the \} go away.
1004                          * This is a little haphazard, as it's not quite
1005                          * clear how nroff does this.
1006                          * If we're at the end of line, then just chop
1007                          * off the \} and resize the buffer.
1008                          * If we aren't, then conver it to spaces.
1009                          */
1010 
1011                         if ('\0' == *(ep + 1)) {
1012                                 *--ep = '\0';
1013                                 *szp -= 2;
1014                         } else
1015                                 *(ep - 1) = *ep = ' ';
1016 
1017                         roff_ccond(r, ROFF_ccond, bufp, szp, 
1018                                         ln, pos, pos + 2, offs);
1019                         break;
1020                 }
1021                 return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1022         }
1023 
1024         /*
1025          * A denied conditional must evaluate its children if and only
1026          * if they're either structurally required (such as loops and
1027          * conditionals) or a closing macro.
1028          */
1029 
1030         if (ROFFRULE_DENY == rr)
1031                 if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
1032                         if (ROFF_ccond != t)
1033                                 return(ROFF_IGN);
1034 
1035         assert(roffs[t].proc);
1036         return((*roffs[t].proc)(r, t, bufp, szp, 
1037                                 ln, ppos, pos, offs));
1038 }
1039 
1040 /* ARGSUSED */
1041 static enum rofferr
1042 roff_cond_text(ROFF_ARGS)
1043 {
1044         char            *ep;
1045         enum roffrule    rr;
1046 
1047         rr = r->last->rule;
1048         roffnode_cleanscope(r);
1049 
1050         ep = &(*bufp)[pos];
1051         for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
1052                 ep++;
1053                 if ('}' != *ep)
1054                         continue;
1055                 *ep = '&';
1056                 roff_ccond(r, ROFF_ccond, bufp, szp, 
1057                                 ln, pos, pos + 2, offs);
1058         }
1059         return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1060 }
1061 


















































1062 static enum roffrule
1063 roff_evalcond(const char *v, int *pos)
1064 {


1065 
1066         switch (v[*pos]) {
1067         case ('n'):
1068                 (*pos)++;
1069                 return(ROFFRULE_ALLOW);
1070         case ('e'):
1071                 /* FALLTHROUGH */
1072         case ('o'):
1073                 /* FALLTHROUGH */
1074         case ('t'):
1075                 (*pos)++;
1076                 return(ROFFRULE_DENY);




1077         default:

1078                 break;
1079         }
1080 
1081         while (v[*pos] && ' ' != v[*pos])
1082                 (*pos)++;
1083         return(ROFFRULE_DENY);





























1084 }
1085 
1086 /* ARGSUSED */
1087 static enum rofferr
1088 roff_line_ignore(ROFF_ARGS)
1089 {
1090 
1091         if (ROFF_it == tok)
1092                 mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it");
1093 
1094         return(ROFF_IGN);
1095 }
1096 
1097 /* ARGSUSED */
1098 static enum rofferr
1099 roff_cond(ROFF_ARGS)
1100 {
1101         int              sv;
1102         enum roffrule    rule;
1103 


1104         /* 
1105          * An `.el' has no conditional body: it will consume the value
1106          * of the current rstack entry set in prior `ie' calls or
1107          * defaults to DENY.  
1108          *
1109          * If we're not an `el', however, then evaluate the conditional.
1110          */
1111 
1112         rule = ROFF_el == tok ?
1113                 (r->rstackpos < 0 ? 
1114                  ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
1115                 roff_evalcond(*bufp, &pos);
1116 
1117         sv = pos;
1118         while (' ' == (*bufp)[pos])
1119                 pos++;
1120 
1121         /*
1122          * Roff is weird.  If we have just white-space after the
1123          * conditional, it's considered the BODY and we exit without
1124          * really doing anything.  Warn about this.  It's probably
1125          * wrong.
1126          */
1127 
1128         if ('\0' == (*bufp)[pos] && sv != pos) {
1129                 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1130                 return(ROFF_IGN);
1131         }
1132 
1133         roffnode_push(r, tok, NULL, ln, ppos);
1134 
1135         r->last->rule = rule;
1136 
1137         /*
1138          * An if-else will put the NEGATION of the current evaluated
1139          * conditional into the stack of rules.
1140          */
1141 
1142         if (ROFF_ie == tok) {
1143                 if (r->rstackpos == RSTACK_MAX - 1) {
1144                         mandoc_msg(MANDOCERR_MEM, 
1145                                 r->parse, ln, ppos, NULL);
1146                         return(ROFF_ERR);
1147                 }
1148                 r->rstack[++r->rstackpos] = 
1149                         ROFFRULE_DENY == r->last->rule ?
1150                         ROFFRULE_ALLOW : ROFFRULE_DENY;
1151         }
1152 
1153         /* If the parent has false as its rule, then so do we. */
1154 
1155         if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
1156                 r->last->rule = ROFFRULE_DENY;
1157 
1158         /*
1159          * Determine scope.  If we're invoked with "\{" trailing the
1160          * conditional, then we're in a multiline scope.  Else our scope
1161          * expires on the next line.
1162          */
1163 
1164         r->last->endspan = 1;



1165 





1166         if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
1167                 r->last->endspan = -1;
1168                 pos += 2;

1169         } 
1170 
1171         /*
1172          * If there are no arguments on the line, the next-line scope is
1173          * assumed.

1174          */
1175 
1176         if ('\0' == (*bufp)[pos])
1177                 return(ROFF_IGN);
1178 
1179         /* Otherwise re-run the roff parser after recalculating. */
1180 

1181         *offs = pos;
1182         return(ROFF_RERUN);
1183 }
1184 
1185 
1186 /* ARGSUSED */
1187 static enum rofferr
1188 roff_ds(ROFF_ARGS)
1189 {
1190         char            *name, *string;
1191 
1192         /*
1193          * A symbol is named by the first word following the macro
1194          * invocation up to a space.  Its value is anything after the
1195          * name's trailing whitespace and optional double-quote.  Thus,
1196          *
1197          *  [.ds foo "bar  "     ]
1198          *
1199          * will have `bar  "     ' as its value.
1200          */
1201 
1202         string = *bufp + pos;
1203         name = roff_getname(r, &string, ln, pos);
1204         if ('\0' == *name)
1205                 return(ROFF_IGN);
1206 
1207         /* Read past initial double-quote. */
1208         if ('"' == *string)
1209                 string++;
1210 
1211         /* The rest is the value. */
1212         roff_setstr(r, name, string, 0);
1213         return(ROFF_IGN);
1214 }
1215 





























1216 int
1217 roff_regisset(const struct roff *r, enum regs reg)
1218 {

1219 
1220         return(r->regs[(int)reg].set);




1221 }
1222 
1223 unsigned int
1224 roff_regget(const struct roff *r, enum regs reg)
1225 {

1226 
1227         return(r->regs[(int)reg].u);





1228 }
1229 
1230 void
1231 roff_regunset(struct roff *r, enum regs reg)
1232 {

1233 
1234         r->regs[(int)reg].set = 0;





1235 }
1236 
1237 /* ARGSUSED */
1238 static enum rofferr
1239 roff_nr(ROFF_ARGS)
1240 {
1241         const char      *key;
1242         char            *val;

1243         int              iv;

1244 
1245         val = *bufp + pos;
1246         key = roff_getname(r, &val, ln, pos);
1247 
1248         if (0 == strcmp(key, "nS")) {
1249                 r->regs[(int)REG_nS].set = 1;
1250                 if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0)
1251                         r->regs[(int)REG_nS].u = (unsigned)iv;
1252                 else
1253                         r->regs[(int)REG_nS].u = 0u;
1254         }
1255 





1256         return(ROFF_IGN);
1257 }
1258 
1259 /* ARGSUSED */
1260 static enum rofferr
1261 roff_rm(ROFF_ARGS)
1262 {
1263         const char       *name;
1264         char             *cp;
1265 
1266         cp = *bufp + pos;
1267         while ('\0' != *cp) {
1268                 name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
1269                 if ('\0' != *name)
1270                         roff_setstr(r, name, NULL, 0);
1271         }
1272         return(ROFF_IGN);
1273 }
1274 
1275 /* ARGSUSED */
1276 static enum rofferr



















































1277 roff_TE(ROFF_ARGS)
1278 {
1279 
1280         if (NULL == r->tbl)
1281                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1282         else
1283                 tbl_end(&r->tbl);
1284 
1285         return(ROFF_IGN);
1286 }
1287 
1288 /* ARGSUSED */
1289 static enum rofferr
1290 roff_T_(ROFF_ARGS)
1291 {
1292 
1293         if (NULL == r->tbl)
1294                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1295         else
1296                 tbl_restart(ppos, ln, r->tbl);


1335 roff_EQ(ROFF_ARGS)
1336 {
1337 
1338         roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
1339         return(ROFF_IGN);
1340 }
1341 
1342 /* ARGSUSED */
1343 static enum rofferr
1344 roff_EN(ROFF_ARGS)
1345 {
1346 
1347         mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1348         return(ROFF_IGN);
1349 }
1350 
1351 /* ARGSUSED */
1352 static enum rofferr
1353 roff_TS(ROFF_ARGS)
1354 {
1355         struct tbl_node *t;
1356 
1357         if (r->tbl) {
1358                 mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
1359                 tbl_end(&r->tbl);
1360         }
1361 
1362         t = tbl_alloc(ppos, ln, r->parse);
1363 
1364         if (r->last_tbl)
1365                 r->last_tbl->next = t;
1366         else
1367                 r->first_tbl = r->last_tbl = t;
1368 
1369         r->tbl = r->last_tbl = t;
1370         return(ROFF_IGN);
1371 }
1372 
1373 /* ARGSUSED */
1374 static enum rofferr

















1375 roff_tr(ROFF_ARGS)
1376 {
1377         const char      *p, *first, *second;
1378         size_t           fsz, ssz;
1379         enum mandoc_esc  esc;
1380 
1381         p = *bufp + pos;
1382 
1383         if ('\0' == *p) {
1384                 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1385                 return(ROFF_IGN);
1386         }
1387 
1388         while ('\0' != *p) {
1389                 fsz = ssz = 1;
1390 
1391                 first = p++;
1392                 if ('\\' == *first) {
1393                         esc = mandoc_escape(&p, NULL, NULL);
1394                         if (ESCAPE_ERROR == esc) {


1453         name = *bufp + pos;
1454         if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
1455                 mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
1456                 return(ROFF_ERR);
1457         }
1458 
1459         *offs = pos;
1460         return(ROFF_SO);
1461 }
1462 
1463 /* ARGSUSED */
1464 static enum rofferr
1465 roff_userdef(ROFF_ARGS)
1466 {
1467         const char       *arg[9];
1468         char             *cp, *n1, *n2;
1469         int               i;
1470 
1471         /*
1472          * Collect pointers to macro argument strings
1473          * and null-terminate them.
1474          */
1475         cp = *bufp + pos;
1476         for (i = 0; i < 9; i++)
1477                 arg[i] = '\0' == *cp ? "" :
1478                     mandoc_getarg(r->parse, &cp, ln, &pos);
1479 
1480         /*
1481          * Expand macro arguments.
1482          */
1483         *szp = 0;
1484         n1 = cp = mandoc_strdup(r->current_string);
1485         while (NULL != (cp = strstr(cp, "\\$"))) {
1486                 i = cp[2] - '1';
1487                 if (0 > i || 8 < i) {
1488                         /* Not an argument invocation. */
1489                         cp += 2;
1490                         continue;
1491                 }
1492 
1493                 *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;


1748                 esc = mandoc_escape(&p, NULL, NULL);
1749                 if (ESCAPE_ERROR == esc) {
1750                         sz = strlen(pp);
1751                         res = mandoc_realloc(res, ssz + sz + 1);
1752                         memcpy(res + ssz, pp, sz);
1753                         break;
1754                 }
1755                 /* 
1756                  * We bail out on bad escapes. 
1757                  * No need to warn: we already did so when
1758                  * roff_res() was called.
1759                  */
1760                 sz = (int)(p - pp);
1761                 res = mandoc_realloc(res, ssz + sz + 1);
1762                 memcpy(res + ssz, pp, sz);
1763                 ssz += sz;
1764         }
1765 
1766         res[(int)ssz] = '\0';
1767         return(res);



































1768 }
   1 /*      $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2010, 2011, 2012, 2013 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 <ctype.h>
  24 #include <stdio.h>
  25 #include <stdlib.h>
  26 #include <string.h>
  27 
  28 #include "mandoc.h"
  29 #include "libroff.h"
  30 #include "libmandoc.h"
  31 
  32 /* Maximum number of nested if-else conditionals. */
  33 #define RSTACK_MAX      128
  34 
  35 /* Maximum number of string expansions per line, to break infinite loops. */
  36 #define EXPAND_LIMIT    1000
  37 
  38 enum    rofft {
  39         ROFF_ad,
  40         ROFF_am,
  41         ROFF_ami,
  42         ROFF_am1,
  43         ROFF_cc,
  44         ROFF_de,
  45         ROFF_dei,
  46         ROFF_de1,
  47         ROFF_ds,
  48         ROFF_el,
  49         ROFF_fam,
  50         ROFF_hw,
  51         ROFF_hy,
  52         ROFF_ie,
  53         ROFF_if,
  54         ROFF_ig,
  55         ROFF_it,
  56         ROFF_ne,
  57         ROFF_nh,
  58         ROFF_nr,
  59         ROFF_ns,
  60         ROFF_ps,
  61         ROFF_rm,
  62         ROFF_so,
  63         ROFF_ta,
  64         ROFF_tr,
  65         ROFF_Dd,
  66         ROFF_TH,
  67         ROFF_TS,
  68         ROFF_TE,
  69         ROFF_T_,
  70         ROFF_EQ,
  71         ROFF_EN,
  72         ROFF_cblock,
  73         ROFF_ccond,
  74         ROFF_USERDEF,
  75         ROFF_MAX
  76 };
  77 
  78 enum    roffrule {
  79         ROFFRULE_DENY,
  80         ROFFRULE_ALLOW
  81 };
  82 
  83 /*










  84  * An incredibly-simple string buffer.
  85  */
  86 struct  roffstr {
  87         char            *p; /* nil-terminated buffer */
  88         size_t           sz; /* saved strlen(p) */
  89 };
  90 
  91 /*
  92  * A key-value roffstr pair as part of a singly-linked list.
  93  */
  94 struct  roffkv {
  95         struct roffstr   key;
  96         struct roffstr   val;
  97         struct roffkv   *next; /* next in list */
  98 };
  99 
 100 /*
 101  * A single number register as part of a singly-linked list.
 102  */
 103 struct  roffreg {
 104         struct roffstr   key;
 105         int              val;
 106         struct roffreg  *next;
 107 };
 108 
 109 struct  roff {
 110         enum mparset     parsetype; /* requested parse type */
 111         struct mparse   *parse; /* parse point */
 112         struct roffnode *last; /* leaf of stack */
 113         enum roffrule    rstack[RSTACK_MAX]; /* stack of !`ie' rules */
 114         char             control; /* control character */
 115         int              rstackpos; /* position in rstack */
 116         struct roffreg  *regtab; /* number registers */
 117         struct roffkv   *strtab; /* user-defined strings & macros */
 118         struct roffkv   *xmbtab; /* multi-byte trans table (`tr') */
 119         struct roffstr  *xtab; /* single-byte trans table (`tr') */
 120         const char      *current_string; /* value of last called user macro */
 121         struct tbl_node *first_tbl; /* first table parsed */
 122         struct tbl_node *last_tbl; /* last table parsed */
 123         struct tbl_node *tbl; /* current table being parsed */
 124         struct eqn_node *last_eqn; /* last equation parsed */
 125         struct eqn_node *first_eqn; /* first equation parsed */
 126         struct eqn_node *eqn; /* current equation being parsed */
 127 };
 128 
 129 struct  roffnode {
 130         enum rofft       tok; /* type of node */
 131         struct roffnode *parent; /* up one in stack */
 132         int              line; /* parse line */
 133         int              col; /* parse col */
 134         char            *name; /* node name, e.g. macro name */
 135         char            *end; /* end-rules: custom token */
 136         int              endspan; /* end-rules: next-line or infty */


 159 };
 160 
 161 struct  predef {
 162         const char      *name; /* predefined input name */
 163         const char      *str; /* replacement symbol */
 164 };
 165 
 166 #define PREDEF(__name, __str) \
 167         { (__name), (__str) },
 168 
 169 static  enum rofft       roffhash_find(const char *, size_t);
 170 static  void             roffhash_init(void);
 171 static  void             roffnode_cleanscope(struct roff *);
 172 static  void             roffnode_pop(struct roff *);
 173 static  void             roffnode_push(struct roff *, enum rofft,
 174                                 const char *, int, int);
 175 static  enum rofferr     roff_block(ROFF_ARGS);
 176 static  enum rofferr     roff_block_text(ROFF_ARGS);
 177 static  enum rofferr     roff_block_sub(ROFF_ARGS);
 178 static  enum rofferr     roff_cblock(ROFF_ARGS);
 179 static  enum rofferr     roff_cc(ROFF_ARGS);
 180 static  enum rofferr     roff_ccond(ROFF_ARGS);
 181 static  enum rofferr     roff_cond(ROFF_ARGS);
 182 static  enum rofferr     roff_cond_text(ROFF_ARGS);
 183 static  enum rofferr     roff_cond_sub(ROFF_ARGS);
 184 static  enum rofferr     roff_ds(ROFF_ARGS);
 185 static  enum roffrule    roff_evalcond(const char *, int *);
 186 static  void             roff_free1(struct roff *);
 187 static  void             roff_freereg(struct roffreg *);
 188 static  void             roff_freestr(struct roffkv *);
 189 static  char            *roff_getname(struct roff *, char **, int, int);
 190 static  int              roff_getnum(const char *, int *, int *);
 191 static  int              roff_getop(const char *, int *, char *);
 192 static  int              roff_getregn(const struct roff *,
 193                                 const char *, size_t);
 194 static  const char      *roff_getstrn(const struct roff *, 
 195                                 const char *, size_t);
 196 static  enum rofferr     roff_it(ROFF_ARGS);
 197 static  enum rofferr     roff_line_ignore(ROFF_ARGS);
 198 static  enum rofferr     roff_nr(ROFF_ARGS);
 199 static  void             roff_openeqn(struct roff *, const char *,
 200                                 int, int, const char *);
 201 static  enum rofft       roff_parse(struct roff *, const char *, int *);
 202 static  enum rofferr     roff_parsetext(char **, size_t *, int, int *);
 203 static  enum rofferr     roff_res(struct roff *, 
 204                                 char **, size_t *, int, int);
 205 static  enum rofferr     roff_rm(ROFF_ARGS);
 206 static  void             roff_setstr(struct roff *,
 207                                 const char *, const char *, int);
 208 static  void             roff_setstrn(struct roffkv **, const char *, 
 209                                 size_t, const char *, size_t, int);
 210 static  enum rofferr     roff_so(ROFF_ARGS);
 211 static  enum rofferr     roff_tr(ROFF_ARGS);
 212 static  enum rofferr     roff_Dd(ROFF_ARGS);
 213 static  enum rofferr     roff_TH(ROFF_ARGS);
 214 static  enum rofferr     roff_TE(ROFF_ARGS);
 215 static  enum rofferr     roff_TS(ROFF_ARGS);
 216 static  enum rofferr     roff_EQ(ROFF_ARGS);
 217 static  enum rofferr     roff_EN(ROFF_ARGS);
 218 static  enum rofferr     roff_T_(ROFF_ARGS);
 219 static  enum rofferr     roff_userdef(ROFF_ARGS);
 220 
 221 /* See roffhash_find() */
 222 
 223 #define ASCII_HI         126
 224 #define ASCII_LO         33
 225 #define HASHWIDTH       (ASCII_HI - ASCII_LO + 1)
 226 
 227 static  struct roffmac  *hash[HASHWIDTH];
 228 
 229 static  struct roffmac   roffs[ROFF_MAX] = {
 230         { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
 231         { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 232         { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 233         { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 234         { "cc", roff_cc, NULL, NULL, 0, NULL },
 235         { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 236         { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 237         { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 238         { "ds", roff_ds, NULL, NULL, 0, NULL },
 239         { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
 240         { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
 241         { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
 242         { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
 243         { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
 244         { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
 245         { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
 246         { "it", roff_it, NULL, NULL, 0, NULL },
 247         { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
 248         { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
 249         { "nr", roff_nr, NULL, NULL, 0, NULL },
 250         { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
 251         { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
 252         { "rm", roff_rm, NULL, NULL, 0, NULL },
 253         { "so", roff_so, NULL, NULL, 0, NULL },
 254         { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
 255         { "tr", roff_tr, NULL, NULL, 0, NULL },
 256         { "Dd", roff_Dd, NULL, NULL, 0, NULL },
 257         { "TH", roff_TH, NULL, NULL, 0, NULL },
 258         { "TS", roff_TS, NULL, NULL, 0, NULL },
 259         { "TE", roff_TE, NULL, NULL, 0, NULL },
 260         { "T&", roff_T_, NULL, NULL, 0, NULL },
 261         { "EQ", roff_EQ, NULL, NULL, 0, NULL },
 262         { "EN", roff_EN, NULL, NULL, 0, NULL },
 263         { ".", roff_cblock, NULL, NULL, 0, NULL },
 264         { "\\}", roff_ccond, NULL, NULL, 0, NULL },
 265         { NULL, roff_userdef, NULL, NULL, 0, NULL },
 266 };
 267 
 268 const   char *const __mdoc_reserved[] = {
 269         "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
 270         "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
 271         "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
 272         "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
 273         "Ds", "Dt", "Dv", "Dx", "D1",
 274         "Ec", "Ed", "Ef", "Ek", "El", "Em", "em",
 275         "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex",
 276         "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
 277         "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP",
 278         "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
 279         "Oc", "Oo", "Op", "Os", "Ot", "Ox",
 280         "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq",
 281         "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv",
 282         "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq",
 283         "Ss", "St", "Sx", "Sy",
 284         "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
 285         "%A", "%B", "%D", "%I", "%J", "%N", "%O",
 286         "%P", "%Q", "%R", "%T", "%U", "%V",
 287         NULL
 288 };
 289 
 290 const   char *const __man_reserved[] = {
 291         "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT",
 292         "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR",
 293         "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT",
 294         "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY",
 295         "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS",
 296         NULL
 297 };
 298 
 299 /* Array of injected predefined strings. */
 300 #define PREDEFS_MAX      38
 301 static  const struct predef predefs[PREDEFS_MAX] = {
 302 #include "predefs.in"
 303 };
 304 
 305 /* See roffhash_find() */
 306 #define ROFF_HASH(p)    (p[0] - ASCII_LO)
 307 
 308 static  int      roffit_lines;  /* number of lines to delay */
 309 static  char    *roffit_macro;  /* nil-terminated macro line */
 310 
 311 static void
 312 roffhash_init(void)
 313 {
 314         struct roffmac   *n;
 315         int               buc, i;
 316 
 317         for (i = 0; i < (int)ROFF_USERDEF; i++) {
 318                 assert(roffs[i].name[0] >= ASCII_LO);
 319                 assert(roffs[i].name[0] <= ASCII_HI);
 320 
 321                 buc = ROFF_HASH(roffs[i].name);
 322 
 323                 if (NULL != (n = hash[buc])) {
 324                         for ( ; n->next; n = n->next)
 325                                 /* Do nothing. */ ;
 326                         n->next = &roffs[i];
 327                 } else
 328                         hash[buc] = &roffs[i];
 329         }
 330 }


 389                 int line, int col)
 390 {
 391         struct roffnode *p;
 392 
 393         p = mandoc_calloc(1, sizeof(struct roffnode));
 394         p->tok = tok;
 395         if (name)
 396                 p->name = mandoc_strdup(name);
 397         p->parent = r->last;
 398         p->line = line;
 399         p->col = col;
 400         p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
 401 
 402         r->last = p;
 403 }
 404 
 405 
 406 static void
 407 roff_free1(struct roff *r)
 408 {
 409         struct tbl_node *tbl;
 410         struct eqn_node *e;
 411         int              i;
 412 
 413         while (NULL != (tbl = r->first_tbl)) {
 414                 r->first_tbl = tbl->next;
 415                 tbl_free(tbl);
 416         }
 417 
 418         r->first_tbl = r->last_tbl = r->tbl = NULL;
 419 
 420         while (NULL != (e = r->first_eqn)) {
 421                 r->first_eqn = e->next;
 422                 eqn_free(e);
 423         }
 424 
 425         r->first_eqn = r->last_eqn = r->eqn = NULL;
 426 
 427         while (r->last)
 428                 roffnode_pop(r);
 429 
 430         roff_freestr(r->strtab);
 431         roff_freestr(r->xmbtab);
 432 
 433         r->strtab = r->xmbtab = NULL;
 434 
 435         roff_freereg(r->regtab);
 436 
 437         r->regtab = NULL;
 438 
 439         if (r->xtab)
 440                 for (i = 0; i < 128; i++)
 441                         free(r->xtab[i].p);
 442 
 443         free(r->xtab);
 444         r->xtab = NULL;
 445 }
 446 
 447 void
 448 roff_reset(struct roff *r)
 449 {
 450         int              i;
 451 
 452         roff_free1(r);
 453 
 454         r->control = 0;
 455 
 456         for (i = 0; i < PREDEFS_MAX; i++) 
 457                 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
 458 }
 459 
 460 
 461 void
 462 roff_free(struct roff *r)
 463 {
 464 
 465         roff_free1(r);
 466         free(r);
 467 }
 468 
 469 
 470 struct roff *
 471 roff_alloc(enum mparset type, struct mparse *parse)
 472 {
 473         struct roff     *r;
 474         int              i;
 475 
 476         r = mandoc_calloc(1, sizeof(struct roff));
 477         r->parsetype = type;
 478         r->parse = parse;
 479         r->rstackpos = -1;
 480         
 481         roffhash_init();
 482 
 483         for (i = 0; i < PREDEFS_MAX; i++) 
 484                 roff_setstr(r, predefs[i].name, predefs[i].str, 0);
 485 
 486         return(r);
 487 }
 488 
 489 /*
 490  * In the current line, expand user-defined strings ("\*")
 491  * and references to number registers ("\n").
 492  * Also check the syntax of other escape sequences.

 493  */
 494 static enum rofferr
 495 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 496 {
 497         char             ubuf[12]; /* buffer to print the number */
 498         const char      *stesc; /* start of an escape sequence ('\\') */
 499         const char      *stnam; /* start of the name, after "[(*" */
 500         const char      *cp;    /* end of the name, e.g. before ']' */
 501         const char      *res;   /* the string to be substituted */
 502         char            *nbuf;  /* new buffer to copy bufp to */
 503         size_t           nsz;   /* size of the new buffer */
 504         size_t           maxl;  /* expected length of the escape name */
 505         size_t           naml;  /* actual length of the escape name */
 506         int              expand_count;  /* to avoid infinite loops */
 507 
 508         expand_count = 0;
 509 
 510 again:
 511         cp = *bufp + pos;
 512         while (NULL != (cp = strchr(cp, '\\'))) {
 513                 stesc = cp++;
 514 
 515                 /*
 516                  * The second character must be an asterisk or an n.
 517                  * If it isn't, skip it anyway:  It is escaped,
 518                  * so it can't start another escape sequence.
 519                  */
 520 
 521                 if ('\0' == *cp)
 522                         return(ROFF_CONT);
 523 
 524                 switch (*cp) {
 525                 case ('*'):
 526                         res = NULL;
 527                         break;
 528                 case ('n'):
 529                         res = ubuf;
 530                         break;
 531                 default:
 532                         if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
 533                                 continue;

 534                         mandoc_msg
 535                                 (MANDOCERR_BADESCAPE, r->parse, 
 536                                  ln, (int)(stesc - *bufp), NULL);
 537                         return(ROFF_CONT);
 538                 }
 539 
 540                 cp++;
 541 
 542                 /*
 543                  * The third character decides the length
 544                  * of the name of the string or register.
 545                  * Save a pointer to the name.
 546                  */
 547 
 548                 switch (*cp) {
 549                 case ('\0'):
 550                         return(ROFF_CONT);
 551                 case ('('):
 552                         cp++;
 553                         maxl = 2;
 554                         break;
 555                 case ('['):
 556                         cp++;
 557                         maxl = 0;
 558                         break;
 559                 default:
 560                         maxl = 1;
 561                         break;
 562                 }
 563                 stnam = cp;
 564 
 565                 /* Advance to the end of the name. */
 566 
 567                 for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
 568                         if ('\0' == *cp) {
 569                                 mandoc_msg
 570                                         (MANDOCERR_BADESCAPE, 
 571                                          r->parse, ln, 
 572                                          (int)(stesc - *bufp), NULL);
 573                                 return(ROFF_CONT);
 574                         }
 575                         if (0 == maxl && ']' == *cp)
 576                                 break;
 577                 }
 578 
 579                 /*
 580                  * Retrieve the replacement string; if it is
 581                  * undefined, resume searching for escapes.
 582                  */
 583 
 584                 if (NULL == res)
 585                         res = roff_getstrn(r, stnam, naml);
 586                 else
 587                         snprintf(ubuf, sizeof(ubuf), "%d",
 588                             roff_getregn(r, stnam, naml));
 589 
 590                 if (NULL == res) {
 591                         mandoc_msg
 592                                 (MANDOCERR_BADESCAPE, r->parse, 
 593                                  ln, (int)(stesc - *bufp), NULL);
 594                         res = "";
 595                 }
 596 
 597                 /* Replace the escape sequence by the string. */
 598 
 599                 pos = stesc - *bufp;
 600 
 601                 nsz = *szp + strlen(res) + 1;
 602                 nbuf = mandoc_malloc(nsz);
 603 
 604                 strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
 605                 strlcat(nbuf, res, nsz);
 606                 strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
 607 
 608                 free(*bufp);
 609 
 610                 *bufp = nbuf;
 611                 *szp = nsz;
 612 
 613                 if (EXPAND_LIMIT >= ++expand_count)
 614                         goto again;
 615 
 616                 /* Just leave the string unexpanded. */
 617                 mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
 618                 return(ROFF_IGN);
 619         }
 620         return(ROFF_CONT);
 621 }
 622 
 623 /*
 624  * Process text streams:
 625  * Convert all breakable hyphens into ASCII_HYPH.
 626  * Decrement and spring input line trap.
 627  */
 628 static enum rofferr
 629 roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
 630 {
 631         size_t           sz;
 632         const char      *start;
 633         char            *p;
 634         int              isz;
 635         enum mandoc_esc  esc;
 636 
 637         start = p = *bufp + pos;
 638 
 639         while ('\0' != *p) {
 640                 sz = strcspn(p, "-\\");
 641                 p += sz;
 642 
 643                 if ('\0' == *p)
 644                         break;
 645 
 646                 if ('\\' == *p) {
 647                         /* Skip over escapes. */
 648                         p++;
 649                         esc = mandoc_escape((const char **)&p, NULL, NULL);

 650                         if (ESCAPE_ERROR == esc)
 651                                 break;
 652                         continue;
 653                 } else if (p == start) {
 654                         p++;
 655                         continue;
 656                 }
 657 
 658                 if (isalpha((unsigned char)p[-1]) &&
 659                     isalpha((unsigned char)p[1]))
 660                         *p = ASCII_HYPH;
 661                 p++;
 662         }
 663 
 664         /* Spring the input line trap. */
 665         if (1 == roffit_lines) {
 666                 isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
 667                 if (-1 == isz) {
 668                         perror(NULL);
 669                         exit((int)MANDOCLEVEL_SYSERR);
 670                 }
 671                 free(*bufp);
 672                 *bufp = p;
 673                 *szp = isz + 1;
 674                 *offs = 0;
 675                 free(roffit_macro);
 676                 roffit_lines = 0;
 677                 return(ROFF_REPARSE);
 678         } else if (1 < roffit_lines)
 679                 --roffit_lines;
 680         return(ROFF_CONT);
 681 }
 682 
 683 enum rofferr
 684 roff_parseln(struct roff *r, int ln, char **bufp, 
 685                 size_t *szp, int pos, int *offs)
 686 {
 687         enum rofft       t;
 688         enum rofferr     e;
 689         int              ppos, ctl;
 690 
 691         /*
 692          * Run the reserved-word filter only if we have some reserved
 693          * words to fill in.
 694          */
 695 
 696         e = roff_res(r, bufp, szp, ln, pos);
 697         if (ROFF_IGN == e)
 698                 return(e);
 699         assert(ROFF_CONT == e);
 700 
 701         ppos = pos;
 702         ctl = roff_getcontrol(r, *bufp, &pos);
 703 
 704         /*
 705          * First, if a scope is open and we're not a macro, pass the
 706          * text through the macro's filter.  If a scope isn't open and
 707          * we're not a macro, just let it through.
 708          * Finally, if there's an equation scope open, divert it into it
 709          * no matter our state.
 710          */
 711 
 712         if (r->last && ! ctl) {
 713                 t = r->last->tok;
 714                 assert(roffs[t].text);
 715                 e = (*roffs[t].text)
 716                         (r, t, bufp, szp, ln, pos, pos, offs);
 717                 assert(ROFF_IGN == e || ROFF_CONT == e);
 718                 if (ROFF_CONT != e)
 719                         return(e);
 720         }
 721         if (r->eqn)
 722                 return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
 723         if ( ! ctl) {
 724                 if (r->tbl)
 725                         return(tbl_read(r->tbl, ln, *bufp, pos));
 726                 return(roff_parsetext(bufp, szp, pos, offs));
 727         }







 728 
 729         /*
 730          * If a scope is open, go to the child handler for that macro,
 731          * as it may want to preprocess before doing anything with it.
 732          * Don't do so if an equation is open.
 733          */
 734 
 735         if (r->last) {
 736                 t = r->last->tok;
 737                 assert(roffs[t].sub);
 738                 return((*roffs[t].sub)
 739                                 (r, t, bufp, szp, 
 740                                  ln, ppos, pos, offs));
 741         }
 742 
 743         /*
 744          * Lastly, as we've no scope open, try to look up and execute
 745          * the new macro.  If no macro is found, simply return and let
 746          * the compilers handle it.
 747          */


 844         default:
 845                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
 846                 return(ROFF_IGN);
 847         }
 848 
 849         if ((*bufp)[pos])
 850                 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
 851 
 852         roffnode_pop(r);
 853         roffnode_cleanscope(r);
 854         return(ROFF_IGN);
 855 
 856 }
 857 
 858 
 859 static void
 860 roffnode_cleanscope(struct roff *r)
 861 {
 862 
 863         while (r->last) {
 864                 if (--r->last->endspan != 0)
 865                         break;
 866                 roffnode_pop(r);
 867         }
 868 }
 869 
 870 
 871 /* ARGSUSED */
 872 static enum rofferr
 873 roff_ccond(ROFF_ARGS)
 874 {
 875 
 876         if (NULL == r->last) {
 877                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
 878                 return(ROFF_IGN);
 879         }
 880 
 881         switch (r->last->tok) {
 882         case (ROFF_el):
 883                 /* FALLTHROUGH */
 884         case (ROFF_ie):


1050 roff_block_text(ROFF_ARGS)
1051 {
1052 
1053         if (ROFF_de == tok)
1054                 roff_setstr(r, r->last->name, *bufp + pos, 1);
1055 
1056         return(ROFF_IGN);
1057 }
1058 
1059 
1060 /* ARGSUSED */
1061 static enum rofferr
1062 roff_cond_sub(ROFF_ARGS)
1063 {
1064         enum rofft       t;
1065         enum roffrule    rr;
1066         char            *ep;
1067 
1068         rr = r->last->rule;
1069         roffnode_cleanscope(r);
1070         t = roff_parse(r, *bufp, &pos);
1071 
1072         /*
1073          * Fully handle known macros when they are structurally
1074          * required or when the conditional evaluated to true.


1075          */
1076 
1077         if ((ROFF_MAX != t) &&
1078             (ROFF_ccond == t || ROFFRULE_ALLOW == rr ||
1079              ROFFMAC_STRUCT & roffs[t].flags)) {
1080                 assert(roffs[t].proc);
1081                 return((*roffs[t].proc)(r, t, bufp, szp,
1082                                         ln, ppos, pos, offs));
1083         }
1084 
1085         /* Always check for the closing delimiter `\}'. */
1086 
1087         ep = &(*bufp)[pos];
1088         while (NULL != (ep = strchr(ep, '\\'))) {
1089                 if ('}' != *(++ep))

1090                         continue;
1091 
1092                 /*



1093                  * If we're at the end of line, then just chop
1094                  * off the \} and resize the buffer.
1095                  * If we aren't, then convert it to spaces.
1096                  */
1097 
1098                 if ('\0' == *(ep + 1)) {
1099                         *--ep = '\0';
1100                         *szp -= 2;
1101                 } else
1102                         *(ep - 1) = *ep = ' ';
1103 
1104                 roff_ccond(r, ROFF_ccond, bufp, szp, 
1105                                 ln, pos, pos + 2, offs);
1106                 break;
1107         }
1108         return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
















1109 }
1110 
1111 /* ARGSUSED */
1112 static enum rofferr
1113 roff_cond_text(ROFF_ARGS)
1114 {
1115         char            *ep;
1116         enum roffrule    rr;
1117 
1118         rr = r->last->rule;
1119         roffnode_cleanscope(r);
1120 
1121         ep = &(*bufp)[pos];
1122         for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
1123                 ep++;
1124                 if ('}' != *ep)
1125                         continue;
1126                 *ep = '&';
1127                 roff_ccond(r, ROFF_ccond, bufp, szp, 
1128                                 ln, pos, pos + 2, offs);
1129         }
1130         return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1131 }
1132 
1133 static int
1134 roff_getnum(const char *v, int *pos, int *res)
1135 {
1136         int p, n;
1137 
1138         p = *pos;
1139         n = v[p] == '-';
1140         if (n)
1141                 p++;
1142 
1143         for (*res = 0; isdigit((unsigned char)v[p]); p++)
1144                 *res += 10 * *res + v[p] - '0';
1145         if (p == *pos + n)
1146                 return 0;
1147 
1148         if (n)
1149                 *res = -*res;
1150 
1151         *pos = p;
1152         return 1;
1153 }
1154 
1155 static int
1156 roff_getop(const char *v, int *pos, char *res)
1157 {
1158         int e;
1159 
1160         *res = v[*pos];
1161         e = v[*pos + 1] == '=';
1162 
1163         switch (*res) {
1164         case '=':
1165                 break;
1166         case '>':
1167                 if (e)
1168                         *res = 'g';
1169                 break;
1170         case '<':
1171                 if (e)
1172                         *res = 'l';
1173                 break;
1174         default:
1175                 return(0);
1176         }
1177 
1178         *pos += 1 + e;
1179 
1180         return(*res);
1181 }
1182 
1183 static enum roffrule
1184 roff_evalcond(const char *v, int *pos)
1185 {
1186         int      not, lh, rh;
1187         char     op;
1188 
1189         switch (v[*pos]) {
1190         case ('n'):
1191                 (*pos)++;
1192                 return(ROFFRULE_ALLOW);
1193         case ('e'):
1194                 /* FALLTHROUGH */
1195         case ('o'):
1196                 /* FALLTHROUGH */
1197         case ('t'):
1198                 (*pos)++;
1199                 return(ROFFRULE_DENY);
1200         case ('!'):
1201                 (*pos)++;
1202                 not = 1;
1203                 break;
1204         default:
1205                 not = 0;
1206                 break;
1207         }
1208 
1209         if (!roff_getnum(v, pos, &lh))
1210                 return ROFFRULE_DENY;
1211         if (!roff_getop(v, pos, &op)) {
1212                 if (lh < 0)
1213                         lh = 0;
1214                 goto out;
1215         }
1216         if (!roff_getnum(v, pos, &rh))
1217                 return ROFFRULE_DENY;
1218         switch (op) {
1219         case 'g':
1220                 lh = lh >= rh;
1221                 break;
1222         case 'l':
1223                 lh = lh <= rh;
1224                 break;
1225         case '=':
1226                 lh = lh == rh;
1227                 break;
1228         case '>':
1229                 lh = lh > rh;
1230                 break;
1231         case '<':
1232                 lh = lh < rh;
1233                 break;
1234         default:
1235                 return ROFFRULE_DENY;
1236         }
1237 out:
1238         if (not)
1239                 lh = !lh;
1240         return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
1241 }
1242 
1243 /* ARGSUSED */
1244 static enum rofferr
1245 roff_line_ignore(ROFF_ARGS)
1246 {
1247 



1248         return(ROFF_IGN);
1249 }
1250 
1251 /* ARGSUSED */
1252 static enum rofferr
1253 roff_cond(ROFF_ARGS)
1254 {


1255 
1256         roffnode_push(r, tok, NULL, ln, ppos);
1257 
1258         /* 
1259          * An `.el' has no conditional body: it will consume the value
1260          * of the current rstack entry set in prior `ie' calls or
1261          * defaults to DENY.  
1262          *
1263          * If we're not an `el', however, then evaluate the conditional.
1264          */
1265 
1266         r->last->rule = ROFF_el == tok ?
1267                 (r->rstackpos < 0 ? 
1268                  ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
1269                 roff_evalcond(*bufp, &pos);
1270 




1271         /*
















1272          * An if-else will put the NEGATION of the current evaluated
1273          * conditional into the stack of rules.
1274          */
1275 
1276         if (ROFF_ie == tok) {
1277                 if (r->rstackpos == RSTACK_MAX - 1) {
1278                         mandoc_msg(MANDOCERR_MEM, 
1279                                 r->parse, ln, ppos, NULL);
1280                         return(ROFF_ERR);
1281                 }
1282                 r->rstack[++r->rstackpos] = 
1283                         ROFFRULE_DENY == r->last->rule ?
1284                         ROFFRULE_ALLOW : ROFFRULE_DENY;
1285         }
1286 
1287         /* If the parent has false as its rule, then so do we. */
1288 
1289         if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
1290                 r->last->rule = ROFFRULE_DENY;
1291 
1292         /*
1293          * Determine scope.
1294          * If there is nothing on the line after the conditional,
1295          * not even whitespace, use next-line scope.
1296          */
1297 
1298         if ('\0' == (*bufp)[pos]) {
1299                 r->last->endspan = 2;
1300                 goto out;
1301         }
1302 
1303         while (' ' == (*bufp)[pos])
1304                 pos++;
1305 
1306         /* An opening brace requests multiline scope. */
1307 
1308         if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
1309                 r->last->endspan = -1;
1310                 pos += 2;
1311                 goto out;
1312         } 
1313 
1314         /*
1315          * Anything else following the conditional causes
1316          * single-line scope.  Warn if the scope contains
1317          * nothing but trailing whitespace.
1318          */
1319 
1320         if ('\0' == (*bufp)[pos])
1321                 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1322 
1323         r->last->endspan = 1;
1324 
1325 out:
1326         *offs = pos;
1327         return(ROFF_RERUN);
1328 }
1329 
1330 
1331 /* ARGSUSED */
1332 static enum rofferr
1333 roff_ds(ROFF_ARGS)
1334 {
1335         char            *name, *string;
1336 
1337         /*
1338          * A symbol is named by the first word following the macro
1339          * invocation up to a space.  Its value is anything after the
1340          * name's trailing whitespace and optional double-quote.  Thus,
1341          *
1342          *  [.ds foo "bar  "     ]
1343          *
1344          * will have `bar  "     ' as its value.
1345          */
1346 
1347         string = *bufp + pos;
1348         name = roff_getname(r, &string, ln, pos);
1349         if ('\0' == *name)
1350                 return(ROFF_IGN);
1351 
1352         /* Read past initial double-quote. */
1353         if ('"' == *string)
1354                 string++;
1355 
1356         /* The rest is the value. */
1357         roff_setstr(r, name, string, 0);
1358         return(ROFF_IGN);
1359 }
1360 
1361 void
1362 roff_setreg(struct roff *r, const char *name, int val, char sign)
1363 {
1364         struct roffreg  *reg;
1365 
1366         /* Search for an existing register with the same name. */
1367         reg = r->regtab;
1368 
1369         while (reg && strcmp(name, reg->key.p))
1370                 reg = reg->next;
1371 
1372         if (NULL == reg) {
1373                 /* Create a new register. */
1374                 reg = mandoc_malloc(sizeof(struct roffreg));
1375                 reg->key.p = mandoc_strdup(name);
1376                 reg->key.sz = strlen(name);
1377                 reg->val = 0;
1378                 reg->next = r->regtab;
1379                 r->regtab = reg;
1380         }
1381 
1382         if ('+' == sign)
1383                 reg->val += val;
1384         else if ('-' == sign)
1385                 reg->val -= val;
1386         else
1387                 reg->val = val;
1388 }
1389 
1390 int
1391 roff_getreg(const struct roff *r, const char *name)
1392 {
1393         struct roffreg  *reg;
1394 
1395         for (reg = r->regtab; reg; reg = reg->next)
1396                 if (0 == strcmp(name, reg->key.p))
1397                         return(reg->val);
1398 
1399         return(0);
1400 }
1401 
1402 static int
1403 roff_getregn(const struct roff *r, const char *name, size_t len)
1404 {
1405         struct roffreg  *reg;
1406 
1407         for (reg = r->regtab; reg; reg = reg->next)
1408                 if (len == reg->key.sz &&
1409                     0 == strncmp(name, reg->key.p, len))
1410                         return(reg->val);
1411 
1412         return(0);
1413 }
1414 
1415 static void
1416 roff_freereg(struct roffreg *reg)
1417 {
1418         struct roffreg  *old_reg;
1419 
1420         while (NULL != reg) {
1421                 free(reg->key.p);
1422                 old_reg = reg;
1423                 reg = reg->next;
1424                 free(old_reg);
1425         }
1426 }
1427 
1428 /* ARGSUSED */
1429 static enum rofferr
1430 roff_nr(ROFF_ARGS)
1431 {
1432         const char      *key;
1433         char            *val;
1434         size_t           sz;
1435         int              iv;
1436         char             sign;
1437 
1438         val = *bufp + pos;
1439         key = roff_getname(r, &val, ln, pos);
1440 
1441         sign = *val;
1442         if ('+' == sign || '-' == sign)
1443                 val++;




1444 
1445         sz = strspn(val, "0123456789");
1446         iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
1447 
1448         roff_setreg(r, key, iv, sign);
1449 
1450         return(ROFF_IGN);
1451 }
1452 
1453 /* ARGSUSED */
1454 static enum rofferr
1455 roff_rm(ROFF_ARGS)
1456 {
1457         const char       *name;
1458         char             *cp;
1459 
1460         cp = *bufp + pos;
1461         while ('\0' != *cp) {
1462                 name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
1463                 if ('\0' != *name)
1464                         roff_setstr(r, name, NULL, 0);
1465         }
1466         return(ROFF_IGN);
1467 }
1468 
1469 /* ARGSUSED */
1470 static enum rofferr
1471 roff_it(ROFF_ARGS)
1472 {
1473         char            *cp;
1474         size_t           len;
1475         int              iv;
1476 
1477         /* Parse the number of lines. */
1478         cp = *bufp + pos;
1479         len = strcspn(cp, " \t");
1480         cp[len] = '\0';
1481         if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
1482                 mandoc_msg(MANDOCERR_NUMERIC, r->parse,
1483                                 ln, ppos, *bufp + 1);
1484                 return(ROFF_IGN);
1485         }
1486         cp += len + 1;
1487 
1488         /* Arm the input line trap. */
1489         roffit_lines = iv;
1490         roffit_macro = mandoc_strdup(cp);
1491         return(ROFF_IGN);
1492 }
1493 
1494 /* ARGSUSED */
1495 static enum rofferr
1496 roff_Dd(ROFF_ARGS)
1497 {
1498         const char *const       *cp;
1499 
1500         if (MPARSE_MDOC != r->parsetype)
1501                 for (cp = __mdoc_reserved; *cp; cp++)
1502                         roff_setstr(r, *cp, NULL, 0);
1503 
1504         return(ROFF_CONT);
1505 }
1506 
1507 /* ARGSUSED */
1508 static enum rofferr
1509 roff_TH(ROFF_ARGS)
1510 {
1511         const char *const       *cp;
1512 
1513         if (MPARSE_MDOC != r->parsetype)
1514                 for (cp = __man_reserved; *cp; cp++)
1515                         roff_setstr(r, *cp, NULL, 0);
1516 
1517         return(ROFF_CONT);
1518 }
1519 
1520 /* ARGSUSED */
1521 static enum rofferr
1522 roff_TE(ROFF_ARGS)
1523 {
1524 
1525         if (NULL == r->tbl)
1526                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1527         else
1528                 tbl_end(&r->tbl);
1529 
1530         return(ROFF_IGN);
1531 }
1532 
1533 /* ARGSUSED */
1534 static enum rofferr
1535 roff_T_(ROFF_ARGS)
1536 {
1537 
1538         if (NULL == r->tbl)
1539                 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1540         else
1541                 tbl_restart(ppos, ln, r->tbl);


1580 roff_EQ(ROFF_ARGS)
1581 {
1582 
1583         roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
1584         return(ROFF_IGN);
1585 }
1586 
1587 /* ARGSUSED */
1588 static enum rofferr
1589 roff_EN(ROFF_ARGS)
1590 {
1591 
1592         mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1593         return(ROFF_IGN);
1594 }
1595 
1596 /* ARGSUSED */
1597 static enum rofferr
1598 roff_TS(ROFF_ARGS)
1599 {
1600         struct tbl_node *tbl;
1601 
1602         if (r->tbl) {
1603                 mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
1604                 tbl_end(&r->tbl);
1605         }
1606 
1607         tbl = tbl_alloc(ppos, ln, r->parse);
1608 
1609         if (r->last_tbl)
1610                 r->last_tbl->next = tbl;
1611         else
1612                 r->first_tbl = r->last_tbl = tbl;
1613 
1614         r->tbl = r->last_tbl = tbl;
1615         return(ROFF_IGN);
1616 }
1617 
1618 /* ARGSUSED */
1619 static enum rofferr
1620 roff_cc(ROFF_ARGS)
1621 {
1622         const char      *p;
1623 
1624         p = *bufp + pos;
1625 
1626         if ('\0' == *p || '.' == (r->control = *p++))
1627                 r->control = 0;
1628 
1629         if ('\0' != *p)
1630                 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1631 
1632         return(ROFF_IGN);
1633 }
1634 
1635 /* ARGSUSED */
1636 static enum rofferr
1637 roff_tr(ROFF_ARGS)
1638 {
1639         const char      *p, *first, *second;
1640         size_t           fsz, ssz;
1641         enum mandoc_esc  esc;
1642 
1643         p = *bufp + pos;
1644 
1645         if ('\0' == *p) {
1646                 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1647                 return(ROFF_IGN);
1648         }
1649 
1650         while ('\0' != *p) {
1651                 fsz = ssz = 1;
1652 
1653                 first = p++;
1654                 if ('\\' == *first) {
1655                         esc = mandoc_escape(&p, NULL, NULL);
1656                         if (ESCAPE_ERROR == esc) {


1715         name = *bufp + pos;
1716         if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
1717                 mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
1718                 return(ROFF_ERR);
1719         }
1720 
1721         *offs = pos;
1722         return(ROFF_SO);
1723 }
1724 
1725 /* ARGSUSED */
1726 static enum rofferr
1727 roff_userdef(ROFF_ARGS)
1728 {
1729         const char       *arg[9];
1730         char             *cp, *n1, *n2;
1731         int               i;
1732 
1733         /*
1734          * Collect pointers to macro argument strings
1735          * and NUL-terminate them.
1736          */
1737         cp = *bufp + pos;
1738         for (i = 0; i < 9; i++)
1739                 arg[i] = '\0' == *cp ? "" :
1740                     mandoc_getarg(r->parse, &cp, ln, &pos);
1741 
1742         /*
1743          * Expand macro arguments.
1744          */
1745         *szp = 0;
1746         n1 = cp = mandoc_strdup(r->current_string);
1747         while (NULL != (cp = strstr(cp, "\\$"))) {
1748                 i = cp[2] - '1';
1749                 if (0 > i || 8 < i) {
1750                         /* Not an argument invocation. */
1751                         cp += 2;
1752                         continue;
1753                 }
1754 
1755                 *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;


2010                 esc = mandoc_escape(&p, NULL, NULL);
2011                 if (ESCAPE_ERROR == esc) {
2012                         sz = strlen(pp);
2013                         res = mandoc_realloc(res, ssz + sz + 1);
2014                         memcpy(res + ssz, pp, sz);
2015                         break;
2016                 }
2017                 /* 
2018                  * We bail out on bad escapes. 
2019                  * No need to warn: we already did so when
2020                  * roff_res() was called.
2021                  */
2022                 sz = (int)(p - pp);
2023                 res = mandoc_realloc(res, ssz + sz + 1);
2024                 memcpy(res + ssz, pp, sz);
2025                 ssz += sz;
2026         }
2027 
2028         res[(int)ssz] = '\0';
2029         return(res);
2030 }
2031 
2032 /*
2033  * Find out whether a line is a macro line or not.  
2034  * If it is, adjust the current position and return one; if it isn't,
2035  * return zero and don't change the current position.
2036  * If the control character has been set with `.cc', then let that grain
2037  * precedence.
2038  * This is slighly contrary to groff, where using the non-breaking
2039  * control character when `cc' has been invoked will cause the
2040  * non-breaking macro contents to be printed verbatim.
2041  */
2042 int
2043 roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
2044 {
2045         int             pos;
2046 
2047         pos = *ppos;
2048 
2049         if (0 != r->control && cp[pos] == r->control)
2050                 pos++;
2051         else if (0 != r->control)
2052                 return(0);
2053         else if ('\\' == cp[pos] && '.' == cp[pos + 1])
2054                 pos += 2;
2055         else if ('.' == cp[pos] || '\'' == cp[pos])
2056                 pos++;
2057         else
2058                 return(0);
2059 
2060         while (' ' == cp[pos] || '\t' == cp[pos])
2061                 pos++;
2062 
2063         *ppos = pos;
2064         return(1);
2065 }