/***************************************************************

        bwb_var.c       Variable-Handling Routines
                        for Bywater BASIC Interpreter

                        Commands:	DIM
                                        COMMON
                                        ERASE
                                        SWAP
					CLEAR

                        Copyright (c) 1992, Ted A. Campbell

                        Bywater Software
                        P. O. Box 4023
                        Duke Station
                        Durham, NC  27706

                        email: tcamp@acpub.duke.edu

        Copyright and Permissions Information:

        All U.S. and international copyrights are claimed by the
        author. The author grants permission to use this code
        and software based on it under the following conditions:
        (a) in general, the code and software based upon it may be
        used by individuals and by non-profit organizations; (b) it
        may also be utilized by governmental agencies in any country,
        with the exception of military agencies; (c) the code and/or
        software based upon it may not be sold for a profit without
        an explicit and specific permission from the author, except
        that a minimal fee may be charged for media on which it is
        copied, and for copying and handling; (d) the code must be
        distributed in the form in which it has been released by the
        author; and (e) the code and software based upon it may not
        be used for illegal activities.

***************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#include "bwbasic.h"
#include "bwb_mes.h"

struct bwb_variable var_start, var_end;

int dim_base = 0;                        	/* set by OPTION BASE */
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 );

/***************************************************************

        FUNCTION:       var_init()

        DESCRIPTION:	This function initializes the internal 
        linked list of variables.

***************************************************************/

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

/***************************************************************

        FUNCTION:       bwb_common()

        DESCRIPTION:	This C function implements the BASIC
        		COMMON command.

***************************************************************/

struct bwb_line *
bwb_common( struct bwb_line *l )
   {   
   register int loop;
   struct bwb_variable *v;
   char tbuf[ MAXSTRINGSIZE + 1 ];

   /* 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 l;
         }

      v->common = TRUE;				/* set common flag to true */

      /* check for comma */

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

      }

   }

/***********************************************************

        Function:	bwb_ddbl()

        This function implements the BASIC DEFDBL command.

***********************************************************/

struct bwb_line *
bwb_ddbl( struct bwb_line *l )
   {
 
   /* call generalized DEF handler with DOUBLE set */

   var_defx( l, DOUBLE );
   
   return l;

   }

/***********************************************************

        Function:	bwb_dint()

        This function implements the BASIC DEFINT command.

***********************************************************/

struct bwb_line *
bwb_dint( struct bwb_line *l )
   {

   /* call generalized DEF handler with INTEGER set */

   var_defx( l, INTEGER );
   
   return l;

   }

/***********************************************************

        Function:	bwb_dsng()

        This function implements the BASIC DEFSNG command.

***********************************************************/

struct bwb_line *
bwb_dsng( struct bwb_line *l )
   {

   /* call generalized DEF handler with SINGLE set */

   var_defx( l, SINGLE );
   
   return l;

   }

/***********************************************************

        Function:	bwb_dstr()

        This function implements the BASIC DEFSTR command.

***********************************************************/

struct bwb_line *
bwb_dstr( struct bwb_line *l )
   {

   /* call generalized DEF handler with STRING set */

   var_defx( l, STRING );
   
   return l;

   }

/***********************************************************

        Function:	var_defx()

        This function is a generalized DEFxxx handler.

***********************************************************/

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

   /* 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 '\n':
         case '\r':
         case '\0':
         case ':':
            return FALSE;
         }

      /* find a sequence of letters for variables */

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

      for ( c = first; c <= last; ++c )
         {
         vname[ 0 ] = (char) c;
         vname[ 1 ] = '\0';
         
#if INTENSIVE_DEBUG
         sprintf( bwb_ebuf, "in var_defx(): calling var_find() for <%s>",
            vname );
         bwb_debug( bwb_ebuf );
#endif

         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 );

         }

      }
   
   return TRUE;

   }

/***********************************************************

        Function:	var_letseq()

        This function finds a sequence of letters for a DEFxxx
        command.

***********************************************************/

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

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in var_letseq(): buffer <%s>", &( buffer[ *position ] ));
   bwb_debug( bwb_ebuf );
#endif

   /* advance beyond whitespace */

   adv_ws( buffer, position );

   /* check for end of line */

   switch( buffer[ *position ] )
      {
      case '\0':
      case '\n':
      case '\r':
      case ':':
         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_clear()

        This function implements the BASIC CLEAR command.

***********************************************************/

struct bwb_line *
bwb_clear( struct bwb_line *l )
   {
   struct bwb_variable *v;
   register int n;
   int *ip;
   bstring *sp;
   float *fp;
   double *dp;
   
   for ( v = var_start.next; v != &var_end; v = v->next )
      {
      switch( v->type )
         {
         case SINGLE:
            fp = (float *) v->array;
            for ( n = 0; n < v->array_units; ++n )
               {
               fp[ n ] = (float) 0.0;
               }
            break;
         case DOUBLE:
            dp = (double *) v->array;
            for ( n = 0; n < v->array_units; ++n )
               {
               dp[ n ] = (double) 0.0;
               }
            break;
         case INTEGER:
            ip = (int *) v->array;
            for ( n = 0; n < v->array_units; ++n )
               {
               ip[ n ] = 0;
               }
            break;
         case STRING:
            sp = (bstring *) v->array;
            for ( n = 0; n < v->array_units; ++n )
               {
               if ( sp[ n ].buffer != NULL )
                  {
                  free( sp[ n ].buffer );
                  sp[ n ].buffer = NULL;
                  }
               sp[ n ].rab = FALSE;
               sp[ n ].length = 0;
               }
            break;
         }
      }

   return l;

   }

/***********************************************************

        Function:	var_delcvars()

        This function deletes all variables in memory except
        those previously marked as common.

***********************************************************/

int
var_delcvars()
   {
   struct bwb_variable *v;
   struct bwb_variable *p;		/* previous variable */

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

      if ( v->common != TRUE )
         {

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

         if ( v->dimensions > 0 )
            {

            /* deallocate memory */

            free( v->array_sizes );
            free( v->array_pos );
            free( v->array );

            }

         /* reassign linkage */

         p->next = v->next;

         /* deallocate the variable itself */

         free( v );

         }

      /* else reset previous variable */

      else
         {
         p = v;
         }

      }

   return TRUE;

   }

/***********************************************************

        Function:	bwb_erase()

        This function implements the BASIC ERASE command.

***********************************************************/

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[ MAXSTRINGSIZE + 1 ];

   /* 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 l;
         }

      /* be sure the variable is dimensioned */

      if (( v->dimensions < 1 ) || ( v->array_sizes[ 0 ] < 1 ))
	 {
	 bwb_error( err_dimnotarray );
	 return l;
         }

      /* find previous variable in chain */

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

      /* reassign linkage */

      p->next = v->next;

      /* deallocate memory */

      free( v->array_sizes );
      free( v->array_pos );
      free( v->array );
      free( v );

      /* check for comma */

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

      }

   }

/***********************************************************

        Function:	bwb_swap()

        This function implements the BASIC SWAP command.

***********************************************************/

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

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_swap(): buffer is <%s>",
      &( l->buffer[ l->position ] ) );
   bwb_debug( bwb_ebuf );
#endif

   /* get left variable name and find variable */

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

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_swap(): tbuf is <%s>", tbuf );
   bwb_debug( bwb_ebuf );
#endif

   if ( ( lhs = var_find( tbuf ) ) == NULL )
      {
      bwb_error( err_syntax );
      return l;
      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_swap(): lhs variable <%s> found",
      lhs->name );
   bwb_debug( bwb_ebuf );
#endif

   /* check for comma */

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

   /* get right variable name */

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_swap(): buffer is now <%s>",
      &( l->buffer[ l->position ] ) );
   bwb_debug( bwb_ebuf );
#endif

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

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_swap(): tbuf is <%s>", tbuf );
   bwb_debug( bwb_ebuf );
#endif

   if ( ( rhs = var_find( tbuf ) ) == NULL )
      {
      bwb_error( err_syntax );
      return l;
      }

   /* check to be sure that both variables are of the same type */

   if ( rhs->type != lhs->type )
      {
      bwb_error( err_mismatch );
      return l;
      }

   /* copy lhs to temp, rhs to lhs, then temp to rhs */

   memcpy( &v,  lhs, sizeof( struct bwb_variable ));
   memcpy( lhs, rhs, sizeof( struct bwb_variable ));
   memcpy( rhs, &v,  sizeof( struct bwb_variable ));

   /* return */

   return l;

   }

/***********************************************************

        bwb_const()

        This function takes the string in lb (the large buffer),
        finds a string constant (beginning and ending with 
        quotation marks), and returns it in sb (the small
        buffer), appropriately incrementing the integer
        pointed to by n. The string in lb should NOT include
        the initial quotation mark.

***********************************************************/

bwb_const( char *lb, char *sb, int *n )
   {
   register int s;

   ++*n;                        /* advance past quotation mark */
   s = 0;

   while ( TRUE )
      {
      switch ( lb[ *n ] )
         {
         case '\"':
            sb[ s ] = 0;
            ++*n;               /* advance past ending quotation mark */
            return TRUE;
         case '\n':
         case '\r':
         case 0:
            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 */
      }

   }

/***********************************************************

        bwb_getvarname()

        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.

***********************************************************/

bwb_getvarname( char *lb, char *sb, int *n )
   {
   register int s;

   s = 0;

   /* advance beyond whitespace */

   adv_ws( lb, n );

   while ( TRUE )
      {
      switch ( lb[ *n ] )
         {
         case ' ':              /* whitespace */
         case '\t':
         case '\n':             /* end of string */
         case '\r':
         case 0:
         case ':':              /* end of expression */
         case ',':
         case ';':
         case '(':              /* beginning of parameter list for dimensioned array */
         case '+':              /* add variables */
            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 */

#if INTENSIVE_DEBUG
      sprintf( bwb_ebuf, "in bwb_getvarname(): found <%s>", sb );
      bwb_debug( bwb_ebuf );
#endif
      }

   }

/***************************************************************

        FUNCTION:       var_find()

        DESCRIPTION:

***************************************************************/

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

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in var_find(): received <%s>", buffer );
   bwb_debug( bwb_ebuf );
#endif

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

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

      if ( strcmp( v->name, buffer ) == 0 )
         {
         switch( v->type )
            {
            case STRING:
            case DOUBLE:
            case INTEGER:
            case SINGLE:
               break;
            default:
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in var_find(): inappropriate precision for variable <%s>",
                  v->name );
               bwb_error( bwb_ebuf );
#endif
               break;
            }
#if INTENSIVE_DEBUG
         sprintf( bwb_ebuf, "in var_find(): found existing variable <%s>", v->name );
         bwb_debug( bwb_ebuf );
#endif

         return v;
         }

      }

   /* presume this is a new variable, so initialize it... */
   /* check for NULL variable name */

   if ( strlen( buffer ) == 0 )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "in var_find(): NULL variable name received\n" );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_syntax );
#endif
      return NULL;
      }

   /* get memory for new variable */

   if ( ( v = (struct bwb_variable *) calloc( 1, sizeof( struct bwb_variable ) )) 
      == NULL )
      {
      bwb_error( err_getmem );
      return NULL;
      }

   /* get memory for new variable name */

#if ALLOCATE_NAME
   if ( ( v->name = (char *) calloc( 1, strlen( buffer ) + 1 )) 
      == NULL )
      {
      bwb_error( err_getmem );
      return NULL;
      }
#endif

   /* copy the name into the appropriate structure */

   strcpy( v->name, buffer );

   /* set memory in the new variable */

   var_make( v, (int) v->name[ strlen( v->name ) - 1 ] );

   /* set place at beginning of variable chain */

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

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in var_find(): initialized new variable <%s> type <%c>, dim <%d>",
      v->name, v->type, v->dimensions );
   bwb_debug( bwb_ebuf );
#endif

   return v;

   }

/***************************************************************

        FUNCTION:       bwb_isvar()

        DESCRIPTION:

***************************************************************/

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

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

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

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

      }

   /* search failed */

   return FALSE;

   }

/***************************************************************

        FUNCTION:   var_getdval()

        DESCRIPTION:  This function returns the current value of
        the variable argument as a double precision number.

***************************************************************/

double
var_getdval( struct bwb_variable *nvar )
   {

   switch( nvar->type )
      {
      case DOUBLE:
         return *( var_finddval( nvar, nvar->array_pos ) );
      case SINGLE:
         return (double) *( var_findfval( nvar, nvar->array_pos ) );
      case INTEGER:
         return (double) *( var_findival( nvar, nvar->array_pos ) );
      }

#if PROG_ERRORS
   sprintf( bwb_ebuf, "in var_getdval(): type is <%d>=<%c>.",
      nvar->type, nvar->type );
   bwb_error( bwb_ebuf );
#else
   bwb_error( err_mismatch );
#endif


   return (double) 0.0;

   }

/***************************************************************

        FUNCTION:   var_getfval()

        DESCRIPTION:  This function returns the current value of
        the variable argument as a single precision number (float).

***************************************************************/

float
var_getfval( struct bwb_variable *nvar )
   {

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in var_getfval(): variable <%s>, type <%c>",
      nvar->name, nvar->type );
   bwb_debug( bwb_ebuf );
#endif

   switch( nvar->type )
      {
      case DOUBLE:
         return (float) *( var_finddval( nvar, nvar->array_pos ) );
      case SINGLE:
         return *( var_findfval( nvar, nvar->array_pos ) );
      case INTEGER:
         return (float) *( var_findival( nvar, nvar->array_pos ) );
      }

#if PROG_ERRORS
   sprintf( bwb_ebuf, "in var_getfval(): type is <%d>=<%c>.",
      nvar->type, nvar->type );
   bwb_error( bwb_ebuf );
#else
   bwb_error( err_mismatch );
#endif

   return (float) 0.0;

   }

/***************************************************************

        FUNCTION:   var_getival()

        DESCRIPTION:  This function returns the current value of
        the variable argument as an integer.

***************************************************************/

int
var_getival( struct bwb_variable *nvar )
   {

   switch( nvar->type )
      {
      case DOUBLE:
         return (int) *( var_finddval( nvar, nvar->array_pos ) );
      case SINGLE:

#if INTENSIVE_DEBUG
         sprintf( bwb_ebuf, "in var_getival(): float <%f> -> int <%d>",
            nvar->fval, (int) nvar->fval );
         bwb_debug( bwb_ebuf );
#endif

         return (int) *( var_findfval( nvar, nvar->array_pos ) );
      case INTEGER:
         return *( var_findival( nvar, nvar->array_pos ) );
      }

#if PROG_ERRORS
   sprintf( bwb_ebuf, "in var_getival(): type is <%d>=<%c>.",
      nvar->type, nvar->type );
   bwb_error( bwb_ebuf );
#else
   bwb_error( err_mismatch );
#endif

   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;

   b.rab = FALSE;

   switch( nvar->type )
      {
      case STRING:
         return var_findsval( nvar, nvar->array_pos );
      case DOUBLE:
         sprintf( bwb_ebuf, "%*f ", prn_precision( nvar ),
            *( var_finddval( nvar, nvar->array_pos ) ) );
         str_ctob( &b, bwb_ebuf );
         return &b;
      case SINGLE:
         sprintf( bwb_ebuf, "%*f ", prn_precision( nvar ),
            *( var_findfval( nvar, nvar->array_pos ) ) );
         str_ctob( &b, bwb_ebuf );
         return &b;
      case INTEGER:
         sprintf( bwb_ebuf, "%d ", *( var_findival( nvar, nvar->array_pos ) ) );
         str_ctob( &b, bwb_ebuf );
         return &b;
      default:
#if PROG_ERRORS
         sprintf( bwb_ebuf, "in var_getsval(): type is <%d>=<%c>.",
            nvar->type, nvar->type );
         bwb_error( bwb_ebuf );
#else
         bwb_error( err_mismatch );
#endif
         return NULL;
      }

   }

/***************************************************************

        FUNCTION:       bwb_dim()

        DESCRIPTION:    This function implements the BASIC DIM
                        statement, allocating memory for a
                        dimensioned array of variables.

***************************************************************/

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;
   double *d;
   float *f;
   int *i;
   int loop;
   int old_name, old_dimensions;
   char tbuf[ MAXSTRINGSIZE + 1 ];

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_dim(): entered function." );
   bwb_debug( bwb_ebuf );
#endif

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

      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 )
         {
#if INTENSIVE_DEBUG
         sprintf( bwb_ebuf, "in bwb_dim(): variable name is already used.",
            l->number );
         bwb_debug( bwb_ebuf );
#endif
         old_name = TRUE;
         }

      /* get the new variable */

      newvar = var_find( tbuf );

#if INTENSIVE_DEBUG
      sprintf( bwb_ebuf, "in bwb_dim(): new variable name is <%s>.",
         newvar->name );
      bwb_debug( bwb_ebuf );
#endif

      /* 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 )
            {
#if PROG_ERRORS
            sprintf( bwb_ebuf, "in bwb_dim(): variable <%s> cannot be re-dimensioned",
               newvar->name );
            bwb_error( bwb_ebuf );
#else
            bwb_error( err_redim );
#endif
            }

         /* check to be sure sizes for the old variable are the same */

         for ( n = 0; n < newvar->dimensions; ++n )
            {
#if INTENSIVE_DEBUG
            sprintf( bwb_ebuf, "in bwb_dim(): old var <%s> parameter <%d> size <%d>.",
               newvar->name, n, pp[ n ] );
            bwb_debug( bwb_ebuf );
#endif
            if ( ( pp[ n ] + ( 1 - dim_base )) != newvar->array_sizes[ n ] )
               {
#if PROG_ERRORS
               sprintf( bwb_ebuf, "in bwb_dim(): variable <%s> parameter <%d> cannot be resized",
                  newvar->name, n );
               bwb_error( bwb_ebuf );
#else
               bwb_error( err_redim );
#endif
               }
            }

         }         /* end of conditional for old variable */


      /* a new variable */

      else
         {

         /* assign memory for parameters */

         if ( ( newvar->array_sizes = (int *) calloc( n_params, sizeof( int )  )) == NULL )
            {
#if PROG_ERRORS
            sprintf( bwb_ebuf, "in line %d: Failed to find memory for array_sizes for <%s>",
               l->number, newvar->name );
            bwb_error( bwb_ebuf );
#else
            bwb_error( err_getmem );
#endif
            l->next->position = 0;
            return l->next;
            }

         for ( n = 0; n < newvar->dimensions; ++n )
            {
            newvar->array_sizes[ n ] = pp[ n ] + ( 1 - dim_base );
#if INTENSIVE_DEBUG
            sprintf( bwb_ebuf, "in bwb_dim(): array_sizes dim <%d> value <%d>",
               n, newvar->array_sizes[ n ] );
            bwb_debug( bwb_ebuf );
#endif
            }

         /* assign memory for current position */

         if ( ( newvar->array_pos = (int *) calloc( n_params, sizeof( int ) )) == NULL )
            {
#if PROG_ERRORS
            sprintf( bwb_ebuf, "in line %d: Failed to find memory for array_pos for <%s>",
               l->number, newvar->name );
            bwb_error( bwb_ebuf );
#else
            bwb_error( err_getmem );
#endif
            l->next->position = 0;
            return l->next;
            }

         for ( n = 0; n < newvar->dimensions; ++n )
            {
            newvar->array_pos[ n ] = dim_base;
            }

         /* calculate the array size */

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

#if INTENSIVE_DEBUG
         sprintf( bwb_ebuf, "in bwb_dim(): array memory requires <%ld> units",
            (long) newvar->array_units );
         bwb_debug( bwb_ebuf );
#endif

         /* assign array memory */

         switch( newvar->type )
            {
            case STRING:
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in bwb_dim(): 1 STRING requires <%ld> bytes",
                  (long) sizeof( bstring ));
               bwb_debug( bwb_ebuf );
               sprintf( bwb_ebuf, "in bwb_dim(): STRING array memory requires <%ld> bytes",
        	  (long) ( newvar->array_units + 1 ) * sizeof( bstring ));
               bwb_debug( bwb_ebuf );
#endif
               if ( ( newvar->array = (char *) calloc( newvar->array_units, sizeof( bstring) )) == NULL )
                  {
#if PROG_ERRORS
                  sprintf( bwb_ebuf, "in line %d: Failed to find memory for array <%s>",
                     l->number, newvar->name );
                  bwb_error( bwb_ebuf );
#else
                  bwb_error( err_getmem );
#endif
                  l->next->position = 0;
                  return l->next;
                  }
               break;
            case DOUBLE:
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in bwb_dim(): 1 DOUBLE requires <%ld> bytes",
                  (long) sizeof( double ));
               bwb_debug( bwb_ebuf );
               sprintf( bwb_ebuf, "in bwb_dim(): DOUBLE array memory requires <%ld> bytes",
        	  (long) ( newvar->array_units + 1 ) * sizeof( double ));
               bwb_debug( bwb_ebuf );
#endif
               if ( ( d = (double *) calloc( newvar->array_units, sizeof( double ) )) == NULL )
                  {
#if PROG_ERRORS
                  sprintf( bwb_ebuf, "in line %d: Failed to find memory for array <%s>",
                  l->number, newvar->name );
                  bwb_error( bwb_ebuf );
#else
                  bwb_error( err_getmem );
#endif
                  l->next->position = 0;
                  return l->next;
                  }
               newvar->array = (char *) d;
               break;
            case SINGLE:
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in bwb_dim(): 1 SINGLE requires <%ld> bytes",
                  (long) sizeof( float ));
               bwb_debug( bwb_ebuf );
               sprintf( bwb_ebuf, "in bwb_dim(): SINGLE array memory requires <%ld> bytes",
        	  (long) ( newvar->array_units + 1 ) * sizeof( float ));
               bwb_debug( bwb_ebuf );
#endif
               if ( ( f = (float *) calloc( newvar->array_units, sizeof( float ) )) == NULL )
                  {
#if PROG_ERRORS
                  sprintf( bwb_ebuf, "in line %d: Failed to find memory for array <%s>",
                     l->number, newvar->name );
                  bwb_error( bwb_ebuf );
#else
                  bwb_error( err_getmem );
#endif
                  l->next->position = 0;
                  return l->next;
                  }
               newvar->array = (char *) f;
               break;
            case INTEGER:
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in bwb_dim(): 1 INTEGER requires <%ld> bytes",
                  (long) sizeof( int ));
               bwb_debug( bwb_ebuf );
               sprintf( bwb_ebuf, "in bwb_dim(): INTEGER array memory requires <%ld> bytes",
        	  (long) ( newvar->array_units + 1 ) * sizeof( int ));
               bwb_debug( bwb_ebuf );
#endif
               if ( ( i = (int *) calloc( newvar->array_units, sizeof( int ) )) == NULL )
                  {
#if PROG_ERRORS
                  sprintf( bwb_ebuf, "in line %d: Failed to find memory for array <%s>",
                     l->number, newvar->name );
                  bwb_error( bwb_ebuf );
#else
                  bwb_error( err_getmem );
#endif
                  l->next->position = 0;
                  return l->next;
                  }
               newvar->array = (char *) i;
               break;
            default:
#if PROG_ERRORS
               sprintf( bwb_ebuf, "in line %d: New variable has unrecognized type.",
                  l->number );
               bwb_error( bwb_ebuf );
#else
               bwb_error( err_syntax );
#endif
               l->next->position = 0;
               return l->next;
            }

         }			/* 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 ));
      switch( l->buffer[ l->position ] )
         {
         case '\n':			/* end of line */
         case '\r':
         case ':':			/* end of line segment */
         case '\0':			/* end of string */
            loop = FALSE;
            break;
         case ',':
            ++( l->position );
            adv_ws( l->buffer, &( l->position ) );
            loop = TRUE;
            break;
         default:
#if PROG_ERRORS
            sprintf( bwb_ebuf, "in bwb_dim(): unexpected end of string, buf <%s>",
               &( l->buffer[ l->position ] ) );
            bwb_error( bwb_ebuf );
#else
            bwb_error( err_syntax );
#endif
            loop = FALSE;
            break;
         }

      }				/* end of loop through variables */

   /* return */

   l->next->position = 0;
   return l->next;

   }

/***************************************************************

        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;

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

   b = 1;
   r = 0;
   for ( n = 0; n < v->dimensions; ++n )
      {
      r += b * ( pp[ n ] - dim_base );
      b *= v->array_sizes[ n ];
      }

#if INTENSIVE_DEBUG
   for ( n = 0; n < v->dimensions; ++n )
      {
      sprintf( bwb_ebuf,
         "in dim_unit(): variable <%s> pos <%d> val <%d>.",
         v->name, n, pp[ n ] );
      bwb_debug( bwb_ebuf );
      }
   sprintf( bwb_ebuf, "in dim_unit(): return unit: <%ld>", (long) r );
   bwb_debug( bwb_ebuf );
#endif

   if ( r > v->array_units )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "in dim_unit(): unit value <%ld> exceeds array units <%ld>",
         r, v->array_units );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_valoorange );
#endif
      return 0;
      }

   return r;

   }

/***************************************************************

        FUNCTION:       dim_getparams()

        DESCRIPTION:    This fuunction 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( char *buffer, int *pos, int *n_params, int **pp )
   {
   int loop;
   static int params[ MAX_DIMS ];
   int x_pos, s_pos;
   int paren_found;
   register int n;
   struct exp_ese *e;
   char tbuf[ MAXSTRINGSIZE + 1 ];

   /* set initial values */

   *n_params = 0;
   paren_found = FALSE;

   /* find open parenthesis */

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

#if INTENSIVE_DEBUG
      sprintf( bwb_ebuf, "in dim_getparams(): eval char <%c = 0x%x>",
         buffer[ *pos ], buffer[ *pos ] );
      bwb_debug( bwb_ebuf );
#endif

      switch( buffer[ *pos ] )
         {
         case '\0':                     /* end of line */
         case '\n':
         case '\r':
#if PROG_ERRORS
            sprintf( bwb_ebuf, "Unexpected end of line in dimensioned variable." );
            bwb_error ( bwb_ebuf );
#else
            bwb_error( err_syntax );
#endif
	    return FALSE;
            break;
         case ' ':                      /* whitespace */
         case '\t':
            if ( paren_found == FALSE )
               {
               ++(*pos);
               *n_params = 1;
               params[ 0 ] = dim_base;
               *pp = params;
               free( tbuf );
               return TRUE;
               }
            else
               {
               ++(*pos);
               }
            break;

         case '(':                      /* the open parenthesis */
            ++(*pos);
            paren_found = TRUE;
            loop = FALSE;
#if INTENSIVE_DEBUG
            sprintf( bwb_ebuf, "in dim_getparams(): open parenthesis found (1)." );
            bwb_debug( bwb_ebuf );
#endif
            break;

         default:			/* any other character */
#if PROG_ERRORS
            sprintf( bwb_ebuf, "in dim_getparams(): illegal char <%c = 0x%x> in dimensioned variable.",
               buffer[ *pos ], buffer[ *pos ] );
            bwb_error ( bwb_ebuf );
#else
            bwb_error( err_syntax );
#endif
	    return FALSE;
         }
      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in dim_getparams(): open parenthesis found (2)." );
   bwb_debug( bwb_ebuf );
#endif

   /* Find each parameter */

   s_pos = 0;
   tbuf[ 0 ] = '\0';
   loop = TRUE;
   while( loop == TRUE )
      {
      switch( buffer[ *pos ] )
         {
         case ')':                      /* end of parameter list */
            x_pos = 0;
            if ( tbuf[ 0 ] == '\0' )
               {
               params[ *n_params ] = DEF_SUBSCRIPT;
               }
            else
               {
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in dim_getparams(): call bwb_exp() for last element" );
               bwb_debug( bwb_ebuf );
#endif
               e = bwb_exp( tbuf, FALSE, &x_pos );
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in dim_getparams(): return from bwb_exp() for last element" );
               bwb_debug( bwb_ebuf );
#endif
               params[ *n_params ] = exp_getival( e );
               }
            ++(*n_params);
            loop = FALSE;
            ++( *pos );
            break;

         case ',':                      /* end of a parameter */
            x_pos = 0;
            if ( tbuf[ 0 ] == '\0' )
               {
               params[ *n_params ] = DEF_SUBSCRIPT;
               }
            else
               {
#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in dim_getparams(): call bwb_exp() for element (not last)" );
               bwb_debug( bwb_ebuf );
#endif
               e = bwb_exp( tbuf, FALSE, &x_pos );
               params[ *n_params ] = exp_getival( e );
               }
            ++(*n_params);
            tbuf[ 0 ] = '\0';
            ++(*pos);
            s_pos = 0;
            break;

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

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

#if INTENSIVE_DEBUG
   for ( n = 0; n < *n_params; ++n )
      {
      sprintf( bwb_ebuf, "in dim_getparams(): Parameter <%d>: <%d>",
         n, params[ n ] );
      bwb_debug( bwb_ebuf );
      }
#endif

   /* 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.

***************************************************************/

struct bwb_line *
bwb_option( struct bwb_line *l )
   {
   register int n;
   int newval;
   struct exp_ese *e;
   struct bwb_variable *current;
   char tbuf[ MAXSTRINGSIZE ];

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_option(): entered function." );
   bwb_debug( bwb_ebuf );
#endif

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

   if ( dimmed != FALSE )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "at line %d: OPTION BASE must be called before DIM.",
         l->number );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_obdim );
#endif
      l->next->position = 0;
      return l->next;
      }

   /* capitalize first element in tbuf */

   adv_element( l->buffer, &( l->position ), tbuf );
   for ( n = 0; tbuf[ n ] != '\0'; ++n )
      {
      if ( islower( tbuf[ n ] ) != FALSE )
         {
         tbuf[ n ] = toupper( tbuf[ n ] );
         }
      }

   /* check for BASE statement */

   if ( strncmp( tbuf, "BASE", (size_t) 4 ) != 0 )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "at line %d: Unknown statement <%s> following OPTION.",
         l->number, tbuf );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_syntax );
#endif
      l->next->position = 0;
      return l->next;
      }

   /* Get new value from argument. */

   adv_ws( l->buffer, &( l->position ) );
   e = bwb_exp( l->buffer, FALSE, &( l->position ) );
   newval = exp_getival( e );

   /* Test the new value. */

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_option(): New value received is <%d>.", newval );
   bwb_debug( bwb_ebuf );
#endif

   if ( ( newval < 0 ) || ( newval > 1 ) )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "at line %d: value for OPTION BASE must be 1 or 0.",
         l->number );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_valoorange );
#endif
      l->next->position = 0;
      return l->next;
      }

   /* 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 = var_start.next; current != &var_end; current = current->next )
      {
      current->array_pos[ 0 ] = dim_base;
      }

   /* Return. */

   l->next->position = 0;
   return l->next;

   }

/***************************************************************

        FUNCTION:       var_findival()

        DESCRIPTION:    This function returns the address of
                        the integer for the variable <v>.  If
                        <v> is a dimensioned array, the address
                        returned is for the integer at the
                        position indicated by the integer array
                        <pp>.

***************************************************************/

int *
var_findival( struct bwb_variable *v, int *pp )
   {
   register int n;
   size_t offset;
   int *p;

   /* Check for appropriate type */

   if ( v->type != INTEGER )
      {
#if PROG_ERRORS
      sprintf ( bwb_ebuf, "in var_findival(): variable <%s> is not an integer.", v->name );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_mismatch );
#endif
      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 );

#if INTENSIVE_DEBUG
   for ( n = 0; n < v->dimensions; ++n )
      {
      sprintf( bwb_ebuf,
         "in var_findival(): dimensioned variable pos <%d> <%d>.",
         n, pp[ n ] );
      bwb_debug( bwb_ebuf );
      }
#endif

   p = (int *) v->array;
   return (p + offset);

   }

/***************************************************************

        FUNCTION:       var_finddval()

        DESCRIPTION:    This function returns the address of
                        the double for the variable <v>.  If
                        <v> is a dimensioned array, the address
                        returned is for the double at the
                        position indicated by the integer array
                        <pp>.

***************************************************************/

double *
var_finddval( struct bwb_variable *v, int *pp )
   {
   register int n;
   size_t offset;
   double *p;

   /* Check for appropriate type */

   if ( v->type != DOUBLE )
      {
#if PROG_ERRORS
      sprintf ( bwb_ebuf, "in var_finddval(): Variable <%s> is not double precision.", 
         v->name );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_mismatch );
#endif
      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 );

#if INTENSIVE_DEBUG
   for ( n = 0; n < v->dimensions; ++n )
      {
      sprintf( bwb_ebuf,
         "in var_finddval(): dimensioned variable pos <%d> <%d>.",
         n, pp[ n ] );
      bwb_debug( bwb_ebuf );
      }
#endif

   p = (double *) v->array;
   return (p + offset);

   }

/***************************************************************

        FUNCTION:       var_findfval()

        DESCRIPTION:    This function returns the address of
                        the float value for the variable <v>.  If
                        <v> is a dimensioned array, the address
                        returned is for the float at the
                        position indicated by the integer array
                        <pp>.

***************************************************************/

float *
var_findfval( struct bwb_variable *v, int *pp )
   {
   register int n;
   size_t offset;
   float *r;
   float *p;

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in var_findfval(): variable <%s>, type <%c>",
      v->name, v->type );
   bwb_debug( bwb_ebuf );
#endif

   /* Check for appropriate type */

   if ( v->type != SINGLE )
      {
#if PROG_ERRORS
      sprintf ( bwb_ebuf, "in var_findfval(): Variable <%s> is not single precision: prec <%c>",
         v->name, v->type );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_mismatch );
#endif
      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 );

#if INTENSIVE_DEBUG
   for ( n = 0; n < v->dimensions; ++n )
      {
      sprintf( bwb_ebuf,
         "in var_findfval(): dimensioned variable <%s> dim <%d> val <%d>.",
         v->name, n, pp[ n ] );
      bwb_debug( bwb_ebuf );
      }
#endif

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf,
      "in var_findfval(): dimensioned variable <%s> offset <%ld>",
      v->name, (long) offset );
      bwb_debug( bwb_ebuf );
#endif

   p = (float *) v->array;
   r = (p + offset);

#if INTENSIVE_DEBUG
   if ( ( r < (float *) v->array ) || ( r > (float *) v->array_max ))
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "in var_findfval(): return value is out of range" );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_valoorange );
#endif
      return r;
      }
#endif

   return r;

   }

/***************************************************************

        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 )
   {
   register int n;
   size_t offset;
   bstring *p;

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in var_findsval(): entered, var <%s>", v->name );
   bwb_debug( bwb_ebuf );
#endif

   /* Check for appropriate type */

   if ( v->type != STRING )
      {
#if PROG_ERRORS
      sprintf ( bwb_ebuf, "in var_findsval(): Variable <%s> is not a string.", v->name );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_mismatch );
#endif
      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 );

#if INTENSIVE_DEBUG
   for ( n = 0; n < v->dimensions; ++n )
      {
      sprintf( bwb_ebuf,
         "in var_findsval(): dimensioned variable pos <%d> val <%d>.",
         n, pp[ n ] );
      bwb_debug( bwb_ebuf );
      }
#endif

   p = (bstring *) v->array;
   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 )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "in dim_check(): var <%s> dimensions <%d>",
         v->name, v->dimensions );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_valoorange );
#endif
      return FALSE;
      }

   /* Check for validly allocated array */

   if ( v->array == NULL )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "in dim_check(): var <%s> array not allocated",
         v->name );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_valoorange );
#endif
      return FALSE;
      }

   /* Now check subscript values */

   for ( n = 0; n < v->dimensions; ++n )
      {
      if ( ( pp[ n ] < dim_base ) || ( ( pp[ n ] - dim_base )
         > v->array_sizes[ n ] ))
         {
#if PROG_ERRORS
         sprintf( bwb_ebuf, "in dim_check(): array subscript var <%s> pos <%d> val <%d> out of range <%d>-<%d>.",
            v->name, n, pp[ n ], dim_base, v->array_sizes[ n ]  );
         bwb_error( bwb_ebuf );
#else
         bwb_error( err_valoorange );
#endif
         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 )
   {
   size_t data_size;
   bstring *b;
#if TEST_BSTRING
   static int tnumber = 0;
#endif

   switch( type )
      {
      case DOUBLE:
         v->type = DOUBLE;
         data_size = sizeof( double );
         break;
      case INTEGER:
         v->type = INTEGER;
         data_size = sizeof( int );
         break;
      case STRING:
         v->type = STRING;
         data_size = sizeof( bstring );
         break;
      default:
         v->type = SINGLE;
         data_size = sizeof( float );
         break;
      }

   /* get memory for array */

   if ( ( v->array = (char *) calloc( 2, data_size )) == NULL )
      {
      bwb_error( err_getmem );
      return FALSE;
      }

   /* get memory for array_sizes and array_pos */

   if ( ( v->array_sizes = (int *) calloc( 2, sizeof( int ) )) == NULL )
      {
      bwb_error( err_getmem );
      return FALSE;
      }

   if ( ( v->array_pos = (int *) calloc( 2, sizeof( int ) )) == 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;

   if ( type == STRING )
      {
      b = var_findsval( v, v->array_pos );
      b->rab = FALSE;      
      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in var_make(): made variable <%s> type <%c> pos[ 0 ] <%d>",
      v->name, v->type, v->array_pos[ 0 ] );
   bwb_debug( bwb_ebuf );
#endif

#if TEST_BSTRING
   if ( type == STRING )
      {
      b = var_findsval( v, v->array_pos );
      sprintf( b->name, "bstring # %d", tnumber );
      ++tnumber;
      sprintf( bwb_ebuf, "in var_make(): new string variable <%s>",
         b->name );
      bwb_debug( bwb_ebuf );
      }
#endif

   return TRUE;

   }

/***************************************************************

        FUNCTION:       bwb_vars()

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

***************************************************************/

#if PERMANENT_DEBUG
struct bwb_line *
bwb_vars( struct bwb_line *l )
   {
   struct bwb_variable *v;
   char tbuf[ MAXSTRINGSIZE + 1 ];

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

   for ( v = var_start.next; v != &var_end; v = v->next )
      {
      fprintf( stdout, "variable <%s>\t", v->name );
      switch( v->type )
         {
         case STRING:
            str_btoc( tbuf, var_getsval( v ) );
            fprintf( stdout, "STRING\tval: <%s>\n", tbuf );
            break;
         case INTEGER:
            fprintf( stdout, "INTEGER\tval: <%d>\n", var_getival( v ) );
            break;
         case DOUBLE:
            fprintf( stdout, "DOUBLE\tval: <%lf>\n", var_getdval( v ) );
            break;
         case SINGLE:
            fprintf( stdout, "SINGLE\tval: <%f>\n", var_getfval( v ) );
            break;
         default:
            fprintf( stdout, "ERROR: type is <%c>", (char) v->type );
            break;
         }
      }

   l->next->position = 0;
   return l->next;
   }
#endif
