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

Diff for /mandoc/eqn.c between version 1.64 and 1.73

version 1.64, 2017/06/21 18:04:34 version 1.73, 2017/07/05 15:03:27
Line 20 
Line 20 
 #include <sys/types.h>  #include <sys/types.h>
   
 #include <assert.h>  #include <assert.h>
   #include <ctype.h>
 #include <limits.h>  #include <limits.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
Line 83  enum eqn_tok {
Line 84  enum eqn_tok {
         EQN_TOK_ABOVE,          EQN_TOK_ABOVE,
         EQN_TOK__MAX,          EQN_TOK__MAX,
         EQN_TOK_FUNC,          EQN_TOK_FUNC,
           EQN_TOK_QUOTED,
           EQN_TOK_SYM,
         EQN_TOK_EOF          EQN_TOK_EOF
 };  };
   
Line 142  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 273  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 353  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__MAX;  
         }          }
           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++)          for (i = 0; i < EQNSYM__MAX; i++) {
                 if (STRNEQ(start, sz, eqn_toks[i], strlen(eqn_toks[i])))                  if (STRNEQ(ep->start, ep->toksz,
                         return i;                      eqnsyms[i].str, strlen(eqnsyms[i].str))) {
                           mandoc_asprintf(&ep->start,
         if (p != NULL)                              "\\[%s]", eqnsyms[i].sym);
                 *p = mandoc_strndup(start, sz);                          return EQN_TOK_SYM;
                   }
         for (i = 0; i < sizeof(eqn_func)/sizeof(*eqn_func); i++)          }
                 if (STRNEQ(start, sz, eqn_func[i], strlen(eqn_func[i])))          ep->start = mandoc_strndup(ep->start, ep->toksz);
           for (i = 0; i < (int)(sizeof(eqn_func)/sizeof(*eqn_func)); i++)
                   if (STRNEQ(ep->start, ep->toksz,
                       eqn_func[i], strlen(eqn_func[i])))
                         return EQN_TOK_FUNC;                          return EQN_TOK_FUNC;
   
         return EQN_TOK__MAX;          return EQN_TOK__MAX;
 }  }
   
Line 562  eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par
Line 521  eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par
         bp->parent = parent;          bp->parent = parent;
         bp->parent->args++;          bp->parent->args++;
         bp->expectargs = UINT_MAX;          bp->expectargs = UINT_MAX;
           bp->font = bp->parent->font;
         bp->size = ep->gsize;          bp->size = ep->gsize;
   
         if (NULL != parent->first) {          if (NULL != parent->first) {
Line 610  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 634  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 654  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 669  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 684  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 699  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 709  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;          const char      *cp, *cpn;
         const char      *start;  
         char            *p;          char            *p;
         size_t           i, 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;
         int              size;          int              size;
   
         assert(parent != NULL);          assert(parent != NULL);
Line 728  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 + strspn(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 741  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 750  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 774  this_tok:
Line 729  this_tok:
                         cur->text = mandoc_strdup("");                          cur->text = mandoc_strdup("");
                 }                  }
                 parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);                  parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);
                 parent->type = EQN_LISTONE;                  parent->type = EQN_LIST;
                 parent->expectargs = 1;                  parent->expectargs = 1;
                   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 847  this_tok:
Line 782  this_tok:
                  * exactly one of those.                   * exactly one of those.
                  */                   */
                 parent = eqn_box_alloc(ep, parent);                  parent = eqn_box_alloc(ep, parent);
                 parent->type = EQN_LISTONE;                  parent->type = EQN_LIST;
                 parent->expectargs = 1;                  parent->expectargs = 1;
                 switch (tok) {                  switch (tok) {
                 case EQN_TOK_FAT:                  case EQN_TOK_FAT:
Line 869  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 885  this_tok:
Line 820  this_tok:
                         break;                          break;
                 }                  }
                 parent = eqn_box_alloc(ep, parent);                  parent = eqn_box_alloc(ep, parent);
                 parent->type = EQN_LISTONE;                  parent->type = EQN_LIST;
                 parent->expectargs = 1;                  parent->expectargs = 1;
                 parent->size = size;                  parent->size = size;
                 break;                  break;
Line 973  this_tok:
Line 908  this_tok:
                  */                   */
                 for (cur = parent; cur != NULL; cur = cur->parent)                  for (cur = parent; cur != NULL; cur = cur->parent)
                         if (cur->type == EQN_LIST &&                          if (cur->type == EQN_LIST &&
                               cur->expectargs > 1 &&
                             (tok == EQN_TOK_BRACE_CLOSE ||                              (tok == EQN_TOK_BRACE_CLOSE ||
                              cur->left != NULL))                               cur->left != NULL))
                                 break;                                  break;
Line 983  this_tok:
Line 919  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 1005  this_tok:
Line 940  this_tok:
                      parent->type == EQN_MATRIX))                       parent->type == EQN_MATRIX))
                         parent = parent->parent;                          parent = parent->parent;
                 /* Close out any "singleton" lists. */                  /* Close out any "singleton" lists. */
                 while (parent->type == EQN_LISTONE &&                  while (parent->type == EQN_LIST &&
                     parent->args == parent->expectargs)                      parent->expectargs == 1 &&
                       parent->args == 1)
                         parent = parent->parent;                          parent = parent->parent;
                 break;                  break;
         case EQN_TOK_BRACE_OPEN:          case EQN_TOK_BRACE_OPEN:
Line 1019  this_tok:
Line 955  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 1027  this_tok:
Line 963  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 1075  this_tok:
Line 1010  this_tok:
                  * TODO: make sure we're not in an open subexpression.                   * TODO: make sure we're not in an open subexpression.
                  */                   */
                 return ROFF_EQN;                  return ROFF_EQN;
         case EQN_TOK_FUNC:  
         case EQN_TOK__MAX:          case EQN_TOK__MAX:
           case EQN_TOK_FUNC:
           case EQN_TOK_QUOTED:
           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
Line 1084  this_tok:
Line 1022  this_tok:
                  */                   */
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         parent = parent->parent;                          parent = parent->parent;
                 if (tok == EQN_TOK_FUNC) {  
                         for (cur = parent; cur != NULL; cur = cur->parent)  
                                 if (cur->font != EQNFONT_NONE)  
                                         break;  
                         if (cur == NULL || cur->font != EQNFONT_ROMAN) {  
                                 parent = eqn_box_alloc(ep, parent);  
                                 parent->type = EQN_LISTONE;  
                                 parent->font = EQNFONT_ROMAN;  
                                 parent->expectargs = 1;  
                         }  
                 }  
                 cur = eqn_box_alloc(ep, parent);                  cur = eqn_box_alloc(ep, parent);
                 cur->type = EQN_TEXT;                  cur->type = EQN_TEXT;
                 for (i = 0; i < EQNSYM__MAX; i++)                  cur->text = p;
                         if (0 == strcmp(eqnsyms[i].str, p)) {                  switch (tok) {
                                 (void)snprintf(sym, sizeof(sym),                  case EQN_TOK_FUNC:
                                         "\\[%s]", eqnsyms[i].sym);                          cur->font = EQNFONT_ROMAN;
                                 cur->text = mandoc_strdup(sym);                          break;
                                 free(p);                  case EQN_TOK_QUOTED:
                           if (cur->font == EQNFONT_NONE)
                                   cur->font = EQNFONT_ITALIC;
                           break;
                   case EQN_TOK_SYM:
                           break;
                   default:
                           if (cur->font != EQNFONT_NONE || *p == '\0')
                                 break;                                  break;
                           cpn = p - 1;
                           ccln = CCL_LET;
                           split = NULL;
                           for (;;) {
                                   /* Advance to next character. */
                                   cp = cpn++;
                                   ccl = ccln;
                                   ccln = isalpha((unsigned char)*cpn) ? CCL_LET :
                                       isdigit((unsigned char)*cpn) ||
                                       (*cpn == '.' && (ccl == CCL_DIG ||
                                        isdigit((unsigned char)cpn[1]))) ?
                                       CCL_DIG : CCL_PUN;
                                   /* No boundary before first character. */
                                   if (cp < p)
                                           continue;
                                   cur->font = ccl == CCL_LET ?
                                       EQNFONT_ITALIC : EQNFONT_ROMAN;
                                   if (*cp == '\\')
                                           mandoc_escape(&cpn, NULL, NULL);
                                   /* No boundary after last character. */
                                   if (*cpn == '\0')
                                           break;
                                   if (ccln == ccl)
                                           continue;
                                   /* Boundary found, split the text. */
                                   if (parent->args == parent->expectargs) {
                                           /* Remove the text from the tree. */
                                           if (cur->prev == NULL)
                                                   parent->first = cur->next;
                                           else
                                                   cur->prev->next = NULL;
                                           parent->last = cur->prev;
                                           parent->args--;
                                           /* Set up a list instead. */
                                           split = eqn_box_alloc(ep, parent);
                                           split->type = EQN_LIST;
                                           /* Insert the word into the list. */
                                           split->first = split->last = cur;
                                           cur->parent = split;
                                           cur->prev = NULL;
                                           parent = split;
                                   }
                                   /* Append a new text box. */
                                   nbox = eqn_box_alloc(ep, parent);
                                   nbox->type = EQN_TEXT;
                                   nbox->text = mandoc_strdup(cpn);
                                   /* Truncate the old box. */
                                   p = mandoc_strndup(cur->text,
                                       cpn - cur->text);
                                   free(cur->text);
                                   cur->text = p;
                                   /* Setup to process the new box. */
                                   cur = nbox;
                                   p = nbox->text;
                                   cpn = p - 1;
                                   ccln = CCL_LET;
                         }                          }
                           if (split != NULL)
                 if (i == EQNSYM__MAX)                                  parent = split->parent;
                         cur->text = p;                          break;
                   }
                 /*                  /*
                  * Post-process list status.                   * Post-process list status.
                  */                   */
                 while (parent->type == EQN_LISTONE &&                  while (parent->type == EQN_LIST &&
                     parent->args == parent->expectargs)                      parent->expectargs == 1 &&
                       parent->args == 1)
                         parent = parent->parent;                          parent = parent->parent;
                 break;                  break;
         default:          default:

Legend:
Removed from v.1.64  
changed lines
  Added in v.1.73

CVSweb