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

Diff for /mandoc/roff.c between version 1.180 and 1.192

version 1.180, 2013/10/05 22:08:12 version 1.192, 2014/02/14 22:27:41
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>   * Copyright (c) 2010-2014 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 46  enum rofft {
Line 46  enum rofft {
         ROFF_de1,          ROFF_de1,
         ROFF_ds,          ROFF_ds,
         ROFF_el,          ROFF_el,
           ROFF_fam,
           ROFF_hw,
         ROFF_hy,          ROFF_hy,
         ROFF_ie,          ROFF_ie,
         ROFF_if,          ROFF_if,
Line 74  enum rofft {
Line 76  enum rofft {
 };  };
   
 enum    roffrule {  enum    roffrule {
         ROFFRULE_ALLOW,          ROFFRULE_DENY,
         ROFFRULE_DENY          ROFFRULE_ALLOW
 };  };
   
 /*  /*
Line 97  struct roffkv {
Line 99  struct roffkv {
   
 /*  /*
  * A single number register as part of a singly-linked list.   * A single number register as part of a singly-linked list.
  * Registers are assumed to be unsigned ints for now.  
  */   */
 struct  roffreg {  struct  roffreg {
         struct roffstr   key;          struct roffstr   key;
         unsigned int     u;          int              val;
         struct roffreg  *next;          struct roffreg  *next;
 };  };
   
 struct  roff {  struct  roff {
         enum mparset     parsetype; /* requested parse type */          enum mparset     parsetype; /* requested parse type */
         struct mparse   *parse; /* parse point */          struct mparse   *parse; /* parse point */
           int              quick; /* skip standard macro deletion */
         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 */          char             control; /* control character */
Line 186  static void   roff_free1(struct roff *);
Line 188  static void   roff_free1(struct roff *);
 static  void             roff_freereg(struct roffreg *);  static  void             roff_freereg(struct roffreg *);
 static  void             roff_freestr(struct roffkv *);  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  int              roff_getnum(const char *, int *, int *);
   static  int              roff_getop(const char *, int *, char *);
   static  int              roff_getregn(const struct roff *,
                                   const char *, size_t);
   static  int              roff_getregro(const char *name);
 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_it(ROFF_ARGS);  static  enum rofferr     roff_it(ROFF_ARGS);
Line 232  static struct roffmac  roffs[ROFF_MAX] = {
Line 239  static struct roffmac  roffs[ROFF_MAX] = {
         { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },          { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
         { "ds", roff_ds, NULL, NULL, 0, NULL },          { "ds", roff_ds, NULL, NULL, 0, NULL },
         { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },          { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
           { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
           { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
         { "hy", roff_line_ignore, NULL, NULL, 0, NULL },          { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
         { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },          { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
         { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },          { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
Line 440  roff_free1(struct roff *r)
Line 449  roff_free1(struct roff *r)
 void  void
 roff_reset(struct roff *r)  roff_reset(struct roff *r)
 {  {
         int              i;  
   
         roff_free1(r);          roff_free1(r);
   
         r->control = 0;          r->control = 0;
   
         for (i = 0; i < PREDEFS_MAX; i++)  
                 roff_setstr(r, predefs[i].name, predefs[i].str, 0);  
 }  }
   
   
Line 461  roff_free(struct roff *r)
Line 465  roff_free(struct roff *r)
   
   
 struct roff *  struct roff *
 roff_alloc(enum mparset type, struct mparse *parse)  roff_alloc(enum mparset type, struct mparse *parse, int quick)
 {  {
         struct roff     *r;          struct roff     *r;
         int              i;  
   
         r = mandoc_calloc(1, sizeof(struct roff));          r = mandoc_calloc(1, sizeof(struct roff));
         r->parsetype = type;          r->parsetype = type;
         r->parse = parse;          r->parse = parse;
           r->quick = quick;
         r->rstackpos = -1;          r->rstackpos = -1;
   
         roffhash_init();          roffhash_init();
   
         for (i = 0; i < PREDEFS_MAX; i++)  
                 roff_setstr(r, predefs[i].name, predefs[i].str, 0);  
   
         return(r);          return(r);
 }  }
   
 /*  /*
  * Pre-filter each and every line for reserved words (one beginning with   * In the current line, expand user-defined strings ("\*")
  * `\*', e.g., `\*(ab').  These must be handled before the actual line   * and references to number registers ("\n").
  * is processed.   * Also check the syntax of other escape sequences.
  * This also checks the syntax of regular escapes.  
  */   */
 static enum rofferr  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;          char             ubuf[12]; /* buffer to print the number */
         const char      *stesc; /* start of an escape sequence ('\\') */          const char      *stesc; /* start of an escape sequence ('\\') */
         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, expand_count;          char            *nbuf;  /* new buffer to copy bufp to */
         size_t           nsz;          size_t           nsz;   /* size of the new buffer */
         char            *n;          size_t           maxl;  /* expected length of the escape name */
           size_t           naml;  /* actual length of the escape name */
           int              expand_count;  /* to avoid infinite loops */
   
         expand_count = 0;          expand_count = 0;
   
Line 505  again:
Line 507  again:
                 stesc = cp++;                  stesc = cp++;
   
                 /*                  /*
                  * The second character must be an asterisk.                   * The second character must be an asterisk or an n.
                  * If it isn't, skip it anyway:  It is escaped,                   * If it isn't, skip it anyway:  It is escaped,
                  * so it can't start another escape sequence.                   * so it can't start another escape sequence.
                  */                   */
Line 513  again:
Line 515  again:
                 if ('\0' == *cp)                  if ('\0' == *cp)
                         return(ROFF_CONT);                          return(ROFF_CONT);
   
                 if ('*' != *cp) {                  switch (*cp) {
                         res = cp;                  case ('*'):
                         esc = mandoc_escape(&cp, NULL, NULL);                          res = NULL;
                         if (ESCAPE_ERROR != esc)                          break;
                   case ('n'):
                           res = ubuf;
                           break;
                   default:
                           if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
                                 continue;                                  continue;
                         cp = res;  
                         mandoc_msg                          mandoc_msg
                                 (MANDOCERR_BADESCAPE, r->parse,                                  (MANDOCERR_BADESCAPE, r->parse,
                                  ln, (int)(stesc - *bufp), NULL);                                   ln, (int)(stesc - *bufp), NULL);
Line 529  again:
Line 535  again:
   
                 /*                  /*
                  * The third character decides the length                   * The third character decides the length
                  * of the name of the string.                   * of the name of the string or register.
                  * Save a pointer to the name.                   * Save a pointer to the name.
                  */                   */
   
Line 552  again:
Line 558  again:
   
                 /* Advance to the end of the name. */                  /* Advance to the end of the name. */
   
                 for (i = 0; 0 == maxl || i < maxl; i++, cp++) {                  for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
                         if ('\0' == *cp) {                          if ('\0' == *cp) {
                                 mandoc_msg                                  mandoc_msg
                                         (MANDOCERR_BADESCAPE,                                          (MANDOCERR_BADESCAPE,
Line 569  again:
Line 575  again:
                  * undefined, resume searching for escapes.                   * undefined, resume searching for escapes.
                  */                   */
   
                 res = roff_getstrn(r, stnam, (size_t)i);                  if (NULL == res)
                           res = roff_getstrn(r, stnam, naml);
                   else
                           snprintf(ubuf, sizeof(ubuf), "%d",
                               roff_getregn(r, stnam, naml));
   
                 if (NULL == res) {                  if (NULL == res) {
                         mandoc_msg                          mandoc_msg
Line 583  again:
Line 593  again:
                 pos = stesc - *bufp;                  pos = stesc - *bufp;
   
                 nsz = *szp + strlen(res) + 1;                  nsz = *szp + strlen(res) + 1;
                 n = mandoc_malloc(nsz);                  nbuf = mandoc_malloc(nsz);
   
                 strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1));                  strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
                 strlcat(n, res, nsz);                  strlcat(nbuf, res, nsz);
                 strlcat(n, cp + (maxl ? 0 : 1), nsz);                  strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
   
                 free(*bufp);                  free(*bufp);
   
                 *bufp = n;                  *bufp = nbuf;
                 *szp = nsz;                  *szp = nsz;
   
                 if (EXPAND_LIMIT >= ++expand_count)                  if (EXPAND_LIMIT >= ++expand_count)
Line 630  roff_parsetext(char **bufp, size_t *szp, int pos, int 
Line 640  roff_parsetext(char **bufp, size_t *szp, int pos, int 
                 if ('\\' == *p) {                  if ('\\' == *p) {
                         /* Skip over escapes. */                          /* Skip over escapes. */
                         p++;                          p++;
                         esc = mandoc_escape                          esc = mandoc_escape((const char **)&p, NULL, NULL);
                                 ((const char const **)&p, NULL, NULL);  
                         if (ESCAPE_ERROR == esc)                          if (ESCAPE_ERROR == esc)
                                 break;                                  break;
                         continue;                          continue;
Line 702  roff_parseln(struct roff *r, int ln, char **bufp, 
Line 711  roff_parseln(struct roff *r, int ln, char **bufp, 
                 assert(ROFF_IGN == e || ROFF_CONT == e);                  assert(ROFF_IGN == e || ROFF_CONT == e);
                 if (ROFF_CONT != e)                  if (ROFF_CONT != e)
                         return(e);                          return(e);
                 if (r->eqn)          }
                         return(eqn_read(&r->eqn, ln, *bufp, pos, offs));          if (r->eqn)
                   return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
           if ( ! ctl) {
                 if (r->tbl)                  if (r->tbl)
                         return(tbl_read(r->tbl, ln, *bufp, pos));                          return(tbl_read(r->tbl, ln, *bufp, pos));
                 return(roff_parsetext(bufp, szp, pos, offs));                  return(roff_parsetext(bufp, szp, pos, offs));
         } else if ( ! ctl) {          }
                 if (r->eqn)  
                         return(eqn_read(&r->eqn, ln, *bufp, pos, offs));  
                 if (r->tbl)  
                         return(tbl_read(r->tbl, ln, *bufp, pos));  
                 return(roff_parsetext(bufp, szp, pos, offs));  
         } else if (r->eqn)  
                 return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));  
   
         /*          /*
          * If a scope is open, go to the child handler for that macro,           * If a scope is open, go to the child handler for that macro,
Line 1120  roff_cond_text(ROFF_ARGS)
Line 1124  roff_cond_text(ROFF_ARGS)
         return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);          return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
 }  }
   
   static int
   roff_getnum(const char *v, int *pos, int *res)
   {
           int p, n;
   
           p = *pos;
           n = v[p] == '-';
           if (n)
                   p++;
   
           for (*res = 0; isdigit((unsigned char)v[p]); p++)
                   *res += 10 * *res + v[p] - '0';
           if (p == *pos + n)
                   return 0;
   
           if (n)
                   *res = -*res;
   
           *pos = p;
           return 1;
   }
   
   static int
   roff_getop(const char *v, int *pos, char *res)
   {
           int e;
   
           *res = v[*pos];
           e = v[*pos + 1] == '=';
   
           switch (*res) {
           case '=':
                   break;
           case '>':
                   if (e)
                           *res = 'g';
                   break;
           case '<':
                   if (e)
                           *res = 'l';
                   break;
           default:
                   return(0);
           }
   
           *pos += 1 + e;
   
           return(*res);
   }
   
 static enum roffrule  static enum roffrule
 roff_evalcond(const char *v, int *pos)  roff_evalcond(const char *v, int *pos)
 {  {
           int      not, lh, rh;
           char     op;
   
         switch (v[*pos]) {          switch (v[*pos]) {
         case ('n'):          case ('n'):
Line 1135  roff_evalcond(const char *v, int *pos)
Line 1191  roff_evalcond(const char *v, int *pos)
         case ('t'):          case ('t'):
                 (*pos)++;                  (*pos)++;
                 return(ROFFRULE_DENY);                  return(ROFFRULE_DENY);
           case ('!'):
                   (*pos)++;
                   not = 1;
                   break;
         default:          default:
                   not = 0;
                 break;                  break;
         }          }
   
         while (v[*pos] && ' ' != v[*pos])          if (!roff_getnum(v, pos, &lh))
                 (*pos)++;                  return ROFFRULE_DENY;
         return(ROFFRULE_DENY);          if (!roff_getop(v, pos, &op)) {
                   if (lh < 0)
                           lh = 0;
                   goto out;
           }
           if (!roff_getnum(v, pos, &rh))
                   return ROFFRULE_DENY;
           switch (op) {
           case 'g':
                   lh = lh >= rh;
                   break;
           case 'l':
                   lh = lh <= rh;
                   break;
           case '=':
                   lh = lh == rh;
                   break;
           case '>':
                   lh = lh > rh;
                   break;
           case '<':
                   lh = lh < rh;
                   break;
           default:
                   return ROFFRULE_DENY;
           }
   out:
           if (not)
                   lh = !lh;
           return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
 }  }
   
 /* ARGSUSED */  /* ARGSUSED */
Line 1263  roff_ds(ROFF_ARGS)
Line 1353  roff_ds(ROFF_ARGS)
 }  }
   
 void  void
 roff_setreg(struct roff *r, const char *name, unsigned int val)  roff_setreg(struct roff *r, const char *name, int val, char sign)
 {  {
         struct roffreg  *reg;          struct roffreg  *reg;
   
Line 1278  roff_setreg(struct roff *r, const char *name, unsigned
Line 1368  roff_setreg(struct roff *r, const char *name, unsigned
                 reg = mandoc_malloc(sizeof(struct roffreg));                  reg = mandoc_malloc(sizeof(struct roffreg));
                 reg->key.p = mandoc_strdup(name);                  reg->key.p = mandoc_strdup(name);
                 reg->key.sz = strlen(name);                  reg->key.sz = strlen(name);
                   reg->val = 0;
                 reg->next = r->regtab;                  reg->next = r->regtab;
                 r->regtab = reg;                  r->regtab = reg;
         }          }
   
         reg->u = val;          if ('+' == sign)
                   reg->val += val;
           else if ('-' == sign)
                   reg->val -= val;
           else
                   reg->val = val;
 }  }
   
 unsigned int  /*
    * Handle some predefined read-only number registers.
    * For now, return -1 if the requested register is not predefined;
    * in case a predefined read-only register having the value -1
    * were to turn up, another special value would have to be chosen.
    */
   static int
   roff_getregro(const char *name)
   {
   
           switch (*name) {
           case ('A'):  /* ASCII approximation mode is always off. */
                   return(0);
           case ('g'):  /* Groff compatibility mode is always on. */
                   return(1);
           case ('H'):  /* Fixed horizontal resolution. */
                   return (24);
           case ('j'):  /* Always adjust left margin only. */
                   return(0);
           case ('T'):  /* Some output device is always defined. */
                   return(1);
           case ('V'):  /* Fixed vertical resolution. */
                   return (40);
           default:
                   return (-1);
           }
   }
   
   int
 roff_getreg(const struct roff *r, const char *name)  roff_getreg(const struct roff *r, const char *name)
 {  {
         struct roffreg  *reg;          struct roffreg  *reg;
           int              val;
   
           if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
                   val = roff_getregro(name + 1);
                   if (-1 != val)
                           return (val);
           }
   
         for (reg = r->regtab; reg; reg = reg->next)          for (reg = r->regtab; reg; reg = reg->next)
                 if (0 == strcmp(name, reg->key.p))                  if (0 == strcmp(name, reg->key.p))
                         return(reg->u);                          return(reg->val);
   
         return(0);          return(0);
 }  }
   
   static int
   roff_getregn(const struct roff *r, const char *name, size_t len)
   {
           struct roffreg  *reg;
           int              val;
   
           if ('.' == name[0] && 2 == len) {
                   val = roff_getregro(name + 1);
                   if (-1 != val)
                           return (val);
           }
   
           for (reg = r->regtab; reg; reg = reg->next)
                   if (len == reg->key.sz &&
                       0 == strncmp(name, reg->key.p, len))
                           return(reg->val);
   
           return(0);
   }
   
 static void  static void
 roff_freereg(struct roffreg *reg)  roff_freereg(struct roffreg *reg)
 {  {
Line 1316  roff_nr(ROFF_ARGS)
Line 1467  roff_nr(ROFF_ARGS)
 {  {
         const char      *key;          const char      *key;
         char            *val;          char            *val;
           size_t           sz;
         int              iv;          int              iv;
           char             sign;
   
         val = *bufp + pos;          val = *bufp + pos;
         key = roff_getname(r, &val, ln, pos);          key = roff_getname(r, &val, ln, pos);
   
         iv = mandoc_strntoi(val, strlen(val), 10);          sign = *val;
         if (0 > iv)          if ('+' == sign || '-' == sign)
                 iv = 0;                  val++;
   
         roff_setreg(r, key, (unsigned)iv);          sz = strspn(val, "0123456789");
           iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
   
           roff_setreg(r, key, iv, sign);
   
         return(ROFF_IGN);          return(ROFF_IGN);
 }  }
   
Line 1377  roff_Dd(ROFF_ARGS)
Line 1533  roff_Dd(ROFF_ARGS)
 {  {
         const char *const       *cp;          const char *const       *cp;
   
         if (MPARSE_MDOC != r->parsetype)          if (0 == r->quick && MPARSE_MDOC != r->parsetype)
                 for (cp = __mdoc_reserved; *cp; cp++)                  for (cp = __mdoc_reserved; *cp; cp++)
                         roff_setstr(r, *cp, NULL, 0);                          roff_setstr(r, *cp, NULL, 0);
   
Line 1390  roff_TH(ROFF_ARGS)
Line 1546  roff_TH(ROFF_ARGS)
 {  {
         const char *const       *cp;          const char *const       *cp;
   
         if (MPARSE_MDOC != r->parsetype)          if (0 == r->quick && MPARSE_MDOC != r->parsetype)
                 for (cp = __man_reserved; *cp; cp++)                  for (cp = __man_reserved; *cp; cp++)
                         roff_setstr(r, *cp, NULL, 0);                          roff_setstr(r, *cp, NULL, 0);
   
Line 1612  roff_userdef(ROFF_ARGS)
Line 1768  roff_userdef(ROFF_ARGS)
   
         /*          /*
          * Collect pointers to macro argument strings           * Collect pointers to macro argument strings
          * and null-terminate them.           * and NUL-terminate them.
          */           */
         cp = *bufp + pos;          cp = *bufp + pos;
         for (i = 0; i < 9; i++)          for (i = 0; i < 9; i++)
Line 1781  static const char *
Line 1937  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 roffkv *n;          const struct roffkv *n;
           int i;
   
         for (n = r->strtab; n; n = n->next)          for (n = r->strtab; n; n = n->next)
                 if (0 == strncmp(name, n->key.p, len) &&                  if (0 == strncmp(name, n->key.p, len) &&
                                 '\0' == n->key.p[(int)len])                                  '\0' == n->key.p[(int)len])
                         return(n->val.p);                          return(n->val.p);
   
           for (i = 0; i < PREDEFS_MAX; i++)
                   if (0 == strncmp(name, predefs[i].name, len) &&
                                   '\0' == predefs[i].name[(int)len])
                           return(predefs[i].str);
   
         return(NULL);          return(NULL);
 }  }

Legend:
Removed from v.1.180  
changed lines
  Added in v.1.192

CVSweb