|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539 |
- /***************************************************************
-
- bwbasic.c Main Program File
- for Bywater BASIC Interpreter
-
- Copyright (c) 1993, Ted A. Campbell
- Bywater Software
-
- "I was no programmer, neither was I a
- programmer's son; but I was an herdman
- and a gatherer of sycomore fruit."
- - Amos 7:14b AV, slightly adapted
-
- 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). */
- /*---------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <ctype.h>
- #include <math.h>
-
- #include "bwbasic.h"
- #include "bwb_mes.h"
-
- #if HAVE_SIGNAL
- #include <signal.h>
- #endif
-
- #if HAVE_LONGJUMP
- #include <setjmp.h>
- #endif
-
- char *bwb_ebuf; /* error buffer */
- static char *read_line;
- int bwb_trace = FALSE;
- FILE *errfdevice = stderr; /* output device for error messages */
-
- #if HAVE_LONGJUMP
- jmp_buf mark;
- #endif
-
- static int program_run = 0; /* has the command-line program been run? */
- int bwb_curtask = 0; /* current task */
-
- struct bwb_variable *ed; /* BWB.EDITOR$ variable */
- struct bwb_variable *fi; /* BWB.FILES$ variable */
- struct bwb_variable *pr; /* BWB.PROMPT$ variable */
- struct bwb_variable *im; /* BWB.IMPLEMENTATION$ variable */
- struct bwb_variable *co; /* BWB.COLORS variable */
-
- #if PARACT
- struct bwb_task *bwb_tasks[ TASKS ]; /* table of task pointers */
- #else
- char progfile[ MAXARGSIZE ]; /* program file */
- int rescan = TRUE; /* program needs to be rescanned */
- int number = 0; /* current line number */
- struct bwb_line *bwb_l; /* current line pointer */
- struct bwb_line bwb_start; /* starting line marker */
- struct bwb_line bwb_end; /* ending line marker */
- struct bwb_line *data_line; /* current line to read data */
- int data_pos = 0; /* position in data_line */
- struct bwb_variable var_start; /* variable list start marker */
- struct bwb_variable var_end; /* variable list end marker */
- struct bwb_function fnc_start; /* function list start marker */
- struct bwb_function fnc_end; /* function list end marker */
- struct fslte fslt_start; /* function-sub-label lookup table start marker */
- struct fslte fslt_end; /* function-sub-label lookup table end marker */
- int exsc = -1; /* EXEC stack counter */
- int expsc = 0; /* expression stack counter */
- int xtxtsc = 0; /* eXecute TeXT stack counter */
- struct exse *excs; /* EXEC stack */
- struct exp_ese *exps; /* Expression stack */
- struct xtxtsl *xtxts; /* Execute Text stack */
- #endif
-
- /* Prototypes for functions visible only to this file */
-
- #if ANSI_C
- extern int is_ln( char *buffer );
- #else
- extern int is_ln();
- #endif
-
- /***************************************************************
-
- FUNCTION: bwb_init()
-
- DESCRIPTION: This function initializes bwBASIC.
-
- ***************************************************************/
-
- void
- #if ANSI_C
- bwb_init( int argc, char **argv )
- #else
- bwb_init( argc, argv )
- int argc;
- char **argv;
- #endif
- {
- static FILE *input = NULL;
- register int n;
- #if PROFILE
- struct bwb_variable *v;
- #endif
- #if REDIRECT_STDERR
- FILE *newerr;
- #endif
- #if PROFILE
- FILE *profile;
- #endif
- #if PARACT
- #else
- static char start_buf[] = "\0";
- static char end_buf[] = "\0";
- #endif
-
- #if INTENSIVE_DEBUG
- prn_xprintf( stderr, "Memory Allocation Statistics:\n" );
- prn_xprintf( stderr, "----------------------------\n" );
- #if PARACT
- sprintf( bwb_ebuf, "task structure: %ld bytes\n",
- (long) sizeof( struct bwb_task ) );
- prn_xprintf( stderr, bwb_ebuf );
- getchar();
- #endif
- #endif
-
- /* set all task pointers to NULL */
-
- #if PARACT
-
- for ( n = 0; n < TASKS; ++n )
- {
- bwb_tasks[ n ] = NULL;
- }
-
- #else
-
- /* Memory allocation */
- /* eXecute TeXT stack */
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( xtxts = CALLOC( XTXTSTACKSIZE, sizeof( struct xtxtsl ), "bwb_init") ) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_init(): failed to find memory for xtxts" );
- #else
- bwb_error( err_getmem );
- #endif
- }
-
- /* expression stack */
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( exps = CALLOC( ESTACKSIZE, sizeof( struct exp_ese ), "bwb_init") ) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_init(): failed to find memory for exps" );
- #else
- bwb_error( err_getmem );
- #endif
- }
-
- /* EXEC stack */
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( excs = CALLOC( EXECLEVELS, sizeof( struct exse ), "bwb_init") ) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_init(): failed to find memory for excs" );
- #else
- bwb_error( err_getmem );
- #endif
- }
-
- /* initialize tables of variables, functions */
-
- bwb_start.number = 0;
- bwb_start.next = &bwb_end;
- bwb_end.number = MAXLINENO + 1;
- bwb_end.next = &bwb_end;
- bwb_start.buffer = start_buf;
- bwb_end.buffer = end_buf;
- data_line = &bwb_start;
- data_pos = 0;
- exsc = -1;
- expsc = 0;
- xtxtsc = 0;
- bwb_start.position = 0;
- bwb_l = &bwb_start;
-
- var_init( 0 );
- fnc_init( 0 );
- fslt_init( 0 );
-
- #endif
-
- /* character buffers */
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( bwb_ebuf = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_init") ) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_init(): failed to find memory for bwb_ebuf" );
- #else
- bwb_error( err_getmem );
- #endif
- }
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( read_line = CALLOC( MAXREADLINESIZE + 1, sizeof(char), "bwb_init") ) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_init(): failed to find memory for read_line" );
- #else
- bwb_error( err_getmem );
- #endif
- }
-
- #if PARACT
-
- /* request task 0 as current (base) task */
-
- bwb_curtask = bwb_newtask( 0 );
-
- if ( bwb_curtask == -1 )
- {
- return; /* error message has already been called*/
- }
-
- #endif
-
- #if TEST_BSTRING
- for ( n = 0; n < ESTACKSIZE; ++n )
- {
- sprintf( CURTASK exps[ n ].sval.name, "<Exp stack bstring %d>", n );
- }
- #endif
-
- /* assign memory for the device table */
-
- #if COMMON_CMDS
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( dev_table = CALLOC( DEF_DEVICES, sizeof( struct dev_element ), "bwb_init") ) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_init(): failed to find memory for dev_table" );
- #else
- bwb_error( err_getmem );
- #endif
- bwx_terminate();
- }
-
- /* initialize all devices to DEVMODE_AVAILABLE */
-
- for ( n = 0; n < DEF_DEVICES; ++n )
- {
- dev_table[ n ].mode = DEVMODE_AVAILABLE;
- dev_table[ n ].reclen = -1;
- dev_table[ n ].cfp = NULL;
- dev_table[ n ].buffer = NULL;
- dev_table[ n ].width = DEF_WIDTH;
- dev_table[ n ].col = 1;
- }
- #endif /* COMMON_CMDS */
-
- /* initialize preset variables */
-
- ed = var_find( DEFVNAME_EDITOR );
- ed->preset = TRUE;
- ed->common = TRUE;
- str_ctob( var_findsval( ed, ed->array_pos ), DEF_EDITOR );
-
- fi = var_find( DEFVNAME_FILES );
- fi->preset = TRUE;
- fi->common = TRUE;
- str_ctob( var_findsval( fi, fi->array_pos ), DEF_FILES );
-
- pr = var_find( DEFVNAME_PROMPT );
- pr->preset = TRUE;
- pr->common = TRUE;
- str_ctob( var_findsval( pr, pr->array_pos ), PROMPT );
-
- im = var_find( DEFVNAME_IMPL );
- im->preset = TRUE;
- im->common = TRUE;
- str_ctob( var_findsval( im, im->array_pos ), IMP_IDSTRING );
-
- co = var_find( DEFVNAME_COLORS );
- co->preset = TRUE;
- co->common = TRUE;
- * var_findnval( co, co->array_pos ) = (bnumber) DEF_COLORS;
-
- /* Signon message */
-
- bwx_signon();
-
- /* Redirect stderr if specified */
-
- #if REDIRECT_STDERR
- newerr = freopen( ERRFILE, "w", stderr );
- if ( newerr == NULL )
- {
- sprintf( bwb_ebuf, "Failed to redirect error messages to file <%s>\n",
- ERRFILE );
- errfdevice = stdout;
- prn_xprintf( errfdevice, bwb_ebuf );
- }
- else
- {
- sprintf( bwb_ebuf, "NOTE: Error messages are redirected to file <%s>\n",
- ERRFILE );
- prn_xprintf( errfdevice, bwb_ebuf );
- errfdevice = stderr;
- }
- #else
- errfdevice = stdout;
- #endif
-
- /* if there is a profile.bas, execute it */
-
- #if PROFILE
- if ( ( profile = fopen( PROFILENAME, "r" )) != NULL )
- {
- bwb_fload( profile ); /* load profile */
- bwb_run( &CURTASK bwb_start ); /* run profile */
-
- /* profile must be run immediately, not by scheduler */
-
- while ( CURTASK exsc > -1 )
- {
- bwb_execline();
- }
-
- /* mark all profiled variables as preset */
-
- for ( v = CURTASK var_start.next; v != &CURTASK var_end; v = v->next )
- {
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_init(): marked variable <%s> preset TRUE",
- v->name );
- bwb_debug( bwb_ebuf );
- #endif
-
- v->preset = TRUE;
- }
-
- bwb_new( &CURTASK bwb_start ); /* remove profile from memory */
- }
- #endif
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in main(): Ready to save jump MARKER" );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* set a buffer for jump: program execution returns to this point
- in case of a jump (error, interrupt, or finish program) */
-
- #if INTERACTIVE
-
- #if HAVE_SIGNAL
- signal( SIGINT, break_mes );
- #endif
-
- #if HAVE_LONGJUMP
- setjmp( mark );
- #endif
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_init(): Return from jump MARKER, program run <%d>",
- program_run + 1 );
- bwb_debug( bwb_ebuf );
- getchar();
- #endif
-
- /* if INTERACTIVE is FALSE, then we must have a program file */
-
- #else
-
- if ( argc < 2 )
- {
- bwb_error( err_noprogfile );
- }
-
- #endif /* INTERACTIVE */
-
- /* check to see if there is a program file: but do this only the first
- time around! */
-
- ++program_run;
- if (( argc > 1 ) && ( program_run == 1 ))
- {
- strcpy( CURTASK progfile, argv[ 1 ] ); /* JBV */
- if ( ( input = fopen( CURTASK progfile, "r" )) == NULL ) /* JBV */
- {
- strcat( CURTASK progfile, ".bas" );
- if ( ( input = fopen( CURTASK progfile, "r" )) == NULL )
- {
- CURTASK progfile[ 0 ] = 0;
- sprintf( bwb_ebuf, err_openfile, argv[ 1 ] );
- bwb_error( bwb_ebuf );
- }
- }
- if ( input != NULL )
- {
- /* strcpy( CURTASK progfile, argv[ 1 ] ); */ /* Removed by JBV */
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in main(): progfile is <%s>.", CURTASK progfile );
- bwb_debug( bwb_ebuf );
- #endif
-
- bwb_fload( input );
- bwb_run( &CURTASK bwb_start );
- }
- }
-
- }
-
- /***************************************************************
-
- FUNCTION: bwb_interact()
-
- DESCRIPTION: This function gets a line from the user
- and processes it.
-
- ***************************************************************/
-
- #if INTERACTIVE
- int
- #if ANSI_C
- bwb_interact( void )
- #else
- bwb_interact()
- #endif
- {
- char tbuf[ MAXSTRINGSIZE + 1 ]; /* JBV */
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_interact(): ready to read from keyboard" );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* take input from keyboard */
-
- bwb_gets( read_line );
- bwb_stripcr( read_line ); /* JBV */
-
- /* If there is no line number, execute the line as received */
-
- if ( is_ln( read_line ) == FALSE )
- {
- bwb_xtxtline( read_line );
- }
-
- /*-----------------------------------------------------------------*/
- /* Another possibility: if read_line is a numeric constant, delete */
- /* the indicated line number (JBV) */
- /*-----------------------------------------------------------------*/
- else if ( is_numconst( read_line ) == TRUE )
- {
- strcpy(tbuf, read_line);
- sprintf(read_line, "delete %s\0", tbuf);
- bwb_xtxtline( read_line );
- }
-
- /* If there is a line number, add the line to the file in memory */
-
- else
- {
- bwb_ladd( read_line, TRUE );
- #if INTENSIVE_DEBUG
- bwb_debug( "Return from bwb_ladd()" );
- #endif
- }
-
- return TRUE;
-
- }
-
- #endif /* INTERACTIVE == TRUE */
-
- /***************************************************************
-
- FUNCTION: bwb_fload()
-
- DESCRIPTION: This function loads a BASIC program
- file into memory given a FILE pointer.
-
- ***************************************************************/
-
- int
- #if ANSI_C
- bwb_fload( FILE *file )
- #else
- bwb_fload( file )
- FILE *file;
- #endif
- {
-
- while ( feof( file ) == FALSE )
- {
- read_line[ 0 ] = '\0';
- fgets( read_line, MAXREADLINESIZE, file );
- if ( file == stdin )
- {
- * prn_getcol( stdout ) = 1; /* reset column */
- }
- bwb_stripcr( read_line );
-
- /* be sure that this is not EOF with a NULL line */
-
- if (( feof( file ) == FALSE ) || ( strlen( read_line ) > 0 ))
- {
- bwb_ladd( read_line, FALSE );
- }
- }
-
- /* close file stream */
-
- fclose( file );
-
- return TRUE;
- }
-
- /***************************************************************
-
- FUNCTION: bwb_ladd()
-
- DESCRIPTION: This function adds a new line (in the
- buffer) to the program in memory.
-
- ***************************************************************/
-
- int
- #if ANSI_C
- bwb_ladd( char *buffer, int replace )
- #else
- bwb_ladd( buffer, replace )
- char *buffer;
- int replace;
- #endif
- {
- struct bwb_line *l, *previous, *p;
- static char *s_buffer;
- static int init = FALSE;
- static int prev_num = 0;
- char *newbuffer;
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): add line <%s>",
- buffer );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* get memory for temporary buffer if necessary */
-
- if ( init == FALSE )
- {
- init = TRUE;
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( s_buffer = CALLOC( (size_t) MAXSTRINGSIZE + 1, sizeof( char ), "bwb_ladd" )) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_ladd(): failed to find memory for s_buffer" );
- #else
- bwb_error( err_getmem );
- #endif
- return FALSE;
- }
- }
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): s_buffer initialized " );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* get memory for this line */
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( l = (struct bwb_line *) CALLOC( (size_t) 1, sizeof( struct bwb_line ), "bwb_ladd")) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in bwb_ladd(): failed to find memory for new line" );
- #else
- bwb_error( err_getmem );
- #endif
- return FALSE;
- }
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): got memory." );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* note that line is not yet marked and the program must be rescanned */
-
- l->marked = FALSE;
- CURTASK rescan = TRUE; /* program needs to be scanned again */
- l->xnum = FALSE;
-
- /* get the first element and test for a line number */
-
- adv_element( buffer, &( l->position ), s_buffer );
-
- /* set line number in line structure */
-
- if ( is_numconst( s_buffer ) == TRUE )
- {
-
- l->number = atoi( s_buffer );
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): line is numbered, number is <%d>",
- l->number );
- bwb_debug( bwb_ebuf );
- #endif
-
- prev_num = l->number;
- l->xnum = TRUE;
- ++( l->position );
- newbuffer = &( buffer[ l->position ] );
-
- /* allocate memory and assign buffer to line buffer */
-
- ln_asbuf( l, newbuffer );
-
- }
-
- /* There is not a line number */
-
- else
- {
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): line is not numbered, using prev <%d>",
- prev_num );
- bwb_debug( bwb_ebuf );
- #endif
-
- newbuffer = buffer;
-
- /* allocate memory and assign buffer to line buffer */
-
- ln_asbuf( l, newbuffer );
-
- l->xnum = FALSE;
- l->number = prev_num;
- }
-
- /* find the place of the current line */
-
- for ( previous = &CURTASK bwb_start; previous != &CURTASK bwb_end; previous = previous->next )
- {
-
- /* replace a previously existing line */
-
- if ( ( l->xnum == (char) TRUE ) /* Better recast this one (JBV) */
- && ( previous->number == l->number )
- && ( replace == TRUE )
- )
- {
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): writing to previous number <%d>",
- l->number );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* allocate memory and assign buffer to line buffer */
-
- ln_asbuf( previous, newbuffer );
-
- /* free the current line */
-
- /* Revised to FREE pass-thru calls by JBV */
- /* if (l->buffer != NULL) FREE( l->buffer, "bwb_ladd" ); */
- /* FREE( l, "bwb_ladd" ); */
- bwb_freeline( l ); /* JBV */
-
- /* and return */
-
- return TRUE;
-
- }
-
- /* add after previously existing line: this is to allow unnumbered
- lines that follow in sequence after a previously numbered line */
-
- else if (( previous->number == l->number )
- && ( replace == FALSE )
- )
- {
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): adding doubled number <%d>",
- l->number );
- bwb_debug( bwb_ebuf);
- #endif
-
- /* if there are multiple instances of this particular line number,
- then it is incumbent upon us to find the very last one */
-
- for ( p = previous; p->number == l->number; p = p->next )
- {
- #if INTENSIVE_DEBUG
- bwb_debug( "in bwb_ladd(): advancing..." );
- #endif
- previous = p;
- }
-
- l->next = previous->next;
- previous->next = l;
- return TRUE;
- }
-
- /* add a new line */
-
- else if ( ( previous->number < l->number )
- && ( previous->next->number > l->number ))
- {
- l->next = previous->next;
- previous->next = l;
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): added new line <%d> buffer <%s>",
- l->number, l->buffer );
- bwb_debug( bwb_ebuf );
- #endif
-
- return TRUE;
- }
-
- }
-
- /* attempt to link line number has failed; free memory */
-
- /* Revised to FREE pass-thru calls by JBV */
- /* if (l->buffer != NULL) FREE( l->buffer, "bwb_ladd" ); */
- /* FREE( l, "bwb_ladd" ); */
- bwb_freeline( l ); /* JBV */
-
- sprintf( bwb_ebuf, ERR_LINENO );
- bwb_error( bwb_ebuf );
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_ladd(): attempt to add line has failed" );
- bwb_debug( bwb_ebuf );
- #endif
-
- return FALSE;
-
- }
-
- /***************************************************************
-
- FUNCTION: bwb_xtxtline()
-
- DESCRIPTION: This function executes a text line, i.e.,
- places it in memory and then relinquishes
- control.
-
- ***************************************************************/
-
- struct bwb_line *
- #if ANSI_C
- bwb_xtxtline( char *buffer )
- #else
- bwb_xtxtline( buffer )
- char *buffer;
- #endif
- {
- struct bwb_line *c;
- char *p;
- int loop;
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_xtxtline(): received <%s>", buffer );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* increment xtxt stack counter */
-
- if ( CURTASK xtxtsc >= XTXTSTACKSIZE )
- {
- sprintf( bwb_ebuf, "Exceeded maximum xtxt stack <%d>",
- CURTASK xtxtsc );
- return &CURTASK bwb_end;
- }
-
- ++CURTASK xtxtsc;
-
- /* advance past whitespace */
-
- p = buffer;
- loop = TRUE;
- while( loop == TRUE )
- {
-
- switch( *p )
- {
- case '\0': /* end of string */
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "Null command line received." );
- bwb_debug( bwb_ebuf );
- #endif
- --CURTASK xtxtsc;
- return &CURTASK bwb_end;
- case ' ': /* whitespace */
- case '\t':
- ++p;
- break;
- default:
- loop = FALSE;
- break;
- }
-
- }
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_xtxtline(): ready to get memory" );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* Removed by JBV (no longer needed, done by ln_asbuf) */
- /* if ( CURTASK xtxts[ CURTASK xtxtsc ].l.buffer != NULL )
- { */
- /* #if INTENSIVE_DEBUG */
- /* sprintf( bwb_ebuf, "in bwb_xtxtline(): freeing buffer memory" );
- bwb_debug( bwb_ebuf ); */
- /* #endif */
- /* Revised to FREE pass-thru call by JBV */
- /* FREE( CURTASK xtxts[ CURTASK xtxtsc ].l.buffer, "bwb_xtxtline" );
- } */
-
- /* copy the whole line to the line structure buffer */
-
- ln_asbuf( &( CURTASK xtxts[ CURTASK xtxtsc ].l ), buffer );
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_xtxtline(): copied to line buffer <%s>.",
- CURTASK xtxts[ CURTASK xtxtsc ].l.buffer );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* set line number in line structure */
-
- CURTASK xtxts[ CURTASK xtxtsc ].l.number = 0;
- CURTASK xtxts[ CURTASK xtxtsc ].l.marked = FALSE;
-
- /* execute the line as BASIC command line */
-
- CURTASK xtxts[ CURTASK xtxtsc ].l.next = &CURTASK bwb_end;
- c = &( CURTASK xtxts[ CURTASK xtxtsc ].l );
- c->position = 0;
-
- #if THEOLDWAY
- do
- {
- c = bwb_xline( c );
- }
-
- while( c != &CURTASK bwb_end );
- #endif
-
- bwb_incexec(); /* increment EXEC stack */
- bwb_setexec( c, 0, EXEC_NORM ); /* and set current line in it */
-
- /* decrement xtxt stack counter ??? */
-
- --CURTASK xtxtsc;
-
- return c;
-
- }
-
- /***************************************************************
-
- FUNCTION: bwb_incexec()
-
- DESCRIPTION: This function increments the EXEC
- stack counter.
-
- ***************************************************************/
-
- #if ANSI_C
- extern void
- bwb_incexec( void )
- {
- #else
- void
- bwb_incexec()
- {
- #endif
- ++CURTASK exsc;
-
- if ( CURTASK exsc >= EXECLEVELS )
- {
- --CURTASK exsc;
- #if PROG_ERRORS
- sprintf( bwb_ebuf, "in bwb_incexec(): incremented EXEC stack past max <%d>",
- EXECLEVELS );
- bwb_error( bwb_ebuf );
- #else
- bwb_error( err_overflow );
- #endif
- }
-
- CURTASK excs[ CURTASK exsc ].while_line = NULL;
- CURTASK excs[ CURTASK exsc ].wend_line = NULL;
- CURTASK excs[ CURTASK exsc ].n_cvs = 0;
- CURTASK excs[ CURTASK exsc ].local_variable = NULL;
-
- }
-
- /***************************************************************
-
- FUNCTION: bwb_decexec()
-
- DESCRIPTION: This function decrements the EXEC
- stack counter.
-
- ***************************************************************/
-
- #if ANSI_C
- extern void
- bwb_decexec( void )
- {
- #else
- void
- bwb_decexec()
- {
- #endif
-
- /* decrement the exec stack counter */
-
- --CURTASK exsc;
-
- if ( CURTASK exsc < -1 )
- {
- CURTASK exsc = -1;
- #if PROG_ERRORS
- sprintf( bwb_ebuf, "in bwb_decexec(): decremented EXEC stack past min <-1>" );
- bwb_error( bwb_ebuf );
- #else
- bwb_error( err_overflow );
- #endif
- }
-
- /* check for EXEC_ON and decrement recursively */
-
- if ( CURTASK excs[ CURTASK exsc ].code == EXEC_ON )
- {
-
- /* Revised to FREE pass-thru calls by JBV */
- /* FREE( CURTASK excs[ CURTASK exsc ].while_line->buffer, "bwb_decexec" ); */
- /* FREE( CURTASK excs[ CURTASK exsc ].while_line, "bwb_decexec" ); */
- bwb_freeline( CURTASK excs[ CURTASK exsc ].while_line ); /* JBV */
-
- bwb_decexec();
- }
-
- }
-
- /***************************************************************
-
- FUNCTION: bwb_setexec()
-
- DESCRIPTION: This function sets the line and position
- for the next call to bwb_execline();
-
- ***************************************************************/
-
- #if ANSI_C
- extern int
- bwb_setexec( struct bwb_line *l, int position, int code )
- {
- #else
- int
- bwb_setexec( l, position, code )
- struct bwb_line *l;
- int position;
- int code;
- {
- #endif
-
- CURTASK excs[ CURTASK exsc ].line = l;
- CURTASK excs[ CURTASK exsc ].position = position;
- CURTASK excs[ CURTASK exsc ].code = code;
-
- return TRUE;
-
- }
-
- /***************************************************************
-
- FUNCTION: bwb_mainloop()
-
- DESCRIPTION: This C function performs one iteration
- of the interpreter. In a non-preemptive
- scheduler, this function should be called
- by the scheduler, not by bwBASIC code.
-
- ***************************************************************/
-
- void
- #if ANSI_C
- bwb_mainloop( void )
- #else
- bwb_mainloop()
- #endif
- {
- if ( CURTASK exsc > -1 )
- {
- bwb_execline(); /* execute one line of program */
- }
- #if INTERACTIVE
- else
- {
- bwb_interact(); /* get user interaction */
- }
- #endif
- }
-
- /***************************************************************
-
- FUNCTION: bwb_execline()
-
- DESCRIPTION: This function executes a single line of
- a program in memory. This function is
- called by bwb_mainloop().
-
- ***************************************************************/
-
- void
- #if ANSI_C
- bwb_execline( void )
- #else
- bwb_execline()
- #endif
- {
- struct bwb_line *r, *l;
-
- l = CURTASK excs[ CURTASK exsc ].line;
-
- /* if the line is &CURTASK bwb_end, then break out of EXEC loops */
-
- if ( l == &CURTASK bwb_end )
- {
- CURTASK exsc = -1;
- return;
- }
-
- /* Check for wacko line numbers */
-
- #if INTENSIVE_DEBUG
- if ( l->number < -1 )
- {
- #if PROG_ERRORS
- sprintf( bwb_ebuf, "in bwb_execline(): received line number <%d> < -1",
- l->number );
- bwb_error( bwb_ebuf );
- #else
- bwb_error( err_syntax );
- #endif
- return;
- }
-
- if ( l->number > MAXLINENO )
- {
- #if PROG_ERRORS
- sprintf( bwb_ebuf, "in bwb_execline(): received line number <%d> > MAX <%d>",
- l->number, MAXLINENO );
- bwb_error( bwb_ebuf );
- #else
- bwb_error( err_syntax );
- #endif
- return;
- }
- #endif
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_execline(): buffer <%s>",
- &( l->buffer[ l->position ] ) );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* Print line number if trace is on */
-
- if ( bwb_trace == TRUE )
- {
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "[ %d ]", l->number );
- prn_xprintf( errfdevice, bwb_ebuf );
- #else
- if ( l->number > 0 )
- {
- sprintf( bwb_ebuf, "[ %d ]", l->number );
- prn_xprintf( errfdevice, bwb_ebuf );
- }
- #endif
- }
-
- /* Set current line for error/break handling */
-
- CURTASK number = l->number;
- CURTASK bwb_l = l;
-
- /* advance beyond whitespace */
-
- adv_ws( l->buffer, &( l->position ) );
-
- /* advance past segment delimiter and warn */
-
- #if MULTISEG_LINES
- if ( l->buffer[ l->position ] == ':' )
- {
- ++( l->position );
- adv_ws( l->buffer, &( l->position ) );
- }
- l->marked = FALSE;
- #else
- #if PROG_ERRORS
- if ( l->buffer[ l->position ] == ':' )
- {
- ++( l->position );
- adv_ws( l->buffer, &( l->position ) );
- sprintf( bwb_ebuf, "Enable MULTISEG_LINES for multi-segmented lines",
- VERSION );
- bwb_error( bwb_ebuf );
- }
- #endif
- #endif
-
- /* set positions in buffer */
-
- #if MULTISEG_LINES
- if ( ( l->marked != TRUE ) || ( l->position > l->startpos ))
- {
- line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
- &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
- l->marked = TRUE;
- }
- else
- {
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_execline(): line <%d> is already marked",
- l->number );
- bwb_debug( bwb_ebuf );
- #endif
- }
- l->position = l->startpos;
- #else /* not MULTISEG_LINES */
- line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
- &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
- if ( l->position < l->startpos )
- {
- l->position = l->startpos;
- }
- #endif
-
- /* if there is a BASIC command in the line, execute it here */
-
- if ( l->cmdnum > -1 )
- {
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_execline(): executing <%s>", l->buffer );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* execute the command vector */
-
- r = bwb_cmdtable[ l->cmdnum ].vector ( l );
-
- }
-
- /* No BASIC command; try to execute it as a shell command */
-
- #if COMMAND_SHELL
- else
- {
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "Breaking out to shell, line num <%d> buf <%s> cmd <%d> pos <%d>",
- l->number, &( l->buffer[ l->position ] ), l->cmdnum, l->position );
- bwb_debug( bwb_ebuf );
- getchar();
- #endif
-
- bwx_shell( l );
- bwb_setexec( l->next, 0, CURTASK excs[ CURTASK exsc ].code );
- return;
- }
-
- #else /* COMMAND_SHELL == FALSE */
-
- else
- {
- bwb_error( err_uc );
- }
-
- #endif
-
- /* check for end of line: if so, advance to next line and return */
-
- adv_ws( r->buffer, &( r->position ) );
- switch( r->buffer[ r->position ] )
- {
- case '\n':
- case '\r':
- case '\0':
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_execline(): detected end of line" );
- bwb_debug( bwb_ebuf );
- #endif
-
- r->next->position = 0;
- bwb_setexec( r->next, 0, CURTASK excs[ CURTASK exsc ].code );
- return; /* and return */
- }
-
- /* else reset with the value in r */
-
- bwb_setexec( r, r->position, CURTASK excs[ CURTASK exsc ].code );
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in bwb_execline(): exit setting line number <%d>",
- r->number );
- bwb_debug( bwb_ebuf );
- #endif
-
- }
-
- /***************************************************************
-
- FUNCTION: ln_asbuf()
-
- DESCRIPTION: This function allocates memory and copies
- a null-terminated string to a line buffer.
-
- ***************************************************************/
-
- int
- #if ANSI_C
- ln_asbuf( struct bwb_line *l, char *s )
- #else
- ln_asbuf( l, s )
- struct bwb_line *l;
- char *s;
- #endif
- {
-
- /* Reinstated by JBV */
- /* #if DONTDOTHIS */ /* but why not? */
- if ( l->buffer != NULL )
- {
- /* Revised to FREE pass-thru call by JBV */
- FREE( l->buffer, "ln_asbuf" );
- l->buffer = NULL; /* JBV */
- }
- /* #endif */
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( l->buffer = CALLOC( strlen( s ) + 2, sizeof( char ), "ln_asbuf") )
- == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in ln_asbuf(): failed to find memory for new line" );
- #else
- bwb_error( err_getmem );
- #endif
- return FALSE;
- }
-
- /* copy the whole line to the line structure buffer */
-
- strcpy( l->buffer, s );
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in ln_asbuf(): allocated buffer <%s>", l->buffer );
- bwb_debug( bwb_ebuf );
- #endif
-
- /* strip CR from the buffer */
-
- bwb_stripcr( l->buffer );
-
- #if INTENSIVE_DEBUG
- sprintf( bwb_ebuf, "in ln_asbuf(): stripped CRs" );
- bwb_debug( bwb_ebuf );
- #endif
-
- return TRUE;
-
- }
-
- /***************************************************************
-
- FUNCTION: bwb_gets()
-
- DESCRIPTION: This function reads a single line from
- the specified buffer.
-
- ***************************************************************/
-
- int
- #if ANSI_C
- bwb_gets( char *buffer )
- #else
- bwb_gets( buffer )
- char *buffer;
- #endif
- {
- struct bwb_variable *v;
- char tbuf[ MAXSTRINGSIZE + 1 ];
- #if PARACT
- char ubuf[ MAXSTRINGSIZE + 1 ];
- #endif
-
- CURTASK number = 0;
-
- v = var_find( DEFVNAME_PROMPT );
- str_btoc( tbuf, var_getsval( v ) );
- #if PARACT
- sprintf( ubuf, "TASK %d %s", bwb_curtask, tbuf );
- strcpy( tbuf, ubuf );
- #endif
-
- bwx_input( tbuf, buffer );
-
- return TRUE;
- }
-
- /***************************************************************
-
- FUNCTION: break_mes()
-
- DESCRIPTION: This function is called (a) by a SIGINT
- signal or (b) by error-handling routines.
- It prints an error message then calls
- break_handler() to handle the program
- interruption.
-
- ***************************************************************/
-
- void
- #if ANSI_C
- break_mes( int x )
- #else
- break_mes( x )
- int x;
- #endif
- {
- static char *tmp_buffer;
- static int init = FALSE;
-
- /* get memory for temporary buffer if necessary */
-
- if ( init == FALSE )
- {
- init = TRUE;
-
- /* Revised to CALLOC pass-thru call by JBV */
- if ( ( tmp_buffer = CALLOC( MAXSTRINGSIZE + 1, sizeof( char ), "break_mes")) == NULL )
- {
- #if PROG_ERRORS
- bwb_error( "in break_mes(): failed to find memory for tmp_buffer" );
- #else
- bwb_error( err_getmem );
- #endif
- }
- }
-
- CURTASK expsc = 0;
-
- sprintf( tmp_buffer, "\r%s %d\n", MES_BREAK, CURTASK number );
- prn_xprintf( errfdevice, tmp_buffer );
-
- break_handler();
-
- }
-
- /***************************************************************
-
- FUNCTION: break_handler()
-
- DESCRIPTION: This function is called by break_mes()
- and handles program interruption by break
- (or by the STOP command).
-
- ***************************************************************/
-
- void
- #if ANSI_C
- break_handler( void )
- #else
- break_handler()
- #endif
- {
-
- #if INTERACTIVE /* INTERACTIVE: reset counters and jump back to mark */
-
- /* reset all stack counters */
-
- CURTASK exsc = -1;
- CURTASK expsc = 0;
- CURTASK xtxtsc = 0;
- err_gosubl[ 0 ] = '\0';
-
- /* reset the break handler */
-
- #if HAVE_SIGNAL
- signal( SIGINT, break_mes );
- #endif
-
- #if HAVE_LONGJUMP
- longjmp( mark, -1 );
- #else /* HAVE_LONGJUMP = FALSE; no jump available; terminate */
- bwx_terminate();
- #endif
-
- #else /* nonINTERACTIVE: terminate immediately */
-
- bwx_terminate();
-
- #endif
-
- }
-
-
- /***************************************************************
-
- FUNCTION: is_ln()
-
- DESCRIPTION: This function determines whether a program
- line (in buffer) begins with a line number.
-
- ***************************************************************/
-
- int
- #if ANSI_C
- is_ln( char *buffer )
- #else
- is_ln( buffer )
- char *buffer;
- #endif
- {
- static int position;
-
- position = 0;
- adv_ws( buffer, &position );
- switch( buffer[ position ] )
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return TRUE;
- default:
- return FALSE;
- }
- }
-
-
- /***************************************************************
-
- FUNCTION: CALLOC()
-
- DESCRIPTION: Pass-thru function to calloc() for debugging
- purposes. Added by JBV 10/95
-
- ***************************************************************/
-
- void *
- #if ANSI_C
- CALLOC( size_t nelem, size_t elsize, char *str )
- #else
- CALLOC( nelem, elsize, str )
- size_t nelem;
- size_t elsize;
- char *str;
- #endif
- {
- void *ptr;
-
- ptr = calloc(nelem, elsize);
- /* printf("%x %x\n", ptr, mallocblksize(ptr)); */
- return ptr;
- }
-
- /***************************************************************
-
- FUNCTION: FREE()
-
- DESCRIPTION: Pass-thru function to free() for debugging
- purposes. Added by JBV 10/95
-
- ***************************************************************/
-
- void
- #if ANSI_C
- FREE( void *ptr, char *str )
- #else
- FREE( ptr, str )
- void *ptr;
- char *str;
- #endif
- {
- /* printf("%x\n", ptr); */
- free(ptr);
- }
|