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

        bwb_cnd.c       Conditional Expressions and Commands
                        for Bywater BASIC Interpreter

                        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 <math.h>
#include <ctype.h>
#include <string.h>

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

/* global variables visible to this file only */

static struct bwb_line * ws[ WHILELEVELS ];             /* WHILE stack */
int ws_counter = 0;                                     /* WHILE stack counter */

int fs_counter = 0;                                     /* FOR stack counter */

/* declarations of functions visible to this file only */

static int cnd_thenels( char *buffer, int position, int *then, int *els );
static int cnd_tostep( char *buffer, int position, int *to, int *step );
static struct bwb_line *find_wend( struct bwb_line *l );
static int var_setival( struct bwb_variable *v, int i );
static int dec_fsc( int level );

/***    IF-THEN-ELSE ***/

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

        FUNCTION:       bwb_if()

        DESCRIPTION:    This function handles the BASIC IF
                        statement.

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

struct bwb_line *
bwb_if( struct bwb_line *l )
   {
   register int i, n;
   int then, els;
   int pos;
   struct exp_ese *e;
   char tbuf[ MAXSTRINGSIZE + 1 ];
   char then_buffer[ MAXSTRINGSIZE + 1 ];	/* hold THEN statement */
   char elb_buffer[ MAXSTRINGSIZE + 1 ]; 	/* hold ELSE statement */

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_if(): entry, line <%d> buffer <%s>",
      l->number, &( l->buffer[ l->position ] ) );
   bwb_debug( bwb_ebuf );
#endif

   /* Call bwb_exp() to evaluate the condition. This should return
      with position set to the "THEN" statement */

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

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_if(): line <%d> condition returns <%d>",
      l->number, exp_getival( e ) );
   bwb_debug( bwb_ebuf );
#endif

   /* test for "THEN" and "ELSE" statements */

   cnd_thenels( l->buffer, l->position, &then, &els );

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_if(): return from cnd_thenelse, line is <%s>", 
      l->buffer );
   bwb_debug( bwb_ebuf );
#endif

   if ( then != FALSE )
      {
      if ( els != FALSE )
         {
         then_buffer[ 0 ] = '\0';
         n = 0;
         for ( i = (then + 4); i < els; ++i )
            {
            then_buffer[ n ] = l->buffer[ i ];
            ++n;
            then_buffer[ n ] = '\0';
            }
         }
      else
         {
         then_buffer[ 0 ] = '\0';
         n = 0;
         for ( i = (then + 4); l->buffer[ i ] != '\0'; ++i )
            {
            then_buffer[ n ] = l->buffer[ i ];
            ++n;
            then_buffer[ n ] = '\0';
            }
         }

      }

   /* test for THEN line-number */

   pos = 0;
   adv_ws( then_buffer, &pos );
   adv_element( then_buffer, &pos, tbuf );
   if ( ( tbuf[ 0 ] >= '0' ) && ( tbuf[ 0 ] <= '9' ))
      {
      sprintf( tbuf, "GOSUB %s", then_buffer );
      strcpy( then_buffer, tbuf );
      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_if(): THEN statement is <%s>", then_buffer );
   bwb_debug( bwb_ebuf );
#endif

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_if(): found THEN statement, line is <%s>", 
      l->buffer );
   bwb_debug( bwb_ebuf );
#endif

   if ( els != FALSE )
      {
      elb_buffer[ 0 ] = '\0';
      n = 0;
      for ( i = (els + 4); l->buffer[ i ] != '\0'; ++i )
         {
         elb_buffer[ n ] = l->buffer[ i ];
         ++n;
         elb_buffer[ n ] = '\0';
         }

#if INTENSIVE_DEBUG
      sprintf( bwb_ebuf, "in bwb_if(): ELSE statement is <%s>", elb_buffer );
      bwb_debug( bwb_ebuf );
#endif

      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_if(): searched for ELSE statement, line is <%s>", 
      l->buffer );
   bwb_debug( bwb_ebuf );
#endif

   /* evaluate and execute */

   if ( exp_getival( e ) != FALSE )
      {
      if ( then == FALSE )
         {
#if PROG_ERRORS
         sprintf( bwb_ebuf, "IF without THEN" );
         bwb_error( bwb_ebuf );
#else
         bwb_error( err_syntax );
#endif
         }
      else
         {
#if INTENSIVE_DEBUG
	 sprintf( bwb_ebuf, "in bwb_if(): executing then buffer <%s>",
	    then_buffer );
	 bwb_debug( bwb_ebuf );
#endif
	 return cnd_xpline( l, then_buffer );
	 }
      }
   else
      {
      if ( els != FALSE )
         {
#if INTENSIVE_DEBUG
	 sprintf( bwb_ebuf, "in bwb_if(): executing else buffer <%s>",
	    elb_buffer );
	 bwb_debug( bwb_ebuf );
#endif
	 return cnd_xpline( l, elb_buffer );
	 }
      }

   /* if neither then nor else were found */

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

   }

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

        FUNCTION:       cnd_thenelse()

        DESCRIPTION:    This function searches through the
                        <buffer> beginning at point <position>
                        and attempts to find positions of THEN
                        and ELSE statements.

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

static int
cnd_thenels( char *buffer, int position, int *then, int *els )
   {
   int loop, t_pos, b_pos, p_word;
   char tbuf[ MAXSTRINGSIZE + 1 ];

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in cnd_thenelse(): entry, line is <%s>", buffer );
   bwb_debug( bwb_ebuf );
#endif

   /* set then and els to FALSE initially */

   *then = *els = FALSE;

   /* loop to find words */

   p_word = b_pos = position;
   t_pos = 0;
   tbuf[ 0 ] = '\0';
   loop = TRUE;
   while( loop == TRUE )
      {

      switch( buffer[ b_pos ] )
         {
         case '\0':                     /* end of string */
            return TRUE;
         case ' ':                      /* whitespace = end of word */
         case '\t':

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

            if ( strncmp( tbuf, "THEN", (size_t) 4 ) == 0 )
               {

#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in cnd_thenels(): THEN found at position <%d>.",
                  p_word );
               bwb_debug( bwb_ebuf );
               sprintf( bwb_ebuf, "in cnd_thenelse(): after THEN, line is <%s>", buffer );
               bwb_debug( bwb_ebuf );
#endif

               *then = p_word;
               }
            else if ( strncmp( tbuf, "ELSE", (size_t) 4 ) == 0 )
               {

#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in cnd_thenels(): ELSE found at position <%d>.",
                  p_word );
               bwb_debug( bwb_ebuf );
               sprintf( bwb_ebuf, "in cnd_thenelse(): after ELSE, line is <%s>", buffer );
               bwb_debug( bwb_ebuf );
#endif

               *els = p_word;
               }
            ++b_pos;
            p_word = b_pos;
            t_pos = 0;
            tbuf[ 0 ] = '\0';
            break;

         default:
            if ( islower( buffer[ b_pos ] ) != FALSE )
               {
               tbuf[ t_pos ] = toupper( buffer[ b_pos ] );
               }
            else
               {
               tbuf[ t_pos ] = buffer[ b_pos ];
               }
            ++b_pos;
            ++t_pos;
            tbuf[ t_pos ] = '\0';
            break;
         }

      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in cnd_thenelse(): exit, line is <%s>", buffer );
   bwb_debug( bwb_ebuf );
#endif

   return FALSE;

   }

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

        FUNCTION:       cnd_xpline()

        DESCRIPTION:    This function interprets a portion of a
                        command line.

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

struct bwb_line *
cnd_xpline( struct bwb_line *l, char *buffer )
   {
   char l_buffer[ MAXSTRINGSIZE + 1 ];
   struct bwb_line *nl;
   struct bwb_line *rl;

   if ( ( nl = calloc( 1, sizeof( struct bwb_line ) ) ) == NULL )
      {
      bwb_error( err_getmem );
      return l;
      }

   strncpy( l_buffer, buffer, MAXSTRINGSIZE );

   nl->marked = FALSE;
   nl->next = l->next;
   nl->number = l->number;
   nl->position = 0;
   nl->buffer = l_buffer;

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in cnd_xpline(): interpret line portion <%s>",
      nl->buffer );
   bwb_debug( bwb_ebuf );
#endif

   rl = bwb_xline( nl );

   if ( nl->cmdnum == getcmdnum( "GOTO" ) )
      {
      return rl;
      }
   
   else if ( nl->cmdnum == getcmdnum( "GOSUB" ) )
      {
      return rl;
      }
   
   else if ( nl->cmdnum == getcmdnum( "RETURN" ) )
      {
#if INTENSIVE_DEBUG
      sprintf( bwb_ebuf, "in cnd_xpline(): RETURN returning line <%d>",
         rl->number );
      bwb_debug( bwb_ebuf );
#endif

      l->cmdnum = getcmdnum( "RETURN" );
      l->marked = FALSE;

      return rl;
      }
   
   /* in all other cases, return the next line after the current one */

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

   }

/***    WHILE-WEND ***/

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

        FUNCTION:       bwb_while()

        DESCRIPTION:    This function handles the BASIC WHILE
                        statement.

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

struct bwb_line *
bwb_while( struct bwb_line *l )
   {
   register int n;
   struct bwb_line *wendnext;
   struct exp_ese *e;

   /* find the WEND statement */

   wendnext = find_wend( l );
   if ( wendnext == NULL )
      {
      l->next->position = 0;                           /* error routine has already been called */
      return l->next;                           /* error routine has already been called */
      }

   /* call bwb_exp() to interpret the expression */

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

   if ( exp_getival( e ) == TRUE )
      {
      ws[ ws_counter ] = l;
      ++ws_counter;
      l->next->position = 0;
      return l->next;
      }
   else
      {
      wendnext->position = 0;
      return wendnext;
      }

   }

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

        FUNCTION:       bwb_wend()

        DESCRIPTION:    This function handles the BASIC WEND
                        statement.

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

struct bwb_line *
bwb_wend( struct bwb_line *l )
   {

   if ( ws_counter <= 0 )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "in bwb_wend(): WEND without WHILE" );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_syntax  );
#endif
      l->next->position = 0;
      return l->next;
      }

   --ws_counter;
   ws[ ws_counter ]->position = 0;
   return ws[ ws_counter ];
   }

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

        FUNCTION:       find_wend()

        DESCRIPTION:    This function searches for a line containing
                        a WEND statement corresponding to a previous
                        WHILE statement.

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

static struct bwb_line *
find_wend( struct bwb_line *l )
   {
   struct bwb_line *current;
   register int w_level;
   int position;

   w_level = 1;
   for ( current = l->next; current != &bwb_end; current = current->next )
      {
      position = 0;
      line_start( current->buffer, &position, &( current->lnpos ),
         &( current->lnum ),
         &( current->cmdpos ),
         &( current->cmdnum ),
         &( current->startpos ) );
      current->position = current->startpos;

      if ( current->cmdnum > -1 )
         {

         if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_while )
            {
            ++w_level;

#if INTENSIVE_DEBUG
            sprintf( bwb_ebuf, "in bwb_wend(): found WHILE at line %d, level %d",
               current->number, w_level );
            bwb_debug( bwb_ebuf );
#endif

            }
         else if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_wend )
            {
            --w_level;

#if INTENSIVE_DEBUG
            sprintf( bwb_ebuf, "in bwb_wend(): found WEND at line %d, level %d",
               current->number, w_level );
            bwb_debug( bwb_ebuf );
#endif

            if ( w_level == 0 )
               {
               return current->next;
               }
            }
         }
      }

#if PROG_ERRORS
   sprintf( bwb_ebuf, "WHILE without WEND" );
   bwb_error( bwb_ebuf );
#else
   bwb_error( err_syntax  );
#endif

   return NULL;

   }

/***    FOR-NEXT ***/

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

        FUNCTION:       bwb_for()

        DESCRIPTION:    This function handles the BASIC FOR
                        statement.

	LIMITATION:	As implemented here, the NEXT statement
			must be at the beginning of a program
			line; a NEXT statement following a colon
			will not be recognized and may cause the
			program to hang up.

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

struct bwb_line *
bwb_for( struct bwb_line *l )
   {
   register int n;
   int e, loop;
   int to, step, p;
   struct exp_ese *exp;
   struct bwb_variable *v;
   char tbuf[ MAXSTRINGSIZE + 1 ];

   /* get the variable name */

   exp_getvfname( &( l->buffer[ l->startpos ] ), tbuf );
   v = var_find( tbuf );

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

   /* increment the FOR stack counter and check it */

   ++fs_counter;                                /* increment the counter */
   if ( fs_counter >= FORLEVELS )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "Maximum FOR levels exceeded." );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_overflow );
#endif
      l->next->position = 0;
      return l->next;
      }

   /* initialize the FOR stack element for this level */

   fs[ fs_counter ].nextline = l;               /* set next line for loop */
   fs[ fs_counter ].variable = v;            /* set variable */
   fs[ fs_counter ].step = 1;                   /* set default step */
   l->position += strlen( tbuf );           /* set current position to end of variable */

   /* at this point one should find an equals sign ('=') */

   loop = TRUE;
   while( loop == TRUE )
      {
      switch( l->buffer[ l->position ] )
         {
         case '=':                              /* found equals sign; continue */
            ++l->position;
            loop = FALSE;
            break;
         case ' ':                              /* whitespace */
         case '\t':
            ++l->position;
            break;
         default:
#if PROG_ERRORS
            sprintf( bwb_ebuf, "in bwb_for(): failed to find equals sign, buf <%s>",
               &( l->buffer[ l->position ] ) );
            bwb_error( bwb_ebuf );
#else
            bwb_error( err_syntax );
#endif
            l->next->position = 0;
            return l->next;
         }
      }

   /* Find the TO and STEP statements */

   cnd_tostep( l->buffer, l->position, &to, &step );

   /* if there is no TO statement, then an error has ocurred */

   if ( to < 1 )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "FOR statement without TO" );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_syntax  );
#endif
      l->next->position = 0;
      return l->next;
      }

   /* copy initial value to small buffer and evaluate it */

   tbuf[ 0 ] = '\0';
   p = 0;
   for ( n = l->position; n < to; ++n )
      {
      tbuf[ p ] = l->buffer[ n ];
      ++p;
      ++l->position;
      tbuf[ p ] = '\0';
      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_for(): initial value string <%s>",
      tbuf );
   bwb_debug( bwb_ebuf );
#endif

   p = 0;
   exp = bwb_exp( tbuf, FALSE, &p );
   var_setival( fs[ fs_counter ].variable, exp_getival( exp ) );

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_for(): initial value <%d> pos <%d>",
      exp_getival( exp ), l->position );
   bwb_debug( bwb_ebuf );
#endif

   /* copy target value to small buffer and evaluate it */

   tbuf[ 0 ] = '\0';
   p = 0;
   l->position = to + 2;
   if ( step < 1 )
      {
      e = strlen( l->buffer );
      }
   else
      {
      e = step - 1;
      }

   loop = TRUE;
   n = l->position;
   while( loop == TRUE )
      {
      tbuf[ p ] = l->buffer[ n ];
      ++p;
      ++l->position;
      tbuf[ p ] = '\0';

      if ( n >= e )
          {
          loop = FALSE;
          }

      ++n;

      if ( l->buffer[ n ] == ':' )
         {
         loop = FALSE;
         }

      }

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_for(): target value string <%s>",
      tbuf );
   bwb_debug( bwb_ebuf );
#endif

   p = 0;
   exp = bwb_exp( tbuf, FALSE, &p );
   fs[ fs_counter ].target = exp_getival( exp );

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_for(): target value <%d> pos <%d>",
      exp_getival( exp ), l->position );
   bwb_debug( bwb_ebuf );
#endif

   /* If there is a STEP statement, copy it to the small buffer
      and evaluate it */

   if ( step > 1 )
      {
      tbuf[ 0 ] = '\0';
      p = 0;
      l->position = step + 4;

      for ( n = l->position; n < strlen( l->buffer ); ++n )
         {
         tbuf[ p ] = l->buffer[ n ];
         ++p;
         ++l->position;
         tbuf[ p ] = '\0';
         }

#if INTENSIVE_DEBUG
      sprintf( bwb_ebuf, "in bwb_for(): step value string <%s>",
         tbuf );
      bwb_debug( bwb_ebuf );
#endif

      p = 0;
      exp = bwb_exp( tbuf, FALSE, &p );
      fs[ fs_counter ].step = exp_getival( exp );

#if INTENSIVE_DEBUG
      sprintf( bwb_ebuf, "in bwb_for(): step value <%d>",
         exp_getival( exp ) );
      bwb_debug( bwb_ebuf );
#endif

      }

   /* set position in current line for reset */

   fs[ fs_counter ].position = l->position;     /* position for reset */

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_for(): ready to exit, position <%d>",
      l->position );
   bwb_debug( bwb_ebuf );
#endif

   /* proceed with processing */

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

   }

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

        FUNCTION:       bwb_next()

        DESCRIPTION:    This function handles the BASIC NEXT
                        statement.

	LIMITATION:	As implemented here, the NEXT statement
			must be at the beginning of a program
			line; a NEXT statement following a colon
			will not be recognized and may cause the
			program to hang up.

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

struct bwb_line *
bwb_next( struct bwb_line *l )
   {
   register int c;
   int stack_level;
   char tbuf[ MAXSTRINGSIZE + 1 ];

   /* Check the integrity of the FOR stack */

   if ( fs_counter <= 0 )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "NEXT without FOR" );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_nf );
#endif
      l->next->position = 0;
      return l->next;
      }

   /* Check for argument */

   adv_ws( l->buffer, &( l->position ) );
   switch( l->buffer[ l->position ] )
      {
      case '\0':
      case '\n':
      case '\r':
      case ':':
#if PROG_ERRORS
         sprintf( bwb_ebuf, "at line %d: NEXT: no variable specified.",
            l->number );
         bwb_error( bwb_ebuf );
#else
         bwb_error( err_syntax );
#endif
         l->next->position = 0;
         return l->next;
      default:
         break;
      }

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

   stack_level = 0;
   for ( c = 1; c <= fs_counter; ++c )
      {
      if ( strcmp( tbuf, fs[ c ].variable->name ) == 0 )
         {
         stack_level = c;
         }
      }
   if ( stack_level == 0  )
      {
#if PROG_ERRORS
      sprintf( bwb_ebuf, "NEXT has invalid variable" );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_syntax );
#endif
      l->next->position = 0;
      return l->next;
      }

   /* we now have a valid stack level; now increment the variable value */

   var_setival( fs[ stack_level ].variable,
      var_getival( fs[ stack_level ].variable ) + fs[ stack_level ].step );

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_next(): variable <%s> is <%d>",
      fs[ stack_level ].variable->name,
      var_getival( fs[ stack_level ].variable ) );
   bwb_debug( bwb_ebuf );
#endif

   /* check for completion of the loop */

   if ( fs[ stack_level ].step > 0 )            /* if step is positive */
      {
      if ( var_getival( fs[ stack_level ].variable )
         > fs[ stack_level ].target )
         {

         /* decrement the FOR stack counter and return */

         dec_fsc( stack_level );
         l->next->position = 0;
         return l->next;
         }
      }
   else                                         /* if step is negative */
      {
      if ( var_getival( fs[ stack_level ].variable )
         < fs[ stack_level ].target )
         {

         /* decrement the FOR stack counter and return */

         dec_fsc( stack_level );
         l->next->position = 0;
         return l->next;
         }
      }

   /* Target not reached: return to the top of the FOR loop */

   fs[ stack_level ].nextline->position = fs[ stack_level ].position;

#if INTENSIVE_DEBUG
   sprintf( bwb_ebuf, "in bwb_next(): return to line <%d> position <%d> char <%c>",
      fs[ stack_level ].nextline->number,
      fs[ stack_level ].nextline->position,
      fs[ stack_level ].nextline->buffer[ fs[ stack_level ].nextline->position ] );
   bwb_debug( bwb_ebuf );
#endif

   return fs[ stack_level ].nextline;

   }

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

        FUNCTION:       cnd_tostep()

        DESCRIPTION:    This function searches through the
                        <buffer> beginning at point <position>
                        and attempts to find positions of TO
                        and STEP statements.

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

static int
cnd_tostep( char *buffer, int position, int *to, int *step )
   {
   int loop, t_pos, b_pos, p_word;
   char tbuf[ MAXSTRINGSIZE + 1 ];

   /* set then and els to FALSE initially */

   *to = *step = FALSE;

   /* loop to find words */

   p_word = b_pos = position;
   t_pos = 0;
   tbuf[ 0 ] = '\0';
   loop = TRUE;
   while ( loop == TRUE )
      {

      switch( buffer[ b_pos ] )
         {
         case '\0':                     /* end of string */
         case ':':			/* end of line segment */
            return TRUE;
         case ' ':                      /* whitespace = end of word */
         case '\t':

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

            if ( strncmp( tbuf, "TO", (size_t) 2 ) == 0 )
               {

#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in cnd_tostep(): TO found at position <%d>.",
                  p_word );
               bwb_debug( bwb_ebuf );
#endif

               *to = p_word;
               }
            else if ( strncmp( tbuf, "STEP", (size_t) 4 ) == 0 )
               {

#if INTENSIVE_DEBUG
               sprintf( bwb_ebuf, "in cnd_tostep(): STEP found at position <%d>.",
                  p_word );
               bwb_debug( bwb_ebuf );
#endif

               *step = p_word;
               }
            ++b_pos;
            p_word = b_pos;
            t_pos = 0;
            tbuf[ 0 ] = '\0';
            break;

         default:
            if ( islower( buffer[ b_pos ] ) != FALSE )
               {
               tbuf[ t_pos ] = toupper( buffer[ b_pos ] );
               }
            else
               {
               tbuf[ t_pos ] = buffer[ b_pos ];
               }
            ++b_pos;
            ++t_pos;
            tbuf[ t_pos ] = '\0';
            break;
         }

      }

   return TRUE;

   }

static int
var_setival( struct bwb_variable *v, int i )
   {

   switch( v->type )
      {
      case INTEGER:
         * var_findival( v, v->array_pos ) = i;
         break;
      case DOUBLE:
         * var_finddval( v, v->array_pos ) = (double) i;
         break;
      case SINGLE:
         * var_findfval( v, v->array_pos ) = (float) i;
         break;
      default:
#if INTENSIVE_DEBUG
         sprintf( bwb_ebuf, "in var_setival(): variable <%s> is not a number",
            v->name );
         bwb_error( bwb_ebuf );
#else
         bwb_error( err_mismatch );
#endif
      }

   /* successful assignment */

   return TRUE;

   }

static int
dec_fsc( int level )
   {
   register int l;

   --fs_counter;
   if ( fs_counter < 0 )
      {
      fs_counter = 0;
#if PROG_ERRORS
      sprintf( bwb_ebuf, "FOR stack counter decremented below 0." );
      bwb_error( bwb_ebuf );
#else
      bwb_error( err_overflow );
#endif
      return FALSE;
      }

   /* pull down the FOR stack if necessary */

   l = level;
   while( l <= fs_counter )
      {
      memcpy( &( fs[ l ] ), &( fs[ l + 1 ] ), sizeof( struct fse ) );
      }

   /* return */

   return TRUE;

   }

