/***************************************************************f bwb_int.c Line Interpretation 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 */ /* */ /*---------------------------------------------------------------*/ #include "bwbasic.h" int buff_is_eol( char *buffer, int * position ) { /* determines whether 'position' is at the NUL (BasicNulChar) in 'buffer'. if successful then returns TRUE otherwise returns FALSE. 'position' is unchanged. */ int p; p = *position; if( buffer[p] == BasicNulChar ) { return TRUE; } return FALSE; } int line_is_eol( LineType * line ) { return buff_is_eol( line->buffer, &(line->position) ); } int buff_skip_eol( char *buffer, int * position ) { /* skip to the NUL (BasicNulChar) in 'buffer'. if successful then 'position' is updated and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; p = *position; if( buffer[p] != BasicNulChar ) { while( buffer[p] != BasicNulChar ) { p++; } *position = p; return TRUE; } return FALSE; } int line_skip_eol( LineType * line ) { return buff_skip_eol( line->buffer, &(line->position) ); } int buff_skip_spaces( char *buffer, int * position ) { /* skip spaces in 'buffer'. if successful then 'position' is updated and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; p = *position; if( buffer[p] == ' ' ) { while( buffer[p] == ' ' ) { p++; } *position = p; return TRUE; } return FALSE; } int line_skip_spaces( LineType * line ) { return buff_skip_spaces( line->buffer, &(line->position) ); } int buff_peek_char( char *buffer, int * position, char find ) { /* determine whether the next non-space character in 'buffer' is 'find'. if successful then returns TRUE otherwise returns FALSE. 'position' is unchanged. */ int p; p = *position; buff_skip_spaces( buffer, &p ); if( bwb_toupper(buffer[p]) == bwb_toupper(find) ) { return TRUE; } return FALSE; } int line_peek_char( LineType * line, char find ) { return buff_peek_char( line->buffer, &(line->position), find ); } int buff_skip_char( char *buffer, int * position, char find ) { /* skip the next non-space character in 'buffer' if it is 'find'. if successful then 'position' is updated past 'find' and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; p = *position; buff_skip_spaces( buffer, &p ); if( bwb_toupper(buffer[p]) == bwb_toupper(find) ) { p++; *position = p; return TRUE; } return FALSE; } int line_skip_char( LineType * line, char find ) { return buff_skip_char( line->buffer, &(line->position), find ); } int buff_skip_comma( char *buffer, int * position ) { /* skip the next non-space character in 'buffer' if it is a comma, semicolon, or colon. if successful then 'position' is updated past the character and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; p = *position; buff_skip_spaces( buffer, &p ); switch( buffer[p] ) { case ',': /* COMMA */ case ';': /* SEMICOLON */ case ':': /* COLON */ p++; buff_skip_spaces( buffer, &p ); *position = p; return TRUE; } return FALSE; } int line_skip_comma( LineType * line ) { return buff_skip_comma( line->buffer, &(line->position) ); } static int char_is_varfirst( char C ) { /* determine whether the character is allowed to be the first character of a BASIC variable name. if successful then returns TRUE otherwise returns FALSE. */ if( bwb_isalpha( C ) ) { return TRUE; } return FALSE; } static int char_is_varnext( char C ) { /* determine whether the character is allowed to be the second character of a BASIC variable name. if successful then returns TRUE otherwise returns FALSE. */ if( bwb_isalnum( C ) ) { return TRUE; } switch(C) { case '.': case '_': if( My->CurrentVersion->OptionFlags & (OPTION_BUGS_ON) /* varnamex: period and underscore are allowed */ ) { return TRUE; } } return FALSE; } int char_is_vartype( char C ) { /* determine whether the character is allowed to be the type character of a BASIC variable name. if successful then returns TRUE otherwise returns FALSE. */ switch( C ) { case BasicStringSuffix: return TRUE; case BasicDoubleSuffix: case BasicSingleSuffix: case BasicCurrencySuffix: case BasicLongSuffix: case BasicIntegerSuffix: case BasicByteSuffix: if( My->CurrentVersion->OptionFlags & (OPTION_BUGS_ON) /* varname: numeric type-chars allowed */ ) { return TRUE; } } return FALSE; } static int char_is_varhead( char C ) { if( char_is_varfirst( C ) ) { return TRUE; } if( char_is_varnext( C ) ) { return TRUE; } return FALSE; } int char_is_vartail( char C ) { if( char_is_varnext( C ) ) { return TRUE; } if( char_is_vartype( C ) ) { return TRUE; } return FALSE; } int buff_peek_word( char *buffer, int * position, char * find ) { /* determine whether the next non-space word in 'buffer' is 'find'; the word 'find' is not a sub-string of a bigger word. if successful then returns TRUE otherwise returns FALSE. 'position' is unchanged. */ int p; int n; p = *position; buff_skip_spaces( buffer, &p ); if( buff_is_eol( buffer, &p ) ) { return FALSE; } n = bwb_strlen(find); if( bwb_strnicmp( &(buffer[p]), find, n) == 0 ) { if( p > 0 ) { if( char_is_varhead( buffer[p-1] ) ) { /* _TO */ return FALSE; } } if( char_is_vartail( buffer[p+n] ) ) { /* TO_ */ return FALSE; } return TRUE; } return FALSE; } int line_peek_word( LineType * line, char * find ) { return buff_peek_word( line->buffer, &(line->position), find ); } int buff_skip_word( char *buffer, int * position, char * find ) { /* skip the next non-space word in 'buffer' if it is 'find'; the word 'find' is not a sub-string of a bigger word. if successful then 'position' is updated past 'find' and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; int n; p = *position; buff_skip_spaces( buffer, &p ); if( buff_is_eol( buffer, &p ) ) { return FALSE; } n = bwb_strlen(find); if( bwb_strnicmp( &(buffer[p]), find, n) == 0 ) { if( p > 0 ) { if( char_is_varhead( buffer[p-1] ) ) { /* _TO */ return FALSE; } } if( char_is_vartail( buffer[p+n] ) ) { /* TO_ */ return FALSE; } p += n; *position = p; return TRUE; } return FALSE; } int line_skip_word( LineType * line, char * find ) { return buff_skip_word( line->buffer, &(line->position), find ); } int buff_read_varname( char *buffer, int * position, char * varname ) { /* read the next non-space word in 'buffer' that conforms to a BASIC variable name into 'varname'. if successful then 'position' is updated past 'varname' and returns TRUE otherwise 'position' is unchanged ('varname' is truncated) and returns FALSE. 'varname' shall be declared "char varname[BasicNameLengthMax + 1]". */ int p; p = *position; buff_skip_spaces( buffer, &p ); if( char_is_varfirst( buffer[p] ) ) { int i; i = 0; if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } varname[i] = buffer[p]; p++; i++; while (char_is_varnext(buffer[p])) { if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } varname[i] = buffer[p]; p++; i++; } if (char_is_vartype(buffer[p])) { if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } varname[i] = buffer[p]; p++; i++; } varname[i] = BasicNulChar; *position = p; return TRUE; } varname[0] = BasicNulChar; return FALSE; } int line_read_varname( LineType * line, char * varname ) { return buff_read_varname( line->buffer, &(line->position), varname ); } int buff_read_label( char * buffer, int * position, char * label ) { /* read the next non-space word in 'buffer' that conforms to a BASIC label name into 'label'. if successful then 'position' is updated past 'label' and returns TRUE otherwise 'position' is unchanged and returns FALSE. 'label' shall be declared "char label[BasicNameLengthMax + 1]". */ int p; p = *position; buff_skip_spaces( buffer, &p ); if( char_is_varfirst( buffer[p] ) ) { int i; i = 0; if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } label[i] = buffer[p]; p++; i++; while (char_is_varnext(buffer[p])) { if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } label[i] = buffer[p]; p++; i++; } label[i] = BasicNulChar; *position = p; return TRUE; } return FALSE; } int line_read_label( LineType * line, char * label ) { return buff_read_label( line->buffer, &(line->position), label ); } static int buff_read_keyword( char * buffer, int * position, char * keyword ) { /* read the next non-space word in 'buffer' that conforms to a BASIC keyword into 'keyword'. if successful then 'position' is updated past 'keyword' and returns TRUE otherwise 'position' is unchanged and returns FALSE. 'label' shall be declared "char keyword[BasicNameLengthMax + 1]". */ int p; p = *position; buff_skip_spaces( buffer, &p ); if( char_is_varfirst( buffer[p] ) ) { int i; i = 0; if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } keyword[i] = buffer[p]; p++; i++; while (char_is_varnext(buffer[p])) { if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } keyword[i] = buffer[p]; p++; i++; } if( buffer[p] == BasicStringSuffix ) { if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } keyword[i] = buffer[p]; p++; i++; } keyword[i] = BasicNulChar; *position = p; return TRUE; } keyword[0] = BasicNulChar; return FALSE; } VariableType * buff_read_scalar( char *buffer, int * position ) { /* read the next non-space word in 'buffer' that conforms to a BASIC variable name, including both scalar variables and subscripted array variables. if successful then 'position' is updated past 'varname' for scalar variables (past ')' for subscripted array variables). and returns a pointer to the variable. otherwise 'position' is unchanged and returns NULL. */ int p; VariableType *v; char varname[BasicNameLengthMax + 1]; p = *position; /* Read a variable name */ buff_skip_spaces( buffer, &p ); if( buff_read_varname(buffer, &p, varname) == FALSE ) { WARN_VARIABLE_NOT_DECLARED; return NULL; } if( buff_peek_char( buffer, &p, BasicLeftParenChar ) ) { /* MUST be a an array */ register int n; int n_params; /* number of parameters */ int pp[ MAX_DIMS ]; /* get parameters because the variable is dimensioned */ if( buff_read_array_dimensions(buffer, &p, &n_params, pp) == FALSE ) { WARN_SUBSCRIPT_OUT_OF_RANGE; return NULL; } /* get the array variable */ if( (v = var_find(varname,n_params,TRUE)) == NULL ) { WARN_VARIABLE_NOT_DECLARED; return NULL; } for (n = 0; n < v->dimensions; n++) { v->array_pos[n] = pp[n]; } } else { /* simple scalar variable */ if( (v = var_find(varname,0,TRUE)) == NULL ) { WARN_VARIABLE_NOT_DECLARED; return NULL; } } *position = p; return v; } VariableType * line_read_scalar( LineType * line ) { return buff_read_scalar( line->buffer, &(line->position) ); } VariableType * buff_read_matrix( char *buffer, int * position ) { /* read the next non-space word in 'buffer' that conforms to a BASIC matrix name, including both simple matrix variables and redimensioned matrix variables. if successful then 'position' is updated past 'varname' for matrix variables (past ')' for redimensioned matrix variables). and returns a pointer to the variable. otherwise 'position' is unchanged and returns NULL. */ int p; VariableType *v; char varname[BasicNameLengthMax + 1]; p = *position; /* Read a variable name */ buff_skip_spaces( buffer, &p ); if( buff_read_varname(buffer, &p, varname) == FALSE ) { WARN_SYNTAX_ERROR; return NULL; } buff_skip_spaces( buffer, &p ); v = mat_find( varname ); if( v == NULL) { WARN_VARIABLE_NOT_DECLARED; return NULL; } if (buff_peek_char(buffer, &p, BasicLeftParenChar)) { /* get requested matrix size, which is <= original matrix size */ size_t array_units; int n; int n_params; /* number of parameters */ int pp[ MAX_DIMS ]; for (n = 0; n < MAX_DIMS; n++) { pp[n] = 0; } if( buff_read_array_dimensions(buffer, &p, &n_params, pp) == FALSE ) { WARN_SYNTAX_ERROR; return NULL; } /* update array dimensions */ array_units = 1; for (n = 0; n < n_params; n++) { if( pp[n] < My->CurrentVersion->OptionBaseValue ) { WARN_SUBSCRIPT_OUT_OF_RANGE; return NULL; } array_units *= pp[n] - My->CurrentVersion->OptionBaseValue + 1; } if( array_units > v->array_units ) { WARN_SUBSCRIPT_OUT_OF_RANGE; return NULL; } v->dimensions = n_params; for (n = 0; n < v->dimensions; n++) { v->LBOUND[n] = My->CurrentVersion->OptionBaseValue; v->UBOUND[n] = pp[n]; } } *position = p; return v; } VariableType * line_read_matrix( LineType * line ) { return buff_read_matrix( line->buffer, &(line->position) ); } int buff_read_line_number( char * buffer, int * position, int * linenum ) { /* read the next non-space word in 'buffer' that conforms to a BASIC line number. if successful then 'position' is updated past 'linenum' and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; p = *position; buff_skip_spaces( buffer, &p ); if( bwb_isdigit( buffer[p] ) ) { int i; char label[BasicNameLengthMax + 1]; i = 0; while (bwb_isdigit(buffer[p])) { if( i > BasicNameLengthMax ) { i = BasicNameLengthMax; } label[i] = buffer[p]; p++; i++; } label[i] = BasicNulChar; *linenum = atoi( label ); *position = p; return TRUE; } return FALSE; } int line_read_line_number( LineType * line, int * linenum ) { return buff_read_line_number( line->buffer, &(line->position), linenum ); } int buff_read_line_sequence( char *buffer, int * position, int * head, int * tail ) { /* read the next non-space words in 'buffer' that conforms to a BASIC line number sequnence. if successful then 'position' is updated past the line number sequence and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ /* ### head == tail ### - head to BMAX ### - ### head to tail - ### BMIN to tail */ int p; int h; int t; p = *position; buff_skip_spaces( buffer, &p ); if( buff_skip_char( buffer, &p, '-' ) ) { /* - ... */ if( buff_read_line_number( buffer, &p, &t ) ) { /* - ### */ *head = BasicLineNumberMin; *tail = t; *position = p; return TRUE; } } else if( buff_read_line_number( buffer, &p, &h ) ) { /* ### ... */ if( buff_skip_char( buffer, &p, '-' ) ) { /* ### - ... */ if( buff_read_line_number( buffer, &p, &t ) ) { /* ### - ### */ *head = h; *tail = t; *position = p; return TRUE; } else { /* ### - */ *head = h; *tail = BasicLineNumberMax; *position = p; return TRUE; } } else { /* ### */ *head = h; *tail = h; *position = p; return TRUE; } } return FALSE; } int line_read_line_sequence( LineType * line, int * head, int * tail ) { return buff_read_line_sequence( line->buffer, &(line->position), head, tail ); } int buff_read_integer_expression( char * buffer, int * position, int * Value ) { /* read the next non-space words in 'buffer' that conforms to a BASIC integer expression into 'Value'. if successful then 'position' is updated past 'Value' and returns TRUE otherwise 'position' is unchanged and returns FALSE. 'Value' shall be declared "int Value". */ BasicNumberType X; int p; bwx_DEBUG(__FUNCTION__); p = *position; buff_skip_spaces( buffer, &p ); if( buff_read_numeric_expression( buffer, &p, &X ) ) { /* we want the rounded value */ X = bwb_rint( X ); if( INT_MIN <= X && X <= INT_MAX ) { /* OK */ *Value = (int) bwb_rint( X ); *position = p; return TRUE; } } /* ERROR */ if( My->MaintainerDebugOn ) { sprintf( My->bwb_ebuf, "%s, BUFFER:%s\n", __FUNCTION__, &( buffer[ p ] ) ); fputs( My->bwb_ebuf, My->SYSPRN->cfp ); } return FALSE; } int line_read_integer_expression( LineType * line, int * Value ) { return buff_read_integer_expression( line->buffer, &(line->position), Value ); } int buff_read_numeric_expression( char * buffer, int * position, BasicNumberType * Value ) { /* read the next non-space words in 'buffer' that conforms to a BASIC numeric expression into 'Value'. if successful then 'position' is updated past 'Value' and returns TRUE otherwise 'position' is unchanged and returns FALSE. 'Value' shall be declared "BasicNumberType Value". */ int p; VariantType x; VariantType * X = &x; p = *position; CLEAR_VARIANT( X ); buff_skip_spaces( buffer, &p ); if( buff_read_expression( buffer, &p, X ) == FALSE ) { return FALSE; } if( X->TypeChar != BasicStringSuffix ) { /* OK */ *Value = X->Number; *position = p; return TRUE; } RELEASE( X ); return FALSE; } int line_read_numeric_expression( LineType * line, BasicNumberType * Value ) { return buff_read_numeric_expression( line->buffer, &(line->position), Value ); } int buff_read_string_expression( char * buffer, int * position, char ** Value ) { /* read the next non-space words in 'buffer' that conforms to a BASIC string expression into 'Value'. if successful then 'position' is updated past 'Value' and returns TRUE otherwise 'position' is unchanged and returns FALSE. 'Value' shall be declared "char * Value = NULL". */ int p; VariantType x; VariantType * X = &x; p = *position; CLEAR_VARIANT( X ); buff_skip_spaces( buffer, &p ); if( buff_read_expression( buffer, &p, X ) == FALSE ) { return FALSE; } if( X->TypeChar == BasicStringSuffix ) { /* OK */ X->Buffer[ X->Length ] = BasicNulChar; *Value = X->Buffer; *position = p; return TRUE; } return FALSE; } int line_read_string_expression( LineType * line, char ** Value ) { return buff_read_string_expression( line->buffer, &(line->position), Value ); } int buff_read_index_item( char * buffer, int * position, int Index, int * Value ) { /* read the next non-space words in 'buffer' that conforms to a BASIC integer expression list into 'Value', selecting the item matching 'Index'. The first 'Index' value is one; if successful then 'position' is updated past 'Value' and returns TRUE otherwise 'position' is unchanged and returns FALSE. 'Value' shall be declared "int Value". */ int p; int i; p = *position; buff_skip_spaces( buffer, &p ); if( buff_is_eol( buffer, &p ) ) { return FALSE; } if( Index < 1 ) { return FALSE; } /* Index >= 1 */ i = 0; do { int v; if( buff_read_integer_expression( buffer, &p, &v ) ) { i++; if( i == Index ) { *Value = v; *position = p; return TRUE; } } else { return FALSE; } } while( buff_skip_comma( buffer, &p ) ); return FALSE; } int line_read_index_item( LineType * line, int Index, int * Value ) { return buff_read_index_item( line->buffer, &(line->position), Index, Value ); } int buff_read_element( char * buffer, int * position, char * element ) { /* read the next non-space word in 'buffer' that conforms to a BASIC element. if successful then 'position' is updated past the element and returns TRUE otherwise 'position' is unchanged and returns FALSE. 'element' shall be declared "char element[BasicStringLengthMax + 1]". */ int p; int i; p = *position; i = 0; buff_skip_spaces( buffer, &p ); if( buff_is_eol( buffer, &p ) ) { return FALSE; } while( TRUE ) { switch (buffer[p]) { case BasicNulChar: case ',': /* COMMA */ case ';': /* SEMICOLON */ case ':': /* COLON */ case '=': case ' ': /* element terminators */ element[i] = BasicNulChar; *position = p; return TRUE; /* break; */ case BasicQuoteChar: /* string constant */ if( i > 0 ) { /* terminates previous element */ element[i] = BasicNulChar; *position = p; return TRUE; } /* return the string constant */ if( i > BasicStringLengthMax ) { i = BasicStringLengthMax; } element[i] = buffer[p]; i++; p++; while( buffer[p] != BasicNulChar && buffer[p] != BasicQuoteChar ) { if( i > BasicStringLengthMax ) { i = BasicStringLengthMax; } element[i] = buffer[p]; i++; p++; } if( buffer[p] == BasicQuoteChar ) { p++; } if( i > BasicStringLengthMax ) { i = BasicStringLengthMax; } element[i] = BasicQuoteChar; i++; element[i] = BasicNulChar; *position = p; return TRUE; /* break; */ default: if( i > BasicStringLengthMax ) { i = BasicStringLengthMax; } element[i] = buffer[p]; i++; p++; break; } } /* return FALSE; */ /* never reached */ } int line_read_element( LineType * line, char * element ) { return buff_read_element( line->buffer, &(line->position), element ); } int buff_read_letter_sequence(char *buffer, int *position, char *start, char *end) { /* read the next non-space alphabetic character in 'buffer' into 'start'; if seperated by a '-' then read the next non-space alphabetic character into 'end'. if successful then 'position' is updated past 'start' (or 'end') and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; char s; char e; p = *position; buff_skip_spaces(buffer, &p); if ( ! bwb_isalpha(buffer[p]) ) { /* character at this position must be a letter */ return FALSE; } s = buffer[p]; p++; /* check for hyphen, indicating sequence of more than one letter */ if ( buff_skip_char( buffer, &p, '-') ) { buff_skip_spaces(buffer, &p); if ( ! bwb_isalpha(buffer[p]) ) { /* character at this position must be a letter */ return FALSE; } e = buffer[p]; p++; } else { e = s; } *start = s; *end = e; *position = p; return TRUE; } int line_read_letter_sequence( LineType * line, char *start, char *end) { return buff_read_letter_sequence( line->buffer, &(line->position), start, end ); } int buff_read_array_dimensions(char *buffer, int *position, int *n_params , int params[ /* MAX_DIMS */ ] ) { /* read the next non-space words in 'buffer' that conform to BASIC array index values; if successful then 'position' is updated past the ending ')' and returns TRUE otherwise 'position' is unchanged and returns FALSE. */ int p; int n; p = *position; n = 0; buff_skip_spaces(buffer, &p); if ( buff_skip_char( buffer, &p, BasicLeftParenChar) ) { /* matrix */ do { int Value; if( n < MAX_DIMS ) { /* OK */ if( buff_read_integer_expression( buffer, &p, &Value) ) { params[n] = Value; n++; } else { return FALSE; } } else { /* ERROR */ return FALSE; } } while( buff_skip_comma( buffer, &p ) ); if ( buff_skip_char( buffer, &p, BasicRightParenChar) == FALSE ) { /* ERROR */ return FALSE; } } else { /* scalar */ n = 0; } *n_params = n; *position = p; return TRUE; } int line_read_array_dimensions( LineType * line, int *n_params , int params[ /* MAX_DIMS */ ] ) { return buff_read_array_dimensions(line->buffer, &(line->position), n_params , params ); } int buff_peek_array_dimensions(char *buffer, int *position, int *n_params ) { /* peek the next non-space words in 'buffer' that conform to BASIC array index values; if successful then 'n_params' is updated and returns TRUE otherwise 'n_params' is unchanged and returns FALSE. 'position' is always unchanged. */ int p; int ParenLevel = 0; int NumDimensions = 1; p = *position; buff_skip_spaces( buffer, &p ); while( buffer[p] != BasicNulChar ) { /* check the current character */ buff_skip_spaces( buffer, &p ); if ( buff_skip_char( buffer, &p, BasicLeftParenChar) ) { ParenLevel++; } else if ( buff_skip_char( buffer, &p, BasicRightParenChar) ) { ParenLevel--; if (ParenLevel < 0) { return FALSE; } if (ParenLevel == 0) { *n_params = NumDimensions; return TRUE; } } else if ( buff_skip_comma( buffer, &p) ) { if (ParenLevel == 1) { NumDimensions++; } } else if( buffer[p] == BasicQuoteChar ) { /* embedded string constant */ p++; while ((buffer[p] != BasicQuoteChar) && (buffer[p] != BasicNulChar)) { p++; } if (buffer[p] == BasicQuoteChar) { p++; } } else { /* normal character */ p++; } } return FALSE; } int line_peek_array_dimensions( LineType * line, int *n_params ) { return buff_peek_array_dimensions(line->buffer, &(line->position), n_params ); } char buff_read_type_declaration( char *buffer, int * position ) { /* skip the next non-space words in 'buffer' if it is a BASIC type declaration. if successful then 'position' is updated past the BASIC type declaration and returns the TypeChar otherwise 'position' is unchanged and returns BasicNulChar. */ int p; char TypeChar; p = *position; TypeChar = BasicNulChar; buff_skip_spaces( buffer, &p ); if( buff_is_eol( buffer, &p ) ) { return FALSE; } if( buff_skip_word(buffer, &p, "AS") == TRUE ) { /* AS ... */ if( buff_skip_word(buffer, &p, "STRING" ) ) { /* AS STRING */ TypeChar = BasicStringSuffix; } else if( buff_skip_word(buffer, &p, "DOUBLE" ) ) { /* AS DOUBLE */ TypeChar = BasicDoubleSuffix; } else if( buff_skip_word(buffer, &p, "SINGLE" ) ) { /* AS SINGLE */ TypeChar = BasicSingleSuffix; } else if( buff_skip_word(buffer, &p, "CURRENCY" ) ) { /* AS CURRENCY */ TypeChar = BasicCurrencySuffix; } else if( buff_skip_word(buffer, &p, "LONG" ) ) { /* AS LONG */ TypeChar = BasicLongSuffix; } else if( buff_skip_word(buffer, &p, "INTEGER" ) ) { /* AS INTEGER */ TypeChar = BasicIntegerSuffix; } else if( buff_skip_word(buffer, &p, "BYTE" ) ) { /* AS BYTE */ TypeChar = BasicByteSuffix; } else { /* invalid type */ } } if( TypeChar != BasicNulChar ) { /* success */ *position = p; } return TypeChar; } char line_read_type_declaration( LineType * line ) { return buff_read_type_declaration(line->buffer, &(line->position) ); } /*************************************************************** FUNCTION: line_start() DESCRIPTION: This function reads a line buffer in beginning at the position and attempts to determine (a) the position of the line number in the buffer (returned in ), (b) the line number at this position (returned in ), (c) the position of the BASIC command in the buffer (returned in ), (d) the position of this BASIC command in the command table (returned in ), and (e) the position of the beginning of the rest of the line (returned in ). Although must be returned as a positive integer, the other searches may fail, in which case FALSE will be returned in their positions. is not incremented. ***************************************************************/ int line_start(LineType * l) { int position; char tbuf[BasicNameLengthMax + 1]; bwx_DEBUG(__FUNCTION__); /* set initial values */ l->Startpos = 0; l->cmdnum = 0; /* not found */ position = 0; buff_skip_spaces(l->buffer, &position); /* handle special cases */ if (l->buffer[position] == BasicNulChar) { /* the NUL (0) char must be handled first */ l->cmdnum = C_REM; return TRUE; } if (l->buffer[position] == My->CurrentVersion->OptionCommentChar) { l->cmdnum = C_REM; buff_skip_eol(l->buffer, &(position)); l->Startpos = position; return TRUE; } if (l->buffer[position] == My->CurrentVersion->OptionPrintChar) { l->cmdnum = C_PRINT; l->Startpos = position; /* skip past '?' */ l->Startpos++; return TRUE; } if (l->buffer[position] == My->CurrentVersion->OptionImageChar) { l->cmdnum = C_IMAGE; l->Startpos = position; /* skip past ':' */ l->Startpos++; return TRUE; } if (bwb_strnicmp(&l->buffer[position], "REM", 3) == 0) { l->cmdnum = C_REM; buff_skip_eol(l->buffer, &(position)); l->Startpos = position; return TRUE; } /* not a SPECIAL */ /* get the first keyword */ if( buff_read_keyword(l->buffer, &position, tbuf) == FALSE ) { /* ERROR */ return FALSE; } buff_skip_spaces(l->buffer, &position); /* check for COMMAND */ if ((l->cmdnum = is_cmd(tbuf)) > 0) { /* it is a COMMAND */ /* * NOTE: This is NOT a full parser, this exists only to * handle STRUCTURED commands. It is true that we also handle * some other easy cases, but remember that this only exists * to support STRUCTURED commands. Whether any other commands * get processed here is simply because it was easy to do so. */ int cmdnum = 0; #define MAX_COMMAND_LENGTH 63 char xbuf[ MAX_COMMAND_LENGTH + 1 /* NUL */ ]; /* ON ERROR RESUME NEXT */ bwb_strcpy( xbuf, tbuf ); do { cmdnum = 0; buff_skip_spaces(l->buffer, &position); l->Startpos = position; if( buff_read_keyword(l->buffer, &position, tbuf) ) { int n; n = bwb_strlen( xbuf ) + 1 + bwb_strlen( tbuf ); if( n < MAX_COMMAND_LENGTH ) { /* not too long */ bwb_strcat( xbuf, " " ); bwb_strcat( xbuf, tbuf ); cmdnum = is_cmd( xbuf ); if( cmdnum > 0 ) { /* longer command is valid */ buff_skip_spaces(l->buffer, &position); l->cmdnum = cmdnum; l->Startpos = position; } } } } while( cmdnum > 0 ); /* process special cases here */ switch (l->cmdnum) { case C_CLOAD: { position = l->Startpos; if( buff_skip_char(l->buffer, &position, '*' ) ) { /* CLOAD* */ buff_skip_spaces(l->buffer, &position); l->cmdnum = C_CLOAD8; l->Startpos = position; } } break; case C_CSAVE: { position = l->Startpos; if( buff_skip_char(l->buffer, &position, '*' ) ) { /* CSAVE* */ buff_skip_spaces(l->buffer, &position); l->cmdnum = C_CSAVE8; l->Startpos = position; } } break; case C_DEF: if( bwb_strchr( l->buffer, '=' ) == NULL ) { /* multi-line DEF ... FNEND */ l->cmdnum = C_FUNCTION; } fslt_add(l); break; case C_FEND: l->cmdnum = C_END_FUNCTION; break; case C_FNEND: l->cmdnum = C_END_FUNCTION; break; case C_FUNCTION: fslt_add(l); break; case C_IF: if( IsLastKeyword( l, " THEN" ) ) { /* STRUCTURED */ l->cmdnum = C_IF_THEN; } break; case C_OPEN: { if( My->CurrentVersion->OptionVersionBitmask & ( I70 | I73 ) ) { /* OPEN filenum, filename$, INPUT | OUTPUT */ } else if (GetKeyword(l, NULL, " AS ")) { /* STRUCTURED */ } else { /* CLASSIC */ l->cmdnum = C_DEF_SUB; l->Startpos = 0; } } break; case C_SUB: fslt_add(l); break; case C_SUBEND: l->cmdnum = C_END_SUB; break; case C_USER_LBL: fslt_add(l); break; } /* done */ return TRUE; #if FALSE if (l->cmdnum == C_CASE) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "ELSE") == 0) { l->cmdnum = C_CASE_ELSE; l->Startpos = position; } else { /* CASE ... */ /* CASE IF ... */ /* CASE IS ... */ } } else if (l->cmdnum == C_CLOAD) { position = l->Startpos; if( buff_skip_char(l->buffer, &position, '*' ) ) { /* CLOAD* */ buff_skip_spaces(l->buffer, &position); l->cmdnum = C_CLOAD8; l->Startpos = position; } else { /* CLOAD ... */ } } else if (l->cmdnum == C_CSAVE) { position = l->Startpos; if( buff_skip_char(l->buffer, &position, '*' ) ) { /* CSAVE* */ buff_skip_spaces(l->buffer, &position); l->cmdnum = C_CSAVE8; l->Startpos = position; } else { /* CSAVE ... */ } } else if (l->cmdnum == C_DEF) { if(bwb_strchr(l->buffer,'=') == NULL) { /* multi-line DEF ... FNEND */ l->cmdnum = C_FUNCTION; l->Startpos = position; } else { /* single line DEF */ } } else if (l->cmdnum == C_FNEND) { l->cmdnum = C_END_FUNCTION; } else if (l->cmdnum == C_FEND) { l->cmdnum = C_END_FUNCTION; } else if (l->cmdnum == C_END) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "FUNCTION") == 0) { l->cmdnum = C_END_FUNCTION; l->Startpos = position; } else if (bwb_stricmp(tbuf, "IF") == 0) { l->cmdnum = C_END_IF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "SELECT") == 0) { l->cmdnum = C_END_SELECT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "SUB") == 0) { l->cmdnum = C_END_SUB; l->Startpos = position; } else { /* plain END */ } } else if (l->cmdnum == C_EXIT) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "DO") == 0) { l->cmdnum = C_EXIT_DO; l->Startpos = position; } else if (bwb_stricmp(tbuf, "FOR") == 0) { l->cmdnum = C_EXIT_FOR; l->Startpos = position; } else if (bwb_stricmp(tbuf, "FUNCTION") == 0) { l->cmdnum = C_EXIT_FUNCTION; l->Startpos = position; } else if (bwb_stricmp(tbuf, "SUB") == 0) { l->cmdnum = C_EXIT_SUB; l->Startpos = position; } else if (bwb_stricmp(tbuf, "UNTIL") == 0) { l->cmdnum = C_EXIT_UNTIL; l->Startpos = position; } else if (bwb_stricmp(tbuf, "WHILE") == 0) { l->cmdnum = C_EXIT_WHILE; l->Startpos = position; } else { /* EXIT line */ } } else if (l->cmdnum == C_GO) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "SUB") == 0) { l->cmdnum = C_GOSUB; l->Startpos = position; } else if (bwb_stricmp(tbuf, "TO") == 0) { l->cmdnum = C_GOTO; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (l->cmdnum == C_IF) { if (IsLastKeyword(l, " THEN") == TRUE) { /* STRUCTURED */ l->cmdnum = C_IF_THEN; } else { /* CLASSIC */ position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "END") == 0) { /* IF END # X THEN ... */ l->cmdnum = C_IF_END; l->Startpos = position; } else if (bwb_stricmp(tbuf, "MORE") == 0) { /* IF MORE # X THEN ... */ l->cmdnum = C_IF_MORE; l->Startpos = position; } else { /* normal */ } } } else if (l->cmdnum == C_MAT) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "GET") == 0) { l->cmdnum = C_MAT_GET; l->Startpos = position; } else if (bwb_stricmp(tbuf, "INPUT") == 0) { l->cmdnum = C_MAT_INPUT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "PRINT") == 0) { l->cmdnum = C_MAT_PRINT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "PUT") == 0) { l->cmdnum = C_MAT_PUT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "READ") == 0) { l->cmdnum = C_MAT_READ; l->Startpos = position; } else if (bwb_stricmp(tbuf, "WRITE") == 0) { l->cmdnum = C_MAT_WRITE; l->Startpos = position; } else { /* plain MAT */ } } else if (l->cmdnum == C_ON) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "ERROR") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "GOTO") == 0) { l->cmdnum = C_ON_ERROR_GOTO; l->Startpos = position; } else if (bwb_stricmp(tbuf, "GOSUB") == 0) { l->cmdnum = C_ON_ERROR_GOSUB; l->Startpos = position; } else if (bwb_stricmp(tbuf, "RESUME") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "NEXT") == 0) { l->cmdnum = C_ON_ERROR_RESUME_NEXT; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "RETURN") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "NEXT") == 0) { l->cmdnum = C_ON_ERROR_RETURN_NEXT; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "TIMER") == 0) { l->cmdnum = C_ON_TIMER; l->Startpos = position; } else { /* ON ... GO ... */ } } else if (l->cmdnum == C_OPEN) { if( My->CurrentVersion->OptionVersionBitmask & ( I70 | I73 ) ) { /* OPEN filenum, filename$, INPUT | OUTPUT */ } else if (GetKeyword(l, NULL, " AS ")) { /* STRUCTURED */ } else { /* CLASSIC */ l->cmdnum = C_DEF_SUB; l->Startpos = 0; } } else if (l->cmdnum == C_OPTION) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "ANGLE") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "DEGREES") == 0) { l->cmdnum = C_OPTION_ANGLE_DEGREES; l->Startpos = position; } else if (bwb_stricmp(tbuf, "GRADIANS") == 0) { l->cmdnum = C_OPTION_ANGLE_GRADIANS; l->Startpos = position; } else if (bwb_stricmp(tbuf, "RADIANS") == 0) { l->cmdnum = C_OPTION_ANGLE_RADIANS; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "ARITHMETIC") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "DECIMAL") == 0) { l->cmdnum = C_OPTION_ARITHMETIC_DECIMAL; l->Startpos = position; } else if (bwb_stricmp(tbuf, "FIXED") == 0) { l->cmdnum = C_OPTION_ARITHMETIC_FIXED; l->Startpos = position; } else if (bwb_stricmp(tbuf, "NATIVE") == 0) { l->cmdnum = C_OPTION_ARITHMETIC_NATIVE; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "BASE") == 0) { l->cmdnum = C_OPTION_BASE; l->Startpos = position; } else if (bwb_stricmp(tbuf, "BUGS") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "OFF") == 0) { l->cmdnum = C_OPTION_BUGS_OFF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ON") == 0) { l->cmdnum = C_OPTION_BUGS_ON; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "COMMENT") == 0) { l->cmdnum = C_OPTION_COMMENT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "COMPARE") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "BINARY") == 0) { l->cmdnum = C_OPTION_COMPARE_BINARY; l->Startpos = position; } else if (bwb_stricmp(tbuf, "DATABASE") == 0) { l->cmdnum = C_OPTION_COMPARE_DATABASE; l->Startpos = position; } else if (bwb_stricmp(tbuf, "TEXT") == 0) { l->cmdnum = C_OPTION_COMPARE_TEXT; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "COVERAGE") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "OFF") == 0) { l->cmdnum = C_OPTION_COVERAGE_OFF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ON") == 0) { l->cmdnum = C_OPTION_COVERAGE_ON; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "DATE") == 0) { l->cmdnum = C_OPTION_DATE; l->Startpos = position; } else if (bwb_stricmp(tbuf, "DISABLE") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "COMMAND") == 0) { l->cmdnum = C_OPTION_DISABLE_COMMAND; l->Startpos = position; } else if (bwb_stricmp(tbuf, "FUNCTION") == 0) { l->cmdnum = C_OPTION_DISABLE_FUNCTION; l->Startpos = position; } else if (bwb_stricmp(tbuf, "OPERATOR") == 0) { l->cmdnum = C_OPTION_DISABLE_OPERATOR; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "ENABLE") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "COMMAND") == 0) { l->cmdnum = C_OPTION_ENABLE_COMMAND; l->Startpos = position; } else if (bwb_stricmp(tbuf, "FUNCTION") == 0) { l->cmdnum = C_OPTION_ENABLE_FUNCTION; l->Startpos = position; } else if (bwb_stricmp(tbuf, "OPERATOR") == 0) { l->cmdnum = C_OPTION_ENABLE_OPERATOR; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "ERROR") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "GOSUB") == 0) { l->cmdnum = C_OPTION_ERROR_GOSUB; l->Startpos = position; } else if (bwb_stricmp(tbuf, "GOTO") == 0) { l->cmdnum = C_OPTION_ERROR_GOTO; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "EXPLICIT") == 0) { l->cmdnum = C_OPTION_EXPLICIT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "IMAGE") == 0) { l->cmdnum = C_OPTION_IMAGE; l->Startpos = position; } else if (bwb_stricmp(tbuf, "IMPLICIT") == 0) { l->cmdnum = C_OPTION_IMPLICIT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "INDENT") == 0) { l->cmdnum = C_OPTION_INDENT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "LABELS") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "OFF") == 0) { l->cmdnum = C_OPTION_LABELS_OFF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ON") == 0) { l->cmdnum = C_OPTION_LABELS_ON; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "PRINT") == 0) { l->cmdnum = C_OPTION_PRINT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ROUND") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "BANK") == 0) { l->cmdnum = C_OPTION_ROUND_BANK; l->Startpos = position; } else if (bwb_stricmp(tbuf, "MATH") == 0) { l->cmdnum = C_OPTION_ROUND_MATH; l->Startpos = position; } else if (bwb_stricmp(tbuf, "TRUNCATE") == 0) { l->cmdnum = C_OPTION_ROUND_TRUNCATE; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "SLEEP") == 0) { l->cmdnum = C_OPTION_SLEEP; l->Startpos = position; } else if (bwb_stricmp(tbuf, "STATEMENT") == 0) { l->cmdnum = C_OPTION_STATEMENT; l->Startpos = position; } else if (bwb_stricmp(tbuf, "STRICT") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "OFF") == 0) { l->cmdnum = C_OPTION_STRICT_OFF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ON") == 0) { l->cmdnum = C_OPTION_STRICT_ON; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "TERMINAL") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "NONE") == 0) { l->cmdnum = C_OPTION_TERMINAL_NONE; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ADM-3A") == 0) { l->cmdnum = C_OPTION_TERMINAL_ADM; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ANSI") == 0) { l->cmdnum = C_OPTION_TERMINAL_ANSI; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "TIME") == 0) { l->cmdnum = C_OPTION_TIME; l->Startpos = position; } else if (bwb_stricmp(tbuf, "TRACE") == 0) { buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "OFF") == 0) { l->cmdnum = C_OPTION_TRACE_OFF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ON") == 0) { l->cmdnum = C_OPTION_TRACE_ON; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (bwb_stricmp(tbuf, "VERSION") == 0) { l->cmdnum = C_OPTION_VERSION; l->Startpos = position; } else if (bwb_stricmp(tbuf, "USING") == 0) { l->cmdnum = C_OPTION_USING; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (l->cmdnum == C_SELECT) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "CASE") == 0) { l->cmdnum = C_SELECT_CASE; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (l->cmdnum == C_SUBEND) { l->cmdnum = C_END_SUB; } else if (l->cmdnum == C_TIMER) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "OFF") == 0) { l->cmdnum = C_TIMER_OFF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ON") == 0) { l->cmdnum = C_TIMER_ON; l->Startpos = position; } else if (bwb_stricmp(tbuf, "STOP") == 0) { l->cmdnum = C_TIMER_STOP; l->Startpos = position; } else { /* syntax error */ l->cmdnum = 0; } } else if (l->cmdnum == C_TRACE) { position = l->Startpos; buff_read_keyword(l->buffer, &position, tbuf); buff_skip_spaces(l->buffer, &position); if (bwb_stricmp(tbuf, "OFF") == 0) { l->cmdnum = C_TRACE_OFF; l->Startpos = position; } else if (bwb_stricmp(tbuf, "ON") == 0) { l->cmdnum = C_TRACE_ON; l->Startpos = position; } else { /* plain TRACE */ } } /* check for a bogus assignment to a command */ /* 100 PRINT = X */ if (l->cmdnum == 0) { /* syntax error */ return FALSE; } /* add to the Function-Sub-Label list */ switch (l->cmdnum) { case C_DEF: case C_FUNCTION: case C_SUB: case C_USER_LBL: fslt_add(l); break; } /* done */ return TRUE; #endif } /* not a COMMAND */ /* check for implied LET */ if (is_let(l->buffer) == TRUE) { /* this is an implied LET */ /* 100 A = 123 */ l->cmdnum = C_LET; /* bwb_LET */ l->Startpos = 0; return TRUE; } /* not an implied LET */ /* check for FUNCTION */ if (fnc_find(tbuf) != NULL) { /* check for a bogus assignment to a function */ /* 100 COS = X */ if( buff_peek_char(l->buffer, &position, '=' ) ) { /* syntax error */ l->cmdnum = 0; return FALSE; } /* user is executing a function, such as 100 COS X */ l->cmdnum = C_DEF_SUB; /* bwb_DEF_SUB, in bwb_tbl.c */ l->Startpos = 0; return TRUE; } /* not a FUNCTION */ /* check for LABEL */ if (My->CurrentVersion->OptionFlags & OPTION_LABELS_ON) { /* labels are enabled */ if( My->CurrentVersion->OptionStatementChar != BasicNulChar ) { /* a Statement seperator exists */ if( buff_skip_char(l->buffer, &position, My->CurrentVersion->OptionStatementChar) ) { /* this is a label */ /* 100 MyLabel: */ l->cmdnum = C_USER_LBL; /* bwb_USER_LBL */ buff_skip_spaces(l->buffer, &position); l->Startpos = position; return TRUE; } } } /* not a LABEL */ /* ERROR */ return FALSE; } /*************************************************************** FUNCTION: is_cmd() DESCRIPTION: This function determines whether the string in 'buffer' is a BASIC command statement, returning 'id' or 0. ***************************************************************/ int is_cmd(char *buffer) { #if THE_PRICE_IS_RIGHT char C; bwx_DEBUG(__FUNCTION__); #if FALSE printf( "check [%s]\n", buffer ); /* HWULF */ #endif C = buffer[0]; if( bwb_isalpha( C ) ) { /* start with the closest command, without going over */ int n; n = My->CommandStart[ VarTypeIndex( C ) ]; /* first command starting with this letter, assigned in SortAllCommands() */ if( n < 0 ) { /* NOT FOUND */ return 0; } for( ; n < NUM_COMMANDS; n++ ) { if (My->CurrentVersion->OptionVersionBitmask & bwb_cmdtable[n].OptionVersionBitmask) { int result; result = bwb_stricmp(bwb_cmdtable[n].name, buffer); if( result == 0 ) { /* FOUND */ #if FALSE printf( "found [%s]\n", buffer ); /* HWULF */ #endif return bwb_cmdtable[n].id; } if( result > 0 /* found > searched */ ) { /* NOT FOUND */ return 0; } } } } /* NOT FOUND */ return 0; #else register int n; bwx_DEBUG(__FUNCTION__); /* Go through the command table and search for a match. */ for (n = 0; n < NUM_COMMANDS; ++n) { if (My->CurrentVersion->OptionVersionBitmask & bwb_cmdtable[n].OptionVersionBitmask) if (bwb_stricmp(bwb_cmdtable[n].name, buffer) == 0) { return bwb_cmdtable[n].id; } } /* No command name was found */ return 0; #endif } /*************************************************************** FUNCTION: is_let() DESCRIPTION: This function tries to determine if the expression in is a LET statement without the LET command specified. ***************************************************************/ int is_let(char *buffer) { register int n; bwx_DEBUG(__FUNCTION__); /* Go through the expression and search for an unquoted assignment operator. */ for (n = 0; buffer[n] != BasicNulChar; ++n) { switch (buffer[n]) { case BasicQuoteChar: /* string constant */ ++n; while (buffer[n] != BasicQuoteChar) { ++n; if (buffer[n] == BasicNulChar) { WARN_SYNTAX_ERROR; return FALSE; } } ++n; break; case '=': return TRUE; } } /* No command name was found */ return FALSE; } /*************************************************************** FUNCTION: bwb_stripcr() DESCRIPTION: This function strips the carriage return or line-feed from the end of a string. ***************************************************************/ int bwb_stripcr(char *s) { char *E; bwx_DEBUG(__FUNCTION__); E = bwb_strchr(s, '\r'); if( E != NULL ) { *E = BasicNulChar; } E = bwb_strchr(s, '\n'); if( E != NULL ) { *E = BasicNulChar; } while (*s) { if ( ! bwb_isprint( *s ) ) { *s = ' '; } s++; } return TRUE; } /*************************************************************** FUNCTION: is_numconst() DESCRIPTION: This function reads the string in and returns TRUE if it is a numerical constant and FALSE if it is not. At this point, only decimal (base 10) constants are detected. ***************************************************************/ int is_numconst(char *buffer) { char *p; bwx_DEBUG(__FUNCTION__); /* Return FALSE for empty buffer */ if (buffer[0] == BasicNulChar) { return FALSE; } /* else check digits */ p = buffer; while (*p != BasicNulChar) { switch (*p) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: return FALSE; } ++p; } /* only numerical characters detected */ return TRUE; } /*************************************************************** FUNCTION: bwb_freeline() DESCRIPTION: This function frees memory associated with a program line in memory. ***************************************************************/ int bwb_freeline(LineType * l) { bwx_DEBUG(__FUNCTION__); /* free arguments if there are any */ /* Revised to FREE pass-thru calls by JBV */ if (l->buffer != NULL) { FREE(l->buffer, "bwb_freeline"); l->buffer = NULL; /* JBV */ } FREE(l, "bwb_freeline"); /* l = NULL; *//* Assignment of function parameter has no effect * outside the function. */ return TRUE; } #if FALSE /*************************************************************** FUNCTION: is_eol() DESCRIPTION: This function determines whether the buffer is at the end of a line. ***************************************************************/ int is_eol(char *buffer, int *position) { char c; bwx_DEBUG(__FUNCTION__); buff_skip_spaces(buffer, position); c = buffer[*position]; if (c == BasicNulChar || c == My->CurrentVersion->OptionCommentChar) { return TRUE; } return FALSE; } char * GetRestOfLine(LineType * l, char *OutputBuffer) { char *S; char *C; bwx_DEBUG(__FUNCTION__); S = l->buffer; S += l->position; C = S; while (*C != BasicNulChar && *C != My->CurrentVersion->OptionCommentChar) { C++; } /* FOUND */ if (OutputBuffer != NULL) { char c; c = *C; *C = BasicNulChar; l->position += bwb_strlen(S); bwb_strcpy(OutputBuffer, S); *C = c; } return C; } #endif /* FALSE */ char * GetKeyword(LineType * l, char *OutputBuffer, char *Keyword) { /* if OutputBuffer is NULL then we just want to know if a keyword * exists, and if so where to look after the keyword. this is used by * line_start() in bwb_int.c to determine various command flavors. * else we want to extract the expression before the keyword and * update the position to after the keyword. this is used by various * bwb_XXX() when executing BASIC commands. end if * * if FOUND then if OutputBuffer != NULL then copy line's buffer BEFORE * keyword into OutputBuffer update line's position to AFTER keyword * end if return pointer AFTER keyword else return NULL end if */ char *S; char *C; int n; bwx_DEBUG(__FUNCTION__); S = l->buffer; S += l->position; C = S; n = bwb_strlen(Keyword); while (*C != BasicNulChar && *C != My->CurrentVersion->OptionCommentChar) { if (bwb_strnicmp(C, Keyword, n) == 0) { /* FOUND */ char c; c = *C; *C = BasicNulChar; if (OutputBuffer != NULL) { l->position += bwb_strlen(S); l->position += n; bwb_strcpy(OutputBuffer, S); } *C = c; C += n; return C; } else if (*C == BasicQuoteChar) { /* skip string constant */ C++; while (*C != BasicNulChar && *C != BasicQuoteChar) { C++; } if (*C == BasicQuoteChar) { C++; } } else { /* skip normal character */ C++; } } /* NOT FOUND */ return NULL; } int IsLastKeyword(LineType * l, char *Keyword) { /* find the end of the line ( 0 or ' ) */ /* backup thru spaces */ int n; char *S; char *C; bwx_DEBUG(__FUNCTION__); S = l->buffer; S += l->position; C = S; n = bwb_strlen(Keyword); S += n; /* IF x THEN0 IF x THEN'0 IF x THEN ' 0 */ while (*C != BasicNulChar && *C != My->CurrentVersion->OptionCommentChar) { /* skip string constants */ if( *C == BasicQuoteChar ) { /* skip leading quote */ C++; while (*C != BasicNulChar && *C != BasicQuoteChar) { C++; } /* skip trailing quote */ if( *C == BasicQuoteChar ) { C++; } } else { C++; } } if (C > S) { C--; while (C > S && *C == ' ') { C--; } C++; if (C > S) { C -= n; if (bwb_strnicmp(C, Keyword, n) == 0) { /* FOUND */ return TRUE; } } } /* NOT FOUND */ return FALSE; } int bwb_isalnum( int C ) { /* 4.3.1.1 The isalnum function Synopsis #include int isalnum(int c); Description The isalnum function tests for any character for which isalpha or isdigit is true. */ switch( C ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': return TRUE; } return FALSE; } int bwb_isalpha( int C ) { /* 4.3.1.2 The isalpha function Synopsis #include int isalpha(int c); Description The isalpha function tests for any character for which isupper or islower is true, or any of an implementation-defined set of characters for which none of iscntrl , isdigit , ispunct , or isspace is true. In the C locale, isalpha returns true only for the characters for which isupper or islower is true. */ switch( C ) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': return TRUE; } return FALSE; } int bwb_iscntrl( int C ) { /* 4.3.1.3 The iscntrl function Synopsis #include int iscntrl(int c); Description The iscntrl function tests for any control character. */ switch( C ) { case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': return FALSE; } return TRUE; } int bwb_isdigit( int C ) { /* 4.3.1.4 The isdigit function Synopsis #include int isdigit(int c); Description The isdigit function tests for any decimal-digit character (as defined in $2.2.1). */ switch( C ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return TRUE; } return FALSE; } int bwb_isgraph( int C ) { /* 4.3.1.5 The isgraph function Synopsis #include int isgraph(int c); Description The isgraph function tests for any printing character except space (' '). */ switch( C ) { case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': return TRUE; } return FALSE; } int bwb_islower( int C ) { /* 4.3.1.6 The islower function Synopsis #include int islower(int c); Description The islower function tests for any lower-case letter or any of an implementation-defined set of characters for which none of iscntrl , isdigit , ispunct , or isspace is true. In the C locale, islower returns true only for the characters defined as lower-case letters (as defined in $2.2.1). */ switch( C ) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': return TRUE; } return FALSE; } int bwb_isprint( int C ) { /* 4.3.1.7 The isprint function Synopsis #include int isprint(int c); Description The isprint function tests for any printing character including space (' '). */ switch( C ) { case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': return TRUE; } return FALSE; } int bwb_ispunct( int C ) { /* 4.3.1.8 The ispunct function Synopsis #include int ispunct(int c); Description The ispunct function tests for any printing character except space (' ') or a character for which isalnum is true. */ switch( C ) { case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\\': case ']': case '^': case '_': case '`': case '{': case '|': case '}': case '~': return TRUE; } return FALSE; } int bwb_isspace( int C ) { /* 4.3.1.9 The isspace function Synopsis #include int isspace(int c); Description The isspace function tests for the standard white-space characters or for any of an implementation-defined set of characters for which isalnum is false. The standard white-space characters are the following: space (' '), form feed ('\f'), new-line ('\n'), carriage return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). In the C locale, isspace returns true only for the standard white-space characters. */ switch( C ) { case '\f': case '\n': case '\r': case '\t': case '\v': case ' ': return TRUE; } return FALSE; } int bwb_isupper( int C ) { /* 4.3.1.10 The isupper function Synopsis #include int isupper(int c); Description The isupper function tests for any upper-case letter or any of an implementation-defined set of characters for which none of iscntrl , isdigit , ispunct , or isspace is true. In the C locale, isupper returns true only for the characters defined as upper-case letters (as defined in $2.2.1). */ switch( C ) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': return TRUE; } return FALSE; } int bwb_isxdigit( int C ) { /* 4.3.1.11 The isxdigit function Synopsis #include int isxdigit(int c); Description The isxdigit function tests for any hexadecimal-digit character (as defined in $3.1.3.2). */ switch( C ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return TRUE; } return FALSE; } int bwb_tolower( int C ) { /* 4.3.2.1 The tolower function Synopsis #include int tolower(int c); Description The tolower function converts an upper-case letter to the corresponding lower-case letter. Returns If the argument is an upper-case letter, the tolower function returns the corresponding lower-case letter if there is one; otherwise the argument is returned unchanged. In the C locale, tolower maps only the characters for which isupper is true to the corresponding characters for which islower is true. */ switch( C ) { case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c'; case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f'; case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i'; case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l'; case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o'; case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; case 'Y': return 'y'; case 'Z': return 'z'; } return C; } int bwb_toupper( int C ) { /* 4.3.2.2 The toupper function Synopsis #include int toupper(int c); Description The toupper function converts a lower-case letter to the corresponding upper-case letter. Returns If the argument is a lower-case letter, the toupper function returns the corresponding upper-case letter if there is one; otherwise the argument is returned unchanged. In the C locale, toupper maps only the characters for which islower is true to the corresponding characters for which isupper is true. */ switch( C ) { case 'a': return 'A'; case 'b': return 'B'; case 'c': return 'C'; case 'd': return 'D'; case 'e': return 'E'; case 'f': return 'F'; case 'g': return 'G'; case 'h': return 'H'; case 'i': return 'I'; case 'j': return 'J'; case 'k': return 'K'; case 'l': return 'L'; case 'm': return 'M'; case 'n': return 'N'; case 'o': return 'O'; case 'p': return 'P'; case 'q': return 'Q'; case 'r': return 'R'; case 's': return 'S'; case 't': return 'T'; case 'u': return 'U'; case 'v': return 'V'; case 'w': return 'W'; case 'x': return 'X'; case 'y': return 'Y'; case 'z': return 'Z'; } return C; } void * bwb_memcpy(void *s1, const void *s2, size_t n) { /* 4.11.2.1 The memcpy function Synopsis #include void *memcpy(void *s1, const void *s2, size_t n); Description The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1 . If copying takes place between objects that overlap, the behavior is undefined. Returns The memcpy function returns the value of s1 . */ if( n > 0 ) { char * Target; char * Source; int p; Target = (char *) s1; Source = (char *) s2; p = 0; while( p < n ) { Target[p] = Source[p]; p++; } } return s1; } void * bwb_memmove(void *s1, const void *s2, size_t n) { /* 4.11.2.2 The memmove function Synopsis #include void *memmove(void *s1, const void *s2, size_t n); Description The memmove function copies n characters from the object pointed to by s2 into the object pointed to by s1 . Copying takes place as if the n characters from the object pointed to by s2 are first copied into a temporary array of n characters that does not overlap the objects pointed to by s1 and s2 , and then the n characters from the temporary array are copied into the object pointed to by s1 . Returns The memmove function returns the value of s1 . */ if( n > 0 ) { char * Target; char * Source; char * Temp; Target = (char *) s1; Source = (char *) s2; Temp = (char *) malloc(n); if( Temp != NULL ) { int p; p = 0; while( p < n ) { Temp[p] = Source[p]; p++; } p = 0; while( p < n ) { Target[p] = Temp[p]; p++; } free(Temp); } } return s1; } char * bwb_strcpy(char *s1, const char *s2) { /* 4.11.2.3 The strcpy function Synopsis #include char *strcpy(char *s1, const char *s2); Description The strcpy function copies the string pointed to by s2 (including the terminating null character) into the array pointed to by s1 . If copying takes place between objects that overlap, the behavior is undefined. Returns The strcpy function returns the value of s1 . */ char C; int p; p = 0; do { C = s2[p]; s1[p] = C; p++; } while( C != BasicNulChar ); return s1; } char * bwb_strncpy(char *s1, const char *s2, size_t n) { /* 4.11.2.4 The strncpy function Synopsis #include char *strncpy(char *s1, const char *s2, size_t n); Description The strncpy function copies not more than n characters (characters that follow a null character are not copied) from the array pointed to by s2 to the array pointed to by s1 ./120/ If copying takes place between objects that overlap, the behavior is undefined. If the array pointed to by s2 is a string that is shorter than n characters, null characters are appended to the copy in the array pointed to by s1 , until n characters in all have been written. Returns The strncpy function returns the value of s1 . */ if( n > 0 ) { char C; int p; p = 0; do { C = s2[p]; s1[p] = C; p++; } while( C != BasicNulChar && p < n ); while( p < n ) { s1[p] = BasicNulChar; p++; } } return s1; } char * bwb_strcat(char *s1, const char *s2) { /* 4.11.3.1 The strcat function Synopsis #include char *strcat(char *s1, const char *s2); Description The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1 . The initial character of s2 overwrites the null character at the end of s1 . If copying takes place between objects that overlap, the behavior is undefined. Returns The strcat function returns the value of s1 . */ char * Temp; Temp = bwb_strchr( s1, BasicNulChar ); bwb_strcpy( Temp, s2 ); return s1; } char * bwb_strncat(char *s1, const char *s2, size_t n) { /* 4.11.3.2 The strncat function Synopsis #include char *strncat(char *s1, const char *s2, size_t n); Description The strncat function appends not more than n characters (a null character and characters that follow it are not appended) from the array pointed to by s2 to the end of the string pointed to by s1 . The initial character of s2 overwrites the null character at the end of s1 . A terminating null character is always appended to the result./121/ If copying takes place between objects that overlap, the behavior is undefined. Returns The strncat function returns the value of s1 . */ char * Temp; Temp = bwb_strchr( s1, BasicNulChar ); bwb_strncpy( Temp, s2, n ); return s1; } int bwb_memcmp(const void *s1, const void *s2, size_t n) { /* 4.11.4.1 The memcmp function Synopsis #include int memcmp(const void *s1, const void *s2, size_t n); Description The memcmp function compares the first n characters of the object pointed to by s1 to the first n characters of the object pointed to by s2 ./122/ Returns The memcmp function returns an integer greater than, equal to, or less than zero, according as the object pointed to by s1 is greater than, equal to, or less than the object pointed to by s2 . */ if( n > 0 ) { int p; char * L; char * R; p = 0; L = (char *) s1; R = (char *) s2; while( p < n ) { if( L[p] > R[p] ) { return 1; } if( L[p] < R[p] ) { return -1; } /* L[p] == R[p] */ p++; } } return 0; } int bwb_strcmp(const char *s1, const char *s2) { /* 4.11.4.2 The strcmp function Synopsis #include int strcmp(const char *s1, const char *s2); Description The strcmp function compares the string pointed to by s1 to the string pointed to by s2 . Returns The strcmp function returns an integer greater than, equal to, or less than zero, according as the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2 . */ char C; int p; p = 0; do { if( s1[p] > s2[p] ) { return 1; } if( s1[p] < s2[p] ) { return -1; } /* s1[p] == s2[p] */ C = s1[p]; p++; } while( C != BasicNulChar ); return 0; } int bwb_strncmp(const char *s1, const char *s2, size_t n) { /* 4.11.4.4 The strncmp function Synopsis #include int strncmp(const char *s1, const char *s2, size_t n); Description The strncmp function compares not more than n characters (characters that follow a null character are not compared) from the array pointed to by s1 to the array pointed to by s2 . Returns The strncmp function returns an integer greater than, equal to, or less than zero, according as the possibly null-terminated array pointed to by s1 is greater than, equal to, or less than the possibly null-terminated array pointed to by s2 . */ if( n > 0 ) { char C; int p; p = 0; do { if( s1[p] > s2[p] ) { return 1; } if( s1[p] < s2[p] ) { return -1; } /* s1[p] == s2[p] */ C = s1[p]; p++; } while( C != BasicNulChar && p < n ); } return 0; } void * bwb_memchr(const void *s, int c, size_t n) { /* 4.11.5.1 The memchr function Synopsis #include void *memchr(const void *s, int c, size_t n); Description The memchr function locates the first occurrence of c (converted to an unsigned char ) in the initial n characters (each interpreted as unsigned char ) of the object pointed to by s . Returns The memchr function returns a pointer to the located character, or a null pointer if the character does not occur in the object. */ if( n > 0 ) { int p; unsigned char *Check; unsigned char Find; p = 0; Check = (unsigned char *)s; Find = (unsigned char) c; do { if( Check[p] == Find ) { return (void *) &(Check[p]); } p++; } while( p < n ); } return NULL; } char * bwb_strchr(const char *s, int c) { /* 4.11.5.2 The strchr function Synopsis #include char *strchr(const char *s, int c); Description The strchr function locates the first occurrence of c (converted to a char ) in the string pointed to by s . The terminating null character is considered to be part of the string. Returns The strchr function returns a pointer to the located character, or a null pointer if the character does not occur in the string. */ int p; char Find; char C; p = 0; Find = (char) c; do { C = s[p]; if( C == Find ) { return (char *) &(s[p]); } p++; } while( C != BasicNulChar ); return NULL; } char * bwb_strrchr(const char *s, int c) { /* 4.11.5.5 The strrchr function Synopsis #include char *strrchr(const char *s, int c); Description The strrchr function locates the last occurrence of c (converted to a char ) in the string pointed to by s . The terminating null character is considered to be part of the string. Returns The strrchr function returns a pointer to the character, or a null pointer if c does not occur in the string. */ int p; char Find; char * Found; char C; p = 0; Find = (char) c; Found = NULL; do { C = s[p]; if( C == Find ) { Found = (char *) &(s[p]); } p++; } while( C != BasicNulChar ); return Found; } void * bwb_memset(void *s, int c, size_t n) { /* 4.11.6.1 The memset function Synopsis #include void *memset(void *s, int c, size_t n); Description The memset function copies the value of c (converted to an unsigned char ) into each of the first n characters of the object pointed to by s . Returns The memset function returns the value of s . */ if( n > 0 ) { int p; unsigned char * Target; unsigned char Value; p = 0; Target = (unsigned char *)s; Value = (unsigned char) c; do { Target[p] = Value; p++; } while( p < n ); } return s; } size_t bwb_strlen(const char *s) { /* 4.11.6.3 The strlen function Synopsis #include size_t strlen(const char *s); Description The strlen function computes the length of the string pointed to by s . Returns The strlen function returns the number of characters that precede the terminating null character. */ size_t p; p = 0; while( s[p] != BasicNulChar ) { p++; } return p; } #if HAVE_UNIX_GCC /* these are intrinsic C functions in my environment using -ansi */ #else /* ! HAVE_UNIX_GCC */ unsigned int sleep( unsigned int X ) { return X; } #endif /* ! HAVE_UNIX_GCC */ double bwb_rint(double x) { /* BASIC dialects have different rounding rules */ double Result; if( x < 0 ) { return - bwb_rint(-x); } /* x >= 0 */ switch( My->OptionRoundType ) { case C_OPTION_ROUND_BANK: /* normal financial rounding */ Result = floor(x + 0.5); if( x - floor( x ) == 0.5 ) { /* midway */ double Half; Half = Result / 2.0; if( Half != floor( Half ) ) { /* odd -> even */ Result--; } } break; case C_OPTION_ROUND_MATH: /* normal mathematical rounding */ Result = floor(x + 0.5); break; case C_OPTION_ROUND_TRUNCATE: /* simple truncation */ Result = floor(x); break; } return Result; } int bwb_stricmp(const char *s1, const char *s2) { const unsigned char *p1; const unsigned char *p2; p1 = (const unsigned char *) s1; p2 = (const unsigned char *) s2; while (*p1 != BasicNulChar) { char c1; char c2; c1 = bwb_toupper(*p1); c2 = bwb_toupper(*p2); if (c1 < c2) { return -1; } if (c1 > c2) { return 1; } p1++; p2++; } if (*p2 == BasicNulChar) { return 0; } return -1; } int bwb_strnicmp(const char *s1, const char *s2, size_t n) { const unsigned char *p1; const unsigned char *p2; size_t x = 0; p1 = (const unsigned char *) s1; p2 = (const unsigned char *) s2; while (x < n) { char c1; char c2; c1 = bwb_toupper(p1[x]); c2 = bwb_toupper(p2[x]); if (c1 < c2) { return -1; } if (c1 > c2) { return 1; } if (c1 == BasicNulChar) { return 0; } x++; } return 0; } /* EOF */