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

Diff for /mandoc/eqn.c between version 1.51 and 1.56

version 1.51, 2014/10/10 14:27:46 version 1.56, 2014/10/25 15:06:30
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 35 
Line 36 
 #define EQN_NEST_MAX     128 /* maximum nesting of defines */  #define EQN_NEST_MAX     128 /* maximum nesting of defines */
 #define STRNEQ(p1, sz1, p2, sz2) \  #define STRNEQ(p1, sz1, p2, sz2) \
         ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))          ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
 #define EQNSTREQ(x, p, sz) \  
         STRNEQ((x)->name, (x)->sz, (p), (sz))  
   
 enum    eqn_tok {  enum    eqn_tok {
         EQN_TOK_DYAD = 0,          EQN_TOK_DYAD = 0,
Line 314  eqn_read(struct eqn_node **epp, int ln,
Line 313  eqn_read(struct eqn_node **epp, int ln,
 }  }
   
 struct eqn_node *  struct eqn_node *
 eqn_alloc(const char *name, int pos, int line, struct mparse *parse)  eqn_alloc(int pos, int line, struct mparse *parse)
 {  {
         struct eqn_node *p;          struct eqn_node *p;
         size_t           sz;  
         const char      *end;  
   
         p = mandoc_calloc(1, sizeof(struct eqn_node));          p = mandoc_calloc(1, sizeof(struct eqn_node));
   
         if (name && '\0' != *name) {  
                 sz = strlen(name);  
                 assert(sz);  
                 do {  
                         sz--;  
                         end = name + (int)sz;  
                 } while (' ' == *end || '\t' == *end);  
                 p->eqn.name = mandoc_strndup(name, sz + 1);  
         }  
   
         p->parse = parse;          p->parse = parse;
         p->eqn.ln = line;          p->eqn.ln = line;
         p->eqn.pos = pos;          p->eqn.pos = pos;
Line 486  eqn_tok_parse(struct eqn_node *ep, char **p)
Line 473  eqn_tok_parse(struct eqn_node *ep, char **p)
 {  {
         const char      *start;          const char      *start;
         size_t           i, sz;          size_t           i, sz;
           int              quoted;
   
         if (NULL != p)          if (NULL != p)
                 *p = NULL;                  *p = NULL;
   
           quoted = ep->data[ep->cur] == '"';
   
         if (NULL == (start = eqn_nexttok(ep, &sz)))          if (NULL == (start = eqn_nexttok(ep, &sz)))
                 return(EQN_TOK_EOF);                  return(EQN_TOK_EOF);
   
           if (quoted) {
                   if (p != NULL)
                           *p = mandoc_strndup(start, sz);
                   return(EQN_TOK__MAX);
           }
   
         for (i = 0; i < EQN_TOK__MAX; i++) {          for (i = 0; i < EQN_TOK__MAX; i++) {
                 if (NULL == eqn_toks[i])                  if (NULL == eqn_toks[i])
                         continue;                          continue;
Line 578  eqn_box_makebinary(struct eqn_node *ep,
Line 574  eqn_box_makebinary(struct eqn_node *ep,
 }  }
   
 /*  /*
    * Parse the "delim" control statement.
    */
   static void
   eqn_delim(struct eqn_node *ep)
   {
           const char      *start;
           size_t           sz;
   
           if ((start = eqn_nextrawtok(ep, &sz)) == NULL)
                   mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                       ep->eqn.ln, ep->eqn.pos, "delim");
           else if (strncmp(start, "off", 3) == 0)
                   ep->delim = 0;
           else if (strncmp(start, "on", 2) == 0) {
                   if (ep->odelim && ep->cdelim)
                           ep->delim = 1;
           } else if (start[1] != '\0') {
                   ep->odelim = start[0];
                   ep->cdelim = start[1];
                   ep->delim = 1;
           }
   }
   
   /*
  * Undefine a previously-defined string.   * Undefine a previously-defined string.
  */   */
 static int  static int
Line 656  static int
Line 676  static int
 eqn_parse(struct eqn_node *ep, struct eqn_box *parent)  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
 {  {
         char            *p;          char            *p;
         enum eqn_tok     tok;          enum eqn_tok     tok, subtok;
         enum eqn_post    pos;          enum eqn_post    pos;
         struct eqn_box  *cur;          struct eqn_box  *cur;
         int              rc, size;          int              rc, size;
Line 664  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
Line 684  eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
         char             sym[64];          char             sym[64];
         const char      *start;          const char      *start;
   
         assert(NULL != parent);          assert(parent != NULL);
 again:          if (ep->data == NULL)
                   return(-1);
   
         switch ((tok = eqn_tok_parse(ep, &p))) {  next_tok:
           tok = eqn_tok_parse(ep, &p);
   
   this_tok:
           switch (tok) {
         case (EQN_TOK_UNDEF):          case (EQN_TOK_UNDEF):
                 if ((rc = eqn_undef(ep)) <= 0)                  if ((rc = eqn_undef(ep)) <= 0)
                         return(rc);                          return(rc);
Line 685  again:
Line 710  again:
                         EQN_MSG(MANDOCERR_EQNEOF, ep);                          EQN_MSG(MANDOCERR_EQNEOF, ep);
                 break;                  break;
         case (EQN_TOK_DELIM):          case (EQN_TOK_DELIM):
                   eqn_delim(ep);
                   break;
         case (EQN_TOK_GFONT):          case (EQN_TOK_GFONT):
                 if (NULL == eqn_nextrawtok(ep, NULL)) {                  if (eqn_nextrawtok(ep, NULL) == NULL)
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                         return(-1);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                 }  
                 break;                  break;
         case (EQN_TOK_MARK):          case (EQN_TOK_MARK):
         case (EQN_TOK_LINEUP):          case (EQN_TOK_LINEUP):
Line 703  again:
Line 729  again:
         case (EQN_TOK_HAT):          case (EQN_TOK_HAT):
         case (EQN_TOK_DOT):          case (EQN_TOK_DOT):
         case (EQN_TOK_DOTDOT):          case (EQN_TOK_DOTDOT):
                 if (NULL == parent->last) {                  if (parent->last == NULL) {
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
                         return(-1);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           cur = eqn_box_alloc(ep, parent);
                           cur->type = EQN_TEXT;
                           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_LISTONE;
Line 761  again:
Line 790  again:
         case (EQN_TOK_BACK):          case (EQN_TOK_BACK):
         case (EQN_TOK_DOWN):          case (EQN_TOK_DOWN):
         case (EQN_TOK_UP):          case (EQN_TOK_UP):
                 tok = eqn_tok_parse(ep, NULL);                  subtok = eqn_tok_parse(ep, NULL);
                 if (EQN_TOK__MAX != tok) {                  if (subtok != EQN_TOK__MAX) {
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                         return(-1);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           tok = subtok;
                           goto this_tok;
                 }                  }
                 break;                  break;
         case (EQN_TOK_FAT):          case (EQN_TOK_FAT):
Line 772  again:
Line 803  again:
         case (EQN_TOK_ITALIC):          case (EQN_TOK_ITALIC):
         case (EQN_TOK_BOLD):          case (EQN_TOK_BOLD):
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                 /*                  /*
                  * These values apply to the next word or sequence of                   * These values apply to the next word or sequence of
                  * words; thus, we mark that we'll have a child with                   * words; thus, we mark that we'll have a child with
Line 805  again:
Line 833  again:
         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 (NULL == (start = eqn_nexttok(ep, &sz))) {
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                         return(-1);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           break;
                 }                  }
                 size = mandoc_strntoi(start, sz, 10);                  size = mandoc_strntoi(start, sz, 10);
                 if (-1 == size) {                  if (-1 == size) {
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);                          mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
                         return(-1);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           break;
                 }                  }
                 if (EQN_TOK_GSIZE == tok) {                  if (EQN_TOK_GSIZE == tok) {
                         ep->gsize = size;                          ep->gsize = size;
Line 831  again:
Line 861  again:
                  * Repivot under a positional node, open a child scope                   * Repivot under a positional node, open a child scope
                  * and keep on reading.                   * and keep on reading.
                  */                   */
                 if (NULL == parent->last) {                  if (parent->last == NULL) {
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
                         return(-1);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           cur = eqn_box_alloc(ep, parent);
                           cur->type = EQN_TEXT;
                           cur->text = mandoc_strdup("");
                 }                  }
                 /* Handle the "subsup" and "fromto" positions. */                  /* Handle the "subsup" and "fromto" positions. */
                 if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {                  if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {
Line 866  again:
Line 899  again:
                 break;                  break;
         case (EQN_TOK_SQRT):          case (EQN_TOK_SQRT):
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                 /*                  /*
                  * Accept a left-right-associative set of arguments just                   * Accept a left-right-associative set of arguments just
                  * like sub and sup and friends but without rebalancing                   * like sub and sup and friends but without rebalancing
Line 886  again:
Line 916  again:
                  * Close out anything that's currently open, then                   * Close out anything that's currently open, then
                  * rebalance and continue reading.                   * rebalance and continue reading.
                  */                   */
                 if (NULL == parent->last) {                  if (parent->last == NULL) {
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
                         return(-1);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           cur = eqn_box_alloc(ep, parent);
                           cur->type = EQN_TEXT;
                           cur->text = mandoc_strdup("");
                 }                  }
                 while (EQN_SUBEXPR == parent->type)                  while (EQN_SUBEXPR == parent->type)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                 parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);                  parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
                 break;                  break;
         case (EQN_TOK_RIGHT):          case (EQN_TOK_RIGHT):
Line 904  again:
Line 934  again:
                  * FIXME: this is a shitty sentinel: we should really                   * FIXME: this is a shitty sentinel: we should really
                  * have a native EQN_BRACE type or whatnot.                   * have a native EQN_BRACE type or whatnot.
                  */                   */
                 while (parent->type != EQN_LIST)                  for (cur = parent; cur != NULL; cur = cur->parent)
                         if (NULL == (parent = parent->parent)) {                          if (cur->type == EQN_LIST &&
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);                              (tok == EQN_TOK_BRACE_CLOSE ||
                                 return(-1);                               cur->left != NULL))
                         }                                  break;
                   if (cur == NULL) {
                           mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
                               ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           break;
                   }
                   parent = cur;
                 if (EQN_TOK_RIGHT == tok) {                  if (EQN_TOK_RIGHT == tok) {
                         if (NULL == parent->left) {  
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                         if (NULL == (start = eqn_nexttok(ep, &sz))) {                          if (NULL == (start = eqn_nexttok(ep, &sz))) {
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);                                  mandoc_msg(MANDOCERR_REQ_EMPTY,
                                 return(-1);                                      ep->parse, ep->eqn.ln,
                                       ep->eqn.pos, eqn_toks[tok]);
                                   break;
                         }                          }
                         /* Handling depends on right/left. */                          /* Handling depends on right/left. */
                         if (STRNEQ(start, sz, "ceiling", 7)) {                          if (STRNEQ(start, sz, "ceiling", 7)) {
Line 928  again:
Line 962  again:
                         } else                          } else
                                 parent->right = mandoc_strndup(start, sz);                                  parent->right = mandoc_strndup(start, sz);
                 }                  }
                 if (NULL == (parent = parent->parent)) {                  parent = parent->parent;
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                         return(-1);  
                 }  
                 if (EQN_TOK_BRACE_CLOSE == tok && parent &&                  if (EQN_TOK_BRACE_CLOSE == tok && parent &&
                     (parent->type == EQN_PILE ||                      (parent->type == EQN_PILE ||
                      parent->type == EQN_MATRIX))                       parent->type == EQN_MATRIX))
Line 939  again:
Line 970  again:
                 /* Close out any "singleton" lists. */                  /* Close out any "singleton" lists. */
                 while (parent->type == EQN_LISTONE &&                  while (parent->type == EQN_LISTONE &&
                     parent->args == parent->expectargs)                      parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                 break;                  break;
         case (EQN_TOK_BRACE_OPEN):          case (EQN_TOK_BRACE_OPEN):
         case (EQN_TOK_LEFT):          case (EQN_TOK_LEFT):
Line 952  again:
Line 980  again:
                  * (just like with the text node).                   * (just like with the text node).
                  */                   */
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);                  if (EQN_TOK_LEFT == tok &&
                                 return(-1);                      (start = eqn_nexttok(ep, &sz)) == NULL) {
                         }                          mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
                               ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           break;
                   }
                 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 (NULL == (start = eqn_nexttok(ep, &sz))) {  
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                         /* Handling depends on right/left. */  
                         if (STRNEQ(start, sz, "ceiling", 7)) {                          if (STRNEQ(start, sz, "ceiling", 7)) {
                                 strlcpy(sym, "\\[lc]", sizeof(sym));                                  strlcpy(sym, "\\[lc]", sizeof(sym));
                                 parent->left = mandoc_strdup(sym);                                  parent->left = mandoc_strdup(sym);
Line 982  again:
Line 1008  again:
         case (EQN_TOK_LCOL):          case (EQN_TOK_LCOL):
         case (EQN_TOK_RCOL):          case (EQN_TOK_RCOL):
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                 if (EQN_TOK_BRACE_OPEN != eqn_tok_parse(ep, NULL)) {  
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                         return(-1);  
                 }  
                 parent = eqn_box_alloc(ep, parent);                  parent = eqn_box_alloc(ep, parent);
                 parent->type = EQN_PILE;                  parent->type = EQN_PILE;
                 parent = eqn_box_alloc(ep, parent);                  parent->expectargs = 1;
                 parent->type = EQN_LIST;  
                 break;                  break;
         case (EQN_TOK_ABOVE):          case (EQN_TOK_ABOVE):
                 while (parent->type != EQN_PILE)                  for (cur = parent; cur != NULL; cur = cur->parent)
                         if (NULL == (parent = parent->parent)) {                          if (cur->type == EQN_PILE)
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);                                  break;
                                 return(-1);                  if (cur == NULL) {
                         }                          mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
                 parent = eqn_box_alloc(ep, parent);                              ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                           break;
                   }
                   parent = eqn_box_alloc(ep, cur);
                 parent->type = EQN_LIST;                  parent->type = EQN_LIST;
                 break;                  break;
         case (EQN_TOK_MATRIX):          case (EQN_TOK_MATRIX):
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                 if (EQN_TOK_BRACE_OPEN != eqn_tok_parse(ep, NULL)) {  
                         EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                         return(-1);  
                 }  
                 parent = eqn_box_alloc(ep, parent);                  parent = eqn_box_alloc(ep, parent);
                 parent->type = EQN_MATRIX;                  parent->type = EQN_MATRIX;
                 parent = eqn_box_alloc(ep, parent);                  parent->expectargs = 1;
                 parent->type = EQN_LIST;  
                 break;                  break;
         case (EQN_TOK_EOF):          case (EQN_TOK_EOF):
                 /*                  /*
Line 1033  again:
Line 1046  again:
                  * in an expression, then rewind til we're not any more.                   * in an expression, then rewind til we're not any more.
                  */                   */
                 while (parent->args == parent->expectargs)                  while (parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 free(p);  
                                 return(-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++)                  for (i = 0; i < EQNSYM__MAX; i++)
Line 1055  again:
Line 1064  again:
                  * Post-process list status.                   * Post-process list status.
                  */                   */
                 while (parent->type == EQN_LISTONE &&                  while (parent->type == EQN_LISTONE &&
                         parent->args == parent->expectargs)                      parent->args == parent->expectargs)
                         if (NULL == (parent = parent->parent)) {                          parent = parent->parent;
                                 EQN_MSG(MANDOCERR_EQNSYNT, ep);  
                                 return(-1);  
                         }  
                 break;                  break;
         }          }
         goto again;          goto next_tok;
 }  }
   
 enum rofferr  enum rofferr
Line 1090  eqn_free(struct eqn_node *p)
Line 1096  eqn_free(struct eqn_node *p)
                 free(p->defs[i].val);                  free(p->defs[i].val);
         }          }
   
         free(p->eqn.name);  
         free(p->data);          free(p->data);
         free(p->defs);          free(p->defs);
         free(p);          free(p);

Legend:
Removed from v.1.51  
changed lines
  Added in v.1.56

CVSweb