/***************************************************************
  
        bwb_var.c       Variable-Handling Routines
                        for Bywater BASIC Interpreter
  
                        Copyright (c) 1993, Ted A. Campbell
                        Bywater Software
  
                        email: tcamp@delphi.com
  
        Copyright and Permissions Information:
  
        All U.S. and international rights are claimed by the author,
        Ted A. Campbell.
  
   This software is released under the terms of the GNU General
   Public License (GPL), which is distributed with this software
   in the file "COPYING".  The GPL specifies the terms under
   which users may copy and use the software in this distribution.
  
   A separate license is available for commercial distribution,
   for information on which you should contact the author.
  
***************************************************************/

/*---------------------------------------------------------------*/
/* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */
/* 11/1995 (eidetics@cerf.net).                                  */
/*                                                               */
/* Those additionally marked with "DD" were at the suggestion of */
/* Dale DePriest (daled@cadence.com).                            */
/*                                                               */
/* Version 3.00 by Howard Wulf, AF5NE                            */
/*                                                               */
/*---------------------------------------------------------------*/


#include "bwbasic.h"



static int      dimmed = FALSE;  /* has DIM been called? */
static int      first, last;  /* first, last for DEFxxx commands */

/* Prototypes for functions visible to this file only */

static int
dim_check(struct bwb_variable * v, int *pp);
static int
var_defx(struct bwb_line * l, int type);
static int
var_letseq(char *buffer, int *position, int *start, int *end);
static          size_t
dim_unit(struct bwb_variable * v, int *pp);
static struct bwb_variable *
var_islocal(char *buffer);


/***************************************************************
  
        FUNCTION:       var_init()
  
        DESCRIPTION: This function initializes the internal
         linked list of variables.
  
***************************************************************/

int
var_init(int task)
{
   bwx_DEBUG(__FUNCTION__);

   LOCALTASK       var_start.next = &(LOCALTASK var_end);
   strcpy(LOCALTASK var_start.name, "<START>");
   strcpy(LOCALTASK var_end.name, "<END>");
   return TRUE;
}


/***************************************************************
  
        FUNCTION:       bwb_common()
  
        DESCRIPTION: This C function implements the BASIC
            COMMON command.
  
   SYNTAX:     COMMON variable [, variable...]
  
***************************************************************/

struct bwb_line *
bwb_COMMON(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);

   /* loop while arguments are available */

   while (TRUE)
   {

      struct bwb_variable *v;
      char            tbuf[BasicStringLengthMax + 1];
      /* get variable name and find variable */

      bwb_getvarname(l->buffer, tbuf, &(l->position));

      if ((v = var_find(tbuf)) == NULL)
      {
         bwb_error(err_syntax);
         return bwb_zline(l);
      }
      v->common = TRUE; /* set common flag to true */

      /* check for comma */

      adv_ws(l->buffer, &(l->position));
      if (l->buffer[l->position] != ',')
      {
         /* no comma; leave */
         return bwb_zline(l);
      }
      ++(l->position);
      adv_ws(l->buffer, &(l->position));

   }

   return bwb_zline(l);

}

/***********************************************************
  
        FUNCTION: bwb_erase()
  
   DESCRIPTION:    This C function implements the BASIC
         ERASE command.
  
   SYNTAX:     ERASE variable[, variable]...
  
***********************************************************/

struct bwb_line *
bwb_ERASE(struct bwb_line * l)
{
   register int    loop;
   struct bwb_variable *v;
   struct bwb_variable *p; /* previous variable in linked list */
   char            tbuf[BasicStringLengthMax + 1];
   bstring        *sp;  /* JBV */
   register int    n;   /* JBV */

   bwx_DEBUG(__FUNCTION__);

   /* loop while arguments are available */

   loop = TRUE;
   while (loop == TRUE)
   {

      /* get variable name and find variable */

      bwb_getvarname(l->buffer, tbuf, &(l->position));

      if ((v = var_find(tbuf)) == NULL)
      {
         bwb_error(err_syntax);
         return bwb_zline(l);
      }
      /* be sure the variable is dimensioned */

      if ((v->dimensions < 1) || (v->array_sizes[0] < 1))
      {
         bwb_error(err_dimnotarray);
         return bwb_zline(l);
      }
      /* find previous variable in chain */

      for (p = &CURTASK var_start; p->next != v; p = p->next)
      {
         ;
      }

      /* reassign linkage */

      p->next = v->next;

      /* deallocate memory */

      /* Revised to FREE pass-thru calls by JBV */
      FREE(v->array_sizes, "bwb_erase");
      v->array_sizes = NULL;  /* JBV */
      FREE(v->array_pos, "bwb_erase");
      v->array_pos = NULL; /* JBV */
      if (v->type == NUMBER)
      {
         /* Revised to FREE pass-thru call by JBV */
         FREE(v->memnum, "bwb_erase");
         v->memnum = NULL; /* JBV */
      }
      else
      {
         /* Following section added by JBV */
         sp = v->memstr;
         for (n = 0; n < (int) v->array_units; ++n)
         {
            if (sp[n].sbuffer != NULL)
            {
               /* Revised to FREE pass-thru call by
                * JBV */
               FREE(sp[n].sbuffer, "bwb_erase");
               sp[n].sbuffer = NULL;
            }
            sp[n].rab = FALSE;
            sp[n].length = 0;
         }
         /* Revised to FREE pass-thru call by JBV */
         FREE(v->memstr, "bwb_erase");
         v->memstr = NULL; /* JBV */
      }
      /* Revised to FREE pass-thru call by JBV */
      FREE(v, "bwb_erase");
      v = NULL;   /* JBV */

      /* check for comma */

      adv_ws(l->buffer, &(l->position));
      if (l->buffer[l->position] != ',')
      {
         return bwb_zline(l); /* no comma; leave */
      }
      ++(l->position);
      adv_ws(l->buffer, &(l->position));

   }

   return bwb_zline(l);

}

/***********************************************************
  
        FUNCTION: bwb_swap()
  
   DESCRIPTION:    This C function implements the BASIC
         SWAP command.
  
   SYNTAX:     SWAP variable, variable
  
***********************************************************/

struct bwb_line *
bwb_SWAP(struct bwb_line * l)
{
   struct bwb_variable tmp;/* temp holder */
   struct bwb_variable *lhs, *rhs;  /* left and right- hand side of swap
                * statement */
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   /* get left variable name and find variable */

   bwb_getvarname(l->buffer, tbuf, &(l->position));

   if ((lhs = var_find(tbuf)) == NULL)
   {
      bwb_error(err_syntax);
      return bwb_zline(l);
   }
   /* check for comma */

   adv_ws(l->buffer, &(l->position));
   if (l->buffer[l->position] != ',')
   {
      bwb_error(err_syntax);
      return bwb_zline(l);
   }
   ++(l->position);
   adv_ws(l->buffer, &(l->position));

   /* get right variable name */


   bwb_getvarname(l->buffer, tbuf, &(l->position));


   if ((rhs = var_find(tbuf)) == NULL)
   {
      bwb_error(err_syntax);
      return bwb_zline(l);
   }
   /* check to be sure that both variables are of the same type */

   if (rhs->type != lhs->type)
   {
      bwb_error(err_mismatch);
      return bwb_zline(l);
   }
   /* copy lhs to temp, rhs to lhs, then temp to rhs */
   tmp.memnum = NULL;   /* AF5NE */
   tmp.memstr = NULL;   /* AF5NE */

   if (lhs->type == NUMBER)
   {
      tmp.memnum = lhs->memnum;
   }
   else
   {
      tmp.memstr = lhs->memstr;
   }
   tmp.array_sizes = lhs->array_sizes;
   tmp.array_units = lhs->array_units;
   tmp.array_pos = lhs->array_pos;
   tmp.dimensions = lhs->dimensions;


   lhs->memnum = NULL;  /* AF5NE */
   lhs->memstr = NULL;  /* AF5NE */


   if (lhs->type == NUMBER)
   {
      lhs->memnum = rhs->memnum;
   }
   else
   {
      lhs->memstr = rhs->memstr;
   }
   lhs->array_sizes = rhs->array_sizes;
   lhs->array_units = rhs->array_units;
   lhs->array_pos = rhs->array_pos;
   lhs->dimensions = rhs->dimensions;


   rhs->memnum = NULL;  /* AF5NE */
   rhs->memstr = NULL;  /* AF5NE */


   if (lhs->type == NUMBER)
   {
      rhs->memnum = tmp.memnum;
   }
   else
   {
      rhs->memstr = tmp.memstr;
   }
   rhs->array_sizes = tmp.array_sizes;
   rhs->array_units = tmp.array_units;
   rhs->array_pos = tmp.array_pos;
   rhs->dimensions = tmp.dimensions;

   /* return */

   return bwb_zline(l);

}


/***********************************************************
  
        FUNCTION: bwb_clear()
  
   DESCRIPTION:    This C function implements the BASIC
         CLEAR command.
  
   SYNTAX:     CLEAR
  
***********************************************************/

void
var_CLEAR(void)
{
   struct bwb_variable *v;
   register int    n;
   bstring        *sp;
   BasicNumberType *np;

   bwx_DEBUG(__FUNCTION__);

   for (v = CURTASK var_start.next; v != &CURTASK var_end; v = v->next)
   {
      if (v->preset != TRUE)
      {
         switch (v->type)
         {
         case NUMBER:
            np = v->memnum;
            for (n = 0; n < (int) v->array_units; ++n)
            {
               np[n] = (BasicNumberType) 0.0;
            }
            break;
         case STRING:
            sp = v->memstr;
            for (n = 0; n < (int) v->array_units; ++n)
            {
               if (sp[n].sbuffer != NULL)
               {
                  /* Revised to FREE pass-thru
                   * call by JBV */
                  FREE(sp[n].sbuffer, "bwb_clear");
                  sp[n].sbuffer = NULL;
               }
               sp[n].rab = FALSE;
               sp[n].length = 0;
            }
            break;
         }
      }
   }

   dimmed = FALSE;
}

struct bwb_line *
bwb_CLEAR(struct bwb_line * l)
{

   var_CLEAR();

   /* ignoare all parameters */
   adv_eos(l->buffer, &(l->position));

   return bwb_zline(l);
}

/***********************************************************
  
   FUNCTION:       var_delcvars()
  
   DESCRIPTION:    This function deletes all variables
         in memory except those previously marked
         as common.
  
***********************************************************/

int
var_delcvars(void)
{
   struct bwb_variable *v;
   struct bwb_variable *p; /* previous variable */
   bstring        *sp;  /* JBV */
   register int    n;   /* JBV */


   bwx_DEBUG(__FUNCTION__);


   for (v = CURTASK var_start.next; (v != NULL) && (v != &CURTASK var_end); v = v->next)
   {


      if ((v->preset != TRUE) && (v->common != TRUE))

      {



         /* if the variable is dimensioned, release allocated
          * memory */

         if (v->dimensions > 0)
         {

            /* deallocate memory */

            /* Revised to FREE pass-thru calls by JBV */
            FREE(v->array_sizes, "var_delcvars");
            v->array_sizes = NULL;  /* JBV */
            FREE(v->array_pos, "var_delcvars");
            v->array_pos = NULL; /* JBV */
            if (v->type == NUMBER)
            {
               /* Revised to FREE pass-thru call by
                * JBV */
               FREE(v->memnum, "var_delcvars");
               v->memnum = NULL; /* JBV */
            }
            else
            {
               /* Following section added by JBV */
               sp = v->memstr;
               for (n = 0; n < (int) v->array_units; ++n)
               {
                  if (sp[n].sbuffer != NULL)
                  {
                     /* Revised to FREE
                      * pass-thru call by
                      * JBV */
                     FREE(sp[n].sbuffer, "var_delcvars");
                     sp[n].sbuffer = NULL;
                  }
                  sp[n].rab = FALSE;
                  sp[n].length = 0;
               }
               /* Revised to FREE pass-thru call by
                * JBV */
               FREE(v->memstr, "var_delcvars");
               v->memstr = NULL; /* JBV */
            }
         }
         /* find previous variable in chain */
         for (p = &CURTASK var_start; p->next != v; p = p->next)
         {
            ;
         }


         /* reassign linkage */

         p->next = v->next;

         /* deallocate the variable itself */

         /* Revised to FREE pass-thru call by JBV */
         FREE(v, "var_delcvars");
         /* v = NULL; *//* Variable 'v' is reassigned a value
          * before the old one has been used. */
         v = p;

      }
   }

   return TRUE;

}

/***********************************************************
  
        FUNCTION: bwb_mid()
  
   DESCRIPTION:    This function implements the BASIC
         MID$ command.
  
         Same as MID$ function, except it will set
         the desired substring and not return its
         value.  Added by JBV 10/95
  
   SYNTAX:     MID$( string-variable$, start-position-in-string
         [, number-of-spaces ] ) = expression
  
***********************************************************/

struct bwb_line *
bwb_MID_(struct bwb_line * l)
{
   char            tbuf[BasicStringLengthMax + 1];
   char            source_string[BasicStringLengthMax + 1];
   struct bwb_variable *v;
   int             pos;
   bstring        *d;
   int            *pp;
   int             n_params;
   int             p;
   register int    n;
   int             startpos;
   int             numchars;
   int             endpos;
   int             source_length;
   int             target_length;



   int             target_terminate;
   struct exp_ese *e;

   bwx_DEBUG(__FUNCTION__);

   /* Get past left parenthesis */
   adv_ws(l->buffer, &(l->position));
   ++(l->position);
   adv_ws(l->buffer, &(l->position));

   /* Get variable name and find variable */
   bwb_getvarname(l->buffer, tbuf, &(l->position));
   v = var_find(tbuf);
   if (v == NULL)
   {
      sprintf(bwb_ebuf, "in bwb_mid(): failed to find variable");
      bwb_error(bwb_ebuf);
      return bwb_zline(l);
   }
   if (v->type != STRING)
   {
      sprintf(bwb_ebuf, "in bwb_mid(): assignment must be to string variable");
      bwb_error(bwb_ebuf);
      return bwb_zline(l);
   }
   /* read subscripts */
   pos = 0;
   if ((v->dimensions == 1) && (v->array_sizes[0] == 1))
   {
      n_params = 1;
      pp = &p;
      pp[0] = dim_base;
   }
   else
   {
      dim_getparams(l->buffer, &(l->position), &n_params, &pp);
   }

   CURTASK         exps[CURTASK expsc].pos_adv = pos;
   for (n = 0; n < v->dimensions; ++n)
   {
      v->array_pos[n] = pp[n];
   }

   /* get bstring pointer */
   d = var_findsval(v, pp);

   /* Get past next comma and white space */
   adv_ws(l->buffer, &(l->position));
   ++(l->position);
   adv_ws(l->buffer, &(l->position));

   /* Get starting position (expression) */
   adv_element(l->buffer, &(l->position), tbuf);
   pos = 0;
   e = bwb_exp(tbuf, FALSE, &pos);
   if (ERROR_PENDING)
   {
      return bwb_zline(l);
   }
   startpos = exp_getival(e);


   /* Get past next comma and white space (if they exist) */
   adv_ws(l->buffer, &(l->position));
   if (l->buffer[l->position] == ',')
   {
      target_terminate = 0;
      ++(l->position);
      adv_ws(l->buffer, &(l->position));
      adv_element(l->buffer, &(l->position), tbuf);
      pos = 0;
      e = bwb_exp(tbuf, FALSE, &pos);
      if (ERROR_PENDING)
      {
         return bwb_zline(l);
      }
      numchars = exp_getival(e);
      if (numchars == 0)
      {
         sprintf(bwb_ebuf, "in bwb_mid(): destination string no. of chars out of range");
         bwb_error(bwb_ebuf);
         return bwb_zline(l);
      }
   }
   else
   {
      target_terminate = 1;
      numchars = 0;
   }

   if (numchars < 0)
   {
      sprintf(bwb_ebuf, "in bwb_mid(): negative string length");
      bwb_error(bwb_ebuf);
      return bwb_zline(l);
   }
   /* Get past equal sign */
   adv_ws(l->buffer, &(l->position));
   if (l->buffer[l->position] == ')')
   {
      ++(l->position);
      adv_ws(l->buffer, &(l->position));
   }
   ++(l->position);
   adv_ws(l->buffer, &(l->position));

   /* Evaluate string expression */
   e = bwb_exp(l->buffer, FALSE, &(l->position));
   if (ERROR_PENDING)
   {
      return bwb_zline(l);
   }
   if (e->type != STRING)
   {
      sprintf(bwb_ebuf, "in bwb_mid(): assignment must be from string expression");
      bwb_error(bwb_ebuf);
      return bwb_zline(l);
   }
   /* Prepare to MID the string */
   str_btoc(source_string, exp_getsval(e));
   str_btoc(tbuf, d);
   target_length = strlen(tbuf);
   if (startpos > (target_length + 1))
   {
      sprintf(bwb_ebuf, "in bwb_mid(): non-contiguous string created");
      bwb_error(bwb_ebuf);
      return bwb_zline(l);
   }
   if (startpos < 1)
   {
      sprintf(bwb_ebuf, "in bwb_mid(): destination string start position out of range");
      bwb_error(bwb_ebuf);
      return bwb_zline(l);
   }
   source_length = strlen(source_string);
   if (numchars == 0)
      numchars = source_length;
   endpos = startpos + numchars - 1;

   /* MID the string */
   if (endpos < startpos)
      tbuf[startpos - 1] = '\0';
   else
   {
      int             source_counter;

      source_counter = 0;
      for (n = startpos - 1; n < endpos; ++n)
      {
         if (source_counter < source_length)
            tbuf[n] = source_string[source_counter];
         else
            tbuf[n] = ' ';
         ++source_counter;
      }
      /* Terminate if indicated or characters were added */
      if ((endpos > target_length) || (target_terminate == 1))
         tbuf[endpos] = '\0';
   }
   str_ctob(d, tbuf);

   adv_eos(l->buffer, &(l->position));

   return bwb_zline(l);

}


/***********************************************************
  
        FUNCTION: bwb_ddbl()
  
   DESCRIPTION:    This function implements the BASIC
         DEFDBL command.
  
   SYNTAX:     DEFDBL letter[-letter](, letter[-letter])...
  
***********************************************************/

struct bwb_line *
bwb_DEFDBL(struct bwb_line * l)
{

   bwx_DEBUG(__FUNCTION__);

   /* call generalized DEF handler with DOUBLE set */

   var_defx(l, NUMBER);

   return bwb_zline(l);

}

/***********************************************************
  
        FUNCTION: bwb_dint()
  
   DESCRIPTION:    This function implements the BASIC
         DEFINT command.
  
   SYNTAX:     DEFINT letter[-letter](, letter[-letter])...
  
***********************************************************/

struct bwb_line *
bwb_DEFINT(struct bwb_line * l)
{

   bwx_DEBUG(__FUNCTION__);

   /* call generalized DEF handler with INTEGER set */

   var_defx(l, NUMBER);

   return bwb_zline(l);

}

/***********************************************************
  
        FUNCTION: bwb_dsng()
  
   DESCRIPTION:    This function implements the BASIC
         DEFSNG command.
  
   SYNTAX:     DEFSNG letter[-letter](, letter[-letter])...
  
***********************************************************/

struct bwb_line *
bwb_DEFSNG(struct bwb_line * l)
{

   bwx_DEBUG(__FUNCTION__);

   /* call generalized DEF handler with SINGLE set */

   var_defx(l, NUMBER);

   return bwb_zline(l);

}

/***********************************************************
  
        FUNCTION: bwb_dstr()
  
   DESCRIPTION:    This function implements the BASIC
         DEFSTR command.
  
   SYNTAX:     DEFSTR letter[-letter](, letter[-letter])...
  
***********************************************************/

struct bwb_line *
bwb_DEFSTR(struct bwb_line * l)
{

   bwx_DEBUG(__FUNCTION__);

   /* call generalized DEF handler with STRING set */

   var_defx(l, STRING);

   return bwb_zline(l);

}

static
int
VarTypeIndex(int C)
{
   bwx_DEBUG(__FUNCTION__);

   if (isalpha(C))
   {
      static char     A2Z[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      char           *P;

      P = strchr(A2Z, ToUpper(C));
      if (P == NULL)
      {
         bwb_error("INTERNAL: VarTypeIndex() called for non-char");
      }
      else
      {
         return P - A2Z;
      }
   }
   else
   {
      bwb_error("INTERNAL: VarTypeIndex() called for non-alpha");
   }
   return 0;
}

/***********************************************************
  
        Function: var_defx()
  
   DESCRIPTION:    This function is a generalized DEFxxx handler.
  
***********************************************************/

static int
var_defx(struct bwb_line * l, int type)
{
   int             loop;
   register int    c;
#if 0
   char            vname[2];
   struct bwb_variable *v;
#endif

   bwx_DEBUG(__FUNCTION__);

   /* loop while there are variable names to process */

   loop = TRUE;
   while (loop == TRUE)
   {

      /* check for end of line or line segment */

      adv_ws(l->buffer, &(l->position));
      switch (l->buffer[l->position])
      {
      case '\0':
         return FALSE;
      }
      if( l->buffer[l->position] == OptionCommentChar )
      {
         return FALSE;
      }

      /* find a sequence of letters for variables */

      if (var_letseq(l->buffer, &(l->position), &first, &last) == FALSE)
      {
         return FALSE;
      }
#if 0
      /* loop through the list getting variables */

      for (c = first; c <= last; ++c)
      {
         vname[0] = (char) c;
         vname[1] = '\0';


         v = var_find(vname);

         /* but var_find() assigns on the basis of name
          * endings (so all in this case should be SINGLEs),
          * so we must force the type of the variable */

         var_make(v, type);

      }
#endif
      if (isalpha(first) && isalpha(last))
      {
         first = VarTypeIndex(first);
         last = VarTypeIndex(last);
         for (c = first; c <= last; c++)
         {
            DefaultVariableType[c] = type;
         }
      }
   }

   return TRUE;

}


/***********************************************************
  
        Function: var_letseq()
  
   DESCRIPTION:    This function finds a sequence of letters
         for a DEFxxx command.
  
***********************************************************/

static int
var_letseq(char *buffer, int *position, int *start, int *end)
{

   bwx_DEBUG(__FUNCTION__);

   /* advance beyond whitespace */

   adv_ws(buffer, position);

   /* check for end of line */

   switch (buffer[*position])
   {
   case '\0':
      return TRUE;
   }

   /* character at this position must be a letter */

   if (isalpha(buffer[*position]) == 0)
   {
      bwb_error(err_defchar);
      return FALSE;
   }
   *end = *start = buffer[*position];

   /* advance beyond character and whitespace */

   ++(*position);
   adv_ws(buffer, position);

   /* check for hyphen, indicating sequence of more than one letter */

   if (buffer[*position] == '-')
   {

      ++(*position);

      /* advance beyond whitespace */

      adv_ws(buffer, position);

      /* character at this position must be a letter */

      if (isalpha(buffer[*position]) == 0)
      {
         *end = *start;
      }
      else
      {
         *end = buffer[*position];
         ++(*position);
      }

   }
   /* advance beyond comma if present */

   if (buffer[*position] == ',')
   {
      ++(*position);
   }
   return TRUE;
}


/***********************************************************
  
   FUNCTION:       bwb_getvarname()
  
   DESCRIPTION:    This function takes the string in lb
         (the large buffer), finds a variable name,
         and returns it in sb (the small buffer),
         appropriately incrementing the integer
         pointed to by n.
  
***********************************************************/

int
bwb_getvarname(char *lb, char *sb, int *n)
{
   /* FIXME: use BasicNameLengthMax */
#if 0
   register int    s;

   bwx_DEBUG(__FUNCTION__);

   s = 0;

   /* advance beyond whitespace */
   adv_ws(lb, n);

   while (TRUE)
   {
      switch (lb[*n])
      {
      case ' ':   /* whitespace */
      case '\0':
      case ',':
      case ';':
      case '(':   /* beginning of parameter list for
             * dimensioned array */
      case '+':   /* add variables *//* FIXME: looks like a bug */
      case '=':   /* Don't forget this one (JBV) */
         sb[s] = 0;
         return TRUE;
      default:
         sb[s] = lb[*n];
         break;
      }

      ++*n;    /* advance to next character in large buffer */
      ++s;     /* advance to next position in small buffer */
      sb[s] = 0;  /* terminate with 0 */

   }
#endif


   bwx_DEBUG(__FUNCTION__);

   /* advance beyond whitespace */
   adv_ws(lb, n);

   lb += (*n);
   if (isalpha(*lb))
   {
      *sb = *lb;
      sb++;
      lb++;
      (*n)++;

      if (OptionFlags & OPTION_BUGS_ON)
      {
         /* allow '.' and '_' in variable names */
         while (isalnum(*lb) || *lb == '.' || *lb == '_')
         {
            *sb = *lb;
            sb++;
            lb++;
            (*n)++;
         }
      }
      else
      {
         while (isalnum(*lb))
         {
            *sb = *lb;
            sb++;
            lb++;
            (*n)++;
         }
      }
      if (OptionFlags & OPTION_BUGS_ON)
      {
         /* allow '!','@','#', '%', '&' and '$' in variable names */
         switch (*lb)
         {
         case BasicDoubleSuffix:
         case BasicSingleSuffix:
         case BasicCurrencySuffix:
         case BasicLongSuffix:
         case BasicIntegerSuffix:
         case BasicStringSuffix:
            /* suffix IS part of the name. *
             * A$ is distinct from A. */
            *sb = *lb;
            sb++;
            lb++;
            (*n)++;
            break;
         }
      }
      else
      {
         switch (*lb)
         {
         case BasicStringSuffix:
            /* suffix IS part of the name. *
             * A$ is distinct from A. */
            *sb = *lb;
            sb++;
            lb++;
            (*n)++;
            break;
         }
      }
   }
   *sb = '\0';
   return TRUE;
}

/***************************************************************
  
        FUNCTION:       var_find()
  
   DESCRIPTION:    This C function attempts to find a variable
         name matching the argument in buffer. If
         it fails to find a matching name, it
         sets up a new variable with that name.
  
***************************************************************/

struct bwb_variable *
var_find(char *buffer)
{
   struct bwb_variable *v;

   bwx_DEBUG(__FUNCTION__);

   /* check for NULL variable name */

   if (strlen(buffer) == 0)
   {
      sprintf(bwb_ebuf, "in var_find(): NULL variable name received\n");
      bwb_error(bwb_ebuf);
      return NULL;
   }
   /* check for a local variable at this EXEC level */

   v = var_islocal(buffer);
   if (v != NULL)
   {
      return v;
   }
   /* now run through the global variable list and try to find a match */

   for (v = CURTASK var_start.next; v != &CURTASK var_end; v = v->next)
   {

      if (strcasecmp(v->name, buffer) == 0)
      {
         switch (v->type)
         {
         case STRING:
         case NUMBER:
            break;
         default:
            sprintf(bwb_ebuf, "in var_find(): inappropriate precision for variable <%s>",
               v->name);
            bwb_error(bwb_ebuf);
            return NULL;
            break;
         }

         return v;
      }
   }

   /* presume this is a new variable, so initialize it... */

   /* initialize new variable */

   v = var_new(buffer);

   /* set place at beginning of variable chain */

   v->next = CURTASK var_start.next;
   CURTASK         var_start.next = v;

   /* normally not a preset */

   v->preset = FALSE;


   return v;

}

/***************************************************************
  
        FUNCTION:       var_new()
  
   DESCRIPTION:    This function assigns memory for a new variable.
  
***************************************************************/

struct bwb_variable *
var_new(char *name)
{
   struct bwb_variable *v;
   char            C;
   int             type;


   bwx_DEBUG(__FUNCTION__);
   /* get memory for new variable */

   if (name == NULL)
   {
      bwb_error("INTERNAL ERROR - not a valid variable name - name == NULL");
      return NULL;
   }
   if (strlen(name) == 0)
   {
      bwb_error("INTERNAL ERROR - not a valid variable name - strlen(name) == 0");
      return NULL;
   }
   if (isalpha(*name))
   {
      /* OK */
   }
   else
   {
      bwb_error("INTERNAL ERROR - not a valid variable name - !isalpha(*name)");
      return NULL;
   }
   C = ToUpper(*name);
   /* Revised to CALLOC pass-thru call by JBV */
   if ((v = (struct bwb_variable *) CALLOC(1, sizeof(struct bwb_variable), "var_new"))
       == NULL)
   {
      bwb_error(err_getmem);
      return NULL;
   }
   /* copy the name into the appropriate structure */

   strcpy(v->name, name);

#if 0
   var_make(v, (int) v->name[strlen(v->name) - 1]);
#endif
   /* set memory in the new variable */

   type = NUMBER;    /* DEFAULT */
   switch (v->name[strlen(v->name) - 1])
   {
   case BasicStringSuffix:
      type = STRING;
      break;
   case BasicDoubleSuffix:
   case BasicSingleSuffix:
   case BasicCurrencySuffix:
   case BasicLongSuffix:
   case BasicIntegerSuffix:
      type = NUMBER;
      break;
   default:
      type = DefaultVariableType[VarTypeIndex(C)];
      break;
   }
   var_make(v, type);

   /* and return */

   return v;

}

/***************************************************************
  
        FUNCTION:       bwb_isvar()
  
   DESCRIPTION:    This function determines if the string
         in 'buffer' is the name of a previously-
         existing variable.
  
***************************************************************/

int
bwb_isvar(char *buffer)
{
   struct bwb_variable *v;


   bwx_DEBUG(__FUNCTION__);

   /* run through the variable list and try to find a match */

   for (v = CURTASK var_start.next; v != &CURTASK var_end; v = v->next)
   {

      if (strcasecmp(v->name, buffer) == 0)
      {
         return TRUE;
      }
   }

   /* search failed */

   return FALSE;

}

/***************************************************************
  
   FUNCTION:       var_getnval()
  
   DESCRIPTION:    This function returns the current value of
         the variable argument as a number.
  
***************************************************************/

BasicNumberType
var_getnval(struct bwb_variable * nvar)
{

   bwx_DEBUG(__FUNCTION__);

   switch (nvar->type)
   {
   case NUMBER:
      return *(var_findnval(nvar, nvar->array_pos));
   }

   sprintf(bwb_ebuf, "in var_getnval(): type is <%d>=<%c>.",
      nvar->type, nvar->type);
   bwb_error(bwb_ebuf);
   return 0;

}


/***************************************************************
  
   FUNCTION:       var_getsval()
  
   DESCRIPTION:    This function returns the current value of
         the variable argument as a pointer to a BASIC
         string structure.
  
***************************************************************/

bstring        *
var_getsval(struct bwb_variable * nvar)
{
   static bstring  b;

   bwx_DEBUG(__FUNCTION__);

   b.rab = FALSE;

   switch (nvar->type)
   {
   case STRING:
      return var_findsval(nvar, nvar->array_pos);
   case NUMBER:
      sprintf(bwb_ebuf, "%*f ", prn_precision(nvar),
         *(var_findnval(nvar, nvar->array_pos)));
      str_ctob(&b, bwb_ebuf);
      return &b;
   default:
      sprintf(bwb_ebuf, "in var_getsval(): type is <%d>=<%c>.",
         nvar->type, nvar->type);
      bwb_error(bwb_ebuf);
      return NULL;
   }

}

/***************************************************************
  
   FUNCTION:   bwb_dim()
  
   DESCRIPTION:   This function implements the BASIC DIM
         statement, allocating memory for a
         dimensioned array of variables.
  
   SYNTAX:     DIM variable(elements...)[variable(elements...)]...
  
***************************************************************/

struct bwb_line *
bwb_DIM(struct bwb_line * l)
{
   register int    n;
   static int      n_params;  /* number of parameters */
   static int     *pp;  /* pointer to parameter values */
   struct bwb_variable *newvar;
   BasicNumberType *np;
   int             loop;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);




   loop = TRUE;
   while (loop == TRUE)
   {
      int             old_name;
      int             old_dimensions;

      old_name = FALSE;

      /* Get variable name */

      adv_ws(l->buffer, &(l->position));
      bwb_getvarname(l->buffer, tbuf, &(l->position));


      /* check for previously used variable name */

      if (bwb_isvar(tbuf) == TRUE)
      {
         old_name = TRUE;
      }
      /* get the new variable */

      newvar = var_find(tbuf);


      /* note that DIM has been called */

      dimmed = TRUE;

      /* read parameters */

      old_dimensions = newvar->dimensions;
      dim_getparams(l->buffer, &(l->position), &n_params, &pp);
      newvar->dimensions = n_params;

      /* Check parameters for an old variable name */

      if (old_name == TRUE)
      {

         /* check to be sure the number of dimensions is the
          * same */

         if (newvar->dimensions != old_dimensions)
         {
            sprintf(bwb_ebuf, "in bwb_dim(): variable <%s> cannot be re-dimensioned",
               newvar->name);
            bwb_error(bwb_ebuf);
            return bwb_zline(l);
         }
         /* check to be sure sizes for the old variable are
          * the same */

         for (n = 0; n < newvar->dimensions; ++n)
         {
            if ((pp[n] + (1 - dim_base)) != newvar->array_sizes[n])
            {
               sprintf(bwb_ebuf, "in bwb_dim(): variable <%s> parameter <%d> cannot be resized",
                  newvar->name, n);
               bwb_error(bwb_ebuf);
               return bwb_zline(l);
            }
         }

      }     /* end of conditional for old variable */
      /*       a new variable */

      else
      {

         /* assign memory for parameters */

         /* Revised to CALLOC pass-thru call by JBV */
         if ((newvar->array_sizes = (int *) CALLOC(n_params, sizeof(int), "bwb_dim")) == NULL)
         {
            sprintf(bwb_ebuf, "in line %d: Failed to find memory for array_sizes for <%s>",
               l->number, newvar->name);
            bwb_error(bwb_ebuf);
            return bwb_zline(l);
         }
         for (n = 0; n < newvar->dimensions; ++n)
         {
            newvar->array_sizes[n] = pp[n] + (1 - dim_base);
         }

         /* assign memory for current position */

         /* Revised to CALLOC pass-thru call by JBV */
         if ((newvar->array_pos = (int *) CALLOC(n_params, sizeof(int), "bwb_dim")) == NULL)
         {
            sprintf(bwb_ebuf, "in line %d: Failed to find memory for array_pos for <%s>",
               l->number, newvar->name);
            bwb_error(bwb_ebuf);
            return bwb_zline(l);
         }
         for (n = 0; n < newvar->dimensions; ++n)
         {
            newvar->array_pos[n] = dim_base;
         }

         /* calculate the array size */
#define MAXINTSIZE      2147483647  /* this is a HACK */

         newvar->array_units = (size_t) MAXINTSIZE;   /* avoid error in
                            * dim_unit() */
         newvar->array_units = dim_unit(newvar, pp) + 1;


         /* assign array memory */

         switch (newvar->type)
         {
         case STRING:
            /*------------------------------------------------------*/
            /* memnum, not memstr, was used here --
             * incorrect (JBV) */
            /* Revised to CALLOC pass-thru call by JBV              */
            /*------------------------------------------------------*/
            if ((newvar->memstr = (bstring *)
                 CALLOC(newvar->array_units, sizeof(bstring), "bwb_dim")) == NULL)
            {
               sprintf(bwb_ebuf, "in line %d: Failed to find memory for array <%s>",
                  l->number, newvar->name);
               bwb_error(bwb_ebuf);
               return bwb_zline(l);
            }
            break;
         case NUMBER:

            /* Revised to CALLOC pass-thru call by JBV */
            if ((np = (BasicNumberType *)
                 CALLOC(newvar->array_units, sizeof(BasicNumberType), "bwb_dim")) == NULL)
            {
               sprintf(bwb_ebuf, "in line %d: Failed to find memory for array <%s>",
                  l->number, newvar->name);
               bwb_error(bwb_ebuf);
               return bwb_zline(l);
            }
            newvar->memnum = np;
            break;
         default:
            sprintf(bwb_ebuf, "in line %d: New variable has unrecognized type.",
               l->number);
            bwb_error(bwb_ebuf);
            return bwb_zline(l);
         }

      }     /* end of conditional for new variable */

      /* now check for end of string */

      if (l->buffer[l->position] == ')')
      {
         ++(l->position);
      }
      adv_ws(l->buffer, &(l->position));
      if (l->buffer[l->position] == OptionCommentChar)
      {
         loop = FALSE;
      }
      else
      {
         switch (l->buffer[l->position])
         {
         case '\0':  /* end of string */
            loop = FALSE;
            break;
         case ',':
            ++(l->position);
            adv_ws(l->buffer, &(l->position));
            loop = TRUE;
            break;
         default:
            loop = FALSE;
            sprintf(bwb_ebuf, "in bwb_dim(): unexpected end of string, buf <%s>",
               &(l->buffer[l->position]));
            bwb_error(bwb_ebuf);
            return bwb_zline(l);
            break;
         }
      }

   }        /* end of loop through variables */

   /* return */

   return bwb_zline(l);

}

int
DetermineNumberOfDimensions(char *expression, int LastPosition)
{
   /* MUST be a dynamically created array, READ A(10) = ... ' variable
    * "A" has NOT been dimensioned */
   int             ParenLevel = 0;
   int             NumDimensions = 1;
   int             Loop = TRUE;

   bwx_DEBUG(__FUNCTION__);

   while (Loop == TRUE)
   {
      char            C;
      C = expression[LastPosition];
      /* check the current character */


      switch (C)
      {
      case '\0':
         return 0;
         break;

      case '=':
         Loop = FALSE;
         break;

      case '(':
         LastPosition++;
         ParenLevel++;
         break;
      case ')':
         LastPosition++;
         ParenLevel--;
         if (ParenLevel == 0)
         {
            Loop = FALSE;
         }
         break;
      case ',':
         LastPosition++;
         if (ParenLevel == 1)
         {
            NumDimensions++;
         }
         break;
      case '\"':  /* embedded string constant */
         LastPosition++;
         while ((expression[LastPosition] != '\"')
                && (expression[LastPosition] != '\0'))
         {
            LastPosition++;
         }
         if (expression[LastPosition] == '\"')
         {
            LastPosition++;
         }
         break;
      default:
         LastPosition++;
      }
   }

   return NumDimensions;
}

int
ImplicitDim(char *tbuf, int n_params)
{
   /* This is only for ECMA-55.  ECMA-116 requires arrays to be
    * dimensioned prior to being used. */


   register int    n;   /* number of parameters */
   BasicNumberType *np;
   static int     *pp;  /* pointer to parameter values */
   struct bwb_variable *newvar;
   static int      params[MAX_DIMS];

   bwx_DEBUG(__FUNCTION__);

   if (OptionFlags & OPTION_STRICT_ON)
   {
      /* Implicit DIM is not allowed */
      return FALSE;
   }
   for (n = 0; n < MAX_DIMS; n++)
   {
      params[n] = 10;   /* UBOUND() = 10, LBOUND() = OPTION BASE */
   }
   pp = &params[0];

   /* get the new variable */

   newvar = var_find(tbuf);

   /* note that DIM has been (implicitly) called */

   dimmed = TRUE;

   newvar->dimensions = n_params;



   /* assign memory for parameters */

   /* Revised to CALLOC pass-thru call by JBV */
   if ((newvar->array_sizes = (int *) CALLOC(n_params, sizeof(int), "bwb_dim")) == NULL)
   {
      bwb_error(err_getmem);
      return FALSE;
   }
   for (n = 0; n < newvar->dimensions; ++n)
   {
      newvar->array_sizes[n] = pp[n] + (1 - dim_base);
   }

   /* assign memory for current position */

   /* Revised to CALLOC pass-thru call by JBV */
   if ((newvar->array_pos = (int *) CALLOC(n_params, sizeof(int), "bwb_dim")) == NULL)
   {
      bwb_error(err_getmem);
      return FALSE;
   }
   for (n = 0; n < newvar->dimensions; ++n)
   {
      newvar->array_pos[n] = dim_base;
   }

   /* calculate the array size */
#define MAXINTSIZE      2147483647  /* this is a HACK */
   newvar->array_units = (size_t) MAXINTSIZE;   /* avoid error in
                      * dim_unit() */
   newvar->array_units = dim_unit(newvar, pp) + 1;

   /* assign array memory */

   switch (newvar->type)
   {
   case STRING:
      /*------------------------------------------------------*/
      /* memnum, not memstr, was used here -- incorrect (JBV) */
      /* Revised to CALLOC pass-thru call by JBV              */
      /*------------------------------------------------------*/
      if ((newvar->memstr = (bstring *)
           CALLOC(newvar->array_units, sizeof(bstring), "bwb_dim")) == NULL)
      {
         bwb_error(err_getmem);
         return FALSE;
      }
      break;
   case NUMBER:

      /* Revised to CALLOC pass-thru call by JBV */
      if ((np = (BasicNumberType *)
           CALLOC(newvar->array_units, sizeof(BasicNumberType), "bwb_dim")) == NULL)
      {
         bwb_error(err_getmem);
         return FALSE;
      }
      newvar->memnum = np;
      break;
   default:
      bwb_error(err_syntax);
      return FALSE;
   }

   return TRUE;
}




/***************************************************************
  
        FUNCTION:       dim_unit()
  
        DESCRIPTION:    This function calculates the unit
            position for an array.
  
***************************************************************/

static          size_t
dim_unit(struct bwb_variable * v, int *pp)
{
   size_t          r;
   size_t          b;
   register int    n;

   bwx_DEBUG(__FUNCTION__);

   /* Calculate and return the address of the dimensioned array */

   /* Check EACH dimension for out-of-bounds, AND check correct number
    * of dimensions.  NBS_P076_0250 errors correctly. */

   b = 1;
   r = 0;
   for (n = 0; n < v->dimensions; ++n)
   {

      /* newvar->array_sizes[ n ] = pp[ n ] + ( 1 - dim_base ); */
      if ((pp[n] < dim_base) || ((pp[n] + (1 - dim_base)) > v->array_sizes[n]))
      {
         sprintf(bwb_ebuf, "SUBSCRIPT OUT OF RANGE %s(%d)", v->name, pp[n]);
         bwb_error(bwb_ebuf);
         return 0;
      }
      r += b * (pp[n] - dim_base);
      b *= v->array_sizes[n];
   }

   if (r > v->array_units)
   {



      sprintf(bwb_ebuf, "SUBSCRIPT OUT OF RANGE %s(%ld)", v->name, (long) r);
      bwb_error(bwb_ebuf);

      return 0;
   }
   return r;

}

/***************************************************************
  
        FUNCTION:       dim_getparams()
  
   DESCRIPTION:    This function reads a string in <buffer>
                        beginning at position <pos> and finds a
                        list of parameters surrounded by paren-
                        theses, returning in <n_params> the number
                        of parameters found, and returning in
                        <pp> an array of n_params integers giving
                        the sizes for each dimension of the array.
  
***************************************************************/

int
dim_getparams_FIXED(char *buffer, int *pos, int params[ /* MAX_DIMS */ ])
{
   int             n_params;
   int             loop;
   int             x_pos, s_pos;
   struct exp_ese *e;
   char            tbuf[BasicStringLengthMax + 1];
   int             paren_level, quote_level; /* JBV 1/97 */

   bwx_DEBUG(__FUNCTION__);

   /* set initial values */

   n_params = 0;

   /* advance and check for undimensioned variable */

   adv_ws(buffer, pos);
   if (buffer[*pos] != '(')
   {
      n_params = 1;
      params[0] = dim_base;
      return n_params;
   }
   else
   {
      ++(*pos);
   }

   /* Variable has DIMensions: Find each parameter */

   s_pos = 0;
   tbuf[0] = '\0';
   loop = TRUE;
   paren_level = 1;  /* JBV 1/97 */
   quote_level = 0;  /* JBV 1/97 */
   while (loop == TRUE)
   {
      switch (buffer[*pos])
      {
      case ')':   /* end of parameter list */
         /*-----------------------------------------------------*/
         /* paren_level and quote_level check added by JBV
          * 1/97 */
         /*-----------------------------------------------------*/
         if (quote_level == 0)
            --paren_level;
         if (paren_level != 0 || quote_level != 0) /* Still not done? */
         {
            tbuf[s_pos] = buffer[*pos];
            ++(*pos);
            ++s_pos;
            tbuf[s_pos] = '\0';
            break;
         }
         x_pos = 0;
         if (tbuf[0] == '\0')
         {
            params[n_params] = DEF_SUBSCRIPT;
         }
         else
         {





            e = bwb_exp(tbuf, FALSE, &x_pos);
            if (ERROR_PENDING)
            {
               return 0;
            }
            /* Subscripts are rounded */
            params[n_params] = exp_getival(e);




         }
         n_params++;
         loop = FALSE;
         ++(*pos);
         break;

      case ',':   /* end of a parameter */
         /*-----------------------------------------------------*/
         /* paren_level and quote_level check added by JBV
          * 1/97 */
         /*-----------------------------------------------------*/
         if (paren_level != 1 || quote_level != 0) /* Still not done? */
         {
            tbuf[s_pos] = buffer[*pos];
            ++(*pos);
            ++s_pos;
            tbuf[s_pos] = '\0';
            break;
         }
         x_pos = 0;
         if (tbuf[0] == '\0')
         {
            params[n_params] = DEF_SUBSCRIPT;
         }
         else
         {


            e = bwb_exp(tbuf, FALSE, &x_pos);
            if (ERROR_PENDING)
            {
               return 0;
            }
            /* Subscripts are rounded */
            params[n_params] = exp_getival(e);


         }
         n_params++;
         tbuf[0] = '\0';
         ++(*pos);
         s_pos = 0;
         break;

      case ' ':   /* whitespace -- skip */
         ++(*pos);
         break;

      default:
         if (buffer[*pos] == '(' && quote_level == 0)
            ++paren_level; /* JBV 1/97 */
         if (buffer[*pos] == (char) 34)
         {
            if (quote_level == 0)
               quote_level = 1;
            else
               quote_level = 0;
         }
         tbuf[s_pos] = buffer[*pos];
         ++(*pos);
         ++s_pos;
         tbuf[s_pos] = '\0';
         break;
      }

      if (n_params >= MAX_DIMS)
      {
         loop = FALSE;
      }
   }


   /* return params stack */






   return n_params;


}





int
dim_getparams(char *buffer, int *pos, int *n_params, int **pp)
{
   int             loop;
   static int      params[MAX_DIMS];   /* can NOT be called via
                   * bwb_exp() */
   int             x_pos, s_pos;
   struct exp_ese *e;
   char            tbuf[BasicStringLengthMax + 1];
   int             paren_level, quote_level; /* JBV 1/97 */

   bwx_DEBUG(__FUNCTION__);

   /* set initial values */

   *n_params = 0;

   /* advance and check for undimensioned variable */

   adv_ws(buffer, pos);
   if (buffer[*pos] != '(')
   {
      *n_params = 1;
      params[0] = dim_base;
      *pp = params;
      return TRUE;
   }
   else
   {
      ++(*pos);
   }

   /* Variable has DIMensions: Find each parameter */

   s_pos = 0;
   tbuf[0] = '\0';
   loop = TRUE;
   paren_level = 1;  /* JBV 1/97 */
   quote_level = 0;  /* JBV 1/97 */
   while (loop == TRUE)
   {
      switch (buffer[*pos])
      {
      case ')':   /* end of parameter list */
         /*-----------------------------------------------------*/
         /* paren_level and quote_level check added by JBV
          * 1/97 */
         /*-----------------------------------------------------*/
         if (quote_level == 0)
            --paren_level;
         if (paren_level != 0 || quote_level != 0) /* Still not done? */
         {
            tbuf[s_pos] = buffer[*pos];
            ++(*pos);
            ++s_pos;
            tbuf[s_pos] = '\0';
            break;
         }
         x_pos = 0;
         if (tbuf[0] == '\0')
         {
            params[*n_params] = DEF_SUBSCRIPT;
         }
         else
         {



            e = bwb_exp(tbuf, FALSE, &x_pos);
            if (ERROR_PENDING)
            {
               return FALSE;
            }
            /* Subscripts are rounded */
            params[*n_params] = exp_getival(e);




         }
         ++(*n_params);
         loop = FALSE;
         ++(*pos);
         break;

      case ',':   /* end of a parameter */
         /*-----------------------------------------------------*/
         /* paren_level and quote_level check added by JBV
          * 1/97 */
         /*-----------------------------------------------------*/
         if (paren_level != 1 || quote_level != 0) /* Still not done? */
         {
            tbuf[s_pos] = buffer[*pos];
            ++(*pos);
            ++s_pos;
            tbuf[s_pos] = '\0';
            break;
         }
         x_pos = 0;
         if (tbuf[0] == '\0')
         {
            params[*n_params] = DEF_SUBSCRIPT;
         }
         else
         {


            e = bwb_exp(tbuf, FALSE, &x_pos);
            if (ERROR_PENDING)
            {
               return FALSE;
            }
            /* Subscripts are rounded */
            params[*n_params] = exp_getival(e);


         }
         ++(*n_params);
         tbuf[0] = '\0';
         ++(*pos);
         s_pos = 0;
         break;

      case ' ':   /* whitespace -- skip */
         ++(*pos);
         break;

      default:
         if (buffer[*pos] == '(' && quote_level == 0)
            ++paren_level; /* JBV 1/97 */
         if (buffer[*pos] == (char) 34)
         {
            if (quote_level == 0)
               quote_level = 1;
            else
               quote_level = 0;
         }
         tbuf[s_pos] = buffer[*pos];
         ++(*pos);
         ++s_pos;
         tbuf[s_pos] = '\0';
         break;
      }
   }


   /* return params stack */

   *pp = params;





   return TRUE;

}

/***************************************************************
  
        FUNCTION:       bwb_option()
  
        DESCRIPTION:    This function implements the BASIC OPTION
                        BASE statement, designating the base (1 or
                        0) for addressing DIM arrays.
  
   SYNTAX:     OPTION BASE number
  
***************************************************************/

void
OptionBaseHelper(int newval, struct bwb_line * l   /* just for error
           messages */ )
{
   struct bwb_variable *current;

   bwx_DEBUG(__FUNCTION__);

   /* OPTION BASE ... */

   /* If DIM has already been called, do not allow OPTION BASE */

   if (dimmed != FALSE)
   {
      sprintf(bwb_ebuf, "at line %d: OPTION BASE must be called before DIM.",
         l->number);
      bwb_error(bwb_ebuf);
      return;
   }
   /* Test the new value. */


   if ((newval < 0) || (newval > 1))
   {
      sprintf(bwb_ebuf, "at line %d: value for OPTION BASE must be 1 or 0.",
         l->number);
      bwb_error(bwb_ebuf);
      return;
   }
   /* Set the new value. */

   dim_base = newval;

   /* run through the variable list and change any positions that had
    * set 0 before OPTION BASE was run */

   for (current = CURTASK var_start.next; current != &CURTASK var_end; current = current->next)
   {
      current->array_pos[0] = dim_base;
   }


}

void
OptionVersionSet(int i)
{
   bwx_DEBUG(__FUNCTION__);

   OptionVersion = bwb_vertable[i].OptionVersionBitmask;
   OptionFlags = bwb_vertable[i].OptionFlags;
   OptionCommentChar = bwb_vertable[i].OptionCommentChar;
   OptionStatementChar = bwb_vertable[i].OptionStatementChar;
   strcpy(OptionDateFormat,bwb_vertable[i].OptionDateFormat);
   strcpy(OptionTimeFormat,bwb_vertable[i].OptionTimeFormat);

}

struct bwb_line *
bwb_OPTION(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION  ... */
   bwb_error(err_syntax);
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ANGLE_DEGREES(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION ANGLE DEGREES */
   OptionFlags |= OPTION_ANGLE_DEGREES;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ANGLE_RADIANS(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION ANGLE RADIANS */
   OptionFlags &= ~OPTION_ANGLE_DEGREES;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ARITHMETIC_DECIMAL(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION ARITHMETIC DECIMAL */
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ARITHMETIC_FIXED(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION ARITHMETIC FIXED */
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ARITHMETIC_NATIVE(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION ARITHMETIC NATIVE */
   return bwb_zline(l);
}


struct bwb_line *
bwb_OPTION_BASE_1(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION BASE 1 */
   OptionFlags |= OPTION_BASE_ONE;
   OptionBaseHelper(1, l);
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_BASE_0(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION BASE 0 */
   OptionFlags &= ~OPTION_BASE_ONE;
   OptionBaseHelper(0, l);
   return bwb_zline(l);
}


struct bwb_line *
bwb_OPTION_BUGS_ON(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION BUGS ON */
   OptionFlags |= OPTION_BUGS_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_BUGS_OFF(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION BUGS OFF */
   OptionFlags &= ~OPTION_BUGS_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_COMMENT(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION COMMENT char */
   OptionCommentChar = l->buffer[l->position];
   if( OptionCommentChar != '\0' )
   {
      l->position++;
   }
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_COMPARE_BINARY(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION COMPARE BINARY */
   OptionFlags &= ~OPTION_COMPARE_TEXT;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_COMPARE_DATABASE(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION COMPARE DATABASE */
   OptionFlags |= OPTION_COMPARE_TEXT;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_COMPARE_TEXT(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION COMPARE TEXT */
   OptionFlags |= OPTION_COMPARE_TEXT;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_COVERAGE_ON(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION COVERAGE ON */
   OptionFlags |= OPTION_COVERAGE_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_COVERAGE_OFF(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION COVERAGE OFF */
   OptionFlags &= ~OPTION_COVERAGE_ON;
   return bwb_zline(l);
}

static void
StripQuotes( char * tbuf )
{
   /* Remove Leading & Trailing Quotes */
   if( tbuf[0] == '"' )
   {
      char * Q;
      strcpy( tbuf, &(tbuf[1]) );
      Q = strchr( tbuf, '"' );
      if( Q != NULL )
      {
         *Q = '\0';
      }
   }
}

struct bwb_line *
bwb_OPTION_DATE(struct bwb_line * l)
{
   /* OPTION DATE format */
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);
   /* Get FORMAT */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   tbuf[ 80 ] = '\0';
   strcpy( OptionDateFormat, tbuf ); 
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_DISABLE_COMMAND(struct bwb_line * l)
{
   /* OPTION DISABLE COMMAND ... */
   int             IsFound;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   IsFound = FALSE;
   /* Get COMMAND */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   {
      /* Name */
      int i;
      for( i = 0; i < NUM_COMMANDS; i++ )
      {
          if( strcasecmp( tbuf, bwb_cmdtable[i].name ) == 0 )
          {
              /* FOUND */
              /* DISABLE COMMAND */
              bwb_cmdtable[i].OptionVersionBitmask &= ~OptionVersion;
              IsFound = TRUE;
          }
      }
   }
   if( IsFound == FALSE )
   {
       /* display warning message */
       sprintf( bwb_ebuf, "IGNORED: %s", l->buffer);      
       puts(bwb_ebuf);
   }
   return bwb_zline(l);
}


struct bwb_line *
bwb_OPTION_DISABLE_FUNCTION(struct bwb_line * l)
{
   /* OPTION DISABLE FUNCTION ... */
   int             IsFound;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   IsFound = FALSE;
   /* Get FUNCTION */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   {
      /* Name */
      int i;
      for( i = 0; i < NUM_FUNCTIONS; i++ )
      {
          if( strcasecmp( tbuf, bwb_prefuncs[i].Name ) == 0 )
          {
              /* FOUND */
              /* DISABLE FUNCTION */
              bwb_prefuncs[i].OptionVersionBitmask &= ~OptionVersion;
              IsFound = TRUE;
          }
      }
   }
   if( IsFound == FALSE )
   {
       /* display warning message */
       sprintf( bwb_ebuf, "IGNORED: %s", l->buffer);      
       puts(bwb_ebuf);
   }
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_DISABLE_OPERATOR(struct bwb_line * l)
{
   /* OPTION DISABLE OPERATOR ... */
   int             IsFound;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   IsFound = FALSE;
   /* Get OPERATOR */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   {
      /* Name */
      int i;
      for( i = 0; i < NUM_OPERATORS; i++ )
      {
          if( strcasecmp( tbuf, exp_ops[i].symbol ) == 0 )
          {
              /* FOUND */
              /* DISABLE OPERATOR */
              exp_ops[i].OptionVersionBitmask &= ~OptionVersion;
              IsFound = TRUE;
          }
      }
   }
   if( IsFound == FALSE )
   {
       /* display warning message */
       sprintf( bwb_ebuf, "IGNORED: %s", l->buffer);      
       puts(bwb_ebuf);
   }
   return bwb_zline(l);
}



struct bwb_line *
bwb_OPTION_ENABLE_COMMAND(struct bwb_line * l)
{
   /* OPTION ENABLE COMMAND ... */
   int             IsFound;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   IsFound = FALSE;
   /* Get COMMAND */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   {
      /* Name */
      int i;
      for( i = 0; i < NUM_COMMANDS; i++ )
      {
          if( strcasecmp( tbuf, bwb_cmdtable[i].name ) == 0 )
          {
              /* FOUND */
              /* ENABLE COMMAND */
              bwb_cmdtable[i].OptionVersionBitmask |= OptionVersion;
              IsFound = TRUE;
          }
      }
   }
   if( IsFound == FALSE )
   {
       /* display warning message */
       sprintf( bwb_ebuf, "IGNORED: %s", l->buffer);      
       puts(bwb_ebuf);
   }
   return bwb_zline(l);
}


struct bwb_line *
bwb_OPTION_ENABLE_FUNCTION(struct bwb_line * l)
{
   /* OPTION ENABLE FUNCTION ... */
   int             IsFound;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   IsFound = FALSE;
   /* Get FUNCTION */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   {
      /* Name */
      int i;
      for( i = 0; i < NUM_FUNCTIONS; i++ )
      {
          if( strcasecmp( tbuf, bwb_prefuncs[i].Name ) == 0 )
          {
              /* FOUND */
              /* ENABLE FUNCTION */
              bwb_prefuncs[i].OptionVersionBitmask |= OptionVersion;
              IsFound = TRUE;
          }
      }
   }
   if( IsFound == FALSE )
   {
       /* display warning message */
       sprintf( bwb_ebuf, "IGNORED: %s", l->buffer);      
       puts(bwb_ebuf);
   }
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ENABLE_OPERATOR(struct bwb_line * l)
{
   /* OPTION ENABLE OPERATOR ... */
   int             IsFound;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   IsFound = FALSE;
   /* Get OPERATOR */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   {
      /* Name */
      int i;
      for( i = 0; i < NUM_OPERATORS; i++ )
      {
          if( strcasecmp( tbuf, exp_ops[i].symbol ) == 0 )
          {
              /* FOUND */
              /* ENABLE OPERATOR */
              exp_ops[i].OptionVersionBitmask |= OptionVersion;
              IsFound = TRUE;
          }
      }
   }
   if( IsFound == FALSE )
   {
       /* display warning message */
       sprintf( bwb_ebuf, "IGNORED: %s", l->buffer);      
       puts(bwb_ebuf);
   }
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ERROR_GOSUB(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION ERROR GOSUB */
   OptionFlags |= OPTION_ERROR_GOSUB;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_ERROR_GOTO(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION ERROR GOTO */
   OptionFlags &= ~OPTION_ERROR_GOSUB;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_INDENT(struct bwb_line * l)
{
   /* OPTION VERSION ... */
   char            tbuf[BasicStringLengthMax + 1];
   struct exp_ese *e;
   int             pos;

   /* Get starting position (expression) */
   adv_element(l->buffer, &(l->position), tbuf);
   pos = 0;
   e = bwb_exp(tbuf, FALSE, &pos);
   if (ERROR_PENDING)
   {
      return bwb_zline(l);
   }
   if (e->type == STRING)
   {
      sprintf(bwb_ebuf, "Type Mismatch");
      bwb_error(bwb_ebuf);
      return bwb_zline(l);
   }
   OptionIndentValue = exp_getival(e);
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_LABELS_ON(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION LABELS ON */
   OptionFlags |= OPTION_LABELS_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_LABELS_OFF(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION LABELS OFF */
   OptionFlags &= ~OPTION_LABELS_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_STATEMENT(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION STATEMENT char */
   OptionStatementChar = l->buffer[l->position];
   if( OptionStatementChar != '\0' )
   {
      l->position++;
   }
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_STRICT_ON(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION STRICT ON */
   OptionFlags |= OPTION_STRICT_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_STRICT_OFF(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION STRICT OFF */
   OptionFlags &= ~OPTION_STRICT_ON;
   return bwb_zline(l);
}


struct bwb_line *
bwb_OPTION_TERMINAL_NONE(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION TERMINAL NONE */
   OptionTerminalType = C_OPTION_TERMINAL_NONE;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_TERMINAL_ADM_3A(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION TERMINAL ADM-3A */
   OptionTerminalType = C_OPTION_TERMINAL_ADM_3A;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_TERMINAL_ANSI(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION TERMINAL ANSI */
   OptionTerminalType = C_OPTION_TERMINAL_ANSI;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_TIME(struct bwb_line * l)
{
   /* OPTION TIME format */
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);
   /* Get FORMAT */
   adv_element(l->buffer, &(l->position), tbuf);
   StripQuotes( tbuf );
   tbuf[80] = '\0';
   strcpy( OptionTimeFormat, tbuf );
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_TRACE_ON(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION TRACE ON */
   OptionFlags |= OPTION_TRACE_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_TRACE_OFF(struct bwb_line * l)
{
   bwx_DEBUG(__FUNCTION__);
   /* OPTION TRACE OFF */
   OptionFlags &= ~OPTION_TRACE_ON;
   return bwb_zline(l);
}

struct bwb_line *
bwb_OPTION_VERSION(struct bwb_line * l)
{
   /* OPTION VERSION ... */
   char            tbuf[BasicStringLengthMax + 1];
   int             i;


   bwx_DEBUG(__FUNCTION__);



   adv_element(l->buffer, &(l->position), tbuf);
   for (i = 0; i < NUM_VERSIONS; i++)
   {
      if (strcasecmp(tbuf, bwb_vertable[i].Name) == 0)
      {
         /* FOUND */
         OptionVersionSet(i);
         return bwb_zline(l);
      }
   }
   /* NOT FOUND */
   sprintf(bwb_ebuf, "OPTION VERSION %s IS INVALID.  VALID CHOICES ARE:", tbuf);
   puts(bwb_ebuf);
   for (i = 0; i < NUM_VERSIONS; i++)
   {
      sprintf(bwb_ebuf, "OPTION VERSION %s ' %s",
         bwb_vertable[i].Name, bwb_vertable[i].Description);
      puts(bwb_ebuf);
   }
   return bwb_zline(l);
}

/***************************************************************
  
        FUNCTION:       var_findnval()
  
        DESCRIPTION:    This function returns the address of
                        the number for the variable <v>.  If
                        <v> is a dimensioned array, the address
                        returned is for the BasicNumberType at the
                        position indicated by the integer array
                        <pp>.
  
***************************************************************/


BasicNumberType *
var_findnval(struct bwb_variable * v, int *pp)
{
   size_t          offset;
   BasicNumberType *p;

   bwx_DEBUG(__FUNCTION__);
   /* Check for appropriate type */

   if (v->type != NUMBER)
   {
      sprintf(bwb_ebuf, "in var_findnval(): Variable <%s> is not a number.",
         v->name);
      bwb_error(bwb_ebuf);
      return NULL;
   }
   /* Check subscripts */

   if (dim_check(v, pp) == FALSE)
   {
      return NULL;
   }
   /* Calculate and return the address of the dimensioned array */

   offset = dim_unit(v, pp);


   p = v->memnum;
   return (p + offset);

}

/***************************************************************
  
        FUNCTION:       var_findsval()
  
        DESCRIPTION:    This function returns the address of
                        the string for the variable <v>.  If
                        <v> is a dimensioned array, the address
                        returned is for the string at the
                        position indicated by the integer array
                        <pp>.
  
***************************************************************/

bstring        *
var_findsval(struct bwb_variable * v, int *pp)
{
   size_t          offset;
   bstring        *p;

   bwx_DEBUG(__FUNCTION__);

   /* Check for appropriate type */

   if (v->type != STRING)
   {
      sprintf(bwb_ebuf, "in var_findsval(): Variable <%s> is not a string.", v->name);
      bwb_error(bwb_ebuf);
      return NULL;
   }
   /* Check subscripts */

   if (dim_check(v, pp) == FALSE)
   {
      return NULL;
   }
   /* Calculate and return the address of the dimensioned array */

   offset = dim_unit(v, pp);


   p = v->memstr;
   return (p + offset);

}

/***************************************************************
  
        FUNCTION:       dim_check()
  
        DESCRIPTION:    This function checks subscripts of a
                        specific variable to be sure that they
                        are within the correct range.
  
***************************************************************/

static int
dim_check(struct bwb_variable * v, int *pp)
{
   register int    n;

   /* Check for dimensions */

   if (v->dimensions < 1)
   {
      sprintf(bwb_ebuf, "in dim_check(): var <%s> dimensions <%d>",
         v->name, v->dimensions);
      bwb_error(bwb_ebuf);
      return FALSE;
   }
   /* Check for validly allocated array */

   if ((v->type == NUMBER) && (v->memnum == NULL))
   {
      sprintf(bwb_ebuf, "in dim_check(): numerical var <%s> memnum not allocated",
         v->name);
      bwb_error(bwb_ebuf);
      return FALSE;
   }
   if ((v->type == STRING) && (v->memstr == NULL))
   {
      sprintf(bwb_ebuf, "in dim_check(): string var <%s> memstr not allocated",
         v->name);
      bwb_error(bwb_ebuf);
      return FALSE;
   }
   /* Now check subscript values */

   for (n = 0; n < v->dimensions; ++n)
   {


      if ((pp[n] < dim_base) || ((pp[n] + (1 - dim_base)) > v->array_sizes[n]))
      {

         sprintf(bwb_ebuf, "SUBSCRIPT OUT OF RANGE %s(%d)", v->name, pp[n]);
         bwb_error(bwb_ebuf);


         return FALSE;
      }
   }

   /* No problems found */

   return TRUE;

}

/***************************************************************
  
        FUNCTION:       var_make()
  
        DESCRIPTION: This function initializes a variable,
            allocating necessary memory for it.
  
***************************************************************/

int
var_make(struct bwb_variable * v, int type)
{
   bwx_DEBUG(__FUNCTION__);

   switch (type)
   {
   case STRING:
      v->type = STRING;
      break;
   default:
      v->type = NUMBER;
      break;
   }

   /* get memory for array */

   /* First kleanup the joint (JBV) */
   if (v->memnum != NULL)
   {
      /* Revised to FREE pass-thru call by JBV */
      FREE(v->memnum, "var_make");
      v->memnum = NULL;
   }
   if (v->memstr != NULL)
   {
      /* Remember to deallocate those far-flung branches! (JBV) */
      bstring        *sp;  /* JBV */
      register int    n;   /* JBV */

      sp = v->memstr;
      for (n = 0; n < (int) v->array_units; ++n)
      {
         if (sp[n].sbuffer != NULL)
         {
            /* Revised to FREE pass-thru call by JBV */
            FREE(sp[n].sbuffer, "var_make");
            sp[n].sbuffer = NULL;
         }
         sp[n].rab = FALSE;
         sp[n].length = 0;
      }
      /* Revised to FREE pass-thru call by JBV */
      FREE(v->memstr, "var_make");
      v->memstr = NULL;
   }
   /* Revised to FREE pass-thru calls by JBV */
   if (v->array_sizes != NULL)
   {
      FREE(v->array_sizes, "var_make");
      v->array_sizes = NULL;  /* JBV */
   }
   if (v->array_pos != NULL)
   {
      FREE(v->array_pos, "var_make");
      v->array_pos = NULL; /* JBV */
   }
   if (v->type == NUMBER)
   {
      /* Revised to CALLOC pass-thru call by JBV */
      if ((v->memnum = CALLOC(2, sizeof(BasicNumberType), "var_make")) == NULL)
      {
         bwb_error(err_getmem);
         return FALSE;
      }
   }
   else
   {
      /* Revised to CALLOC pass-thru call by JBV */
      if ((v->memstr = CALLOC(2, sizeof(bstring), "var_make")) == NULL)
      {
         bwb_error(err_getmem);
         return FALSE;
      }
   }

   /* get memory for array_sizes and array_pos */

   /* Revised to CALLOC pass-thru call by JBV */
   if ((v->array_sizes = (int *) CALLOC(2, sizeof(int), "var_make")) == NULL)
   {
      bwb_error(err_getmem);
      return FALSE;
   }
   /* Revised to CALLOC pass-thru call by JBV */
   if ((v->array_pos = (int *) CALLOC(2, sizeof(int), "var_make")) == NULL)
   {
      bwb_error(err_getmem);
      return FALSE;
   }
   v->array_pos[0] = dim_base;
   v->array_sizes[0] = 1;
   v->dimensions = 1;
   v->common = FALSE;
   v->array_units = 1;
   v->IsInDim = 0;

   if (type == STRING)
   {
      bstring        *b;


      b = var_findsval(v, v->array_pos);
      b->rab = FALSE;
   }
   return TRUE;

}

/***************************************************************
  
   FUNCTION:       var_islocal()
  
   DESCRIPTION:    This function determines whether the string
         pointed to by 'buffer' has the name of
         a local variable at the present EXEC stack
         level.
  
***************************************************************/

static struct bwb_variable *
var_islocal(char *buffer)
{
   struct bwb_variable *v;

   bwx_DEBUG(__FUNCTION__);

   /* Prevent the expression in the initial value of the for loop below
    * from violating the lower bound of the "excs" array. This would
    * happen during startup when "exsc" is initially set to -1 and
    * bwbasic.exe would fail with a memory exception when compiled with
    * Open Watcom C. */


   if (CURTASK exsc >= 0)
   {
      int             i;
      for (i = CURTASK exsc; i >= 0; i--)
      {
         for (v = CURTASK excs[i].local_variable; v != NULL; v = v->next)
         {
            if (strcasecmp(v->name, buffer) == 0)
            {
               /* FOUND */
               return v;
            }
         }
         if (CURTASK excs[i].LoopTopLine != NULL)
         {
            switch (CURTASK excs[i].LoopTopLine->cmdnum)
            {
            case C_FUNCTION:
            case C_SUB:
               /* we have checked all the way to a
                * FUNCTION or SUB boundary */
               /* NOT FOUND */
               return NULL;
               break;
            }
         }
      }
   }
   /* NOT FOUND */

   return NULL;

}

/***************************************************************
  
        FUNCTION:       bwb_vars()
  
        DESCRIPTION:    This function implements the Bywater-
            specific debugging command VARS, which
            gives a list of all variables defined
            in memory.
  
***************************************************************/


struct bwb_line *
bwb_VARS(struct bwb_line * l)
{
   struct bwb_variable *v;
   char            tbuf[BasicStringLengthMax + 1];

   bwx_DEBUG(__FUNCTION__);

   /* run through the variable list and print variables */

   for (v = CURTASK var_start.next; v != &CURTASK var_end; v = v->next)
   {
      sprintf(bwb_ebuf, "variable <%s>\t", v->name);
      prn_xprintf(bwb_ebuf);
      switch (v->type)
      {
      case STRING:
         str_btoc(tbuf, var_getsval(v));
         sprintf(bwb_ebuf, "STRING\tval: <%s>\n", tbuf);
         prn_xprintf(bwb_ebuf);
         break;
      case NUMBER:
         sprintf(bwb_ebuf, "NUMBER\tval: <" BasicNumberPrintFormat ">\n", var_getnval(v));
         prn_xprintf(bwb_ebuf);
         break;
      default:
         sprintf(bwb_ebuf, "ERROR: type is <%c>", (char) v->type);
         prn_xprintf(bwb_ebuf);
         break;
      }
   }

   return bwb_zline(l);
}


/* EOF */
