ChipMaster's bwBASIC This also includes history going back to v2.10. *WARN* some binary files might have been corrupted by CRLF.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1440 lines
34 KiB

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