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

Diff for /mandoc/eqn.c between version 1.70 and 1.71

version 1.70, 2017/06/26 11:04:47 version 1.71, 2017/06/26 20:09:04
Line 145  static const char *const eqn_func[] = {
Line 145  static const char *const eqn_func[] = {
 };  };
   
 enum    eqn_symt {  enum    eqn_symt {
         EQNSYM_alpha,          EQNSYM_alpha = 0,
         EQNSYM_beta,          EQNSYM_beta,
         EQNSYM_chi,          EQNSYM_chi,
         EQNSYM_delta,          EQNSYM_delta,
Line 276  static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
Line 276  static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
         { "-", "mi" }, /* EQNSYM_minus */          { "-", "mi" }, /* EQNSYM_minus */
 };  };
   
   enum    parse_mode {
           MODE_QUOTED,
           MODE_NOSUB,
           MODE_SUB,
           MODE_TOK
   };
   
 static  struct eqn_box  *eqn_box_alloc(struct eqn_node *, struct eqn_box *);  static  struct eqn_box  *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
 static  void             eqn_box_free(struct eqn_box *);  static  void             eqn_box_free(struct eqn_box *);
 static  struct eqn_box  *eqn_box_makebinary(struct eqn_node *,  static  struct eqn_box  *eqn_box_makebinary(struct eqn_node *,
                                 enum eqn_post, struct eqn_box *);                                  enum eqn_post, struct eqn_box *);
 static  void             eqn_def(struct eqn_node *);  static  void             eqn_def(struct eqn_node *);
 static  struct eqn_def  *eqn_def_find(struct eqn_node *, const char *, size_t);  static  struct eqn_def  *eqn_def_find(struct eqn_node *);
 static  void             eqn_delim(struct eqn_node *);  static  void             eqn_delim(struct eqn_node *);
 static  const char      *eqn_next(struct eqn_node *, char, size_t *, int);  static  enum eqn_tok     eqn_next(struct eqn_node *, enum parse_mode);
 static  const char      *eqn_nextrawtok(struct eqn_node *, size_t *);  
 static  const char      *eqn_nexttok(struct eqn_node *, size_t *);  
 static  enum rofferr     eqn_parse(struct eqn_node *, struct eqn_box *);  static  enum rofferr     eqn_parse(struct eqn_node *, struct eqn_box *);
 static  enum eqn_tok     eqn_tok_parse(struct eqn_node *, char **);  
 static  void             eqn_undef(struct eqn_node *);  static  void             eqn_undef(struct eqn_node *);
   
   
Line 356  eqn_alloc(int pos, int line, struct mparse *parse)
Line 360  eqn_alloc(int pos, int line, struct mparse *parse)
  * Find the key "key" of the give size within our eqn-defined values.   * Find the key "key" of the give size within our eqn-defined values.
  */   */
 static struct eqn_def *  static struct eqn_def *
 eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)  eqn_def_find(struct eqn_node *ep)
 {  {
         int              i;          int              i;
   
         for (i = 0; i < (int)ep->defsz; i++)          for (i = 0; i < (int)ep->defsz; i++)
                 if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,                  if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
                     ep->defs[i].keysz, key, sz))                      ep->defs[i].keysz, ep->start, ep->toksz))
                         return &ep->defs[i];                          return &ep->defs[i];
   
         return NULL;          return NULL;
 }  }
   
 /*  /*
  * Get the next token from the input stream using the given quote   * Parse a token from the input text.  The modes are:
  * character.   * MODE_QUOTED: Use *ep->start as the delimiter; the token ends
  * Optionally make any replacements.   *   before its next occurence.  Do not interpret the token in any
    *   way and return EQN_TOK_QUOTED.  All other modes behave like
    *   MODE_QUOTED when *ep->start is '"'.
    * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;
    *   otherwise, it ends before the next whitespace or brace.
    *   Do not interpret the token and return EQN_TOK__MAX.
    * MODE_SUB: Like MODE_NOSUB, but try to interpret the token as an
    *   alias created with define.  If it is an alias, replace it with
    *   its string value and reparse.
    * MODE_TOK: Like MODE_SUB, but also check the token against the list
    *   of tokens, and if there is a match, return that token.  Otherwise,
    *   if the token matches a symbol, return EQN_TOK_SYM; if it matches
    *   a function name, EQN_TOK_FUNC, or else EQN_TOK__MAX.  Except for
    *   a token match, *ep->start is set to an allocated string that the
    *   caller is expected to free.
    * All modes skip whitespace following the end of the token.
  */   */
 static const char *  static enum eqn_tok
 eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)  eqn_next(struct eqn_node *ep, enum parse_mode mode)
 {  {
         static size_t    last_len;          static int       last_len, lim;
         static int       lim;  
   
         char            *start, *next;  
         int              q, diff;  
         size_t           ssz, dummy;  
         struct eqn_def  *def;          struct eqn_def  *def;
           size_t           start;
           int              diff, i, quoted;
           enum eqn_tok     tok;
   
         if (NULL == sz)          /*
                 sz = &dummy;           * Reset the recursion counter after advancing
            * beyond the end of the previous substitution.
         if (ep->cur >= last_len)           */
           if (ep->end - ep->data >= last_len)
                 lim = 0;                  lim = 0;
         ep->rew = ep->cur;  
 again:  
         /* Prevent self-definitions. */  
   
         if (lim >= EQN_NEST_MAX) {          ep->start = ep->end;
                 mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,          quoted = mode == MODE_QUOTED;
                     ep->eqn.ln, ep->eqn.pos, NULL);          for (;;) {
                 return NULL;                  switch (*ep->start) {
         }                  case '\0':
                           ep->toksz = 0;
         ep->cur = ep->rew;                          return EQN_TOK_EOF;
         start = &ep->data[(int)ep->cur];                  case '"':
         q = 0;                          quoted = 1;
                           break;
         if ('\0' == *start)                  default:
                 return NULL;                          break;
                   }
         if (quote == *start) {                  if (quoted) {
                 ep->cur++;                          ep->end = strchr(ep->start + 1, *ep->start);
                 q = 1;                          ep->start++;  /* Skip opening quote. */
         }                          if (ep->end == NULL) {
                                   mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
         start = &ep->data[(int)ep->cur];                                      ep->eqn.ln, ep->eqn.pos, NULL);
                                   ep->end = strchr(ep->start, '\0');
         if ( ! q) {                          }
                 if ('{' == *start || '}' == *start)                  } else {
                         ssz = 1;                          ep->end = ep->start + 1;
                 else                          if (*ep->start != '{' && *ep->start != '}')
                         ssz = strcspn(start + 1, " ^~\"{}\t") + 1;                                  ep->end += strcspn(ep->end, " ^~\"{}\t");
                 next = start + (int)ssz;                  }
                 if ('\0' == *next)                  ep->toksz = ep->end - ep->start;
                         next = NULL;                  if (quoted && *ep->end != '\0')
         } else                          ep->end++;  /* Skip closing quote. */
                 next = strchr(start, quote);                  while (*ep->end != '\0' && strchr(" \t^~", *ep->end) != NULL)
                           ep->end++;
         if (NULL != next) {                  if (quoted)  /* Cannot return, may have to strndup. */
                 *sz = (size_t)(next - start);                          break;
                 ep->cur += *sz;                  if (mode == MODE_NOSUB)
                 if (q)                          return EQN_TOK__MAX;
                         ep->cur++;                  if ((def = eqn_def_find(ep)) == NULL)
                 while (' ' == ep->data[(int)ep->cur] ||                          break;
                     '\t' == ep->data[(int)ep->cur] ||                  if (++lim > EQN_NEST_MAX) {
                     '^' == ep->data[(int)ep->cur] ||                          mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
                     '~' == ep->data[(int)ep->cur])  
                         ep->cur++;  
         } else {  
                 if (q)  
                         mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,  
                             ep->eqn.ln, ep->eqn.pos, NULL);                              ep->eqn.ln, ep->eqn.pos, NULL);
                 next = strchr(start, '\0');                          return EQN_TOK_EOF;
                 *sz = (size_t)(next - start);                  }
                 ep->cur += *sz;  
         }  
   
         /* Quotes aren't expanded for values. */                  /* Replace a defined name with its string value. */
                   if ((diff = def->valsz - ep->toksz) > 0) {
         if (q || ! repl)                          start = ep->start - ep->data;
                 return start;  
   
         if (NULL != (def = eqn_def_find(ep, start, *sz))) {  
                 diff = def->valsz - *sz;  
   
                 if (def->valsz > *sz) {  
                         ep->sz += diff;                          ep->sz += diff;
                         ep->data = mandoc_realloc(ep->data, ep->sz + 1);                          ep->data = mandoc_realloc(ep->data, ep->sz + 1);
                         ep->data[ep->sz] = '\0';                          ep->start = ep->data + start;
                         start = &ep->data[(int)ep->rew];  
                 }                  }
                   if (diff)
                 diff = def->valsz - *sz;                          memmove(ep->start + def->valsz, ep->start + ep->toksz,
                 memmove(start + *sz + diff, start + *sz,                              strlen(ep->start + ep->toksz) + 1);
                     (strlen(start) - *sz) + 1);                  memcpy(ep->start, def->val, def->valsz);
                 memcpy(start, def->val, def->valsz);                  last_len = ep->start - ep->data + def->valsz;
                 last_len = start - ep->data + def->valsz;  
                 lim++;  
                 goto again;  
         }          }
           if (mode != MODE_TOK)
         return start;                  return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;
 }  
   
 /*  
  * Get the next delimited token using the default current quote  
  * character.  
  */  
 static const char *  
 eqn_nexttok(struct eqn_node *ep, size_t *sz)  
 {  
   
         return eqn_next(ep, '"', sz, 1);  
 }  
   
 /*  
  * Get next token without replacement.  
  */  
 static const char *  
 eqn_nextrawtok(struct eqn_node *ep, size_t *sz)  
 {  
   
         return eqn_next(ep, '"', sz, 0);  
 }  
   
 /*  
  * Parse a token from the stream of text.  
  * A token consists of one of the recognised eqn(7) strings.  
  * Strings are separated by delimiting marks.  
  * This returns EQN_TOK_EOF when there are no more tokens.  
  * If the token is an unrecognised string literal, then it returns  
  * EQN_TOK__MAX and sets the "p" pointer to an allocated, nil-terminated  
  * string.  
  * This must be later freed with free(3).  
  */  
 static enum eqn_tok  
 eqn_tok_parse(struct eqn_node *ep, char **p)  
 {  
         const char      *start;  
         size_t           i, sz;  
         int              quoted;  
   
         if (p != NULL)  
                 *p = NULL;  
   
         quoted = ep->data[ep->cur] == '"';  
   
         if ((start = eqn_nexttok(ep, &sz)) == NULL)  
                 return EQN_TOK_EOF;  
   
         if (quoted) {          if (quoted) {
                 if (p != NULL)                  ep->start = mandoc_strndup(ep->start, ep->toksz);
                         *p = mandoc_strndup(start, sz);  
                 return EQN_TOK_QUOTED;                  return EQN_TOK_QUOTED;
         }          }
           for (tok = 0; tok < EQN_TOK__MAX; tok++)
                   if (STRNEQ(ep->start, ep->toksz,
                       eqn_toks[tok], strlen(eqn_toks[tok])))
                           return tok;
   
         for (i = 0; i < EQN_TOK__MAX; i++)  
                 if (STRNEQ(start, sz, eqn_toks[i], strlen(eqn_toks[i])))  
                         return i;  
   
         for (i = 0; i < EQNSYM__MAX; i++) {          for (i = 0; i < EQNSYM__MAX; i++) {
                 if (STRNEQ(start, sz,                  if (STRNEQ(ep->start, ep->toksz,
                     eqnsyms[i].str, strlen(eqnsyms[i].str))) {                      eqnsyms[i].str, strlen(eqnsyms[i].str))) {
                         mandoc_asprintf(p, "\\[%s]", eqnsyms[i].sym);                          mandoc_asprintf(&ep->start,
                               "\\[%s]", eqnsyms[i].sym);
                         return EQN_TOK_SYM;                          return EQN_TOK_SYM;
                 }                  }
         }          }
           ep->start = mandoc_strndup(ep->start, ep->toksz);
         if (p != NULL)          for (i = 0; i < (int)(sizeof(eqn_func)/sizeof(*eqn_func)); i++)
                 *p = mandoc_strndup(start, sz);                  if (STRNEQ(ep->start, ep->toksz,
                       eqn_func[i], strlen(eqn_func[i])))
         for (i = 0; i < sizeof(eqn_func)/sizeof(*eqn_func); i++)  
                 if (STRNEQ(start, sz, eqn_func[i], strlen(eqn_func[i])))  
                         return EQN_TOK_FUNC;                          return EQN_TOK_FUNC;
   
         return EQN_TOK__MAX;          return EQN_TOK__MAX;
 }  }
   
Line 622  eqn_box_makebinary(struct eqn_node *ep,
Line 570  eqn_box_makebinary(struct eqn_node *ep,
 static void  static void
 eqn_delim(struct eqn_node *ep)  eqn_delim(struct eqn_node *ep)
 {  {
         const char      *start;          if (ep->end[0] == '\0' || ep->end[1] == '\0') {
         size_t           sz;  
   
         if ((start = eqn_nextrawtok(ep, &sz)) == NULL)  
                 mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                  mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                     ep->eqn.ln, ep->eqn.pos, "delim");                      ep->eqn.ln, ep->eqn.pos, "delim");
         else if (strncmp(start, "off", 3) == 0)                  if (ep->end[0] != '\0')
                           ep->end++;
           } else if (strncmp(ep->end, "off", 3) == 0) {
                 ep->delim = 0;                  ep->delim = 0;
         else if (strncmp(start, "on", 2) == 0) {                  ep->end += 3;
           } else if (strncmp(ep->end, "on", 2) == 0) {
                 if (ep->odelim && ep->cdelim)                  if (ep->odelim && ep->cdelim)
                         ep->delim = 1;                          ep->delim = 1;
         } else if (start[1] != '\0') {                  ep->end += 2;
                 ep->odelim = start[0];          } else {
                 ep->cdelim = start[1];                  ep->odelim = *ep->end++;
                   ep->cdelim = *ep->end++;
                 ep->delim = 1;                  ep->delim = 1;
         }          }
 }  }
Line 646  eqn_delim(struct eqn_node *ep)
Line 595  eqn_delim(struct eqn_node *ep)
 static void  static void
 eqn_undef(struct eqn_node *ep)  eqn_undef(struct eqn_node *ep)
 {  {
         const char      *start;  
         struct eqn_def  *def;          struct eqn_def  *def;
         size_t           sz;  
   
         if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {          if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
                 mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                  mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                     ep->eqn.ln, ep->eqn.pos, "undef");                      ep->eqn.ln, ep->eqn.pos, "undef");
                 return;                  return;
         }          }
         if ((def = eqn_def_find(ep, start, sz)) == NULL)          if ((def = eqn_def_find(ep)) == NULL)
                 return;                  return;
         free(def->key);          free(def->key);
         free(def->val);          free(def->val);
Line 666  eqn_undef(struct eqn_node *ep)
Line 613  eqn_undef(struct eqn_node *ep)
 static void  static void
 eqn_def(struct eqn_node *ep)  eqn_def(struct eqn_node *ep)
 {  {
         const char      *start;  
         size_t           sz;  
         struct eqn_def  *def;          struct eqn_def  *def;
         int              i;          int              i;
   
         if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {          if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
                 mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                  mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                     ep->eqn.ln, ep->eqn.pos, "define");                      ep->eqn.ln, ep->eqn.pos, "define");
                 return;                  return;
Line 681  eqn_def(struct eqn_node *ep)
Line 626  eqn_def(struct eqn_node *ep)
          * Search for a key that already exists.           * Search for a key that already exists.
          * Create a new key if none is found.           * Create a new key if none is found.
          */           */
         if (NULL == (def = eqn_def_find(ep, start, sz))) {          if ((def = eqn_def_find(ep)) == NULL) {
                 /* Find holes in string array. */                  /* Find holes in string array. */
                 for (i = 0; i < (int)ep->defsz; i++)                  for (i = 0; i < (int)ep->defsz; i++)
                         if (0 == ep->defs[i].keysz)                          if (0 == ep->defs[i].keysz)
Line 696  eqn_def(struct eqn_node *ep)
Line 641  eqn_def(struct eqn_node *ep)
   
                 def = ep->defs + i;                  def = ep->defs + i;
                 free(def->key);                  free(def->key);
                 def->key = mandoc_strndup(start, sz);                  def->key = mandoc_strndup(ep->start, ep->toksz);
                 def->keysz = sz;                  def->keysz = ep->toksz;
         }          }
   
         start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);          if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
         if (start == NULL) {  
                 mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,                  mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
                     ep->eqn.ln, ep->eqn.pos, "define %s", def->key);                      ep->eqn.ln, ep->eqn.pos, "define %s", def->key);
                 free(def->key);                  free(def->key);
Line 711  eqn_def(struct eqn_node *ep)
Line 655  eqn_def(struct eqn_node *ep)
                 return;                  return;
         }          }
         free(def->val);          free(def->val);
         def->val = mandoc_strndup(start, sz);          def->val = mandoc_strndup(ep->start, ep->toksz);
         def->valsz = sz;          def->valsz = ep->toksz;
 }  }
   
 /*  /*
Line 721  eqn_def(struct eqn_node *ep)
Line 665  eqn_def(struct eqn_node *ep)
 static enum rofferr  static enum rofferr
 eqn_parse(struct eqn_node *ep, struct eqn_box *parent)  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
 {  {
         char             sym[64];  
         struct eqn_box  *cur, *nbox, *split;          struct eqn_box  *cur, *nbox, *split;
         const char      *cp, *cpn, *start;          const char      *cp, *cpn;
         char            *p;          char            *p;
         size_t           sz;          enum eqn_tok     tok;
         enum eqn_tok     tok, subtok;  
         enum eqn_post    pos;          enum eqn_post    pos;
         enum { CCL_LET, CCL_DIG, CCL_PUN } ccl, ccln;          enum { CCL_LET, CCL_DIG, CCL_PUN } ccl, ccln;
         int              size;          int              size;
Line 741  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
Line 683  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
         if (ep->data == NULL)          if (ep->data == NULL)
                 return ROFF_IGN;                  return ROFF_IGN;
   
 next_tok:          ep->start = ep->end = ep->data;
         tok = eqn_tok_parse(ep, &p);  
   
 this_tok:  next_tok:
           tok = eqn_next(ep, MODE_TOK);
         switch (tok) {          switch (tok) {
         case EQN_TOK_UNDEF:          case EQN_TOK_UNDEF:
                 eqn_undef(ep);                  eqn_undef(ep);
Line 754  this_tok:
Line 696  this_tok:
                 eqn_def(ep);                  eqn_def(ep);
                 break;                  break;
         case EQN_TOK_TDEFINE:          case EQN_TOK_TDEFINE:
                 if (eqn_nextrawtok(ep, NULL) == NULL ||                  if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
                     eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL)                      eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, "tdefine");                              ep->eqn.ln, ep->eqn.pos, "tdefine");
                 break;                  break;
Line 763  this_tok:
Line 705  this_tok:
                 eqn_delim(ep);                  eqn_delim(ep);
                 break;                  break;
         case EQN_TOK_GFONT:          case EQN_TOK_GFONT:
                 if (eqn_nextrawtok(ep, NULL) == NULL)                  if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                 break;                  break;
Line 792  this_tok:
Line 734  this_tok:
                 parent->font = EQNFONT_ROMAN;                  parent->font = EQNFONT_ROMAN;
                 switch (tok) {                  switch (tok) {
                 case EQN_TOK_DOTDOT:                  case EQN_TOK_DOTDOT:
                         strlcpy(sym, "\\[ad]", sizeof(sym));                          parent->top = mandoc_strdup("\\[ad]");
                         break;                          break;
                 case EQN_TOK_VEC:                  case EQN_TOK_VEC:
                         strlcpy(sym, "\\[->]", sizeof(sym));                          parent->top = mandoc_strdup("\\[->]");
                         break;                          break;
                 case EQN_TOK_DYAD:                  case EQN_TOK_DYAD:
                         strlcpy(sym, "\\[<>]", sizeof(sym));                          parent->top = mandoc_strdup("\\[<>]");
                         break;                          break;
                 case EQN_TOK_TILDE:                  case EQN_TOK_TILDE:
                         strlcpy(sym, "\\[a~]", sizeof(sym));                          parent->top = mandoc_strdup("\\[a~]");
                         break;                          break;
                 case EQN_TOK_UNDER:                  case EQN_TOK_UNDER:
                         strlcpy(sym, "\\[ul]", sizeof(sym));                          parent->bottom = mandoc_strdup("\\[ul]");
                         break;                          break;
                 case EQN_TOK_BAR:                  case EQN_TOK_BAR:
                         strlcpy(sym, "\\[rl]", sizeof(sym));                          parent->top = mandoc_strdup("\\[rl]");
                         break;                          break;
                 case EQN_TOK_DOT:                  case EQN_TOK_DOT:
                         strlcpy(sym, "\\[a.]", sizeof(sym));                          parent->top = mandoc_strdup("\\[a.]");
                         break;                          break;
                 case EQN_TOK_HAT:                  case EQN_TOK_HAT:
                         strlcpy(sym, "\\[ha]", sizeof(sym));                          parent->top = mandoc_strdup("\\[ha]");
                         break;                          break;
                 default:                  default:
                         abort();                          abort();
                 }                  }
   
                 switch (tok) {  
                 case EQN_TOK_DOTDOT:  
                 case EQN_TOK_VEC:  
                 case EQN_TOK_DYAD:  
                 case EQN_TOK_TILDE:  
                 case EQN_TOK_BAR:  
                 case EQN_TOK_DOT:  
                 case EQN_TOK_HAT:  
                         parent->top = mandoc_strdup(sym);  
                         break;  
                 case EQN_TOK_UNDER:  
                         parent->bottom = mandoc_strdup(sym);  
                         break;  
                 default:  
                         abort();  
                 }  
                 parent = parent->parent;                  parent = parent->parent;
                 break;                  break;
         case EQN_TOK_FWD:          case EQN_TOK_FWD:
         case EQN_TOK_BACK:          case EQN_TOK_BACK:
         case EQN_TOK_DOWN:          case EQN_TOK_DOWN:
         case EQN_TOK_UP:          case EQN_TOK_UP:
                 subtok = eqn_tok_parse(ep, NULL);                  if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
                 if (subtok != EQN_TOK__MAX) {  
                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                         tok = subtok;  
                         goto this_tok;  
                 }  
                 break;                  break;
         case EQN_TOK_FAT:          case EQN_TOK_FAT:
         case EQN_TOK_ROMAN:          case EQN_TOK_ROMAN:
Line 883  this_tok:
Line 804  this_tok:
         case EQN_TOK_SIZE:          case EQN_TOK_SIZE:
         case EQN_TOK_GSIZE:          case EQN_TOK_GSIZE:
                 /* Accept two values: integral size and a single. */                  /* Accept two values: integral size and a single. */
                 if (NULL == (start = eqn_nexttok(ep, &sz))) {                  if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 size = mandoc_strntoi(start, sz, 10);                  size = mandoc_strntoi(ep->start, ep->toksz, 10);
                 if (-1 == size) {                  if (-1 == size) {
                         mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,                          mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
Line 997  this_tok:
Line 918  this_tok:
                 }                  }
                 parent = cur;                  parent = cur;
                 if (EQN_TOK_RIGHT == tok) {                  if (EQN_TOK_RIGHT == tok) {
                         if (NULL == (start = eqn_nexttok(ep, &sz))) {                          if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
                                 mandoc_msg(MANDOCERR_REQ_EMPTY,                                  mandoc_msg(MANDOCERR_REQ_EMPTY,
                                     ep->parse, ep->eqn.ln,                                      ep->parse, ep->eqn.ln,
                                     ep->eqn.pos, eqn_toks[tok]);                                      ep->eqn.pos, eqn_toks[tok]);
                                 break;                                  break;
                         }                          }
                         /* Handling depends on right/left. */                          /* Handling depends on right/left. */
                         if (STRNEQ(start, sz, "ceiling", 7)) {                          if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
                                 strlcpy(sym, "\\[rc]", sizeof(sym));                                  parent->right = mandoc_strdup("\\[rc]");
                                 parent->right = mandoc_strdup(sym);                          else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
                         } else if (STRNEQ(start, sz, "floor", 5)) {                                  parent->right = mandoc_strdup("\\[rf]");
                                 strlcpy(sym, "\\[rf]", sizeof(sym));                          else
                                 parent->right = mandoc_strdup(sym);                                  parent->right =
                         } else                                      mandoc_strndup(ep->start, ep->toksz);
                                 parent->right = mandoc_strndup(start, sz);  
                 }                  }
                 parent = parent->parent;                  parent = parent->parent;
                 if (tok == EQN_TOK_BRACE_CLOSE &&                  if (tok == EQN_TOK_BRACE_CLOSE &&
Line 1033  this_tok:
Line 953  this_tok:
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         parent = parent->parent;                          parent = parent->parent;
                 if (EQN_TOK_LEFT == tok &&                  if (EQN_TOK_LEFT == tok &&
                     (start = eqn_nexttok(ep, &sz)) == NULL) {                      eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                         break;                          break;
Line 1041  this_tok:
Line 961  this_tok:
                 parent = eqn_box_alloc(ep, parent);                  parent = eqn_box_alloc(ep, parent);
                 parent->type = EQN_LIST;                  parent->type = EQN_LIST;
                 if (EQN_TOK_LEFT == tok) {                  if (EQN_TOK_LEFT == tok) {
                         if (STRNEQ(start, sz, "ceiling", 7)) {                          if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
                                 strlcpy(sym, "\\[lc]", sizeof(sym));                                  parent->left = mandoc_strdup("\\[lc]");
                                 parent->left = mandoc_strdup(sym);                          else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
                         } else if (STRNEQ(start, sz, "floor", 5)) {                                  parent->left = mandoc_strdup("\\[lf]");
                                 strlcpy(sym, "\\[lf]", sizeof(sym));                          else
                                 parent->left = mandoc_strdup(sym);                                  parent->left =
                         } else                                      mandoc_strndup(ep->start, ep->toksz);
                                 parent->left = mandoc_strndup(start, sz);  
                 }                  }
                 break;                  break;
         case EQN_TOK_PILE:          case EQN_TOK_PILE:
Line 1093  this_tok:
Line 1012  this_tok:
         case EQN_TOK_FUNC:          case EQN_TOK_FUNC:
         case EQN_TOK_QUOTED:          case EQN_TOK_QUOTED:
         case EQN_TOK_SYM:          case EQN_TOK_SYM:
                   p = ep->start;
                 assert(p != NULL);                  assert(p != NULL);
                 /*                  /*
                  * If we already have something in the stack and we're                   * If we already have something in the stack and we're

Legend:
Removed from v.1.70  
changed lines
  Added in v.1.71

CVSweb