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

Diff for /mandoc/eqn.c between version 1.77 and 1.86

version 1.77, 2017/07/14 18:18:26 version 1.86, 2023/04/28 19:11:03
Line 1 
Line 1 
 /*      $Id$ */  /* $Id$ */
 /*  /*
    * Copyright (c) 2014, 2015, 2017, 2018, 2020, 2022
    *               Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015, 2017 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 30 
Line 31 
 #include "mandoc_aux.h"  #include "mandoc_aux.h"
 #include "mandoc.h"  #include "mandoc.h"
 #include "roff.h"  #include "roff.h"
   #include "eqn.h"
 #include "libmandoc.h"  #include "libmandoc.h"
 #include "libroff.h"  #include "eqn_parse.h"
   
 #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) \
Line 284  enum parse_mode {
Line 286  enum parse_mode {
         MODE_TOK          MODE_TOK
 };  };
   
   struct  eqn_def {
           char             *key;
           size_t            keysz;
           char             *val;
           size_t            valsz;
   };
   
 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  struct eqn_box  *eqn_box_makebinary(struct eqn_node *,  static  struct eqn_box  *eqn_box_makebinary(struct eqn_node *,
                                 struct eqn_box *);                                  struct eqn_box *);
Line 295  static void   eqn_undef(struct eqn_node *);
Line 304  static void   eqn_undef(struct eqn_node *);
   
   
 struct eqn_node *  struct eqn_node *
 eqn_alloc(struct mparse *parse)  eqn_alloc(void)
 {  {
         struct eqn_node *ep;          struct eqn_node *ep;
   
         ep = mandoc_calloc(1, sizeof(*ep));          ep = mandoc_calloc(1, sizeof(*ep));
         ep->parse = parse;  
         ep->gsize = EQN_DEFSIZE;          ep->gsize = EQN_DEFSIZE;
         return ep;          return ep;
 }  }
Line 348  eqn_def_find(struct eqn_node *ep)
Line 356  eqn_def_find(struct eqn_node *ep)
 /*  /*
  * Parse a token from the input text.  The modes are:   * Parse a token from the input text.  The modes are:
  * MODE_QUOTED: Use *ep->start as the delimiter; the token ends   * MODE_QUOTED: Use *ep->start as the delimiter; the token ends
  *   before its next occurence.  Do not interpret the token in any   *   before its next occurrence.  Do not interpret the token in any
  *   way and return EQN_TOK_QUOTED.  All other modes behave like   *   way and return EQN_TOK_QUOTED.  All other modes behave like
  *   MODE_QUOTED when *ep->start is '"'.   *   MODE_QUOTED when *ep->start is '"'.
  * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;   * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;
Line 368  eqn_def_find(struct eqn_node *ep)
Line 376  eqn_def_find(struct eqn_node *ep)
 static enum eqn_tok  static enum eqn_tok
 eqn_next(struct eqn_node *ep, enum parse_mode mode)  eqn_next(struct eqn_node *ep, enum parse_mode mode)
 {  {
         static int       last_len, lim;  
   
         struct eqn_def  *def;          struct eqn_def  *def;
         size_t           start;          size_t           start;
         int              diff, i, quoted;          int              diff, i, newlen, quoted;
         enum eqn_tok     tok;          enum eqn_tok     tok;
   
         /*          /*
          * Reset the recursion counter after advancing           * Reset the recursion counter after advancing
          * beyond the end of the previous substitution.           * beyond the end of the rightmost substitution.
          */           */
         if (ep->end - ep->data >= last_len)          if (ep->end - ep->data >= ep->sublen)
                 lim = 0;                  ep->subcnt = 0;
   
         ep->start = ep->end;          ep->start = ep->end;
         quoted = mode == MODE_QUOTED;          quoted = mode == MODE_QUOTED;
Line 392  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 398  eqn_next(struct eqn_node *ep, enum parse_mode mode)
                 case '"':                  case '"':
                         quoted = 1;                          quoted = 1;
                         break;                          break;
                   case ' ':
                   case '\t':
                   case '~':
                   case '^':
                           if (quoted)
                                   break;
                           ep->start++;
                           continue;
                 default:                  default:
                         break;                          break;
                 }                  }
Line 399  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 413  eqn_next(struct eqn_node *ep, enum parse_mode mode)
                         ep->end = strchr(ep->start + 1, *ep->start);                          ep->end = strchr(ep->start + 1, *ep->start);
                         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->node->line, ep->node->pos, NULL);                                      ep->node->line, ep->node->pos, NULL);
                                 ep->end = strchr(ep->start, '\0');                                  ep->end = strchr(ep->start, '\0');
                         }                          }
Line 419  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 433  eqn_next(struct eqn_node *ep, enum parse_mode mode)
                         return EQN_TOK__MAX;                          return EQN_TOK__MAX;
                 if ((def = eqn_def_find(ep)) == NULL)                  if ((def = eqn_def_find(ep)) == NULL)
                         break;                          break;
                 if (++lim > EQN_NEST_MAX) {                  if (++ep->subcnt > EQN_NEST_MAX) {
                         mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,                          mandoc_msg(MANDOCERR_ROFFLOOP,
                             ep->node->line, ep->node->pos, NULL);                              ep->node->line, ep->node->pos, NULL);
                         return EQN_TOK_EOF;                          break;
                 }                  }
   
                 /* Replace a defined name with its string value. */                  /* Replace a defined name with its string value. */
Line 431  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 445  eqn_next(struct eqn_node *ep, enum parse_mode mode)
                         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->start = ep->data + start;                          ep->start = ep->data + start;
                           ep->sublen += diff;
                 }                  }
                 if (diff)                  if (diff)
                         memmove(ep->start + def->valsz, ep->start + ep->toksz,                          memmove(ep->start + def->valsz, ep->start + ep->toksz,
                             strlen(ep->start + ep->toksz) + 1);                              strlen(ep->start + ep->toksz) + 1);
                 memcpy(ep->start, def->val, def->valsz);                  memcpy(ep->start, def->val, def->valsz);
                 last_len = ep->start - ep->data + def->valsz;                  newlen = ep->start - ep->data + def->valsz;
                   if (ep->sublen < newlen)
                           ep->sublen = newlen;
         }          }
         if (mode != MODE_TOK)          if (mode != MODE_TOK)
                 return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;                  return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;
Line 468  eqn_next(struct eqn_node *ep, enum parse_mode mode)
Line 485  eqn_next(struct eqn_node *ep, enum parse_mode mode)
 void  void
 eqn_box_free(struct eqn_box *bp)  eqn_box_free(struct eqn_box *bp)
 {  {
           if (bp == NULL)
                   return;
   
         if (bp->first)          if (bp->first)
                 eqn_box_free(bp->first);                  eqn_box_free(bp->first);
Line 482  eqn_box_free(struct eqn_box *bp)
Line 501  eqn_box_free(struct eqn_box *bp)
         free(bp);          free(bp);
 }  }
   
   struct eqn_box *
   eqn_box_new(void)
   {
           struct eqn_box  *bp;
   
           bp = mandoc_calloc(1, sizeof(*bp));
           bp->expectargs = UINT_MAX;
           return bp;
   }
   
 /*  /*
  * Allocate a box as the last child of the parent node.   * Allocate a box as the last child of the parent node.
  */   */
Line 490  eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par
Line 519  eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par
 {  {
         struct eqn_box  *bp;          struct eqn_box  *bp;
   
         bp = mandoc_calloc(1, sizeof(struct eqn_box));          bp = eqn_box_new();
         bp->parent = parent;          bp->parent = parent;
         bp->parent->args++;          bp->parent->args++;
         bp->expectargs = UINT_MAX;  
         bp->font = bp->parent->font;          bp->font = bp->parent->font;
         bp->size = ep->gsize;          bp->size = ep->gsize;
   
Line 542  static void
Line 570  static void
 eqn_delim(struct eqn_node *ep)  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->node->line, ep->node->pos, "delim");                      ep->node->line, ep->node->pos, "delim");
                 if (ep->end[0] != '\0')                  if (ep->end[0] != '\0')
                         ep->end++;                          ep->end++;
Line 569  eqn_undef(struct eqn_node *ep)
Line 597  eqn_undef(struct eqn_node *ep)
         struct eqn_def  *def;          struct eqn_def  *def;
   
         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->node->line, ep->node->pos, "undef");                      ep->node->line, ep->node->pos, "undef");
                 return;                  return;
         }          }
Line 588  eqn_def(struct eqn_node *ep)
Line 616  eqn_def(struct eqn_node *ep)
         int              i;          int              i;
   
         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->node->line, ep->node->pos, "define");                      ep->node->line, ep->node->pos, "define");
                 return;                  return;
         }          }
Line 617  eqn_def(struct eqn_node *ep)
Line 645  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_msg(MANDOCERR_REQ_EMPTY,
                     ep->node->line, ep->node->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);
Line 651  eqn_parse(struct eqn_node *ep)
Line 679  eqn_parse(struct eqn_node *ep)
         if (ep->data == NULL)          if (ep->data == NULL)
                 return;                  return;
   
         ep->start = ep->end = ep->data + strspn(ep->data, " ^~");          ep->start = ep->end = ep->data;
           ep->sublen = 0;
           ep->subcnt = 0;
   
 next_tok:  next_tok:
         tok = eqn_next(ep, MODE_TOK);          tok = eqn_next(ep, MODE_TOK);
Line 666  next_tok:
Line 696  next_tok:
         case EQN_TOK_TDEFINE:          case EQN_TOK_TDEFINE:
                 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->node->line, ep->node->pos, "tdefine");                              ep->node->line, ep->node->pos, "tdefine");
                 break;                  break;
         case EQN_TOK_DELIM:          case EQN_TOK_DELIM:
Line 674  next_tok:
Line 704  next_tok:
                 break;                  break;
         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->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", eqn_toks[tok]);
                 break;                  break;
         case EQN_TOK_MARK:          case EQN_TOK_MARK:
         case EQN_TOK_LINEUP:          case EQN_TOK_LINEUP:
Line 690  next_tok:
Line 720  next_tok:
         case EQN_TOK_DOT:          case EQN_TOK_DOT:
         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->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", 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("");
Line 717  next_tok:
Line 747  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 735  next_tok:
Line 765  next_tok:
         case EQN_TOK_DOWN:          case EQN_TOK_DOWN:
         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->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", eqn_toks[tok]);
                 break;                  break;
         case EQN_TOK_FAT:          case EQN_TOK_FAT:
         case EQN_TOK_ROMAN:          case EQN_TOK_ROMAN:
Line 773  next_tok:
Line 803  next_tok:
         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 (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->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", 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->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 if (EQN_TOK_GSIZE == tok) {                  if (EQN_TOK_GSIZE == tok) {
Line 804  next_tok:
Line 834  next_tok:
                  * and keep on reading.                   * and keep on reading.
                  */                   */
                 if (parent->last == NULL) {                  if (parent->last == NULL) {
                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", 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("");
Line 871  next_tok:
Line 901  next_tok:
                  * rebalance and continue reading.                   * rebalance and continue reading.
                  */                   */
                 if (parent->last == NULL) {                  if (parent->last == NULL) {
                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,                          mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", 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("");
Line 898  next_tok:
Line 928  next_tok:
                              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->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", 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->node->line,                                      ep->node->line, ep->node->pos,
                                     ep->node->pos, eqn_toks[tok]);                                      "%s", eqn_toks[tok]);
                                 break;                                  break;
                         }                          }
                         /* Handling depends on right/left. */                          /* Handling depends on right/left. */
Line 941  next_tok:
Line 971  next_tok:
                         parent = parent->parent;                          parent = parent->parent;
                 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->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 parent = eqn_box_alloc(ep, parent);                  parent = eqn_box_alloc(ep, parent);
Line 975  next_tok:
Line 1005  next_tok:
                         if (cur->type == EQN_PILE)                          if (cur->type == EQN_PILE)
                                 break;                                  break;
                 if (cur == NULL) {                  if (cur == NULL) {
                         mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,                          mandoc_msg(MANDOCERR_IT_STRAY, ep->node->line,
                             ep->node->line, ep->node->pos, eqn_toks[tok]);                              ep->node->pos, "%s", eqn_toks[tok]);
                         break;                          break;
                 }                  }
                 parent = eqn_box_alloc(ep, cur);                  parent = eqn_box_alloc(ep, cur);
Line 1091  void
Line 1121  void
 eqn_free(struct eqn_node *p)  eqn_free(struct eqn_node *p)
 {  {
         int              i;          int              i;
   
           if (p == NULL)
                   return;
   
         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.77  
changed lines
  Added in v.1.86

CVSweb