home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / bwbasic.zip / src / bwbasic.c < prev    next >
C/C++ Source or Header  |  1993-04-27  |  26KB  |  1,064 lines

  1. /***************************************************************
  2.  
  3.         bwbasic.c       Main Program File
  4.                         for Bywater BASIC Interpreter
  5.  
  6.                         Copyright (c) 1992, Ted A. Campbell
  7.  
  8.             "I was no programmer, neither was I a
  9.             programmer's son; but I was an herdman
  10.             and a gatherer of sycomore fruit."
  11.                  - Amos 7:14b AV, slightly adapted
  12.  
  13.                         Bywater Software
  14.                         P. O. Box 4023
  15.                         Duke Station
  16.                         Durham, NC  27706
  17.  
  18.                         email: tcamp@acpub.duke.edu
  19.  
  20.         Copyright and Permissions Information:
  21.  
  22.         All U.S. and international copyrights are claimed by the
  23.         author. The author grants permission to use this code
  24.         and software based on it under the following conditions:
  25.         (a) in general, the code and software based upon it may be
  26.         used by individuals and by non-profit organizations; (b) it
  27.         may also be utilized by governmental agencies in any country,
  28.         with the exception of military agencies; (c) the code and/or
  29.         software based upon it may not be sold for a profit without
  30.         an explicit and specific permission from the author, except
  31.         that a minimal fee may be charged for media on which it is
  32.         copied, and for copying and handling; (d) the code must be
  33.         distributed in the form in which it has been released by the
  34.         author; and (e) the code and software based upon it may not
  35.         be used for illegal activities.
  36.  
  37. ***************************************************************/
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <ctype.h>
  42. #include <string.h>
  43. #include <math.h>
  44. #include <signal.h>
  45. #include <setjmp.h>
  46.  
  47. #include "bwbasic.h"
  48. #include "bwb_mes.h"
  49.  
  50. char bwb_progfile[ MAXARGSIZE ];
  51. struct bwb_line bwb_start, bwb_end;
  52. char *bwb_ebuf;                /* error buffer */
  53. static char *read_line;
  54. int bwb_trace = FALSE;
  55. int bwb_number = 0;
  56. struct bwb_line *bwb_l;
  57.  
  58. struct xtxtsl
  59.    {
  60.    int  position;
  61.    struct bwb_line l;
  62.    };
  63.  
  64. struct xtxtsl *xtxts;                /* eXecute TeXT stack */
  65. struct exp_ese *exp_es;            /* expression stack */
  66. struct ufsel *ufs;                  /* user function stack */
  67. struct fse *fs;                         /* FOR stack */
  68.  
  69. int xtxtsc = -1;                        /* eXecute TeXT stack counter */
  70.  
  71. FILE *errfdevice;                       /* output device for error messages */
  72. static jmp_buf mark;
  73. static int program_run = FALSE;        /* has the command-line program ben run? */
  74.  
  75. /* Prototypes for functions visible only to this file */
  76.  
  77. #if COMMAND_SHELL
  78. extern int bwb_shell( struct bwb_line *l );
  79. #endif
  80.  
  81. extern int is_ln( char *buffer );
  82.  
  83. /***************************************************************
  84.  
  85.         FUNCTION:       main()
  86.  
  87.         DESCRIPTION:    As in any C program, main() is the basic
  88.                         function from which the rest of the
  89.                         program is called.
  90.  
  91.     PRAYER:        Everlasting God,
  92.  
  93.             Thine eternal Logos is the main() function
  94.             from which all things have their being
  95.             and unto which all things shall return;
  96.             all subroutines are restless until they
  97.             find their rest in thee.
  98.  
  99.             Grant that users of this software may
  100.             apply it for good purposes; grant
  101.             unto programmers searching its ways that
  102.             they may not be entirely confounded; and
  103.             grant that all our work may be unto thy
  104.             glory. Amen.
  105.  
  106. ***************************************************************/
  107.  
  108. void
  109. main( int argc, char **argv )
  110.    {
  111.    static FILE *input = NULL;
  112.    static int jump_set = FALSE;
  113.    static char start_buf[] = "\0";
  114.    static char end_buf[] = "\0";
  115.    register int n;
  116.    #if REDIRECT_STDERR
  117.    FILE *newerr;
  118.    #endif
  119.  
  120.    /* set some initial variables */
  121.  
  122.    bwb_start.number = 0;
  123.    bwb_start.next = &bwb_end;
  124.    bwb_end.number = MAXLINENO;
  125.    bwb_end.next = &bwb_end;
  126.    bwb_start.buffer = start_buf;
  127.    bwb_end.buffer = end_buf;
  128.    data_line = &bwb_start;
  129.    data_pos = 0;
  130.  
  131.    /* Memory allocation for various tables */
  132.  
  133.    /* eXecute TeXT stack */
  134.  
  135.    if ( ( xtxts = calloc( XTXTSTACKSIZE, sizeof( struct xtxtsl ) ) ) == NULL )
  136.       {
  137.       bwb_error( err_getmem );
  138.       }
  139.  
  140.    /* expression stack */
  141.  
  142.    if ( ( exp_es = calloc( ESTACKSIZE, sizeof( struct exp_ese ) ) ) == NULL )
  143.       {
  144.       bwb_error( err_getmem );
  145.       }
  146.  
  147.    /* user-defined function stack */
  148.  
  149.    if ( ( ufs = calloc( UFNCSTACKSIZE, sizeof( struct ufsel ) ) ) == NULL )
  150.       {
  151.       bwb_error( err_getmem );
  152.       }
  153.  
  154.    /* FOR-NEXT stack */
  155.  
  156.    if ( ( fs = calloc( FORLEVELS, sizeof( struct fse ) ) ) == NULL )
  157.       {
  158.       bwb_error( err_getmem );
  159.       }
  160.  
  161.    /* GOSUB-RETURN stack */
  162.  
  163.    if ( ( bwb_gss = calloc( GOSUBLEVELS, sizeof( struct gsse ) ) ) == NULL )
  164.       {
  165.       bwb_error( err_getmem );
  166.       }
  167.  
  168.    /* character buffers */
  169.  
  170.    if ( ( bwb_ebuf = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  171.       {
  172.       bwb_error( err_getmem );
  173.       }
  174.    if ( ( read_line = calloc( MAXREADLINESIZE + 1, sizeof(char) ) ) == NULL )
  175.       {
  176.       bwb_error( err_getmem );
  177.       }
  178.  
  179.    /* Variable and function table initializations */
  180.  
  181.    var_init();                  /* initialize variable chain */
  182.  
  183.    fnc_init();                  /* initialize function chain */
  184.  
  185.    #if TEST_BSTRING
  186.    for ( n = 0; n < ESTACKSIZE; ++n )
  187.       {
  188.       sprintf( exp_es[ n ].sval.name, "<Exp stack bstring %d>", n );
  189.       }
  190.    #endif
  191.  
  192.    /* assign memory for the device table */
  193.  
  194.    if ( ( dev_table = calloc( DEF_DEVICES, sizeof( struct dev_element ) ) ) == NULL )
  195.       {
  196.       bwb_error( err_getmem );
  197.       exit(-1);
  198.       }
  199.  
  200.    /* initialize all devices to DEVMODE_AVAILABLE */
  201.  
  202.    for ( n = 0; n < DEF_DEVICES; ++n )
  203.       {
  204.       dev_table[ n ].mode = DEVMODE_AVAILABLE;
  205.       dev_table[ n ].reclen = -1;
  206.       dev_table[ n ].cfp = NULL;
  207.       dev_table[ n ].buffer = NULL;
  208.       dev_table[ n ].width = DEF_WIDTH;
  209.       dev_table[ n ].col = 1;
  210.       }
  211.  
  212.    /* Signon message */
  213.  
  214.    sprintf( bwb_ebuf, "\r%s %s\n", MES_SIGNON, VERSION );
  215.    xprintf( stdout, bwb_ebuf );
  216.    sprintf( bwb_ebuf, "\r%s\n", MES_COPYRIGHT );
  217.    xprintf( stdout, bwb_ebuf );
  218.    #if PERMANENT_DEBUG
  219.    sprintf( bwb_ebuf, "\r%s\n", "DEBUGGING MODE" );
  220.    xprintf( stdout, bwb_ebuf );
  221.    #else
  222.    sprintf( bwb_ebuf, "\r%s\n", MES_LANGUAGE );
  223.    xprintf( stdout, bwb_ebuf );
  224.    #endif
  225.  
  226.    /* Redirect stderr if specified */
  227.  
  228.    #if REDIRECT_STDERR
  229.    newerr = freopen( ERRFILE, "w", stderr );
  230.    if ( newerr == NULL )
  231.       {
  232.       sprintf( bwb_ebuf, "Failed to redirect error messages to file <%s>\n",
  233.          ERRFILE );
  234.       xprintf( stdout, bwb_ebuf );
  235.       errfdevice = stdout;
  236.       }
  237.    else
  238.       {
  239.       sprintf( bwb_ebuf, "NOTE: Error messages are redirected to file <%s>\n",
  240.          ERRFILE );
  241.       xprintf( errfdevice, bwb_ebuf );
  242.       errfdevice = stderr;
  243.       }
  244.    #else
  245.    errfdevice = stdout;
  246.    #endif
  247.  
  248.    #if INTENSIVE_DEBUG
  249.    sprintf( bwb_ebuf, "in main(): Ready to save jump MARKER" );
  250.    bwb_debug( bwb_ebuf );
  251.    getchar();
  252.    #endif
  253.  
  254.    /* set a buffer for jump: program execution returns to this point
  255.       in case of a jump (error, interrupt, or finish program) */
  256.  
  257.    signal( SIGINT, break_mes );
  258.    setjmp( mark );
  259.  
  260.    #if THEOLDWAY
  261.    if ( jump_set == FALSE )
  262.       {
  263.       signal( SIGINT, break_mes );
  264.       setjmp( mark );
  265.       jump_set = TRUE;
  266.       }
  267.    #endif
  268.  
  269.    #if INTENSIVE_DEBUG
  270.    sprintf( bwb_ebuf, "in main(): Return from jump MARKER, program run <%d>",
  271.       program_run );
  272.    bwb_debug( bwb_ebuf );
  273.    getchar();
  274.    #endif
  275.  
  276.    /* check to see if there is a program file: but do this only the first
  277.       time around! */
  278.  
  279.    if (( argc > 1 ) && ( program_run == FALSE ))
  280.       {
  281.       program_run = TRUE;            /* don't do it again */
  282.       if ( ( input = fopen( argv[ 1 ], "r" )) == NULL )
  283.          {
  284.          strcpy( bwb_progfile, argv[ 1 ] );
  285.          strcat( bwb_progfile, ".bas" );
  286.          if ( ( input = fopen( bwb_progfile, "r" )) == NULL )
  287.             {
  288.             bwb_progfile[ 0 ] = 0;
  289.             sprintf( bwb_ebuf, err_openfile, argv[ 1 ] );
  290.             bwb_error( bwb_ebuf );
  291.             }
  292.          }
  293.       if ( input != NULL )
  294.          {
  295.          strcpy( bwb_progfile, argv[ 1 ] );
  296.          #if INTENSIVE_DEBUG
  297.          sprintf( bwb_ebuf, "in main(): progfile is <%s>.", bwb_progfile );
  298.          bwb_debug( bwb_ebuf );
  299.          #endif
  300.          bwb_fload( input );
  301.          bwb_run( &bwb_start );
  302.          }
  303.       }
  304.  
  305.    /* Main Program Loop */
  306.  
  307.    while( TRUE )
  308.       {
  309.  
  310.       /* take input from keyboard */
  311.  
  312.       bwb_gets( read_line );
  313.  
  314.       /* If there is no line number, execute the line as received */
  315.  
  316.       if ( is_ln( read_line ) == FALSE )
  317.          {
  318.          bwb_xtxtline( read_line );
  319.          }
  320.  
  321.       /* If there is a line number, add the line to the file in memory */
  322.  
  323.       else
  324.          {
  325.          bwb_ladd( read_line, TRUE );
  326.          }
  327.  
  328.       }
  329.  
  330.    }
  331.  
  332. /***************************************************************
  333.  
  334.         FUNCTION:       bwb_fload()
  335.  
  336.         DESCRIPTION: This function loads a BASIC program
  337.         file into memory.
  338.  
  339. ***************************************************************/
  340.  
  341. bwb_fload( FILE *file )
  342.    {
  343.  
  344.    while ( feof( file ) == FALSE )
  345.       {
  346.       read_line[ 0 ] = '\0';
  347.       if ( file == stdin )
  348.          {
  349.          fflush( file );
  350.          }
  351.       fgets( read_line, MAXREADLINESIZE, file );
  352.       if ( file == stdin )
  353.          {
  354.          * prn_getcol( stdout ) = 1;        /* reset column */
  355.          }
  356.       bwb_stripcr( read_line );
  357.       bwb_ladd( read_line, FALSE );
  358.       }
  359.  
  360.    /* close file stream */
  361.  
  362.    fclose( file );
  363.  
  364.    return TRUE;
  365.    }
  366.  
  367. /***************************************************************
  368.  
  369.         FUNCTION:       bwb_ladd()
  370.  
  371.         DESCRIPTION:    This function adds a new line (in the
  372.                         buffer) to the program in memory.
  373.  
  374. ***************************************************************/
  375.  
  376. bwb_ladd( char *buffer, int replace )
  377.    {
  378.    struct bwb_line *l, *previous;
  379.    register int n, a;
  380.    static char *s_buffer;
  381.    static int init = FALSE;
  382.    static int prev_num = 0;
  383.  
  384.    #if INTENSIVE_DEBUG
  385.    sprintf( bwb_ebuf, "in bwb_ladd(): ready to get memory for <%s>",
  386.       buffer );
  387.    bwb_debug( bwb_ebuf );
  388.    #endif
  389.  
  390.    /* get memory for temporary buffer if necessary */
  391.  
  392.    if ( init == FALSE )
  393.       {
  394.       init = TRUE;
  395.       if ( ( s_buffer = calloc( (size_t) MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  396.          {
  397.          bwb_error( err_getmem );
  398.          return FALSE;
  399.          }
  400.       }
  401.  
  402.    /* get memory for this line */
  403.  
  404.    if ( ( l = (struct bwb_line *) calloc( (size_t) 1, sizeof( struct bwb_line ) )) == NULL )
  405.       {
  406.       bwb_error( err_getmem );
  407.       return FALSE;
  408.       }
  409.  
  410.    #if INTENSIVE_DEBUG
  411.    sprintf( bwb_ebuf, "in bwb_ladd(): got memory." );
  412.    bwb_debug( bwb_ebuf );
  413.    #endif
  414.  
  415.    /* allocate memory and assign buffer to line buffer */
  416.  
  417.    ln_asbuf( l, buffer );
  418.  
  419.    /* get the first element and test for a line number */
  420.  
  421.    adv_element( l->buffer, &( l->position ), s_buffer );
  422.  
  423.    /* note that line is not yet marked */
  424.  
  425.    l->marked = FALSE;
  426.  
  427.    /* set line number in line structure */
  428.  
  429.    if ( is_numconst( s_buffer ) == TRUE )
  430.       {
  431.       l->number = atoi( s_buffer );
  432.       prev_num = l->number;
  433.       }
  434.    else
  435.       {
  436.  
  437.       #if INTENSIVE_DEBUG
  438.       sprintf( bwb_ebuf, "in bwb_ladd(): line is not numbered, using prev <%d>",
  439.          prev_num );
  440.       bwb_debug( bwb_ebuf );
  441.       #endif
  442.  
  443.       l->number = prev_num;
  444.       }
  445.  
  446.    /* find the place of the current line */
  447.  
  448.    for ( previous = &bwb_start; previous != &bwb_end; previous = previous->next )
  449.       {
  450.  
  451.       /* replace a previously existing line */
  452.  
  453.       if (( previous->number == l->number ) && ( replace == TRUE ))
  454.          {
  455.  
  456.          #if INTENSIVE_DEBUG
  457.          sprintf( bwb_ebuf, "in bwb_ladd(): writing to previous number." );
  458.          bwb_debug( bwb_ebuf );
  459.          #endif
  460.  
  461.          /* allocate memory and assign buffer to line buffer */
  462.  
  463.          ln_asbuf( previous, buffer );
  464.  
  465.          /* free the current line */
  466.  
  467.          free( l );
  468.  
  469.          /* and return */
  470.  
  471.          return TRUE;
  472.  
  473.          }
  474.  
  475.       /* add after previously existing line: this is to allow unnumbered
  476.          lines that follow in sequence after a previously numbered line */
  477.  
  478.       else if (( previous->number == l->number ) && ( replace == FALSE ))
  479.          {
  480.          #if INTENSIVE_DEBUG
  481.          sprintf( bwb_ebuf, "in bwb_ladd(): adding doubled number <%d>",
  482.             l->number );
  483.          bwb_debug( bwb_ebuf);
  484.          #endif
  485.          l->next = previous->next;
  486.          previous->next = l;
  487.          return TRUE;
  488.          }
  489.  
  490.       /* add a new line */
  491.  
  492.       else if ( ( previous->number < l->number )
  493.          && ( previous->next->number > l->number ))
  494.          {
  495.          l->next = previous->next;
  496.          previous->next = l;
  497.  
  498.          #if INTENSIVE_DEBUG
  499.          sprintf( bwb_ebuf, "in bwb_ladd(): added new line <%d> buffer <%s>",
  500.             l->number, l->buffer );
  501.          bwb_debug( bwb_ebuf );
  502.          #endif
  503.  
  504.          return TRUE;
  505.          }
  506.  
  507.       }
  508.  
  509.    sprintf( bwb_ebuf, ERR_LINENO );
  510.    bwb_error( bwb_ebuf );
  511.    return FALSE;
  512.  
  513.    }
  514.  
  515. /***************************************************************
  516.  
  517.         FUNCTION:       bwb_shell()
  518.  
  519.         DESCRIPTION:
  520.  
  521. ***************************************************************/
  522.  
  523. #if COMMAND_SHELL
  524. int
  525. bwb_shell( struct bwb_line *l )
  526.    {
  527.    static char *s_buffer;
  528.    static int init = FALSE;
  529.    static int position;
  530.  
  531.    /* get memory for temporary buffer if necessary */
  532.  
  533.    if ( init == FALSE )
  534.       {
  535.       init = TRUE;
  536.       if ( ( s_buffer = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  537.          {
  538.          bwb_error( err_getmem );
  539.          return FALSE;
  540.          }
  541.       }
  542.  
  543.    /* get the first element and check for a line number */
  544.  
  545.    #if INTENSIVE_DEBUG
  546.    sprintf( bwb_ebuf, "in bwb_shell(): line buffer is <%s>.", l->buffer );
  547.    bwb_debug( bwb_ebuf );
  548.    #endif
  549.  
  550.    position = 0;
  551.    adv_element( l->buffer, &position, s_buffer );
  552.    if ( is_numconst( s_buffer ) != TRUE )                  /* not a line number */
  553.       {
  554.  
  555.       #if INTENSIVE_DEBUG
  556.       sprintf( bwb_ebuf, "in bwb_shell(): no line number, command <%s>.",
  557.          l->buffer );
  558.       bwb_debug( bwb_ebuf );
  559.       #endif
  560.  
  561.       if ( system( l->buffer ) == 0 )
  562.          {
  563.          return TRUE;
  564.          }
  565.       else
  566.          {
  567.          return FALSE;
  568.          }
  569.       }
  570.  
  571.    else                                         /* advance past line number */
  572.       {
  573.       adv_ws( l->buffer, &position );           /* advance past whitespace */
  574.  
  575.       #if INTENSIVE_DEBUG
  576.       sprintf( bwb_ebuf, "in bwb_shell(): line number, command <%s>.",
  577.          l->buffer );
  578.       bwb_debug( bwb_ebuf );
  579.       #endif
  580.  
  581.       if ( system( &( l->buffer[ position ] ) ) == 0 )
  582.          {
  583.          return TRUE;
  584.          }
  585.       else
  586.          {
  587.          return FALSE;
  588.          }
  589.       }
  590.    }
  591. #endif
  592.  
  593. /***************************************************************
  594.  
  595.         FUNCTION:       bwb_xtxtline()
  596.  
  597.         DESCRIPTION:    This function executes a text line, i.e.,
  598.                         places it in memory and then calls
  599.                         bwb_xline() to execute it.
  600.  
  601. ***************************************************************/
  602.  
  603. struct bwb_line *
  604. bwb_xtxtline( char *buffer )
  605.    {
  606.    struct bwb_line *c;
  607.    register int n, a;
  608.    char *p;
  609.    int loop;
  610.  
  611.    #if INTENSIVE_DEBUG
  612.    sprintf( bwb_ebuf, "in bwb_xtxtline(): received <%s>", buffer );
  613.    bwb_debug( bwb_ebuf );
  614.    #endif
  615.  
  616.    /* increment xtxt stack counter */
  617.  
  618.    if ( xtxtsc >= XTXTSTACKSIZE )
  619.       {
  620.       sprintf( bwb_ebuf, "Exceeded maximum xtxt stack <%d>",
  621.          xtxtsc );
  622.       return &bwb_end;
  623.       }
  624.  
  625.    ++xtxtsc;
  626.  
  627.    /* advance past whitespace */
  628.  
  629.    p = buffer;
  630.    loop = TRUE;
  631.    while( loop == TRUE )
  632.       {
  633.  
  634.       switch( *p )
  635.          {
  636.          case '\0':                     /* end of string */
  637.  
  638.             #if INTENSIVE_DEBUG
  639.             sprintf( bwb_ebuf, "Null command line received." );
  640.             bwb_debug( bwb_ebuf );
  641.             #endif
  642.             --xtxtsc;
  643.             return &bwb_end;
  644.          case ' ':                      /* whitespace */
  645.          case '\t':
  646.             ++p;
  647.             break;
  648.          default:
  649.             loop = FALSE;
  650.             break;
  651.          }
  652.  
  653.       }
  654.  
  655.    #if INTENSIVE_DEBUG
  656.    sprintf( bwb_ebuf, "in bwb_xtxtline(): ready to get memory" );
  657.    bwb_debug( bwb_ebuf );
  658.    #endif
  659.  
  660.    if ( xtxts[ xtxtsc ].l.buffer != NULL )
  661.       {
  662.       #if INTENSIVE_DEBUG
  663.       sprintf( bwb_ebuf, "in bwb_xtxtline(): freeing buffer memory" );
  664.       bwb_debug( bwb_ebuf );
  665.       #endif
  666.       free( xtxts[ xtxtsc ].l.buffer );
  667.       }
  668.  
  669.    /* copy the whole line to the line structure buffer */
  670.  
  671.    ln_asbuf( &( xtxts[ xtxtsc ].l ), buffer );
  672.  
  673.    #if INTENSIVE_DEBUG
  674.    sprintf( bwb_ebuf, "in bwb_xtxtline(): copied to line buffer <%s>.",
  675.       xtxts[ xtxtsc ].l.buffer );
  676.    bwb_debug( bwb_ebuf );
  677.    #endif
  678.  
  679.    /* set line number in line structure */
  680.  
  681.    xtxts[ xtxtsc ].l.number = 0;
  682.    xtxts[ xtxtsc ].l.marked = FALSE;
  683.  
  684.    /* execute the line as BASIC command line */
  685.  
  686.    xtxts[ xtxtsc ].l.next = &bwb_end;
  687.    c = &( xtxts[ xtxtsc ].l );
  688.    c->position = 0;
  689.  
  690.    do
  691.       {
  692. /*      xtxts[ xtxtsc ].position = 0; */
  693.       c = bwb_xline( c );
  694.       }
  695.  
  696.    while( c != &bwb_end );
  697.  
  698.    /* decrement xtxt stack counter */
  699.  
  700.    --xtxtsc;
  701.  
  702.    return c;
  703.  
  704.    }
  705.  
  706. /***************************************************************
  707.  
  708.         FUNCTION:       bwb_xline()
  709.  
  710.         DESCRIPTION:    This function executes a single line of
  711.                         the program in memory.
  712.  
  713. ***************************************************************/
  714.  
  715. struct bwb_line *
  716. bwb_xline( struct bwb_line *l )
  717.    {
  718.    int loop, extended_line;
  719.    struct bwb_line *r;
  720.  
  721.    #if INTENSIVE_DEBUG
  722.    sprintf( bwb_ebuf, "in bwb_xline(): buffer <%s>",
  723.       &( l->buffer[ l->position ] ) );
  724.    bwb_debug( bwb_ebuf );
  725.    #endif
  726.  
  727.    /* Print line number if trace is on */
  728.  
  729.    if ( bwb_trace == TRUE )
  730.       {
  731.       if ( l->number > 0 )
  732.          {
  733.          sprintf( bwb_ebuf, "[ %d ]", l->number );
  734.          xprintf( errfdevice, bwb_ebuf );
  735.          }
  736.       }
  737.  
  738.    /* Set current line for error/break handling */
  739.  
  740.    bwb_number = l->number;
  741.    bwb_l = l;
  742.    extended_line = FALSE;
  743.  
  744.    /* advance past whitespace and segment delimiter */
  745.  
  746.    if ( l->buffer[ l->position ] == ':' )
  747.       {
  748.       ++( l->position );
  749.       }
  750.    adv_ws( l->buffer, &( l->position ) );
  751.    if ( l->buffer[ l->position ] == ':' )
  752.       {
  753.       ++( l->position );
  754.       adv_ws( l->buffer, &( l->position ) );
  755.       }
  756.  
  757.    /* Loop through line segments delimited by ':' */
  758.  
  759.    loop = TRUE;
  760.    r = l->next;
  761.  
  762.    while ( loop == TRUE )
  763.       {
  764.  
  765.       /* set loop to false: it will be set to TRUE later if needed */
  766.  
  767.       loop = FALSE;
  768.  
  769.       /* set positions in buffer */
  770.  
  771.       #if MARK_LINES
  772.       if ( ( l->marked != TRUE ) || ( l->position > l->startpos ))
  773.      {
  774.      line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  775.         &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  776.      l->marked = TRUE;
  777.      }
  778.       else
  779.          {
  780.          #if INTENSIVE_DEBUG
  781.          sprintf( bwb_ebuf, "in bwb_xline(): line <%d> is already marked",
  782.              l->number );
  783.          bwb_debug( bwb_ebuf );
  784.          #endif
  785.          }
  786.       #else
  787.       line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  788.          &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  789.       #endif
  790.  
  791.       if ( l->position < l->startpos )
  792.          {
  793.          l->position = l->startpos;
  794.          }
  795.  
  796.       /* if there is a BASIC command in the line, execute it here */
  797.  
  798.       if ( l->cmdnum > -1 )
  799.          {
  800.  
  801.          #if INTENSIVE_DEBUG
  802.          sprintf( bwb_ebuf, "in bwb_xline(): executing <%s>", l->buffer );
  803.          bwb_debug( bwb_ebuf );
  804.          #endif
  805.  
  806.          /* execute the command vector */
  807.  
  808.          r = ( bwb_cmdtable[ l->cmdnum ].vector ) ( l );
  809.  
  810.      #if INTENSIVE_DEBUG
  811.      if ( l->cmdnum == getcmdnum( "GOSUB" ) )
  812.         {
  813.         sprintf( bwb_ebuf, "in bwb_xline(): returning from GOSUB, position <%d>",
  814.            l->position );
  815.         bwb_debug( bwb_ebuf );
  816.             }
  817.      #endif
  818.  
  819.          /* If the command was RETURN OR GOTO, then we must break out of
  820.             the loop at this point; the rest of the line is irrelevant */
  821.  
  822.          if ( l->cmdnum == getcmdnum( "RETURN" ) )
  823.             {
  824.         #if INTENSIVE_DEBUG
  825.         sprintf( bwb_ebuf, "in bwb_xline(): returning from RETURN command, ret line <%d>",
  826.            r->number );
  827.         bwb_debug( bwb_ebuf );
  828.         #endif
  829.         r->cmdnum = getcmdnum( "RETURN" );
  830.         r->marked = FALSE;
  831.         return r;            /* break out; return now */
  832.         }
  833.  
  834.          else if ( l->cmdnum == getcmdnum( "GOTO" ) )
  835.             {
  836.         #if INTENSIVE_DEBUG
  837.             sprintf( bwb_ebuf, "in bwb_xline(): returning from GOTO command, ret line <%d>",
  838.                r->number );
  839.             bwb_debug( bwb_ebuf );
  840.             #endif
  841.             return r;
  842.             }
  843.          }
  844.  
  845.       else if ( l->buffer[ l->position ] == ':' )
  846.          {
  847.          l->marked = FALSE;
  848.          }                /* do nothing */
  849.  
  850.       /* No BASIC command; try to execute it as a shell command */
  851.  
  852.       #if COMMAND_SHELL
  853.       else
  854.      {
  855.  
  856.      #if INTENSIVE_DEBUG
  857.      sprintf( bwb_ebuf, "Breaking out to shell, line num <%d> buf <%s> cmd <%d> pos <%d>",
  858.         l->number, &( l->buffer[ l->position ] ), l->cmdnum, l->position );
  859.      bwb_debug( bwb_ebuf );
  860.      getchar();
  861.      #endif
  862.  
  863.      bwb_shell( l );
  864.      }
  865.  
  866.       #else                /* COMMAND_SHELL == FALSE */
  867.  
  868.       else
  869.         {
  870.         bwb_error( err_uc );
  871.         }
  872.  
  873.       #endif
  874.  
  875.       /* detect if the current character is ':', in which case loop
  876.          back through to execute it */
  877.  
  878.       #if INTENSIVE_DEBUG
  879.       sprintf( bwb_ebuf, "in bwb_xline(): remaining line is <%s>",
  880.          &( l->buffer[ l->position ] ) );
  881.       bwb_debug( bwb_ebuf );
  882.       #endif
  883.  
  884.       adv_ws( l->buffer, &( l->position ) );
  885.       if ( l->buffer[ l->position ] == ':' )
  886.          {
  887.  
  888.      #if INTENSIVE_DEBUG
  889.      sprintf( bwb_ebuf, "in bwb_xline(): line <%d> found \':\'",
  890.         l->number );
  891.          bwb_debug( bwb_ebuf );
  892.          #endif
  893.  
  894.      ++l->position;
  895.      l->marked = FALSE;
  896.      extended_line = TRUE;
  897.          loop = TRUE;
  898.          }
  899.  
  900.       else if ( extended_line == TRUE )
  901.      {
  902.      l->marked = FALSE;
  903.      }
  904.  
  905.       }                                 /* end of loop through line */
  906.  
  907.    /* return the value in r */
  908.  
  909.    #if INTENSIVE_DEBUG
  910.    if ( r->cmdnum == getcmdnum( "RETURN" ) )
  911.       {
  912.       bwb_debug( "in bwb_xline(): returning RETURN cmdnum" );
  913.       }
  914.    #endif
  915.  
  916.    return r;
  917.  
  918.    }
  919.  
  920. /***************************************************************
  921.  
  922.         FUNCTION:       ln_asbuf()
  923.  
  924.         DESCRIPTION:    This function allocates memory and copies
  925.             a null-terminated string to a line buffer.
  926.  
  927. ***************************************************************/
  928.  
  929. int
  930. ln_asbuf( struct bwb_line *l, char *s )
  931.    {
  932.  
  933.    #ifdef DONTDOIT
  934.    if ( l->buffer != NULL )
  935.       {
  936.       free( l->buffer );
  937.       }
  938.    #endif
  939.  
  940.    if ( ( l->buffer = calloc( strlen( s ) + 2, sizeof( char ) ) )
  941.       == NULL )
  942.       {
  943.       bwb_error( err_getmem );
  944.       return FALSE;
  945.       }
  946.  
  947.    /* copy the whole line to the line structure buffer */
  948.  
  949.    strcpy( l->buffer, s );
  950.  
  951.    #if INTENSIVE_DEBUG
  952.    sprintf( bwb_ebuf, "in ln_asbuf(): allocated buffer <%s>", l->buffer );
  953.    bwb_debug( bwb_ebuf );
  954.    #endif
  955.  
  956.    /* strip CR from the buffer */
  957.  
  958.    bwb_stripcr( l->buffer );
  959.  
  960.    return TRUE;
  961.  
  962.    }
  963.  
  964. /***************************************************************
  965.  
  966.         FUNCTION:       bwb_gets()
  967.  
  968.         DESCRIPTION:    This function reads a single line from
  969.                         the specified buffer.
  970.  
  971. ***************************************************************/
  972.  
  973. bwb_gets( char *buffer )
  974.    {
  975.    bwb_number = 0;
  976.    sprintf( bwb_ebuf, "\r%s ", PROMPT );
  977.    xprintf( stdout, bwb_ebuf );
  978.    fflush( stdin );
  979.    fgets( buffer, MAXREADLINESIZE, stdin );
  980.    * prn_getcol( stdout ) = 1;            /* reset column */
  981.    return TRUE;
  982.    }
  983.  
  984. /***************************************************************
  985.  
  986.         FUNCTION:       break_mes()
  987.  
  988.         DESCRIPTION:    This function is called (a) by a SIGINT
  989.                         signal or (b) by error-handling routines.
  990.  
  991. ***************************************************************/
  992.  
  993. void
  994. break_mes( int x )
  995.    {
  996.    static char *tmp_buffer;
  997.    static int init = FALSE;
  998.  
  999.    /* get memory for temporary buffer if necessary */
  1000.  
  1001.    if ( init == FALSE )
  1002.       {
  1003.       init = TRUE;
  1004.       if ( ( tmp_buffer = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  1005.          {
  1006.          bwb_error( err_getmem );
  1007.          }
  1008.       }
  1009.  
  1010.    exp_esc = 0;
  1011.  
  1012.    sprintf( tmp_buffer, "\r%s %d\n", MES_BREAK, bwb_number );
  1013.    xprintf( errfdevice, tmp_buffer );
  1014.  
  1015.    break_handler();
  1016.  
  1017.    }
  1018.  
  1019. void
  1020. break_handler( void )
  1021.    {
  1022.  
  1023.    /* zero all stack counters */
  1024.  
  1025.    exp_esc = 0;
  1026.    bwb_gssc = 0;
  1027.    ufsc = 0;
  1028.    ws_counter = 0;
  1029.    fs_counter = 0;
  1030.    xtxtsc = 0;
  1031.  
  1032.    /* jump back to mark */
  1033.  
  1034.    longjmp( mark, -1 );
  1035.  
  1036.    }
  1037.  
  1038.  
  1039. int
  1040. is_ln( char *buffer )
  1041.    {
  1042.    static int position;
  1043.  
  1044.    position = 0;
  1045.    adv_ws( buffer, &position );
  1046.    switch( buffer[ position ] )
  1047.       {
  1048.       case '0':
  1049.       case '1':
  1050.       case '2':
  1051.       case '3':
  1052.       case '4':
  1053.       case '5':
  1054.       case '6':
  1055.       case '7':
  1056.       case '8':
  1057.       case '9':
  1058.          return TRUE;
  1059.       default:
  1060.          return FALSE;
  1061.       }
  1062.    }
  1063.  
  1064.