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