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

  1. /***************************************************************
  2.  
  3.         bwb_inp.c       Input Routines
  4.                         for Bywater BASIC Interpreter
  5.  
  6.                         Commands:       DATA
  7.                                         READ
  8.                                         RESTORE
  9.                                         INPUT
  10.                                         LINE INPUT
  11.  
  12.                         Copyright (c) 1992, Ted A. Campbell
  13.  
  14.                         Bywater Software
  15.                         P. O. Box 4023
  16.                         Duke Station
  17.                         Durham, NC  27706
  18.  
  19.                         email: tcamp@acpub.duke.edu
  20.  
  21.         Copyright and Permissions Information:
  22.  
  23.         All U.S. and international copyrights are claimed by the
  24.         author. The author grants permission to use this code
  25.         and software based on it under the following conditions:
  26.         (a) in general, the code and software based upon it may be
  27.         used by individuals and by non-profit organizations; (b) it
  28.         may also be utilized by governmental agencies in any country,
  29.         with the exception of military agencies; (c) the code and/or
  30.         software based upon it may not be sold for a profit without
  31.         an explicit and specific permission from the author, except
  32.         that a minimal fee may be charged for media on which it is
  33.         copied, and for copying and handling; (d) the code must be
  34.         distributed in the form in which it has been released by the
  35.         author; and (e) the code and software based upon it may not
  36.         be used for illegal activities.
  37.  
  38. ***************************************************************/
  39.  
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <ctype.h>
  43. #include <string.h>
  44. #include <math.h>
  45.  
  46. #include "bwbasic.h"
  47. #include "bwb_mes.h"
  48.  
  49. struct bwb_line *data_line;
  50. int data_pos;
  51.  
  52. /* Declarations of functions visible to this file only */
  53.  
  54. static struct bwb_line *bwb_xinp( struct bwb_line *l, FILE *f );
  55. static struct bwb_line *inp_str( struct bwb_line *l, char *buffer,
  56.    char *var_list, int *position );
  57. static int inp_const( char *m_buffer, char *s_buffer, int *position );
  58. static int inp_assign( char *b, struct bwb_variable *v );
  59. static int inp_advws( FILE *f );
  60. static int inp_xgetc( FILE *f, int is_string );
  61. static int inp_eatcomma( FILE *f );
  62. static char_saved = FALSE;
  63. static cs;
  64.  
  65. /***************************************************************
  66.  
  67.         FUNCTION:       bwb_read()
  68.  
  69.         DESCRIPTION:    This function implements the BASIC READ
  70.                         statement.
  71.  
  72.         SYNTAX:         READ variable[, variable...]
  73.  
  74. ***************************************************************/
  75.  
  76. struct bwb_line *
  77. bwb_read( struct bwb_line *l )
  78.    {
  79.    int pos;
  80.    register int n;
  81.    int main_loop, adv_loop;
  82.    struct bwb_variable *v;
  83.    int n_params;                         /* number of parameters */
  84.    int *pp;                              /* pointer to parameter values */
  85.    char tbuf[ MAXSTRINGSIZE + 1 ];
  86.  
  87.    #if INTENSIVE_DEBUG
  88.    sprintf( bwb_ebuf, "in bwb_read(): buffer <%s>",
  89.       &( l->buffer[ l->position ]));
  90.    bwb_debug( bwb_ebuf );
  91.    #endif
  92.  
  93.    /* Process each variable read from the READ statement */
  94.  
  95.    main_loop = TRUE;
  96.    while ( main_loop == TRUE )
  97.       {
  98.  
  99.       /* first check position in l->buffer and advance beyond whitespace */
  100.  
  101.       adv_loop = TRUE;
  102.       while( adv_loop == TRUE )
  103.          {
  104.  
  105.          #if INTENSIVE_DEBUG
  106.          sprintf( bwb_ebuf, "in bwb_read() adv_loop char <%d> = <%c>",
  107.             l->buffer[ l->position ], l->buffer[ l->position ] );
  108.          bwb_debug( bwb_ebuf );
  109.          #endif
  110.  
  111.          switch ( l->buffer[ l->position ] )
  112.             {
  113.             case ',':                   /* comma delimiter */
  114.             case ' ':                   /* whitespace */
  115.             case '\t':
  116.                ++l->position;
  117.                break;
  118.             case ':':                   /* end of line segment */
  119.         case '\n':                  /* end of line */
  120.             case '\r':
  121.             case '\0':
  122.                adv_loop = FALSE;        /* break out of advance loop */
  123.                main_loop = FALSE;       /* break out of main loop */
  124.                break;
  125.             default:                    /* anything else */
  126.                adv_loop = FALSE;        /* break out of advance loop */
  127.                break;
  128.             }
  129.          }
  130.  
  131.       #if INTENSIVE_DEBUG
  132.       sprintf( bwb_ebuf, "in bwb_read(): end of adv_loop <%d> main_loop <%d>",
  133.          adv_loop, main_loop );
  134.       bwb_debug( bwb_ebuf );
  135.       #endif
  136.  
  137.       /* be sure main_loop id still valid after checking the line */
  138.  
  139.       if ( main_loop == TRUE )
  140.          {
  141.  
  142.          /* Read a variable name */
  143.  
  144.          bwb_getvarname( l->buffer, tbuf, &( l->position ) );
  145.          inp_adv( l->buffer, &( l->position ) );
  146.          v = var_find( tbuf );
  147.  
  148.      #if INTENSIVE_DEBUG
  149.      sprintf( bwb_ebuf, "in bwb_read(): line <%d> variable <%s>",
  150.         l->number, v->name );
  151.      bwb_debug( bwb_ebuf );
  152.      sprintf( bwb_ebuf, "in bwb_read(): remaining line <%s>",
  153.         &( l->buffer[ l->position ] ) );
  154.      bwb_debug( bwb_ebuf );
  155.      #endif
  156.  
  157.          /* advance beyond whitespace or comma in data buffer */
  158.  
  159.          inp_adv( data_line->buffer, &data_pos );
  160.  
  161.          /* Advance to next line if end of buffer */
  162.  
  163.          switch( data_line->buffer[ data_pos ] )
  164.             {
  165.             case '\0':                     /* end of buffer */
  166.             case '\n':
  167.             case '\r':
  168.  
  169.                data_line = data_line->next;
  170.  
  171.                /* advance farther to line with DATA statement if necessary */
  172.  
  173.                pos = 0;
  174.                line_start( data_line->buffer, &pos,
  175.                   &( data_line->lnpos ),
  176.                   &( data_line->lnum ),
  177.                   &( data_line->cmdpos ),
  178.                   &( data_line->cmdnum ),
  179.                   &( data_line->startpos ) );
  180.                data_pos = data_line->startpos;
  181.  
  182.            #if INTENSIVE_DEBUG
  183.                sprintf( bwb_ebuf, "in bwb_read(): current data line: <%s>",
  184.                   data_line->buffer );
  185.                bwb_debug( bwb_ebuf );
  186.                #endif
  187.  
  188.                break;
  189.             }
  190.  
  191.          while ( bwb_cmdtable[ data_line->cmdnum ].vector != bwb_data )
  192.             {
  193.  
  194.             if ( data_line == &bwb_end )
  195.                {
  196.                data_line = bwb_start.next;
  197.                }
  198.  
  199.             else
  200.                {
  201.                data_line = data_line->next;
  202.                }
  203.  
  204.             pos = 0;
  205.             line_start( data_line->buffer, &pos,
  206.                &( data_line->lnpos ),
  207.                &( data_line->lnum ),
  208.                &( data_line->cmdpos ),
  209.                &( data_line->cmdnum ),
  210.                &( data_line->startpos ) );
  211.             data_pos = data_line->startpos;
  212.  
  213.             #if INTENSIVE_DEBUG
  214.             sprintf( bwb_ebuf, "in bwb_read(): advance to data line: <%s>",
  215.                data_line->buffer );
  216.             bwb_debug( bwb_ebuf );
  217.             #endif
  218.  
  219.             }
  220.  
  221.          /* advance beyond whitespace in data buffer */
  222.  
  223.          adv_loop = TRUE;
  224.          while ( adv_loop == TRUE )
  225.             {
  226.             switch( data_line->buffer[ data_pos ] )
  227.                {
  228.                case '\0':                       /* end of buffer */
  229.                case '\n':
  230.                case '\r':
  231.                   bwb_error( err_od );
  232.                   l->next->position = 0;
  233.                   return l->next;
  234.                case ' ':                        /* whitespace */
  235.                case '\t':
  236.                   ++data_pos;
  237.                   break;
  238.                default:
  239.                   adv_loop = FALSE;             /* carry on */
  240.                   break;
  241.                }
  242.             }
  243.  
  244.          /* now at last we have a variable in v that needs to be
  245.             assigned data from the data_buffer at position data_pos.
  246.             What remains to be done is to get one single bit of data,
  247.             a string constant or numerical constant, into the small
  248.             buffer */
  249.  
  250.          inp_const( data_line->buffer, tbuf, &data_pos );
  251.  
  252.      #if INTENSIVE_DEBUG
  253.      sprintf( bwb_ebuf, "in bwb_read(): data constant is <%s>", tbuf );
  254.      bwb_debug( bwb_ebuf );
  255.      #endif
  256.  
  257.          /* get parameters if the variable is dimensioned */
  258.  
  259.      adv_ws( l->buffer, &( l->position ) );
  260.      if ( l->buffer[ l->position ] == '(' )
  261.         {
  262.         #if INTENSIVE_DEBUG
  263.         sprintf( bwb_ebuf, "in bwb_read(): variable <%s> is dimensioned",
  264.            v->name );
  265.         bwb_debug( bwb_ebuf );
  266.         #endif
  267.             dim_getparams( l->buffer, &( l->position ), &n_params, &pp );
  268.             for ( n = 0; n < v->dimensions; ++n )
  269.                {
  270.                v->array_pos[ n ] = pp[ n ];
  271.                }
  272.         }
  273.      #if INTENSIVE_DEBUG
  274.      else
  275.         {
  276.         sprintf( bwb_ebuf, "in bwb_read(): variable <%s> is NOT dimensioned",
  277.            v->name );
  278.         bwb_debug( bwb_ebuf );
  279.         sprintf( bwb_ebuf, "in bwb_read(): remaining line <%s>",
  280.            &( l->buffer[ l->position ] ) );
  281.         bwb_debug( bwb_ebuf );
  282.         }
  283.      #endif
  284.  
  285.          /* finally assign the data to the variable */
  286.  
  287.          inp_assign( tbuf, v );
  288.  
  289.          }                              /* end of remainder of main loop */
  290.  
  291.       }                                 /* end of main_loop */
  292.  
  293.    #if INTENSIVE_DEBUG
  294.    sprintf( bwb_ebuf, "in bwb_read(): exiting function, line <%s> ",
  295.       &( l->buffer[ l->position ] ) );
  296.    bwb_debug( bwb_ebuf );
  297.    #endif
  298.  
  299.    l->next->position = 0;
  300.    return l->next;
  301.  
  302.    }
  303.  
  304. /***************************************************************
  305.  
  306.         FUNCTION:       bwb_data()
  307.  
  308.         DESCRIPTION:    This function implements the BASIC DATA
  309.                         statement, although at the point at which
  310.                         DATA statements are encountered, no
  311.                         processing is done.  All actual processing
  312.                         of DATA statements is accomplished by READ
  313.                         (bwb_read()).
  314.  
  315.         SYNTAX:         DATA constant[, constant]...
  316.  
  317.  
  318. ***************************************************************/
  319.  
  320. struct bwb_line *
  321. bwb_data( struct bwb_line *l )
  322.    {
  323.    l->next->position = 0;
  324.    return l->next;
  325.    }
  326.  
  327. /***************************************************************
  328.  
  329.         FUNCTION:       bwb_restore()
  330.  
  331.         DESCRIPTION:    This function implements the BASIC RESTORE
  332.                         statement.
  333.  
  334.         SYNTAX:         RESTORE [line number]
  335.  
  336. ***************************************************************/
  337.  
  338. struct bwb_line *
  339. bwb_restore( struct bwb_line *l )
  340.    {
  341.    struct bwb_line *r;
  342.    struct bwb_line *r_line;
  343.    int n;
  344.    int pos;
  345.    char tbuf[ MAXSTRINGSIZE + 1 ];
  346.  
  347.    /* get the first element beyond the starting position */
  348.  
  349.    adv_element( l->buffer, &( l->position ), tbuf );
  350.  
  351.    /* if the line is not a numerical constant, then there is no
  352.       argument; set the current line to the first in the program */
  353.  
  354.    if ( is_numconst( tbuf ) != TRUE )
  355.       {
  356.       data_line = &bwb_start;
  357.       data_pos = 0;
  358.       #if INTENSIVE_DEBUG
  359.       sprintf( bwb_ebuf, "in bwb_restore(): RESTORE w/ no argument " );
  360.       bwb_debug( bwb_ebuf );
  361.       #endif
  362.       l->next->position = 0;
  363.       return l->next;
  364.       }
  365.  
  366.    /* find the line */
  367.  
  368.    n = atoi( tbuf );
  369.  
  370.    #if INTENSIVE_DEBUG
  371.    sprintf( bwb_ebuf, "in bwb_restore(): line for restore is <%d>", n );
  372.    bwb_debug( bwb_ebuf );
  373.    #endif
  374.  
  375.    r_line = NULL;
  376.    for ( r = bwb_start.next; r != &bwb_end; r = r->next )
  377.       {
  378.  
  379.       if ( r->number == n )
  380.          {
  381.          r_line = r;
  382.          }
  383.       }
  384.  
  385.    if ( r_line == NULL )
  386.       {
  387.       #if PROG_ERRORS
  388.       sprintf( bwb_ebuf, "at line %d: Can't find line number for RESTORE.",
  389.          l->number );
  390.       bwb_error( bwb_ebuf );
  391.       #else
  392.       sprintf( bwb_ebuf, err_lnnotfound, n );
  393.       bwb_error( bwb_ebuf );
  394.       #endif
  395.       l->next->position = 0;
  396.       return l->next;
  397.       }
  398.  
  399.    /* initialize variables for the line */
  400.  
  401.    pos = 0;
  402.    line_start( r_line->buffer, &pos,
  403.       &( r_line->lnpos ),
  404.       &( r_line->lnum ),
  405.       &( r_line->cmdpos ),
  406.       &( r_line->cmdnum ),
  407.       &( r_line->startpos ) );
  408.  
  409.    /* verify that line is a data statement */
  410.  
  411.    if ( bwb_cmdtable[ r_line->cmdnum ].vector != bwb_data )
  412.       {
  413.       #if PROG_ERRORS
  414.       sprintf( bwb_ebuf, "at line %d: Line %d is not a DATA statement.",
  415.          l->number, r_line->number );
  416.       bwb_error( bwb_ebuf );
  417.       #else
  418.       bwb_error( err_syntax );
  419.       #endif
  420.       l->next->position = 0;
  421.       return l->next;
  422.       }
  423.  
  424.    /* reassign data_line */
  425.  
  426.    data_line = r_line;
  427.    data_pos = data_line->startpos;
  428.  
  429.    l->next->position = 0;
  430.    return l->next;
  431.    }
  432.  
  433. /***************************************************************
  434.  
  435.         FUNCTION:       bwb_input()
  436.  
  437.         DESCRIPTION:    This function implements the BASIC INPUT
  438.                         statement.
  439.  
  440.         SYNTAX:         INPUT [;][prompt$;]variable[$,variable]...
  441.                         INPUT #n variable[$,variable]...
  442.  
  443. ***************************************************************/
  444.  
  445. struct bwb_line *
  446. bwb_input( struct bwb_line *l )
  447.    {
  448.    FILE *fp;
  449.    int pos;
  450.    int req_devnumber;
  451.    struct exp_ese *v;
  452.    int is_prompt;
  453.    int suppress_qm;
  454.    static char tbuf[ MAXSTRINGSIZE + 1 ];
  455.  
  456.    #if INTENSIVE_DEBUG
  457.    sprintf( bwb_ebuf, "in bwb_input(): enter function" );
  458.    bwb_debug( bwb_ebuf );
  459.    #endif
  460.  
  461.    /* advance beyond whitespace and check for the '#' sign */
  462.  
  463.    adv_ws( l->buffer, &( l->position ) );
  464.  
  465.    if ( l->buffer[ l->position ] == '#' )
  466.       {
  467.       ++( l->position );
  468.       adv_element( l->buffer, &( l->position ), tbuf );
  469.       pos = 0;
  470.       v = bwb_exp( tbuf, FALSE, &pos );
  471.       adv_ws( l->buffer, &( l->position ) );
  472.       if ( l->buffer[ l->position ] == ',' )
  473.          {
  474.          ++( l->position );
  475.          }
  476.       else
  477.          {
  478.      #if PROG_ERRORS
  479.          bwb_error( "in bwb_input(): no comma after #n" );
  480.          #else
  481.          bwb_error( err_syntax );
  482.          #endif
  483.          l->next->position = 0;
  484.          return l->next;
  485.          }
  486.  
  487.       req_devnumber = exp_getival( v );
  488.  
  489.       #if INTENSIVE_DEBUG
  490.       sprintf( bwb_ebuf, "in bwb_input(): requested device number <%d>",
  491.          req_devnumber );
  492.       bwb_debug( bwb_ebuf );
  493.       #endif
  494.  
  495.       /* check the requested device number */
  496.  
  497.       if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  498.          {
  499.          #if PROG_ERRORS
  500.          bwb_error( "in bwb_input(): Requested device number is out if range." );
  501.          #else
  502.          bwb_error( err_devnum );
  503.          #endif
  504.          l->next->position = 0;
  505.          return l->next;
  506.          }
  507.  
  508.       if ( ( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  509.          ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ) )
  510.          {
  511.          #if PROG_ERRORS
  512.          bwb_error( "in bwb_input(): Requested device number is not open." );
  513.          #else
  514.          bwb_error( err_devnum );
  515.          #endif
  516.  
  517.          l->next->position = 0;
  518.          return l->next;
  519.          }
  520.  
  521.       if ( dev_table[ req_devnumber ].mode != DEVMODE_INPUT )
  522.          {
  523.          #if PROG_ERRORS
  524.          bwb_error( "in bwb_input(): Requested device is not open for INPUT." );
  525.          #else
  526.          bwb_error( err_devnum );
  527.          #endif
  528.  
  529.          l->next->position = 0;
  530.          return l->next;
  531.          }
  532.  
  533.       /* look up the requested device in the device table */
  534.  
  535.       fp = dev_table[ req_devnumber ].cfp;
  536.  
  537.       }
  538.    else
  539.       {
  540.       fp = stdin;
  541.       }
  542.  
  543.    /* if input is not from stdin, then branch to bwb_xinp() */
  544.  
  545.    if ( fp != stdin )
  546.       {
  547.       return bwb_xinp( l, fp );
  548.       }
  549.  
  550.    /* from this point we presume that input is from stdin */
  551.  
  552.    /* check for a semicolon or a quotation mark, not in
  553.       first position: this should indicate a prompt string */
  554.  
  555.    suppress_qm = is_prompt = FALSE;
  556.  
  557.    adv_ws( l->buffer, &( l->position ) );
  558.  
  559.    switch( l->buffer[ l->position ] )
  560.       {
  561.       case '\"':
  562.          is_prompt = TRUE;
  563.          break;
  564.  
  565.       case ';':
  566.  
  567.          /* AGENDA: add code to suppress newline if a
  568.             semicolon is used here; this may not be possible
  569.             using ANSI C alone, since it has not functions for
  570.             unechoed console input. */
  571.  
  572.          is_prompt = TRUE;
  573.          ++l->position;
  574.          break;
  575.  
  576.       case ',':
  577.  
  578.          /* QUERY: why is this code here? the question mark should
  579.             be suppressed if a comma <follows> the prompt string. */
  580.  
  581.          #if INTENSIVE_DEBUG
  582.          bwb_debug( "in bwb_input(): found initial comma" );
  583.          #endif
  584.          suppress_qm = TRUE;
  585.          ++l->position;
  586.          break;
  587.       }
  588.  
  589.    /* get prompt string and print it */
  590.  
  591.    if ( is_prompt == TRUE )
  592.       {
  593.  
  594.       /* get string element */
  595.  
  596.       inp_const( l->buffer, tbuf, &( l->position ) );
  597.  
  598.       /* advance past semicolon to beginning of variable */
  599.  
  600.       suppress_qm = inp_adv( l->buffer, &( l->position ) );
  601.  
  602.       /* print the prompt string */
  603.  
  604.       xprintf( stdout, tbuf );
  605.       }                                      /* end condition: prompt string */
  606.  
  607.    /* print out the question mark delimiter unless it has been
  608.       suppressed */
  609.  
  610.    if ( suppress_qm != TRUE )
  611.       {
  612.       xprintf( stdout, "? " );
  613.       }
  614.  
  615.    #if INTENSIVE_DEBUG
  616.    sprintf( bwb_ebuf, "in bwb_input(): ready to get input line" );
  617.    bwb_debug( bwb_ebuf );
  618.    #endif
  619.  
  620.    /* read a line into the input buffer */
  621.  
  622.    fflush( stdin );
  623.    fgets( tbuf, MAXSTRINGSIZE, stdin );
  624.    bwb_stripcr( tbuf );
  625.  
  626.    #if INTENSIVE_DEBUG
  627.    sprintf( bwb_ebuf, "in bwb_input(): received line <%s>", tbuf );
  628.    bwb_debug( bwb_ebuf );
  629.    bwb_debug( "Press RETURN: " );
  630.    getchar();
  631.    #endif
  632.  
  633.    /* reset print column to account for LF at end of fgets() */
  634.  
  635.    * prn_getcol( stdout ) = 1;
  636.  
  637.    return inp_str( l, tbuf, l->buffer, &( l->position ) );
  638.  
  639.    }
  640.  
  641. /***************************************************************
  642.  
  643.         FUNCTION:       bwb_xinp()
  644.  
  645.         DESCRIPTION:    This function does the bulk of processing
  646.                         for INPUT #, and so is file independent.
  647.  
  648. ***************************************************************/
  649.  
  650. struct bwb_line *
  651. bwb_xinp( struct bwb_line *l, FILE *f )
  652.    {
  653.    int loop;
  654.    struct bwb_variable *v;
  655.    char c;
  656.    register int n;
  657.    int pos;
  658.    int *pp;
  659.    int n_params;
  660.    char tbuf[ MAXSTRINGSIZE + 1 ];
  661.  
  662.    #if INTENSIVE_DEBUG
  663.    sprintf( bwb_ebuf, "in bwb_xinp(): buffer <%s>",
  664.       &( l->buffer[ l->position ] ) );
  665.    bwb_debug( bwb_ebuf );
  666.    #endif
  667.  
  668.    /* loop through elements required */
  669.  
  670.    loop = TRUE;
  671.    while ( loop == TRUE )
  672.       {
  673.       
  674.       /* read a variable from the list */
  675.  
  676.       bwb_getvarname( l->buffer, tbuf, &( l->position ) );
  677.       v = var_find( tbuf );
  678.  
  679.       #if INTENSIVE_DEBUG
  680.       sprintf( bwb_ebuf, "in bwb_xinp(): found variable name <%s>",
  681.          v->name );
  682.       bwb_debug( bwb_ebuf );
  683.       #endif
  684.  
  685.       /* read subscripts */
  686.  
  687.       adv_ws( l->buffer, &( l->position ) );
  688.       if ( l->buffer[ l->position ] == ')' )
  689.          {
  690.          #if INTENSIVE_DEBUG
  691.          sprintf( bwb_ebuf, "in bwb_xinp(): variable <%s> has dimensions",
  692.             v->name );
  693.          bwb_debug( bwb_ebuf );
  694.          #endif
  695.          dim_getparams( l->buffer, &( l->position ), &n_params, &pp );
  696.          for ( n = 0; n < v->dimensions; ++n )
  697.             {
  698.             v->array_pos[ n ] = pp[ n ];
  699.             }
  700.          }
  701.  
  702.       inp_advws( f );
  703.  
  704.       /* perform type-specific input */
  705.  
  706.       switch( v->type )
  707.          {
  708.          case STRING:
  709.             if ( inp_xgetc( f, TRUE ) != '\"' )
  710.                {
  711.                #if PROG_ERRORS
  712.                sprintf( bwb_ebuf, "in bwb_xinp(): expected quotation mark" );
  713.                bwb_error( bwb_ebuf );
  714.                #else
  715.                bwb_error( err_mismatch );
  716.                #endif
  717.                }
  718.             n = 0;
  719.             while ( ( c = (char) inp_xgetc( f, TRUE )) != '\"' )
  720.                {
  721.                tbuf[ n ] = c;
  722.                ++n;
  723.                tbuf[ n ] = '\0';
  724.                }
  725.             str_ctob( var_findsval( v, v->array_pos ), tbuf );
  726.             #if INTENSIVE_DEBUG
  727.             sprintf( bwb_ebuf, "in bwb_xinp(): read STRING <%s>",
  728.                tbuf );
  729.             bwb_debug( bwb_ebuf );
  730.             #endif
  731.             inp_eatcomma( f );
  732.             break;
  733.          case INTEGER:
  734.             n = 0;
  735.             while ( ( c = (char) inp_xgetc( f, FALSE )) != ',' )
  736.                {
  737.                tbuf[ n ] = c;
  738.                ++n;
  739.                tbuf[ n ] = '\0';
  740.                }
  741.             #if INTENSIVE_DEBUG
  742.             sprintf( bwb_ebuf, "in bwb_xinp(): read INTEGER <%s>",
  743.                tbuf );
  744.             bwb_debug( bwb_ebuf );
  745.             #endif
  746.             * var_findival( v, v->array_pos ) = atoi( tbuf );
  747.             break;
  748.          case DOUBLE:
  749.             n = 0;
  750.             while ( ( c = (char) inp_xgetc( f, FALSE )) != ',' )
  751.                {
  752.                tbuf[ n ] = c;
  753.                ++n;
  754.                tbuf[ n ] = '\0';
  755.                }
  756.             #if INTENSIVE_DEBUG
  757.             sprintf( bwb_ebuf, "in bwb_xinp(): read DOUBLE <%s>",
  758.                tbuf );
  759.             bwb_debug( bwb_ebuf );
  760.             #endif
  761.             * var_finddval( v, v->array_pos ) = (double) atof( tbuf );
  762.             break;
  763.          default:            /* take SINGLE as default */
  764.             n = 0;
  765.             while ( ( c = (char) inp_xgetc( f, FALSE )) != ',' )
  766.                {
  767.                tbuf[ n ] = c;
  768.                ++n;
  769.                tbuf[ n ] = '\0';
  770.                }
  771.             #if INTENSIVE_DEBUG
  772.             sprintf( bwb_ebuf, "in bwb_xinp(): read SINGLE <%s>",
  773.                tbuf );
  774.             bwb_debug( bwb_ebuf );
  775.             #endif
  776.             * var_findfval( v, v->array_pos ) = (float) atof( tbuf );
  777.             break;
  778.          }                /* end of switch for type-specific input */
  779.  
  780.       /* check for comma */
  781.  
  782.       adv_ws( l->buffer, &( l->position ) );
  783.       if ( l->buffer[ l->position ] == ',' )
  784.          {
  785.          ++( l->position );
  786.          }
  787.       else
  788.          {
  789.          loop = FALSE;
  790.          }
  791.  
  792.       }
  793.  
  794.    /* return */
  795.  
  796.    return l;
  797.  
  798.    }
  799.  
  800. /***************************************************************
  801.  
  802.         FUNCTION:       inp_advws()
  803.  
  804.         DESCRIPTION:    
  805.  
  806. ***************************************************************/
  807.  
  808. int
  809. inp_advws( FILE *f )
  810.    {
  811.    register int c;
  812.    int loop;
  813.  
  814.    loop = TRUE;
  815.    while ( loop == TRUE )
  816.       {
  817.       c = (char) inp_xgetc( f, TRUE );
  818.  
  819.       switch( c )
  820.          {
  821.          case '\n':
  822.          case '\r':
  823.          case ' ':
  824.          case '\t':
  825.             break;
  826.          default:
  827.             char_saved = TRUE;
  828.             cs = c;
  829.             loop = FALSE;
  830.             break;
  831.          }
  832.       }   
  833.  
  834.    return TRUE;
  835.    }
  836.  
  837. /***************************************************************
  838.  
  839.         FUNCTION:       inp_xgetc()
  840.  
  841.         DESCRIPTION:    
  842.  
  843. ***************************************************************/
  844.  
  845. int
  846. inp_xgetc( FILE *f, int is_string )
  847.    {
  848.    register int c;
  849.    static int prev_eof = FALSE;
  850.  
  851.    if ( char_saved == TRUE )
  852.       {
  853.       char_saved = FALSE;
  854.       return cs;
  855.       }
  856.  
  857.    if ( feof( f ) != 0 )
  858.       {
  859.       if ( prev_eof == TRUE )
  860.          {
  861.          bwb_error( err_od );
  862.          }
  863.       else
  864.          {
  865.      prev_eof = TRUE;
  866.      return (int) ',';
  867.      }
  868.       }
  869.  
  870.    prev_eof = FALSE;
  871.  
  872.    c = fgetc( f );
  873.  
  874.    if ( is_string == TRUE )
  875.       {
  876.       return c;
  877.       }
  878.       
  879.    switch( c )
  880.       {
  881.       case ' ':
  882.       case '\n':
  883.       case ',':
  884.       case '\r':
  885.          return ',';
  886.       }
  887.  
  888.    return c;
  889.  
  890.    }
  891.  
  892. /***************************************************************
  893.  
  894.         FUNCTION:       inp_eatcomma()
  895.  
  896.         DESCRIPTION:    
  897.  
  898. ***************************************************************/
  899.  
  900. int
  901. inp_eatcomma( FILE *f )
  902.    {
  903.    char c;
  904.  
  905.    while ( ( c = (char) inp_xgetc( f, TRUE ) ) == ',' )
  906.       {
  907.       }
  908.       
  909.    char_saved = TRUE;
  910.    cs = c;
  911.       
  912.    return TRUE;
  913.    }
  914.  
  915. /***************************************************************
  916.  
  917.         FUNCTION:       inp_str()
  918.  
  919.         DESCRIPTION:    This function does INPUT processing
  920.                         from a determined string of input
  921.                         data and a determined variable list
  922.                         (both in memory).  This presupposes
  923.             that input has been taken from stdin,
  924.             not from a disk file or device.
  925.  
  926. ***************************************************************/
  927.  
  928. struct bwb_line *
  929. inp_str( struct bwb_line *l, char *input_buffer, char *var_list, int *vl_position )
  930.    {
  931.    int i;
  932.    register int n;
  933.    struct bwb_variable *v;
  934.    int loop;
  935.    int *pp;
  936.    int n_params;
  937.    char ttbuf[ MAXSTRINGSIZE + 1 ];        /* build element */
  938.    char varname[ MAXSTRINGSIZE + 1 ];        /* build element */
  939.  
  940.    #if INTENSIVE_DEBUG
  941.    sprintf( bwb_ebuf, "in inp_str(): received line <%s>",
  942.       l->buffer );
  943.    bwb_debug( bwb_ebuf );
  944.    sprintf( bwb_ebuf, "in inp_str(): received variable list <%s>.",
  945.       &( var_list[ *vl_position ] ) );
  946.    bwb_debug( bwb_ebuf );
  947.    sprintf( bwb_ebuf, "in inp_str(): received input buffer  <%s>.",
  948.       input_buffer );
  949.    bwb_debug( bwb_ebuf );
  950.    #endif
  951.  
  952.    /* Read elements, and assign them to variables */
  953.  
  954.    i = 0;
  955.    loop = TRUE;
  956.    while ( loop == TRUE )
  957.       {
  958.  
  959.       /* get a variable name from the list */
  960.  
  961.       bwb_getvarname( var_list, varname, vl_position );    /* get name */
  962.       v = var_find( varname );
  963.  
  964.       #if INTENSIVE_DEBUG
  965.       sprintf( bwb_ebuf, "in inp_str(): found variable buffer <%s> name <%s>",
  966.          varname, v->name );
  967.       bwb_debug( bwb_ebuf );
  968.       #endif
  969.  
  970.       /* read subscripts if appropriate */
  971.  
  972.       adv_ws( var_list, vl_position );
  973.       if ( var_list[ *vl_position ] == ')' )
  974.          {
  975.      #if INTENSIVE_DEBUG
  976.      sprintf( bwb_ebuf, "in inp_str(): variable <%s> has dimensions",
  977.         v->name );
  978.      bwb_debug( bwb_ebuf );
  979.      #endif
  980.          dim_getparams( var_list, vl_position, &n_params, &pp );
  981.          for ( n = 0; n < v->dimensions; ++n )
  982.             {
  983.             v->array_pos[ n ] = pp[ n ];
  984.             }
  985.          }
  986.  
  987.       /* build string from input buffer in ttbuf */
  988.  
  989.       n = 0;
  990.       ttbuf[ 0 ] = '\0';
  991.       while ( ( input_buffer[ i ] != ',' )
  992.          &&   ( input_buffer[ i ] != '\0' ))
  993.          {
  994.          ttbuf[ n ] = input_buffer[ i ];
  995.          ++n;
  996.          ++i;
  997.          ttbuf[ n ] = '\0';
  998.          }
  999.  
  1000.       #if INTENSIVE_DEBUG
  1001.       sprintf( bwb_ebuf, "in inp_str(): string for input <%s>",
  1002.          ttbuf );
  1003.       bwb_debug( bwb_ebuf );
  1004.       #endif
  1005.  
  1006.       /* perform type-specific input */
  1007.  
  1008.       inp_assign( ttbuf, v );
  1009.  
  1010.       /* check for commas in variable list and input list and advance */
  1011.  
  1012.       adv_ws( var_list, vl_position );
  1013.       switch( var_list[ *vl_position ] )
  1014.      {
  1015.      case '\n':
  1016.      case '\r':
  1017.      case '\0':
  1018.      case ':':
  1019.         loop = FALSE;
  1020.         break;
  1021.      case ',':
  1022.         ++( *vl_position );
  1023.         break;
  1024.          }
  1025.       adv_ws( var_list, vl_position );
  1026.  
  1027.       adv_ws( input_buffer, &i );
  1028.       switch ( input_buffer[ i ] )
  1029.      {
  1030.      case '\n':
  1031.      case '\r':
  1032.      case '\0':
  1033.      case ':':
  1034.         loop = FALSE;
  1035.         break;
  1036.      case ',':
  1037.         ++i;
  1038.         break;
  1039.      }
  1040.       adv_ws( input_buffer, &i );
  1041.  
  1042.       }
  1043.  
  1044.    #if INTENSIVE_DEBUG
  1045.    sprintf( bwb_ebuf, "in inp_str(): exit, line buffer <%s>",
  1046.       &( l->buffer[ l->position ] ) );
  1047.    bwb_debug( bwb_ebuf );
  1048.    #endif
  1049.  
  1050.    /* return */
  1051.  
  1052.    l->next->position = 0;
  1053.    return l->next;
  1054.  
  1055.    }
  1056.  
  1057. /***************************************************************
  1058.  
  1059.         FUNCTION:       inp_assign()
  1060.  
  1061.         DESCRIPTION:    This function assigns the value of a
  1062.                         numerical or string constant to a
  1063.                         variable.
  1064.  
  1065.  
  1066. ***************************************************************/
  1067.  
  1068. int
  1069. inp_assign( char *b, struct bwb_variable *v )
  1070.    {
  1071.  
  1072.    switch( v->type )
  1073.       {
  1074.       case STRING:
  1075.          str_ctob( var_findsval( v, v->array_pos ), b );
  1076.          break;
  1077.  
  1078.       case DOUBLE:
  1079.          if ( strlen( b ) == 0 )
  1080.             {
  1081.             *( var_finddval( v, v->array_pos )) = (double) 0.0;
  1082.             }
  1083.          else
  1084.             {
  1085.             *( var_finddval( v, v->array_pos )) = (double) atof( b );
  1086.             }
  1087.          break;
  1088.  
  1089.       case SINGLE:
  1090.          if ( strlen( b ) == 0 )
  1091.             {
  1092.             *( var_findfval( v, v->array_pos )) = (float) 0.0;
  1093.             }
  1094.          else
  1095.             {
  1096.             *( var_findfval( v, v->array_pos )) = (float) atof( b );
  1097.             }
  1098.          break;
  1099.  
  1100.       case INTEGER:
  1101.          if ( strlen( b ) == 0 )
  1102.             {
  1103.             *( var_findival( v, v->array_pos )) = 0;
  1104.             }
  1105.          else
  1106.             {
  1107.             *( var_findival( v, v->array_pos )) = atoi( b );
  1108.             }
  1109.          break;
  1110.  
  1111.       default:
  1112.          #if PROG_ERRORS
  1113.          sprintf( bwb_ebuf, "in inp_assign(): variable <%s> of unknown type",
  1114.             v->name );
  1115.          bwb_error( bwb_ebuf );
  1116.          #else
  1117.          bwb_error( err_mismatch );
  1118.          #endif
  1119.          return FALSE;
  1120.  
  1121.       }
  1122.  
  1123.    return FALSE;
  1124.  
  1125.    }
  1126.  
  1127. /***************************************************************
  1128.  
  1129.         FUNCTION:       inp_adv()
  1130.  
  1131.         DESCRIPTION:    This function advances the string pointer
  1132.                         past whitespace and the item delimiter
  1133.                         (comma).
  1134.  
  1135. ***************************************************************/
  1136.  
  1137. int
  1138. inp_adv( char *b, int *c )
  1139.    {
  1140.    int rval;
  1141.  
  1142.    rval = FALSE;
  1143.  
  1144.    while( TRUE )
  1145.       {
  1146.       switch( b[ *c ] )
  1147.          {
  1148.          case ' ':              /* whitespace */
  1149.          case '\t':
  1150.          case ';':              /* semicolon, end of prompt string */
  1151.             ++*c;
  1152.             break;
  1153.          case ',':              /* comma, variable delimiter */
  1154.             rval = TRUE;
  1155.             ++*c;
  1156.             break;
  1157.          case '\0':        /* end of line */
  1158.          case ':':         /* end of line segment */
  1159.             rval = TRUE;
  1160.             return rval;
  1161.          default:
  1162.             return rval;
  1163.          }
  1164.       }
  1165.    }
  1166.  
  1167. /***************************************************************
  1168.  
  1169.         FUNCTION:       inp_const()
  1170.  
  1171.         DESCRIPTION:    This function reads a numerical or string
  1172.                         constant from <m_buffer> into <s_buffer>,
  1173.                         incrementing <position> appropriately.
  1174.  
  1175. ***************************************************************/
  1176.  
  1177. int
  1178. inp_const( char *m_buffer, char *s_buffer, int *position )
  1179.    {
  1180.    int string;
  1181.    int s_pos;
  1182.    int loop;
  1183.  
  1184.    #if INTENSIVE_DEBUG
  1185.    sprintf( bwb_ebuf, "in inp_const(): received argument <%s>.",
  1186.       &( m_buffer[ *position ] ) );
  1187.    bwb_debug( bwb_ebuf );
  1188.    #endif
  1189.  
  1190.    string = FALSE;
  1191.  
  1192.    /* first detect string constant */
  1193.  
  1194.    if ( m_buffer[ *position ] == '\"' )
  1195.       {
  1196.       string = TRUE;
  1197.       ++( *position );
  1198.       }
  1199.    else
  1200.       {
  1201.       string = FALSE;
  1202.       }
  1203.  
  1204.    /* build the constant string */
  1205.  
  1206.    s_buffer[ 0 ] = '\0';
  1207.    s_pos = 0;
  1208.    loop = TRUE;
  1209.  
  1210.    while ( loop == TRUE )
  1211.       {
  1212.  
  1213.       switch ( m_buffer[ *position ] )
  1214.          {
  1215.          case '\0':                     /* end of string */
  1216.          case '\n':
  1217.          case '\r':
  1218.             return TRUE;
  1219.          case ' ':                      /* whitespace */
  1220.          case '\t':
  1221.          case ',':                      /* or end of argument */
  1222.             if ( string == FALSE )
  1223.                {
  1224.                return TRUE;
  1225.                }
  1226.             else
  1227.                {
  1228.                s_buffer[ s_pos ] = m_buffer[ *position ];
  1229.                ++( *position );
  1230.                ++s_buffer;
  1231.                s_buffer[ s_pos ] = '\0';
  1232.                }
  1233.             break;
  1234.          case '\"':
  1235.             if ( string == TRUE )
  1236.                {
  1237.                ++( *position );                 /* advance beyond quotation mark */
  1238.                inp_adv( m_buffer, position );
  1239.                return TRUE;
  1240.                }
  1241.             else
  1242.                {
  1243.                #if PROG_ERRORS
  1244.                sprintf( bwb_ebuf, "Unexpected character in numerical constant." );
  1245.                bwb_error( bwb_ebuf );
  1246.                #else
  1247.                bwb_error( err_syntax );
  1248.                #endif
  1249.                return FALSE;
  1250.                }
  1251.          default:
  1252.             s_buffer[ s_pos ] = m_buffer[ *position ];
  1253.             ++( *position );
  1254.             ++s_buffer;
  1255.             s_buffer[ s_pos ] = '\0';
  1256.             break;
  1257.          }
  1258.  
  1259.       }
  1260.  
  1261.    return 0;
  1262.  
  1263.    }
  1264.  
  1265. /***************************************************************
  1266.  
  1267.         FUNCTION:       bwb_line()
  1268.  
  1269.         DESCRIPTION:    This function implements the BASIC LINE
  1270.                         INPUT statement.
  1271.  
  1272.         SYNTAX:         LINE INPUT
  1273.  
  1274. ***************************************************************/
  1275.  
  1276. struct bwb_line *
  1277. bwb_line( struct bwb_line *l )
  1278.    {
  1279.    int dev_no;
  1280.    struct bwb_variable *v;
  1281.    FILE *inp_device;
  1282.    char tbuf[ MAXSTRINGSIZE + 1 ];
  1283.  
  1284.    /* assign default values */
  1285.  
  1286.    inp_device = stdin;
  1287.    l->next->position = 0;
  1288.  
  1289.    /* advance to first element (INPUT statement) */
  1290.  
  1291.    adv_element( l->buffer, &( l->position ), tbuf );
  1292.    bwb_strtoupper( tbuf );
  1293.    if ( strcmp( tbuf, "INPUT" ) != 0 )
  1294.       {
  1295.       bwb_error( err_syntax );
  1296.       return l->next;
  1297.       }
  1298.    adv_ws( l->buffer, &( l->position ) );
  1299.  
  1300.    /* check for semicolon in first position */
  1301.  
  1302.    if ( l->buffer[ l->position ] == ';' )
  1303.       {
  1304.       ++l->position;
  1305.       adv_ws( l->buffer, &( l->position ) );
  1306.       }
  1307.  
  1308.    /* else check for # for file number in first position */
  1309.  
  1310.    else if ( l->buffer[ l->position ] == '#' )
  1311.       {
  1312.       ++l->position;
  1313.       adv_element( l->buffer, &( l->position ), tbuf );
  1314.       adv_ws( l->buffer, &( l->position ));
  1315.       dev_no = atoi( tbuf );
  1316.  
  1317.       #if INTENSIVE_DEBUG
  1318.       sprintf( bwb_ebuf, "in bwb_line(): file number requested <%d>", dev_no );
  1319.       bwb_debug( bwb_ebuf );
  1320.       #endif
  1321.  
  1322.       if ( dev_table[ dev_no ].cfp == NULL )
  1323.          {
  1324.          bwb_error( err_dev );
  1325.          return l->next;
  1326.          }
  1327.       else
  1328.          {
  1329.          inp_device = dev_table[ dev_no ].cfp;
  1330.          }
  1331.       }
  1332.  
  1333.    /* check for comma */
  1334.  
  1335.    if ( l->buffer[ l->position ] == ',' )
  1336.       {
  1337.       ++( l->position );
  1338.       adv_ws( l->buffer, &( l->position ));
  1339.       }
  1340.  
  1341.    /* check for quotation mark indicating prompt */
  1342.  
  1343.    if ( l->buffer[ l->position ] == '\"' )
  1344.       {
  1345.       inp_const( l->buffer, tbuf, &( l->position ) );
  1346.       xprintf( stdout, tbuf );
  1347.       }
  1348.  
  1349.    /* read the variable for assignment */
  1350.  
  1351.    #if INTENSIVE_DEBUG
  1352.    sprintf( bwb_ebuf, "in bwb_line(): tbuf <%s>", 
  1353.       tbuf );
  1354.    bwb_debug( bwb_ebuf );
  1355.    sprintf( bwb_ebuf, "in bwb_line(): line buffer <%s>", 
  1356.       &( l->buffer[ l->position ] ) );
  1357.    bwb_debug( bwb_ebuf );
  1358.    #endif
  1359.  
  1360.    adv_element( l->buffer, &( l->position ), tbuf );
  1361.  
  1362.    #if INTENSIVE_DEBUG
  1363.    sprintf( bwb_ebuf, "in bwb_line(): variable buffer <%s>", tbuf );
  1364.    bwb_debug( bwb_ebuf );
  1365.    #endif
  1366.    v = var_find( tbuf );
  1367.    if ( v->type != STRING )
  1368.       {
  1369.       #if PROG_ERRORS
  1370.       bwb_error( "in bwb_line(): String variable required" );
  1371.       #else
  1372.       bwb_error( err_syntax );
  1373.       #endif
  1374.       return l->next;
  1375.       }
  1376.  
  1377.    #if INTENSIVE_DEBUG
  1378.    sprintf( bwb_ebuf, "in bwb_line(): variable for assignment <%s>", v->name );
  1379.    bwb_debug( bwb_ebuf );
  1380.    #endif
  1381.  
  1382.    /* read a line of text into the bufffer */
  1383.  
  1384.    fgets( tbuf, MAXSTRINGSIZE, inp_device );
  1385.    bwb_stripcr( tbuf );
  1386.    str_ctob( var_findsval( v, v->array_pos ), tbuf );
  1387.  
  1388.    /* end: return next line */
  1389.  
  1390.    return l->next;
  1391.    }
  1392.  
  1393.