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

  1. /***************************************************************
  2.  
  3.         bwb_cmd.c       Miscellaneous Commands
  4.                         for Bywater BASIC Interpreter
  5.  
  6.                         Commands:       RUN
  7.                                         LET
  8.                                         LOAD
  9.                                         MERGE
  10.                                         CHAIN
  11.                                         NEW
  12.                                         RENUM
  13.                                         SAVE
  14.                                         LIST
  15.                                         GOTO
  16.                                         GOSUB
  17.                                         RETURN
  18.                                         ON
  19.                                         STOP
  20.                                         END
  21.                                         SYSTEM
  22.                                         TRON
  23.                                         TROFF
  24.                                         DELETE
  25.                                         RANDOMIZE
  26.                     ENVIRON
  27.                                         CMDS            (*debugging)
  28.  
  29.                         Copyright (c) 1992, Ted A. Campbell
  30.  
  31.                         Bywater Software
  32.                         P. O. Box 4023
  33.                         Duke Station
  34.                         Durham, NC  27706
  35.  
  36.                         email: tcamp@acpub.duke.edu
  37.  
  38.         Copyright and Permissions Information:
  39.  
  40.         All U.S. and international copyrights are claimed by the
  41.         author. The author grants permission to use this code
  42.         and software based on it under the following conditions:
  43.         (a) in general, the code and software based upon it may be
  44.         used by individuals and by non-profit organizations; (b) it
  45.         may also be utilized by governmental agencies in any country,
  46.         with the exception of military agencies; (c) the code and/or
  47.         software based upon it may not be sold for a profit without
  48.         an explicit and specific permission from the author, except
  49.         that a minimal fee may be charged for media on which it is
  50.         copied, and for copying and handling; (d) the code must be
  51.         distributed in the form in which it has been released by the
  52.         author; and (e) the code and software based upon it may not
  53.         be used for illegal activities.
  54.  
  55. ***************************************************************/
  56.  
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <math.h>
  60. #include <string.h>
  61.  
  62. #include "bwbasic.h"
  63. #include "bwb_mes.h"
  64.  
  65. struct gsse *bwb_gss;            /* GOSUB stack */
  66. int bwb_gssc = 0;            /* GOSUB stack counter */
  67. int err_gosubn = 0;            /* line number for error GOSUB */
  68.  
  69. extern struct bwb_line *bwb_xnew( struct bwb_line *l );
  70. extern struct bwb_line *bwb_onerror( struct bwb_line *l );
  71.  
  72. /***************************************************************
  73.  
  74.         FUNCTION:       bwb_null()
  75.  
  76.         DESCRIPTION:
  77.  
  78. ***************************************************************/
  79.  
  80. struct bwb_line *
  81. bwb_null( struct bwb_line *l )
  82.    {
  83.    #if  INTENSIVE_DEBUG
  84.    sprintf( bwb_ebuf, "in bwb_null(): NULL function: argc = %d", l->argc );
  85.    bwb_debug( bwb_ebuf );
  86.    #endif
  87.    l->next->position = 0;
  88.    return l->next;
  89.    }
  90.  
  91. /***************************************************************
  92.  
  93.     FUNCTION:       bwb_rem()
  94.  
  95.         DESCRIPTION:
  96.  
  97. ***************************************************************/
  98.  
  99. struct bwb_line *
  100. bwb_rem( struct bwb_line *l )
  101.    {
  102.    #if INTENSIVE_DEBUG
  103.    sprintf( bwb_ebuf, "in bwb_rem(): REM command" );
  104.    bwb_debug( bwb_ebuf );
  105.    #endif
  106.  
  107.    l->position = strlen( l->buffer ) - 1;
  108.  
  109.    l->next->position = 0;
  110.    return l->next;
  111.    }
  112.  
  113. /***************************************************************
  114.  
  115.         FUNCTION:       bwb_run()
  116.  
  117.         DESCRIPTION:
  118.  
  119. ***************************************************************/
  120.  
  121. struct bwb_line *
  122. bwb_run( struct bwb_line *l )
  123.    {
  124.    struct bwb_line *current, *x;
  125.    int go_lnumber;                /* line number to go to */
  126.    register int n;                /* counter */
  127.    char tbuf[ MAXSTRINGSIZE + 1 ];
  128.    struct exp_ese *e;
  129.    FILE *input;
  130.  
  131.    #if INTENSIVE_DEBUG
  132.    sprintf( bwb_ebuf, "in bwb_run(): entered function. buffer <%s> pos <%d>",
  133.       l->buffer, l->position );
  134.    bwb_debug( bwb_ebuf );
  135.    #endif
  136.  
  137.    /* see if there is an element */
  138.  
  139.    current = NULL;
  140.    adv_ws( l->buffer, &( l->position ) );
  141.    #if INTENSIVE_DEBUG
  142.    sprintf( bwb_ebuf, "in bwb_run(): check buffer <%s> pos <%d> char <0x%x>",
  143.       l->buffer, l->position, l->buffer[ l->position ] );
  144.    bwb_debug( bwb_ebuf );
  145.    #endif
  146.    switch ( l->buffer[ l->position ] )
  147.       {
  148.       case '\0':
  149.       case '\n':
  150.       case '\r':
  151.       case ':':
  152.          #if INTENSIVE_DEBUG
  153.          sprintf( bwb_ebuf, "in bwb_run(): no argument; begin at start.next" );
  154.          bwb_debug( bwb_ebuf );
  155.          #endif
  156.          current = bwb_start.next;
  157.          e = NULL;
  158.          break;
  159.       default:
  160.          e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  161.          break;
  162.       }
  163.  
  164.    /* check its type: if it is a string, open the file and execute it */
  165.  
  166.    if (( e != NULL ) && ( e->type == STRING ))
  167.       {
  168.       bwb_new( l );                /* clear memory */
  169.       str_btoc( tbuf, exp_getsval( e ) );    /* get string in tbuf */
  170.       if ( ( input = fopen( tbuf, "r" )) == NULL )    /* open file */
  171.          {
  172.          sprintf( bwb_ebuf, err_openfile, tbuf );
  173.          bwb_error( bwb_ebuf );
  174.          }
  175.       bwb_fload( input );        /* load program */
  176.       bwb_run( &bwb_start );        /* and call bwb_run() recursively */
  177.       }
  178.  
  179.    /* else if it is a line number, execute the progrm in memory
  180.       at that line number */
  181.  
  182.    else
  183.       {
  184.  
  185.       if ( current == NULL )
  186.          {
  187.  
  188.          if ( e != NULL )
  189.             {
  190.             go_lnumber = exp_getival( e );
  191.             }
  192.  
  193.          #if INTENSIVE_DEBUG
  194.          sprintf( bwb_ebuf, "in bwb_run(): element detected <%s>, lnumber <%d>",
  195.             tbuf, go_lnumber );
  196.          bwb_debug( bwb_ebuf );
  197.          #endif
  198.  
  199.          for ( x = bwb_start.next; x != &bwb_end; x = x->next )
  200.             {
  201.             if ( x->number == go_lnumber )
  202.                {
  203.                current = x;
  204.                }
  205.             }
  206.          }
  207.  
  208.       if ( current == NULL )
  209.          {
  210.          sprintf( bwb_ebuf, err_lnnotfound, go_lnumber );
  211.          bwb_error( bwb_ebuf );
  212.          return &bwb_end;
  213.          }
  214.  
  215.       #if INTENSIVE_DEBUG
  216.       sprintf( bwb_ebuf, "in bwb_run(): ready to call do-while loop at line %d",
  217.          current->number );
  218.       bwb_debug( bwb_ebuf );
  219.       #endif
  220.  
  221.       current->position = 0;
  222.  
  223.       while ( current != &bwb_end )
  224.          {
  225.          current = bwb_xline( current );
  226.          }
  227.  
  228.       }
  229.  
  230.    #if INTENSIVE_DEBUG
  231.    sprintf( bwb_ebuf, "in bwb_run(): function complete." );
  232.    bwb_debug( bwb_ebuf );
  233.    #endif
  234.  
  235.    return &bwb_end;
  236.  
  237.    }
  238.  
  239. /***************************************************************
  240.  
  241.         FUNCTION:       bwb_let()
  242.  
  243.         DESCRIPTION:
  244.  
  245. ***************************************************************/
  246.  
  247. struct bwb_line *
  248. bwb_let( struct bwb_line *l )
  249.    {
  250.  
  251.    #if INTENSIVE_DEBUG
  252.    sprintf( bwb_ebuf, "in bwb_let(): pos <%d> line <%s>",
  253.       l->position, l->buffer );
  254.    bwb_debug( bwb_ebuf );
  255.    #endif
  256.  
  257.    /* Call the expression interpreter to evaluate the assignment */
  258.  
  259.    bwb_exp( l->buffer, TRUE, &( l->position ) );
  260.  
  261.    l->next->position = 0;
  262.    return l->next;
  263.  
  264.    }
  265.  
  266. /***************************************************************
  267.  
  268.         FUNCTION:       bwb_chain()
  269.  
  270.         DESCRIPTION:    This C function implements the BASIC
  271.             CHAIN command.
  272.  
  273. ***************************************************************/
  274.  
  275. struct bwb_line *
  276. bwb_chain( struct bwb_line *l )
  277.    {
  278.    struct bwb_line *current;
  279.  
  280.    /* deallocate all variables except common ones */
  281.  
  282.    var_delcvars();
  283.  
  284.    /* remove old program from memory */
  285.  
  286.    bwb_xnew( l );
  287.  
  288.    /* call xload function to load new program in memory */
  289.  
  290.    bwb_xload( l );
  291.  
  292.    /* process other arguments */
  293.  
  294.    /*** TEMP -- WORKPOINT ***/
  295.  
  296.    /* run the newly loaded program */
  297.  
  298.    current = bwb_start.next;
  299.  
  300.    current->position = 0;
  301.  
  302.    while ( current != &bwb_end )
  303.       {
  304.       current = bwb_xline( current );
  305.       }
  306.  
  307.    /* return */
  308.  
  309.    return &bwb_end;
  310.  
  311.    }
  312.  
  313. /***************************************************************
  314.  
  315.         FUNCTION:       bwb_merge()
  316.  
  317.         DESCRIPTION:    This C function implements the BASIC
  318.             MERGE command.
  319.  
  320. ***************************************************************/
  321.  
  322. struct bwb_line *
  323. bwb_merge( struct bwb_line *l )
  324.    {
  325.  
  326.    /* call xload function to merge program in memory */
  327.  
  328.    bwb_xload( l );
  329.  
  330.    return l;
  331.  
  332.    }
  333.  
  334. /***************************************************************
  335.  
  336.         FUNCTION:       bwb_load()
  337.  
  338.         DESCRIPTION:    This C function implements the BASIC
  339.             LOAD command.
  340.  
  341. ***************************************************************/
  342.  
  343. struct bwb_line *
  344. bwb_load( struct bwb_line *l )
  345.    {
  346.  
  347.    /* clear current contents */
  348.  
  349.    bwb_new( l );
  350.  
  351.    /* call xload function to load program in memory */
  352.  
  353.    bwb_xload( l );
  354.  
  355.    return l;
  356.  
  357.    }
  358.  
  359. /***************************************************************
  360.  
  361.         FUNCTION:       bwb_xload()
  362.  
  363.         DESCRIPTION:    This C function implements the BASIC
  364.             LOAD command.
  365.  
  366. ***************************************************************/
  367.  
  368. struct bwb_line *
  369. bwb_xload( struct bwb_line *l )
  370.    {
  371.    FILE *loadfile;
  372.    char filename[ MAXARGSIZE ];
  373.  
  374.    /* Get an argument for filename */
  375.  
  376.    adv_ws( l->buffer, &( l->position ) );
  377.    switch( l->buffer[ l->position ] )
  378.       {
  379.       case '\0':
  380.       case '\n':
  381.       case '\r':
  382.       case ':':
  383.          bwb_error( err_nofn );
  384.          l->next->position = 0;
  385.          return l->next;
  386.       default:
  387.          break;
  388.       }
  389.  
  390.    bwb_const( l->buffer, filename, &( l->position ) );
  391.    if ( ( loadfile = fopen( filename, "r" )) == NULL )
  392.       {
  393.       sprintf( bwb_ebuf, err_openfile, filename );
  394.       bwb_error( bwb_ebuf );
  395.       l->next->position = 0;
  396.       return l->next;
  397.       }
  398.  
  399.    bwb_fload( loadfile );
  400.  
  401.    l->next->position = 0;
  402.    return l->next;
  403.    }
  404.  
  405. /***************************************************************
  406.  
  407.         FUNCTION:       bwb_new()
  408.  
  409.         DESCRIPTION:    This C function implements the BASIC
  410.             NEW command.
  411.  
  412. ***************************************************************/
  413.  
  414. struct bwb_line *
  415. bwb_new( struct bwb_line *l )
  416.    {
  417.  
  418.    /* clear program in memory */
  419.  
  420.    bwb_xnew( l );
  421.  
  422.    /* clear all variables */
  423.  
  424.    bwb_clear( l );
  425.  
  426.    return l->next;
  427.    }
  428.  
  429. /***************************************************************
  430.  
  431.         FUNCTION:       bwb_xnew()
  432.  
  433.         DESCRIPTION:    Clears the program in memory, but does not
  434.             deallocate all variables.
  435.  
  436. ***************************************************************/
  437.  
  438. struct bwb_line *
  439. bwb_xnew( struct bwb_line *l )
  440.    {
  441.    struct bwb_line *current, *previous;
  442.    int wait;
  443.  
  444.    wait = TRUE;
  445.    for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  446.       {
  447.       if ( wait != TRUE )
  448.          {
  449.          free( previous );
  450.          }
  451.       wait = FALSE;
  452.       previous = current;
  453.       }
  454.  
  455.    bwb_start.next = &bwb_end;
  456.  
  457.    l->next->position = 0;
  458.  
  459.    return l->next;
  460.    }
  461.  
  462. /***************************************************************
  463.  
  464.         FUNCTION:       bwb_renum()
  465.  
  466.         DESCRIPTION:
  467.  
  468. ***************************************************************/
  469.  
  470. #ifdef ALLOW_RENUM
  471. struct bwb_line *
  472. bwb_renum( struct bwb_line *l )
  473.    {
  474.    struct bwb_line *current, *x;
  475.    register int c, o;
  476.    char tbuf[ MAXSTRINGSIZE + 1 ];
  477.  
  478.    /* set c to initial number */
  479.  
  480.    c = 10;
  481.  
  482.    /* set all reset flags to FALSE */
  483.  
  484.    for ( x = bwb_start.next; x != &bwb_end; x = x->next )
  485.       {
  486.       x->reset = FALSE;
  487.       }
  488.  
  489.    /* cycle through each line */
  490.  
  491.    for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  492.       {
  493.       o = current->number;
  494.       current->number = c;
  495.  
  496.       /* run back through and change any GOTO statements
  497.          or GOSUB statements depending on this line */
  498.  
  499.       for ( x = bwb_start.next; x != &bwb_end; x = x->next )
  500.          {
  501.  
  502.          if ( ( x->vector == bwb_goto ) || ( x->vector == bwb_gosub ))
  503.             {
  504.             if ( atoi( x->argv[ 0 ] ) == o )
  505.                {
  506.  
  507.                if ( x->reset == FALSE )
  508.                   {
  509.  
  510.                   #if INTENSIVE_DEBUG
  511.                   sprintf( bwb_ebuf,
  512.                      "in bwb_renum(): renumbering line %d, new argument is %d",
  513.                      x->number, c );
  514.                   bwb_debug( bwb_ebuf );
  515.                   #endif
  516.  
  517.                   free( x->argv[ 0 ] );
  518.                   sprintf( tbuf, "%d", c );
  519.                   if ( ( x->argv[ 0 ] = calloc( 1, strlen( tbuf ) + 1 )) == NULL )
  520.                      {
  521.                      bwb_error( err_getmem );
  522.                      l->next->position = 0;
  523.                      return l->next;
  524.                      }
  525.                   strcpy( x->argv[ 0 ], tbuf );
  526.                   x->reset = TRUE;
  527.                   }
  528.                }
  529.             }
  530.  
  531.          }
  532.  
  533.       c += 10;
  534.       }
  535.  
  536.    l->next->position = 0;
  537.    return l->next;
  538.    }
  539. #endif
  540.  
  541. /***************************************************************
  542.  
  543.         FUNCTION:       bwb_save()
  544.  
  545.         DESCRIPTION:
  546.  
  547. ***************************************************************/
  548.  
  549. struct bwb_line *
  550. bwb_save( struct bwb_line *l )
  551.    {
  552.    FILE *outfile;
  553.    static char filename[ MAXARGSIZE ];
  554.  
  555.    #if INTENSIVE_DEBUG
  556.    sprintf( bwb_ebuf, "in bwb_save(): entered function." );
  557.    bwb_debug( bwb_ebuf );
  558.    #endif
  559.  
  560.    /* Get an argument for filename */
  561.  
  562.    adv_ws( l->buffer, &( l->position ) );
  563.    switch( l->buffer[ l->position ] )
  564.       {
  565.       case '\0':
  566.       case '\n':
  567.       case '\r':
  568.       case ':':
  569.          bwb_error( err_nofn );
  570.          l->next->position = 0;
  571.          return l->next;
  572.       default:
  573.          break;
  574.       }
  575.  
  576.    bwb_const( l->buffer, filename, &( l->position ) );
  577.    if ( ( outfile = fopen( filename, "w" )) == NULL )
  578.       {
  579.       sprintf( bwb_ebuf, err_openfile, filename );
  580.       bwb_error( bwb_ebuf );
  581.       l->next->position = 0;
  582.       return l->next;
  583.       }
  584.  
  585.    bwb_xlist( l, outfile );
  586.    fclose( outfile );
  587.  
  588.    l->next->position = 0;
  589.    return l->next;
  590.  
  591.    }
  592.  
  593. /***************************************************************
  594.  
  595.         FUNCTION:       bwb_list()
  596.  
  597.         DESCRIPTION:
  598.  
  599. ***************************************************************/
  600.  
  601. struct bwb_line *
  602. bwb_list( struct bwb_line *l )
  603.    {
  604.    bwb_xlist( l, stdout );
  605.    l->next->position = 0;
  606.    return l->next;
  607.    }
  608.  
  609. /***************************************************************
  610.  
  611.         FUNCTION:       bwb_xlist()
  612.  
  613.         DESCRIPTION:
  614.  
  615. ***************************************************************/
  616.  
  617. struct bwb_line *
  618. bwb_xlist( struct bwb_line *l, FILE *file )
  619.    {
  620.    struct bwb_line *start, *end, *current;
  621.    register int n;
  622.    static int s, e;
  623.    int f, r;
  624.    char tbuf[ MAXSTRINGSIZE + 1 ];
  625.  
  626.    start = bwb_start.next;
  627.    end = &bwb_end;
  628.  
  629.    r = bwb_numseq( &( l->buffer[ l->position ] ), &s, &e );
  630.  
  631.    if (( r == FALSE ) || ( s == 0 ))
  632.       {
  633.       s = bwb_start.next->number;
  634.       }
  635.  
  636.    if ( e == 0 )
  637.       {
  638.       e = s;
  639.       }
  640.  
  641.    if ( r == FALSE )
  642.       {
  643.       for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  644.          {
  645.          if ( current->next == &bwb_end )
  646.             {
  647.             e = current->number;
  648.             }
  649.          }
  650.       }
  651.  
  652.    #if INTENSIVE_DEBUG
  653.    sprintf( bwb_ebuf, "in bwb_list(): LBUFFER sequence is %d-%d", s, e );
  654.    bwb_debug( bwb_ebuf );
  655.    #endif
  656.  
  657.    /* Now try to find the actual lines in memory */
  658.  
  659.    f = FALSE;
  660.  
  661.    for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  662.       {
  663.       if ( current != l )
  664.          {
  665.          current->position = 0;
  666.          adv_element( current->buffer, &( current->position ), tbuf );
  667.          if ( atoi( tbuf ) == s )
  668.             {
  669.             f = TRUE;
  670.         start = current;
  671.  
  672.             #if INTENSIVE_DEBUG
  673.             sprintf( bwb_ebuf, "in bwb_list(): start line number is <%d>",
  674.                s );
  675.             bwb_debug( bwb_ebuf );
  676.             #endif
  677.  
  678.             }
  679.          }
  680.       }
  681.  
  682.    /* check and see if a line number was found */
  683.  
  684.    if ( f == FALSE )
  685.       {
  686.       sprintf( bwb_ebuf, err_lnnotfound, s );
  687.       bwb_error( bwb_ebuf );
  688.       l->next->position = 0;
  689.       return l->next;
  690.       }
  691.  
  692.    if ( e > s )
  693.       {
  694.       for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  695.          {
  696.          if ( current != l )
  697.             {
  698.             current->position = 0;
  699.             adv_element( current->buffer, &( current->position ), tbuf );
  700.             if ( atoi( tbuf ) == e )
  701.                {
  702.                #if INTENSIVE_DEBUG
  703.                sprintf( bwb_ebuf, "in bwb_list(): end line number is <%d>",
  704.                   e );
  705.                bwb_debug( bwb_ebuf );
  706.                #endif
  707.  
  708.                end = current->next;
  709.                }
  710.             }
  711.          }
  712.       }
  713.    else
  714.       {
  715.       end = start;
  716.       }
  717.  
  718.    /* previous should now be set to the line previous to the
  719.       first in the omission list */
  720.  
  721.    /* now go through and list appropriate lines */
  722.  
  723.    if ( start == end )
  724.       {
  725.       fprintf( file, "%s\n", start->buffer );
  726.       }
  727.    else
  728.       {
  729.       current = start;
  730.       while ( current != end )
  731.          {
  732.          fprintf( file, "%s\n", current->buffer );
  733.          current = current->next;
  734.          }
  735.       }
  736.  
  737.    l->next->position = 0;
  738.    return l->next;
  739.  
  740.    }
  741.  
  742. /***************************************************************
  743.  
  744.         FUNCTION:       bwb_goto
  745.  
  746.         DESCRIPTION:
  747.  
  748. ***************************************************************/
  749.  
  750. struct bwb_line *
  751. bwb_goto( struct bwb_line *l )
  752.    {
  753.    struct bwb_line *x;
  754.    char tbuf[ MAXSTRINGSIZE + 1 ];
  755.  
  756.    /* Check for argument */
  757.  
  758.    adv_ws( l->buffer, &( l->position ) );
  759.    switch( l->buffer[ l->position ] )
  760.       {
  761.       case '\0':
  762.       case '\n':
  763.       case '\r':
  764.       case ':':
  765.          bwb_error( err_noln );
  766.          l->next->position = 0;
  767.          return l->next;
  768.       default:
  769.          break;
  770.       }
  771.  
  772.    adv_element( l->buffer, &( l->position ), tbuf );
  773.  
  774.    for ( x = &bwb_start; x != &bwb_end; x = x->next )
  775.       {
  776.       if ( x->number == atoi( tbuf ) )
  777.          {
  778.          x->position = 0;
  779.          return x;
  780.          }
  781.       }
  782.  
  783.    sprintf( bwb_ebuf, err_lnnotfound, atoi( tbuf ) );
  784.    bwb_error( bwb_ebuf );
  785.  
  786.    l->next->position = 0;
  787.    return l->next;
  788.    }
  789.  
  790. /***************************************************************
  791.  
  792.         FUNCTION:       bwb_gosub()
  793.  
  794.     DESCRIPTION:    This function implements the BASIC GOSUB
  795.             command.
  796.  
  797. ***************************************************************/
  798.  
  799. struct bwb_line *
  800. bwb_gosub( struct bwb_line *l )
  801.    {
  802.    struct bwb_line *x, *nl;
  803.    int save_pos;
  804.    register int c;
  805.    char atbuf[ MAXSTRINGSIZE + 1 ];
  806.    char btbuf[ MAXSTRINGSIZE + 1 ];
  807.  
  808.    /* Check for argument */
  809.  
  810.    adv_ws( l->buffer, &( l->position ) );
  811.    switch( l->buffer[ l->position ] )
  812.       {
  813.       case '\0':
  814.       case '\n':
  815.       case '\r':
  816.       case ':':
  817.          sprintf( bwb_ebuf, err_noln );
  818.          bwb_error( bwb_ebuf );
  819.          l->next->position = 0;
  820.          return l->next;
  821.       default:
  822.          break;
  823.       }
  824.  
  825.    /* get the target line number in tbuf */
  826.  
  827.    adv_element( l->buffer, &( l->position ), atbuf );
  828.  
  829.    for ( x = &bwb_start; x != &bwb_end; x = x->next )
  830.       {
  831.  
  832.       if ( x != l )
  833.          {
  834.          x->position = 0;
  835.          }
  836.  
  837.       /* try to get line number in tbuf */
  838.  
  839.       adv_element( x->buffer, &( x->position ), btbuf );
  840.  
  841.       if ( is_numconst( btbuf ) == TRUE )
  842.          {
  843.          if ( atoi( btbuf ) == atoi( atbuf ) )
  844.             {
  845.         save_pos = l->position;
  846.  
  847.         #if  INTENSIVE_DEBUG
  848.         sprintf( bwb_ebuf, "in bwb_gosub() at line <%d> gssc <%d>\n",
  849.                l->number, bwb_gssc );
  850.             bwb_debug( bwb_ebuf );
  851.             bwb_debug( "Press RETURN: " );
  852.             getchar();
  853.             #endif
  854.  
  855.             /* increment the GOSUB stack counter */
  856.  
  857.             ++bwb_gssc;
  858.  
  859.             x->cmdnum = -1;
  860.             x->marked = FALSE;
  861.             x->position = 0;
  862.  
  863.             do
  864.                {
  865.                bwb_gss[ bwb_gssc ].position = 0;
  866.  
  867.            /* execute the line */
  868.  
  869.            nl = bwb_xline( x );
  870.  
  871.            /* check for RETURN in the line */
  872.  
  873.            if ( x->cmdnum == getcmdnum( "RETURN" ) )
  874.           {
  875.           l->position = save_pos;
  876.           #if  INTENSIVE_DEBUG
  877.           sprintf( bwb_ebuf, "in bwb_gosub(): return to line <%d>, position <%d>, gssc <%d>",
  878.              l->number, l->position, bwb_gssc );
  879.           bwb_debug( bwb_ebuf );
  880.           #endif
  881.           l->next->position = 0;
  882.           return l->next;     /* but why shouldn't we continue processing */
  883.           }            /* this line? */
  884.                     /* answer: bwb_xline() will continue */
  885.            x = nl;
  886.  
  887.            }
  888.  
  889.         while ( TRUE );
  890.  
  891.             }
  892.          }
  893.       }
  894.  
  895.    sprintf( bwb_ebuf, err_lnnotfound, atoi( atbuf ) );
  896.    bwb_error( bwb_ebuf );
  897.  
  898.    l->next->position = 0;
  899.    return l->next;
  900.  
  901.    }
  902.  
  903. /***************************************************************
  904.  
  905.         FUNCTION:       bwb_return()
  906.  
  907.     DESCRIPTION:    This function implements the BASIC RETURN
  908.             command.
  909.  
  910. ***************************************************************/
  911.  
  912. struct bwb_line *
  913. bwb_return( struct bwb_line *l )
  914.    {
  915.  
  916.    #if  INTENSIVE_DEBUG
  917.    sprintf( bwb_ebuf, "in bwb_return() at line <%d> bwb_gssc <%d>, cmdnum <%d>",
  918.       l->number, bwb_gssc, l->cmdnum );
  919.    bwb_debug( bwb_ebuf );
  920.    #endif
  921.  
  922.    if ( bwb_gssc < 1 )
  923.       {
  924.       #if PROG_ERRORS
  925.       sprintf( bwb_ebuf, "in bwb_return(): bwb_gssc <%d>", bwb_gssc );
  926.       #else
  927.       sprintf( bwb_ebuf, ERR_RETNOGOSUB );
  928.       #endif
  929.       bwb_error( bwb_ebuf );
  930.       l->next->position = 0;
  931.       return l->next;
  932.       }
  933.  
  934.    --bwb_gssc;
  935.  
  936.    #if  INTENSIVE_DEBUG
  937.    sprintf( bwb_ebuf, "in bwb_return() at line <%d>: gss level <%d>",
  938.       l->number, bwb_gssc );
  939.    bwb_debug( bwb_ebuf );
  940.    #endif
  941.  
  942.    l->cmdnum = getcmdnum( "RETURN" );
  943.    l->marked = FALSE;
  944.  
  945.    l->next->position = 0;
  946.    return l->next;
  947.  
  948.    }
  949.  
  950. /***************************************************************
  951.  
  952.         FUNCTION:       bwb_on
  953.  
  954.         DESCRIPTION:    This function implements the BASIC ON...
  955.                         GOTO or ON...GOSUB statements.
  956.  
  957. ***************************************************************/
  958.  
  959. struct bwb_line *
  960. bwb_on( struct bwb_line *l )
  961.    {
  962.    struct bwb_line *x;
  963.    char varname[ MAXVARNAMESIZE + 1 ];
  964.    static int p;
  965.    struct exp_ese *rvar;
  966.    int v;
  967.    int loop;
  968.    int num_lines;
  969.    int command;
  970.    int lines[ MAX_GOLINES ];
  971.    char tbuf[ MAXSTRINGSIZE + 1 ];
  972.    char sbuf[ 7 ];
  973.  
  974.    /* Check for argument */
  975.  
  976.    adv_ws( l->buffer, &( l->position ) );
  977.  
  978.    switch( l->buffer[ l->position ] )
  979.       {
  980.       case '\0':
  981.       case '\n':
  982.       case '\r':
  983.       case ':':
  984.          sprintf( bwb_ebuf, err_incomplete );
  985.          bwb_error( bwb_ebuf );
  986.          l->next->position = 0;
  987.          return l->next;
  988.       default:
  989.          break;
  990.       }
  991.  
  992.    /* get the variable name or numerical constant */
  993.  
  994.    adv_element( l->buffer, &( l->position ), varname );
  995.  
  996.    /* check for ON ERROR statement */
  997.  
  998.    strncpy( sbuf, varname, 6 );
  999.    bwb_strtoupper( sbuf );
  1000.    if ( strcmp( sbuf, "ERROR" ) == 0 )
  1001.       {
  1002.       #if INTENSIVE_DEBUG
  1003.       sprintf( bwb_ebuf, "in bwb_on(): detected ON ERROR" );
  1004.       bwb_debug( bwb_ebuf );
  1005.       #endif
  1006.       return bwb_onerror( l );
  1007.       }
  1008.  
  1009.    /* evaluate the variable name or constant */
  1010.  
  1011.    p = 0;
  1012.    rvar = bwb_exp( varname, FALSE, &p );
  1013.    v = exp_getival( rvar );
  1014.  
  1015.    #if INTENSIVE_DEBUG
  1016.    sprintf( bwb_ebuf, "in bwb_on(): value is <%d>", v );
  1017.    bwb_debug( bwb_ebuf );
  1018.    #endif
  1019.  
  1020.    /* Get GOTO or GOSUB statements */
  1021.  
  1022.    adv_element( l->buffer, &( l->position ), tbuf );
  1023.    bwb_strtoupper( tbuf );
  1024.    if ( strncmp( tbuf, "GOTO", (size_t) 4 ) == 0 )
  1025.       {
  1026.       command = getcmdnum( "GOTO" );
  1027.       }
  1028.    else if ( strncmp( tbuf, "GOSUB", (size_t) 5 ) == 0 )
  1029.       {
  1030.       command = getcmdnum( "GOSUB" );
  1031.       }
  1032.    else
  1033.       {
  1034.       sprintf( bwb_ebuf, ERR_ONNOGOTO );
  1035.       bwb_error( bwb_ebuf );
  1036.       l->next->position = 0;
  1037.       return l->next;
  1038.       }
  1039.  
  1040.    num_lines = 0;
  1041.  
  1042.    loop = TRUE;
  1043.    while( loop == TRUE )
  1044.       {
  1045.  
  1046.       /* read a line number */
  1047.  
  1048.       inp_adv( l->buffer, &( l->position ) );
  1049.       adv_element( l->buffer, &( l->position ), tbuf );
  1050.  
  1051.       lines[ num_lines ] = atoi( tbuf );
  1052.  
  1053.       ++num_lines;
  1054.  
  1055.       if ( num_lines >= MAX_GOLINES )
  1056.          {
  1057.          loop = FALSE;
  1058.          }
  1059.  
  1060.       /* check for end of line */
  1061.  
  1062.       adv_ws( l->buffer, &( l->position ) );
  1063.       switch( l->buffer[ l->position ] )
  1064.          {
  1065.          case '\0':
  1066.          case '\n':
  1067.          case '\r':
  1068.          case ':':
  1069.             loop = FALSE;
  1070.             break;
  1071.          }
  1072.  
  1073.       }
  1074.  
  1075.    /* Be sure value is in range */
  1076.  
  1077.    if ( ( v < 1 ) || ( v > num_lines ))
  1078.       {
  1079.       sprintf( bwb_ebuf, err_valoorange );
  1080.       bwb_error( bwb_ebuf );
  1081.       l->next->position = 0;
  1082.       return l->next;
  1083.       }
  1084.  
  1085.    if ( command == getcmdnum( "GOTO" ))
  1086.       {
  1087.       sprintf( tbuf, "GOTO %d", lines[ v - 1 ] );
  1088.       return cnd_xpline( l, tbuf );
  1089.       }
  1090.    else if ( command == getcmdnum( "GOSUB" ))
  1091.       {
  1092.       sprintf( tbuf, "GOSUB %d", lines[ v - 1 ] );
  1093.       return cnd_xpline( l, tbuf );
  1094.       }
  1095.    else
  1096.       {
  1097.       #if PROG_ERRORS
  1098.       sprintf( bwb_ebuf, "in bwb_on(): invalid value for command." );
  1099.       bwb_error( bwb_ebuf );
  1100.       #else
  1101.       bwb_error( err_syntax );
  1102.       #endif
  1103.       l->next->position = 0;
  1104.       return l->next;
  1105.       }
  1106.  
  1107.    }
  1108.  
  1109. /***************************************************************
  1110.  
  1111.         FUNCTION:       bwb_onerror()
  1112.  
  1113.         DESCRIPTION:    This C function implements the BASIC
  1114.                 ON ERROR GOSUB command.
  1115.  
  1116. ***************************************************************/
  1117.  
  1118. struct bwb_line *
  1119. bwb_onerror( struct bwb_line *l )
  1120.    {
  1121.    char tbuf[ MAXSTRINGSIZE + 1 ];
  1122.  
  1123.    #if INTENSIVE_DEBUG
  1124.    sprintf( bwb_ebuf, "in bwb_onerror(): entered function" );
  1125.    bwb_debug( bwb_ebuf );
  1126.    #endif
  1127.  
  1128.    /* get the GOSUB STATEMENT */
  1129.  
  1130.    adv_element( l->buffer, &( l->position ), tbuf );
  1131.  
  1132.    /* check for GOSUB statement */
  1133.  
  1134.    bwb_strtoupper( tbuf );
  1135.    if ( strcmp( tbuf, "GOSUB" ) != 0 )
  1136.       {
  1137.       #if PROG_ERRORS
  1138.       sprintf( bwb_ebuf, "in bwb_onerror(): GOSUB statement missing" );
  1139.       bwb_error( bwb_ebuf );
  1140.       #else
  1141.       bwb_error( err_syntax );
  1142.       #endif
  1143.       return l;
  1144.       }
  1145.  
  1146.    /* get the GOSUB line number */
  1147.  
  1148.    adv_element( l->buffer, &( l->position ), tbuf );
  1149.    err_gosubn = atoi( tbuf );
  1150.  
  1151.    return l;
  1152.    }
  1153.  
  1154. /***************************************************************
  1155.  
  1156.         FUNCTION:       bwb_stop()
  1157.  
  1158.         DESCRIPTION:
  1159.  
  1160. ***************************************************************/
  1161.  
  1162. struct bwb_line *
  1163. bwb_stop( struct bwb_line *l )
  1164.    {
  1165.    return bwb_xend( l );
  1166.    }
  1167.  
  1168. /***************************************************************
  1169.  
  1170.         FUNCTION:       bwb_xend()
  1171.  
  1172.         DESCRIPTION:
  1173.  
  1174. ***************************************************************/
  1175.  
  1176. struct bwb_line *
  1177. bwb_xend( struct bwb_line *l )
  1178.    {
  1179.  
  1180.    #if INTENSIVE_DEBUG
  1181.    sprintf( bwb_ebuf, "in bwb_xend(): entered funtion" );
  1182.    bwb_debug( bwb_ebuf );
  1183.    #endif
  1184.  
  1185.    break_handler();
  1186.  
  1187.    return &bwb_end;
  1188.    }
  1189.  
  1190. /***************************************************************
  1191.  
  1192.         FUNCTION:       bwb_system()
  1193.  
  1194.         DESCRIPTION:
  1195.  
  1196.  
  1197. ***************************************************************/
  1198.  
  1199. struct bwb_line *
  1200. bwb_system( struct bwb_line *l )
  1201.    {
  1202.    fprintf( stdout, "\n" );
  1203.  
  1204.    #if INTENSIVE_DEBUG
  1205.    bwb_debug( "in bwb_system(): ready to exit" );
  1206.    #endif
  1207.  
  1208.    exit( 0 );
  1209.    return &bwb_end;                 /* to make LINT happy */
  1210.    }
  1211.  
  1212. /***************************************************************
  1213.  
  1214.         FUNCTION:       bwb_tron()
  1215.  
  1216.         DESCRIPTION:
  1217.  
  1218. ***************************************************************/
  1219.  
  1220. struct bwb_line *
  1221. bwb_tron( struct bwb_line *l )
  1222.    {
  1223.    bwb_trace = TRUE;
  1224.    fprintf( stdout, "Trace is ON\n" );
  1225.    l->next->position = 0;
  1226.    return l->next;
  1227.    }
  1228.  
  1229. /***************************************************************
  1230.  
  1231.         FUNCTION:       bwb_troff()
  1232.  
  1233.         DESCRIPTION:
  1234.  
  1235. ***************************************************************/
  1236.  
  1237. struct bwb_line *
  1238. bwb_troff( struct bwb_line *l )
  1239.    {
  1240.    bwb_trace = FALSE;
  1241.    fprintf( stdout, "Trace is OFF\n" );
  1242.    l->next->position = 0;
  1243.    return l->next;
  1244.    }
  1245.  
  1246. /***************************************************************
  1247.  
  1248.  
  1249.         FUNCTION:       bwb_delete()
  1250.  
  1251.         DESCRIPTION:
  1252.  
  1253. ***************************************************************/
  1254.  
  1255. struct bwb_line *
  1256.  
  1257. bwb_delete( struct bwb_line *l )
  1258.    {
  1259.    struct bwb_line *start, *end, *current, *previous, *p;
  1260.    register int n;
  1261.    static int s, e;
  1262.    int f;
  1263.    char tbuf[ MAXSTRINGSIZE + 1 ];
  1264.  
  1265.    previous = &bwb_start;
  1266.    start = bwb_start.next;
  1267.    end = &bwb_end;
  1268.  
  1269.    bwb_numseq( &( l->buffer[ l->position ] ), &s, &e );
  1270.  
  1271.    #if INTENSIVE_DEBUG
  1272.    sprintf( bwb_ebuf, "in bwb_delete(): LBUFFER sequence is %d-%d", s, e );
  1273.    bwb_debug( bwb_ebuf );
  1274.    #endif
  1275.  
  1276.    /* Now try to find the actual lines in memory */
  1277.  
  1278.    previous = p = &bwb_start;
  1279.    f = FALSE;
  1280.  
  1281.    for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  1282.       {
  1283.       if ( current != l )
  1284.          {
  1285.          current->position = 0;
  1286.          adv_element( current->buffer, &( current->position ), tbuf );
  1287.          if ( atoi( tbuf ) == s )
  1288.             {
  1289.             f = TRUE;
  1290.             previous = p;
  1291.             start = current;
  1292.  
  1293.             #if INTENSIVE_DEBUG
  1294.             sprintf( bwb_ebuf, "in bwb_delete(): start line number is <%d>",
  1295.                s );
  1296.             bwb_debug( bwb_ebuf );
  1297.             #endif
  1298.  
  1299.             }
  1300.          }
  1301.       p = current;
  1302.       }
  1303.  
  1304.    /* check and see if a line number was found */
  1305.  
  1306.    if ( f == FALSE )
  1307.       {
  1308.       sprintf( bwb_ebuf, err_lnnotfound, s );
  1309.       bwb_error( bwb_ebuf );
  1310.       l->next->position = 0;
  1311.       return l->next;
  1312.       }
  1313.  
  1314.    if ( e > s )
  1315.       {
  1316.       for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  1317.          {
  1318.          if ( current != l )
  1319.             {
  1320.             current->position = 0;
  1321.             adv_element( current->buffer, &( current->position ), tbuf );
  1322.             if ( atoi( tbuf ) == e )
  1323.                {
  1324.                #if INTENSIVE_DEBUG
  1325.                sprintf( bwb_ebuf, "in bwb_delete(): end line number is <%d>",
  1326.                   e );
  1327.                bwb_debug( bwb_ebuf );
  1328.                #endif
  1329.  
  1330.                end = current->next;
  1331.                }
  1332.             }
  1333.          }
  1334.       }
  1335.    else
  1336.       {
  1337.       end = start;
  1338.       }
  1339.  
  1340.    /* previous should now be set to the line previous to the
  1341.       first in the omission list */
  1342.  
  1343.    /* now go through and delete appropriate lines */
  1344.  
  1345.    current = start;
  1346.    while ( current != end )
  1347.       {
  1348.  
  1349.       #if INTENSIVE_DEBUG
  1350.       sprintf( bwb_ebuf, "in bwb_delete(): deleting line %d",
  1351.          current->number );
  1352.       bwb_debug( bwb_ebuf );
  1353.       #endif
  1354.  
  1355.       /* free line memory */
  1356.  
  1357.       bwb_freeline( current );
  1358.  
  1359.       /* recycle */
  1360.  
  1361.       current = current->next;
  1362.       }
  1363.  
  1364.    /* reset link */
  1365.  
  1366.    previous->next = current;
  1367.  
  1368.    l->next->position = 0;
  1369.    return l->next;
  1370.    }
  1371.  
  1372. /***************************************************************
  1373.  
  1374.         FUNCTION:       bwb_randomize()
  1375.  
  1376.         DESCRIPTION:
  1377.  
  1378. ***************************************************************/
  1379.  
  1380. struct bwb_line *
  1381. bwb_randomize( struct bwb_line *l )
  1382.    {
  1383.    register unsigned n;
  1384.    char tbuf[ MAXSTRINGSIZE + 1 ];
  1385.  
  1386.    /* Check for argument */
  1387.  
  1388.    adv_ws( l->buffer, &( l->position ) );
  1389.    switch( l->buffer[ l->position ] )
  1390.       {
  1391.       case '\0':
  1392.       case '\n':
  1393.       case '\r':
  1394.       case ':':
  1395.          n = (unsigned) 1;
  1396.          break;
  1397.       default:
  1398.          n = (unsigned) 0;
  1399.          break;
  1400.       }
  1401.  
  1402.    /* get the argument in tbuf */
  1403.  
  1404.    if ( n == (unsigned) 0 )
  1405.       {
  1406.       adv_element( l->buffer, &( l->position ), tbuf );
  1407.       n = (unsigned) atoi( tbuf );
  1408.       }
  1409.  
  1410.    #if INTENSIVE_DEBUG
  1411.    sprintf( bwb_ebuf, "in bwb_randomize(): argument is <%d>", n );
  1412.    bwb_debug( bwb_ebuf );
  1413.    #endif
  1414.  
  1415.    srand( n );
  1416.  
  1417.    l->next->position = 0;
  1418.    return l->next;
  1419.    }
  1420.  
  1421.  
  1422. /***************************************************************
  1423.  
  1424.         FUNCTION:       bwb_environ()
  1425.  
  1426.         DESCRIPTION:    This C function implements the BASIC
  1427.             ENVIRON command.  
  1428.  
  1429. ***************************************************************/
  1430.  
  1431. struct bwb_line *
  1432. bwb_environ( struct bwb_line *l )
  1433.    {
  1434.    static char tbuf[ MAXSTRINGSIZE + 1 ];
  1435.    char tmp[ MAXSTRINGSIZE + 1 ];
  1436.    register int h, i;
  1437.    int pos;
  1438.    struct exp_ese *e;
  1439.  
  1440.    /* find the equals sign */
  1441.  
  1442.    for ( i = 0; ( l->buffer[ l->position ] != '=' ) && ( l->buffer[ l->position ] != '\0' ); ++i )
  1443.       {
  1444.       tbuf[ i ] = l->buffer[ l->position ];
  1445.       tbuf[ i + 1 ] = '\0';
  1446.       ++( l->position );
  1447.       }
  1448.  
  1449.    #if INTENSIVE_DEBUG
  1450.    sprintf( bwb_ebuf, "in bwb_environ(): variable string is <%s>", tbuf );
  1451.    bwb_debug( bwb_ebuf );
  1452.    #endif
  1453.  
  1454.    /* get the value string to be assigned */
  1455.  
  1456.    pos = 0;
  1457.    e = bwb_exp( tbuf, FALSE, &pos );
  1458.    str_btoc( tbuf, exp_getsval( e ) );
  1459.  
  1460.    #if INTENSIVE_DEBUG
  1461.    sprintf( bwb_ebuf, "in bwb_environ(): variable string resolves to <%s>", tbuf );
  1462.    bwb_debug( bwb_ebuf );
  1463.    #endif
  1464.  
  1465.    /* find the equals sign */
  1466.  
  1467.    adv_ws( l->buffer, &( l->position ) );
  1468.    if ( l->buffer[ l->position ] != '=' )
  1469.       {
  1470.       #if PROG_ERRORS
  1471.       sprintf( bwb_ebuf, "in bwb_environ(): failed to find equal sign" );
  1472.       bwb_error( bwb_ebuf );
  1473.       #else
  1474.       bwb_error( err_syntax );
  1475.       #endif
  1476.       return l;
  1477.       }
  1478.    ++( l->position );
  1479.  
  1480.    /* get the value string to be assigned */
  1481.  
  1482.    e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1483.    str_btoc( tmp, exp_getsval( e ) );
  1484.  
  1485.    #if INTENSIVE_DEBUG
  1486.    sprintf( bwb_ebuf, "in bwb_environ(): value string resolves to <%s>", tmp );
  1487.    bwb_debug( bwb_ebuf );
  1488.    #endif
  1489.  
  1490.    /* construct string */
  1491.  
  1492.    strcat( tbuf, "=" );
  1493.    strcat( tbuf, tmp );
  1494.  
  1495.    #if INTENSIVE_DEBUG
  1496.    sprintf( bwb_ebuf, "in bwb_environ(): assignment string is <%s>", tbuf );
  1497.    bwb_debug( bwb_ebuf );
  1498.    #endif
  1499.  
  1500.    /* now assign value to variable */
  1501.  
  1502.    if ( putenv( tbuf ) == -1 )
  1503.       {
  1504.       bwb_error( err_opsys );
  1505.       return l;
  1506.       }
  1507.  
  1508.    /* return */ 
  1509.  
  1510.    return l;
  1511.  
  1512.    }
  1513.  
  1514. /***************************************************************
  1515.  
  1516.         FUNCTION:       bwb_cmds()
  1517.  
  1518.         DESCRIPTION:
  1519.  
  1520. ***************************************************************/
  1521.  
  1522. #if PERMANENT_DEBUG
  1523. struct bwb_line *
  1524. bwb_cmds( struct bwb_line *l )
  1525.    {
  1526.    register int n;
  1527.  
  1528.    fprintf( stdout, "BWBASIC COMMANDS AVAILABLE: \n" );
  1529.  
  1530.    /* run through the command table and print comand names */
  1531.  
  1532.    for ( n = 0; n < COMMANDS; ++n )
  1533.       {
  1534.       fprintf( stdout, "%s \n", bwb_cmdtable[ n ].name );
  1535.       }
  1536.  
  1537.    l->next->position = 0;
  1538.    return l->next;
  1539.    }
  1540. #endif
  1541.  
  1542. int
  1543. getcmdnum( char *cmdstr )
  1544.    {
  1545.    register int c;
  1546.  
  1547.    for ( c = 0; c < COMMANDS; ++c )
  1548.       {
  1549.       if ( strcmp( bwb_cmdtable[ c ].name, cmdstr ) == 0 )
  1550.          {
  1551.          return c;
  1552.          }
  1553.       }
  1554.  
  1555.    return -1;
  1556.  
  1557.    }
  1558.