[BACK]Return to roff.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/roff.c between version 1.165 and 1.174

version 1.165, 2011/07/28 14:53:22 version 1.174, 2012/06/12 20:21:04
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>   * Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 31 
Line 31 
 /* Maximum number of nested if-else conditionals. */  /* Maximum number of nested if-else conditionals. */
 #define RSTACK_MAX      128  #define RSTACK_MAX      128
   
   /* Maximum number of string expansions per line, to break infinite loops. */
   #define EXPAND_LIMIT    1000
   
 enum    rofft {  enum    rofft {
         ROFF_ad,          ROFF_ad,
         ROFF_am,          ROFF_am,
         ROFF_ami,          ROFF_ami,
         ROFF_am1,          ROFF_am1,
           ROFF_cc,
         ROFF_de,          ROFF_de,
         ROFF_dei,          ROFF_dei,
         ROFF_de1,          ROFF_de1,
Line 77  enum roffrule {
Line 81  enum roffrule {
  * Registers are assumed to be unsigned ints for now.   * Registers are assumed to be unsigned ints for now.
  */   */
 struct  reg {  struct  reg {
         int               set; /* whether set or not */          int              set; /* whether set or not */
         unsigned int      u; /* unsigned integer */          unsigned int     u; /* unsigned integer */
 };  };
   
   /*
    * An incredibly-simple string buffer.
    */
 struct  roffstr {  struct  roffstr {
         char            *key; /* key of symbol */          char            *p; /* nil-terminated buffer */
         size_t           keysz;          size_t           sz; /* saved strlen(p) */
         char            *val; /* current value */  
         size_t           valsz;  
         struct roffstr  *next; /* next in list */  
 };  };
   
   /*
    * A key-value roffstr pair as part of a singly-linked list.
    */
   struct  roffkv {
           struct roffstr   key;
           struct roffstr   val;
           struct roffkv   *next; /* next in list */
   };
   
 struct  roff {  struct  roff {
         struct mparse   *parse; /* parse point */          struct mparse   *parse; /* parse point */
         struct roffnode *last; /* leaf of stack */          struct roffnode *last; /* leaf of stack */
         enum roffrule    rstack[RSTACK_MAX]; /* stack of !`ie' rules */          enum roffrule    rstack[RSTACK_MAX]; /* stack of !`ie' rules */
           char             control; /* control character */
         int              rstackpos; /* position in rstack */          int              rstackpos; /* position in rstack */
         struct reg       regs[REG__MAX];          struct reg       regs[REG__MAX];
         struct roffstr  *strtab; /* user-defined strings & macros */          struct roffkv   *strtab; /* user-defined strings & macros */
         struct roffstr  *chrtab; /* user-defined characters */          struct roffkv   *xmbtab; /* multi-byte trans table (`tr') */
           struct roffstr  *xtab; /* single-byte trans table (`tr') */
         const char      *current_string; /* value of last called user macro */          const char      *current_string; /* value of last called user macro */
         struct tbl_node *first_tbl; /* first table parsed */          struct tbl_node *first_tbl; /* first table parsed */
         struct tbl_node *last_tbl; /* last table parsed */          struct tbl_node *last_tbl; /* last table parsed */
Line 156  static enum rofferr  roff_block(ROFF_ARGS);
Line 171  static enum rofferr  roff_block(ROFF_ARGS);
 static  enum rofferr     roff_block_text(ROFF_ARGS);  static  enum rofferr     roff_block_text(ROFF_ARGS);
 static  enum rofferr     roff_block_sub(ROFF_ARGS);  static  enum rofferr     roff_block_sub(ROFF_ARGS);
 static  enum rofferr     roff_cblock(ROFF_ARGS);  static  enum rofferr     roff_cblock(ROFF_ARGS);
   static  enum rofferr     roff_cc(ROFF_ARGS);
 static  enum rofferr     roff_ccond(ROFF_ARGS);  static  enum rofferr     roff_ccond(ROFF_ARGS);
 static  enum rofferr     roff_cond(ROFF_ARGS);  static  enum rofferr     roff_cond(ROFF_ARGS);
 static  enum rofferr     roff_cond_text(ROFF_ARGS);  static  enum rofferr     roff_cond_text(ROFF_ARGS);
Line 163  static enum rofferr  roff_cond_sub(ROFF_ARGS);
Line 179  static enum rofferr  roff_cond_sub(ROFF_ARGS);
 static  enum rofferr     roff_ds(ROFF_ARGS);  static  enum rofferr     roff_ds(ROFF_ARGS);
 static  enum roffrule    roff_evalcond(const char *, int *);  static  enum roffrule    roff_evalcond(const char *, int *);
 static  void             roff_free1(struct roff *);  static  void             roff_free1(struct roff *);
 static  void             roff_freestr(struct roffstr **);  static  void             roff_freestr(struct roffkv *);
 static  char            *roff_getname(struct roff *, char **, int, int);  static  char            *roff_getname(struct roff *, char **, int, int);
 static  const char      *roff_getstrn(const struct roff *,  static  const char      *roff_getstrn(const struct roff *,
                                 const char *, size_t);                                  const char *, size_t);
 static  enum rofferr     roff_line_ignore(ROFF_ARGS);  static  enum rofferr     roff_line_ignore(ROFF_ARGS);
 static  enum rofferr     roff_nr(ROFF_ARGS);  static  enum rofferr     roff_nr(ROFF_ARGS);
 static  void             roff_openeqn(struct roff *, const char *,  static  void             roff_openeqn(struct roff *, const char *,
                                 int, int, const char *);                                  int, int, const char *);
 static  enum rofft       roff_parse(struct roff *, const char *, int *);  static  enum rofft       roff_parse(struct roff *, const char *, int *);
 static  enum rofferr     roff_parsetext(char *);  static  enum rofferr     roff_parsetext(char *);
 static  void             roff_res(struct roff *,  static  enum rofferr     roff_res(struct roff *,
                                 char **, size_t *, int, int);                                  char **, size_t *, int, int);
 static  enum rofferr     roff_rm(ROFF_ARGS);  static  enum rofferr     roff_rm(ROFF_ARGS);
 static  void             roff_setstr(struct roff *,  static  void             roff_setstr(struct roff *,
                                 const char *, const char *, int);                                  const char *, const char *, int);
 static  void             roff_setstrn(struct roffstr **, const char *,  static  void             roff_setstrn(struct roffkv **, const char *,
                                 size_t, const char *, size_t, int);                                  size_t, const char *, size_t, int);
 static  enum rofferr     roff_so(ROFF_ARGS);  static  enum rofferr     roff_so(ROFF_ARGS);
 static  enum rofferr     roff_tr(ROFF_ARGS);  static  enum rofferr     roff_tr(ROFF_ARGS);
Line 202  static struct roffmac  roffs[ROFF_MAX] = {
Line 218  static struct roffmac  roffs[ROFF_MAX] = {
         { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },          { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
         { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },          { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
         { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },          { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
           { "cc", roff_cc, NULL, NULL, 0, NULL },
         { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },          { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
         { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },          { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
         { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },          { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
Line 340  roff_free1(struct roff *r)
Line 357  roff_free1(struct roff *r)
 {  {
         struct tbl_node *t;          struct tbl_node *t;
         struct eqn_node *e;          struct eqn_node *e;
           int              i;
   
         while (NULL != (t = r->first_tbl)) {          while (NULL != (t = r->first_tbl)) {
                 r->first_tbl = t->next;                  r->first_tbl = t->next;
Line 358  roff_free1(struct roff *r)
Line 376  roff_free1(struct roff *r)
         while (r->last)          while (r->last)
                 roffnode_pop(r);                  roffnode_pop(r);
   
         roff_freestr(&r->strtab);          roff_freestr(r->strtab);
         roff_freestr(&r->chrtab);          roff_freestr(r->xmbtab);
 }  
   
           r->strtab = r->xmbtab = NULL;
   
           if (r->xtab)
                   for (i = 0; i < 128; i++)
                           free(r->xtab[i].p);
   
           free(r->xtab);
           r->xtab = NULL;
   }
   
 void  void
 roff_reset(struct roff *r)  roff_reset(struct roff *r)
 {  {
Line 370  roff_reset(struct roff *r)
Line 396  roff_reset(struct roff *r)
   
         roff_free1(r);          roff_free1(r);
   
           r->control = 0;
         memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);          memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);
   
         for (i = 0; i < PREDEFS_MAX; i++)          for (i = 0; i < PREDEFS_MAX; i++)
Line 410  roff_alloc(struct mparse *parse)
Line 437  roff_alloc(struct mparse *parse)
  * is processed.   * is processed.
  * This also checks the syntax of regular escapes.   * This also checks the syntax of regular escapes.
  */   */
 static void  static enum rofferr
 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)  roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 {  {
         enum mandoc_esc  esc;          enum mandoc_esc  esc;
Line 418  roff_res(struct roff *r, char **bufp, size_t *szp, int
Line 445  roff_res(struct roff *r, char **bufp, size_t *szp, int
         const char      *stnam; /* start of the name, after "[(*" */          const char      *stnam; /* start of the name, after "[(*" */
         const char      *cp;    /* end of the name, e.g. before ']' */          const char      *cp;    /* end of the name, e.g. before ']' */
         const char      *res;   /* the string to be substituted */          const char      *res;   /* the string to be substituted */
         int              i, maxl;          int              i, maxl, expand_count;
         size_t           nsz;          size_t           nsz;
         char            *n;          char            *n;
   
           expand_count = 0;
   
 again:  again:
         cp = *bufp + pos;          cp = *bufp + pos;
         while (NULL != (cp = strchr(cp, '\\'))) {          while (NULL != (cp = strchr(cp, '\\'))) {
Line 434  again:
Line 463  again:
                  */                   */
   
                 if ('\0' == *cp)                  if ('\0' == *cp)
                         return;                          return(ROFF_CONT);
   
                 if ('*' != *cp) {                  if ('*' != *cp) {
                         res = cp;                          res = cp;
Line 445  again:
Line 474  again:
                         mandoc_msg                          mandoc_msg
                                 (MANDOCERR_BADESCAPE, r->parse,                                  (MANDOCERR_BADESCAPE, r->parse,
                                  ln, (int)(stesc - *bufp), NULL);                                   ln, (int)(stesc - *bufp), NULL);
                         return;                          return(ROFF_CONT);
                 }                  }
   
                 cp++;                  cp++;
Line 458  again:
Line 487  again:
   
                 switch (*cp) {                  switch (*cp) {
                 case ('\0'):                  case ('\0'):
                         return;                          return(ROFF_CONT);
                 case ('('):                  case ('('):
                         cp++;                          cp++;
                         maxl = 2;                          maxl = 2;
Line 481  again:
Line 510  again:
                                         (MANDOCERR_BADESCAPE,                                          (MANDOCERR_BADESCAPE,
                                          r->parse, ln,                                           r->parse, ln,
                                          (int)(stesc - *bufp), NULL);                                           (int)(stesc - *bufp), NULL);
                                 return;                                  return(ROFF_CONT);
                         }                          }
                         if (0 == maxl && ']' == *cp)                          if (0 == maxl && ']' == *cp)
                                 break;                                  break;
Line 516  again:
Line 545  again:
   
                 *bufp = n;                  *bufp = n;
                 *szp = nsz;                  *szp = nsz;
                 goto again;  
                   if (EXPAND_LIMIT >= ++expand_count)
                           goto again;
   
                   /* Just leave the string unexpanded. */
                   mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
                   return(ROFF_IGN);
         }          }
           return(ROFF_CONT);
 }  }
   
 /*  /*
Line 526  again:
Line 562  again:
 static enum rofferr  static enum rofferr
 roff_parsetext(char *p)  roff_parsetext(char *p)
 {  {
         char             l, r;  
         size_t           sz;          size_t           sz;
         const char      *start;          const char      *start;
         enum mandoc_esc  esc;          enum mandoc_esc  esc;
Line 553  roff_parsetext(char *p)
Line 588  roff_parsetext(char *p)
                         continue;                          continue;
                 }                  }
   
                 l = *(p - 1);                  if (isalpha((unsigned char)p[-1]) &&
                 r = *(p + 1);                      isalpha((unsigned char)p[1]))
                 if ('\\' != l &&  
                                 '\t' != r && '\t' != l &&  
                                 ' ' != r && ' ' != l &&  
                                 '-' != r && '-' != l &&  
                                 ! isdigit((unsigned char)l) &&  
                                 ! isdigit((unsigned char)r))  
                         *p = ASCII_HYPH;                          *p = ASCII_HYPH;
                 p++;                  p++;
         }          }
Line 581  roff_parseln(struct roff *r, int ln, char **bufp, 
Line 610  roff_parseln(struct roff *r, int ln, char **bufp, 
          * words to fill in.           * words to fill in.
          */           */
   
         roff_res(r, bufp, szp, ln, pos);          e = roff_res(r, bufp, szp, ln, pos);
           if (ROFF_IGN == e)
                   return(e);
           assert(ROFF_CONT == e);
   
         ppos = pos;          ppos = pos;
         ctl = mandoc_getcontrol(*bufp, &pos);          ctl = roff_getcontrol(r, *bufp, &pos);
   
         /*          /*
          * First, if a scope is open and we're not a macro, pass the           * First, if a scope is open and we're not a macro, pass the
Line 751  roffnode_cleanscope(struct roff *r)
Line 783  roffnode_cleanscope(struct roff *r)
 {  {
   
         while (r->last) {          while (r->last) {
                 if (--r->last->endspan < 0)                  if (--r->last->endspan != 0)
                         break;                          break;
                 roffnode_pop(r);                  roffnode_pop(r);
         }          }
Line 1071  roff_line_ignore(ROFF_ARGS)
Line 1103  roff_line_ignore(ROFF_ARGS)
 static enum rofferr  static enum rofferr
 roff_cond(ROFF_ARGS)  roff_cond(ROFF_ARGS)
 {  {
         int              sv;  
         enum roffrule    rule;  
   
           roffnode_push(r, tok, NULL, ln, ppos);
   
         /*          /*
          * An `.el' has no conditional body: it will consume the value           * An `.el' has no conditional body: it will consume the value
          * of the current rstack entry set in prior `ie' calls or           * of the current rstack entry set in prior `ie' calls or
Line 1082  roff_cond(ROFF_ARGS)
Line 1114  roff_cond(ROFF_ARGS)
          * If we're not an `el', however, then evaluate the conditional.           * If we're not an `el', however, then evaluate the conditional.
          */           */
   
         rule = ROFF_el == tok ?          r->last->rule = ROFF_el == tok ?
                 (r->rstackpos < 0 ?                  (r->rstackpos < 0 ?
                  ROFFRULE_DENY : r->rstack[r->rstackpos--]) :                   ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
                 roff_evalcond(*bufp, &pos);                  roff_evalcond(*bufp, &pos);
   
         sv = pos;  
         while (' ' == (*bufp)[pos])  
                 pos++;  
   
         /*          /*
          * Roff is weird.  If we have just white-space after the  
          * conditional, it's considered the BODY and we exit without  
          * really doing anything.  Warn about this.  It's probably  
          * wrong.  
          */  
   
         if ('\0' == (*bufp)[pos] && sv != pos) {  
                 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);  
                 return(ROFF_IGN);  
         }  
   
         roffnode_push(r, tok, NULL, ln, ppos);  
   
         r->last->rule = rule;  
   
         /*  
          * An if-else will put the NEGATION of the current evaluated           * An if-else will put the NEGATION of the current evaluated
          * conditional into the stack of rules.           * conditional into the stack of rules.
          */           */
Line 1129  roff_cond(ROFF_ARGS)
Line 1141  roff_cond(ROFF_ARGS)
                 r->last->rule = ROFFRULE_DENY;                  r->last->rule = ROFFRULE_DENY;
   
         /*          /*
          * Determine scope.  If we're invoked with "\{" trailing the           * Determine scope.
          * conditional, then we're in a multiline scope.  Else our scope           * If there is nothing on the line after the conditional,
          * expires on the next line.           * not even whitespace, use next-line scope.
          */           */
   
         r->last->endspan = 1;          if ('\0' == (*bufp)[pos]) {
                   r->last->endspan = 2;
                   goto out;
           }
   
           while (' ' == (*bufp)[pos])
                   pos++;
   
           /* An opening brace requests multiline scope. */
   
         if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {          if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
                 r->last->endspan = -1;                  r->last->endspan = -1;
                 pos += 2;                  pos += 2;
                   goto out;
         }          }
   
         /*          /*
          * If there are no arguments on the line, the next-line scope is           * Anything else following the conditional causes
          * assumed.           * single-line scope.  Warn if the scope contains
            * nothing but trailing whitespace.
          */           */
   
         if ('\0' == (*bufp)[pos])          if ('\0' == (*bufp)[pos])
                 return(ROFF_IGN);                  mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
   
         /* Otherwise re-run the roff parser after recalculating. */          r->last->endspan = 1;
   
   out:
         *offs = pos;          *offs = pos;
         return(ROFF_RERUN);          return(ROFF_RERUN);
 }  }
Line 1345  roff_TS(ROFF_ARGS)
Line 1368  roff_TS(ROFF_ARGS)
   
 /* ARGSUSED */  /* ARGSUSED */
 static enum rofferr  static enum rofferr
   roff_cc(ROFF_ARGS)
   {
           const char      *p;
   
           p = *bufp + pos;
   
           if ('\0' == *p || '.' == (r->control = *p++))
                   r->control = 0;
   
           if ('\0' != *p)
                   mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
   
           return(ROFF_IGN);
   }
   
   /* ARGSUSED */
   static enum rofferr
 roff_tr(ROFF_ARGS)  roff_tr(ROFF_ARGS)
 {  {
         const char      *p, *first, *second;          const char      *p, *first, *second;
Line 1390  roff_tr(ROFF_ARGS)
Line 1430  roff_tr(ROFF_ARGS)
                         p--;                          p--;
                 }                  }
   
                 roff_setstrn(&r->chrtab, first, fsz, second, ssz, 0);                  if (fsz > 1) {
                           roff_setstrn(&r->xmbtab, first,
                                           fsz, second, ssz, 0);
                           continue;
                   }
   
                   if (NULL == r->xtab)
                           r->xtab = mandoc_calloc
                                   (128, sizeof(struct roffstr));
   
                   free(r->xtab[(int)*first].p);
                   r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
                   r->xtab[(int)*first].sz = ssz;
         }          }
   
         return(ROFF_IGN);          return(ROFF_IGN);
Line 1525  roff_setstr(struct roff *r, const char *name, const ch
Line 1577  roff_setstr(struct roff *r, const char *name, const ch
 }  }
   
 static void  static void
 roff_setstrn(struct roffstr **r, const char *name, size_t namesz,  roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
                 const char *string, size_t stringsz, int multiline)                  const char *string, size_t stringsz, int multiline)
 {  {
         struct roffstr  *n;          struct roffkv   *n;
         char            *c;          char            *c;
         int              i;          int              i;
         size_t           oldch, newch;          size_t           oldch, newch;
Line 1536  roff_setstrn(struct roffstr **r, const char *name, siz
Line 1588  roff_setstrn(struct roffstr **r, const char *name, siz
         /* Search for an existing string with the same name. */          /* Search for an existing string with the same name. */
         n = *r;          n = *r;
   
         while (n && strcmp(name, n->key))          while (n && strcmp(name, n->key.p))
                 n = n->next;                  n = n->next;
   
         if (NULL == n) {          if (NULL == n) {
                 /* Create a new string table entry. */                  /* Create a new string table entry. */
                 n = mandoc_malloc(sizeof(struct roffstr));                  n = mandoc_malloc(sizeof(struct roffkv));
                 n->key = mandoc_strndup(name, namesz);                  n->key.p = mandoc_strndup(name, namesz);
                 n->keysz = namesz;                  n->key.sz = namesz;
                 n->val = NULL;                  n->val.p = NULL;
                 n->valsz = 0;                  n->val.sz = 0;
                 n->next = *r;                  n->next = *r;
                 *r = n;                  *r = n;
         } else if (0 == multiline) {          } else if (0 == multiline) {
                 /* In multiline mode, append; else replace. */                  /* In multiline mode, append; else replace. */
                 free(n->val);                  free(n->val.p);
                 n->val = NULL;                  n->val.p = NULL;
                 n->valsz = 0;                  n->val.sz = 0;
         }          }
   
         if (NULL == string)          if (NULL == string)
Line 1564  roff_setstrn(struct roffstr **r, const char *name, siz
Line 1616  roff_setstrn(struct roffstr **r, const char *name, siz
          */           */
         newch = stringsz + (multiline ? 2u : 1u);          newch = stringsz + (multiline ? 2u : 1u);
   
         if (NULL == n->val) {          if (NULL == n->val.p) {
                 n->val = mandoc_malloc(newch);                  n->val.p = mandoc_malloc(newch);
                 *n->val = '\0';                  *n->val.p = '\0';
                 oldch = 0;                  oldch = 0;
         } else {          } else {
                 oldch = n->valsz;                  oldch = n->val.sz;
                 n->val = mandoc_realloc(n->val, oldch + newch);                  n->val.p = mandoc_realloc(n->val.p, oldch + newch);
         }          }
   
         /* Skip existing content in the destination buffer. */          /* Skip existing content in the destination buffer. */
         c = n->val + (int)oldch;          c = n->val.p + (int)oldch;
   
         /* Append new content to the destination buffer. */          /* Append new content to the destination buffer. */
         i = 0;          i = 0;
Line 1593  roff_setstrn(struct roffstr **r, const char *name, siz
Line 1645  roff_setstrn(struct roffstr **r, const char *name, siz
                 *c++ = '\n';                  *c++ = '\n';
   
         *c = '\0';          *c = '\0';
         n->valsz = (int)(c - n->val);          n->val.sz = (int)(c - n->val.p);
 }  }
   
 static const char *  static const char *
 roff_getstrn(const struct roff *r, const char *name, size_t len)  roff_getstrn(const struct roff *r, const char *name, size_t len)
 {  {
         const struct roffstr *n;          const struct roffkv *n;
   
         for (n = r->strtab; n; n = n->next)          for (n = r->strtab; n; n = n->next)
                 if (0 == strncmp(name, n->key, len) &&                  if (0 == strncmp(name, n->key.p, len) &&
                                 '\0' == n->key[(int)len])                                  '\0' == n->key.p[(int)len])
                         return(n->val);                          return(n->val.p);
   
         return(NULL);          return(NULL);
 }  }
   
 static void  static void
 roff_freestr(struct roffstr **r)  roff_freestr(struct roffkv *r)
 {  {
         struct roffstr   *n, *nn;          struct roffkv    *n, *nn;
   
         for (n = *r; n; n = nn) {          for (n = r; n; n = nn) {
                 free(n->key);                  free(n->key.p);
                 free(n->val);                  free(n->val.p);
                 nn = n->next;                  nn = n->next;
                 free(n);                  free(n);
         }          }
   
         *r = NULL;  
 }  }
   
 const struct tbl_span *  const struct tbl_span *
Line 1638  roff_eqn(const struct roff *r)
Line 1688  roff_eqn(const struct roff *r)
         return(r->last_eqn ? &r->last_eqn->eqn : NULL);          return(r->last_eqn ? &r->last_eqn->eqn : NULL);
 }  }
   
 char  
 roff_eqndelim(const struct roff *r)  
 {  
   
         return('\0');  
 }  
   
 /*  /*
  * Duplicate an input string, making the appropriate character   * Duplicate an input string, making the appropriate character
  * conversations (as stipulated by `tr') along the way.   * conversations (as stipulated by `tr') along the way.
Line 1653  roff_eqndelim(const struct roff *r)
Line 1696  roff_eqndelim(const struct roff *r)
 char *  char *
 roff_strdup(const struct roff *r, const char *p)  roff_strdup(const struct roff *r, const char *p)
 {  {
         const struct roffstr *cp;          const struct roffkv *cp;
         char            *res;          char            *res;
         const char      *pp;          const char      *pp;
         size_t           ssz, sz;          size_t           ssz, sz;
         enum mandoc_esc  esc;          enum mandoc_esc  esc;
   
         if (NULL == r->chrtab)          if (NULL == r->xmbtab && NULL == r->xtab)
                 return(mandoc_strdup(p));                  return(mandoc_strdup(p));
         else if ('\0' == *p)          else if ('\0' == *p)
                 return(mandoc_strdup(""));                  return(mandoc_strdup(""));
Line 1676  roff_strdup(const struct roff *r, const char *p)
Line 1719  roff_strdup(const struct roff *r, const char *p)
         ssz = 0;          ssz = 0;
   
         while ('\0' != *p) {          while ('\0' != *p) {
                   if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
                           sz = r->xtab[(int)*p].sz;
                           res = mandoc_realloc(res, ssz + sz + 1);
                           memcpy(res + ssz, r->xtab[(int)*p].p, sz);
                           ssz += sz;
                           p++;
                           continue;
                   } else if ('\\' != *p) {
                           res = mandoc_realloc(res, ssz + 2);
                           res[ssz++] = *p++;
                           continue;
                   }
   
                 /* Search for term matches. */                  /* Search for term matches. */
                 for (cp = r->chrtab; cp; cp = cp->next)                  for (cp = r->xmbtab; cp; cp = cp->next)
                         if (0 == strncmp(p, cp->key, cp->keysz))                          if (0 == strncmp(p, cp->key.p, cp->key.sz))
                                 break;                                  break;
   
                 if (NULL != cp) {                  if (NULL != cp) {
Line 1687  roff_strdup(const struct roff *r, const char *p)
Line 1743  roff_strdup(const struct roff *r, const char *p)
                          * Append the match to the array and move                           * Append the match to the array and move
                          * forward by its keysize.                           * forward by its keysize.
                          */                           */
                         res = mandoc_realloc(res, ssz + cp->valsz + 1);                          res = mandoc_realloc
                         memcpy(res + ssz, cp->val, cp->valsz);                                  (res, ssz + cp->val.sz + 1);
                         ssz += cp->valsz;                          memcpy(res + ssz, cp->val.p, cp->val.sz);
                         p += (int)cp->keysz;                          ssz += cp->val.sz;
                           p += (int)cp->key.sz;
                         continue;                          continue;
                 }                  }
   
                 if ('\\' == *p) {                  /*
                         /*                   * Handle escapes carefully: we need to copy
                          * Handle escapes carefully: we need to copy                   * over just the escape itself, or else we might
                          * over just the escape itself, or else we might                   * do replacements within the escape itself.
                          * do replacements within the escape itself.                   * Make sure to pass along the bogus string.
                          * Make sure to pass along the bogus string.                   */
                          */                  pp = p++;
                         pp = p++;                  esc = mandoc_escape(&p, NULL, NULL);
                         esc = mandoc_escape(&p, NULL, NULL);                  if (ESCAPE_ERROR == esc) {
                         if (ESCAPE_ERROR == esc) {                          sz = strlen(pp);
                                 sz = strlen(pp);  
                                 res = mandoc_realloc(res, ssz + sz + 1);  
                                 memcpy(res + ssz, pp, sz);  
                                 break;  
                         }  
                         /*  
                          * We bail out on bad escapes.  
                          * No need to warn: we already did so when  
                          * roff_res() was called.  
                          */  
                         sz = (int)(p - pp);  
                         res = mandoc_realloc(res, ssz + sz + 1);                          res = mandoc_realloc(res, ssz + sz + 1);
                         memcpy(res + ssz, pp, sz);                          memcpy(res + ssz, pp, sz);
                         ssz += sz;                          break;
                         continue;  
                 }                  }
                   /*
                 /* Just append the charater. */                   * We bail out on bad escapes.
                 res = mandoc_realloc(res, ssz + 2);                   * No need to warn: we already did so when
                 res[ssz++] = *p++;                   * roff_res() was called.
                    */
                   sz = (int)(p - pp);
                   res = mandoc_realloc(res, ssz + sz + 1);
                   memcpy(res + ssz, pp, sz);
                   ssz += sz;
         }          }
   
         res[(int)ssz] = '\0';          res[(int)ssz] = '\0';
         return(res);          return(res);
   }
   
   /*
    * Find out whether a line is a macro line or not.
    * If it is, adjust the current position and return one; if it isn't,
    * return zero and don't change the current position.
    * If the control character has been set with `.cc', then let that grain
    * precedence.
    * This is slighly contrary to groff, where using the non-breaking
    * control character when `cc' has been invoked will cause the
    * non-breaking macro contents to be printed verbatim.
    */
   int
   roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
   {
           int             pos;
   
           pos = *ppos;
   
           if (0 != r->control && cp[pos] == r->control)
                   pos++;
           else if (0 != r->control)
                   return(0);
           else if ('\\' == cp[pos] && '.' == cp[pos + 1])
                   pos += 2;
           else if ('.' == cp[pos] || '\'' == cp[pos])
                   pos++;
           else
                   return(0);
   
           while (' ' == cp[pos] || '\t' == cp[pos])
                   pos++;
   
           *ppos = pos;
           return(1);
 }  }

Legend:
Removed from v.1.165  
changed lines
  Added in v.1.174

CVSweb