/****************************************************************
  
        bwb_fnc.c       Interpretation Routines
                        for Predefined Functions
                        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                            */
/*                                                               */
/* Version 3.10 by Howard Wulf, AF5NE                            */
/*                                                               */
/*---------------------------------------------------------------*/



#include "bwbasic.h"


#ifndef RAND_MAX
#define RAND_MAX  32767
#endif            /* RAND_MAX */

#ifndef PI
#define PI       3.14159265358979323846
#endif           /* PI */

#define FromDegreesToRadians(  X ) ( X * PI / 180.0 )
#define FromRadiansToDegrees(  X ) ( X * 180.0 / PI )

#define FromGradiansToRadians( X ) ( X * PI / 200.0 )
#define FromRadiansToGradians( X ) ( X * 200.0 / PI )


static time_t   t;
static struct tm *lt;


/*  ORD() Table 1    */

 /* ACRONYM */
typedef struct
{
   const int       Value;
   const char     *Name;
}               Acronym;

#define NUM_ACRONYMS (34)

Acronym         AcronymTable[NUM_ACRONYMS] =
{
 {0, "NUL"},
 {1, "SOH"},
 {2, "STX"},
 {3, "ETX"},
 {4, "EOT"},
 {5, "ENQ"},
 {6, "ACK"},
 {7, "BEL"},
 {8, "BS"},
 {9, "HT"},
 {10, "LF"},
 {11, "VT"},
 {12, "FF"},
 {13, "CR"},
 {14, "SO"},
 {15, "SI"},
 {16, "DLE"},
 {17, "DC1"},
 {18, "DC2"},
 {19, "DC3"},
 {20, "DC4"},
 {21, "NAK"},
 {22, "SYN"},
 {23, "ETB"},
 {24, "CAN"},
 {25, "EM"},
 {26, "SUB"},
 {27, "ESC"},
 {28, "FS"},
 {29, "GS"},
 {30, "RS"},
 {31, "US"},
 {32, "SP"},
 {127, "DEL"}
};

/* ... ORD() */

VariableType *
fnc_intrinsic(int argc, VariableType * argv, int unique_id)
{
   /* this is the generic handler for all intrinsic BASIC functions */
   /* BasicStringLengthMax must be <= INT_MAX */
   FunctionType *f;
   VariableType *argn;
   unsigned char   IsError;/* for ERROR messages */
   /* Follow the BASIC naming conventions, so the code is easier to
    * maintain */
   char           *S;   /* S$ - STRING functions */
   BasicStringLengthType s;/* LEN( S$ ) */
   BasicNumberType N;   /* N  -  NUMBER functions */
   char           *A;   /* A$ - 1st STRING parameter */
   BasicStringLengthType a;/* LEN( A$ ) */
   char           *B;   /* B$ - 2nd STRING parameter */
   BasicStringLengthType b;/* LEN( B$ ) */
#if FALSE /* keep third parameter */
   char           *C;   /* C$ - 3rd STRING parameter */
   BasicStringLengthType c;/* LEN( C$ ) */
#endif
   BasicNumberType X;   /* X  - 1st NUMBER parameter */
   BasicIntegerType x;  /* INT( X ) */
   BasicNumberType Y;   /* Y  - 2nd NUMBER parameter */
   BasicIntegerType y;  /* INT( Y ) */
#if FALSE /* keep third parameter */
   BasicNumberType Z;   /* Z  - 3rd NUMBER parameter */
   BasicIntegerType z;  /* INT( Z ) */
#endif
   bwx_DEBUG(__FUNCTION__);


   /* so the following code is easier to read and maintain */
#define PARAM_NUMBER   *argn->memnum
#define PARAM_LENGTH    argn->memstr->length
#define PARAM_BUFFER    argn->memstr->sbuffer
#define RESULT_NUMBER  *argv->memnum
#define RESULT_BUFFER   argv->memstr->sbuffer
#define RESULT_LENGTH   argv->memstr->length

   /* no errors have occurred (yet) */
   IsError = 0;

   /* look up the intrinsic function, so we can get the details */
   {
      f = fnc_find_by_id(unique_id);
      if (f == NULL)
      {
         /* bwb_prefuncs[] in bwb_tbl.c is wrong -- this is really bad */
         WARN_INTERNAL_ERROR;
         return NULL;
      }
   }
   /* the RETURN variable is the first variable in the 'argv' vaariable chain */
   if (argv == NULL)
   {
      WARN_INTERNAL_ERROR;
      return NULL;
   }
   if ( VAR_IS_STRING( argv ) )
   {
      if (argv->memstr == NULL)
      {
         WARN_INTERNAL_ERROR;
         return NULL;
      }
      RESULT_LENGTH = 0;
      RESULT_BUFFER[RESULT_LENGTH] = BasicNulChar;
   }
   else
   {
      if (argv->memnum == NULL)
      {
         WARN_INTERNAL_ERROR;
         return NULL;
      }
      RESULT_NUMBER = 0;
   }
   argn = argv;
   /* don't make a bad situation worse */
   if( bwb_Warning_Pending() /* Keep This */ )
   {
      /* An unrecognized NON-FATAL ERROR is pending.  Just return a sane value. */
      /* LET N = LOG(SQR(X)) ' X = -1 */
      return argv;
   }
   /* Follow the BASIC naming conventions, so the code is easier to read and maintain */
   {
      int             i;
      int             StrCount = 0; /* count of STRING parameters - NEVER > 3 */
      int             NumCount = 0; /* count of NUMBER parameters - NEVER > 3 */
      unsigned long   ParameterTests;
      ParameterTests = f->ParameterTests;
      /* assign reasonable default values */
      S = NULL;   /* S$ - return value is a STRING */
      s = 0;      /* LEN( S$ ) */
      N = 0;      /* N  - return value is a NUMBER */
      A = NULL;   /* A$ - 1st STRING parameter */
      a = 0;      /* LEN( A$ ) */
      B = NULL;   /* B$ - 2nd STRING parameter */
      b = 0;      /* LEN( B$ ) */
#if FALSE /* keep third parameter */
      C = NULL;   /* C$ - 3rd STRING parameter */
      c = 0;      /* LEN( C$ ) */
#endif
      X = 0;      /* X  - 1st NUMBER parameter */
      x = 0;      /* INT( X ) */
      Y = 0;      /* Y  - 2nd NUMBER parameter */
      y = 0;      /* INT( Y ) */
#if FALSE /* keep third parameter */
      Z = 0;      /* Z  - 3rd NUMBER parameter */
      z = 0;      /* INT( Z ) */
#endif
      /* assign actual values */
      if (f->ReturnType == BasicStringSuffix)
      {
         S = RESULT_BUFFER;
         s = RESULT_LENGTH;
      }
      else
      {
         N = RESULT_NUMBER;
      }
      for (i = 0; i < argc && IsError == 0; i++)
      {
         argn = argn->next;
         if (argn == NULL)
         {
            WARN_INTERNAL_ERROR;
            return NULL;
         }
         if ( VAR_IS_STRING( argn ) )
         {
            if (argn->memstr == NULL)
            {
               WARN_INTERNAL_ERROR;
               return NULL;
            }
            StrCount++;
            switch (StrCount)
            {
            case 1:
               /* 1st STRING parameter = A$ */
               A = PARAM_BUFFER;
               a = PARAM_LENGTH;
               if (StringLengthCheck(ParameterTests, a))
               {
                  IsError = 'A';
               }
               else
               {
                  A[a] = 0;
               }
               break;
            case 2:
               /* 2nd STRING parameter = B$ */
               B = PARAM_BUFFER;
               b = PARAM_LENGTH;
               if (StringLengthCheck(ParameterTests, b))
               {
                  IsError = 'B';
               }
               else
               {
                  B[b] = 0;
               }
               break;
#if FALSE /* keep third parameter */
            case 3:
               /* 3rd STRING parameter = C$ */
               /* not currently used */
               C = PARAM_BUFFER;
               c = PARAM_LENGTH;
               if (StringLengthCheck(ParameterTests, c))
               {
                  IsError = 'C';
               }
               else
               {
                  C[c] = 0;
               }
               break;
#endif
            default:
               /* Nth STRING parameter = ERROR */
               IsError = i + 1;
               break;
            }
         }
         else
         {
            if (argn->memnum == NULL)
            {
               WARN_INTERNAL_ERROR;
               return NULL;
            }
            NumCount++;
            switch (NumCount)
            {
            case 1:
               /* 1st NUMBER parameter = X */
               X = PARAM_NUMBER;
               if (NumberValueCheck(ParameterTests, X))
               {
                  IsError = 'X';
               }
               else
               {
                  BasicNumberType R;
                  R = bwb_rint(X);
                  if (R < INT_MIN || R > INT_MAX)
                  {
                     /* certainly not a
                      * classic BASIC
                      * integer */
                  }
                  else
                  {
                     /* Many classic BASIC
                      * intrinsic
                      * functions use the
                      * rounded integer
                      * value. */
                     x = (int) R;
                  }
               }
               break;
            case 2:
               /* 2nd NUMBER parameter = Y */
               Y = PARAM_NUMBER;
               if (NumberValueCheck(ParameterTests, Y))
               {
                  IsError = 'Y';
               }
               else
               {
                  BasicNumberType R;
                  R = bwb_rint(Y);
                  if (R < INT_MIN || R > INT_MAX)
                  {
                     /* certainly not a
                      * classic BASIC
                      * integer */
                  }
                  else
                  {
                     /* Many classic BASIC
                      * intrinsic
                      * functions use the
                      * rounded integer
                      * value. */
                     y = (int) R;
                  }
               }
               break;
#if FALSE /* keep third parameter */
            case 3:
               /* 3rd NUMBER parameter = Z */
               /* not currently used */
               Z = PARAM_NUMBER;
               if (NumberValueCheck(ParameterTests, Z))
               {
                  IsError = 'Z';
               }
               else
               {
                  BasicNumberType R;
                  R = bwb_rint(Z);
                  if (R < INT_MIN || R > INT_MAX)
                  {
                     /* certainly not a
                      * classic BASIC
                      * integer */
                  }
                  else
                  {
                     /* Many classic BASIC
                      * intrinsic
                      * functions use the
                      * rounded integer
                      * value. */
                     z = (int) R;
                  }
               }
               break;
#endif
            default:
               /* Nth NUMBER parameter = ERROR */
               IsError = i + 1;
               break;
            }
         }
         ParameterTests = ParameterTests >> 4;
      }
   }


   /* execute the intrinsic function */
   /* WARNING -- do NOT execute a BASIC intrinsic function with bogus parameters */
   if (IsError == 0   )
   {
      switch (unique_id)
      {
         /* ALL paramters have  been checked for TYPE MISMATCH
          * and INVALID RANGE */
         /* ONLY A HANDFUL OF ERRORS CAN OCCUR */
      case 0:
         {
            /* INTERNAL ERROR */
            IsError = 1;
         }
         break;
      case F_DEF_FN_N:
         {
            /* INTERNAL ERROR */
            IsError = 1;
         }
         break;
      case F_ARGC_N:
         /* N = ARGC */
         {
            /* determine number of parameters to the current USER DEFINED FUNCTION */
            int             n;
            n = 0;
            if ( My->stack_head != NULL )
            {
               int             Loop;
               StackType * stack_item;
               Loop = TRUE;
               for (stack_item = My->stack_head; stack_item != NULL && Loop == TRUE; stack_item = stack_item->next)
               {
                  if (stack_item->LoopTopLine != NULL)
                  {
                     switch (stack_item->LoopTopLine->cmdnum)
                     {
                     case C_FUNCTION:
                     case C_SUB:
                        /* we have checked all the way to a FUNCTION or SUB boundary */
                        /* FOUND */
                        {
                           VariableType *v;

                           for (v = stack_item->local_variable; v != NULL && Loop == TRUE; v = v->next)
                           {
                              n++;
                           }
                        }
                        Loop = FALSE;
                        break;
                     }
                  }
               }
            }
            n--;  /* FUNCTION or SUB name */
            N = n;
         }
         break;
      case F_ARGT4_X_S:
         /* S$ = ARGT$( X ) */
         {
            /* determine parameter type to the current USER DEFINED FUNCTION */
            int             Found;
            int             n;
            Found = FALSE;
            n = 0;
            s = 0;
            if (x < 1)
            {
               /* bad param number  */
            }
            else
            if ( My->stack_head != NULL )
            {
               int             Loop;
               StackType * stack_item;
               Loop = TRUE;
               for (stack_item = My->stack_head; stack_item != NULL && Loop == TRUE; stack_item = stack_item->next)
               {
                  if (stack_item->LoopTopLine != NULL)
                  {
                     switch (stack_item->LoopTopLine->cmdnum)
                     {
                     case C_FUNCTION:
                     case C_SUB:
                        /* we have checked all the way to a FUNCTION or SUB boundary */
                        /* FOUND */
                        {
                           VariableType *v;


                           for (v = stack_item->local_variable; v != NULL && Loop == TRUE; v = v->next)
                           {
                              if (n == x)
                              {
                                 if ( VAR_IS_STRING( v ) )
                                 {
                                    S[0] = BasicStringSuffix;
                                    s = 1;
                                    Found = TRUE;
                                 }
                                 else
                                 {
                                    S[0] = BasicDoubleSuffix;
                                    s = 1;
                                    Found = TRUE;
                                 }
                                 Loop = FALSE;
                              }
                              n++;
                           }
                        }
                        Loop = FALSE;
                        break;
                     }
                  }
               }
            }
            if (Found == FALSE)
            {
               IsError = 'X';
            }
         }
         break;

      case F_ARGV4_X_S:
         /* S$ = ARGV$( X ) */
         {
            /* determine parameter value to the current
             * USER DEFINED FUNCTION */
            int             Found;
            int             n;
            Found = FALSE;
            n = 0;
            if (x < 1)
            {
               /* bad param number  */
            }
            else
            if ( My->stack_head != NULL )
            {
               int             Loop;
               StackType * stack_item;
               Loop = TRUE;
               for (stack_item = My->stack_head; stack_item != NULL && Loop == TRUE; stack_item = stack_item->next)
               {
                  if (stack_item->LoopTopLine != NULL)
                  {
                     switch (stack_item->LoopTopLine->cmdnum)
                     {
                     case C_FUNCTION:
                     case C_SUB:
                        /* we have checked all the way to a FUNCTION or SUB boundary */
                        /* FOUND */
                        {
                           VariableType *v;


                           for (v = stack_item->local_variable; v != NULL && Loop == TRUE; v = v->next)
                           {
                              if (n == x)
                              {
                                 if ( VAR_IS_STRING( v ) )
                                 {
                                    s = v->memstr->length;
                                    bwb_memcpy(S, v->memstr->sbuffer, s);
                                    Found = TRUE;
                                 }
                                 else
                                 {
                                 }
                                 Loop = FALSE;
                              }
                              n++;
                           }
                        }
                        Loop = FALSE;
                        break;
                     }
                  }
               }
            }
            if (Found == FALSE)
            {
               IsError = 'X';
            }
         }
         break;

      case F_ARGV_X_N:
         /* S$ = ARGV( X ) */
         {
            /* determine parameter value to the current USER DEFINED FUNCTION */
            int             Found;
            int             n;
            Found = FALSE;
            n = 0;
            if (x < 1)
            {
               /* bad param number  */
            }
            else
            if ( My->stack_head != NULL )
            {
               int             Loop;
               StackType * stack_item;
               Loop = TRUE;
               for (stack_item = My->stack_head; stack_item != NULL && Loop == TRUE; stack_item = stack_item->next)
               {
                  if (stack_item->LoopTopLine != NULL)
                  {
                     switch (stack_item->LoopTopLine->cmdnum)
                     {
                     case C_FUNCTION:
                     case C_SUB:
                        /* we have checked all the way to a FUNCTION or SUB boundary */
                        /* FOUND */
                        {
                           VariableType *v;


                           for (v = stack_item->local_variable; v != NULL && Loop == TRUE; v = v->next)
                           {
                              if (n == x)
                              {
                                 if ( VAR_IS_STRING( v ) )
                                 {
                                 }
                                 else
                                 {
                                    N = *v->memnum;
                                    Found = TRUE;
                                 }
                                 Loop = FALSE;
                              }
                              n++;
                           }
                        }
                        Loop = FALSE;
                        break;
                     }
                  }
               }
            }
            if (Found == FALSE)
            {
               IsError = 'X';
            }
         }
         break;
      case F_BASE_N:
         /* N = BASE */
         {
            /* PNONE */
            N = My->CurrentVersion->OptionBaseValue;
         }
         break;
      case F_ASC_A_N:
      case F_ASCII_A_N:
      case F_CODE_A_N:
         /* N = ASC( A$ ) */
         /* N = ASCII( A$ ) */
         /* N = CODE( A$ ) */
         {
            /* P1BYT */
            N = A[0];
         }
         break;
      case F_ASC_A_X_N:
         /* N = ASC( A$, X ) */
         {
            /* P1BYT|P2POS */
            x--; /* BASIC -> C */
            if( x < a )
            {
                N = A[x];
            }
            else
            {
                IsError = 'X';
            }
         }
         break;
      case F_CDBL_X_N:
         /* N = CDBL( X ) */
         {
            /* P1DBL */
            N = X;
            /* argv->VariableType = BasicDoubleSuffix; */
         }
         break;
      case F_CSNG_X_N:
         /* N = CSNG( X ) */
         {
            /* P1FLT */
            N = X;
            /* argv->VariableType = BasicSingleSuffix; */
         }
         break;
      case F_CCUR_X_N:
         /* N = CCUR( X ) */
         {
            /* P1CUR */
            N = bwb_rint(X);
            /* argv->VariableType = BasicCurrencySuffix; */
         }
         break;
      case F_CLNG_X_N:
         /* N = CLNG( X ) */
         {
            /* P1LNG */
            N = bwb_rint(X);
            /* argv->VariableType = BasicLongSuffix; */
         }
         break;
      case F_CINT_X_N:
         /* N = CINT( X ) */
         {
            /* P1INT */
            N = bwb_rint(X);
            /* argv->VariableType = BasicIntegerSuffix; */
         }
         break;
      case F_MKD4_X_S:
         /* S$ = MKD$( X ) */
         {
            /* P1DBL */
            BasicDoubleType x;
            x = (BasicDoubleType) X;
            s = sizeof(BasicDoubleType);
            bwb_memcpy(S, &x, s);
         }
         break;
      case F_MKS4_X_S:
         /* S$ = MKS$( X ) */
         {
            /* P1FLT */
            BasicSingleType x;
            x = (BasicSingleType) X;
            s = sizeof(BasicSingleType);
            bwb_memcpy(S, &x, s);
         }
         break;
      case F_MKI4_X_S:
         /* S$ = MKI$( X ) */
         {
            /* P1INT */
            BasicIntegerType x;
            x = (BasicIntegerType) bwb_rint(X);
            s = sizeof(BasicIntegerType);
            bwb_memcpy(S, &x, s);
         }
         break;
      case F_MKL4_X_S:
         /* S$ = MKL$( X ) */
         {
            /* P1LNG */
            BasicLongType   x;
            x = (BasicLongType) bwb_rint(X);
            s = sizeof(BasicLongType);
            bwb_memcpy(S, &x, s);
         }
         break;
      case F_MKC4_X_S:
         /* S$ = MKC$( X ) */
         {
            /* P1CUR */
            BasicCurrencyType x;
            x = (BasicCurrencyType) bwb_rint(X);
            s = sizeof(BasicCurrencyType);
            bwb_memcpy(S, &x, s);
         }
         break;
      case F_CVD_A_N:
         /* N = CVD( A$ ) */
         {
            /* P1DBL */
            BasicDoubleType n;
            a = sizeof(BasicDoubleType);
            bwb_memcpy(&n, A, a);
            N = n;
         }
         break;
      case F_CVS_A_N:
         /* N = CVS( X$ ) */
         {
            /* P1FLT */
            BasicSingleType n;
            a = sizeof(BasicSingleType);
            bwb_memcpy(&n, A, a);
            N = n;
         }
         break;
      case F_CVI_A_N:
         /* N = CVI( X$ ) */
         {
            /* P1INT */
            BasicIntegerType n;
            a = sizeof(BasicIntegerType);
            bwb_memcpy(&n, A, a);
            N = n;
         }
         break;
      case F_CVL_A_N:
         /* N = CVL( X$ ) */
         {
            /* P1LNG */
            BasicLongType   n;
            a = sizeof(BasicLongType);
            bwb_memcpy(&n, A, a);
            N = n;
         }
         break;
      case F_CVC_A_N:
         /* N = CVC( X$ ) */
         {
            /* P1CUR */
            BasicCurrencyType n;
            a = sizeof(BasicCurrencyType);
            bwb_memcpy(&n, A, a);
            N = n;
         }
         break;
      case F_ENVIRON4_A_S:
         /* S$ = ENVIRON$( A$ ) */
         {
            /* P1BYT */
            char           *CharPointer;

            CharPointer = getenv(A);
            if (CharPointer == NULL)
            {
               /* empty string */
            }
            else
            {
               s = bwb_strlen(CharPointer);
               s = MIN(s, BasicStringLengthMax);
               if (s == 0)
               {
                  /* empty string */
               }
               else
               {
                  bwb_memcpy(S, CharPointer, s);
               }
            }
         }
         break;
      case F_ENVIRON_A_N:
         /* ENVIRON A$ */
         {
            /* P1BYT */

            char           *CharPointer;

            CharPointer = bwb_strchr(A, '=');
            if (CharPointer == NULL)
            {
               /* missing required '=' */
               IsError = 'A';
            }
            else
            {
               if (putenv(A) == -1)
               {
                  IsError = 'A';
               }
               else
               {
                  /* OK */
                  N = 0;
               }
            }
         }
         break;

      case F_OPEN_A_X_B_Y_N:
         /* OPEN "I"|"O"|"R"|"A", [#]n, filename [,rlen] */
         {
            /* P1STR|P2NUM|P3STR|P4NUM */
            /* P1BYT|P2DEV|P3BYT|P4INT */

            while (*A == ' ')
            {
               A++;  /* LTRIM$ */
            }
            IsError = bwb_file_open( *A, x, B, y );
         }
         break;
      case F_OPEN_A_X_B_N:
         /* default  LEN is 128 for RANDOM, 0 for all others */
         /* OPEN "I"|"O"|"R"|"A", [#]n, filename [,rlen] */
         {
            /* P1STR|P2NUM|P3STR|P4NUM */
            /* P1BYT|P2DEV|P3BYT|P4INT */
            int             y = 0;

            while (*A == ' ')
            {
               A++;  /* LTRIM$ */
            }
            if( bwb_toupper(*A) == 'R' )
            {
               /* default RANDOM record size */
               y = 128;
            }
            IsError = bwb_file_open( *A, x, B, y );
         }
         break;
      case F_LOC_X_N:
         /* N = LOC( X ) */
         {
            /* P1DEV */
            if( x <= 0 )
            {
               N = 0;
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  N = 0;
               }
               else
               if( F == My->SYSOUT )
               {
                  N = 0;
               }
               else
               if( F == My->SYSPRN )
               {
                  N = 0;
               }
               else
               {
                  FILE           *fp;
                  fp = F->cfp;
                  N = ftell(fp);
                  if( My->CurrentVersion->OptionVersionBitmask & (G65 | G67)  )
                  {
                     /* byte position, regardless of 'mode' */
                  }
                  else
                  if (F->mode == DEVMODE_RANDOM)
                  {
                     /* record number */
                     if( F->width == 0 )
                     {
                        /* byte position */
                     }
                     else
                     {
                        N /= F->width;
                     }
                  }
                  else
                  if (F->mode == DEVMODE_BINARY)
                  {
                     /* byte position */
                  }
                  else
                  {
                     /* byte positiion / 128 */
                     N /= 128;
                  }
                  N = floor(N);
                  N++;  /* C to BASIC */
               }
            }
         }
         break;
      case F_SEEK_X_N:
         /* N = SEEK( X ) */
         {
            /* P1DEV */
            if( x <= 0 )
            {
               N = 0;
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  N = 0;
               }
               else
               if( F == My->SYSOUT )
               {
                  N = 0;
               }
               else
               if( F == My->SYSPRN )
               {
                  N = 0;
               }
               else
               {
                  FILE           *fp;
                  fp = F->cfp;
                  N = ftell(fp);
                  if (F->mode == DEVMODE_RANDOM)
                  {
                     /* record number */
                     if( F->width > 0 )
                     {
                        N /= F->width;
                     }
                  }
                  else
                  {
                     /* byte positiion */
                  }
                  N = floor(N);
                  N++;  /* C to BASIC */
               }
            }
         }
         break;
      case F_SEEK_X_Y_N:
         /* SEEK X, Y */
         {
            /* P1DEV|P2INT */
            if( x <= 0 )
            {
               IsError = 'X';
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSOUT )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSPRN )
               {
                  IsError = 'X';
               }
               else
               if (y < 1)
               {
                  IsError = 'Y';
               }
               else
               {
                  long            offset;
                  offset = y;
                  offset--;   /* BASIC to C */
                  if (F->mode == DEVMODE_RANDOM)
                  {
                     if( F->width > 0 )
                     {
                        offset *= F->width;
                     }
                  }
                  if (fseek(F->cfp, offset, SEEK_SET) != 0)
                  {
                     IsError = 'Y';
                  }
                  else
                  {
                     /* OK */
                     N = 0;
                  }
               }
            }
         }
         break;
      case F_LOF_X_N:
         /* N = LOF( X ) */
         {
            /* P1DEV */
            if( x <= 0 )
            {
               N = 0;
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  N = 0;
               }
               else
               if( F == My->SYSOUT )
               {
                  N = 0;
               }
               else
               if( F == My->SYSPRN )
               {
                  N = 0;
               }
               else
               {
                  /* file size in bytes */
                  FILE           *fp;
                  long            current;
                  long            total;
                  fp = F->cfp;
                  current = ftell(fp);
                  fseek(fp, 0, SEEK_END);
                  total = ftell(fp);
                  if (total == current)
                  {
                     /* EOF */
                  }
                  else
                  {
                     fseek(fp, current, SEEK_SET);
                  }
                  N = total;
               }
            }
         }
         break;
      case F_EOF_X_N:
         /* N = EOF( X ) */
         {
            /* P1DEV */
            if( x <= 0 )
            {
               N = 0;
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  N = 0;
               }
               else
               if( F == My->SYSOUT )
               {
                  N = 0;
               }
               else
               if( F == My->SYSPRN )
               {
                  N = 0;
               }
               else
               {
                  /* are we at the end? */
                  N = bwb_is_eof( F->cfp );
               }     
            }
         }
         break;
      case F_FILEATTR_X_Y_N:
         /* N = FILEATTR( X, Y ) */
         {
            /* P1DEV|P2INT */

            if( x <= 0 )
            {
               /* Printer and Console */
               IsError = 'X';
            }
            else
            if( y == 1 )
            {
               FileType * F;

               F = find_file_by_number( x );
               if( F == NULL )
               {
                  /* normal CLOSED file */
                  N = 0;
               }
               else
               {
                  /* normal OPEN file */
                  N = F->mode;
               }
            }
            else
            if( y == 2 )
            {
               N = 0;
            }
            else
            {
               IsError = 'Y';
            }
         }
         break;
      case F_CLOSE_X_N:
         /* CLOSE X */
         {
            /* P1DEV */            
            if( x <= 0 )
            {
               /* Printer and Console */
               IsError = 'X';
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSOUT )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSPRN )
               {
                  IsError = 'X';
               }
               else
               {
                  field_close_file( F );
                  file_clear( F );
                  N = 0;
               }
            }
         }
         break;
      case F_RESET_N:
      case F_CLOSE_N:
         /* RESET */
         /* CLOSE */
         {
            /* PNONE */
            FileType * F;

            for (F = My->file_head; F != NULL; F = F->next)
            {
               field_close_file( F );
               file_clear( F );
            }
            N = 0;
         }
         break;
      case F_FREEFILE_N:
         /* N = FREEFILE */
         {
            /* PNONE */
            int             x;
            FileType * F;

            x = 0;
            for (F = My->file_head; F != NULL; F = F->next)
            {
               if (F->mode != DEVMODE_CLOSED)
               {
                  if( F->FileNumber > x )
                  {
                     x = F->FileNumber;
                  }
               }
            }
            /* 'x' is the highest FileNumber that is currently open */
            x++;
            if( x > BasicFileNumberMax )
            {
               x = 0;
            }
            N = x;
         }
         break;
      case F_GET_X_Y_N:
         /* GET X, Y */
         {
            /* P1DEV|P2INT */
            if( x <= 0 )
            {
               /* Printer and Console */
               IsError = 'X';
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSOUT )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSPRN )
               {
                  IsError = 'X';
               }
               else
               if (F->mode != DEVMODE_RANDOM)
               {
                  IsError = 'X';
               }
               else
               if (y < 1)
               {
                  IsError = 'Y';
               }
               else
               {
                  long offset;
                  offset = y;
                  offset--;   /* BASIC to C */
                  if (F->mode == DEVMODE_RANDOM)
                  {
                     if( F->width > 0 )
                     {
                        offset *= F->width;
                     }
                  }
                  if (fseek(F->cfp, offset, SEEK_SET) != 0)
                  {
                     IsError = 'Y';
                  }
                  else
                  {
                     int i;
                     for (i = 0; i < F->width; i++)
                     {
                        F->buffer[i] = fgetc(F->cfp);
                     }
                     field_get( F );
                     N = 0;
                  }
               }
            }
         }
         break;
      case F_GET_X_N:
         /* GET X */
         {
            /* PDEV1 */
            if( x <= 0 )
            {
               /* Printer and Console */
               IsError = 'X';
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSOUT )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSPRN )
               {
                  IsError = 'X';
               }
               else
               if (F->mode != DEVMODE_RANDOM)
               {
                  IsError = 'X';
               }
               else
               {
                  {
                     int i;
                     for (i = 0; i < F->width; i++)
                     {
                        F->buffer[i] = fgetc(F->cfp);
                     }
                     field_get( F );
                     N = 0;
                  }
               }
            }
         }
         break;
      case F_PUT_X_Y_N:
         /* PUT X, Y */
         {
            /* P1DEV|P2INT */
            if( x <= 0 )
            {
               /* Printer and Console */
               IsError = 'X';
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSOUT )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSPRN )
               {
                  IsError = 'X';
               }
               else
               if (F->mode != DEVMODE_RANDOM)
               {
                  IsError = 'X';
               }
               else
               if (y < 1)
               {
                  IsError = 'Y';
               }
               else
               {
                  long offset;
                  offset = y;
                  offset--;   /* BASIC to C */
                  if (F->mode == DEVMODE_RANDOM)
                  {
                     if( F->width > 0 )
                     {
                        offset *= F->width;
                     }
                  }
                  if (fseek(F->cfp, offset, SEEK_SET) != 0)
                  {
                     IsError = 'Y';
                  }
                  else
                  {
                     int i;
                     field_put( F );
                     for (i = 0; i < F->width; i++)
                     {
                        fputc(F->buffer[i], F->cfp);
                        F->buffer[i] = ' '; /* flush  */
                     }
                     N = 0;
                  }
               }
            }
         }
         break;
      case F_PUT_X_N:
         /* PUT X */
         {
            /* P1DEV */
            if( x <= 0 )
            {
               /* Printer and Console */
               IsError = 'X';
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSIN )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSOUT )
               {
                  IsError = 'X';
               }
               else
               if( F == My->SYSPRN )
               {
                  IsError = 'X';
               }
               else
               if (F->mode != DEVMODE_RANDOM)
               {
                  IsError = 'X';
               }
               else
               {
                  {
                     int i;
                     field_put( F );
                     for (i = 0; i < F->width; i++)
                     {
                        fputc(F->buffer[i], F->cfp);
                        F->buffer[i] = ' '; /* flush  */
                     }
                     N = 0;
                  }
               }
            }
         }
         break;
      case F_WIDTH_X_N:
         /* WIDTH X */
         {
            /* P1BYT */
            /* console is #0 */
            My->SYSIN->width = x;
            My->SYSIN->col = 1;
            My->SYSOUT->width = x;
            My->SYSOUT->col = 1;
            N = 0;
         }
         break;
      case F_WIDTH_X_Y_N:
         /* WIDTH X, Y */
         {
            /*  WIDTH #file, cols */
            /* P1BYT|PB2YT */
            if( x == 0 )
            {
               My->SYSIN->width = y;
               My->SYSOUT->width = y;
               N = 0;
            }
            else
            if( x < 0 )
            {
               My->SYSPRN->width = y;
               N = 0;
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  /* WIDTH rows, cols */
                  My->SCREEN_ROWS = x;
                  My->SYSIN->width = y;
                  My->SYSIN->col = 1;
                  My->SYSOUT->width = y;
                  My->SYSOUT->col = 1;
                  N = 0;
               }
               else
               if (F->mode == DEVMODE_RANDOM)
               {
                  IsError = 'X';
               }
               else
               {
                  /* WIDTH # file, cols */
                  F->width = y;
                  F->col = 1;
                  N = 0;
               }
            }
         }
         break;
      case F_INSTR_X_A_B_N:
         /* N = INSTR( X, A$, B$ ) */
         {
            /* P1POS */
            if (a == 0)
            {
               /* empty searched */
            }
            else
            if (b == 0)
            {
               /* empty pattern */
            }
            else
            if (b > a)
            {
               /* pattern is longer than searched */
            }
            else
            {
               /* search */
               int             i;
               int             n;
               n = a - b;  /* last valid search position */
               n++;

               x--;  /* BASIC to C */
               A += x;  /* advance to the start
                   * position */
               for (i = x; i < n; i++)
               {
                  if (bwb_memcmp(A, B, b) == 0)
                  {
                     /* FOU ND */
                     i++;  /* C to BASIC */
                     N = i;
                     i = n;   /* exit for */
                  }
                  A++;
               }
            }
         }
         break;
      case F_INSTR_A_B_N:
      case F_INDEX_A_B_N:
         /* N = INSTR( A$, B$ ) */
         /* N = INDEX( A$, B$ ) */
         {
            if (a == 0)
            {
               /* empty searched */
            }
            else
            if (b == 0)
            {
               /* empty pattern */
            }
            else
            if (b > a)
            {
               /* pattern is longer than searched */
            }
            else
            {
               /* search */
               int             i;
               int             n;
               n = a - b;  /* last valid search
                      * position */
               n++;
               /* search */
               for (i = 0; i < n; i++)
               {
                  if (bwb_memcmp(A, B, b) == 0)
                  {
                     /* FOU ND */
                     i++;  /* C to BASIC */
                     N = i;
                     i = n;   /* exit for */
                  }
                  A++;
               }
            }
         }
         break;
      case F_SPACE4_X_S:
      case F_SPACE_X_S:
      case F_SPA_X_S:
         /* S$ = SPACE$( X ) */
         /* S$ = SPACE( X ) */
         /* S$ = SPA( X ) */
         {
            /* P1LEN */
            if (x == 0)
            {
               /* no copies */
            }
            else
            {
               bwb_memset(S, (char) ' ', x);
               s = x;
            }
         }
         break;
      case F_STRING4_X_Y_S:
      case F_STRING_X_Y_S:
      case F_STR_X_Y_S:
         /* S$ = STRING$( X, Y ) */
         /* S$ = STRING( X, Y ) */
         /* S$ = STR( X, Y ) */
         {
            /* P1LEN|P2BYT */
            if (x == 0)
            {
               /* no copies */
            }
            else
            {
               bwb_memset(S, (char) y, x);
               s = x;
            }
         }
         break;
      case F_STRING4_X_A_S:
         /* S$ = STRING$( X, A$ ) */
         {
            /* P1LEN|P2BYT */
            if (x == 0)
            {
               /* no copies */
            }
            else
            {
               bwb_memset(S, (char) A[0], x);
               s = x;
            }
         }
         break;
      case F_LIN_X_S:
         /* S$ = LIN( X ) */
         {
            /* P1LEN */
            if (x == 0)
            {
               /* no copies */
            }
            else
            {
               bwb_memset(S, (char) '\n', x);
               s = x;
            }
         }
         break;
      case F_MID4_A_X_S:
      case F_MID_A_X_S:
         /* S$ = MID$( A$, X ) */
         /* S$ = MID( A$, X ) */
         {
            /* P1ANY|P2POS */
            if (a == 0)
            {
               /* empty string */
            }
            else
            if (x > a)
            {
               /* start beyond length */
            }
            else
            {
               x--;  /* BASIC to C */
               a -= x;  /* nummber of characters to
                   * copy */
               A += x;  /* pointer to first character
                   * to copy */
               bwb_memcpy(S, A, a);
               s = a;
            }
         }
         break;
      case F_MID4_A_X_Y_S:
      case F_MID_A_X_Y_S:
      case F_SEG4_A_X_Y_S:
      case F_SEG_A_X_Y_S:
         /* S$ = MID$( A$, X, Y ) */
         /* S$ = MID( A$, X, Y ) */
         /* S$ = SEG$( A$, X, Y ) */
         /* S$ = SEG( A$, X, Y ) */
         {
            /* P1ANY|P2POS|P3LEN */
            if (a == 0)
            {
               /* empty string */
            }
            else
            if (x > a)
            {
               /* start beyond length */
            }
            else
            if (y == 0)
            {
               /* empty string */
            }
            else
            {
               x--;  /* BASIC to C */
               a -= x;
               /* maximum nummber of characters to
                * copy */
               a = MIN(a, y);
               A += x;
               /* pointer to first character to copy */
               bwb_memcpy(S, A, a);
               s = a;
            }
         }
         break;
      case F_LEFT4_A_X_S:
      case F_LEFT_A_X_S:
         /* S$ = LEFT$( A$, X ) */
         /* S$ = LEFT( A$, X ) */
         {
            /* P1ANY|P2LEN */
            if (a == 0)
            {
               /* empty string */
            }
            else
            if (x == 0)
            {
               /* empty string */
            }
            else
            {
               a = MIN(a, x);
               bwb_memcpy(S, A, a);
               s = a;
            }
         }
         break;
      case F_RIGHT4_A_X_S:
      case F_RIGHT_A_X_S:
         /* S$ = RIGHT$( A$, X ) */
         /* S$ = RIGHT( A$, X ) */
         {
            /* P1ANY|P2LEN */
            if (a == 0)
            {
               /* empty string */
            }
            else
            if (x == 0)
            {
               /* empty string */
            }
            else
            {
               x = MIN(a, x);
               A += a;
               A -= x;
               bwb_memcpy(S, A, x);
               s = x;
            }
         }
         break;
      case F_HEX4_X_S:
         /* S$ = HEX$( X ) */
         {
            sprintf(S, "%X", x);
            s = bwb_strlen(S);
         }
         break;
      case F_OCT4_X_S:
         /* S$ = OCT$( X ) */
         {
            sprintf(S, "%o", x);
            s = bwb_strlen(S);
         }
         break;
      case F_CHR_X_S:
      case F_CHR4_X_S:
      case F_CHAR4_X_S:
         /* S$ = CHR( X ) */
         /* S$ = CHR$( X ) */
         /* S$ = CHAR$( X ) */

         /* P1ANY */
         if( My->CurrentVersion->OptionVersionBitmask & ( I70 | I73 ) )
         {
            /* IBM System/360 & System/370 BASIC dialects: the opposite of N = NUM( A$ ) */
            BasicNumerc(X, S);
            s = bwb_strlen(S);
         }
         else
         {
            if( x < 0 || x > 255 )
            {
               IsError = 'X';
            }
            else
            {
               S[0] = (char) x;
               s = 1;
            }
         }
         break;
      case F_CHAR_X_Y_S:
         /* S$ = CHAR( X, Y ) ' same as STRING$(Y,X) */
         {
            /* P1BYT|P2LEN */
            if (y == 0)
            {
               /* no copies */
            }
            else
            {
               bwb_memset(S, (char) x, y);
               s = y;
            }
         }
         break;
      case F_LEN_A_N:
         /* N = LEN( A$ ) */
         {
            N = a;
         }
         break;
      case F_POS_A_B_N:
         /* N = POS( A$, B$ ) */
         {
            if (b == 0)
            {
               /* empty pattern */
               N = 1;
            }
            else
            if (a == 0)
            {
               /* empty searched */
            }
            else
            if (b > a)
            {
               /* pattern is longer than searched */
            }
            else
            {
               /* search */
               int             i;
               int             n;
               n = a - b;  /* last valid search
                      * position */
               n++;
               /* search */
               for (i = 0; i < n; i++)
               {
                  if (bwb_memcmp(A, B, b) == 0)
                  {
                     /* FOU ND */
                     i++;  /* C to BASIC */
                     N = i;
                     i = n;   /* exit for */
                  }
                  A++;
               }
            }
         }
         break;
      case F_MATCH_A_B_X_N:
         /* N = POS( A$, B$, X ) */
         {
            N = str_match( A, a, B, b, x );
         }
         break;
      case F_POS_A_B_X_N:
         /* N = POS( A$, B$, X ) */
         {
            if (b == 0)
            {
               /* empty pattern */
               N = 1;
            }
            else
            if (a == 0)
            {
               /* empty searched */
            }
            else
            if (b > a)
            {
               /* pattern is longer than searched */
            }
            else
            {
               /* search */
               int             i;
               int             n;
               n = a - b;  /* last valid search position */
               n++;

               /* search */
               x--;  /* BASIC to C */
               A += x;  /* advance to the start
                   * position */
               for (i = x; i < n; i++)
               {
                  if (bwb_memcmp(A, B, b) == 0)
                  {
                     /* FOU ND */
                     N = i + 1;  /* C to BASIC */
                     i = n;   /* exit for */
                  }
                  A++;
               }
            }
         }
         break;
      case F_VAL_A_N:
      case F_NUM_A_N:
         /* N = VAL( A$ ) */
         /* N = NUM( A$ ) */
         {
            /* P1ANY */
            int             ScanResult;
            BasicNumberType Value;
            ScanResult = sscanf(A, BasicNumberScanFormat, &Value);
            if (ScanResult != 1)
            {
               /* not a number */
               if (My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* VAL("X") = 0 */ )
               {
                  /* IGNORE */
                  N = 0;
               }
               else
               {
                  /* ERROR */
                  IsError = 'A';
               }
            }
            else
            {
               /* OK */
               N = Value;
            }
         }
         break;
      case F_STR4_X_S:
      case F_NUM4_X_S:
         /* S$ = STR$( X ) */
         /* S$ = NUM$( X ) */
         {
            /* P1ANY */
            BasicNumerc(X, S);
            s = bwb_strlen(S);
         }
         break;
      case F_DATE_N:
         /* N = DATE ' YYYYDDD  */
         {
            /* PNONE */
            /* ECMA-116 */
            time(&t);
            lt = localtime(&t);
            N = lt->tm_year;
            N *= 1000;
            N += lt->tm_yday;
            N += 1;
         }
         break;
      case F_DATE4_X_S:
      case F_DATE4_S:
      case F_DAT4_S:
         /* S$ = DATE$( X ) ' value of X is ignored */
         /* S$ = DATE$ */
         /* S$ = DAT$ */
         {
            /* PNONE */
            time(&t);
            lt = localtime(&t);
            s = strftime(S, BasicStringLengthMax, My->CurrentVersion->OptionDateFormat, lt);
         }
         break;
      case F_CLK_X_S:
      case F_CLK4_S:
      case F_TI4_S:
      case F_TIME4_S:
      case F_TIME4_X_S:
         /* S$ = CLK(X) ' the value of paameter X is ignored */
         /* S$ = CLK$ */
         /* S$ = TI$ */
         /* S$ = TIME$ */
         /* S$ = TIME$(X) ' the value of paameter X is ignored */
         {
            /* PNONE */
            time(&t);
            lt = localtime(&t);
            s = strftime(S, BasicStringLengthMax, My->CurrentVersion->OptionTimeFormat, lt);
         }
         break;
      case F_TI_N:
      case F_TIM_N:
      case F_TIME_N:
      case F_TIME_X_N:
      case F_TIMER_N:
         /* N = TI */
         /* N = TIM */
         /* N = TIME */
         /* N = TIME( X ) ' value of X is ignored */
         /* N = TIMER */
         /* N = CPU */
         {
            /* PNONE */
            time(&t);
            lt = localtime(&t);
            if( My->CurrentVersion->OptionVersionBitmask & ( G67 ) )
            {
               N = lt->tm_hour;
               N *= 60;
               N += lt->tm_min;
               N *= 60;
               N += lt->tm_sec;
               /* number of seconds since midnight */
               N -= My->StartTime; 
               /* elapsed run time */
            }
            else
            {
               N = lt->tm_hour;
               N *= 60;
               N += lt->tm_min;
               N *= 60;
               N += lt->tm_sec;
               /* number of seconds since midnight */
            }
         }
         break;
      case F_CLK_X_N:
         /* N = CLK( X ) ' value of X is ignored */
         {
            /* PNONE */
            time(&t);
            lt = localtime(&t);
            N = lt->tm_hour;
            N *= 60;
            N += lt->tm_min;
            N *= 60;
            N += lt->tm_sec;
            N /= 3600;
            /* decimal hours: 3:30 PM = 15.50 */
         }
         break;
      
      case F_TIM_X_N:
         /* N = TIM( X ) */
         {
            /* P1BYT */
            time(&t);
            lt = localtime(&t);
            
            if( My->CurrentVersion->OptionVersionBitmask & (G65 | G67) )
            {
               /* value of 'X' is ignored */
               N = lt->tm_hour;
               N *= 60;
               N += lt->tm_min;
               N *= 60;
               N += lt->tm_sec;
               /* number of seconds since midnight */
               N -= My->StartTime; 
               /* elapsed run time */
            }
            else
            {
               switch( x )
               {
               case 0:
                  /* TIM(0) == minute (0..59) */
                  N += lt->tm_min;
                  break;
               case 1:
                  /* TIM(1) == hour (0..23) */
                  N = lt->tm_hour;
                  break;
               case 2:
                  /* TIM(2) == day of year (1..366) */
                  N = 1 + lt->tm_yday;
                  break;
               case 3:
                  /* TIM(3) == year since 1900  (0..) */
                  N = lt->tm_year;
                  break;
               default:
                  IsError = 'X';
               }
            }
         }
         break;
      case F_COMMAND4_X_S:
         /* S$ = COMMAND$(X) */
         if( x < 0 || x > 9 )
         {
            IsError = 'X';
         }
         else
         {
            if( My->COMMAND5[x] == NULL )
            {
               s = 0;
            }
            else
            {
               bwb_strcpy( S, My->COMMAND5[x] );
               s = bwb_strlen( My->COMMAND5[x] );
            }
         }
         break;
      case F_COSH_X_N:
      case F_CSH_X_N:
      case F_HCS_X_N:
         /* N = COSH( X ) */
         /* N = CSH( X ) */
         /* N = HCS( X ) */
         {
            /* P1ANY */
            N = cosh(X);
         }
         break;
      case F_SINH_X_N:
      case F_SNH_X_N:
      case F_HSN_X_N:
         /* N = SINH( X ) */
         /* N = SNH( X ) */
         /* N = HSN( X ) */
         {
            /* P1ANY */
            N = sinh(X);
         }
         break;
      case F_TANH_X_N:
      case F_HTN_X_N:
         /* N = TANH( X ) */
         /* N = HTN( X ) */
         {
            /* P1ANY */
            N = tanh(X);
         }
         break;
      case F_CLG_X_N:
      case F_CLOG_X_N:
      case F_LOG10_X_N:
      case F_LGT_X_N:
         /* N = CLG( X ) */
         /* N = CLOG( X ) */
         /* N = LOG10( X ) */
         /* N = LGT( X ) */
         {
            /* P1GTZ */
            N = log10(X);
         }
         break;
      case F_SLEEP_X_N:
      case F_WAIT_X_N:
      case F_PAUSE_X_N:
         /* N = SLEEP( X ) */
         /* N = WAIT( X ) */
         /* N = PAUSE( X ) */
         {
            /* P1ANY */
            X = X * My->OptionSleepValue;
            if( X <= 0 || X > SHRT_MAX)
            {
               /* do nothing */
            }
            else
            {
               x = (int) bwb_rint( X );
               sleep(x);
            }
         }
         break;
      case F_LOG2_X_N:
      case F_LTW_X_N:
         /* N = LOG2( X ) */
         /* N = LTW( X ) */
         {
            /* P1GTZ */
            N = log(X) / log((BasicNumberType) 2);
         }
         break;
      case F_ACOS_X_N:
      case F_ACS_X_N:
         /* N = ACOS( X ) */
         /* N = ACS( X ) */
         {
            /* P1ANY */
            if (X < -1 || X > 1)
            {
               IsError = 'X';
            }
            else
            {
               N = acos(X);
               if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
               {
                  N = FromRadiansToDegrees( N );
               }
               else
               if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
               {
                  N = FromRadiansToGradians( N );
               }
            }
         }
         break;
      case F_ACSD_X_N:
         /* N = ACSD( X ) */
         {
            /* P1ANY */
            if (X < -1 || X > 1)
            {
               IsError = 'X';
            }
            else
            {
               N = acos(X);
               /* result is always in DEGREES, regardless of OPTION ANGLE setting */
               N = FromRadiansToDegrees( N );
            }
         }
         break;
      case F_ACSG_X_N:
         /* N = ACSG( X ) */
         {
            /* P1ANY */
            if (X < -1 || X > 1)
            {
               IsError = 'X';
            }
            else
            {
               N = acos(X);
               /* result is always in GRADIANS, regardless of OPTION ANGLE setting */
               N = FromRadiansToGradians( N );
            }
         }
         break;

      case F_ASIN_X_N:
      case F_ASN_X_N:
      case F_ARCSIN_X_N:
         /* N = ASIN( X ) */
         /* N = ASN( X ) */
         /* N = ARCSIN( X ) */
         {
            /* P1ANY */
            if (X < -1 || X > 1)
            {
               IsError = 'X';
            }
            else
            {
               N = asin(X);
               if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
               {
                  N = FromRadiansToDegrees( N );
               }
               else
               if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
               {
                  N = FromRadiansToGradians( N );
               }
            }
         }
         break;


      case F_ASND_X_N:
         /* N = ASND( X ) */
         {
            /* P1ANY */
            if (X < -1 || X > 1)
            {
               IsError = 'X';
            }
            else
            {
               N = asin(X);
               /* result is always in DEGREES, regardless of OPTION ANGLE setting */
               N = FromRadiansToDegrees( N );
            }
         }
         break;
      case F_ASNG_X_N:
         /* N = ASNG( X ) */
         {
            /* P1ANY */
            if (X < -1 || X > 1)
            {
               IsError = 'X';
            }
            else
            {
               N = asin(X);
               /* result is always in GRADIANS, regardless of OPTION ANGLE setting */
               N = FromRadiansToGradians( N );
            }
         }
         break;


      case F_COT_X_N:
         /* N = COT( X ) ' = 1 / TAN( X ) */
         {
            /* P1ANY */
            BasicNumberType T;
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
            {
               X = FromDegreesToRadians( X );
            }
            else
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
            {
               X = FromGradiansToRadians( X );
            }
            T = tan(X);
            if (T == 0)
            {
               IsError = 'X';
            }
            else
            {
               N = 1.0 / T;
            }
         }
         break;
      case F_CSC_X_N:
         /* N = CSC( X ) ' = 1 / SIN( X ) */
         {
            /* P1ANY */
            BasicNumberType T;
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
            {
               X = FromDegreesToRadians( X );
            }
            else
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
            {
               X = FromGradiansToRadians( X );
            }
            T = sin(X);
            if (T == 0)
            {
               IsError = 'X';
            }
            else
            {
               N = 1.0 / T;
            }
         }
         break;
      case F_SEC_X_N:
         /* N = SEC( X ) ' = 1 / COS( X ) */
         {
            /* P1ANY */
            BasicNumberType T;
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
            {
               X = FromDegreesToRadians( X );
            }
            else
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
            {
               X = FromGradiansToRadians( X );
            }
            T = cos(X);
            if (T == 0)
            {
               IsError = 'X';
            }
            else
            {
               N = 1.0 / T;
            }
         }
         break;
      case F_UCASE4_A_S:
         /* S$ = UCASE$( A$ ) */
         {
            /* P1ANY */
            if (a == 0)
            {
               /* empty string */
            }
            else
            {
               int             i;
               bwb_memcpy(S, A, a);
               s = a;
               /* BASIC allows embedded NULL
                * characters */
               for (i = 0; i < a; i++)
               {
                  S[i] = bwb_toupper(S[i]);
               }
            }
         }
         break;
      case F_LCASE4_A_S:
         /* S$ = LCASE$( A$ ) */
         {
            /* P1ANY */
            if (a == 0)
            {
               /* empty string */
            }
            else
            {
               int             i;
               bwb_memcpy(S, A, a);
               s = a;
               /* BASIC allows embedded NULL
                * characters */
               for (i = 0; i < a; i++)
               {
                  S[i] = bwb_tolower(S[i]);
               }
            }
         }
         break;
      case F_ANGLE_X_Y_N:
         /* N = ANGLE( X, Y ) */
         {
            /* P1ANY|P2ANY */
            if (X == 0 && Y == 0)
            {
               IsError = 'X';
            }
            else
            {
               N = atan2(Y, X);
               if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
               {
                  N = FromRadiansToDegrees( N );
               }
               else
               if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
               {
                  N = FromRadiansToGradians( N );
               }
            }
         }
         break;
      case F_CEIL_X_N:
         /* N = CEIL( X ) */
         {
            /* P1ANY */
            N = ceil(X);
         }
         break;
      case F_DET_N:
         /* N = DET */
         {
            /* PNONE */
            N = My->LastDeterminant;
         }
         break;
      case F_NUM_N:
         /* N = NUM */
         {
            /* PNONE */
            N = My->LastInputCount;
         }
         break;
      case F_DEG_N:
      case F_DEGREE_N:
         /* N = DEG */
         /* N = DEGREE */
         {
            /* PNONE */
            My->CurrentVersion->OptionFlags |= OPTION_ANGLE_DEGREES;
            My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_GRADIANS;
            N = 0;
         }
         break;
      case F_RAD_N:
      case F_RADIAN_N:
         /* N = RAD */
         /* N = RADIAN */
         {
            /* PNONE */
            My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_DEGREES;
            My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_GRADIANS;
            N = 0;
         }
         break;
      case F_GRAD_N:
      case F_GRADIAN_N:
         /* N = GRAD */
         /* N = GRADIAN */
         {
            /* PNONE */
            My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_DEGREES;
            My->CurrentVersion->OptionFlags |= OPTION_ANGLE_GRADIANS;
            N = 0;
         }
         break;
      case F_DEG_X_N:
      case F_DEGREE_X_N:
         /* N = DEG( X ) */
         /* N = DEGREE( X ) */
         {
            /* P1ANY */
            N = FromRadiansToDegrees( X );
         }
         break;
      case F_RAD_X_N:
         /* N = RAD( X ) */
         {
            /* P1ANY */
            N = FromDegreesToRadians( X );
         }
         break;
      case F_PI_N:
         /* N = PI */
         {
            /* PNONE */
            N = PI;
         }
         break;
      case F_PI_X_N:
         /* N = PI(X) */
         {
            /* P1ANY */
            N = PI * X;
         }
         break;
      case F_LTRIM4_A_S:
         /* S$ = LTRIM$( A$ ) */
         {
            /* P1ANY */
            if (a == 0)
            {
               /* empty string */
            }
            else
            {
               int             i;
               /* BASIC allows embedded NULL
                * characters */
               for (i = 0; i < a && A[i] == ' '; i++)
               {
                  /* skip spaces */
               }
               /* 'A[ i ]' is first non-space
                * character */
               if (i >= a)
               {
                  /* empty string */
               }
               else
               {
                  A += i;
                  a -= i;
                  bwb_memcpy(S, A, a);
                  s = a;
               }
            }
         }
         break;
      case F_RTRIM4_A_S:
         /* S$ = RTRIM$( A$ ) */
         {
            /* P1ANY */
            if (a == 0)
            {
               /* empty string */
            }
            else
            {
               int             i;
               /* BASIC allows embedded NULL
                * characters */
               for (i = a - 1; i >= 0 && A[i] == ' '; i--)
               {
                  /* skip spaces */
               }
               /* 'A[ i ]' is last non-space
                * character */
               if (i < 0)
               {
                  /* empty string */
               }
               else
               {
                  a = i + 1;
                  bwb_memcpy(S, A, a);
                  s = a;
               }
            }
         }
         break;
      case F_TRIM4_A_S:
         /* S$ = TRIM$( A$ ) */
         {
            /* P1ANY */
            if (a == 0)
            {
               /* empty string */
            }
            else
            {
               /* LTRIM */
               int             i;
               /* BASIC allows embedded NULL
                * characters */
               for (i = 0; i < a && A[i] == ' '; i++)
               {
                  /* skip spaces */
               }
               /* 'A[ i ]' is first non-space
                * character */
               if (i >= a)
               {
                  /* empty string */
               }
               else
               {
                  A += i;
                  a -= i;
                  bwb_memcpy(S, A, a);
                  s = a;
                  /* RTRIM */
                  A = S;
                  a = s;
                  if (a == 0)
                  {
                     /* empty string */
                  }
                  else
                  {
                     int             i;
                     /* BASIC allows
                      * embedded NULL
                      * characters */
                     for (i = a - 1; i >= 0 && A[i] == ' '; i--)
                     {
                        /* skip
                         * spaces */
                     }
                     /* 'A[ i ]' is last
                      * non-space
                      * character */
                     if (i < 0)
                     {
                        /* empty
                         * string */
                     }
                     else
                     {
                        a = i + 1;
                        /* bwb_memcpy( S,
                         * A, a ); */
                        s = a;
                     }
                  }
               }
            }
         }
         break;
      case F_MAX_X_Y_N:
         /* N = MAX( X, Y ) */
         {
            N = MAX(X, Y);
         }
         break;
      case F_MAX_A_B_S:
         /* S$ = MAX( A$, B$ ) */
         {
            StringType L;
            StringType R;
            
            L.length = a;
            R.length = b;
            L.sbuffer = A;
            R.sbuffer = B;
            if( str_cmp( &L, &R ) >= 0 )
            {
               /* A >= B */
               bwb_memcpy( S, A, a );
               s = a;
            }
            else
            {
               /* A < B */
               bwb_memcpy( S, B, b );
               s = b;
            }
         }
         break;
      case F_MIN_X_Y_N:
         /* N = MIN( X, Y ) */
         {
            N = MIN(X, Y);
         }
         break;
      case F_MIN_A_B_S:
         /* S$ = MIN( A$, B$ ) */
         {
            StringType L;
            StringType R;
            
            L.length = a;
            R.length = b;
            L.sbuffer = A;
            R.sbuffer = B;
            if( str_cmp( &L, &R ) <= 0 )
            {
               /* A <= B */
               bwb_memcpy( S, A, a );
               s = a;
            }
            else
            {
               /* A > B */
               bwb_memcpy( S, B, b );
               s = b;
            }
         }
         break;
      case F_FP_X_N:
      case F_FRAC_X_N:
         /* N = FP( X ) */
         /* N = FRAC( X ) */
         {
            BasicNumberType FP;
            BasicNumberType IP;
            FP = modf(X, &IP);
            N = FP;
         }
         break;
      case F_IP_X_N:
         /* N = IP( X ) */
         {
            BasicNumberType IP;
            modf(X, &IP);
            N = IP;
         }
         break;
      case F_EPS_X_N:
         /* N = EPS( Number ) */
         {
            N = DBL_MIN;
         }
         break;
      case F_MAXLVL_N:
         /* N = MAXLVL */
         {
            N = EXECLEVELS;
         }
         break;
      case F_MAXNUM_N:
         /* N = MAXNUM */
         {
            N = DBL_MAX;
         }
         break;
      case F_MINNUM_N:
         /* N = MINNUM */
         {
            N = -DBL_MAX;
         }
         break;
      case F_MAXDBL_N:
         /* N = MAXDBL */
         {
            N = DBL_MAX;
         }
         break;
      case F_MINDBL_N:
         /* N = MINDBL */
         {
            N = -DBL_MAX;
         }
         break;
      case F_MAXSNG_N:
         /* N = MAXSNG */
         {
            N = FLT_MAX;
         }
         break;
      case F_MINSNG_N:
         /* N = MINSNG */
         {
            N = -FLT_MAX;
         }
         break;
      case F_MAXCUR_N:
         /* N = MAXCUR */
         {
            N = LONG_MAX;
         }
         break;
      case F_MINCUR_N:
         /* N = MINCUR */
         {
            N = LONG_MIN;
         }
         break;
      case F_MAXLNG_N:
         /* N = MAXLNG */
         {
            N = LONG_MAX;
         }
         break;
      case F_MINLNG_N:
         /* N = MINLNG */
         {
            N = LONG_MIN;
         }
         break;
      case F_MAXINT_N:
         /* N = MAXINT */
         {
            N = SHRT_MAX;
         }
         break;
      case F_MININT_N:
         /* N = MININT */
         {
            N = SHRT_MIN;
         }
         break;
      case F_MAXBYT_N:
         /* N = MAXBYT */
         {
            N = UCHAR_MAX;
         }
         break;
      case F_MINBYT_N:
         /* N = MINBYT */
         {
            N = 0;
         }
         break;
      case F_MAXDEV_N:
         /* N = MAXDEV */
         {
            N = BasicFileNumberMax;
         }
         break;
      case F_MINDEV_N:
         /* N = MINDEV */
         {
            N = 0;
         }
         break;

      case F_MOD_X_Y_N:
         /* N = MOD( X, Y ) */
         {
            /* P1ANY|P2NEZ */
            BasicNumberType IP;

            IP = floor(X / Y);
            N = X - (Y * IP);
         }
         break;
      case F_REMAINDER_X_Y_N:
         /* REMAINDER( X, Y ) */
         {
            /* P1ANY|P2NEZ */
            BasicNumberType Value;
            BasicNumberType IP;

            Value = X / Y;
            modf(Value, &IP);
            N = X - (Y * IP);
         }
         break;
      case F_ROUND_X_Y_N:
         /* N = ROUND( X, Y ) == INT(X*10^Y+.5)/10^Y */
         {
            /* P1ANY | P2INT */
            if (y < -32 || y > 32)
            {
               IsError = 'Y';
            }
            else
            {
               BasicNumberType T;   /* 10^Y */

               T = pow(10.0, Y);
               if (T == 0)
               {
                  IsError = 'Y';
               }
               else
               {
                  N = floor(X * T + 0.5) / T;
               }
            }
         }
         break;
      case F_TRUNCATE_X_Y_N:
         /* N = TRUNCATE( X, Y ) == INT(X*10^Y)/10^Y */
         {
            /* P1ANY | P2INT */
            if (y < -32 || y > 32)
            {
               IsError = 'Y';
            }
            else
            {
               BasicNumberType T;   /* 10^Y */

               T = pow(10.0, Y);
               if (T == 0)
               {
                  IsError = 'Y';
               }
               else
               {
                  N = floor(X * T) / T;
               }
            }
         }
         break;
      case F_MAXLEN_A_N:
         /* N = MAXLEN( A$ ) */
         {
            N = BasicStringLengthMax;
         }
         break;
      case F_ORD_A_N:
         /* N = ORD( A$ ) */
         {
            /* P1BYT */
            if (a == 1)
            {
               /* same as ASC(A$) */
               N = A[0];
            }
            else
            {
               /* lookup Acronym */
               int             c;
               N = -1;  /* not found */
               for (c = 0; c < NUM_ACRONYMS; c++)
               {
                  if (bwb_stricmp(AcronymTable[c].Name, A) == 0)
                  {
                     /* found */
                     N = AcronymTable[c].Value;
                     c = NUM_ACRONYMS; /* exit for */
                  }
               }
               if (N < 0)
               {
                  /* not found */
                  IsError = 'A';
               }
            }
         }
         break;
      case F_RENAME_A_B_N:
         /* N = RENAME( A$, B$ ) */
         {
            /* P1BYT | P2BYT */
            if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
            {
               strupper( A ); /* CBASIC-II: file names are always upper case */
               strupper( B ); /* CBASIC-II: file names are always upper case */
            }
            if( rename( A, B ) )
            {
               /* ERROR -- return FALSE */
               N = 0;
            }
            else
            {
               /* OK -- return TRUE */
               N = -1;
            }
         }
         break;
      case F_SIZE_A_N:
         /* N = SIZE( A$ ) */
         {
            /* P1BYT */
            FILE * F;
            
            if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
            {
               strupper( A ); /* CBASIC-II: file names are always upper case */
            }

            F = fopen( A, "rb" );
            if( F != NULL )
            {
               long n;

               fseek( F, 0, SEEK_END );
               n = ftell( F );
               fclose( F );

               if( n > 0 )
               {
                  /* round up filesize to next whole kilobyte */
                  n += 1023;
                  n /= 1024;
               }
               else
               {
                  /* a zero-length file returns 0 */
                  n = 0;
               }
               N = n;
            }
            /* a non-existing file returns 0 */
         }
         break;
      case F_REPEAT4_X_Y_S:
         /* S$ = REPEAT$( X, Y ) ' X is count, Y is code */
         {
            /* P1LEN | P2BYT */
            if (x == 0)
            {
               /* empty string */
            }
            else
            {
               bwb_memset(S, (char) y, x);
               s = x;
            }
         }
         break;
      case F_REPEAT4_X_A_S:
         /* S$ = REPEAT$( X, A$ ) ' X is count, A$ is code */
         {
            /* P1LEN | P2BYT */
            if (x == 0)
            {
               /* empty string */
            }
            else
            {
               bwb_memset(S, (char) A[0], x);
               s = x;
            }
         }
         break;
      case F_FIX_X_N:
         /* N = FIX( X ) */
         {
            /* N = bwb_rint(X); */
            if( X < 0 )
            {
               N = -floor(-X);
            }
            else
            {
               N = floor(X);
            }
         }
         break;
      case F_ABS_X_N:
         /* N = ABS( X ) */
         {
            N = fabs(X);
         }
         break;
      case F_ATN_X_N:
      case F_ATAN_X_N:
      case F_ARCTAN_X_N:
         /* N = ATN( X ) */
         /* N = ATAN( X ) */
         /* N = ARCTAN( X ) */
         {
            N = atan(X);
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
            {
               N = FromRadiansToDegrees( N );
            }
            else
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
            {
               N = FromRadiansToGradians( N );
            }
         }
         break;
      case F_ATND_X_N:
         /* N = ATND( X ) */
         {
            N = atan(X);
            N = FromRadiansToDegrees( N );
         }
         break;
      case F_ATNG_X_N:
         /* N = ATNG( X ) */
         {
            N = atan(X);
            N = FromRadiansToGradians( N );
         }
         break;
      case F_COS_X_N:
         /* N = COS( X ) */
         {
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
            {
               X = FromDegreesToRadians( X );
            }
            else
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
            {
               X = FromGradiansToRadians( X );
            }
            N = cos(X);
         }
         break;
      case F_COSD_X_N:
         /* N = COSD( X ) */
         {
            X = FromDegreesToRadians( X );
            N = cos(X);
         }
         break;
      case F_COSG_X_N:
         /* N = COSG( X ) */
         {
            X = FromGradiansToRadians( X );
            N = cos(X);
         }
         break;
      case F_EXP_X_N:
         /* N = EXP( X ) */
         {
            N = exp(X);
         }
         break;
      case F_INT_X_N:
         /* N = INT( X ) */
         {
            N = floor(X);
         }
         break;
      case F_FLOAT_X_N:
      case F_INT5_X_N:
         /* N = FLOAT( X ) */
         /* N = INT%( X ) */
         {
            N = bwb_rint(X);
         }
         break;
      case F_INITIALIZE_N:
         /* INITIALIZE */
         {
            N = 0;
         }
         break;
      case F_LOG_X_N:
      case F_LN_X_N:
      case F_LOGE_X_N:
         /* N = LOG( X ) */
         /* N = LN( X ) */
         /* N = LOGE( X ) */
         {
            /* P1GTZ */
            N = log(X);
         }
         break;
      case F_RND_N:
         /* N = RND */
         {
            N = rand();
            N /= RAND_MAX;
         }
         break;
      case F_RND_X_N:
         /* N = RND( X ) */
         {
            N = rand();
            N /= RAND_MAX;
         }
         break;
      case F_SGN_X_N:
         /* N = SGN( X ) */
         {
            if (X > 0)
            {
               N = 1;
            }
            else
            if (X < 0)
            {
               N = -1;
            }
            else
            {
               N = 0;
            }
         }
         break;
      case F_SIN_X_N:
         /* N = SIN( X ) */
         {
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
            {
               X = FromDegreesToRadians( X );
            }
            else
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
            {
               X = FromGradiansToRadians( X );
            }
            N = sin(X);
         }
         break;
      case F_SIND_X_N:
         /* N = SIND( X ) */
         {
            X = FromDegreesToRadians( X );
            N = sin(X);
         }
         break;
      case F_SING_X_N:
         /* N = SING( X ) */
         {
            X = FromGradiansToRadians( X );
            N = sin(X);
         }
         break;
      case F_SQR_X_N:
      case F_SQRT_X_N:
         /* N = SQR( X ) */
         /* N = SQRT( X ) */
         {
            /* P1GEZ */
            N = sqrt(X);
         }
         break;
      case F_TAN_X_N:
         /* N = TAN( X ) */
         {
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_DEGREES)
            {
               X = FromDegreesToRadians( X );
            }
            else
            if (My->CurrentVersion->OptionFlags & OPTION_ANGLE_GRADIANS)
            {
               X = FromGradiansToRadians( X );
            }
            N = tan(X);
         }
         break;
      case F_TAND_X_N:
         /* N = TAND( X ) */
         {
            X = FromDegreesToRadians( X );
            N = tan(X);
         }
         break;
      case F_TANG_X_N:
         /* N = TANG( X ) */
         {
            X = FromGradiansToRadians( X );
            N = tan(X);
         }
         break;
      case F_SPC_X_S:
         /* S$ = SPC( X ) */
         {
            /* P1ANY */
            /* SPECIAL RULES APPLY.  PART OF PRINT COMMAND.  WIDTH > 0 */
            X = bwb_rint(X);
            if (X < 1 || X > 255)
            {
               if( bwb_Warning_Overflow("*** WARNING: INVALID SPC() ***") )
               {
                  /* ERROR */
               }
               /* CONTINUE */
               X = 1;
            }
            x = (int) X;
            S[0] = PRN_SPC;
            S[1] = (char) x;
            s = 2;
         }
         break;
      case F_TAB_X_S:
         /* S$ = TAB( X ) */
         {
            /* P1ANY */
            /* SPECIAL RULES APPLY.  PART OF PRINT COMMAND.  WIDTH > 0 */
            X = bwb_rint(X);
            if (X < 1 || X > 255)
            {
               if( bwb_Warning_Overflow("*** WARNING: INVALID TAB() ***") )
               {
                  /* ERROR */
               }
               /* CONTINUE */
               X = 1;
            }
            x = (int) X;
            S[0] = PRN_TAB;
            S[1] = (char) x;
            s = 2;
         }
         break;
      case F_POS_N:
         /* N = POS */
         {
            /* PNONE */
            N = My->SYSOUT->col;
         }
         break;
      case F_COUNT_N:
         /* N = COUNT */
         /* COUNT = POS - 1 */
         {
            /* PNONE */
            N = My->SYSOUT->col;
            N--;
         }
         break;
      case F_POS_X_N:
         /* N = POS( X ) */
         {
            /* P1DEV */
            if( x == 0 )
            {
               N = My->SYSOUT->col;
            }
            else
            if( x < 0 )
            {
               N = My->SYSPRN->col;
            }
            else
            {
               FileType * F;
               F = find_file_by_number( x );
               if( F == NULL )
               {
                  IsError = 'X';
               }
               else
               {
                  N = F->col;
               }
            }
         }
         break;
      case F_INPUT4_X_Y_S:
         /* S$ = INPUT$( X, Y )  */
         {
            /* P1LEN|P2DEV */
            if( y <= 0 )
            {
               IsError = 'Y';
            }
            else
            {
               FileType * F;
   
               F = find_file_by_number( y );
               if( F == NULL )
               {
                  IsError = 'Y';
               }
               else
               {
                  if ((F->mode & DEVMODE_READ) == 0)
                  {
                     IsError = 'Y';
                  }
                  else
                  if (x == 0)
                  {
                     /* empty string */
                  }
                  else
                  {
                     FILE           *fp;
                     fp = F->cfp;
                     if (fp == NULL)
                     {
                        IsError = 'Y';
                     }
                     else
                     {
                        s = fread(S, 1, x, fp);
                        s = MAX(s, 0); /* if( s < 0 ) s = 0; */
                     }
                  }
               }
            }
         }
         break;
      case F_ERROR_X_N:
         /* ERROR X */
         {
            /* P1BYT */
            bwb_Warning(x, "");
            N = 0;
         }
         break;
      case F_ERROR_X_A_N:
         /* ERROR X, A$ */
         {
            /* P1BYT */
            bwb_Warning(x, A);
            N = 0;
         }
         break;
      case F_ERR_N:
      case F_ERRN_N:
         /* N = ERR */
         /* N = ERRN */
         {
            /* PNONE */
            N = My->err_number;
         }
         break;
      case F_ERL_N:
      case F_ERRL_N:
         /* N = ERL */
         /* N = ERRL */
         {
            /* PNONE */
            if( My->err_line != NULL )
            {
                N = My->err_line->number;
            }
         }
         break;
      case F_ERR4_S:
      case F_ERROR4_S:
         /* S = ERR$ */
         /* S = ERROR$ */
         {
            /* PNONE */
            s = bwb_strlen(My->ErrMsg);
            if (s > 0)
            {
               bwb_strcpy(S, My->ErrMsg);
            }
         }
         break;


         /********************************************************************************************
         **  Keep the platform specific functions together.
         *********************************************************************************************/
      case F_INP_X_N:
      case F_PIN_X_N:
         /* N = INP( X ) */
         /* N = PIN( X ) */
         {
            /* P1BYT */
            IsError = 0xFF;
         }
         break;
      case F_PDL_X_N:
         /* N = PDL( X ) */
         {
            /* P1BYT */
            IsError = 0xFF;
         }
         break;
      case F_WAIT_X_Y_N:
         /* WAIT X, Y */
         {
            /* P1NUM|P2NUM */
            /* P1INT|P2BYT */
            IsError = 0xFF;
         }
         break;
      case F_WAIT_X_Y_Z_N:
         /* WAIT X, Y, Z */
         {
            /* P1NUM|P2NUM|P3NUM */
            /* P1INT|P2BYT|P3BYT */
            IsError = 0xFF;
         }
         break;
      case F_OUT_X_Y_N:
         /* OUT X, Y */
         {
            /* P1NUM|P2NUM */
            /* P1INT|P2BYT */
            IsError = 0xFF;
         }
         break;
      case F_PEEK_X_N:
      case F_EXAM_X_N:
      case F_FETCH_X_N:
         /* N = PEEK( X ) */
         /* N = EXAM( X ) */
         /* N = FETCH( X ) */
         {
            /* P1INT */
            IsError = 0xFF;
         }
         break;
      case F_POKE_X_Y_N:
      case F_FILL_X_Y_N:
      case F_STUFF_X_Y_N:
         /* POKE X, Y */
         /* FILL X, Y */
         /* STUFF X, Y */
         {
            /* P1NUM|P2NUM */
            /* P1INT|P2BYT */
            IsError = 0xFF;
         }
         break;
      case F_CLS_N:
      case F_HOME_N:
         /* CLS */
         /* HOME */
         {
            /* PNONE */
            switch (My->OptionTerminalType)
            {
            case C_OPTION_TERMINAL_NONE:
               break;
            case C_OPTION_TERMINAL_ADM:
               fprintf(My->SYSOUT->cfp, "%c", 26);
               break;
            case C_OPTION_TERMINAL_ANSI:
               fprintf(My->SYSOUT->cfp, "%c[2J", 27);
               fprintf(My->SYSOUT->cfp, "%c[%d;%dH", 27, 1, 1);
               break;
            default:
               IsError = 0xFF;
               break;
            }
            fflush(My->SYSOUT->cfp);
         }
         break;
      case F_LOCATE_X_Y_N:
         /* LOCATE X, Y */
         {
            /* P1NUM|P2NUM */
            /* P1BYT|P2BYT */
            /* X is 1 based */
            /* Y is 1 based */
            switch (My->OptionTerminalType)
            {
            case C_OPTION_TERMINAL_NONE:
               break;
            case C_OPTION_TERMINAL_ADM:
               fprintf(My->SYSOUT->cfp, "%c=%c%c", 27, x + 32, y + 32);
               break;
            case C_OPTION_TERMINAL_ANSI:
               fprintf(My->SYSOUT->cfp, "%c[%d;%dH", 27, x, y);
               break;
            default:
               IsError = 0xFF;
               break;
            }
            fflush(My->SYSOUT->cfp);
         }
         break;
      case F_CUR_X_Y_S:
         /* CUR X, Y */
         {
            /* P1NUM|P2NUM */
            /* P1BYT|P2BYT */
            x++; /* X is 0 based */
            y++; /* Y is 0 based */
            switch (My->OptionTerminalType)
            {
            case C_OPTION_TERMINAL_NONE:
               break;
            case C_OPTION_TERMINAL_ADM:
               fprintf(My->SYSOUT->cfp, "%c=%c%c", 27, x + 32, y + 32);
               break;
            case C_OPTION_TERMINAL_ANSI:
               fprintf(My->SYSOUT->cfp, "%c[%d;%dH", 27, x, y);
               break;
            default:
               IsError = 0xFF;
               break;
            }
            fflush(My->SYSOUT->cfp);
            s = 0;
         }
         break;
      case F_VTAB_X_N:
         /* VTAB X  */
         {
            /* P1BYT */
            switch (My->OptionTerminalType)
            {
            case C_OPTION_TERMINAL_NONE:
               break;
            case C_OPTION_TERMINAL_ADM:
               fprintf(My->SYSOUT->cfp, "%c=%c%c", 27, x + 32, 1 + 32);
               break;
            case C_OPTION_TERMINAL_ANSI:
               fprintf(My->SYSOUT->cfp, "%c[%d;%dH", 27, x, 1);
               break;
            default:
               IsError = 0xFF;
               break;
            }
            fflush(My->SYSOUT->cfp);
         }
         break;
      case F_COLOR_X_Y_N:
         /* COLOR X, Y */
         {
            /* P1NUM|P2NUM */
            /* P1BYT|P2BYT */
            switch (My->OptionTerminalType)
            {
            case C_OPTION_TERMINAL_NONE:
               break;
            case C_OPTION_TERMINAL_ADM:
               break;
            case C_OPTION_TERMINAL_ANSI:
               fprintf(My->SYSOUT->cfp, "%c[%d;%dm", 27, 30 + x, 40 + y);
               break;
            default:
               IsError = 0xFF;
               break;
            }
            fflush(My->SYSOUT->cfp);
         }
         break;
      case F_FILES_N:
      case F_CATALOG_N:
         /* FILES */
         /* CATALOG */
         {
            /* PNONE */
            VariableType *v; 
            char   Buffer[BasicStringLengthMax + 1];

            if( (v = var_find(DEFVNAME_FILES,0,FALSE)) == NULL )
            {
                bwb_strcpy(Buffer, DEF_FILES);
            }
            else
            {
               VariantType variant;
               
               if( var_get( v, &variant ) == FALSE )
               {
                  bwb_strcpy( Buffer, DEF_FILES );
               }
               else
               {
                  if( variant.TypeChar == '$' )
                  {
                     bwb_strcpy( Buffer, variant.Buffer );
                     RELEASE( (&variant) );
                  }
                  else
                  {
                     bwb_strcpy( Buffer, DEF_FILES );
                  }
               }
            }
            N = system( Buffer );
         }
         break;
      case F_FILES_A_N:
      case F_CATALOG_A_N:
         /* FILES A$ */
         /* CATALOG A$ */
         {
            /* P1BYT */
            VariableType *v; 
            char   Buffer[BasicStringLengthMax + 1];

            if( (v = var_find(DEFVNAME_FILES,0,FALSE)) == NULL )
            {
                bwb_strcpy(Buffer, DEF_FILES);
            }
            else
            {
               VariantType variant;
               
               if( var_get( v, &variant ) == FALSE )
               {
                  bwb_strcpy( Buffer, DEF_FILES );
               }
               else
               {
                  if( variant.TypeChar == '$' )
                  {
                     bwb_strcpy( Buffer, variant.Buffer );
                     RELEASE( (&variant) );
                  }
                  else
                  {
                     bwb_strcpy( Buffer, DEF_FILES );
                  }
               }
            }
            bwb_strcat(Buffer, " ");
            bwb_strcat(Buffer, A);
            N = system(Buffer);
         }
         break;
      case F_FRE_N:
      case F_FRE_X_N:
      case F_FRE_A_N:
      case F_FREE_N:
      case F_FREE_X_N:
      case F_FREE_A_N:
      case F_MEM_N:
      case F_TOP_N:
         /* N = FRE(    ) */
         /* N = FRE( X  ) */
         /* N = FRE( X$ ) */
         /* N = FREE(    ) */
         /* N = FREE( X  ) */
         /* N = FREE( X$ ) */
         /* N = MEM(    ) */
         /* N = TOP(    ) */
         {
            N = 32000;  /* reasonable value */
         }
         break;
      case F_SHELL_A_N:
         /* N = SHELL( A$ ) */
         {
            /* P1BYT */
            N = system(A);
         }
         break;
      case F_CHDIR_A_N:
         /* CHDIR A$ */
         {
            /* P1BYT */
#if DIRECTORY_CMDS
            N = chdir(A);
#else
            IsError = 0xFF;
#endif
         }
         break;
      case F_MKDIR_A_N:
         /* MKDIR A$ */
         {
            /* P1BYT */
#if DIRECTORY_CMDS
#if MKDIR_ONE_ARG
            N = mkdir(A);
#else
            N = mkdir(A, PERMISSIONS);
#endif
#else
            IsError = 0xFF;
#endif
         }
         break;
      case F_RMDIR_A_N:
         /* RMDIR A$ */
         {
            /* P1BYT */
#if DIRECTORY_CMDS
            N = rmdir(A);
#else
            IsError = 0xFF;
#endif
         }
         break;
      case F_KILL_A_N:
      case F_UNSAVE_A_N:
         /* KILL A$ */
         /* UNSAVE A$ */
         {
            /* P1BYT */
            N = remove(A);
         }
         break;
      case F_NAME_A_B_N:
         /* NAME A$ AS B$      */
         /* N = NAME( A$, B$ ) */
         {
            /* P1BYT|P2BYT */
            N = rename(A, B);
         }
         break;
      case F_INPUT4_X_S:
         /* S$ = INPUT$( X )  */
         {
            /* P1LEN */
            if (x == 0)
            {
               /* empty string */
            }
            else
            {
               for (s = 0; s < x; s++)
               {
                  int             c;
                  c = fgetc( My->SYSIN->cfp );
                  if ((c == EOF) || (c == '\n') || (c == '\r'))
                  {
                     break;
                  }
                  S[s] = c;
               }
               S[s] = 0;
            }
         }
         break;
      case F_INKEY4_S:
      case F_KEY4_S:
      case F_KEY_S:
         /* S$ = INKEY$ */
         /* S$ = KEY$ */
         /* S$ = KEY */
         {
            /* PNONE */
            int             c;

            c = fgetc( My->SYSIN->cfp );
            if (c < 0 || c > 255)
            {
               /* EOF */
            }
            else
            {
               S[s] = c;
               s++;
            }
            S[s] = 0;
         }
         break;
      case F_NULL_X_N:
         /* NULL X */
         {
            /* P1NUM */
            /* P1BYT */
            My->LPRINT_NULLS = x;
            N = 0;
         }
         break;
      case F_LWIDTH_X_N:
         /* LWIDTH X */
         {
            /* P1NUM */
            /* P1BYT */
            My->SYSPRN->width = x;
            My->SYSPRN->col = 1;
            N = 0;
         }
         break;
      case F_LPOS_N:
         /* N = LPOS */
         {
            /* PNONE */
            /* PNONE */
            N = My->SYSPRN->col;
         }
         break;
      case F_TRON_N:
      case F_TRACE_N:
      case F_FLOW_N:
         /* TRON */
         /* TRACE */
         /* FLOW */
         {
            /* PNONE */
            prn_xprintf("Trace is ON\n");
            My->bwb_trace = TRUE;
            N = 0;
         }
         break;
      case F_TROFF_N:
      case F_NOTRACE_N:
      case F_NOFLOW_N:
         /* TROFF */
         /* NOTRACE */
         /* NOFLOW */
         {
            /* PNONE */
            prn_xprintf("Trace is OFF\n");
            My->bwb_trace = FALSE;
            N = 0;
         }
         break;
      case F_RANDOMIZE_N:
      case F_RAN_N:
      case F_RANDOM_N:
         /* RANDOMIZE */
         /* RAN */
         /* RANDOM */
         {
            /* PNONE */
            /* USE THE CURRENT TIME AS THE SEED */
            time(&t);
            lt = localtime(&t);
            x = lt->tm_hour * 3600 + lt->tm_min * 60 + lt->tm_sec;
            srand(x);
            N = 0;
         }
         break;
      case F_RANDOMIZE_X_N:
      case F_RAN_X_N:
      case F_RANDOM_X_N:
         /* RANDOMIZE X */
         /* RAN X */
         /* RANDOM X */
         {
            /* P1NUM */
            /* P1ANY */
            x = (int) bwb_rint( X );
            srand(x);
            N = 0;
         }
         break;
      default:
         {
            /* NOT IMPLEMENTED ON THIS PLATFORM */
            IsError = 0xFF;
         }
      }
   }
   /* sanity check */
   if (IsError == 0)
   {
      if (f->ReturnType == BasicStringSuffix)
      {
         /* STRING */
         if ( /* s < 0 || */ s > BasicStringLengthMax)
         {
            /* ERROR */
            WARN_INTERNAL_ERROR;
            return NULL;
         }
         else
         if (S != RESULT_BUFFER)
         {
            /* ERROR */
            WARN_INTERNAL_ERROR;
            return NULL;
         }
         else
         {
            RESULT_LENGTH = s;
            RESULT_BUFFER[RESULT_LENGTH] = BasicNulChar;
         }
      }
      else
      {
         /* NUMBER */
         if (isnan(N))
         {
            /* ERROR */
            /* this means the parameters were not properly checked */
            WARN_INTERNAL_ERROR;
            return NULL;
         }
         else
         if (isinf(N))
         {
            /* Evaluation of an expression results in an
             * overflow (nonfatal, the recommended
             * recovery procedure is to supply machine
             * in- finity with the algebraically correct
             * sign and continue). */
            if (N < 0)
            {
               N = -DBL_MAX;
            }
            else
            {
               N = DBL_MAX;
            }
            if( bwb_Warning_Overflow("*** Arithmetic Overflow ***") )
            {
               /* ERROR */
            }
            /* CONTINUE */
         }
         RESULT_NUMBER = N;
      }
   }
   /* process errors */
   if (IsError == 0xFF)
   {
      /* NOT IMPLEMENTED ON THIS PLATFORM */
      sprintf(My->bwb_ebuf, "%s IS NOT IMPLEMENTED ON THIS PLATFORM", f->Name);
      bwb_Warning(73, My->bwb_ebuf); /* WARN_ADVANCED_FEATURE */
   }
   else
   if (IsError != 0)
   {
      /* ERROR */
      char            Buffer[80];
      switch (IsError)
      {
      case 'A':
      case 'B':
      case 'C':
         /* STRING parameter's value is invalid */
         sprintf(Buffer, "%s(%c$)", f->Name, IsError);
         break;
      case 'X':
      case 'Y':
      case 'Z':
         /* NUMBER parameter's value is invalid */
         sprintf(Buffer, "%s(%c)", f->Name, IsError);
         break;
      default:
         /* All other errors */
         sprintf(Buffer, "%s() #%d", f->Name, IsError);
         break;
      }
      sprintf(My->bwb_ebuf, "ILLEGAL FUUNCTION CALL: %s", Buffer);
      bwb_Warning(5, My->bwb_ebuf); /* WARN_ILLEGAL_FUNCTION_CALL */
   }
   return argv;      /* released by exp_function() in bwb_elx.c */
}

/* EOF */
