/*************************************************************** bwb_cmd.c Miscellaneous Commands 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 */ /* */ /*---------------------------------------------------------------*/ #include "bwbasic.h" static int xl_line(FILE * file, struct bwb_line * l); static int LastLineNumber = -1; /*************************************************************** FUNCTION: bwb_rem() DESCRIPTION: This C function implements the BASIC rem (REMark) command, ignoring the remainder of the line. ***************************************************************/ struct bwb_line * bwb_REM(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); adv_eos(l->buffer, &(l->position)); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_let() DESCRIPTION: This C function implements the BASIC LET assignment command, even if LET is implied and not explicit. SYNTAX: LET variable = expression ***************************************************************/ struct bwb_line * bwb_LET(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* Call the expression interpreter to evaluate the assignment */ bwb_exp(l->buffer, TRUE, &(l->position)); if (ERROR_PENDING) { return bwb_zline(l); } return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_go DESCRIPTION: This C function implements the BASIC GO command, branching appropriately to GOTO or GOSUB. ***************************************************************/ struct bwb_line * bwb_GO(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); bwb_error(err_syntax); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_goto DESCRIPTION: This C function implements the BASIC GOTO command. SYNTAX: GOTO line | label ***************************************************************/ struct bwb_line * bwb_GOTO(struct bwb_line * l) { struct bwb_line *x; char tbuf[BasicStringLengthMax + 1]; bwx_DEBUG(__FUNCTION__); adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); /* check for target label */ x = find_label(tbuf); if (x != NULL) { x->position = 0; return x; } return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_gosub() DESCRIPTION: This function implements the BASIC GOSUB command. SYNTAX: GOSUB line | label ***************************************************************/ struct bwb_line * bwb_GOSUB(struct bwb_line * l) { struct bwb_line *x; char tbuf[BasicStringLengthMax + 1]; bwx_DEBUG(__FUNCTION__); adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); x = find_label(tbuf); if (x != NULL) { bwb_zline(l); bwb_incexec(); /* set the new position to x and return x */ x->position = 0; bwb_setexec(x, 0, EXEC_GOSUB); return x; } return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_return() DESCRIPTION: This function implements the BASIC RETURN command. SYNTAX: RETURN ***************************************************************/ struct bwb_line * bwb_RETURN(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); while (CURTASK excs[CURTASK exsc].code != EXEC_GOSUB) { bwb_decexec(); if (CURTASK excs[CURTASK exsc].code == EXEC_NORM) /* End of the line? */ { bwb_error(err_retnogosub); } } /* decrement the EXEC stack counter */ bwb_decexec(); return CURTASK excs[CURTASK exsc].line; } /*************************************************************** FUNCTION: bwb_on DESCRIPTION: This function implements the BASIC ON... GOTO or ON...GOSUB statements. It will also detect the ON ERROR... statement and pass execution to bwb_onerror(). SYNTAX: ON variable GOTO|GOSUB line|label[,...] ***************************************************************/ struct bwb_line * bwb_ON(struct bwb_line * l) { struct bwb_line *x; char tbuf[BasicStringLengthMax + 1]; int p; struct exp_ese *rvar; int v; int loop; int num_lines; int command; bwx_DEBUG(__FUNCTION__); /* Check for argument */ adv_ws(l->buffer, &(l->position)); if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar) { bwb_error(err_incomplete); return bwb_zline(l); } /* get the variable name, numerical constant, or expression */ adv_element(l->buffer, &(l->position), tbuf); /* evaluate the variable name or constant */ p = 0; rvar = bwb_exp(tbuf, FALSE, &p); if (ERROR_PENDING) { return bwb_zline(l); } v = exp_getival(rvar); /* Get GOTO or GOSUB statements */ adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "GO") == 0) { adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "TO") == 0) { command = C_GOTO; } else if (strcasecmp(tbuf, "SUB") == 0) { command = C_GOSUB; } else { sprintf(bwb_ebuf, ERR_ONNOGOTO); bwb_error(bwb_ebuf); return bwb_zline(l); } } else if (strcasecmp(tbuf, "GOTO") == 0) { command = C_GOTO; } else if (strcasecmp(tbuf, "GOSUB") == 0) { command = C_GOSUB; } else { sprintf(bwb_ebuf, ERR_ONNOGOTO); bwb_error(bwb_ebuf); return bwb_zline(l); } if (v < 1) { if (OptionFlags & OPTION_BUGS_ON) { /* fall-thru to next line without error */ /* advance to end of segment */ adv_eos(l->buffer, &(l->position)); } else { /* ERROR */ bwb_error(err_valoorange); } return bwb_zline(l); } num_lines = 0; loop = TRUE; while (loop == TRUE) { /* read a line|label */ inp_adv(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); num_lines++; if (num_lines == v) { loop = FALSE; } /* check for end of line */ adv_ws(l->buffer, &(l->position)); if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar) { loop = FALSE; } } /* advance to end of segment */ adv_eos(l->buffer, &(l->position)); /* Be sure value is in range */ if (v > num_lines) { if (OptionFlags & OPTION_BUGS_ON) { /* fall-thru to next line without error */ /* advance to end of segment */ adv_eos(l->buffer, &(l->position)); } else { /* ERROR */ bwb_error(err_valoorange); } return bwb_zline(l); } x = find_label(tbuf); if (x == NULL) { return bwb_zline(l); } if (command == C_GOTO) { x->position = 0; bwb_setexec(x, 0, CURTASK excs[CURTASK exsc].code); return x; } else if (command == C_GOSUB) { /* save current stack level */ bwb_setexec(l, l->position, CURTASK excs[CURTASK exsc].code); /* increment exec stack */ bwb_incexec(); /* set the new position to x and return x */ x->position = 0; bwb_setexec(x, 0, EXEC_GOSUB); return x; } sprintf(bwb_ebuf, "in bwb_on(): invalid value for command."); bwb_error(bwb_ebuf); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_stop() DESCRIPTION: This C function implements the BASIC STOP command, interrupting program flow at a specific point. SYNTAX: STOP ***************************************************************/ struct bwb_line * bwb_STOP(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); stopped_line = l->number; bwx_STOP(); return bwb_END(l); } /*************************************************************** FUNCTION: bwb_xend() DESCRIPTION: This C function implements the BASIC END command, checking for END SUB or END FUNCTION, else stopping program execution for a simple END command. ***************************************************************/ struct bwb_line * bwb_END(struct bwb_line * l) { /* a simple END statement */ bwx_DEBUG(__FUNCTION__); stopped_line = l->number; break_handler(); return &CURTASK bwb_end; } /*************************************************************** FUNCTION: bwb_run() DESCRIPTION: This C function implements the BASIC RUN command. Even though RUN is not a core statement, the function bwb_run() is called from core, so it must be present for a minimal implementation. SYNTAX: RUN [line]|[file-name] ***************************************************************/ struct bwb_line * bwb_RUN(struct bwb_line * l) { struct bwb_line *current; bwx_DEBUG(__FUNCTION__); /* see if there is an element */ current = NULL; adv_ws(l->buffer, &(l->position)); if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar) { current = CURTASK bwb_start.next; var_CLEAR(); } else { struct exp_ese *e; e = bwb_exp(l->buffer, FALSE, &(l->position)); if (ERROR_PENDING) { return bwb_zline(l); } if (e->type == STRING) { /* check its type: if it is a STRING, open the file * and execute it */ FILE *input; char tbuf[BasicStringLengthMax + 1]; bwb_NEW(l); /* clear memory */ str_btoc(tbuf, exp_getsval(e)); /* get string in tbuf */ if ((input = fopen(tbuf, "r")) == NULL) /* open file */ { sprintf(bwb_ebuf, err_openfile, tbuf); bwb_error(bwb_ebuf); } bwb_fload(input); /* load program */ current = &CURTASK bwb_start; /* JBV */ } else { /* check its type: if it is a NUMBER, execute the * line */ int go_lnumber; /* line number to go to */ struct bwb_line *x; go_lnumber = exp_getival(e); for (x = CURTASK bwb_start.next; x != &CURTASK bwb_end; x = x->next) { if (x->number == go_lnumber) { current = x; } } if (current == NULL) { sprintf(bwb_ebuf, err_lnnotfound, go_lnumber); bwb_error(bwb_ebuf); return &CURTASK bwb_end; } } } bwb_scan(); current->position = 0; CURTASK exsc = 0; bwb_setexec(current, 0, EXEC_NORM); /* RUN */ bwb_Warning_Clear(); stopped_line = 0; SetOnError(0); return current; } /*************************************************************** FUNCTION: bwb_cont() DESCRIPTION: This C function implements the BASIC CONT command. SYNTAX: CONT ***************************************************************/ struct bwb_line * bwb_CONT(struct bwb_line * l) { struct bwb_line *current, *x; bwx_DEBUG(__FUNCTION__); /* see if there is an element */ current = NULL; if (stopped_line > 0) { for (x = CURTASK bwb_start.next; (x != &CURTASK bwb_end) && (current == NULL); x = x->next) { if (x->number > stopped_line) { current = x; } } } if (current == NULL) { /* same as "RUN" */ current = CURTASK bwb_start.next; } bwb_scan(); current->position = 0; CURTASK exsc = 0; bwb_setexec(current, 0, EXEC_NORM); /* CONT */ stopped_line = 0; return current; } /*************************************************************** FUNCTION: bwb_new() DESCRIPTION: This C function implements the BASIC NEW command. Even though NEW is not a core statement, the function bwb_run() is called from core, so it must be present for a minimal implementation. SYNTAX: NEW ***************************************************************/ struct bwb_line * bwb_NEW(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* clear program in memory */ bwb_xnew(&bwb_start); /* clear all variables */ var_CLEAR(); /* NEW */ bwb_Warning_Clear(); stopped_line = 0; SetOnError(0); return bwb_zline(l); } /* End of Core Functions Section */ /*************************************************************** FUNCTION: bwb_system() DESCRIPTION: This C function implements the BASIC SYSTEM command, exiting to the operating system (or calling program). It is also called by the QUIT command, a functional equivalent for SYSTEM in Bywater BASIC. SYNTAX: SYSTEM QUIT ***************************************************************/ struct bwb_line * bwb_QUIT(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); return bwb_SYSTEM(l); } struct bwb_line * bwb_SYSTEM(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); prn_xprintf("\n"); bwx_terminate(); return &CURTASK bwb_end;/* to make LINT happy */ } /*************************************************************** FUNCTION: bwb_load() DESCRIPTION: This C function implements the BASIC LOAD command. SYNTAX: LOAD [file-name] ***************************************************************/ struct bwb_line * bwb_LOAD(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* clear current contents */ bwb_NEW(l); /* call xload function to load program in memory */ bwb_xload(l); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_xload() DESCRIPTION: This C function loads a BASIC program into memory. ***************************************************************/ struct bwb_line * bwb_xload(struct bwb_line * l) { FILE *loadfile; bwx_DEBUG(__FUNCTION__); /* Get an argument for filename */ adv_ws(l->buffer, &(l->position)); if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar) { /* default is the last filename used by LOAD or SAVE */ } else { /* Section added by JBV (bug found by DD) */ struct exp_ese *e; /* JBV */ e = bwb_exp(l->buffer, FALSE, &(l->position)); if (ERROR_PENDING) { return bwb_zline(l); } if (e->type != STRING) { sprintf(bwb_ebuf, "in bwb_xload(): Missing filespec"); bwb_error(bwb_ebuf); return bwb_zline(l); } str_btoc(CURTASK progfile, exp_getsval(e)); /* JBV */ } if (strlen(CURTASK progfile) == 0) { bwb_error(err_nofn); /* Added by JBV (bug found by DD) */ return bwb_zline(l); } if ((loadfile = fopen(CURTASK progfile, "r")) == NULL) { sprintf(bwb_ebuf, err_openfile, CURTASK progfile); bwb_error(bwb_ebuf); return bwb_zline(l); } bwb_fload(loadfile); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_save() DESCRIPTION: This C function implements the BASIC SAVE command. SYNTAX: SAVE [file-name] ***************************************************************/ #define CSAVE_VERSION_1 0x20150218 struct bwb_line * bwb_CSAVE_(struct bwb_line * l) { /* CSAVE* NumericArrayName */ char tbuf[BasicStringLengthMax + 1]; struct bwb_variable *v; FILE *f; unsigned long n; unsigned long t; bwx_DEBUG(__FUNCTION__); bwb_getvarname(l->buffer, tbuf, &(l->position)); v = var_find(tbuf); if (v == NULL) { bwb_error(err_syntax); return bwb_zline(l); } /* variable MUST be numeric */ if (v->type == STRING) { bwb_error(err_syntax); return bwb_zline(l); } /* variable MUST be an array */ if ((v->dimensions == 1) && (v->array_sizes[0] == 1)) { bwb_error(err_syntax); return bwb_zline(l); } /* * variable storage is a mess, * we bypass that tradition here. */ t = 1; for (n = 0; n < v->dimensions; n++) { t *= v->array_sizes[n]; } if (t <= 1) { bwb_error(err_syntax); return bwb_zline(l); } /* open file */ f = fopen(v->name, "w"); if (f == NULL) { bwb_error(err_syntax); return bwb_zline(l); } /* write version number */ n = CSAVE_VERSION_1; fwrite(&n, sizeof(long), 1, f); /* write total number of elements */ fwrite(&t, sizeof(long), 1, f); /* write data */ fwrite(v->memnum, sizeof(BasicNumberType), t, f); /* OK */ fclose(f); return bwb_zline(l); } struct bwb_line * bwb_CLOAD_(struct bwb_line * l) { /* CLOAD* NumericArrayName */ char tbuf[BasicStringLengthMax + 1]; struct bwb_variable *v; FILE *f; unsigned long n; unsigned long t; bwx_DEBUG(__FUNCTION__); bwb_getvarname(l->buffer, tbuf, &(l->position)); v = var_find(tbuf); if (v == NULL) { bwb_error(err_syntax); return bwb_zline(l); } /* variable MUST be numeric */ if (v->type == STRING) { bwb_error(err_syntax); return bwb_zline(l); } /* variable MUST be an array */ if ((v->dimensions == 1) && (v->array_sizes[0] == 1)) { bwb_error(err_syntax); return bwb_zline(l); } /* variable storage is a mess, we bypass that tradition here. */ t = 1; for (n = 0; n < v->dimensions; n++) { t *= v->array_sizes[n]; } if (t <= 1) { bwb_error(err_syntax); return bwb_zline(l); } /* open file */ f = fopen(v->name, "r"); if (f == NULL) { bwb_error(err_syntax); return bwb_zline(l); } /* read version number */ n = 0; fread(&n, sizeof(long), 1, f); if (n != CSAVE_VERSION_1) { fclose(f); bwb_error("Bad File"); return bwb_zline(l); } /* read total number of elements */ n = 0; fread(&n, sizeof(long), 1, f); if (n != t) { fclose(f); bwb_error("Size Mismatch"); return bwb_zline(l); } /* read data */ fread(v->memnum, sizeof(BasicNumberType), t, f); /* OK */ fclose(f); return bwb_zline(l); } struct bwb_line * bwb_CSAVE(struct bwb_line * l) { /* CSAVE [filename$] */ bwx_DEBUG(__FUNCTION__); return bwb_SAVE(l); } struct bwb_line * bwb_CLOAD(struct bwb_line * l) { /* CLOAD [filename$] */ bwx_DEBUG(__FUNCTION__); return bwb_LOAD(l); } struct bwb_line * bwb_SAVE(struct bwb_line * l) { FILE *outfile; bwx_DEBUG(__FUNCTION__); /* Get an argument for filename */ adv_ws(l->buffer, &(l->position)); if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar) { /* default is the last filename used by LOAD or SAVE */ } else { /* Section added by JBV (bug found by DD) */ struct exp_ese *e; /* JBV */ e = bwb_exp(l->buffer, FALSE, &(l->position)); if (ERROR_PENDING) { return bwb_zline(l); } if (e->type != STRING) { sprintf(bwb_ebuf, "in bwb_save(): Missing filespec"); bwb_error(bwb_ebuf); return bwb_zline(l); } str_btoc(CURTASK progfile, exp_getsval(e)); /* JBV */ } if (strlen(CURTASK progfile) == 0) { bwb_error(err_nofn); /* Added by JBV (bug found by DD) */ return bwb_zline(l); } if ((outfile = fopen(CURTASK progfile, "w")) == NULL) { sprintf(bwb_ebuf, err_openfile, CURTASK progfile); bwb_error(bwb_ebuf); return bwb_zline(l); } bwb_xlist(l, outfile); fclose(outfile); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_list() DESCRIPTION: This C function implements the BASIC LIST command. SYNTAX: LIST line[-line] ***************************************************************/ struct bwb_line * bwb_LIST(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); bwb_xlist(l, stdout); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_xlist() DESCRIPTION: This C function lists the program in memory to a specified output device. ***************************************************************/ struct bwb_line * bwb_xlist(struct bwb_line * l, FILE * file) { struct bwb_line *start, *end, *current; BasicLineNumberType s, e; int f, r; bwx_DEBUG(__FUNCTION__); /* Default first value */ start = CURTASK bwb_start.next; s = BasicLineNumberMin; /* Default last value */ end = &CURTASK bwb_end; e = BasicLineNumberMax; /* Parse parameters */ r = bwb_numseq(&(l->buffer[l->position]), &s, &e); /* r example = ================ 0 LIST 1 LIST 1000 4 LIST - 5 LIST 1000- 6 LIST -9000 7 LIST 1000-9000 */ if (r == 1) { /* LIST 1000 */ e = s; } /* advance to the end of the segment */ adv_eos(l->buffer, &(l->position)); /* abort if either number is out of range */ if (s < BasicLineNumberMin || s > BasicLineNumberMax) { /* LIST 99999- */ sprintf(bwb_ebuf, err_lnnotfound, s); bwb_error(bwb_ebuf); return bwb_zline(l); } if (e < BasicLineNumberMin || e > BasicLineNumberMax) { /* LIST -99999 */ sprintf(bwb_ebuf, err_lnnotfound, e); bwb_error(bwb_ebuf); return bwb_zline(l); } if (s > e) { /* LIST 9999-1 */ sprintf(bwb_ebuf, err_lnnotfound, s); bwb_error(bwb_ebuf); return bwb_zline(l); } /* find the first line that actually exists that is >= START */ f = FALSE; for (current = CURTASK bwb_start.next; (f == FALSE) && (current != &CURTASK bwb_end); current = current->next) { if (current->number >= s) { f = TRUE; start = current; } } /* "start" now points at the first line that actually exists that is * >= START */ if (r == 1) { /* LIST 999 */ if (s != start->number) { /* THE SPECIFIED LINE DOES NOT EXIST */ f = FALSE; } } /* check and see if a line number was found */ if (f == FALSE) { if (l->number > 0) { /* this is an executing program */ sprintf(bwb_ebuf, err_lnnotfound, s); bwb_error(bwb_ebuf); } return bwb_zline(l); } f = FALSE; if (e > s) { /* find the last line that actually exists that is <= END */ for (current = start; current != &CURTASK bwb_end; current = current->next) { if (current->number <= e) { f = TRUE; end = current; } } } else { /* e == s */ f = TRUE; end = start; } /* "end" now points at the last line that actually exists that is <= * END */ if (r == 6 || r == 7) { /* LIST -999 */ if (e < end->number) { /* THERE ARE NO LINES LESS THAN SPECIFIED */ f = FALSE; } } /* "end" is always after "start" */ end = end->next; while (end->number <= e) { end = end->next; } /* * "end" now points at the first line * that actually exists that * is > END */ /* check and see if a line number was found */ if (f == FALSE) { if (l->number > 0) { /* this is an executing program */ sprintf(bwb_ebuf, err_lnnotfound, e); bwb_error(bwb_ebuf); } return bwb_zline(l); } /* now go through and list appropriate lines */ bwb_scan(); LastLineNumber = -1; for (current = start; current != end; current = current->next) { xl_line(file, current); } fprintf(file, "\n"); return bwb_zline(l); } /*************************************************************** FUNCTION: xl_line() DESCRIPTION: This function lists a single program line to a specified device of file. It is called by bwb_xlist(); ***************************************************************/ static int xl_line(FILE * file, struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); if ((file == stdout) || (file == stderr)) { char tbuf[32]; if (LastLineNumber == l->number) { strcpy(tbuf, " :"); } else { sprintf(tbuf, "%5d:", l->number); } prn_xprintf(tbuf); if (OptionFlags & OPTION_COVERAGE_ON) { #if 0 sprintf(tbuf, "%c:", l->Coverage); prn_xprintf(tbuf); #endif if( l->LineFlags & LINE_EXECUTED ) { prn_xprintf("*"); } else { prn_xprintf(" "); } prn_xprintf(":"); } if (OptionIndentValue > 0) { int i; for (i = 0; i < l->Indention; i++) { int j; for (j = 0; j < OptionIndentValue; j++) { prn_xprintf(" "); } } } prn_xprintf(l->buffer); prn_xprintf("\n"); } else { #if 0 if (LastLineNumber == l->number) { fprintf(file, "%s\n", l->buffer); } else { fprintf(file, "%d %s\n", l->number, l->buffer); } #endif if (LastLineNumber == l->number && OptionStatementChar != '\0' ) { fprintf(file, "%c", OptionStatementChar); } else if(LastLineNumber == -1 ) { /* first line, do nothing */ } else { fprintf(file, "\n"); } if( l->LineFlags & LINE_NUMBERED ) { fprintf(file, "%d ", l->number); } fprintf(file, "%s", l->buffer); } LastLineNumber = l->number; return TRUE; } /*************************************************************** FUNCTION: bwb_delete() DESCRIPTION: This C function implements the BASIC DELETE command for interactive programming, deleting a specified program line (or lines) from memory. SYNTAX: DELETE line[-line] ***************************************************************/ struct bwb_line * bwb_DELETE(struct bwb_line * l) { struct bwb_line *start, *end, *current, *previous, *p, *next; BasicLineNumberType s, e; int f, r; bwx_DEBUG(__FUNCTION__); /* Default first value */ start = CURTASK bwb_start.next; s = BasicLineNumberMin; /* Default last value */ end = &CURTASK bwb_end; e = BasicLineNumberMax; /* Default previous value */ previous = p = &CURTASK bwb_start; r = bwb_numseq(&(l->buffer[l->position]), &s, &e); /* r example = ================ 0 DELETE 1 DELETE 1000 4 DELETE - 5 DELETE 1000- 6 DELETE -9000 7 DELETE 1000-9000 */ if (r == 1) { /* DELETE 1000 */ e = s; } /* advance to the end of the segment */ adv_eos(l->buffer, &(l->position)); /* abort if either number is out of range */ if (s < BasicLineNumberMin || s > BasicLineNumberMax) { /* DELETE 99999- */ sprintf(bwb_ebuf, err_lnnotfound, s); bwb_error(bwb_ebuf); return bwb_zline(l); } if (e < BasicLineNumberMin || e > BasicLineNumberMax) { /* DELETE -99999 */ sprintf(bwb_ebuf, err_lnnotfound, e); bwb_error(bwb_ebuf); return bwb_zline(l); } if (s > e) { /* DELETE 9999-1 */ sprintf(bwb_ebuf, err_lnnotfound, s); bwb_error(bwb_ebuf); return bwb_zline(l); } /* find the first line that exists that is >= START */ f = FALSE; for (current = CURTASK bwb_start.next; (f == FALSE) && (current != &CURTASK bwb_end); current = current->next) { if (current->number >= s) { f = TRUE; previous = p; start = current; } p = current; } /* "start" now points at the first line that actually exists that is * >= START */ /* "previous" now points at the first line that actually exists that * is < START */ if (r == 1) { /* DELETE 1000 */ if (s != start->number) { /* THE SPECIFIED LINE DOES NOT EXIST */ f = FALSE; } } /* check and see if a line number was found */ if (f == FALSE) { if (l->number > 0) { /* this is an executing program */ sprintf(bwb_ebuf, err_lnnotfound, s); bwb_error(bwb_ebuf); } return bwb_zline(l); } f = FALSE; if (e > s) { /* find the last line that actually exists that is <= END */ for (current = start; current != &CURTASK bwb_end; current = current->next) { if (current->number <= e) { f = TRUE; end = current; } } } else { /* e == s */ f = TRUE; end = start; } /* "end" now points at the last line that actually exists that is <= * END */ if (r == 6 || r == 7) { /* DELETE -999 */ /* DELETE 1-999 */ if (e < end->number) { /* THERE ARE NO LINES LESS THAN SPECIFIED */ f = FALSE; } } /* "end" is always after "start" */ end = end->next; while (end->number <= e) { end = end->next; } /* * "end" now points at the first line * that actually exists * that * is > END */ /* check and see if a line number was found */ if (f == FALSE) { if (l->number > 0) { /* this is an executing program */ sprintf(bwb_ebuf, err_lnnotfound, e); bwb_error(bwb_ebuf); } return bwb_zline(l); } if (l->number > 0) { /* This is an executing progrram. So make sure DELETE removes * structured commands completely. The BASIC program must * delete all of a structured command. Do not allow a * dangling FOR, NEXT, and so on, since that is just a FATAL * error waiting to happen. FOR - NEXT DO - LOOP WHILE - WEND * UNTIL - UEND IF - END IF SELECT CASE - END SELECT */ s = start->number; e = end->number; current = start; while ((current != end) && (current != &CURTASK bwb_end)) { if (current->OtherLine != NULL) { /* this line is either the Top or the Bottomm * of a structured command */ /* verify the other end of the block is also * in the DELETE range */ int n; n = current->OtherLine->number; if (n < s || n >= e) { sprintf(bwb_ebuf, "Cannot delete at %d because %d is not included" ,current->number ,n ); bwb_error(bwb_ebuf); return bwb_zline(l); } } current = current->next; } } else { /* The user is executing DELETE interactively, Allow user to * DELETE whatever they want. Whenever user attempts to run, * bwb_scan() will find any mismatch. */ } /* now go through and delete appropriate lines */ current = start; while ((current != end) && (current != &CURTASK bwb_end)) { next = current->next; if (current == l) { l = previous; } if (current->OtherLine != NULL) { /* remove any existing structured command linkage */ current->OtherLine->OtherLine = NULL; current->OtherLine = NULL; } bwb_freeline(current); current = next; } /* previous should now be set to the line previous to the first in * the omission list */ previous->next = current; CURTASK rescan = TRUE; /* program needs to be scanned again */ bwb_scan(); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_donum() DESCRIPTION: This function implements the BASIC DO NUM command, numbering all program lines in memory in increments of 10 beginning at 10. SYNTAX: DO NUM ***************************************************************/ #if 0 struct bwb_line * bwb_donum(struct bwb_line * l) { struct bwb_line *current; register int lnumber; bwx_DEBUG(__FUNCTION__); lnumber = 10; for (current = bwb_start.next; current != &bwb_end; current = current->next) { current->number = lnumber; lnumber += 10; if (lnumber > BasicLineNumberMax) { return bwb_zline(l); } } return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_dounnum() DESCRIPTION: This function implements the BASIC DO UNNUM command, removing all line numbers from the program in memory. SYNTAX: DO UNNUM ***************************************************************/ struct bwb_line * bwb_dounnum(struct bwb_line * l) { struct bwb_line *current; bwx_DEBUG(__FUNCTION__); for (current = bwb_start.next; current != &bwb_end; current = current->next) { current->number = 0; } return bwb_zline(l); } #endif /* 0 */ /*************************************************************** FUNCTION: bwb_chain() DESCRIPTION: This C function implements the BASIC CHAIN command. SYNTAX: CHAIN "file-name" | file-name$ ***************************************************************/ struct bwb_line * bwb_CHAIN(struct bwb_line * l) { /* based upon bwb_xload() */ FILE *loadfile; struct exp_ese *e; bwx_DEBUG(__FUNCTION__); /* Get an argument for filename */ adv_ws(l->buffer, &(l->position)); if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar) { bwb_error(err_nofn); /* Added by JBV (bug found by DD) */ return bwb_zline(l); } /* The file-name may be any string expression */ e = bwb_exp(l->buffer, FALSE, &(l->position)); if (ERROR_PENDING) { return bwb_zline(l); } if (e->type != STRING) { sprintf(bwb_ebuf, "in bwb_chain(): Missing filespec"); bwb_error(bwb_ebuf); return bwb_zline(l); } /* save the filename */ str_btoc(CURTASK progfile, exp_getsval(e)); /* deallocate all variables except common ones */ var_delcvars(); /* remove old program from memory */ bwb_xnew(&bwb_start); /* call xload function to load new program in memory */ if ((loadfile = fopen(CURTASK progfile, "r")) == NULL) { sprintf(bwb_ebuf, err_openfile, CURTASK progfile); bwb_error(bwb_ebuf); return bwb_zline(l); } bwb_fload(loadfile); bwb_scan(); /* reset all stack counters */ CURTASK exsc = 0; CURTASK expsc = 0; /* run the program */ /* CHAIN */ bwb_Warning_Clear(); stopped_line = 0; SetOnError(0); CURTASK bwb_start.position = 0; bwb_setexec(&CURTASK bwb_start, 0, EXEC_NORM); return &CURTASK bwb_start; } /*************************************************************** FUNCTION: bwb_merge() DESCRIPTION: This C function implements the BASIC MERGE command, merging command lines from a specified file into the program in memory without deleting the lines already in memory. SYNTAX: MERGE file-name ***************************************************************/ struct bwb_line * bwb_MERGE(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* call xload function to merge program in memory */ bwb_xload(l); return bwb_zline(l); } void SetOnError(int LineNumber) { /* scan the stack looking for a FUNCTION/SUB */ int i; bwx_DEBUG(__FUNCTION__); i = CURTASK exsc; while (i > 0) { struct bwb_line *current; current = CURTASK excs[i].LoopTopLine; if (current != NULL) { switch (current->cmdnum) { case C_FUNCTION: case C_SUB: /* FOUND */ /* we are in a FUNCTION/SUB, so this is LOCAL */ CURTASK excs[i].OnErrorGoto = LineNumber; return; break; } } i--; } /* NOT FOUND */ /* we are NOT in a FUNCTION/SUB */ CURTASK excs[0].OnErrorGoto = LineNumber; } int GetOnError(void) { /* scan the stack looking for a FUNCTION/SUB */ int i; bwx_DEBUG(__FUNCTION__); i = CURTASK exsc; while (i >= 0) { if (CURTASK excs[i].OnErrorGoto != 0) { /* FOUND */ return CURTASK excs[i].OnErrorGoto; } i--; } /* NOT FOUND */ return 0; } /*************************************************************** FUNCTION: bwb_onerror() DESCRIPTION: This C function implements the BASIC ON ERROR GOSUB command. SYNTAX: ON ERROR GOSUB line | label ***************************************************************/ struct bwb_line * bwb_ON_ERROR_GOTO(struct bwb_line * l) { /* ON ERROR GOTO line */ struct bwb_line *x; char tbuf[BasicStringLengthMax + 1]; /* get the line number */ adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "0") == 0) { SetOnError(0); return bwb_zline(l); } x = find_label(tbuf); if (x != NULL) { SetOnError(x->number); return bwb_zline(l); } bwb_error(err_syntax); return bwb_zline(l); } struct bwb_line * bwb_ON_ERROR_GOSUB(struct bwb_line * l) { /* ON ERROR GOSUB line */ struct bwb_line *x; char tbuf[BasicStringLengthMax + 1]; /* get the line number */ adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "0") == 0) { SetOnError(0); return bwb_zline(l); } x = find_label(tbuf); if (x != NULL) { SetOnError(x->number); return bwb_zline(l); } bwb_error(err_syntax); return bwb_zline(l); } struct bwb_line * bwb_ON_ERROR_RESUME_NEXT(struct bwb_line * l) { SetOnError(-1); return bwb_zline(l); } struct bwb_line * bwb_ON_ERROR_RETURN_NEXT(struct bwb_line * l) { SetOnError(-1); return bwb_zline(l); } struct bwb_line * bwb_ON_TIMER(struct bwb_line * l) { /* ON TIMER(...) GOSUB ... TIMER ON ... */ char tbuf[BasicStringLengthMax + 1]; int p; struct exp_ese *rvar; BasicNumberType v; BasicNumberType minv; bwx_DEBUG(__FUNCTION__); /* turn off the TIMER - so syntax errors will NOT fire the timer */ bwb_Timer_Off(); tmr_gotol = 0; tmr_count = 0; /* get the SECOMDS parameter */ adv_element(l->buffer, &(l->position), tbuf); p = 0; rvar = bwb_exp(tbuf, FALSE, &p); if (ERROR_PENDING) { return bwb_zline(l); } v = exp_getnval(rvar); minv = 1; minv /= CLOCKS_PER_SEC; if (v > minv) { /* get the GOSUB keyword */ adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "GOSUB") == 0) { /* ON TIMER(X) GOSUB line */ struct bwb_line *x; /* get the line number */ adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); x = find_label(tbuf); if (x != NULL) { tmr_gotol = x->number; tmr_count = v; return bwb_zline(l); } } } bwb_error(err_syntax); return bwb_zline(l); } struct bwb_line * bwb_TIMER(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* turn off the TIMER - so syntax errors will NOT fire the timer */ bwb_Timer_Off(); bwb_error(err_syntax); return bwb_zline(l); } struct bwb_line * bwb_TIMER_OFF(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* turn off the TIMER - so syntax errors will NOT fire the timer */ bwb_Timer_Off(); /* TIMER OFF */ tmr_gotol = 0; tmr_count = 0; return bwb_zline(l); } struct bwb_line * bwb_TIMER_ON(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* turn off the TIMER - so syntax errors will NOT fire the timer */ bwb_Timer_Off(); /* TIMER ON */ if (tmr_count > 0 && tmr_gotol > 0) { tmr_expires = bwx_TIMER(tmr_count); bwb_Timer_On(); } return bwb_zline(l); } struct bwb_line * bwb_TIMER_STOP(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* turn off the TIMER - so syntax errors will NOT fire the timer */ bwb_Timer_Off(); /* TIMER STOP */ return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_resume() DESCRIPTION: This C function implements the BASIC RESUME command. SYNTAX: RESUME [ 0 | NEXT | line | label ] ***************************************************************/ struct bwb_line * bwb_RESUME(struct bwb_line * l) { char tbuf[BasicStringLengthMax + 1]; struct bwb_line *x = NULL; bwx_DEBUG(__FUNCTION__); if (err_number == 0) /* RESUME without ERR are FATAL */ { sprintf(bwb_ebuf, "RESUME WITHOUT ERR AT %d", CURTASK number); bwb_error(bwb_ebuf); return bwb_zline(l); } if (err_line == NULL) { /* RESUME without ERL are FATAL */ sprintf(bwb_ebuf, "RESUME WITHOUT ERL AT %d", CURTASK number); bwb_error(bwb_ebuf); return bwb_zline(l); } if (err_line->number == 0) { /* RESUME without ERL are FATAL */ sprintf(bwb_ebuf, "RESUME WITHOUT ERL AT %d", CURTASK number); bwb_error(bwb_ebuf); return bwb_zline(l); } /* Get optional argument for RESUME */ adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); if (strlen(tbuf) == 0 || strcasecmp(tbuf, "0") == 0) { /* RESUME [0] */ /* Execution resumes at the statement which caused the error */ x = err_line; } else if (strcasecmp(tbuf, "NEXT") == 0) { /* RESUME NEXT */ /* Execution resumes at the statement immediately following * the one which caused the error */ x = err_line->next; } else { /* RESUME line|label */ x = find_label(tbuf); } if (x != NULL) { bwb_Warning_Clear(); x->position = 0; return x; } return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_xnew() DESCRIPTION: Clears the program in memory, but does not deallocate all variables. ***************************************************************/ void bwb_xnew(struct bwb_line * l) { struct bwb_line *current, *previous; int wait; bwx_DEBUG(__FUNCTION__); previous = NULL; /* JBV */ wait = TRUE; for (current = l->next; current != &CURTASK bwb_end; current = current->next) { if (wait != TRUE) { /* Revised to FREE pass-thru call by JBV */ FREE(previous, "bwb_xnew"); } wait = FALSE; previous = current; } l->next = &bwb_end; } /*************************************************************** FUNCTION: bwb_cmds() DESCRIPTION: This function implements a CMD command, which lists all commands implemented. It is not part of a BASIC specification, but is used for debugging bwBASIC. SYNTAX: CMDS ***************************************************************/ struct bwb_line * bwb_CMDS(struct bwb_line * l) { register int n; int t; bwx_DEBUG(__FUNCTION__); prn_iprintf("BWBASIC COMMANDS AVAILABLE:\n"); /* run through the command table and print comand names */ t = 0; for (n = 0; n < NUM_COMMANDS; ++n) { prn_iprintf(bwb_cmdtable[n].name); if (t < 4) { prn_iprintf("\t"); t++; } else { prn_iprintf("\n"); t = 0; } } if (t > 0) { prn_iprintf("\n"); } return bwb_zline(l); } static void CommandUniqueID(int i, char *UniqueID) { char *C; bwx_DEBUG(__FUNCTION__); strcpy(UniqueID, "C_"); if (strcasecmp(bwb_cmdtable[i].name, "?") == 0) { strcat(UniqueID, "QUEST"); } else { strcat(UniqueID, bwb_cmdtable[i].name); } C = UniqueID; while (*C != '\0') { if (!isalnum(*C)) *C = '_'; C++; } } static void CommandVector(int i, char *Vector) { char *C; bwx_DEBUG(__FUNCTION__); strcpy(Vector, "bwb_"); if (strcasecmp(bwb_cmdtable[i].name, "?") == 0) { strcat(Vector, "QUEST"); } else { strcat(Vector, bwb_cmdtable[i].name); } C = Vector; while (*C != '\0') { if (!isalnum(*C)) *C = '_'; C++; } } static void CommandOptionVersion(int n, char *OutputLine) { int i; int j; bwx_DEBUG(__FUNCTION__); strcpy(OutputLine, ""); j = 0; for (i = 0; i < NUM_VERSIONS; i++) { if (bwb_cmdtable[n].OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask) { if (j > 0) { strcat(OutputLine, " | "); } strcat(OutputLine, bwb_vertable[i].ID); j++; } } } void SortAllCommands(void) { static int IsSorted = FALSE; bwx_DEBUG(__FUNCTION__); if (IsSorted == FALSE) { int i; for (i = 0; i < NUM_COMMANDS - 1; i++) { int j; int k; k = i; for (j = i + 1; j < NUM_COMMANDS; j++) { if (strcasecmp(bwb_cmdtable[j].name, bwb_cmdtable[k].name) < 0) { k = j; } } if (k > i) { struct bwb_command t; memcpy(&t, &(bwb_cmdtable[i]), sizeof(struct bwb_command)); memcpy(&(bwb_cmdtable[i]), &(bwb_cmdtable[k]), sizeof(struct bwb_command)); memcpy(&(bwb_cmdtable[k]), &t, sizeof(struct bwb_command)); } } IsSorted = TRUE; } } void SortAllFunctions(void) { static int IsSorted = FALSE; bwx_DEBUG(__FUNCTION__); if (IsSorted == FALSE) { int i; for (i = 0; i < NUM_FUNCTIONS - 1; i++) { int j; int k; k = i; for (j = i + 1; j < NUM_FUNCTIONS; j++) { int n; n = strcasecmp(bwb_prefuncs[j].Name, bwb_prefuncs[k].Name); if (n < 0) { k = j; } else if (n == 0) { if (bwb_prefuncs[j].ParameterCount < bwb_prefuncs[k].ParameterCount) { k = j; } } } if (k > i) { struct bwb_function t; memcpy(&t, &(bwb_prefuncs[i]), sizeof(struct bwb_function)); memcpy(&(bwb_prefuncs[i]), &(bwb_prefuncs[k]), sizeof(struct bwb_function)); memcpy(&(bwb_prefuncs[k]), &t, sizeof(struct bwb_function)); } } IsSorted = TRUE; } } void DumpAllCommandUniqueID(void) { register int i; char tbuf[BasicStringLengthMax + 1]; bwx_DEBUG(__FUNCTION__); prn_lprintf("/* COMMANDS */\n"); /* run through the command table and print comand #define */ for (i = 0; i < NUM_COMMANDS; i++) { char *Syntax; char UniqueID[BasicNameLengthMax + 1]; CommandUniqueID(i, UniqueID); Syntax = bwb_cmdtable[i].name; sprintf(tbuf, "#define %-30s %3d /* %-30s */\n", UniqueID, i + 1, Syntax); prn_lprintf(tbuf); } sprintf(tbuf, "#define NUM_COMMANDS %d\n", i); prn_lprintf(tbuf); } static void ProcessEscapeChars(const char *Input, char *Output) { int n; bwx_DEBUG(__FUNCTION__); n = 0; while (*Input != '\0') { switch (*Input) { case '\n': *Output = '\\'; Output++; *Output = 'n'; Output++; break; case '\t': *Output = '\\'; Output++; *Output = 't'; Output++; break; case '\"': *Output = '\\'; Output++; *Output = '"'; Output++; break; default: *Output = *Input; Output++; break; } Input++; *Output = '\0'; n++; if (n > 60) { *Output = '\"'; Output++; *Output = '\n'; Output++; *Output = '\"'; Output++; *Output = '\0'; n = 0; } } } void DumpAllCommandTableDefinitions(void) { /* generate bwd_cmd.c */ int i; bwx_DEBUG(__FUNCTION__); prn_lprintf("/* COMMAND TABLE */\n\n"); prn_lprintf("#include \"bwbasic.h\"\n\n"); prn_lprintf("struct bwb_command bwb_cmdtable[ NUM_COMMANDS ] =\n"); prn_lprintf("{\n"); /* run through the command table and print comand #define */ for (i = 0; i < NUM_COMMANDS; i++) { char tbuf[BasicStringLengthMax + 1]; prn_lprintf("{\n"); prn_lprintf(" "); CommandUniqueID(i, tbuf); prn_lprintf(tbuf); prn_lprintf(", /* UniqueID */\n"); prn_lprintf(" "); prn_lprintf("\""); ProcessEscapeChars(bwb_cmdtable[i].Syntax, tbuf); prn_lprintf(tbuf); prn_lprintf("\""); prn_lprintf(", /* Syntax */\n"); prn_lprintf(" "); prn_lprintf("\""); ProcessEscapeChars(bwb_cmdtable[i].Description, tbuf); prn_lprintf(tbuf); prn_lprintf("\""); prn_lprintf(", /* Description */\n"); prn_lprintf(" "); prn_lprintf("\""); prn_lprintf(bwb_cmdtable[i].name); prn_lprintf("\""); prn_lprintf(", /* Name */\n"); prn_lprintf(" "); CommandOptionVersion(i, tbuf); prn_lprintf(tbuf); prn_lprintf(" /* OptionVersionBitmask */\n"); prn_lprintf("},\n"); } prn_lprintf("};\n\n"); } void DumpAllCommandSwitchStatement(void) { int i; bwx_DEBUG(__FUNCTION__); /* run through the command table and print comand #define */ prn_lprintf("/* SWITCH */\n"); prn_lprintf("struct bwb_line *bwb_vector( struct bwb_line *l )\n"); prn_lprintf("{\n"); prn_lprintf(" "); prn_lprintf("struct bwb_line *r;\n"); prn_lprintf(" "); prn_lprintf("switch( l->cmdnum )\n"); prn_lprintf(" "); prn_lprintf("{\n"); for (i = 0; i < NUM_COMMANDS; i++) { char tbuf[BasicNameLengthMax + 1]; prn_lprintf(" "); prn_lprintf("case "); CommandUniqueID(i, tbuf); prn_lprintf(tbuf); prn_lprintf(":\n"); prn_lprintf(" "); prn_lprintf(" "); prn_lprintf("r = "); CommandVector(i, tbuf); prn_lprintf(tbuf); prn_lprintf("( l );\n"); prn_lprintf(" "); prn_lprintf(" "); prn_lprintf("break;\n"); } prn_lprintf(" "); prn_lprintf("default:\n"); prn_lprintf(" "); prn_lprintf(" "); prn_lprintf("sprintf( bwb_ebuf, \"in bwb_vector(), INTERNAL ERROR: %d not in switch\", l->cmdnum );\n"); prn_lprintf(" "); prn_lprintf(" "); prn_lprintf("bwb_error( bwb_ebuf );\n"); prn_lprintf(" "); prn_lprintf(" "); prn_lprintf("r = l;\n"); prn_lprintf(" "); prn_lprintf(" "); prn_lprintf("break;\n"); prn_lprintf(" "); prn_lprintf("}\n"); prn_lprintf(" "); prn_lprintf("return r;\n"); prn_lprintf("}\n"); } void DumpOneCommandSyntax(int n, int lp) { char tbuf[BasicStringLengthMax + 1]; bwx_DEBUG(__FUNCTION__); if (n < 0 || n >= NUM_COMMANDS) { return; } /* NAME */ { sprintf(tbuf, " SYNTAX: %s\n", bwb_cmdtable[n].Syntax); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } } /* DESCRIPTION */ { sprintf(tbuf, "DESCRIPTION: %s\n", bwb_cmdtable[n].Description); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } } /* COMPATIBILITY */ if (lp) { int i; sprintf(tbuf, " VERSIONS:\n"); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } for (i = 0; i < NUM_VERSIONS; i++) { char X; if (bwb_cmdtable[n].OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask) { /* SUPPORTED */ X = 'X'; } else { /* NOT SUPPORTED */ X = '_'; } sprintf(tbuf, " [%c] %s\n", X, bwb_vertable[i].Name); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } } } } void DumpAllCommandSyntax(void) { /* for the C maintainer */ int n; bwx_DEBUG(__FUNCTION__); for (n = 0; n < NUM_COMMANDS; n++) { prn_lprintf("------------------------------------------------------------\n"); DumpOneCommandSyntax(n, TRUE); } prn_lprintf("------------------------------------------------------------\n"); } void DumpAllCommandHtmlTable(void) { /* generate bwd_cmd.htm */ int i; int j; bwx_DEBUG(__FUNCTION__); /* LEGEND */ prn_lprintf("

LEGEND


\n"); prn_lprintf("\n"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("\n"); for (j = 0; j < NUM_VERSIONS; j++) { prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("\n"); } prn_lprintf("
"); prn_lprintf(""); prn_lprintf("ID"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("NAME"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("DESCRIPTION"); prn_lprintf(""); prn_lprintf("
"); prn_lprintf(bwb_vertable[j].ID); prn_lprintf(""); prn_lprintf(bwb_vertable[j].Name); prn_lprintf(""); prn_lprintf(bwb_vertable[j].Description); prn_lprintf("
\n"); prn_lprintf("
\n"); /* DETAILS */ prn_lprintf("

DETAILS


\n"); prn_lprintf("\n"); prn_lprintf(""); prn_lprintf(""); for (j = 0; j < NUM_VERSIONS; j++) { prn_lprintf(""); } prn_lprintf("\n"); /* run through the command table and print comand -vs- OPTION VERSION */ for (i = 0; i < NUM_COMMANDS; i++) { prn_lprintf(""); prn_lprintf(""); for (j = 0; j < NUM_VERSIONS; j++) { prn_lprintf(""); } prn_lprintf("\n"); } prn_lprintf("
"); prn_lprintf(""); prn_lprintf("COMMAND"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf(bwb_vertable[j].ID); prn_lprintf(""); prn_lprintf("
"); prn_lprintf(bwb_cmdtable[i].name); prn_lprintf(""); if (bwb_cmdtable[i].OptionVersionBitmask & bwb_vertable[j].OptionVersionBitmask) { prn_lprintf("X"); } else { prn_lprintf(" "); } prn_lprintf("
\n"); prn_lprintf("\n"); } struct bwb_line * bwb_HELP(struct bwb_line * l) { /* HELP ... */ int n; char tbuf[BasicStringLengthMax + 1]; int Found; char * C; bwx_DEBUG(__FUNCTION__); Found = FALSE; C = l->buffer; C += l->position; strcpy( tbuf, C ); C = strchr( tbuf, OptionCommentChar ); if( C != NULL ) { *C = '\0'; } /* RTRIM$ */ C = tbuf; if (*C != 0) { /* not an empty line, so remove one (or more) trailing spaces */ char *E; E = strchr(tbuf, 0); E--; while (E >= tbuf && *E == ' ') { *E = 0; E--; } } /* EXACT match */ for (n = 0; n < NUM_COMMANDS; n++) { if (strcasecmp(bwb_cmdtable[n].name, tbuf) == 0) { prn_xprintf("------------------------------------------------------------\n"); DumpOneCommandSyntax(n, FALSE); Found = TRUE; } } for (n = 0; n < NUM_FUNCTIONS; n++) { if (strcasecmp(bwb_prefuncs[n].Name, tbuf) == 0) { prn_xprintf("------------------------------------------------------------\n"); DumpOneFunctionSyntax(n, FALSE); Found = TRUE; } } if (Found == FALSE) { /* PARTIAL match */ int Length; Length = strlen(tbuf); for (n = 0; n < NUM_COMMANDS; n++) { if (strncasecmp(bwb_cmdtable[n].name, tbuf, Length) == 0) { if (Found == FALSE) { prn_xprintf("The following topics are a partial match:\n"); } prn_xprintf(bwb_cmdtable[n].name); prn_xprintf("\t"); Found = TRUE; } } for (n = 0; n < NUM_FUNCTIONS; n++) { if (strncasecmp(bwb_prefuncs[n].Name, tbuf, Length) == 0) { if (Found == FALSE) { prn_xprintf("The following topics are a partial match:\n"); } prn_xprintf(bwb_prefuncs[n].Name); prn_xprintf("\t"); Found = TRUE; } } if (Found == TRUE) { /* match */ prn_xprintf("\n"); } } if (Found == FALSE) { /* NO match */ prn_xprintf("No help found.\n"); } adv_eos(l->buffer, &(l->position)); return bwb_zline(l); } int NumberValueCheck(unsigned long ParameterTests, BasicNumberType X) { BasicNumberType XR; /* rounded value */ bwx_DEBUG(__FUNCTION__); /* check for invalid numeric value */ if (isnan(X)) { /* INTERNAL ERROR */ return -1; } /* VALID NUMERIC VALUE */ XR = rint(X); ParameterTests &= 0x0000000F; switch (ParameterTests) { case P1ERR: { /* INTERNAL ERROR */ return -1; } break; case P1ANY: if (XR < -DBL_MAX || XR > DBL_MAX) { /* ERROR */ return -1; } else { /* OK */ return 0; } case P1BYT: if (XR < 0 || XR > UCHAR_MAX) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1INT: if (XR < SHRT_MIN || XR > SHRT_MAX) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1LNG: if (XR < LONG_MIN || XR > LONG_MAX) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1CUR: if (XR < LONG_MIN || XR > LONG_MAX) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1FLT: if (X < -FLT_MAX || X > FLT_MAX) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1DBL: if (X < -DBL_MAX || X > DBL_MAX) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1DEV: /* BasicFileNumberMax must be <= INT16_MAX */ if (XR < 0 || XR > BasicFileNumberMax) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1LEN: /* BasicStringLengthMax must be <= INT16_MAX */ if (XR < 0 || XR > BasicStringLengthMax) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1POS: /* BasicStringLengthMax must be <= INT16_MAX */ if (XR < 1 || XR > BasicStringLengthMax) { /* ERROR */ return -1; } else { /* OK */ return 0; } break; case P1COM: /* Number of COMx: ports must be <= INT16_MAX */ if (XR == 1 || XR == 2 || XR == 3 || XR == 4) { /* OK */ return 0; } break; case P1LPT: /* Number of LPTx: ports must be <= INT16_MAX */ if (XR == 0 || XR == 1 || XR == 2 || XR == 3) { /* OK */ return 0; } break; case P1GTZ: if (X > 0) { /* OK */ return 0; } break; case P1GEZ: if (X >= 0) { /* OK */ return 0; } break; case P1NEZ: if (X != 0) { /* OK */ return 0; } break; } /* ERROR */ return -1; } int StringLengthCheck(unsigned long ParameterTests, int s) { bwx_DEBUG(__FUNCTION__); /* check for invalid string length */ if (s < 0 || s > BasicStringLengthMax) { /* INTERNAL ERROR */ return -1; } /* VALID STRING LENGTH */ ParameterTests &= 0x0000000F; switch (ParameterTests) { case P1ERR: { /* INTERNAL ERROR */ return -1; } break; case P1ANY: { /* OK */ return 0; } break; case P1BYT: if (s >= sizeof(BasicByteType)) { /* OK */ return 0; } break; case P1INT: if (s >= sizeof(BasicIntegerType)) { /* OK */ return 0; } break; case P1LNG: if (s >= sizeof(BasicLongType)) { /* OK */ return 0; } break; case P1CUR: if (s >= sizeof(BasicCurrencyType)) { /* OK */ return 0; } break; case P1FLT: if (s >= sizeof(BasicSingleType)) { /* OK */ return 0; } break; case P1DBL: if (s >= sizeof(BasicDoubleType)) { /* OK */ return 0; } break; case P1DEV: case P1LEN: case P1POS: case P1GEZ: case P1GTZ: case P1NEZ: { /* ERROR */ return -1; } break; } /* ERROR */ return -1; } void FunctionDefinitionCheck(struct bwb_function * f) { /* function definition check -- look for obvious errors */ char bwb_ebuf[BasicStringLengthMax + 1]; bwx_DEBUG(__FUNCTION__); /* sanity check */ if (f->ParameterCount == PNONE) { /* function has NO parameters */ if (f->ParameterTypes == PNONE) { /* OK */ } else { /* oops */ sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTypes <%s>\n", f->Name); prn_xprintf(bwb_ebuf); } if (f->ParameterTests == PNONE) { /* OK */ } else { /* oops */ sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s>\n", f->Name); prn_xprintf(bwb_ebuf); } } else { /* function HAS parameters */ int i; unsigned long ParameterTests; ParameterTests = f->ParameterTests; for (i = 0; i < f->ParameterCount; i++) { /* sanity check this parameter */ unsigned long thischeck; thischeck = ParameterTests & 0x0000000F; /* verify parameter check */ if (f->ParameterTypes & (1 << i)) { /* STRING */ if (thischeck >= P1ANY && thischeck <= P1DBL) { /* OK */ } else { /* oops */ sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s> parameter %d\n", f->Name, i + 1); prn_xprintf(bwb_ebuf); } } else { /* NUMBER */ if (thischeck >= P1ANY && thischeck <= P1NEZ) { /* OK */ } else { /* oops */ sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s> parameter %d\n", f->Name, i + 1); prn_xprintf(bwb_ebuf); } } ParameterTests = ParameterTests >> 4; } if (ParameterTests != 0) { /* oops */ sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s> parameter %d\n", f->Name, i + 1); prn_xprintf(bwb_ebuf); } } } void FunctionUniqueID(struct bwb_function * f, char *UniqueID) { /* generate the function's UniqueID */ /* manual fixup required for duplicates */ char *D; /* location of $ */ char NumVar; char StrVar; bwx_DEBUG(__FUNCTION__); NumVar = 'X'; StrVar = 'A'; /* F_ */ strcpy(UniqueID, "F_"); /* NAME */ strcat(UniqueID, f->Name); D = strchr(UniqueID, BasicStringSuffix); if (D == NULL) { /* NOT FOUND */ } else { /* FOUND */ *D = 0; /* remove it */ } /* PARAMETERS */ if (f->ParameterCount == PNONE) { /* function has NO parameters */ } else { /* function HAS parameters */ int i; unsigned int ParameterTypes; /* unsigned long ParameterTests; */ ParameterTypes = f->ParameterTypes; /* ParameterTests = f->ParameterTests; */ for (i = 0; i < f->ParameterCount; i++) { char VarName[BasicNameLengthMax + 1]; /* sanity check this parameter */ /* unsigned long thischeck; thischeck = * ParameterTests & 0x0000000F; */ /* verify parameter check */ if (ParameterTypes & 1) { /* STRING */ sprintf(VarName, "_%c", StrVar); StrVar++; } else { /* NUMBER */ sprintf(VarName, "_%c", NumVar); NumVar++; } strcat(UniqueID, VarName); ParameterTypes = ParameterTypes >> 1; /* ParameterTests = ParameterTests >> 4; */ } } /* RETURN TYPE */ switch (f->ReturnType) { case STRING: strcat(UniqueID, "_S"); break; case NUMBER: strcat(UniqueID, "_N"); break; default: strcat(UniqueID, "_INTERNAL ERROR"); break; } /* fixup illegal characters, "DEF FN" "BLOAD:", "CLOAD*" */ { char *P; P = UniqueID; while (*P) { if (isalnum(*P)) { /* OK */ } else { /* FIXUP */ *P = '_'; } P++; } } } void FunctionSyntax(struct bwb_function * f, char *Syntax) { /* generate the function's Syntax */ char NumVar; char StrVar; bwx_DEBUG(__FUNCTION__); NumVar = 'X'; StrVar = 'A'; /* RETURN TYPE */ switch (f->ReturnType) { case STRING: strcpy(Syntax, "S$ = "); break; case NUMBER: strcpy(Syntax, "N = "); break; default: strcpy(Syntax, "INTERNAL ERROR = "); break; } /* NAME */ strcat(Syntax, f->Name); /* PARAMETERS */ if (f->ParameterCount == PNONE) { /* function has NO parameters */ } else { /* function HAS parameters */ int i; unsigned int ParameterTypes; /* unsigned long ParameterTests; */ ParameterTypes = f->ParameterTypes; /* ParameterTests = f->ParameterTests; */ switch (f->ReturnType) { case STRING: strcat(Syntax, "( "); break; case NUMBER: strcat(Syntax, "( "); break; default: strcat(Syntax, "INTERNAL ERROR( "); break; } for (i = 0; i < f->ParameterCount; i++) { char VarName[BasicNameLengthMax + 1]; /* sanity check this parameter */ /* unsigned long thischeck; thischeck = * ParameterTests & 0x0000000F; */ if (i > 0) { strcat(Syntax, ", "); } /* verify parameter check */ if (ParameterTypes & 1) { /* STRING */ sprintf(VarName, "%c$", StrVar); StrVar++; } else { /* NUMBER */ sprintf(VarName, "%c", NumVar); NumVar++; } strcat(Syntax, VarName); ParameterTypes = ParameterTypes >> 1; /* ParameterTests = ParameterTests >> 4; */ } switch (f->ReturnType) { case STRING: strcat(Syntax, " )"); break; case NUMBER: strcat(Syntax, " )"); break; default: strcat(Syntax, " INTERNAL ERROR)"); break; } } } void DumpAllFuctionUniqueID(void) { /* for the C maintainer */ char tbuf[BasicStringLengthMax + 1]; int i; bwx_DEBUG(__FUNCTION__); prn_lprintf("/* FUNCTIONS */\n"); for (i = 0; i < NUM_FUNCTIONS; i++) { char UniqueID[BasicStringLengthMax + 1]; char Syntax[BasicStringLengthMax + 1]; FunctionUniqueID(&(bwb_prefuncs[i]), UniqueID); FunctionSyntax(&(bwb_prefuncs[i]), Syntax); sprintf(tbuf, "#define %-30s %3d /* %-30s */\n", UniqueID, i + 1, Syntax); prn_lprintf(tbuf); } sprintf(tbuf, "#define NUM_FUNCTIONS %d\n", i); prn_lprintf(tbuf); } void DumpAllFunctionSwitch(void) { /* for the C maintainer */ int i; bwx_DEBUG(__FUNCTION__); prn_lprintf("/* SWITCH */\n"); prn_lprintf("switch( UniqueID )\n"); prn_lprintf("{\n"); for (i = 0; i < NUM_FUNCTIONS; i++) { char tbuf[BasicStringLengthMax + 1]; prn_lprintf("case "); FunctionUniqueID(&(bwb_prefuncs[i]), tbuf); prn_lprintf(tbuf); prn_lprintf(":\n"); prn_lprintf(" break;\n"); } prn_lprintf("}\n"); } static const char *ParameterRangeID[16] = { "P%dERR", "P%dANY", "P%dBYT", "P%dINT", "P%dLNG", "P%dCUR", "P%dFLT", "P%dDBL", "P%dDEV", "P%dLEN", "P%dPOS", "P%dCOM", "P%dLPT", "P%dGTZ", "P%dGEZ", "P%dNEZ", }; static const char *NumberVariableRange[16] = { /* P1ERR */ " PARAMETER: %c is a number, INTERNAL ERROR", /* P1ANY */ " PARAMETER: %c is a number", /* P1BYT */ " PARAMETER: %c is a number, [0,255]", /* P1INT */ " PARAMETER: %c is a number, [MININT,MAXINT]", /* P1LNG */ " PARAMETER: %c is a number, [MINLNG,MAXLNG]", /* P1CUR */ " PARAMETER: %c is a number, [MINCUR,MAXCUR]", /* P1FLT */ " PARAMETER: %c is a number, [MINFLT,MAXFLT]", /* P1DBL */ " PARAMETER: %c is a number, [MINDBL,MAXDBL]", /* P1DEV */ " PARAMETER: %c is a number, [1,MAXDEV]", /* P1LEN */ " PARAMETER: %c is a number, [0,MAXLEN]", /* P1POS */ " PARAMETER: %c is a number, [1,MAXLEN]", /* P1COM */ " PARAMETER: %c is a number, [1,4]", /* P1LPT */ " PARAMETER: %c is a number, [0,3]", /* P1GTZ */ " PARAMETER: %c is a number, > 0", /* P1GEZ */ " PARAMETER: %c is a number, >= 0", /* P1NEZ */ " PARAMETER: %c is a number, <> 0", }; static const char *StringVariableRange[16] = { /* P1ERR */ " PARAMETER: %c$ is a string, INTERNAL ERROR", /* P1ANY */ " PARAMETER: %c$ is a string, LEN >= 0", /* P1BYT */ " PARAMETER: %c$ is a string, LEN >= 1", /* P1INT */ " PARAMETER: %c$ is a string, LEN >= sizeof(INT)", /* P1LNG */ " PARAMETER: %c$ is a string, LEN >= sizeof(LNG)", /* P1CUR */ " PARAMETER: %c$ is a string, LEN >= sizeof(CUR)", /* P1FLT */ " PARAMETER: %c$ is a string, LEN >= sizeof(FLT)", /* P1DBL */ " PARAMETER: %c$ is a string, LEN >= sizeof(DBL)", /* P1DEV */ " PARAMETER: %c$ is a string, RESERVED", /* P1LEN */ " PARAMETER: %c$ is a string, RESERVED", /* P1POS */ " PARAMETER: %c$ is a string, RESERVED", /* P1COM */ " PARAMETER: %c$ is a string, RESERVED", /* P1LPT */ " PARAMETER: %c$ is a string, RESERVED", /* P1GTZ */ " PARAMETER: %c$ is a string, RESERVED", /* P1GEZ */ " PARAMETER: %c$ is a string, RESERVED", /* P1NEZ */ " PARAMETER: %c$ is a string, RESERVED", }; void DumpAllFuctionTableDefinitions(void) { /* generate bwd_fun.c */ int n; bwx_DEBUG(__FUNCTION__); prn_lprintf("/* FUNCTION TABLE */\n\n"); prn_lprintf("#include \"bwbasic.h\"\n\n"); prn_lprintf("struct bwb_function bwb_prefuncs[ NUM_FUNCTIONS ] =\n"); prn_lprintf("{\n"); for (n = 0; n < NUM_FUNCTIONS; n++) { int i; int j; char tbuf[BasicStringLengthMax + 1]; char UniqueID[BasicStringLengthMax + 1]; char Syntax[BasicStringLengthMax + 1]; struct bwb_function *f; f = &(bwb_prefuncs[n]); FunctionUniqueID(f, UniqueID); FunctionSyntax(f, Syntax); prn_lprintf("{\n"); sprintf(tbuf, " %s, /* UniqueID */\n", UniqueID); prn_lprintf(tbuf); sprintf(tbuf, " \"%s\", /* Syntax */\n", Syntax); prn_lprintf(tbuf); prn_lprintf(" "); prn_lprintf("\""); ProcessEscapeChars(f->Description, tbuf); prn_lprintf(tbuf); prn_lprintf("\""); prn_lprintf(", /* Description */\n"); sprintf(tbuf, " \"%s\", /* Name */\n", f->Name); prn_lprintf(tbuf); switch (f->ReturnType) { case STRING: sprintf(tbuf, " %s, /* ReturnType */\n", "STRING"); break; case NUMBER: sprintf(tbuf, " %s, /* ReturnType */\n", "NUMBER"); break; default: sprintf(tbuf, " %s, /* ReturnType */\n", "INTERNAL ERROR"); break; } prn_lprintf(tbuf); sprintf(tbuf, " %d, /* ParameterCount */\n", f->ParameterCount); prn_lprintf(tbuf); if (f->ParameterCount == 0) { sprintf(tbuf, " %s, /* ParameterTypes */\n", "PNONE"); prn_lprintf(tbuf); sprintf(tbuf, " %s, /* ParameterTests */\n", "PNONE"); prn_lprintf(tbuf); } else { strcpy(tbuf, " "); for (i = 0; i < f->ParameterCount; i++) { int ParameterTypes; ParameterTypes = f->ParameterTypes >> i; ParameterTypes &= 0x1; if (i > 0) { strcat(tbuf, " | "); } if (ParameterTypes) { sprintf(strchr(tbuf, 0), "P%dSTR", i + 1); } else { sprintf(strchr(tbuf, 0), "P%dNUM", i + 1); } } strcat(tbuf, ", /* ParameterTypes */\n"); prn_lprintf(tbuf); strcpy(tbuf, " "); for (i = 0; i < f->ParameterCount; i++) { unsigned int ParameterTests; ParameterTests = f->ParameterTests >> (i * 4); ParameterTests &= 0xF; if (i > 0) { strcat(tbuf, " | "); } sprintf(strchr(tbuf, 0), ParameterRangeID[ParameterTests], i + 1); } strcat(tbuf, ", /* ParameterTests */\n"); prn_lprintf(tbuf); } sprintf(tbuf, " %s, /* NextPointer */\n", "NULL"); prn_lprintf(tbuf); strcpy(tbuf, " "); j = 0; for (i = 0; i < NUM_VERSIONS; i++) { if (f->OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask) { if (j > 0) { strcat(tbuf, " | "); } strcat(tbuf, bwb_vertable[i].ID); j++; } } strcat(tbuf, " /* OptionVersionBitmask */\n"); prn_lprintf(tbuf); prn_lprintf("},\n"); } prn_lprintf("};\n\n"); } void DumpOneFunctionSyntax(int n, int lp) { char tbuf[BasicStringLengthMax + 1]; struct bwb_function *f; bwx_DEBUG(__FUNCTION__); if (n < 0 || n >= NUM_FUNCTIONS) { return; } f = &(bwb_prefuncs[n]); /* NAME */ { char UniqueID[BasicStringLengthMax + 1]; char Syntax[BasicStringLengthMax + 1]; FunctionUniqueID(f, UniqueID); FunctionSyntax(f, Syntax); sprintf(tbuf, " SYNTAX: %s\n", Syntax); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } } /* PARAMETERS */ if (f->ParameterCount == PNONE) { /* function has NO parameters */ } else { /* function HAS parameters */ int i; unsigned int ParameterTypes; unsigned long ParameterTests; char NumVar; char StrVar; ParameterTypes = f->ParameterTypes; ParameterTests = f->ParameterTests; NumVar = 'X'; StrVar = 'A'; for (i = 0; i < f->ParameterCount; i++) { /* sanity check this parameter */ unsigned long thischeck; thischeck = ParameterTests & 0x0000000F; /* verify parameter check */ if (ParameterTypes & 1) { /* STRING */ sprintf(tbuf, StringVariableRange[thischeck], StrVar); StrVar++; } else { /* NUMBER */ sprintf(tbuf, NumberVariableRange[thischeck], NumVar); NumVar++; } if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } if (lp) { prn_lprintf("\n"); } else { prn_xprintf("\n"); } ParameterTypes = ParameterTypes >> 1; ParameterTests = ParameterTests >> 4; } } /* DESCRIPTION */ { sprintf(tbuf, "DESCRIPTION: %s\n", f->Description); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } } /* COMPATIBILITY */ if (lp) { int i; sprintf(tbuf, " VERSIONS:\n"); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } for (i = 0; i < NUM_VERSIONS; i++) { char X; if (f->OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask) { /* SUPPORTED */ X = 'X'; } else { /* NOT SUPPORTED */ X = '_'; } sprintf(tbuf, " [%c] %s\n", X, bwb_vertable[i].Name); if (lp) { prn_lprintf(tbuf); } else { prn_xprintf(tbuf); } } } } void DumpAllFuctionSyntax(void) { /* for the C maintainer */ int n; bwx_DEBUG(__FUNCTION__); for (n = 0; n < NUM_FUNCTIONS; n++) { prn_lprintf("------------------------------------------------------------\n"); DumpOneFunctionSyntax(n, TRUE); } prn_lprintf("------------------------------------------------------------\n"); } void DumpAllFunctionHtmlTable(void) { /* generate bwd_cmd.htm */ int i; int j; bwx_DEBUG(__FUNCTION__); /* LEGEND */ prn_lprintf("

LEGEND


\n"); prn_lprintf("\n"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("\n"); for (j = 0; j < NUM_VERSIONS; j++) { prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("\n"); } prn_lprintf("
"); prn_lprintf(""); prn_lprintf("ID"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("NAME"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf("DESCRIPTION"); prn_lprintf(""); prn_lprintf("
"); prn_lprintf(bwb_vertable[j].ID); prn_lprintf(""); prn_lprintf(bwb_vertable[j].Name); prn_lprintf(""); prn_lprintf(bwb_vertable[j].Description); prn_lprintf("
\n"); prn_lprintf("
\n"); /* DETAILS */ prn_lprintf("

DETAILS


\n"); prn_lprintf("\n"); prn_lprintf(""); prn_lprintf(""); for (j = 0; j < NUM_VERSIONS; j++) { prn_lprintf(""); } prn_lprintf("\n"); /* run through the command table and print comand -vs- OPTION VERSION */ for (i = 0; i < NUM_FUNCTIONS; i++) { prn_lprintf(""); prn_lprintf(""); for (j = 0; j < NUM_VERSIONS; j++) { prn_lprintf(""); } prn_lprintf("\n"); } prn_lprintf("
"); prn_lprintf(""); prn_lprintf("FUNCTION"); prn_lprintf(""); prn_lprintf(""); prn_lprintf(""); prn_lprintf(bwb_vertable[j].ID); prn_lprintf(""); prn_lprintf("
"); prn_lprintf(bwb_prefuncs[i].Name); prn_lprintf(""); if (bwb_prefuncs[i].OptionVersionBitmask & bwb_vertable[j].OptionVersionBitmask) { prn_lprintf("X"); } else { prn_lprintf(" "); } prn_lprintf("
\n"); prn_lprintf("\n"); } struct bwb_line * bwb_DEF_SUB(struct bwb_line * l) { /* user is executing a function, such as 100 COS X, as though it were * a command */ /* this applies to both intrinsic functions and user defined * functions and subroutines */ /* no special parsing is required, just add () around the parameters */ char Buffer[BasicStringLengthMax + 1]; int i; char *C; char *F; bwx_DEBUG(__FUNCTION__); i = 0; C = l->buffer; C += l->position; F = Buffer; while (*C == ' ') { /* skip leading spaces before name */ C++; } /* these should not happen */ if (*C == '\0' || *C == OptionCommentChar) { bwb_error("bwb_DEF_SUB, INTERNAL null"); return bwb_zline(l); } if (!isalpha(*C)) { bwb_error("bwb_DEF_SUB, INTERNAL isalpha"); return bwb_zline(l); } if (strlen(C) + 2 > BasicStringLengthMax) { bwb_error("Ibwb_DEF_SUB, NTERNAL strlen"); return bwb_zline(l); } /* OK */ while (isalpha(*C)) { /* copy command name */ *F = *C; F++; C++; } if (*C == BasicStringSuffix) { /* copy command name */ *F = *C; F++; C++; } while (*C == ' ') { /* skip trailing spaces after name */ C++; } /* left paren */ *F = '('; F++; while (*C != '\0') { /* copy parameters */ if( *C == '"' ) { /* quoted string */ { /* leading quote */ *F = *C; F++; C++; } while( *C != '\0' && *C != '"' ) { /* copy inclosed string */ *F = *C; F++; C++; } if( *C == '"' ) { /* trailing quote */ *F = *C; F++; C++; } } else if( *C == OptionCommentChar ) { /* comment */ while( *C != '\0' ) { /* skip to end of line */ C++; } } else if( *C == ' ' ) { /* skip unquoted spaces */ C++; } else { /* normal char, so copy it */ *F = *C; F++; C++; } } /* right paren */ *F = ')'; F++; /* terminate */ *F = '\0'; /* Call the expression interpreter to evaluate the function */ /* prn_xprintf(Buffer); */ bwb_exp(Buffer, FALSE, &i); if (ERROR_PENDING) { /* prn_xprintf("oops"); */ } adv_eos(l->buffer, &(l->position)); return bwb_zline(l); } /*************************************************************** FUNCTION: bwb_zline() DESCRIPTION: This function is called at the exit from Bywater BASIC command functions. It returns a pointer to the current position in the current line. ***************************************************************/ struct bwb_line * bwb_zline(struct bwb_line * l) { bwx_DEBUG(__FUNCTION__); /* skip trailing spaces */ while (l->buffer[l->position] == ' ') l->position++; /* skip trailing comment */ if (l->buffer[l->position] == OptionCommentChar) { /* COMMENT */ while (l->buffer[l->position] != 0) l->position++; } /* usually, but NOT always, we are at the end of the line */ return l; } /*************************************************************** FUNCTION: fnc_fncs() DESCRIPTION: This C function is used for debugging purposes; it prints a list of all defined functions. SYNTAX: FNCS ***************************************************************/ struct bwb_line * bwb_FNCS(struct bwb_line * l) { register int n; int t; bwx_DEBUG(__FUNCTION__); prn_iprintf("BWBASIC FUNCTIONS AVAILABLE:\n"); /* run through the command table and print comand names */ t = 0; for (n = 0; n < NUM_FUNCTIONS; ++n) { prn_iprintf(bwb_prefuncs[n].Name); if (t < 4) { prn_iprintf("\t"); t++; } else { prn_iprintf("\n"); t = 0; } } if (t > 0) { prn_iprintf("\n"); } return bwb_zline(l); } struct bwb_line * bwb_MAINTAINER(struct bwb_line * l) { int ShowHelp; char tbuf[BasicStringLengthMax + 1]; bwx_DEBUG(__FUNCTION__); ShowHelp = TRUE; adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "CMDS") == 0) { adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "HTML") == 0) { DumpAllCommandHtmlTable(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "ID") == 0) { DumpAllCommandUniqueID(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "MANUAL") == 0) { DumpAllCommandSyntax(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "SWITCH") == 0) { DumpAllCommandSwitchStatement(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "TABLE") == 0) { DumpAllCommandTableDefinitions(); ShowHelp = FALSE; } } else if (strcasecmp(tbuf, "FNCS") == 0) { adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "HTML") == 0) { DumpAllFunctionHtmlTable(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "ID") == 0) { DumpAllFuctionUniqueID(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "MANUAL") == 0) { DumpAllFuctionSyntax(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "SWITCH") == 0) { DumpAllFunctionSwitch(); ShowHelp = FALSE; } else if (strcasecmp(tbuf, "TABLE") == 0) { DumpAllFuctionTableDefinitions(); ShowHelp = FALSE; } } else if (strcasecmp(tbuf, "DEBUG") == 0) { adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "ON") == 0) { MaintainerDebugOn = TRUE; ShowHelp = FALSE; } else if (strcasecmp(tbuf, "OFF") == 0) { MaintainerDebugOn = FALSE; ShowHelp = FALSE; } } else if (strcasecmp(tbuf, "STACK") == 0) { /* * dump the current execution stack, * Leftmost is the * bottom, * Rigthmost is the top. */ int i; for (i = 0; i <= CURTASK exsc; i++) { struct bwb_line *l; l = CURTASK excs[i].line; if (l != NULL) { char LineNumber[32]; sprintf(LineNumber, "%d:", l->number); prn_xprintf(LineNumber); } } prn_xprintf("\n"); ShowHelp = FALSE; } if (ShowHelp == TRUE) { prn_xprintf("MAINTAINER is a command intended for the C maintainer.\n"); prn_xprintf("It is used when making global changes to the internal tables.\n"); prn_xprintf("This command is subject to change without notice, at any time.\n"); prn_xprintf("Currently, the valid statements are:\n\n"); prn_xprintf("MAINTAINER CMDS HTML ' dump COMMAND vs VERSION as HTML table\n"); prn_xprintf("MAINTAINER CMDS ID ' dump COMMAND #defines for UniqueID\n"); prn_xprintf("MAINTAINER CMDS MANUAL ' dump COMMAND manual\n"); prn_xprintf("MAINTAINER CMDS SWITCH ' dump COMMAND switch(UniqueID)\n"); prn_xprintf("MAINTAINER CMDS TABLE ' dump COMMAND table\n"); prn_xprintf("MAINTAINER FNCS HTML ' dump FUNCTION vs VERSION as HTML table\n"); prn_xprintf("MAINTAINER FNCS ID ' dump FUNCTION #defines for UniqueID\n"); prn_xprintf("MAINTAINER FNCS MANUAL ' dump FUNCTION manual\n"); prn_xprintf("MAINTAINER FNCS SWITCH ' dump FUNCTION switch(UniqueID)\n"); prn_xprintf("MAINTAINER FNCS TABLE ' dump FUNCTION table\n"); prn_xprintf("MAINTAINER DEBUG ON ' enable degug tracing\n"); prn_xprintf("MAINTAINER DEBUG OFF ' disable degug tracing\n"); prn_xprintf("MAINTAINER STACK ' dump the BASIC stack\n"); } return bwb_zline(l); } /*************************************************************** FUNCTION: fnc_init() DESCRIPTION: This command initializes the function linked list, placing all predefined functions in the list. ***************************************************************/ int fnc_init(int task) { register int n; struct bwb_function *f; bwx_DEBUG(__FUNCTION__); strcpy(LOCALTASK fnc_start.Name, "FNC_START"); LOCALTASK fnc_start.ReturnType = 'X'; strcpy(LOCALTASK fnc_end.Name, "FNC_END"); LOCALTASK fnc_end.ReturnType = 'x'; LOCALTASK fnc_end.next = &LOCALTASK fnc_end; f = &LOCALTASK fnc_start; /* now go through each of the preestablished functions and set up * links between them; from this point the program address the * functions only as a linked list (not as an array) */ for (n = 0; n < NUM_FUNCTIONS; ++n) { f->next = &(bwb_prefuncs[n]); f = f->next; FunctionDefinitionCheck(f); } /* link the last pointer to the end; this completes the list */ f->next = &LOCALTASK fnc_end; return TRUE; } void fnc_add_deffn(struct fslte * F) { struct bwb_function *f; struct bwb_function *n; bwx_DEBUG(__FUNCTION__); /* get memory for fslt structure */ if ((f = CALLOC(1, sizeof(struct bwb_function), "fnc_add_deffn")) == NULL) { bwb_error("in fnc_add_deffn(): failed to get memory for bwb_function structure"); return; } strcpy(f->Name, F->name); if (strchr(F->name, BasicStringSuffix) != NULL) { f->ReturnType = STRING; } else { f->ReturnType = NUMBER; } f->ReturnType |= (F->line->cmdnum & 0x00FF) << 8; /* UniqueID is a line * number */ f->UniqueID = F->line->number; f->ParameterCount = F->ParameterCount; /* 0..32, 0xFF == VARIANT */ f->ParameterTypes = F->ParameterTypes; f->OptionVersionBitmask = OptionVersion; /* establish linkages */ n = CURTASK fnc_start.next; CURTASK fnc_start.next = f; f->next = n; } static struct fslte * fslt_find_by_line(int LineNumber) { struct fslte *f; bwx_DEBUG(__FUNCTION__); /* SEARCH */ for (f = CURTASK fslt_start.next; f != &CURTASK fslt_end; f = f->next) { if (f->line->number == LineNumber) { /* FOUND */ return f; } } /* NOT FOUND */ return NULL; } /* The generic handler for user defined functions. When called by exp_function(), f->id will be set to the line number of a specific DEF USR. */ struct bwb_variable * fnc_deffn(int argc, struct bwb_variable * argv, int unique_id) { struct fslte *f; struct bwb_variable *v; struct bwb_variable *argn; int i; struct bwb_line *call_line; int save_elevel; bwx_DEBUG(__FUNCTION__); /* initialize the variable if necessary */ f = fslt_find_by_line(unique_id); /* these errors should not occur */ if (f == NULL) { sprintf(bwb_ebuf, "INTERNAL ERROR, f == NULL"); bwb_error(bwb_ebuf); return NULL; } if (argv == NULL) { sprintf(bwb_ebuf, "INTERNAL ERROR, argv == NULL"); bwb_error(bwb_ebuf); return NULL; } if (f->ParameterCount == 0xFF) { /* VARIANT */ } else if (argc != f->ParameterCount) { sprintf(bwb_ebuf, "INTERNAL ERROR, argc != f->ParameterCount"); bwb_error(bwb_ebuf); return NULL; } if (f->ParameterCount == 0xFF) { /* VARIANT */ f->local_variable = argv; } else if (argc > 0) { v = f->local_variable; argn = argv; for (i = 0; i < argc; i++) { argn = argn->next; if (v == NULL) { sprintf(bwb_ebuf, "INTERNAL ERROR, v == NULL"); bwb_error(bwb_ebuf); return NULL; } if (argn == NULL) { sprintf(bwb_ebuf, "INTERNAL ERROR, argn == NULL"); bwb_error(bwb_ebuf); return NULL; } if (v->type != argn->type) { sprintf(bwb_ebuf, "INTERNAL ERROR, v->type != argn->type"); bwb_error(bwb_ebuf); return NULL; } /* NEW ... */ if (strlen(v->name) > 0) { /* FIXME: this is a hack - the variable type * should be determined when the variable is * created */ char *E; char e; int IsError; IsError = 0; E = strchr(v->name, '\0'); E--; e = *E; /* sprintf( bwb_ebuf, "LAST CHAR is %c, TYPE * is %c", e, v->type ); puts( bwb_ebuf ); */ /* so the following code is easier to read * and maintain */ #define PARAM_NUMBER *argn->memnum #define PARAM_LENGTH argn->memstr->length #define PARAM_BUFFER argn->memstr->sbuffer /* check actual values versus formal * parameter type */ switch (e) { case BasicStringSuffix: IsError = StringLengthCheck(P1ANY, PARAM_LENGTH); break; case BasicDoubleSuffix: IsError = NumberValueCheck(P1DBL, PARAM_NUMBER); break; case BasicSingleSuffix: IsError = NumberValueCheck(P1FLT, PARAM_NUMBER); break; case BasicCurrencySuffix: IsError = NumberValueCheck(P1CUR, PARAM_NUMBER); break; case BasicLongSuffix: IsError = NumberValueCheck(P1LNG, PARAM_NUMBER); break; case BasicIntegerSuffix: IsError = NumberValueCheck(P1INT, PARAM_NUMBER); break; } if (IsError != 0) { sprintf(bwb_ebuf, "ILLEGAL FUUNCTION CALL: %s(%s)", f->name, v->name); bwb_Warning_InvalidParameter(bwb_ebuf); return argv; } } /* ...NEW */ v = v->next; } } /* OK */ call_line = f->line; /* line to call for function */ call_line->position = f->startpos; if (call_line->cmdnum == C_DEF) { adv_ws(call_line->buffer, &call_line->position); if (call_line->buffer[call_line->position] != '=') { sprintf(bwb_ebuf, "*** INTERNAL ERROR #%d (%s) ***", 5, "call_line->buffer[ ] != '='"); bwb_error(bwb_ebuf); return argv; } call_line->position++; /* NOTE - we skip past the '=' sign */ } /* PUSH STACK */ save_elevel = CURTASK exsc; bwb_incexec(); bwb_setexec(call_line, call_line->position, EXEC_FUNCTION); /* create variable chain */ if (f->ParameterCount == 0xFF) { /* VARIANT */ } else if (argc > 0) { struct bwb_variable *source = NULL; /* source variable */ source = f->local_variable; argn = argv; for (i = 0; i < argc; i++) { argn = argn->next; /* copy the name */ strcpy(argn->name, source->name); source = source->next; } } if (call_line->cmdnum == C_DEF) { struct exp_ese *e; /* the function return variable is hidden */ CURTASK excs[CURTASK exsc].local_variable = argv->next; e = bwb_exp(call_line->buffer, FALSE, &call_line->position); bwb_etov(argv, e); /* break variable chain */ CURTASK excs[CURTASK exsc].local_variable = NULL; /* POP STACK */ bwb_decexec(); } else { /* the function return variable is visible */ CURTASK excs[CURTASK exsc].local_variable = argv; /* exp_isfn() uses these to determine use of the function * name as a variable */ CURTASK excs[CURTASK exsc].LoopTopLine = call_line; CURTASK excs[CURTASK exsc].LoopBottomLine = call_line->OtherLine; /* execute until function returns */ while (CURTASK exsc > save_elevel) { bwb_execline(); } } if (f->ParameterCount == 0xFF) { /* VARIANT */ f->local_variable = NULL; } return argv; } /*************************************************************** FUNCTION: fnc_find() DESCRIPTION: This C function attempts to locate a BASIC function with the specified name. If successful, it returns a pointer to the C structure for the BASIC function, if not successful, it returns NULL. ***************************************************************/ struct bwb_function * fnc_find(char *name) { struct bwb_function *f; bwx_DEBUG(__FUNCTION__); if (strlen(name) == 0) { return NULL; } for (f = CURTASK fnc_start.next; f != &CURTASK fnc_end; f = f->next) { if (OptionVersion & f->OptionVersionBitmask) if (strcasecmp(f->Name, name) == 0) { return f; } } /* search has failed: return NULL */ return NULL; } struct bwb_function * fnc_find_exact(char *name, int ParameterCount, int ParameterTypes) { struct bwb_function *f; bwx_DEBUG(__FUNCTION__); for (f = CURTASK fnc_start.next; f != &CURTASK fnc_end; f = f->next) { if (OptionVersion & f->OptionVersionBitmask) { if (f->ParameterCount == ParameterCount) { if (f->ParameterTypes == ParameterTypes) { if (strcasecmp(f->Name, name) == 0) { return f; } } } } } /* search has failed: return NULL */ return NULL; } struct bwb_variable * var_free(struct bwb_variable * v) { /* // Release all the memory associated with a specific variable. // * This function returns NULL, so you can use it like this: // v * = var_new(...); // ... // v = var_free( v ); */ bwx_DEBUG(__FUNCTION__); if (v != NULL) { if (v->next != NULL) { /* This allows variable chains to be easily released. */ v->next = var_free(v->next); } /* cleanup this variable */ if (v->memnum != NULL) { FREE(v->memnum, "var_free"); v->memnum = NULL; } if (v->memstr != NULL) { int j; for (j = 0; j < v->array_units; ++j) { if (v->memstr[j].sbuffer != NULL) { FREE(v->memstr[j].sbuffer, "var_free"); v->memstr[j].sbuffer = NULL; } v->memstr[j].rab = FALSE; v->memstr[j].length = 0; } FREE(v->memstr, "var_free"); v->memstr = NULL; } if (v->array_sizes != NULL) { FREE(v->array_sizes, "var_free"); v->array_sizes = NULL; } if (v->array_pos != NULL) { FREE(v->array_pos, "var_free"); v->array_pos = NULL; } } return NULL; } struct bwb_function * fnc_find_by_id(int unique_id) { /* NOTE: This should ONLY search the INTRINSIC functions, not USER * functions */ int i; bwx_DEBUG(__FUNCTION__); for (i = 0; i < NUM_FUNCTIONS; i++) { if (bwb_prefuncs[i].UniqueID == unique_id) { /* FOUND */ return &(bwb_prefuncs[i]); } } /* NOT FOUND */ return NULL; } struct bwb_line * bwb_CHANGE(struct bwb_line * l) { /* * CHANGE A$ TO X * CHANGE X TO A$ */ char tbuf[BasicStringLengthMax + 1]; struct bwb_variable *v = NULL; struct bwb_variable *A = NULL; struct bwb_variable *X = NULL; int IsStringToArray = FALSE; bwx_DEBUG(__FUNCTION__); if (OptionFlags & OPTION_BASE_ONE) { bwb_error("CHANGE is only valid for OPTION BASE 0"); return bwb_zline(l); } /* get 1st variable */ adv_ws(l->buffer, &(l->position)); bwb_getvarname(l->buffer, tbuf, &(l->position)); v = var_find(tbuf); if (v == NULL) { bwb_error(err_syntax); return bwb_zline(l); } if (v->type == STRING) { A = v; IsStringToArray = TRUE; } else { /* variable MUST be an array */ if ((v->dimensions == 1) && (v->array_sizes[0] == 1)) { bwb_error(err_syntax); return bwb_zline(l); } X = v; IsStringToArray = FALSE; } /* get "TO" */ adv_ws(l->buffer, &(l->position)); adv_element(l->buffer, &(l->position), tbuf); if (strcasecmp(tbuf, "TO") != 0) { bwb_error(err_syntax); return bwb_zline(l); } /* get 2nd variable */ adv_ws(l->buffer, &(l->position)); bwb_getvarname(l->buffer, tbuf, &(l->position)); v = var_find(tbuf); if (v == NULL) { bwb_error(err_syntax); return bwb_zline(l); } if (v->type == STRING) { A = v; if (IsStringToArray == TRUE) { bwb_error(err_syntax); return bwb_zline(l); } } else { /* variable MUST be an array */ if ((v->dimensions == 1) && (v->array_sizes[0] == 1)) { bwb_error(err_syntax); return bwb_zline(l); } X = v; if (IsStringToArray == FALSE) { bwb_error(err_syntax); return bwb_zline(l); } } if (IsStringToArray) { /* CHANGE A$ TO X */ int i; int n; char *a; BasicNumberType *x; unsigned long t; if (A->memstr == NULL) { bwb_error("String Variable not allocated"); return bwb_zline(l); } if (A->memstr->sbuffer == NULL) { bwb_error("String Variable not allocated"); return bwb_zline(l); } /* variable storage is a mess, we bypass that tradition here. */ t = 1; for (n = 0; n < X->dimensions; n++) { t *= X->array_sizes[n]; } if (t <= A->memstr->length) { bwb_error("Numeric Array too small"); return bwb_zline(l); } n = A->memstr->length; a = A->memstr->sbuffer; x = X->memnum; *x = n; x++; for (i = 0; i < n; i++) { char C; BasicNumberType V; C = *a; V = C; *x = V; x++; a++; } } else { /* CHANGE X TO A$ */ int i; int n; char *a; BasicNumberType *x; unsigned long t; if (A->memstr == NULL) { bwb_error("String Variable not allocated"); return bwb_zline(l); } if (A->memstr->sbuffer == NULL) { bwb_error("String Variable not allocated"); return bwb_zline(l); } /* variable storage is a mess, we bypass that tradition here. */ t = 1; for (n = 0; n < X->dimensions; n++) { t *= X->array_sizes[n]; } if (t <= 1) { bwb_error("Numeric Array to small"); return bwb_zline(l); } if (t > BasicStringLengthMax) { bwb_error("Numeric Array too large"); return bwb_zline(l); } /* n = A->memstr->length; */ a = A->memstr->sbuffer; x = X->memnum; n = *x; x++; for (i = 0; i < n; i++) { char C; BasicNumberType V; V = *x; C = V; *a = C; x++; a++; } } return bwb_zline(l); } /* EOF */