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

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

version 1.71, 2017/06/26 20:09:04 version 1.78, 2017/07/15 16:26:17
Line 27 
Line 27 
 #include <string.h>  #include <string.h>
 #include <time.h>  #include <time.h>
   
 #include "mandoc.h"  
 #include "mandoc_aux.h"  #include "mandoc_aux.h"
   #include "mandoc.h"
   #include "roff.h"
 #include "libmandoc.h"  #include "libmandoc.h"
 #include "libroff.h"  #include "libroff.h"
   
Line 284  enum parse_mode {
Line 285  enum parse_mode {
 };  };
   
 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  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 *);                                  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 *);  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  enum eqn_tok     eqn_next(struct eqn_node *, enum parse_mode);  static  enum eqn_tok     eqn_next(struct eqn_node *, enum parse_mode);
 static  enum rofferr     eqn_parse(struct eqn_node *, struct eqn_box *);  
 static  void             eqn_undef(struct eqn_node *);  static  void             eqn_undef(struct eqn_node *);
   
   
 enum rofferr  struct eqn_node *
 eqn_read(struct eqn_node **epp, int ln,  eqn_alloc(struct mparse *parse)
                 const char *p, int pos, int *offs)  
 {  {
         size_t           sz;          struct eqn_node *ep;
         struct eqn_node *ep;  
         enum rofferr     er;  
   
         ep = *epp;          ep = mandoc_calloc(1, sizeof(*ep));
           ep->parse = parse;
           ep->gsize = EQN_DEFSIZE;
           return ep;
   }
   
         /*  void
          * If we're the terminating mark, unset our equation status and  eqn_reset(struct eqn_node *ep)
          * validate the full equation.  {
          */          free(ep->data);
           ep->data = ep->start = ep->end = NULL;
         if (0 == strncmp(p, ".EN", 3)) {          ep->sz = ep->toksz = 0;
                 er = eqn_end(epp);  
                 p += 3;  
                 while (' ' == *p || '\t' == *p)  
                         p++;  
                 if ('\0' == *p)  
                         return er;  
                 mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,  
                     ln, pos, "EN %s", p);  
                 return er;  
         }  
   
         /*  
          * Build up the full string, replacing all newlines with regular  
          * whitespace.  
          */  
   
         sz = strlen(p + pos) + 1;  
         ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);  
   
         /* First invocation: nil terminate the string. */  
   
         if (0 == ep->sz)  
                 *ep->data = '\0';  
   
         ep->sz += sz;  
         strlcat(ep->data, p + pos, ep->sz + 1);  
         strlcat(ep->data, " ", ep->sz + 1);  
         return ROFF_IGN;  
 }  }
   
 struct eqn_node *  void
 eqn_alloc(int pos, int line, struct mparse *parse)  eqn_read(struct eqn_node *ep, const char *p)
 {  {
         struct eqn_node *p;          char            *cp;
   
         p = mandoc_calloc(1, sizeof(struct eqn_node));          if (ep->data == NULL) {
                   ep->sz = strlen(p);
         p->parse = parse;                  ep->data = mandoc_strdup(p);
         p->eqn.ln = line;          } else {
         p->eqn.pos = pos;                  ep->sz = mandoc_asprintf(&cp, "%s %s", ep->data, p);
         p->gsize = EQN_DEFSIZE;                  free(ep->data);
                   ep->data = cp;
         return p;          }
           ep->sz += 1;
 }  }
   
 /*  /*
Line 427  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 400  eqn_next(struct eqn_node *ep, enum parse_mode mode)
                         ep->start++;  /* Skip opening quote. */                          ep->start++;  /* Skip opening quote. */
                         if (ep->end == NULL) {                          if (ep->end == NULL) {
                                 mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,                                  mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
                                     ep->eqn.ln, ep->eqn.pos, NULL);                                      ep->node->line, ep->node->pos, NULL);
                                 ep->end = strchr(ep->start, '\0');                                  ep->end = strchr(ep->start, '\0');
                         }                          }
                 } else {                  } else {
Line 448  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 421  eqn_next(struct eqn_node *ep, enum parse_mode mode)
                         break;                          break;
                 if (++lim > EQN_NEST_MAX) {                  if (++lim > EQN_NEST_MAX) {
                         mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,                          mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, NULL);                              ep->node->line, ep->node->pos, NULL);
                         return EQN_TOK_EOF;                          return EQN_TOK_EOF;
                 }                  }
   
Line 492  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 465  eqn_next(struct eqn_node *ep, enum parse_mode mode)
         return EQN_TOK__MAX;          return EQN_TOK__MAX;
 }  }
   
 static void  void
 eqn_box_free(struct eqn_box *bp)  eqn_box_free(struct eqn_box *bp)
 {  {
   
Line 541  eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par
Line 514  eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par
  * The new EQN_SUBEXPR will have a two-child limit.   * The new EQN_SUBEXPR will have a two-child limit.
  */   */
 static struct eqn_box *  static struct eqn_box *
 eqn_box_makebinary(struct eqn_node *ep,  eqn_box_makebinary(struct eqn_node *ep, struct eqn_box *parent)
         enum eqn_post pos, struct eqn_box *parent)  
 {  {
         struct eqn_box  *b, *newb;          struct eqn_box  *b, *newb;
   
Line 554  eqn_box_makebinary(struct eqn_node *ep,
Line 526  eqn_box_makebinary(struct eqn_node *ep,
         parent->last = b->prev;          parent->last = b->prev;
         b->prev = NULL;          b->prev = NULL;
         newb = eqn_box_alloc(ep, parent);          newb = eqn_box_alloc(ep, parent);
         newb->pos = pos;  
         newb->type = EQN_SUBEXPR;          newb->type = EQN_SUBEXPR;
         newb->expectargs = 2;          newb->expectargs = 2;
         newb->args = 1;          newb->args = 1;
Line 572  eqn_delim(struct eqn_node *ep)
Line 543  eqn_delim(struct eqn_node *ep)
 {  {
         if (ep->end[0] == '\0' || ep->end[1] == '\0') {          if (ep->end[0] == '\0' || ep->end[1] == '\0') {
                 mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,                  mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                     ep->eqn.ln, ep->eqn.pos, "delim");                      ep->node->line, ep->node->pos, "delim");
                 if (ep->end[0] != '\0')                  if (ep->end[0] != '\0')
                         ep->end++;                          ep->end++;
         } else if (strncmp(ep->end, "off", 3) == 0) {          } else if (strncmp(ep->end, "off", 3) == 0) {
Line 599  eqn_undef(struct eqn_node *ep)
Line 570  eqn_undef(struct eqn_node *ep)
   
         if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {          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->node->line, ep->node->pos, "undef");
                 return;                  return;
         }          }
         if ((def = eqn_def_find(ep)) == NULL)          if ((def = eqn_def_find(ep)) == NULL)
Line 618  eqn_def(struct eqn_node *ep)
Line 589  eqn_def(struct eqn_node *ep)
   
         if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {          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->node->line, ep->node->pos, "define");
                 return;                  return;
         }          }
   
Line 647  eqn_def(struct eqn_node *ep)
Line 618  eqn_def(struct eqn_node *ep)
   
         if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {          if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
                 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->node->line, ep->node->pos, "define %s", def->key);
                 free(def->key);                  free(def->key);
                 free(def->val);                  free(def->val);
                 def->key = def->val = NULL;                  def->key = def->val = NULL;
Line 659  eqn_def(struct eqn_node *ep)
Line 630  eqn_def(struct eqn_node *ep)
         def->valsz = ep->toksz;          def->valsz = ep->toksz;
 }  }
   
 /*  void
  * Recursively parse an eqn(7) expression.  eqn_parse(struct eqn_node *ep)
  */  
 static enum rofferr  
 eqn_parse(struct eqn_node *ep, struct eqn_box *parent)  
 {  {
         struct eqn_box  *cur, *nbox, *split;          struct eqn_box  *cur, *nbox, *parent, *split;
         const char      *cp, *cpn;          const char      *cp, *cpn;
         char            *p;          char            *p;
         enum eqn_tok     tok;          enum eqn_tok     tok;
         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;
   
           parent = ep->node->eqn;
         assert(parent != NULL);          assert(parent != NULL);
   
         /*          /*
Line 681  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
Line 649  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
          */           */
   
         if (ep->data == NULL)          if (ep->data == NULL)
                 return ROFF_IGN;                  return;
   
         ep->start = ep->end = ep->data;          ep->start = ep->end = ep->data + strspn(ep->data, " ^~");
   
 next_tok:  next_tok:
         tok = eqn_next(ep, MODE_TOK);          tok = eqn_next(ep, MODE_TOK);
Line 699  next_tok:
Line 667  next_tok:
                 if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||                  if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
                     eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)                      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->node->line, ep->node->pos, "tdefine");
                 break;                  break;
         case EQN_TOK_DELIM:          case EQN_TOK_DELIM:
                 eqn_delim(ep);                  eqn_delim(ep);
Line 707  next_tok:
Line 675  next_tok:
         case EQN_TOK_GFONT:          case EQN_TOK_GFONT:
                 if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)                  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->node->line, ep->node->pos, eqn_toks[tok]);
                 break;                  break;
         case EQN_TOK_MARK:          case EQN_TOK_MARK:
         case EQN_TOK_LINEUP:          case EQN_TOK_LINEUP:
Line 723  next_tok:
Line 691  next_tok:
         case EQN_TOK_DOTDOT:          case EQN_TOK_DOTDOT:
                 if (parent->last == NULL) {                  if (parent->last == NULL) {
                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->node->line, ep->node->pos, eqn_toks[tok]);
                         cur = eqn_box_alloc(ep, parent);                          cur = eqn_box_alloc(ep, parent);
                         cur->type = EQN_TEXT;                          cur->type = EQN_TEXT;
                         cur->text = mandoc_strdup("");                          cur->text = mandoc_strdup("");
                 }                  }
                 parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);                  parent = eqn_box_makebinary(ep, parent);
                 parent->type = EQN_LISTONE;                  parent->type = EQN_LIST;
                 parent->expectargs = 1;                  parent->expectargs = 1;
                 parent->font = EQNFONT_ROMAN;                  parent->font = EQNFONT_ROMAN;
                 switch (tok) {                  switch (tok) {
Line 749  next_tok:
Line 717  next_tok:
                         parent->bottom = mandoc_strdup("\\[ul]");                          parent->bottom = mandoc_strdup("\\[ul]");
                         break;                          break;
                 case EQN_TOK_BAR:                  case EQN_TOK_BAR:
                         parent->top = mandoc_strdup("\\[rl]");                          parent->top = mandoc_strdup("\\[rn]");
                         break;                          break;
                 case EQN_TOK_DOT:                  case EQN_TOK_DOT:
                         parent->top = mandoc_strdup("\\[a.]");                          parent->top = mandoc_strdup("\\[a.]");
Line 768  next_tok:
Line 736  next_tok:
         case EQN_TOK_UP:          case EQN_TOK_UP:
                 if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)                  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->node->line, ep->node->pos, eqn_toks[tok]);
                 break;                  break;
         case EQN_TOK_FAT:          case EQN_TOK_FAT:
         case EQN_TOK_ROMAN:          case EQN_TOK_ROMAN:
Line 782  next_tok:
Line 750  next_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 806  next_tok:
Line 774  next_tok:
                 /* Accept two values: integral size and a single. */                  /* Accept two values: integral size and a single. */
                 if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {                  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->node->line, ep->node->pos, eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 size = mandoc_strntoi(ep->start, ep->toksz, 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->node->line, ep->node->pos, eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 if (EQN_TOK_GSIZE == tok) {                  if (EQN_TOK_GSIZE == tok) {
                         ep->gsize = size;                          ep->gsize = size;
                         break;                          break;
                 }                  }
                   while (parent->args == parent->expectargs)
                           parent = parent->parent;
                 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 835  next_tok:
Line 805  next_tok:
                  */                   */
                 if (parent->last == NULL) {                  if (parent->last == NULL) {
                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->node->line, ep->node->pos, eqn_toks[tok]);
                         cur = eqn_box_alloc(ep, parent);                          cur = eqn_box_alloc(ep, parent);
                         cur->type = EQN_TEXT;                          cur->type = EQN_TEXT;
                         cur->text = mandoc_strdup("");                          cur->text = mandoc_strdup("");
                 }                  }
                 /* Handle the "subsup" and "fromto" positions. */                  while (parent->expectargs == 1 && parent->args == 1)
                 if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {                          parent = parent->parent;
                   if (tok == EQN_TOK_FROM || tok == EQN_TOK_TO)  {
                           for (cur = parent; cur != NULL; cur = cur->parent)
                                   if (cur->pos == EQNPOS_SUB ||
                                       cur->pos == EQNPOS_SUP ||
                                       cur->pos == EQNPOS_SUBSUP ||
                                       cur->pos == EQNPOS_SQRT ||
                                       cur->pos == EQNPOS_OVER)
                                           break;
                           if (cur != NULL)
                                   parent = cur->parent;
                   }
                   if (tok == EQN_TOK_SUP && parent->pos == EQNPOS_SUB) {
                         parent->expectargs = 3;                          parent->expectargs = 3;
                         parent->pos = EQNPOS_SUBSUP;                          parent->pos = EQNPOS_SUBSUP;
                         break;                          break;
                 }                  }
                 if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) {                  if (tok == EQN_TOK_TO && parent->pos == EQNPOS_FROM) {
                         parent->expectargs = 3;                          parent->expectargs = 3;
                         parent->pos = EQNPOS_FROMTO;                          parent->pos = EQNPOS_FROMTO;
                         break;                          break;
                 }                  }
                   parent = eqn_box_makebinary(ep, parent);
                 switch (tok) {                  switch (tok) {
                 case EQN_TOK_FROM:                  case EQN_TOK_FROM:
                         pos = EQNPOS_FROM;                          parent->pos = EQNPOS_FROM;
                         break;                          break;
                 case EQN_TOK_TO:                  case EQN_TOK_TO:
                         pos = EQNPOS_TO;                          parent->pos = EQNPOS_TO;
                         break;                          break;
                 case EQN_TOK_SUP:                  case EQN_TOK_SUP:
                         pos = EQNPOS_SUP;                          parent->pos = EQNPOS_SUP;
                         break;                          break;
                 case EQN_TOK_SUB:                  case EQN_TOK_SUB:
                         pos = EQNPOS_SUB;                          parent->pos = EQNPOS_SUB;
                         break;                          break;
                 default:                  default:
                         abort();                          abort();
                 }                  }
                 parent = eqn_box_makebinary(ep, pos, parent);  
                 break;                  break;
         case EQN_TOK_SQRT:          case EQN_TOK_SQRT:
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
Line 890  next_tok:
Line 872  next_tok:
                  */                   */
                 if (parent->last == NULL) {                  if (parent->last == NULL) {
                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->node->line, ep->node->pos, eqn_toks[tok]);
                         cur = eqn_box_alloc(ep, parent);                          cur = eqn_box_alloc(ep, parent);
                         cur->type = EQN_TEXT;                          cur->type = EQN_TEXT;
                         cur->text = mandoc_strdup("");                          cur->text = mandoc_strdup("");
                 }                  }
                   while (parent->args == parent->expectargs)
                           parent = parent->parent;
                 while (EQN_SUBEXPR == parent->type)                  while (EQN_SUBEXPR == parent->type)
                         parent = parent->parent;                          parent = parent->parent;
                 parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);                  parent = eqn_box_makebinary(ep, parent);
                   parent->pos = EQNPOS_OVER;
                 break;                  break;
         case EQN_TOK_RIGHT:          case EQN_TOK_RIGHT:
         case EQN_TOK_BRACE_CLOSE:          case EQN_TOK_BRACE_CLOSE:
Line 908  next_tok:
Line 893  next_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;
                 if (cur == NULL) {                  if (cur == NULL) {
                         mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,                          mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->node->line, ep->node->pos, eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 parent = cur;                  parent = cur;
                 if (EQN_TOK_RIGHT == tok) {                  if (EQN_TOK_RIGHT == tok) {
                         if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {                          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->node->line,
                                     ep->eqn.pos, eqn_toks[tok]);                                      ep->node->pos, eqn_toks[tok]);
                                 break;                                  break;
                         }                          }
                         /* Handling depends on right/left. */                          /* Handling depends on right/left. */
Line 939  next_tok:
Line 925  next_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 955  next_tok:
Line 942  next_tok:
                 if (EQN_TOK_LEFT == tok &&                  if (EQN_TOK_LEFT == tok &&
                     eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {                      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->node->line, ep->node->pos, eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 parent = eqn_box_alloc(ep, parent);                  parent = eqn_box_alloc(ep, parent);
Line 989  next_tok:
Line 976  next_tok:
                                 break;                                  break;
                 if (cur == NULL) {                  if (cur == NULL) {
                         mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,                          mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
                             ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);                              ep->node->line, ep->node->pos, eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 parent = eqn_box_alloc(ep, cur);                  parent = eqn_box_alloc(ep, cur);
Line 1003  next_tok:
Line 990  next_tok:
                 parent->expectargs = 1;                  parent->expectargs = 1;
                 break;                  break;
         case EQN_TOK_EOF:          case EQN_TOK_EOF:
                 /*                  return;
                  * End of file!  
                  * TODO: make sure we're not in an open subexpression.  
                  */  
                 return ROFF_EQN;  
         case EQN_TOK__MAX:          case EQN_TOK__MAX:
         case EQN_TOK_FUNC:          case EQN_TOK_FUNC:
         case EQN_TOK_QUOTED:          case EQN_TOK_QUOTED:
Line 1058  next_tok:
Line 1041  next_tok:
                                 /* No boundary after last character. */                                  /* No boundary after last character. */
                                 if (*cpn == '\0')                                  if (*cpn == '\0')
                                         break;                                          break;
                                 if (ccln == ccl)                                  if (ccln == ccl && *cp != ',' && *cpn != ',')
                                         continue;                                          continue;
                                 /* Boundary found, split the text. */                                  /* Boundary found, split the text. */
                                 if (parent->args == parent->expectargs) {                                  if (parent->args == parent->expectargs) {
Line 1097  next_tok:
Line 1080  next_tok:
                                 parent = split->parent;                                  parent = split->parent;
                         break;                          break;
                 }                  }
                 /*  
                  * Post-process list status.  
                  */  
                 while (parent->type == EQN_LISTONE &&  
                     parent->args == parent->expectargs)  
                         parent = parent->parent;  
                 break;                  break;
         default:          default:
                 abort();                  abort();
Line 1110  next_tok:
Line 1087  next_tok:
         goto next_tok;          goto next_tok;
 }  }
   
 enum rofferr  
 eqn_end(struct eqn_node **epp)  
 {  
         struct eqn_node *ep;  
   
         ep = *epp;  
         *epp = NULL;  
   
         ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));  
         ep->eqn.root->expectargs = UINT_MAX;  
         return eqn_parse(ep, ep->eqn.root);  
 }  
   
 void  void
 eqn_free(struct eqn_node *p)  eqn_free(struct eqn_node *p)
 {  {
         int              i;          int              i;
   
         eqn_box_free(p->eqn.root);  
   
         for (i = 0; i < (int)p->defsz; i++) {          for (i = 0; i < (int)p->defsz; i++) {
                 free(p->defs[i].key);                  free(p->defs[i].key);

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

CVSweb