aboutsummaryrefslogtreecommitdiffstats
path: root/bwb_var.c
diff options
context:
space:
mode:
Diffstat (limited to 'bwb_var.c')
-rw-r--r--bwb_var.c5068
1 files changed, 5068 insertions, 0 deletions
diff --git a/bwb_var.c b/bwb_var.c
new file mode 100644
index 0000000..5f8e62e
--- /dev/null
+++ b/bwb_var.c
@@ -0,0 +1,5068 @@
+/***************************************************************
+
+ bwb_var.c Variable-Handling Routines
+ for Bywater BASIC Interpreter
+
+ Copyright (c) 1993, Ted A. Campbell
+ Bywater Software
+
+ email: tcamp@delphi.com
+
+ Copyright and Permissions Information:
+
+ All U.S. and international rights are claimed by the author,
+ Ted A. Campbell.
+
+ This software is released under the terms of the GNU General
+ Public License (GPL), which is distributed with this software
+ in the file "COPYING". The GPL specifies the terms under
+ which users may copy and use the software in this distribution.
+
+ A separate license is available for commercial distribution,
+ for information on which you should contact the author.
+
+***************************************************************/
+
+/*---------------------------------------------------------------*/
+/* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */
+/* 11/1995 (eidetics@cerf.net). */
+/* */
+/* Those additionally marked with "DD" were at the suggestion of */
+/* Dale DePriest (daled@cadence.com). */
+/* */
+/* Version 3.00 by Howard Wulf, AF5NE */
+/* */
+/* Version 3.10 by Howard Wulf, AF5NE */
+/* */
+/* Version 3.20 by Howard Wulf, AF5NE */
+/* */
+/*---------------------------------------------------------------*/
+
+
+
+#include "bwbasic.h"
+
+
+/* Prototypes for functions visible to this file only */
+
+static void clear_virtual (VirtualType * Z);
+static void clear_virtual_by_variable (VariableType * Variable);
+static int dim_check (VariableType * variable);
+static size_t dim_unit (VariableType * v, int *pp);
+static LineType *dio_lrset (LineType * l, int rset);
+static void field_clear (FieldType * Field);
+static FieldType *field_new (void);
+static VirtualType *find_virtual_by_variable (VariableType * Variable);
+static LineType *internal_swap (LineType * l);
+static VariableType *mat_islocal (char *buffer);
+static VirtualType *new_virtual (void);
+static int var_defx (LineType * l, int TypeCode);
+static VariableType *var_islocal (char *buffer, int dimensions);
+static void var_link_new_variable (VariableType * v);
+
+extern int
+var_init (void)
+{
+ assert( My != NULL );
+
+ My->VariableHead = NULL;
+
+ return TRUE;
+}
+
+extern LineType *
+bwb_COMMON (LineType * l)
+{
+ /*
+ SYNTAX: COMMON scalar
+ SYNTAX: COMMON matrix( dimnesions ) ' COMMON A(1), B(2), C(3)
+ SYNTAX: COMMON matrix( [, [,]] ) ' COMMON A(), B(,), C(,,)
+ */
+
+ assert (l != NULL);
+
+ do
+ {
+ int dimensions;
+ VariableType *variable;
+ char varname[NameLengthMax + 1];
+
+ dimensions = 0;
+ /* get variable name and find variable */
+ if (line_read_varname (l, varname) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (line_skip_LparenChar (l))
+ {
+ line_skip_spaces (l); /* keep this */
+ if (bwb_isdigit (l->buffer[l->position]))
+ {
+ /* COMMON A(3) : DIM A( 5, 10, 20 ) */
+ if (line_read_integer_expression (l, &dimensions) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ }
+ else
+ {
+ /* COMMON A(,,) : DIM A( 5, 10, 20 ) */
+ dimensions++;
+ while (line_skip_seperator (l));
+ {
+ dimensions++;
+ }
+ }
+ if (line_skip_RparenChar (l) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ }
+ if ((variable = var_find (varname, dimensions, TRUE)) == NULL)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return (l);
+ }
+
+ /* mark as COMMON */
+ variable->VariableFlags |= VARIABLE_COMMON;
+ }
+ while (line_skip_seperator (l));
+
+ return (l);
+}
+
+extern LineType *
+bwb_ERASE (LineType * l)
+{
+ /*
+ SYNTAX: ERASE variable [, ...] ' ERASE A, B, C
+ */
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+ do
+ {
+ char varname[NameLengthMax + 1];
+
+ /* get variable name and find variable */
+
+ if (line_read_varname (l, varname))
+ {
+ /* erase all matching SCALAR and ARRAY variables */
+ int dimensions;
+
+ for (dimensions = 0; dimensions < MAX_DIMS; dimensions++)
+ {
+ VariableType *variable;
+
+ variable = var_find (varname, dimensions, FALSE);
+ if (variable != NULL)
+ {
+ /* found a variable */
+ VariableType *p; /* previous variable in linked list */
+
+ /* find then previous variable in chain */
+ if (variable == My->VariableHead)
+ {
+ /* free head */
+ My->VariableHead = variable->next;
+ variable->next = NULL;
+ var_free (variable);
+ }
+ else
+ {
+ /* free tail */
+ for (p = My->VariableHead; p != NULL && p->next != variable;
+ p = p->next)
+ {
+ ;
+ }
+ if (p == NULL)
+ {
+ /* this should never happen */
+ WARN_INTERNAL_ERROR;
+ return NULL;
+ }
+ if (p->next != variable)
+ {
+ /* this should never happen */
+ WARN_INTERNAL_ERROR;
+ return NULL;
+ }
+ /* reassign linkage */
+ p->next = variable->next;
+ variable->next = NULL;
+ var_free (variable);
+ }
+ }
+ }
+ }
+ }
+ while (line_skip_seperator (l));
+ return (l);
+}
+
+static LineType *
+internal_swap (LineType * l)
+{
+ VariableType *lhs;
+ VariableType *rhs;
+
+ assert (l != NULL);
+
+ if (line_skip_LparenChar (l))
+ {
+ /* optional */
+ }
+
+ /* get left variable */
+ if ((lhs = line_read_scalar (l)) == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ /* get required comma */
+ if (line_skip_seperator (l) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ /* get right variable */
+ if ((rhs = line_read_scalar (l)) == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ if (line_skip_RparenChar (l))
+ {
+ /* optional */
+ }
+
+ /* check to be sure that both variables are compatible */
+ if (VAR_IS_STRING (rhs) != VAR_IS_STRING (lhs))
+ {
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+
+ /* swap the values */
+ {
+ VariantType L;
+ VariantType R;
+ CLEAR_VARIANT (&L);
+ CLEAR_VARIANT (&R);
+
+ if (var_get (lhs, &L) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (var_get (rhs, &R) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ if (var_set (lhs, &R) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (var_set (rhs, &L) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ }
+ /* return */
+ return (l);
+}
+
+extern LineType *
+bwb_EXCHANGE (LineType * l)
+{
+ /*
+ SYNTAX: EXCHANGE variable, variable
+ SYNTAX: EXCHANGE ( variable, variable )
+ */
+
+ assert (l != NULL);
+ return internal_swap (l);
+}
+
+
+
+extern LineType *
+bwb_SWAP (LineType * l)
+{
+ /*
+ SYNTAX: SWAP variable, variable
+ SYNTAX: SWAP ( variable, variable )
+ */
+
+ assert (l != NULL);
+ return internal_swap (l);
+}
+
+extern VariableType *
+var_free (VariableType * variable)
+{
+ /*
+ Release all the memory associated with a specific variable.
+ This function returns NULL, so you can use it like this:
+ variable = var_new(...);
+ ...
+ variable = var_free( variable );
+ */
+
+
+ if (variable != NULL)
+ {
+ if (variable->next != NULL)
+ {
+ /* This allows variable chains to be easily released. */
+ variable->next = var_free (variable->next);
+ }
+ /* cleanup this variable */
+ field_free_variable (variable);
+ clear_virtual_by_variable (variable);
+ if (VAR_IS_STRING (variable))
+ {
+ if (variable->Value.String != NULL)
+ {
+ int j;
+ for (j = 0; j < variable->array_units; j++)
+ {
+ if (variable->Value.String[j].sbuffer != NULL)
+ {
+ free (variable->Value.String[j].sbuffer);
+ }
+ variable->Value.String[j].length = 0;
+ }
+ free (variable->Value.String);
+ variable->Value.String = NULL;
+ }
+ }
+ else
+ {
+ if (variable->Value.Number != NULL)
+ {
+ free (variable->Value.Number);
+ variable->Value.Number = NULL;
+ }
+ }
+ free (variable);
+ }
+ return NULL;
+}
+
+extern void
+var_CLEAR (void)
+{
+ /*
+ free all variables except PRESET
+ */
+ VariableType *variable;
+ assert( My != NULL );
+
+
+ for (variable = My->VariableHead; variable != NULL;)
+ {
+ if (variable->VariableFlags & VARIABLE_PRESET)
+ {
+ /* keep */
+ variable = variable->next;
+ }
+ else if (variable == My->VariableHead)
+ {
+ /* free head */
+ My->VariableHead = variable->next;
+ variable->next = NULL;
+ var_free (variable);
+ variable = My->VariableHead;
+ }
+ else
+ {
+ /* free tail */
+ VariableType *z;
+ z = variable->next;
+ variable->next = NULL;
+ var_free (variable);
+ variable = z;
+ }
+ }
+}
+
+extern LineType *
+bwb_CLEAR (LineType * l)
+{
+ /*
+ SYNTAX: CLEAR
+ */
+
+ assert (l != NULL);
+ var_CLEAR ();
+ line_skip_eol (l);
+ return (l);
+}
+
+
+LineType *
+bwb_CLR (LineType * l)
+{
+
+ assert (l != NULL);
+ return bwb_CLEAR (l);
+}
+
+/***********************************************************
+
+ FUNCTION: var_delcvars()
+
+ DESCRIPTION: This function deletes all variables
+ in memory except those previously marked
+ as common.
+
+***********************************************************/
+
+int
+var_delcvars (void)
+{
+ VariableType *v;
+
+ assert( My != NULL );
+
+ for (v = My->VariableHead; v != NULL;)
+ {
+ if (v->VariableFlags & VARIABLE_PRESET)
+ {
+ /* keep */
+ v = v->next;
+ }
+ else if (v->VariableFlags & VARIABLE_COMMON)
+ {
+ /* keep */
+ v = v->next;
+ }
+ else if (v == My->VariableHead)
+ {
+ /* free head */
+ My->VariableHead = v->next;
+ v->next = NULL;
+ var_free (v);
+ v = My->VariableHead;
+ }
+ else
+ {
+ /* free tail */
+ VariableType *z; /* next variable */
+
+ z = v->next;
+ v->next = NULL;
+ var_free (v);
+ v = z;
+ }
+ }
+ return TRUE;
+}
+
+/***********************************************************
+
+ FUNCTION: bwb_mid()
+
+ DESCRIPTION: This function implements the BASIC
+ MID$ command.
+
+ Same as MID$ function, except it will set
+ the desired substring and not return its
+ value. Added by JBV 10/95
+
+ SYNTAX: MID$( string-variable$, start-position-in-string
+ [, number-of-spaces ] ) = expression
+
+***********************************************************/
+
+LineType *
+bwb_MID4 (LineType * l)
+{
+ /* MID$( target$, start% [ , length% ] ) = source$ */
+ VariableType *variable;
+ VariantType target;
+ int start;
+ int length;
+ VariantType source;
+ int maxlen;
+
+ assert (l != NULL);
+
+ CLEAR_VARIANT (&source);
+ CLEAR_VARIANT (&target);
+ start = 0;
+ length = 0;
+ maxlen = 0;
+ if (line_skip_LparenChar (l) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if ((variable = line_read_scalar (l)) == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (VAR_IS_STRING (variable))
+ {
+ /* OK */
+ }
+ else
+ {
+ /* ERROR */
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+ if (var_get (variable, &target) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (target.VariantTypeCode != StringTypeCode)
+ {
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+ if (line_skip_seperator (l) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (line_read_integer_expression (l, &start) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (start < 1)
+ {
+ WARN_ILLEGAL_FUNCTION_CALL;
+ return (l);
+ }
+ if (start > target.Length)
+ {
+ WARN_ILLEGAL_FUNCTION_CALL;
+ return (l);
+ }
+ maxlen = 1 + target.Length - start;
+ if (line_skip_seperator (l))
+ {
+ if (line_read_integer_expression (l, &length) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (length < 0)
+ {
+ WARN_ILLEGAL_FUNCTION_CALL;
+ return (l);
+ }
+ }
+ else
+ {
+ length = -1; /* MAGIC */
+ }
+ if (line_skip_RparenChar (l) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* skip the equal sign */
+ if (line_skip_EqualChar (l) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (line_read_expression (l, &source) == FALSE) /* bwb_MID4 */
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (source.VariantTypeCode != StringTypeCode)
+ {
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+ if (length == -1 /* MAGIC */ )
+ {
+ length = source.Length;
+ }
+ length = MIN (length, maxlen);
+ length = MIN (length, source.Length);
+ if (length < 0)
+ {
+ WARN_INTERNAL_ERROR;
+ return (l);
+ }
+ if (length > 0)
+ {
+ int i;
+
+ start--; /* BASIC to C */
+ for (i = 0; i < length; i++)
+ {
+ target.Buffer[start + i] = source.Buffer[i];
+ }
+ target.Buffer[target.Length] = NulChar;
+ if (var_set (variable, &target) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ }
+ RELEASE_VARIANT (&source);
+ RELEASE_VARIANT (&target);
+ return (l);
+}
+
+
+/***********************************************************
+
+ FUNCTION: bwb_ddbl()
+
+ DESCRIPTION: This function implements the BASIC
+ DEFDBL command.
+
+ SYNTAX: DEFDBL letter[-letter](, letter[-letter])...
+
+***********************************************************/
+
+LineType *
+bwb_DEFBYT (LineType * l)
+{
+ /*
+ DEFBYT letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, ByteTypeCode);
+ return (l);
+}
+
+LineType *
+bwb_DEFCUR (LineType * l)
+{
+ /*
+ DEFCUR letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, CurrencyTypeCode);
+ return (l);
+}
+
+LineType *
+bwb_DEFDBL (LineType * l)
+{
+ /*
+ DEFDBL letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, DoubleTypeCode);
+ return (l);
+}
+
+/***********************************************************
+
+ FUNCTION: bwb_dint()
+
+ DESCRIPTION: This function implements the BASIC
+ DEFINT command.
+
+ SYNTAX: DEFINT letter[-letter](, letter[-letter])...
+
+***********************************************************/
+
+LineType *
+bwb_DEFINT (LineType * l)
+{
+ /*
+ DEFINT letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, IntegerTypeCode);
+ return (l);
+}
+
+LineType *
+bwb_DEFLNG (LineType * l)
+{
+ /*
+ DEFLNG letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, LongTypeCode);
+ return (l);
+}
+
+/***********************************************************
+
+ FUNCTION: bwb_dsng()
+
+ DESCRIPTION: This function implements the BASIC
+ DEFSNG command.
+
+ SYNTAX: DEFSNG letter[-letter](, letter[-letter])...
+
+***********************************************************/
+
+LineType *
+bwb_DEFSNG (LineType * l)
+{
+ /*
+ DEFSNG letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, SingleTypeCode);
+ return (l);
+}
+
+/***********************************************************
+
+ FUNCTION: bwb_dstr()
+
+ DESCRIPTION: This function implements the BASIC
+ DEFSTR command.
+
+ SYNTAX: DEFSTR letter[-letter](, letter[-letter])...
+
+***********************************************************/
+
+LineType *
+bwb_DEFSTR (LineType * l)
+{
+ /*
+ DEFSTR letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, StringTypeCode);
+ return (l);
+}
+
+LineType *
+bwb_TEXT (LineType * l)
+{
+ /*
+ TEXT letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ var_defx (l, StringTypeCode);
+ return (l);
+}
+
+LineType *
+bwb_TRACE (LineType * l)
+{
+ assert (l != NULL);
+
+ return bwb_TRACE_ON(l);
+}
+
+LineType *
+bwb_TRACE_ON (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->SYSOUT != NULL );
+ assert( My->SYSOUT->cfp != NULL );
+
+ fprintf (My->SYSOUT->cfp, "Trace is ON\n");
+ ResetConsoleColumn ();
+ My->IsTraceOn = TRUE;
+
+ return (l);
+}
+
+LineType *
+bwb_TRACE_OFF (LineType * l)
+{
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->SYSOUT != NULL );
+ assert( My->SYSOUT->cfp != NULL );
+
+ fprintf (My->SYSOUT->cfp, "Trace is OFF\n");
+ ResetConsoleColumn ();
+ My->IsTraceOn = FALSE;
+
+ return (l);
+}
+
+int
+VarTypeIndex (char C)
+{
+
+ switch (C)
+ {
+ case 'A':
+ return 0;
+ case 'B':
+ return 1;
+ case 'C':
+ return 2;
+ case 'D':
+ return 3;
+ case 'E':
+ return 4;
+ case 'F':
+ return 5;
+ case 'G':
+ return 6;
+ case 'H':
+ return 7;
+ case 'I':
+ return 8;
+ case 'J':
+ return 9;
+ case 'K':
+ return 10;
+ case 'L':
+ return 11;
+ case 'M':
+ return 12;
+ case 'N':
+ return 13;
+ case 'O':
+ return 14;
+ case 'P':
+ return 15;
+ case 'Q':
+ return 16;
+ case 'R':
+ return 17;
+ case 'S':
+ return 18;
+ case 'T':
+ return 19;
+ case 'U':
+ return 20;
+ case 'V':
+ return 21;
+ case 'W':
+ return 22;
+ case 'X':
+ return 23;
+ case 'Y':
+ return 24;
+ case 'Z':
+ return 25;
+ case 'a':
+ return 0;
+ case 'b':
+ return 1;
+ case 'c':
+ return 2;
+ case 'd':
+ return 3;
+ case 'e':
+ return 4;
+ case 'f':
+ return 5;
+ case 'g':
+ return 6;
+ case 'h':
+ return 7;
+ case 'i':
+ return 8;
+ case 'j':
+ return 9;
+ case 'k':
+ return 10;
+ case 'l':
+ return 11;
+ case 'm':
+ return 12;
+ case 'n':
+ return 13;
+ case 'o':
+ return 14;
+ case 'p':
+ return 15;
+ case 'q':
+ return 16;
+ case 'r':
+ return 17;
+ case 's':
+ return 18;
+ case 't':
+ return 19;
+ case 'u':
+ return 20;
+ case 'v':
+ return 21;
+ case 'w':
+ return 22;
+ case 'x':
+ return 23;
+ case 'y':
+ return 24;
+ case 'z':
+ return 25;
+ }
+ return -1;
+}
+
+/***********************************************************
+
+ Function: var_defx()
+
+ DESCRIPTION: This function is a generalized DEFxxx handler.
+
+***********************************************************/
+
+static int
+var_defx (LineType * l, int TypeCode)
+{
+ /*
+ DEFxxx letter[-letter](, letter[-letter])...
+ */
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->DefaultVariableType != NULL );
+
+ do
+ {
+ char firstc;
+ char lastc;
+ int first;
+ int last;
+ int c;
+
+ /* find a sequence of letters for variables */
+ if (line_read_letter_sequence (l, &firstc, &lastc) == FALSE)
+ {
+ /* DEFINT 0-9 */
+ WARN_SYNTAX_ERROR;
+ return FALSE;
+ }
+ first = VarTypeIndex (firstc);
+ if (first < 0)
+ {
+ /* DEFINT 0-Z */
+ WARN_SYNTAX_ERROR;
+ return FALSE;
+ }
+ last = VarTypeIndex (lastc);
+ if (last < 0)
+ {
+ /* DEFINT A-9 */
+ WARN_SYNTAX_ERROR;
+ return FALSE;
+ }
+ if (first > last)
+ {
+ /* DEFINT Z-A */
+ WARN_SYNTAX_ERROR;
+ return FALSE;
+ }
+ for (c = first; c <= last; c++)
+ {
+ My->DefaultVariableType[c] = TypeCode; /* var_defx */
+ }
+ }
+ while (line_skip_seperator (l));
+
+ return TRUE;
+
+}
+
+/***************************************************************
+
+ FUNCTION: var_find()
+
+ DESCRIPTION: This C function attempts to find a variable
+ name matching the argument in buffer. If
+ it fails to find a matching name, it
+ sets up a new variable with that name.
+
+***************************************************************/
+
+VariableType *
+mat_find (char *name)
+{
+ /*
+ similar to var_find, but returns the first matrix found
+ */
+ VariableType *v;
+ assert( My != NULL );
+
+
+ /* check for NULL variable name */
+ if (name == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return NULL;
+ }
+ if (is_empty_string (name))
+ {
+ WARN_SYNTAX_ERROR;
+ return NULL;
+ }
+ /* check for a local variable at this EXEC level */
+
+ v = mat_islocal (name);
+ if (v != NULL)
+ {
+ return v;
+ }
+ /* now run through the global variable list and try to find a match */
+ for (v = My->VariableHead; v != NULL; v = v->next)
+ {
+ assert( v != NULL );
+ if (v->dimensions > 0)
+ {
+ if (bwb_stricmp (v->name, name) == 0)
+ {
+ return v;
+ }
+ }
+ }
+ return NULL;
+}
+
+VariableType *
+var_find (char *name, int dimensions, int IsImplicit)
+{
+ VariableType *v;
+ int n;
+
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+ assert( My->DefaultVariableType != NULL );
+
+ /* check for NULL variable name */
+ if (name == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return NULL;
+ }
+ if (is_empty_string (name))
+ {
+ WARN_SYNTAX_ERROR;
+ return NULL;
+ }
+ if (dimensions < 0)
+ {
+ WARN_INTERNAL_ERROR;
+ return NULL;
+ }
+
+ /* check for a local variable at this EXEC level */
+
+ v = var_islocal (name, dimensions);
+ if (v != NULL)
+ {
+ return v;
+ }
+ /* now run through the global variable list and try to find a match */
+ for (v = My->VariableHead; v != NULL; v = v->next)
+ {
+ assert( v != NULL );
+ if (v->dimensions == dimensions)
+ {
+ if (bwb_stricmp (v->name, name) == 0)
+ {
+ return v;
+ }
+ }
+ }
+ if (IsImplicit == FALSE)
+ {
+ return NULL;
+ }
+ if (My->CurrentVersion->OptionFlags & OPTION_EXPLICIT_ON)
+ {
+ /* NO implicit creation - all variables must be created via DIM */
+ WARN_VARIABLE_NOT_DECLARED;
+ return NULL;
+ }
+ if (My->CurrentVersion->OptionFlags & OPTION_STRICT_ON)
+ {
+ if (dimensions > 0)
+ {
+ /* Implicit ARRAY is not allowed */
+ WARN_VARIABLE_NOT_DECLARED;
+ return NULL;
+ }
+ }
+
+ /* this is a IMPLICIT variable, so initialize it... */
+
+ /* initialize new variable */
+ if ((v = (VariableType *) calloc (1, sizeof (VariableType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ /* copy the name into the appropriate structure */
+
+ assert( v != NULL );
+ bwb_strcpy (v->name, name);
+
+ /* determine variable TypeCode */
+ v->VariableTypeCode = var_nametype (name);
+ if (v->VariableTypeCode == NulChar)
+ {
+ /* variable name has no declared TypeCode */
+ n = VarTypeIndex (name[0]);
+ if (n < 0)
+ {
+ v->VariableTypeCode = DoubleTypeCode; /* default */
+ }
+ else
+ {
+ v->VariableTypeCode = My->DefaultVariableType[n];
+ }
+ }
+ v->VariableFlags = 0;
+ v->dimensions = dimensions;
+ v->array_units = 1;
+ for (n = 0; n < v->dimensions; n++)
+ {
+ v->LBOUND[n] = My->CurrentVersion->OptionBaseInteger; /* implicit lower bound */
+ v->UBOUND[n] = 10; /* implicit upper bound */
+ if (v->UBOUND[n] < v->LBOUND[n])
+ {
+ WARN_SUBSCRIPT_OUT_OF_RANGE;
+ return NULL;
+ }
+ v->VINDEX[n] = v->LBOUND[n];
+ v->array_units *= v->UBOUND[n] - v->LBOUND[n] + 1;
+ }
+
+ /* assign array memory */
+ if (VAR_IS_STRING (v))
+ {
+ if ((v->Value.String =
+ (StringType *) calloc (v->array_units, sizeof (StringType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return NULL;
+ }
+ }
+ else
+ {
+ if ((v->Value.Number =
+ (DoubleType *) calloc (v->array_units, sizeof (DoubleType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return NULL;
+ }
+ }
+
+ /* insert variable at the beginning of the variable chain */
+ v->next = My->VariableHead;
+ My->VariableHead = v;
+ return v;
+}
+
+/***************************************************************
+
+ FUNCTION: var_new()
+
+ DESCRIPTION: This function assigns memory for a new variable.
+
+***************************************************************/
+
+VariableType *
+var_new (char *name, char TypeCode)
+{
+ VariableType *v;
+
+
+ /* get memory for new variable */
+
+ if (name == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return NULL;
+ }
+ if (is_empty_string (name))
+ {
+ WARN_SYNTAX_ERROR;
+ return NULL;
+ }
+ if ((v = (VariableType *) calloc (1, sizeof (VariableType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return NULL;
+ }
+ /* copy the name into the appropriate structure */
+
+ assert( v != NULL );
+ bwb_strcpy (v->name, name);
+
+ /* set memory in the new variable */
+ var_make (v, TypeCode);
+
+ /* and return */
+
+ return v;
+
+}
+
+
+/***************************************************************
+
+ FUNCTION: bwb_dim()
+
+ DESCRIPTION: This function implements the BASIC DIM
+ statement, allocating memory for a
+ dimensioned array of variables.
+
+ SYNTAX: DIM variable(elements...)[,variable(elements...)]
+
+***************************************************************/
+
+static void
+var_link_new_variable (VariableType * v)
+{
+ /*
+ We are called by DIM, so this is an explicitly created variable.
+ There are only two possibilities:
+ 1. We are a LOCAL variable of a SUB or FUNCTION.
+ 2. We are a GLOBAL variable.
+ */
+
+ assert (v != NULL);
+ assert( My != NULL );
+
+ if (My->StackHead != NULL)
+ {
+ StackType *StackItem;
+ for (StackItem = My->StackHead; StackItem != NULL;
+ StackItem = StackItem->next)
+ {
+ if (StackItem->LoopTopLine != NULL)
+ {
+ switch (StackItem->LoopTopLine->cmdnum)
+ {
+ case C_FUNCTION:
+ case C_SUB:
+ /* we have found a FUNCTION or SUB boundary, must be LOCAL */
+ v->next = StackItem->local_variable;
+ StackItem->local_variable = v;
+ return;
+ /* break; */
+ }
+ }
+ }
+ }
+ /* no FUNCTION or SUB on the stack, must be GLOBAL */
+ v->next = My->VariableHead;
+ My->VariableHead = v;
+}
+
+
+static VirtualType *
+new_virtual (void)
+{
+ VirtualType *Z;
+ assert( My != NULL );
+
+
+ /* look for an empty slot */
+ for (Z = My->VirtualHead; Z != NULL; Z = Z->next)
+ {
+ if (Z->Variable == NULL)
+ {
+ /* FOUND */
+ return Z;
+ }
+ }
+ /* NOT FOUND */
+ if ((Z = (VirtualType *) calloc (1, sizeof (VirtualType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return NULL;
+ }
+ Z->next = My->VirtualHead;
+ My->VirtualHead = Z;
+ return Z;
+}
+static void
+clear_virtual (VirtualType * Z)
+{
+
+ assert (Z != NULL);
+
+ Z->Variable = NULL;
+ Z->FileNumber = 0;
+ Z->FileOffset = 0;
+ Z->FileLength = 0;
+}
+static void
+clear_virtual_by_variable (VariableType * Variable)
+{
+ VirtualType *Z;
+
+ assert (Variable != NULL);
+ assert( My != NULL );
+
+ for (Z = My->VirtualHead; Z != NULL; Z = Z->next)
+ {
+ if (Z->Variable == Variable)
+ {
+ /* FOUND */
+ clear_virtual (Z);
+ }
+ }
+}
+extern void
+clear_virtual_by_file (int FileNumber)
+{
+ /* called by file_clear() */
+ VirtualType *Z;
+
+ assert( My != NULL );
+
+ for (Z = My->VirtualHead; Z != NULL; Z = Z->next)
+ {
+ if (Z->FileNumber == FileNumber)
+ {
+ /* FOUND */
+ clear_virtual (Z);
+ }
+ }
+}
+static VirtualType *
+find_virtual_by_variable (VariableType * Variable)
+{
+ VirtualType *Z;
+
+ assert (Variable != NULL);
+ assert( My != NULL );
+
+ for (Z = My->VirtualHead; Z != NULL; Z = Z->next)
+ {
+ if (Z->Variable == Variable)
+ {
+ /* FOUND */
+ return Z;
+ }
+ }
+ /* NOT FOUND */
+ return NULL;
+}
+
+LineType *
+bwb_LOCAL (LineType * l)
+{
+ /* only supported inside a FUNCTION or SUB */
+
+ assert (l != NULL);
+ return bwb_DIM (l);
+}
+
+LineType *
+bwb_DIM (LineType * l)
+{
+ int FileNumber; /* the file might not be OPEN when the variable is declared */
+ size_t FileOffset; /* from beginning of file */
+ int FileLength; /* sizeof( DoubleType ) or Fixed String Length */
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->DefaultVariableType != NULL );
+
+
+ FileNumber = 0;
+ FileOffset = 0;
+ FileLength = 0;
+ if (line_skip_FilenumChar (l))
+ {
+ /* DIM # filenum , ... */
+ if (line_read_integer_expression (l, &FileNumber) == FALSE)
+ {
+ WARN_BAD_FILE_NUMBER;
+ return (l);
+ }
+ if (FileNumber <= 0)
+ {
+ WARN_BAD_FILE_NUMBER;
+ return (l);
+ }
+ if (line_skip_seperator (l) == FALSE)
+ {
+ WARN_BAD_FILE_NUMBER;
+ return (l);
+ }
+ FileOffset = 0;
+ FileLength = 0;
+ }
+
+ do
+ {
+ VariableType *v;
+ int n;
+ int dimensions;
+ int LBOUND[MAX_DIMS];
+ int UBOUND[MAX_DIMS];
+ char TypeCode;
+ char varname[NameLengthMax + 1];
+
+
+ /* Get variable name */
+ if (line_read_varname (l, varname) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ /* read parameters */
+ dimensions = 0;
+ if (line_peek_LparenChar (l))
+ {
+ if (line_read_array_redim (l, &dimensions, LBOUND, UBOUND) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* check array dimensions */
+ for (n = 0; n < dimensions; n++)
+ {
+ if (UBOUND[n] < LBOUND[n])
+ {
+ WARN_SUBSCRIPT_OUT_OF_RANGE;
+ return (l);
+ }
+ }
+ }
+
+ /* determine variable TypeCode */
+ TypeCode = var_nametype (varname);
+ if (TypeCode == NulChar)
+ {
+ /* variable has no explicit TypeCode char */
+ TypeCode = line_read_type_declaration (l); /* AS DOUBLE and so on */
+ if (TypeCode == NulChar)
+ {
+ /* variable has no declared TypeCode */
+ int i;
+ i = VarTypeIndex (varname[0]);
+ if (i < 0)
+ {
+ TypeCode = DoubleTypeCode; /* default */
+ }
+ else
+ {
+ TypeCode = My->DefaultVariableType[i];
+ }
+ }
+ }
+
+ switch (TypeCode)
+ {
+ case ByteTypeCode:
+ /* DIM # file_num , var_name AS BYTE */
+ FileLength = sizeof (ByteType);
+ break;
+ case IntegerTypeCode:
+ /* DIM # file_num , var_name AS INTEGER */
+ FileLength = sizeof (IntegerType);
+ break;
+ case LongTypeCode:
+ /* DIM # file_num , var_name AS LONG */
+ FileLength = sizeof (LongType);
+ break;
+ case CurrencyTypeCode:
+ /* DIM # file_num , var_name AS CURRENCY */
+ FileLength = sizeof (CurrencyType);
+ break;
+ case SingleTypeCode:
+ /* DIM # file_num , var_name AS SINGLE */
+ FileLength = sizeof (SingleType);
+ break;
+ case DoubleTypeCode:
+ /* DIM # file_num , var_name AS DOUBLE */
+ FileLength = sizeof (DoubleType);
+ break;
+ case StringTypeCode:
+ /* DIM # file_num , var_name AS STRING * fixed_length */
+
+ FileLength = 16; /* default */
+ if (line_skip_StarChar (l) || line_skip_EqualChar (l))
+ {
+ /* optional fixed length */
+ if (line_read_integer_expression (l, &FileLength) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (FileLength <= 0)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (FileLength > MAXLEN)
+ {
+ WARN_STRING_TOO_LONG; /* bwb_DIM */
+ FileLength = MAXLEN;
+ }
+ }
+ break;
+ default:
+ {
+ WARN_INTERNAL_ERROR;
+ return (l);
+ }
+ }
+
+ v = var_find (varname, dimensions, FALSE);
+ if (v == NULL)
+ {
+ /* a new variable */
+ if ((v = (VariableType *) calloc (1, sizeof (VariableType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return (l);
+ }
+ bwb_strcpy (v->name, varname);
+ v->VariableTypeCode = TypeCode;
+ /* assign array dimensions */
+ v->dimensions = dimensions;
+ for (n = 0; n < dimensions; n++)
+ {
+ v->LBOUND[n] = LBOUND[n];
+ v->UBOUND[n] = UBOUND[n];
+ }
+ /* assign initial array position */
+ for (n = 0; n < dimensions; n++)
+ {
+ v->VINDEX[n] = v->LBOUND[n];
+ }
+ /* calculate the array size */
+ v->array_units = 1;
+ for (n = 0; n < dimensions; n++)
+ {
+ v->array_units *= v->UBOUND[n] - v->LBOUND[n] + 1;
+ }
+ /* assign array memory */
+
+ if (FileNumber > 0)
+ {
+ /* the new variable is VIRTUAL */
+ v->VariableFlags = VARIABLE_VIRTUAL;
+ /* if( TRUE ) */
+ {
+ /* OK */
+ VirtualType *Z;
+ Z = find_virtual_by_variable (v);
+ if (Z == NULL)
+ {
+ Z = new_virtual ();
+ if (Z == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return (l);
+ }
+ Z->Variable = v;
+ }
+ /* update file information */
+ Z->FileNumber = FileNumber;
+ Z->FileOffset = FileOffset;
+ Z->FileLength = FileLength;
+ FileOffset += FileLength * v->array_units;
+ }
+ }
+ else if (VAR_IS_STRING (v))
+ {
+ if ((v->Value.String =
+ (StringType *) calloc (v->array_units,
+ sizeof (StringType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return (l);
+ }
+ }
+ else
+ {
+ if ((v->Value.Number =
+ (DoubleType *) calloc (v->array_units,
+ sizeof (DoubleType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return (l);
+ }
+ }
+ /* set place at beginning of variable chain */
+ var_link_new_variable (v);
+
+ /* end of conditional for new variable */
+ }
+ else
+ {
+ /* old variable */
+ if (v->VariableTypeCode != TypeCode)
+ {
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+
+ /* check to be sure the number of dimensions is the same */
+ if (v->dimensions != dimensions)
+ {
+ WARN_REDIMENSION_ARRAY;
+ return (l);
+ }
+ /* check to be sure sizes for each dimension are the same */
+ for (n = 0; n < dimensions; n++)
+ {
+ if (v->LBOUND[n] != LBOUND[n])
+ {
+ WARN_REDIMENSION_ARRAY;
+ return (l);
+ }
+ if (v->UBOUND[n] != UBOUND[n])
+ {
+ WARN_REDIMENSION_ARRAY;
+ return (l);
+ }
+ }
+ if (FileNumber > 0)
+ {
+ /* the existing variable MUST be Virtual */
+ if (v->VariableFlags & VARIABLE_VIRTUAL)
+ {
+ /* OK */
+ VirtualType *Z;
+ Z = find_virtual_by_variable (v);
+ if (Z == NULL)
+ {
+ Z = new_virtual ();
+ if (Z == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return (l);
+ }
+ Z->Variable = v;
+ }
+ /* update file information */
+ Z->FileNumber = FileNumber;
+ Z->FileOffset = FileOffset;
+ Z->FileLength = FileLength;
+ FileOffset += FileLength * v->array_units;
+ }
+ else
+ {
+ /* the existing variable is NOT virtual */
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+ }
+ else
+ {
+ /* the existing variable CANNOT be Virtual */
+ if (v->VariableFlags & VARIABLE_VIRTUAL)
+ {
+ /* the existing variable IS virtual */
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+ else
+ {
+ /* OK */
+ }
+ }
+ /* end of conditional for old variable */
+ }
+
+ }
+ while (line_skip_seperator (l));
+
+ /* return */
+ return (l);
+}
+
+
+
+
+/***************************************************************
+
+ FUNCTION: dim_unit()
+
+ DESCRIPTION: This function calculates the unit
+ position for an array.
+
+***************************************************************/
+
+static size_t
+dim_unit (VariableType * v, int *pp)
+{
+ size_t r;
+ size_t b;
+ int n;
+
+ assert (v != NULL);
+ assert (pp != NULL);
+
+ /* Calculate and return the address of the dimensioned array */
+
+ /* Check EACH dimension for out-of-bounds, AND check correct number
+ * of dimensions. NBS_P076_0250 errors correctly. */
+
+ /*
+ Ux = Upper bound of dimension
+ Lx = Lower bound of dimension
+ Ix = Selected idex in dimension
+
+ dimensions b
+ 0 1
+ 1 b0 * ( U0 - L0 + 1 )
+ 2 b1 * ( U1 - L1 + 1 )
+ 3 b2 * ( U2 - L2 + 1 )
+
+
+ dimensions r
+ 0 0
+ 1 r0 + ( I0 - L0 ) * b0
+ 2 r1 + ( I1 - L1 ) * b1
+ 3 r2 + ( I2 - L2 ) * b2
+
+ */
+
+ r = 0;
+ b = 1;
+ for (n = 0; n < v->dimensions; n++)
+ {
+ if (pp[n] < v->LBOUND[n] || pp[n] > v->UBOUND[n])
+ {
+ WARN_SUBSCRIPT_OUT_OF_RANGE;
+ return 0;
+ }
+ r += b * (pp[n] - v->LBOUND[n]);
+ b *= v->UBOUND[n] - v->LBOUND[n] + 1;
+ }
+
+
+ if (r > v->array_units)
+ {
+ WARN_SUBSCRIPT_OUT_OF_RANGE;
+ return 0;
+ }
+ return r;
+
+}
+
+
+/***************************************************************
+
+ FUNCTION: bwb_option()
+
+ DESCRIPTION: This function implements the BASIC OPTION
+ BASE statement, designating the base (1 or
+ 0) for addressing DIM arrays.
+
+ SYNTAX: OPTION BASE number
+
+***************************************************************/
+
+void
+OptionVersionSet (int i)
+{
+ assert( i >= 0 && i < NUM_VERSIONS );
+ assert( My != NULL );
+
+ My->CurrentVersion = &bwb_vertable[i];
+}
+
+LineType *
+bwb_OPTION (LineType * l)
+{
+ assert (l != NULL);
+
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ANGLE (LineType * l)
+{
+ assert (l != NULL);
+
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ANGLE_DEGREES (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION ANGLE DEGREES */
+ My->CurrentVersion->OptionFlags |= OPTION_ANGLE_DEGREES;
+ My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_GRADIANS;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ANGLE_GRADIANS (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION ANGLE GRADIANS */
+ My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_DEGREES;
+ My->CurrentVersion->OptionFlags |= OPTION_ANGLE_GRADIANS;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ANGLE_RADIANS (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION ANGLE RADIANS */
+ My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_DEGREES;
+ My->CurrentVersion->OptionFlags &= ~OPTION_ANGLE_GRADIANS;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ARITHMETIC (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ARITHMETIC_DECIMAL (LineType * l)
+{
+ /* OPTION ARITHMETIC DECIMAL */
+ assert (l != NULL);
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ARITHMETIC_FIXED (LineType * l)
+{
+ /* OPTION ARITHMETIC FIXED */
+ assert (l != NULL);
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ARITHMETIC_NATIVE (LineType * l)
+{
+ /* OPTION ARITHMETIC NATIVE */
+ assert (l != NULL);
+ return (l);
+}
+
+LineType *
+bwb_OPTION_BASE (LineType * l)
+{
+ /* OPTION BASE integer */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_range_integer (l,
+ &(My->CurrentVersion->OptionBaseInteger),
+ MININT, MAXINT);
+}
+
+LineType *
+bwb_OPTION_BUGS (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_BUGS_BOOLEAN (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION BUGS BOOLEAN */
+ My->CurrentVersion->OptionFlags |= OPTION_BUGS_BOOLEAN;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_BUGS_ON (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION BUGS ON */
+ My->CurrentVersion->OptionFlags |= OPTION_BUGS_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_BUGS_OFF (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION BUGS OFF */
+ My->CurrentVersion->OptionFlags &= ~OPTION_BUGS_ON;
+ My->CurrentVersion->OptionFlags &= ~OPTION_BUGS_BOOLEAN;
+ return (l);
+}
+
+LineType *
+bwb_option_punct_char (LineType * l, char *c)
+{
+ /* OPTION ... char$ */
+
+ assert (l != NULL);
+ assert (c != NULL);
+
+ {
+ char *Value;
+ char C;
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ C = Value[0];
+ free (Value);
+ /* OK */
+ if (bwb_ispunct (C))
+ {
+ /* enable */
+ *c = C;
+ }
+ else
+ {
+ /* disable */
+ *c = NulChar;
+ }
+ }
+ return (l);
+}
+
+LineType *
+bwb_option_range_integer (LineType * l, int *Integer, int MinVal, int MaxVal)
+{
+ /* OPTION ... integer */
+
+ assert (l != NULL);
+ assert (Integer != NULL);
+ assert (MinVal < MaxVal);
+
+ {
+ int Value;
+
+ Value = 0;
+ if (line_read_integer_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value < MinVal || Value > MaxVal)
+ {
+ WARN_ILLEGAL_FUNCTION_CALL;
+ return (l);
+ }
+ *Integer = Value;
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_PUNCT_COMMENT (LineType * l)
+{
+ /* OPTION PUNCT COMMENT char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionCommentChar));
+}
+
+LineType *
+bwb_OPTION_COMPARE (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_COMPARE_BINARY (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION COMPARE BINARY */
+ My->CurrentVersion->OptionFlags &= ~OPTION_COMPARE_TEXT;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_COMPARE_DATABASE (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION COMPARE DATABASE */
+ My->CurrentVersion->OptionFlags |= OPTION_COMPARE_TEXT;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_COMPARE_TEXT (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION COMPARE TEXT */
+ My->CurrentVersion->OptionFlags |= OPTION_COMPARE_TEXT;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_COVERAGE (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_COVERAGE_ON (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION COVERAGE ON */
+ My->CurrentVersion->OptionFlags |= OPTION_COVERAGE_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_COVERAGE_OFF (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION COVERAGE OFF */
+ My->CurrentVersion->OptionFlags &= ~OPTION_COVERAGE_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_DATE (LineType * l)
+{
+ /* OPTION DATE format$ */
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ My->CurrentVersion->OptionDateFormat = Value;
+#if FALSE /* keep this ... */
+ /*
+ ** Yes, this can theoretically cause a memory leak.
+ ** No, we are not going to fix it.
+ ** This command is only supported in the profile.
+ ** This will only execute at most once,
+ ** so there is no actual memory leak.
+ **
+ */
+ free (Value);
+#endif
+ return (l);
+}
+
+LineType *
+bwb_OPTION_DIGITS (LineType * l)
+{
+ int Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+ /* OPTION DIGITS integer */
+ Value = 0;
+ if (line_read_integer_expression (l, &Value))
+ {
+ /* OK */
+ if (Value == 0)
+ {
+ /* default */
+ Value = SIGNIFICANT_DIGITS;
+ }
+ if (Value < MINIMUM_DIGITS || Value > MAXIMUM_DIGITS)
+ {
+ WARN_ILLEGAL_FUNCTION_CALL;
+ return (l);
+ }
+ My->OptionDigitsInteger = Value;
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_DISABLE (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_DISABLE_COMMAND (LineType * l)
+{
+ /* OPTION DISABLE COMMAND name$ */
+ int IsFound;
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+
+ IsFound = FALSE;
+ Value = NULL;
+
+ /* Get COMMAND */
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ {
+ /* Name */
+ int i;
+ for (i = 0; i < NUM_COMMANDS; i++)
+ {
+ if (bwb_stricmp (Value, IntrinsicCommandTable[i].name) == 0)
+ {
+ /* FOUND */
+ /* DISABLE COMMAND */
+ IntrinsicCommandTable[i].OptionVersionBitmask &=
+ ~My->CurrentVersion->OptionVersionValue;
+ IsFound = TRUE;
+ }
+ }
+ }
+ free (Value);
+ if (IsFound == FALSE)
+ {
+ /* display warning message */
+ fprintf (My->SYSOUT->cfp, "IGNORED: %s\n", l->buffer);
+ ResetConsoleColumn ();
+ }
+ return (l);
+}
+
+
+LineType *
+bwb_OPTION_DISABLE_FUNCTION (LineType * l)
+{
+ /* OPTION DISABLE FUNCTION name$ */
+ int IsFound;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+
+ IsFound = FALSE;
+ /* Get FUNCTION */
+ {
+ char *Value;
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ {
+ /* Name */
+ int i;
+ for (i = 0; i < NUM_FUNCTIONS; i++)
+ {
+ if (bwb_stricmp (Value, IntrinsicFunctionTable[i].Name) == 0)
+ {
+ /* FOUND */
+ /* DISABLE FUNCTION */
+ IntrinsicFunctionTable[i].OptionVersionBitmask &=
+ ~My->CurrentVersion->OptionVersionValue;
+ IsFound = TRUE;
+ }
+ }
+ }
+ free (Value);
+ }
+ if (IsFound == FALSE)
+ {
+ /* display warning message */
+ fprintf (My->SYSOUT->cfp, "IGNORED: %s\n", l->buffer);
+ ResetConsoleColumn ();
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_EDIT (LineType * l)
+{
+ /* OPTION EDIT string$ */
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ My->OptionEditString = Value;
+#if FALSE /* keep this ... */
+ /*
+ ** Yes, this can theoretically cause a memory leak.
+ ** No, we are not going to fix it.
+ ** This command is only supported in the profile.
+ ** This will only execute at most once,
+ ** so there is no actual memory leak.
+ **
+ */
+ free (Value);
+#endif
+ return (l);
+}
+
+LineType *
+bwb_OPTION_EXTENSION (LineType * l)
+{
+ /* OPTION EXTENSION ext$ */
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ My->OptionExtensionString = Value;
+#if FALSE /* keep this ... */
+ /*
+ ** Yes, this can theoretically cause a memory leak.
+ ** No, we are not going to fix it.
+ ** This command is only supported in the profile.
+ ** This command will only execute at most once,
+ ** so there is no actual memory leak.
+ **
+ */
+ free (Value);
+#endif
+ return (l);
+}
+
+LineType *
+bwb_OPTION_FILES (LineType * l)
+{
+ /* OPTION FILES name$ */
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ My->OptionFilesString = Value;
+#if FALSE /* keep this ... */
+ /*
+ ** Yes, this can theoretically cause a memory leak.
+ ** No, we are not going to fix it.
+ ** This command is only supported in the profile.
+ ** This will only execute at most once,
+ ** so there is no actual memory leak.
+ **
+ */
+ free (Value);
+#endif
+ return (l);
+}
+
+LineType *
+bwb_OPTION_PROMPT (LineType * l)
+{
+ /* OPTION PROMPT prompt$ */
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ My->OptionPromptString = Value;
+#if FALSE /* keep this ... */
+ /*
+ ** Yes, this can theoretically cause a memory leak.
+ ** No, we are not going to fix it.
+ ** This command is only supported in the profile.
+ ** This will only execute at most once,
+ ** so there is no actual memory leak.
+ **
+ */
+ free (Value);
+#endif
+ return (l);
+}
+
+LineType *
+bwb_OPTION_RENUM (LineType * l)
+{
+ /* OPTION RENUM name$ */
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ My->OptionRenumString = Value;
+#if FALSE /* keep this ... */
+ /*
+ ** Yes, this can theoretically cause a memory leak.
+ ** No, we are not going to fix it.
+ ** This command is only supported in the profile.
+ ** This will only execute at most once,
+ ** so there is no actual memory leak.
+ **
+ */
+ free (Value);
+#endif
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ENABLE (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ENABLE_COMMAND (LineType * l)
+{
+ /* OPTION ENABLE COMMAND name$ */
+ int IsFound;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+
+ IsFound = FALSE;
+ /* Get COMMAND */
+ {
+ char *Value;
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ {
+ /* Name */
+ int i;
+ for (i = 0; i < NUM_COMMANDS; i++)
+ {
+ if (bwb_stricmp (Value, IntrinsicCommandTable[i].name) == 0)
+ {
+ /* FOUND */
+ /* ENABLE COMMAND */
+ IntrinsicCommandTable[i].OptionVersionBitmask |=
+ My->CurrentVersion->OptionVersionValue;
+ IsFound = TRUE;
+ }
+ }
+ }
+ free (Value);
+ }
+ if (IsFound == FALSE)
+ {
+ /* display warning message */
+ fprintf (My->SYSOUT->cfp, "IGNORED: %s\n", l->buffer);
+ ResetConsoleColumn ();
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ENABLE_FUNCTION (LineType * l)
+{
+ /* OPTION ENABLE FUNCTION name$ */
+ int IsFound;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+
+ IsFound = FALSE;
+ /* Get FUNCTION */
+ {
+ char *Value;
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ {
+ /* Name */
+ int i;
+ for (i = 0; i < NUM_FUNCTIONS; i++)
+ {
+ if (bwb_stricmp (Value, IntrinsicFunctionTable[i].Name) == 0)
+ {
+ /* FOUND */
+ /* ENABLE FUNCTION */
+ IntrinsicFunctionTable[i].OptionVersionBitmask |=
+ My->CurrentVersion->OptionVersionValue;
+ IsFound = TRUE;
+ }
+ }
+ }
+ free (Value);
+ }
+ if (IsFound == FALSE)
+ {
+ /* display warning message */
+ fprintf (My->SYSOUT->cfp, "IGNORED: %s\n", l->buffer);
+ ResetConsoleColumn ();
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ERROR (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ERROR_GOSUB (LineType * l)
+{
+ /* OPTION ERROR GOSUB */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ My->CurrentVersion->OptionFlags |= OPTION_ERROR_GOSUB;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ERROR_GOTO (LineType * l)
+{
+ /* OPTION ERROR GOTO */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ My->CurrentVersion->OptionFlags &= ~OPTION_ERROR_GOSUB;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_EXPLICIT (LineType * l)
+{
+ /* OPTION EXPLICIT */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ My->CurrentVersion->OptionFlags |= OPTION_EXPLICIT_ON;
+ return (l);
+}
+
+
+LineType *
+bwb_OPTION_PUNCT_IMAGE (LineType * l)
+{
+ /* OPTION PUNCT IMAGE char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionImageChar));
+}
+
+LineType *
+bwb_OPTION_IMPLICIT (LineType * l)
+{
+ /* OPTION IMPLICIT */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ My->CurrentVersion->OptionFlags &= ~OPTION_EXPLICIT_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_INDENT (LineType * l)
+{
+ /* OPTION INDENT integer */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ return bwb_option_range_integer (l, &(My->OptionIndentInteger), 0, 7);
+}
+
+LineType *
+bwb_OPTION_PUNCT_INPUT (LineType * l)
+{
+ /* OPTION PUNCT INPUT char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionInputChar));
+}
+
+LineType *
+bwb_OPTION_LABELS (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_LABELS_ON (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION LABELS ON */
+ My->CurrentVersion->OptionFlags |= OPTION_LABELS_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_LABELS_OFF (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION LABELS OFF */
+ My->CurrentVersion->OptionFlags &= ~OPTION_LABELS_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_PUNCT_PRINT (LineType * l)
+{
+ /* OPTION PUNCT PRINT char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionPrintChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_QUOTE (LineType * l)
+{
+ /* OPTION PUNCT QUOTE char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionQuoteChar));
+}
+
+LineType *
+bwb_OPTION_ROUND (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ROUND_BANK (LineType * l)
+{
+ /* OPTION ROUND BANK */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ My->OptionRoundType = C_OPTION_ROUND_BANK;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ROUND_MATH (LineType * l)
+{
+ /* OPTION ROUND MATH */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ My->OptionRoundType = C_OPTION_ROUND_MATH;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ROUND_TRUNCATE (LineType * l)
+{
+ /* OPTION ROUND TRUNCATE */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ My->OptionRoundType = C_OPTION_ROUND_TRUNCATE;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_SCALE (LineType * l)
+{
+ /* OPTION SCALE integer */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ return bwb_option_range_integer (l, &(My->OptionScaleInteger),
+ MINIMUM_SCALE, MAXIMUM_SCALE);
+}
+
+
+LineType *
+bwb_OPTION_SLEEP (LineType * l)
+{
+ /* OPTION SLEEP number */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ if (line_read_numeric_expression (l, &My->OptionSleepDouble) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_STDERR (LineType * l)
+{
+ /* OPTION STDERR filename$ */
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->SYSPRN != NULL );
+ assert( My->SYSPRN->cfp != NULL );
+
+
+ if (line_is_eol (l))
+ {
+ bwb_fclose (My->SYSPRN->cfp);
+ My->SYSPRN->cfp = stderr;
+ }
+ else
+ {
+ char *Value;
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ if (is_empty_string (Value))
+ {
+ bwb_fclose (My->SYSPRN->cfp);
+ My->SYSPRN->cfp = stderr;
+ }
+ else
+ {
+ bwb_fclose (My->SYSPRN->cfp);
+ My->SYSPRN->cfp = fopen (Value, "w+");
+ if (My->SYSPRN->cfp == NULL)
+ {
+ /* sane default */
+ My->SYSPRN->cfp = stderr;
+ WARN_BAD_FILE_NAME;
+ }
+ }
+ free (Value);
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_STDIN (LineType * l)
+{
+ /* OPTION STDIN filename$ */
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->SYSIN != NULL );
+ assert( My->SYSIN->cfp != NULL );
+
+ if (line_is_eol (l))
+ {
+ bwb_fclose (My->SYSIN->cfp);
+ My->SYSIN->cfp = stdin;
+ }
+ else
+ {
+ char *Value;
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ if (is_empty_string (Value))
+ {
+ bwb_fclose (My->SYSIN->cfp);
+ My->SYSIN->cfp = stdin;
+ }
+ else
+ {
+ bwb_fclose (My->SYSIN->cfp);
+ My->SYSIN->cfp = fopen (Value, "r");
+ if (My->SYSIN->cfp == NULL)
+ {
+ /* sane default */
+ My->SYSIN->cfp = stdin;
+ WARN_BAD_FILE_NAME;
+ }
+ }
+ free (Value);
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_STDOUT (LineType * l)
+{
+ /* OPTION STDOUT filename$ */
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->SYSOUT != NULL );
+ assert( My->SYSOUT->cfp != NULL );
+
+ if (line_is_eol (l))
+ {
+ bwb_fclose (My->SYSOUT->cfp);
+ My->SYSOUT->cfp = stdout;
+ }
+ else
+ {
+ char *Value;
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ if (is_empty_string (Value))
+ {
+ bwb_fclose (My->SYSOUT->cfp);
+ My->SYSOUT->cfp = stdout;
+ }
+ else
+ {
+ bwb_fclose (My->SYSOUT->cfp);
+ My->SYSOUT->cfp = fopen (Value, "w+");
+ if (My->SYSOUT->cfp == NULL)
+ {
+ /* sane default */
+ My->SYSOUT->cfp = stdout;
+ WARN_BAD_FILE_NAME;
+ }
+ }
+ free (Value);
+ }
+ return (l);
+}
+
+LineType *
+bwb_OPTION_PUNCT_STATEMENT (LineType * l)
+{
+ /* OPTION PUNCT STATEMENT char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l,
+ &(My->CurrentVersion->OptionStatementChar));
+}
+
+LineType *
+bwb_OPTION_STRICT (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_STRICT_ON (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION STRICT ON */
+ My->CurrentVersion->OptionFlags |= OPTION_STRICT_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_STRICT_OFF (LineType * l)
+{
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ /* OPTION STRICT OFF */
+ My->CurrentVersion->OptionFlags &= ~OPTION_STRICT_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_PUNCT (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_PUNCT_STRING (LineType * l)
+{
+ /* OPTION PUNCT STRING char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionStringChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_DOUBLE (LineType * l)
+{
+ /* OPTION PUNCT DOUBLE char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionDoubleChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_SINGLE (LineType * l)
+{
+ /* OPTION PUNCT SINGLE char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionSingleChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_CURRENCY (LineType * l)
+{
+ /* OPTION PUNCT CURRENCY char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionCurrencyChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_LONG (LineType * l)
+{
+ /* OPTION PUNCT LONG char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionLongChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_INTEGER (LineType * l)
+{
+ /* OPTION PUNCT INTEGER char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionIntegerChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_BYTE (LineType * l)
+{
+ /* OPTION PUNCT BYTE char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionByteChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_LPAREN (LineType * l)
+{
+ /* OPTION PUNCT LPAREN char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionLparenChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_RPAREN (LineType * l)
+{
+ /* OPTION PUNCT RPAREN char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionRparenChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_FILENUM (LineType * l)
+{
+ /* OPTION PUNCT FILENUM char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionFilenumChar));
+}
+
+LineType *
+bwb_OPTION_PUNCT_AT (LineType * l)
+{
+ /* OPTION PUNCT AT char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionAtChar));
+}
+
+LineType *
+bwb_OPTION_RECLEN (LineType * l)
+{
+ /* OPTION RECLEN integer */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_range_integer (l,
+ &(My->CurrentVersion->OptionReclenInteger),
+ 0, MAXINT);
+}
+
+LineType *
+bwb_OPTION_TERMINAL (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_TERMINAL_NONE (LineType * l)
+{
+ /* OPTION TERMINAL NONE */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ My->OptionTerminalType = C_OPTION_TERMINAL_NONE;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_TERMINAL_ADM (LineType * l)
+{
+ /* OPTION TERMINAL ADM-3A */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ My->OptionTerminalType = C_OPTION_TERMINAL_ADM;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_TERMINAL_ANSI (LineType * l)
+{
+ /* OPTION TERMINAL ANSI */
+ assert (l != NULL);
+ assert( My != NULL );
+
+ My->OptionTerminalType = C_OPTION_TERMINAL_ANSI;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_TIME (LineType * l)
+{
+ /* OPTION TIME format$ */
+ char *Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ Value = NULL;
+ if (line_read_string_expression (l, &Value) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (Value == NULL)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ /* OK */
+ My->CurrentVersion->OptionTimeFormat = Value;
+#if FALSE /* keep this ... */
+ /*
+ ** Yes, this can theoretically cause a memory leak.
+ ** No, we are not going to fix it.
+ ** This command is only supported in the profile.
+ ** This will only execute at most once,
+ ** so there is no actual memory leak.
+ **
+ */
+ free (Value);
+#endif
+ return (l);
+}
+
+LineType *
+bwb_OPTION_TRACE (LineType * l)
+{
+
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_TRACE_ON (LineType * l)
+{
+ /* OPTION TRACE ON */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ My->CurrentVersion->OptionFlags |= OPTION_TRACE_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_TRACE_OFF (LineType * l)
+{
+ /* OPTION TRACE OFF */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ My->CurrentVersion->OptionFlags &= ~OPTION_TRACE_ON;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_USING (LineType * l)
+{
+ assert (l != NULL);
+ WARN_SYNTAX_ERROR;
+ return (l);
+}
+
+LineType *
+bwb_OPTION_USING_DIGIT (LineType * l)
+{
+ /* OPTION USING DIGIT char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingDigit));
+}
+
+LineType *
+bwb_OPTION_USING_COMMA (LineType * l)
+{
+ /* OPTION USING COMMA char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingComma));
+}
+
+LineType *
+bwb_OPTION_USING_PERIOD (LineType * l)
+{
+ /* OPTION USING PERIOD char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingPeriod));
+}
+
+LineType *
+bwb_OPTION_USING_PLUS (LineType * l)
+{
+ /* OPTION USING PLUS char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingPlus));
+}
+
+LineType *
+bwb_OPTION_USING_MINUS (LineType * l)
+{
+ /* OPTION USING MINUS char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingMinus));
+}
+
+LineType *
+bwb_OPTION_USING_EXRAD (LineType * l)
+{
+ /* OPTION USING EXRAD char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingExrad));
+}
+
+LineType *
+bwb_OPTION_USING_DOLLAR (LineType * l)
+{
+ /* OPTION USING DOLLAR char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingDollar));
+}
+
+LineType *
+bwb_OPTION_USING_FILLER (LineType * l)
+{
+ /* OPTION USING FILLER char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingFiller));
+}
+
+LineType *
+bwb_OPTION_USING_LITERAL (LineType * l)
+{
+ /* OPTION USING LITERAL char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingLiteral));
+}
+
+LineType *
+bwb_OPTION_USING_FIRST (LineType * l)
+{
+ /* OPTION USING FIRST char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingFirst));
+}
+
+LineType *
+bwb_OPTION_USING_ALL (LineType * l)
+{
+ /* OPTION USING ALL char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingAll));
+}
+
+LineType *
+bwb_OPTION_USING_LENGTH (LineType * l)
+{
+ /* OPTION USING LENGTH char$ */
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->CurrentVersion != NULL );
+
+ return bwb_option_punct_char (l, &(My->CurrentVersion->OptionUsingLength));
+}
+
+extern LineType *
+bwb_OPTION_VERSION (LineType * l)
+{
+ /* OPTION VERSION [version$] */
+ char *Name;
+ int i;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->SYSOUT != NULL );
+ assert( My->SYSOUT->cfp != NULL );
+
+
+ Name = NULL;
+ if (line_is_eol (l))
+ {
+ /* OPTIONAL */
+ }
+ else if (line_read_string_expression (l, &Name))
+ {
+ if (is_empty_string (Name) == FALSE)
+ {
+ /* a version was specified */
+ for (i = 0; i < NUM_VERSIONS; i++)
+ {
+ if (bwb_stricmp (Name, bwb_vertable[i].Name) == 0)
+ {
+ /* FOUND */
+ OptionVersionSet (i);
+ return (l);
+ }
+ }
+ /* NOT FOUND */
+ fprintf (My->SYSOUT->cfp, "OPTION VERSION \"%s\" IS INVALID\n", Name);
+ }
+ }
+ fprintf (My->SYSOUT->cfp, "VALID CHOICES ARE:\n");
+ for (i = 0; i < NUM_VERSIONS; i++)
+ {
+ char *tbuf;
+
+ tbuf = My->ConsoleOutput;
+ bwb_strcpy (tbuf, "\"");
+ bwb_strcat (tbuf, bwb_vertable[i].Name);
+ bwb_strcat (tbuf, "\"");
+ fprintf (My->SYSOUT->cfp, "OPTION VERSION %-16s ' %s\n", tbuf,
+ bwb_vertable[i].Description);
+ }
+ ResetConsoleColumn ();
+ line_skip_eol (l);
+ return (l);
+}
+
+LineType *
+bwb_OPTION_ZONE (LineType * l)
+{
+ /* OPTION ZONE integer */
+ int Value;
+
+ assert (l != NULL);
+ assert( My != NULL );
+
+ Value = 0;
+ if (line_read_integer_expression (l, &Value))
+ {
+ /* OK */
+ if (Value == 0)
+ {
+ /* default */
+ Value = ZONE_WIDTH;
+ }
+ if (Value < MINIMUM_ZONE || Value > MAXIMUM_ZONE)
+ {
+ WARN_ILLEGAL_FUNCTION_CALL;
+ return (l);
+ }
+ My->OptionZoneInteger = Value;
+ }
+ return (l);
+}
+
+
+
+int
+var_get (VariableType * variable, VariantType * variant)
+{
+ size_t offset;
+
+ /* check sanity */
+ if (variable == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ if (variant == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+
+ /* Check subscripts */
+ if (dim_check (variable) == FALSE)
+ {
+ WARN_SUBSCRIPT_OUT_OF_RANGE;
+ return FALSE;
+ }
+
+ /* Determine offset from array base ( for scalars the offset is always zero ) */
+ offset = dim_unit (variable, variable->VINDEX);
+
+ CLEAR_VARIANT (variant);
+
+ /* Force compatibility */
+ variant->VariantTypeCode = variable->VariableTypeCode;
+
+ if (variable->VariableTypeCode == StringTypeCode)
+ {
+ /* Variable is a STRING */
+ StringType Value;
+
+ Value.sbuffer = NULL;
+ Value.length = 0;
+ /* both STRING */
+
+ if (variable->VariableFlags & VARIABLE_VIRTUAL) /* var_get() */
+ {
+ /* get file information */
+ VirtualType *Z;
+ FileType *F;
+
+ Z = find_virtual_by_variable (variable);
+ if (Z == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ offset *= Z->FileLength; /* Byte offset */
+ offset += Z->FileOffset; /* Beginning of this data */
+ /* update file information */
+ F = find_file_by_number (Z->FileNumber);
+ if (F == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->DevMode != DEVMODE_VIRTUAL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->cfp == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (fseek (F->cfp, offset, SEEK_SET) != 0)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ Value.length = Z->FileLength;
+ if ((Value.sbuffer =
+ (char *) calloc (Value.length + 1 /* NulChar */ ,
+ sizeof (char))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return FALSE;
+ }
+ if (fread (Value.sbuffer, Value.length, 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ }
+ else
+ {
+ StringType *string;
+
+ string = variable->Value.String;
+ if (string == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ string += offset;
+ if (str_btob (&Value, string) == FALSE)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ }
+ variant->Buffer = Value.sbuffer;
+ variant->Length = Value.length;
+ }
+ else
+ {
+ /* Variable is a NUMBER */
+ DoubleType Value;
+ /* both NUMBER */
+
+ if (variable->VariableFlags & VARIABLE_VIRTUAL) /* var_get() */
+ {
+ /* get file information */
+ VirtualType *Z;
+ FileType *F;
+
+ Z = find_virtual_by_variable (variable);
+ if (Z == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ offset *= Z->FileLength; /* Byte offset */
+ offset += Z->FileOffset; /* Beginning of this data */
+ /* update file information */
+ F = find_file_by_number (Z->FileNumber);
+ if (F == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->DevMode != DEVMODE_VIRTUAL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->cfp == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (fseek (F->cfp, offset, SEEK_SET) != 0)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ switch (variable->VariableTypeCode)
+ {
+ case ByteTypeCode:
+ {
+ ByteType X;
+ if (fread (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ Value = X;
+ }
+ break;
+ case IntegerTypeCode:
+ {
+ IntegerType X;
+ if (fread (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ Value = X;
+ }
+ break;
+ case LongTypeCode:
+ {
+ LongType X;
+ if (fread (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ Value = X;
+ }
+ break;
+ case CurrencyTypeCode:
+ {
+ CurrencyType X;
+ if (fread (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ Value = X;
+ }
+ break;
+ case SingleTypeCode:
+ {
+ SingleType X;
+ if (fread (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ Value = X;
+ }
+ break;
+ case DoubleTypeCode:
+ {
+ DoubleType X;
+ if (fread (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ Value = X;
+ }
+ break;
+ case StringTypeCode:
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ /* break; */
+ default:
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ DoubleType *number;
+
+ number = variable->Value.Number;
+ if (number == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ number += offset;
+ /* copy value */
+ Value = *number;
+ }
+
+ /* VerifyNumeric */
+ if (isnan (Value))
+ {
+ /*** FATAL - INTERNAL ERROR - SHOULD NEVER HAPPEN ***/
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ if (isinf (Value))
+ {
+ /* - 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 (Value < 0)
+ {
+ Value = MINDBL;
+ }
+ else
+ {
+ Value = MAXDBL;
+ }
+ if (WARN_OVERFLOW)
+ {
+ /* ERROR */
+ return FALSE;
+ }
+ /* CONTINUE */
+ }
+ /* OK */
+ switch (variable->VariableTypeCode)
+ {
+ case ByteTypeCode:
+ case IntegerTypeCode:
+ case LongTypeCode:
+ case CurrencyTypeCode:
+ /* integer values */
+ Value = bwb_rint (Value);
+ break;
+ case SingleTypeCode:
+ case DoubleTypeCode:
+ /* float values */
+ break;
+ default:
+ /* ERROR */
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ /* break; */
+ }
+ variant->Number = Value;
+ }
+ return TRUE;
+}
+
+int
+var_set (VariableType * variable, VariantType * variant)
+{
+ size_t offset;
+
+ assert( My != NULL );
+ assert( My->SYSOUT != NULL );
+ assert( My->SYSOUT->cfp != NULL );
+
+ /* check sanity */
+ if (variable == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ if (variant == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+
+ /* check CONST */
+ if (variable->VariableFlags & (VARIABLE_CONSTANT))
+ {
+ /* attempting to assign to a constant */
+ WARN_VARIABLE_NOT_DECLARED;
+ return FALSE;
+ }
+
+ /* Check subscripts */
+ if (dim_check (variable) == FALSE)
+ {
+ WARN_SUBSCRIPT_OUT_OF_RANGE;
+ return FALSE;
+ }
+
+ /* Determine offset from array base ( for scalars the offset is always zero ) */
+ offset = dim_unit (variable, variable->VINDEX);
+
+ /* Verify compatibility */
+ if (variable->VariableTypeCode == StringTypeCode)
+ {
+ /* Variable is a STRING */
+ StringType Value;
+
+ /* Verify value is a STRING */
+ if (variant->VariantTypeCode != StringTypeCode)
+ {
+ WARN_TYPE_MISMATCH;
+ return FALSE;
+ }
+ Value.sbuffer = variant->Buffer;
+ Value.length = variant->Length;
+ /* both STRING */
+
+ if (variable->VariableFlags & VARIABLE_VIRTUAL) /* var_set() */
+ {
+ /* get file information */
+ VirtualType *Z;
+ FileType *F;
+ int count;
+
+ Z = find_virtual_by_variable (variable);
+ if (Z == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ offset *= Z->FileLength; /* Byte offset */
+ offset += Z->FileOffset; /* Beginning of this data */
+ /* update file information */
+ F = find_file_by_number (Z->FileNumber);
+ if (F == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->DevMode != DEVMODE_VIRTUAL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->cfp == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (fseek (F->cfp, offset, SEEK_SET) != 0)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ count = MIN (Value.length, Z->FileLength);
+ if (fwrite (Value.sbuffer, sizeof (char), count, F->cfp) != count)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ /* PADR */
+ while (count < Z->FileLength)
+ {
+ if (fputc (' ', F->cfp) == EOF)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ count++;
+ }
+ }
+ else
+ {
+ StringType *string;
+
+ string = variable->Value.String;
+ if (string == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ string += offset;
+ if (str_btob (string, &Value) == FALSE)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ }
+ if (variable->VariableFlags & VARIABLE_DISPLAY) /* var_set() */
+ {
+ if (My->ThisLine) /* var_set() */
+ {
+ if (My->ThisLine->LineFlags & (LINE_USER)) /* var_set() */
+ {
+ /* immediate mode */
+ }
+ else
+ {
+ fprintf (My->SYSOUT->cfp, "#%d %s=%s\n", My->ThisLine->number, variable->name, variant->Buffer); /* var_set() */
+ ResetConsoleColumn ();
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Variable is a NUMBER */
+ DoubleType Value;
+
+ /* Verify value is a NUMBER */
+ if (variant->VariantTypeCode == StringTypeCode)
+ {
+ WARN_TYPE_MISMATCH;
+ return FALSE;
+ }
+
+ /* both NUMBER */
+
+ /* VerifyNumeric */
+ if (isnan (variant->Number))
+ {
+ /*** FATAL - INTERNAL ERROR - SHOULD NEVER HAPPEN ***/
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ if (isinf (variant->Number))
+ {
+ /* - 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 (variant->Number < 0)
+ {
+ variant->Number = MINDBL;
+ }
+ else
+ {
+ variant->Number = MAXDBL;
+ }
+ if (WARN_OVERFLOW)
+ {
+ /* ERROR */
+ return FALSE;
+ }
+ /* CONTINUE */
+ }
+ /* OK */
+ switch (variable->VariableTypeCode)
+ {
+ case ByteTypeCode:
+ variant->Number = bwb_rint (variant->Number);
+ if (variant->Number < MINBYT)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MINBYT;
+ }
+ else if (variant->Number > MAXBYT)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MAXBYT;
+ }
+ break;
+ case IntegerTypeCode:
+ variant->Number = bwb_rint (variant->Number);
+ if (variant->Number < MININT)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MININT;
+ }
+ else if (variant->Number > MAXINT)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MAXINT;
+ }
+ break;
+ case LongTypeCode:
+ variant->Number = bwb_rint (variant->Number);
+ if (variant->Number < MINLNG)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MINLNG;
+ }
+ else if (variant->Number > MAXLNG)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MAXLNG;
+ }
+ break;
+ case CurrencyTypeCode:
+ variant->Number = bwb_rint (variant->Number);
+ if (variant->Number < MINCUR)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MINCUR;
+ }
+ else if (variant->Number > MAXCUR)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MAXCUR;
+ }
+ break;
+ case SingleTypeCode:
+ if (variant->Number < MINSNG)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MINSNG;
+ }
+ else if (variant->Number > MAXSNG)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MAXSNG;
+ }
+ break;
+ case DoubleTypeCode:
+ if (variant->Number < MINDBL)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MINDBL;
+ }
+ else if (variant->Number > MAXDBL)
+ {
+ if (WARN_OVERFLOW)
+ {
+ return FALSE;
+ }
+ variant->Number = MAXDBL;
+ }
+ break;
+ default:
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ /* break; */
+ }
+ Value = variant->Number;
+ if (variable->VariableFlags & VARIABLE_VIRTUAL) /* var_set() */
+ {
+ /* get file information */
+ VirtualType *Z;
+ FileType *F;
+
+ Z = find_virtual_by_variable (variable);
+ if (Z == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ offset *= Z->FileLength; /* Byte offset */
+ offset += Z->FileOffset; /* Beginning of this data */
+ /* update file information */
+ F = find_file_by_number (Z->FileNumber);
+ if (F == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->DevMode != DEVMODE_VIRTUAL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (F->cfp == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ if (fseek (F->cfp, offset, SEEK_SET) != 0)
+ {
+ WARN_BAD_FILE_MODE;
+ return FALSE;
+ }
+ switch (variable->VariableTypeCode)
+ {
+ case ByteTypeCode:
+ {
+ ByteType X;
+ X = Value;
+ if (fwrite (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ }
+ break;
+ case IntegerTypeCode:
+ {
+ IntegerType X;
+ X = Value;
+ if (fwrite (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ }
+ break;
+ case LongTypeCode:
+ {
+ LongType X;
+ X = Value;
+ if (fwrite (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ }
+ break;
+ case CurrencyTypeCode:
+ {
+ CurrencyType X;
+ X = Value;
+ if (fwrite (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ }
+ break;
+ case SingleTypeCode:
+ {
+ SingleType X;
+ X = Value;
+ if (fwrite (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ }
+ break;
+ case DoubleTypeCode:
+ {
+ DoubleType X;
+ X = Value;
+ if (fwrite (&X, sizeof (X), 1, F->cfp) != 1)
+ {
+ WARN_DISK_IO_ERROR;
+ return FALSE;
+ }
+ }
+ break;
+ case StringTypeCode:
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ /* break; */
+ default:
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ DoubleType *number;
+ number = variable->Value.Number;
+ if (number == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ number += offset;
+ *number = Value;
+ }
+ if (variable->VariableFlags & VARIABLE_DISPLAY) /* var_set() */
+ {
+ if (My->ThisLine) /* var_set() */
+ {
+ if (My->ThisLine->LineFlags & (LINE_USER)) /* var_set() */
+ {
+ /* immediate mode */
+ }
+ else
+ {
+ FormatBasicNumber (Value, My->NumLenBuffer);
+ fprintf (My->SYSOUT->cfp, "#%d %s=%s\n", My->ThisLine->number, variable->name, My->NumLenBuffer); /* var_set() */
+ ResetConsoleColumn ();
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+/***************************************************************
+
+ FUNCTION: dim_check()
+
+ DESCRIPTION: This function checks subscripts of a
+ specific variable to be sure that they
+ are within the correct range.
+
+***************************************************************/
+
+static int
+dim_check (VariableType * variable)
+{
+ /* Check for validly allocated array */
+ int n;
+
+ assert (variable != NULL);
+
+
+ if (variable->VariableFlags & VARIABLE_VIRTUAL) /* var_set() */
+ {
+ if (variable->Value.String != NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ if (variable->Value.Number != NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ }
+ else if (VAR_IS_STRING (variable))
+ {
+ if (variable->Value.String == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (variable->Value.Number == NULL)
+ {
+ WARN_INTERNAL_ERROR;
+ return FALSE;
+ }
+ }
+ /* Now check subscript values */
+ for (n = 0; n < variable->dimensions; n++)
+ {
+ if (variable->VINDEX[n] < variable->LBOUND[n]
+ || variable->VINDEX[n] > variable->UBOUND[n])
+ {
+ WARN_SUBSCRIPT_OUT_OF_RANGE;
+ return FALSE;
+ }
+ }
+ /* No problems found */
+ return TRUE;
+}
+
+/***************************************************************
+
+ FUNCTION: var_make()
+
+ DESCRIPTION: This function initializes a variable,
+ allocating necessary memory for it.
+
+***************************************************************/
+
+int
+var_make (VariableType * variable, char TypeCode)
+{
+ /* ALL variables are created here */
+
+ assert (variable != NULL);
+
+ switch (TypeCode)
+ {
+ case ByteTypeCode:
+ case IntegerTypeCode:
+ case LongTypeCode:
+ case CurrencyTypeCode:
+ case SingleTypeCode:
+ case DoubleTypeCode:
+ case StringTypeCode:
+ /* OK */
+ break;
+ default:
+ /* ERROR */
+ WARN_TYPE_MISMATCH;
+ return FALSE;
+ }
+
+ variable->VariableTypeCode = TypeCode;
+
+ /* get memory for array */
+
+ /* First cleanup the joint (JBV) */
+ if (variable->Value.Number != NULL)
+ {
+ free (variable->Value.Number);
+ variable->Value.Number = NULL;
+ }
+ if (variable->Value.String != NULL)
+ {
+ /* Remember to deallocate those far-flung branches! (JBV) */
+ StringType *sp; /* JBV */
+ int n; /* JBV */
+
+ sp = variable->Value.String;
+ for (n = 0; n < (int) variable->array_units; n++)
+ {
+ if (sp[n].sbuffer != NULL)
+ {
+ free (sp[n].sbuffer);
+ sp[n].sbuffer = NULL;
+ }
+ sp[n].length = 0;
+ }
+ free (variable->Value.String);
+ variable->Value.String = NULL;
+ }
+
+ variable->dimensions = 0;
+ variable->array_units = 1;
+
+ if (VAR_IS_STRING (variable))
+ {
+ if ((variable->Value.String =
+ calloc (variable->array_units, sizeof (StringType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ((variable->Value.Number =
+ calloc (variable->array_units, sizeof (DoubleType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return FALSE;
+ }
+ }
+ return TRUE;
+
+}
+
+/***************************************************************
+
+ FUNCTION: var_islocal()
+
+ DESCRIPTION: This function determines whether the string
+ pointed to by 'buffer' has the name of
+ a local variable at the present EXEC stack
+ level.
+
+***************************************************************/
+
+static VariableType *
+mat_islocal (char *buffer)
+{
+ /*
+ similar to var_islocal, but returns first matrix found.
+ */
+
+ assert (buffer != NULL);
+ assert( My != NULL );
+
+ if (My->StackHead != NULL)
+ {
+ StackType *StackItem;
+ for (StackItem = My->StackHead; StackItem != NULL;
+ StackItem = StackItem->next)
+ {
+ if (StackItem->LoopTopLine != NULL)
+ {
+ switch (StackItem->LoopTopLine->cmdnum)
+ {
+ case C_DEF:
+ case C_FUNCTION:
+ case C_SUB:
+ /* we have found a FUNCTION or SUB boundary */
+ {
+ VariableType *variable;
+
+ for (variable = StackItem->local_variable; variable != NULL;
+ variable = variable->next)
+ {
+ if (variable->dimensions > 0)
+ {
+ if (bwb_stricmp (variable->name, buffer) == 0)
+ {
+ /* FOUND */
+ return variable;
+ }
+ }
+ }
+ }
+ /* we have checked all the way to a FUNCTION or SUB boundary */
+ /* NOT FOUND */
+ return NULL;
+ /* break; */
+ }
+ }
+ }
+ }
+ /* NOT FOUND */
+ return NULL;
+}
+
+
+static VariableType *
+var_islocal (char *buffer, int dimensions)
+{
+
+ assert (buffer != NULL);
+ assert( My != NULL );
+
+ if (My->StackHead != NULL)
+ {
+ StackType *StackItem;
+ for (StackItem = My->StackHead; StackItem != NULL;
+ StackItem = StackItem->next)
+ {
+ if (StackItem->LoopTopLine != NULL)
+ {
+ switch (StackItem->LoopTopLine->cmdnum)
+ {
+ case C_DEF:
+ case C_FUNCTION:
+ case C_SUB:
+ /* we have found a FUNCTION or SUB boundary */
+ {
+ VariableType *variable;
+
+ for (variable = StackItem->local_variable; variable != NULL;
+ variable = variable->next)
+ {
+ if (variable->dimensions == dimensions)
+ {
+ if (bwb_stricmp (variable->name, buffer) == 0)
+ {
+ /* FOUND */
+ return variable;
+ }
+ }
+ }
+ }
+ /* we have checked all the way to a FUNCTION or SUB boundary */
+ /* NOT FOUND */
+ return NULL;
+ /* break; */
+ }
+ }
+ }
+ }
+ /* NOT FOUND */
+ return NULL;
+}
+
+/***************************************************************
+
+ FUNCTION: bwb_vars()
+
+ DESCRIPTION: This function implements the Bywater-
+ specific debugging command VARS, which
+ gives a list of all variables defined
+ in memory.
+
+***************************************************************/
+
+
+LineType *
+bwb_VARS (LineType * l)
+{
+ VariableType *variable;
+
+ assert (l != NULL);
+ assert( My != NULL );
+ assert( My->SYSOUT != NULL );
+ assert( My->SYSOUT->cfp != NULL );
+
+ /* run through the variable list and print variables */
+
+
+ fprintf (My->SYSOUT->cfp, "%-*s %-6s %-4s %s\n", NameLengthMax, "Name",
+ "Type", "Dims", "Value");
+
+ for (variable = My->VariableHead; variable != NULL;
+ variable = variable->next)
+ {
+ VariantType variant;
+ CLEAR_VARIANT (&variant);
+
+ if (var_get (variable, &variant) == FALSE)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return (l);
+ }
+ if (variant.VariantTypeCode == StringTypeCode)
+ {
+ fprintf (My->SYSOUT->cfp, "%-*s %-6s %-4d %s\n", NameLengthMax,
+ variable->name, "STRING", variable->dimensions,
+ variant.Buffer);
+ }
+ else
+ {
+ FormatBasicNumber (variant.Number, My->NumLenBuffer);
+ fprintf (My->SYSOUT->cfp, "%-*s %-6s %-4d %s\n", NameLengthMax,
+ variable->name, "NUMBER", variable->dimensions,
+ My->NumLenBuffer);
+ }
+ RELEASE_VARIANT (&variant);
+ }
+ ResetConsoleColumn ();
+ return (l);
+}
+
+/***************************************************************
+
+ FUNCTION: bwb_field()
+
+ DESCRIPTION: This C function implements the BASIC
+ FIELD command.
+
+***************************************************************/
+
+static void
+field_clear (FieldType * Field)
+{
+ int i;
+
+ assert (Field != NULL);
+
+ Field->File = NULL;
+ Field->FieldOffset = 0;
+ Field->FieldLength = 0;
+ Field->Var = NULL;
+ for (i = 0; i < MAX_DIMS; i++)
+ {
+ Field->VINDEX[i] = 0;
+ }
+}
+
+static FieldType *
+field_new (void)
+{
+ /* search for an empty slot */
+ FieldType *Field;
+
+ assert( My != NULL );
+
+ for (Field = My->FieldHead; Field != NULL; Field = Field->next)
+ {
+ if (Field->File == NULL || Field->Var == NULL)
+ {
+ field_clear (Field);
+ return Field;
+ }
+ }
+ /* not found */
+ if ((Field = calloc (1, sizeof (FieldType))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return NULL;
+ }
+ Field->next = My->FieldHead;
+ My->FieldHead = Field;
+ return Field;
+}
+
+void
+field_close_file (FileType * File)
+{
+ /* a CLOSE of a file is in progress, release associated fields */
+ FieldType *Field;
+
+ assert (File != NULL);
+ assert( My != NULL );
+
+ for (Field = My->FieldHead; Field != NULL; Field = Field->next)
+ {
+ if (Field->File == File)
+ {
+ Field->File = NULL;
+ Field->Var = NULL;
+ }
+ }
+}
+void
+field_free_variable (VariableType * Var)
+{
+ /* an ERASE of a variable is in progress, release associated fields */
+ FieldType *Field;
+
+ assert (Var != NULL);
+ assert( My != NULL );
+
+ for (Field = My->FieldHead; Field != NULL; Field = Field->next)
+ {
+ if (Field->Var == Var)
+ {
+ Field->File = NULL;
+ Field->Var = NULL;
+ }
+ }
+}
+
+
+void
+field_get (FileType * File)
+{
+ /* a GET of the RANDOM file is in progress, update variables from FILE buffer */
+ FieldType *Field;
+
+ assert( My != NULL );
+
+ if (File == NULL)
+ {
+ WARN_BAD_FILE_NUMBER;
+ return;
+ }
+ if (File->buffer == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return;
+ }
+ for (Field = My->FieldHead; Field != NULL; Field = Field->next)
+ {
+ if (Field->File == File && Field->Var != NULL)
+ {
+ /* from file to variable */
+ VariantType variant;
+ CLEAR_VARIANT (&variant);
+
+ if (Field->FieldOffset < 0)
+ {
+ WARN_FIELD_OVERFLOW;
+ return;
+ }
+ if (Field->FieldLength <= 0)
+ {
+ WARN_FIELD_OVERFLOW;
+ return;
+ }
+ if ((Field->FieldOffset + Field->FieldLength) > File->width)
+ {
+ WARN_FIELD_OVERFLOW;
+ return;
+ }
+ variant.VariantTypeCode = StringTypeCode;
+ variant.Length = Field->FieldLength;
+ if ((variant.Buffer =
+ (char *) calloc (variant.Length + 1 /* NulChar */ ,
+ sizeof (char))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return;
+ }
+ /* if( TRUE ) */
+ {
+ int i;
+
+ for (i = 0; i < Field->Var->dimensions; i++)
+ {
+ Field->Var->VINDEX[i] = Field->VINDEX[i];
+ }
+ }
+ /* if( TRUE ) */
+ {
+ int i;
+ char *Buffer;
+
+ Buffer = File->buffer;
+ Buffer += Field->FieldOffset;
+ for (i = 0; i < variant.Length; i++)
+ {
+ variant.Buffer[i] = Buffer[i];
+ }
+ variant.Buffer[variant.Length] = NulChar;
+ }
+ if (var_set (Field->Var, &variant) == FALSE)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return;
+ }
+ RELEASE_VARIANT (&variant);
+ }
+ }
+}
+void
+field_put (FileType * File)
+{
+ /* a PUT of the RANDOM file is in progress, update FILE buffer from variables */
+ FieldType *Field;
+
+ assert( My != NULL );
+
+ if (File == NULL)
+ {
+ WARN_BAD_FILE_NUMBER;
+ return;
+ }
+ if (File->buffer == NULL)
+ {
+ WARN_BAD_FILE_MODE;
+ return;
+ }
+ for (Field = My->FieldHead; Field != NULL; Field = Field->next)
+ {
+ if (Field->File == File && Field->Var != NULL)
+ {
+ /* from variable to file */
+ VariantType variant;
+ CLEAR_VARIANT (&variant);
+
+ if (Field->FieldOffset < 0)
+ {
+ WARN_FIELD_OVERFLOW;
+ return;
+ }
+ if (Field->FieldLength <= 0)
+ {
+ WARN_FIELD_OVERFLOW;
+ return;
+ }
+ if ((Field->FieldOffset + Field->FieldLength) > File->width)
+ {
+ WARN_FIELD_OVERFLOW;
+ return;
+ }
+ /* if( TRUE ) */
+ {
+ int i;
+
+ for (i = 0; i < Field->Var->dimensions; i++)
+ {
+ Field->Var->VINDEX[i] = Field->VINDEX[i];
+ }
+ }
+ if (var_get (Field->Var, &variant) == FALSE)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return;
+ }
+ if (variant.VariantTypeCode != StringTypeCode)
+ {
+ WARN_TYPE_MISMATCH;
+ return;
+ }
+ /* if( TRUE ) */
+ {
+ int i;
+ int n;
+ char *Buffer;
+
+ i = 0;
+ n = 0;
+ Buffer = File->buffer;
+ Buffer += Field->FieldOffset;
+
+ if (variant.Buffer != NULL)
+ {
+ n = MIN (variant.Length, Field->FieldLength);
+ }
+ for (i = 0; i < n; i++)
+ {
+ Buffer[i] = variant.Buffer[i];
+ }
+ for (i = n; i < Field->FieldLength; i++)
+ {
+ /* Pad on the right with spaces */
+ Buffer[i] = ' ';
+ }
+ }
+ RELEASE_VARIANT (&variant);
+ }
+ }
+}
+
+
+LineType *
+bwb_FIELD (LineType * l)
+{
+ FileType *File;
+ int FileNumber;
+ int FieldOffset;
+
+ assert (l != NULL);
+
+ FileNumber = 0;
+ FieldOffset = 0;
+
+ /* first read device number */
+ if (line_skip_FilenumChar (l))
+ {
+ /* optional */
+ }
+ if (line_read_integer_expression (l, &FileNumber) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (FileNumber <= 0)
+ {
+ /* FIELD # 0 is an error */
+ WARN_BAD_FILE_NUMBER;
+ return (l);
+ }
+ File = find_file_by_number (FileNumber);
+ if (File == NULL)
+ {
+ WARN_BAD_FILE_NUMBER;
+ return (l);
+ }
+ if (File->DevMode != DEVMODE_RANDOM)
+ {
+ WARN_BAD_FILE_MODE;
+ return (l);
+ }
+ /* loop to read variables */
+
+
+ /* read the comma and advance beyond it */
+ while (line_skip_seperator (l))
+ {
+ int FieldLength;
+ VariableType *variable;
+ VariantType variant;
+
+ CLEAR_VARIANT (&variant);
+
+ /* first find the size of the field */
+ FieldLength = 0;
+ if (line_read_integer_expression (l, &FieldLength) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (FieldLength <= 0)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ /* read the AS */
+ if (line_skip_word (l, "AS") == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ /* read the string variable name */
+ if ((variable = line_read_scalar (l)) == NULL)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return (l);
+ }
+
+ if (VAR_IS_STRING (variable))
+ {
+ /* OK */
+ }
+ else
+ {
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+ /* check for overflow of record length */
+ if ((FieldOffset + FieldLength) > File->width)
+ {
+ WARN_FIELD_OVERFLOW;
+ return (l);
+ }
+ /* set buffer */
+ variant.VariantTypeCode = StringTypeCode;
+ /* if( TRUE ) */
+ {
+ FieldType *Field;
+ int i;
+
+ Field = field_new ();
+ if (Field == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return (l);
+ }
+ Field->File = File;
+ Field->FieldOffset = FieldOffset;
+ Field->FieldLength = FieldLength;
+ Field->Var = variable;
+ for (i = 0; i < variable->dimensions; i++)
+ {
+ Field->VINDEX[i] = variable->VINDEX[i];
+ }
+ variant.Length = FieldLength;
+ if ((variant.Buffer =
+ (char *) calloc (variant.Length + 1 /* NulChar */ ,
+ sizeof (char))) == NULL)
+ {
+ WARN_OUT_OF_MEMORY;
+ return (l);
+ }
+ bwb_memset (variant.Buffer, ' ', variant.Length);
+ variant.Buffer[variant.Length] = NulChar;
+ }
+ if (var_set (variable, &variant) == FALSE)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return (l);
+ }
+ RELEASE_VARIANT (&variant);
+ FieldOffset += FieldLength;
+ }
+ /* return */
+ return (l);
+}
+
+/***************************************************************
+
+ FUNCTION: bwb_lset()
+
+ DESCRIPTION: This C function implements the BASIC
+ LSET command.
+
+ SYNTAX: LSET string-variable$ = expression
+
+***************************************************************/
+
+LineType *
+bwb_LSET (LineType * l)
+{
+
+ assert (l != NULL);
+ return dio_lrset (l, FALSE);
+}
+
+/***************************************************************
+
+ FUNCTION: bwb_rset()
+
+ DESCRIPTION: This C function implements the BASIC
+ RSET command.
+
+ SYNTAX: RSET string-variable$ = expression
+
+***************************************************************/
+
+LineType *
+bwb_RSET (LineType * l)
+{
+
+ assert (l != NULL);
+ return dio_lrset (l, TRUE);
+}
+
+/***************************************************************
+
+ FUNCTION: dio_lrset()
+
+ DESCRIPTION: This C function implements the BASIC
+ RSET and LSET commands.
+
+***************************************************************/
+
+static LineType *
+dio_lrset (LineType * l, int rset)
+{
+ /* LSET and RSET */
+ VariantType variant;
+ int n;
+ int i;
+ int startpos;
+ VariableType *v;
+ VariantType t;
+ VariantType *T;
+
+ assert (l != NULL);
+
+ T = &t;
+ CLEAR_VARIANT (T);
+ CLEAR_VARIANT (&variant);
+ /* get the variable */
+ if ((v = line_read_scalar (l)) == NULL)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return (l);
+ }
+ if (VAR_IS_STRING (v) == FALSE)
+ {
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+
+ /* skip the equals sign */
+ if (line_skip_EqualChar (l) == FALSE)
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+
+ /* get the value */
+ if (line_read_expression (l, T) == FALSE) /* dio_lrset */
+ {
+ WARN_SYNTAX_ERROR;
+ return (l);
+ }
+ if (T->VariantTypeCode != StringTypeCode)
+ {
+ WARN_TYPE_MISMATCH;
+ return (l);
+ }
+ if (var_get (v, &variant) == FALSE)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return (l);
+ }
+ /* determine starting position */
+ startpos = 0;
+ if (rset == TRUE && T->Length < variant.Length)
+ {
+ /*
+ LET A$ = "123_456" ' variant.Length = 7
+ LET B$ = "789" ' T->Length = 3
+ RSET A$ = B$ ' startpos = 4
+ PRINT "[";A$;"]" ' [123_789]
+ */
+ startpos = variant.Length - T->Length;
+ }
+ /* write characters to new position */
+ for (n = startpos, i = 0;
+ (n < (int) variant.Length) && (i < (int) T->Length); n++, i++)
+ {
+ variant.Buffer[n] = T->Buffer[i];
+ }
+ if (var_set (v, &variant) == FALSE)
+ {
+ WARN_VARIABLE_NOT_DECLARED;
+ return (l);
+ }
+ /* OK */
+ RELEASE_VARIANT (T);
+ RELEASE_VARIANT (&variant);
+
+ return (l);
+}
+
+/* EOF */
Un proyecto texto-plano.xyz