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.
 
 
 
 
 
 

3399 lines
86 KiB

  1. /***************************************************************
  2. bwb_inp.c Input Routines
  3. for Bywater BASIC Interpreter
  4. Copyright (c) 1993, Ted A. Campbell
  5. Bywater Software
  6. email: tcamp@delphi.com
  7. Copyright and Permissions Information:
  8. All U.S. and international rights are claimed by the author,
  9. Ted A. Campbell.
  10. This software is released under the terms of the GNU General
  11. Public License (GPL), which is distributed with this software
  12. in the file "COPYING". The GPL specifies the terms under
  13. which users may copy and use the software in this distribution.
  14. A separate license is available for commercial distribution,
  15. for information on which you should contact the author.
  16. ***************************************************************/
  17. /*---------------------------------------------------------------*/
  18. /* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */
  19. /* 11/1995 (eidetics@cerf.net). */
  20. /* */
  21. /* Those additionally marked with "DD" were at the suggestion of */
  22. /* Dale DePriest (daled@cadence.com). */
  23. /* */
  24. /* Version 3.00 by Howard Wulf, AF5NE */
  25. /* */
  26. /* Version 3.10 by Howard Wulf, AF5NE */
  27. /* */
  28. /*---------------------------------------------------------------*/
  29. #include "bwbasic.h"
  30. /* Declarations of functions visible to this file only */
  31. static LineType *bwb_xinp(LineType * l, FILE * f, char delimit);
  32. static int inp_str( /* LineType * l, */ char *buffer, char *var_list, int *position, int IsFake);
  33. static int inp_const(char *m_buffer, char *s_buffer, int *position);
  34. static int inp_assign(char *b, VariableType * v, int IsFake, int IsInput);
  35. static int read_data(VariableType *v);
  36. /* ResultCode */
  37. #define RESULT_OK 0
  38. #define RESULT_UNKNOWN 1
  39. #define RESULT_TYPE_MMISMATCH 2
  40. #define RESULT_ARITHMETIC_OVERFLOW 3
  41. /***************************************************************
  42. FUNCTION: bwx_input()
  43. DESCRIPTION: This function outputs the string pointed
  44. to by 'prompt', then inputs a character
  45. string.
  46. ***************************************************************/
  47. int bwb_is_eof( FILE * fp )
  48. {
  49. /*
  50. Have you ever wondered why C file I/O is slow? Here is the reason:
  51. feof() is not set until after a file read error occurs; sad but true.
  52. In order to determine whether you are at the end-of-file,
  53. you have to call both ftell() and fseek() twice,
  54. which effectively trashes any I/O cache scheme.
  55. */
  56. if( fp != NULL )
  57. {
  58. long current;
  59. long total;
  60. current = ftell( fp );
  61. fseek( fp, 0, SEEK_END );
  62. total = ftell( fp ) ;
  63. if( total == current )
  64. {
  65. /* EOF */
  66. return TRUE;
  67. }
  68. else
  69. {
  70. /* NOT EOF */
  71. fseek( fp, current, SEEK_SET );
  72. return FALSE;
  73. }
  74. }
  75. /* a closed file is always EOF */
  76. return TRUE;
  77. }
  78. static void clean_cr_lf( char * buffer )
  79. {
  80. /*
  81. some compilers remove CR, but not LF.
  82. some compilers remove LF, but not CR.
  83. some compilers remove CR/LF but not LF/CR.
  84. some compilers remove either CR or LF.
  85. some compilers remove first CR or LF, but not second LF or CR.
  86. */
  87. char *E;
  88. E = bwb_strchr(buffer, '\r');
  89. if( E != NULL )
  90. {
  91. *E = BasicNulChar;
  92. }
  93. E = bwb_strchr(buffer, '\n');
  94. if( E != NULL )
  95. {
  96. *E = BasicNulChar;
  97. }
  98. }
  99. int
  100. bwx_input(char *prompt, char *buffer)
  101. {
  102. bwx_DEBUG(__FUNCTION__);
  103. prn_xprintf(prompt);
  104. fflush( My->SYSOUT->cfp );
  105. /* for automated testing, TAPE command */
  106. if (My->IsCommandLineFile == TRUE)
  107. {
  108. if ( My->ExternalInputFile != NULL )
  109. {
  110. if( fgets(buffer, BasicStringLengthMax, My->ExternalInputFile) == NULL
  111. || feof( My->ExternalInputFile )
  112. )
  113. {
  114. /* stop reading from external file once all INPUT lines have been read */
  115. fclose(My->ExternalInputFile); /* My->ExternalInputFile != NULL */
  116. My->ExternalInputFile = NULL;
  117. }
  118. else
  119. {
  120. fputs( buffer, My->SYSOUT->cfp );
  121. fflush(My->SYSOUT->cfp);
  122. clean_cr_lf( buffer );
  123. ResetConsoleColumn();
  124. return TRUE;
  125. }
  126. }
  127. }
  128. fgets(buffer, BasicStringLengthMax, My->SYSIN->cfp);
  129. clean_cr_lf( buffer );
  130. ResetConsoleColumn();
  131. return TRUE;
  132. }
  133. LineType *
  134. bwb_BACKSPACE(LineType * l)
  135. {
  136. bwx_DEBUG(__FUNCTION__);
  137. My->CurrentFile = My->SYSIN;
  138. if ( line_skip_char(l,BasicFileNumberPrefix) )
  139. {
  140. /* BACKSPACE # filenum */
  141. int FileNumber;
  142. if( line_read_integer_expression(l, &FileNumber) == FALSE )
  143. {
  144. WARN_SYNTAX_ERROR;
  145. return bwb_zline(l);
  146. }
  147. if( FileNumber < 0 )
  148. {
  149. /* "BACKSPACE # -1" is silently ignored */
  150. return bwb_zline(l);
  151. }
  152. if( FileNumber == 0 )
  153. {
  154. /* "BACKSPACE # 0" is silently ignored */
  155. return bwb_zline(l);
  156. }
  157. My->CurrentFile = find_file_by_number( FileNumber );
  158. if( My->CurrentFile == NULL )
  159. {
  160. WARN_BAD_FILE_NUMBER;
  161. return bwb_zline(l);
  162. }
  163. if ((My->CurrentFile->mode & DEVMODE_READ) == 0)
  164. {
  165. WARN_BAD_FILE_NUMBER;
  166. return bwb_zline(l);
  167. }
  168. /* not for the console */
  169. /* if( TRUE ) */
  170. {
  171. FILE * f;
  172. long Offset;
  173. int DelimiterCount;
  174. int InQuote;
  175. int C;
  176. f = My->CurrentFile->cfp;
  177. Offset = ftell( f );
  178. Offset--;
  179. DelimiterCount = 0;
  180. InQuote = FALSE;
  181. AGAIN:
  182. if( Offset <= 0 )
  183. {
  184. goto DONE;
  185. }
  186. fseek( f, Offset, SEEK_SET );
  187. C = fgetc( f );
  188. if( InQuote )
  189. {
  190. if( C == BasicQuoteChar )
  191. {
  192. InQuote = FALSE;
  193. }
  194. Offset--;
  195. goto AGAIN;
  196. }
  197. if( C == BasicQuoteChar )
  198. {
  199. InQuote = TRUE;
  200. Offset--;
  201. goto AGAIN;
  202. }
  203. if( C == ',' )
  204. {
  205. DelimiterCount++;
  206. if( DelimiterCount > 1 )
  207. {
  208. Offset++;
  209. goto DONE;
  210. }
  211. Offset--;
  212. goto AGAIN;
  213. }
  214. if( C == '\n' )
  215. {
  216. DelimiterCount++;
  217. if( DelimiterCount > 1 )
  218. {
  219. Offset++;
  220. goto DONE;
  221. }
  222. Offset--;
  223. if( Offset <= 0 )
  224. {
  225. goto DONE;
  226. }
  227. fseek( f, Offset, SEEK_SET );
  228. C = fgetc( f );
  229. if( C == '\r' )
  230. {
  231. Offset--;
  232. }
  233. goto AGAIN;
  234. }
  235. if( C == '\r' )
  236. {
  237. DelimiterCount++;
  238. if( DelimiterCount > 1 )
  239. {
  240. Offset++;
  241. goto DONE;
  242. }
  243. Offset--;
  244. if( Offset <= 0 )
  245. {
  246. goto DONE;
  247. }
  248. fseek( f, Offset, SEEK_SET );
  249. C = fgetc( f );
  250. if( C == '\n' )
  251. {
  252. Offset--;
  253. }
  254. goto AGAIN;
  255. }
  256. Offset--;
  257. goto AGAIN;
  258. DONE:
  259. if( Offset < 0 )
  260. {
  261. Offset = 0;
  262. }
  263. fseek( f, Offset, SEEK_SET );
  264. }
  265. }
  266. /* BACKSPACE for console is silently ignored */
  267. return bwb_zline(l);
  268. }
  269. /***************************************************************
  270. FUNCTION: bwb_read()
  271. DESCRIPTION: This function implements the BASIC READ
  272. statement.
  273. SYNTAX: READ variable[, variable...]
  274. ***************************************************************/
  275. LineType *
  276. bwb_READ(LineType * l)
  277. {
  278. bwx_DEBUG(__FUNCTION__);
  279. My->CurrentFile = My->SYSIN;
  280. if ( line_skip_char(l,BasicFileNumberPrefix) )
  281. {
  282. /* READ # filenum, varlist */
  283. int FileNumber;
  284. if( line_read_integer_expression(l, &FileNumber) == FALSE )
  285. {
  286. WARN_SYNTAX_ERROR;
  287. return bwb_zline(l);
  288. }
  289. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
  290. {
  291. /*
  292. CBASIC-II: SERIAL & RANDOM file reads
  293. READ # file_number ; [ scalar_variable [ , ... ] ] ' SERIAL
  294. READ # file_number , record_number ; [ scalar_variable [ , ... ] ] ' RANDOM
  295. */
  296. if( FileNumber <= 0 )
  297. {
  298. WARN_BAD_FILE_NUMBER;
  299. return bwb_zline(l);
  300. }
  301. /* normal file */
  302. My->CurrentFile = find_file_by_number( FileNumber );
  303. if( My->CurrentFile == NULL )
  304. {
  305. WARN_BAD_FILE_NUMBER;
  306. return bwb_zline(l);
  307. }
  308. if( line_skip_char( l, ',' ) /* comma-specific */ )
  309. {
  310. /*
  311. READ # file_number , record_number ; scalar [, scalar] ' RANDOM read
  312. */
  313. /* get the RecordNumber */
  314. int RecordNumber;
  315. if( (My->CurrentFile->mode & DEVMODE_RANDOM) == 0 )
  316. {
  317. WARN_BAD_FILE_MODE;
  318. return bwb_zline(l);
  319. }
  320. if( My->CurrentFile->width <= 0 )
  321. {
  322. WARN_FIELD_OVERFLOW;
  323. return bwb_zline(l);
  324. }
  325. if( line_read_integer_expression( l, &RecordNumber ) == FALSE )
  326. {
  327. WARN_SYNTAX_ERROR;
  328. return bwb_zline(l);
  329. }
  330. if( RecordNumber <= 0 )
  331. {
  332. WARN_BAD_RECORD_NUMBER;
  333. return bwb_zline(l);
  334. }
  335. RecordNumber--; /* BASIC to C */
  336. /* if( TRUE ) */
  337. {
  338. long offset;
  339. offset = RecordNumber;
  340. offset *= My->CurrentFile->width;
  341. fseek( My->CurrentFile->cfp, offset, SEEK_SET );
  342. }
  343. }
  344. if( line_is_eol( l ) )
  345. {
  346. /* READ # filenum */
  347. /* READ # filenum , recnum */
  348. }
  349. else
  350. if( line_skip_char( l, ';' ) )
  351. {
  352. /* READ # filenum ; */
  353. /* READ # filenum , recnum ; */
  354. }
  355. else
  356. {
  357. WARN_SYNTAX_ERROR;
  358. return bwb_zline(l);
  359. }
  360. /* input is not from #0, so branch to bwb_xinp() */
  361. return bwb_xinp(l, My->CurrentFile->cfp, My->CurrentFile->delimit);
  362. }
  363. /*
  364. SERIAL file reads:
  365. READ # file_number
  366. READ # file_number [, scalar]
  367. */
  368. if ( line_skip_comma(l) )
  369. {
  370. /* OK */
  371. }
  372. else
  373. {
  374. WARN_SYNTAX_ERROR;
  375. return bwb_zline(l);
  376. }
  377. if( FileNumber < 0 )
  378. {
  379. /* "READ # -1" is an error */
  380. WARN_BAD_FILE_NUMBER;
  381. return bwb_zline(l);
  382. }
  383. if( FileNumber > 0 )
  384. {
  385. /* normal file */
  386. My->CurrentFile = find_file_by_number( FileNumber );
  387. if( My->CurrentFile == NULL )
  388. {
  389. WARN_BAD_FILE_NUMBER;
  390. return bwb_zline(l);
  391. }
  392. if ((My->CurrentFile->mode & DEVMODE_READ) == 0)
  393. {
  394. WARN_BAD_FILE_NUMBER;
  395. return bwb_zline(l);
  396. }
  397. /* input is not from #0, so branch to bwb_xinp() */
  398. return bwb_xinp(l, My->CurrentFile->cfp, My->CurrentFile->delimit);
  399. }
  400. /* "READ # 0, varlist" is the same as "READ varlist" */
  401. }
  402. /* READ varlist */
  403. do
  404. {
  405. VariableType *v;
  406. /* get a variable */
  407. if( (v = line_read_scalar( l )) == NULL )
  408. {
  409. WARN_SYNTAX_ERROR;
  410. return bwb_zline(l);
  411. }
  412. /* READ data into the variable */
  413. if( read_data(v) == FALSE )
  414. {
  415. WARN_SYNTAX_ERROR;
  416. return bwb_zline(l);
  417. }
  418. }
  419. while( line_skip_comma(l) );
  420. return bwb_zline(l);
  421. }
  422. /***************************************************************
  423. FUNCTION: bwb_data()
  424. DESCRIPTION: This function implements the BASIC DATA
  425. statement, although at the point at which
  426. DATA statements are encountered, no
  427. processing is done. All actual processing
  428. of DATA statements is accomplished by READ
  429. (bwb_read()).
  430. SYNTAX: DATA constant[, constant]...
  431. ***************************************************************/
  432. LineType *
  433. bwb_DATA(LineType * l)
  434. {
  435. bwx_DEBUG(__FUNCTION__);
  436. line_skip_eol(l);
  437. return bwb_zline(l);
  438. }
  439. /***************************************************************
  440. FUNCTION: bwb_restore()
  441. DESCRIPTION: This function implements the BASIC RESTORE
  442. statement.
  443. SYNTAX: RESTORE [line number]
  444. ***************************************************************/
  445. LineType *
  446. bwb_RESET(LineType * l)
  447. {
  448. /* RESET filename$ [, ...] */
  449. VariantType E;
  450. VariantType *e = &E; /* no leaks */
  451. bwx_DEBUG(__FUNCTION__);
  452. My->CurrentFile = My->SYSIN;
  453. do
  454. {
  455. line_skip_spaces(l);
  456. if( line_read_expression( l, e ) == FALSE )
  457. {
  458. WARN_SYNTAX_ERROR;
  459. return bwb_zline(l);
  460. }
  461. if( e->TypeChar == BasicStringSuffix )
  462. {
  463. /* STRING */
  464. /* RESET filename$ ... */
  465. My->CurrentFile = find_file_by_name( e->Buffer );
  466. }
  467. else
  468. {
  469. /* NUMBER -- file must already be OPEN */
  470. /* RESET filenumber ... */
  471. My->CurrentFile = find_file_by_number( (int) bwb_rint( e->Number ) );
  472. }
  473. RELEASE( e );
  474. if( My->CurrentFile == NULL )
  475. {
  476. /* file not OPEN */
  477. /* silently ignored */
  478. }
  479. else
  480. if( My->CurrentFile == My->SYSIN )
  481. {
  482. /* silently ignored */
  483. }
  484. else
  485. if( My->CurrentFile == My->SYSOUT )
  486. {
  487. /* silently ignored */
  488. }
  489. else
  490. if( My->CurrentFile == My->SYSPRN )
  491. {
  492. /* silently ignored */
  493. }
  494. else
  495. {
  496. /* normal file is OPEN */
  497. My->CurrentFile->width = 0;
  498. My->CurrentFile->col = 1;
  499. My->CurrentFile->row = 1;
  500. My->CurrentFile->delimit = ',';
  501. fseek( My->CurrentFile->cfp, 0, SEEK_SET );
  502. }
  503. }
  504. while( line_skip_comma(l) );
  505. return bwb_zline(l);
  506. }
  507. LineType *
  508. bwb_CLOSE(LineType * l)
  509. {
  510. /* CLOSE filename$ [, ...] */
  511. VariantType E;
  512. VariantType *e = &E; /* no leaks */
  513. bwx_DEBUG(__FUNCTION__);
  514. My->CurrentFile = My->SYSIN;
  515. do
  516. {
  517. line_skip_spaces(l);
  518. if( line_read_expression( l, e ) == FALSE )
  519. {
  520. WARN_SYNTAX_ERROR;
  521. return bwb_zline(l);
  522. }
  523. if( e->TypeChar == BasicStringSuffix )
  524. {
  525. /* STRING */
  526. /* CLOSE filename$ ... */
  527. My->CurrentFile = find_file_by_name( e->Buffer );
  528. }
  529. else
  530. {
  531. /* NUMBER -- file must already be OPEN */
  532. /* CLOSE filenumber ... */
  533. My->CurrentFile = find_file_by_number( (int) bwb_rint( e->Number ) );
  534. }
  535. RELEASE( e );
  536. if( My->CurrentFile == NULL )
  537. {
  538. /* file not OPEN */
  539. /* silently ignored */
  540. }
  541. else
  542. if( My->CurrentFile == My->SYSIN )
  543. {
  544. /* silently ignored */
  545. }
  546. else
  547. if( My->CurrentFile == My->SYSOUT )
  548. {
  549. /* silently ignored */
  550. }
  551. else
  552. if( My->CurrentFile == My->SYSPRN )
  553. {
  554. /* silently ignored */
  555. }
  556. else
  557. {
  558. /* normal file is OPEN */
  559. file_clear( My->CurrentFile );
  560. }
  561. }
  562. while( line_skip_comma(l) );
  563. return bwb_zline(l);
  564. }
  565. LineType *
  566. bwb_RESTORE(LineType * l)
  567. {
  568. int LineNumber;
  569. LineType *x;
  570. bwx_DEBUG(__FUNCTION__);
  571. My->CurrentFile = My->SYSIN;
  572. if( My->CurrentVersion->OptionVersionBitmask & ( I70 ) )
  573. {
  574. /* RESTORE [comment] */
  575. line_skip_eol(l);
  576. My->data_line = My->bwb_start.next;
  577. My->data_pos = My->data_line->Startpos;
  578. return bwb_zline(l);
  579. }
  580. /* get the first element beyond the starting position */
  581. if( line_skip_char(l, BasicFileNumberPrefix ) )
  582. {
  583. /* RESTORE # X */
  584. int FileNumber;
  585. if( line_read_integer_expression( l, &FileNumber ) == FALSE )
  586. {
  587. WARN_BAD_FILE_NUMBER;
  588. return bwb_zline(l);
  589. }
  590. if( FileNumber < 0 )
  591. {
  592. /* "RESTORE # -1" is silently ignored */
  593. return bwb_zline(l);
  594. }
  595. if( FileNumber > 0 )
  596. {
  597. /* normal file */
  598. My->CurrentFile = find_file_by_number( FileNumber );
  599. if( My->CurrentFile == NULL )
  600. {
  601. WARN_BAD_FILE_NUMBER;
  602. return bwb_zline(l);
  603. }
  604. if( My->CurrentFile->mode != DEVMODE_CLOSED )
  605. {
  606. if( My->CurrentFile->cfp != NULL )
  607. {
  608. fclose( My->CurrentFile->cfp ); /* My->CurrentFile->cfp != NULL */
  609. }
  610. if( My->CurrentFile->buffer != NULL )
  611. {
  612. FREE( My->CurrentFile->buffer, "bwb_FILES" );
  613. }
  614. }
  615. My->CurrentFile->width = 0;
  616. My->CurrentFile->col = 1;
  617. My->CurrentFile->row = 1;
  618. My->CurrentFile->delimit = ',';
  619. My->CurrentFile->buffer = NULL;
  620. My->CurrentFile->mode = DEVMODE_CLOSED;
  621. if( bwb_strcmp( My->CurrentFile->filename, "*" ) != 0 )
  622. {
  623. if( (My->CurrentFile->cfp = fopen( My->CurrentFile->filename, "r" )) == NULL )
  624. {
  625. WARN_BAD_FILE_NAME;
  626. return bwb_zline(l);
  627. }
  628. My->CurrentFile->mode = DEVMODE_INPUT;
  629. }
  630. /* OK */
  631. return bwb_zline(l);
  632. }
  633. /* "RESTORE # 0" is the same as "RESTORE" */
  634. }
  635. if( line_is_eol(l) == TRUE )
  636. {
  637. /* RESTORE */
  638. My->data_line = My->bwb_start.next;
  639. My->data_pos = My->data_line->Startpos;
  640. return bwb_zline(l);
  641. }
  642. /* RESTORE linenumber */
  643. if( line_read_integer_expression(l, &LineNumber) == FALSE )
  644. {
  645. WARN_SYNTAX_ERROR;
  646. return bwb_zline(l);
  647. }
  648. /* check for target label */
  649. x = find_line_number( LineNumber, TRUE );
  650. if (x != NULL)
  651. {
  652. /* reassign My->data_line */
  653. My->data_line = x;
  654. My->data_pos = x->Startpos;
  655. return bwb_zline(l);
  656. }
  657. WARN_SYNTAX_ERROR;
  658. return bwb_zline(l);
  659. }
  660. /***************************************************************
  661. FUNCTION: bwb_input()
  662. DESCRIPTION: This function implements the BASIC INPUT
  663. statement.
  664. SYNTAX: INPUT [;][prompt$;]variable[$,variable]...
  665. INPUT#n variable[$,variable]...
  666. ***************************************************************/
  667. LineType *
  668. bwb_GET(LineType * l)
  669. {
  670. bwx_DEBUG(__FUNCTION__);
  671. if( My->CurrentVersion->OptionVersionBitmask & ( I70 | I73 ) )
  672. {
  673. /* GET filename$ , scalar [, ...] */
  674. VariantType E;
  675. VariantType *e = &E;
  676. My->CurrentFile = My->SYSIN;
  677. line_skip_spaces(l);
  678. if( line_read_expression( l, e ) == FALSE )
  679. {
  680. WARN_SYNTAX_ERROR;
  681. return bwb_zline(l);
  682. }
  683. if( e->TypeChar == BasicStringSuffix )
  684. {
  685. /* STRING */
  686. /* GET filename$ ... */
  687. if( is_empty_filename( e->Buffer ) )
  688. {
  689. /* "GET # 0" is an error */
  690. WARN_BAD_FILE_NUMBER;
  691. return bwb_zline(l);
  692. }
  693. My->CurrentFile = find_file_by_name( e->Buffer );
  694. if( My->CurrentFile == NULL )
  695. {
  696. /* implicitly OPEN for reading */
  697. My->CurrentFile = file_new();
  698. My->CurrentFile->cfp = fopen(e->Buffer, "r");
  699. if( My->CurrentFile->cfp == NULL )
  700. {
  701. /* bad file name */
  702. WARN_BAD_FILE_NUMBER;
  703. return bwb_zline(l);
  704. }
  705. My->CurrentFile->FileNumber = file_next_number();
  706. My->CurrentFile->mode = DEVMODE_INPUT;
  707. My->CurrentFile->width = 0;
  708. /* WIDTH == RECLEN */
  709. My->CurrentFile->col = 1;
  710. My->CurrentFile->row = 1;
  711. My->CurrentFile->delimit = ',';
  712. My->CurrentFile->buffer = NULL;
  713. bwb_strcpy(My->CurrentFile->filename, e->Buffer);
  714. }
  715. }
  716. else
  717. {
  718. /* NUMBER -- file must already be OPEN */
  719. /* GET filenumber ... */
  720. if( e->Number < 0 )
  721. {
  722. /* "GET # -1" is an error */
  723. WARN_BAD_FILE_NUMBER;
  724. return bwb_zline(l);
  725. }
  726. if( e->Number == 0 )
  727. {
  728. /* "GET # 0" is an error */
  729. WARN_BAD_FILE_NUMBER;
  730. return bwb_zline(l);
  731. }
  732. My->CurrentFile = find_file_by_number( (int) bwb_rint( e->Number ) );
  733. if( My->CurrentFile == NULL )
  734. {
  735. /* file not OPEN */
  736. WARN_BAD_FILE_NUMBER;
  737. return bwb_zline(l);
  738. }
  739. }
  740. RELEASE( e );
  741. if( My->CurrentFile == NULL )
  742. {
  743. WARN_BAD_FILE_NUMBER;
  744. return bwb_zline(l);
  745. }
  746. if (( My->CurrentFile->mode & DEVMODE_READ) == 0)
  747. {
  748. WARN_BAD_FILE_NUMBER;
  749. return bwb_zline(l);
  750. }
  751. if ( line_skip_comma(l) )
  752. {
  753. /* OK */
  754. }
  755. else
  756. {
  757. WARN_SYNTAX_ERROR;
  758. return bwb_zline(l);
  759. }
  760. return bwb_xinp(l, My->CurrentFile->cfp, My->CurrentFile->delimit);
  761. }
  762. else
  763. if( My->CurrentVersion->OptionVersionBitmask & ( D71 ) )
  764. {
  765. /* GET # file_number [ , RECORD record_number ] */
  766. int file_number = 0;
  767. if( line_skip_char( l, BasicFileNumberPrefix ) == FALSE )
  768. {
  769. /* OPTIONAL */
  770. }
  771. if( line_read_integer_expression( l, &file_number ) == FALSE )
  772. {
  773. WARN_BAD_FILE_NUMBER;
  774. return bwb_zline( l );
  775. }
  776. if( file_number < 1 )
  777. {
  778. WARN_BAD_FILE_NUMBER;
  779. return bwb_zline( l );
  780. }
  781. My->CurrentFile = find_file_by_number( file_number );
  782. if( My->CurrentFile == NULL )
  783. {
  784. WARN_BAD_FILE_NUMBER;
  785. return bwb_zline( l );
  786. }
  787. if( My->CurrentFile->mode != DEVMODE_RANDOM )
  788. {
  789. WARN_BAD_FILE_NUMBER;
  790. return bwb_zline( l );
  791. }
  792. if( My->CurrentFile->width <= 0 )
  793. {
  794. WARN_BAD_FILE_NUMBER;
  795. return bwb_zline( l );
  796. }
  797. if( line_is_eol( l ) )
  798. {
  799. /* GET # file_number */
  800. }
  801. else
  802. {
  803. /* GET # file_number , RECORD record_number */
  804. int record_number = 0;
  805. long offset = 0;
  806. if( line_skip_comma( l ) == FALSE )
  807. {
  808. WARN_SYNTAX_ERROR;
  809. return bwb_zline( l );
  810. }
  811. if( line_skip_word( l, "RECORD" ) == FALSE )
  812. {
  813. WARN_SYNTAX_ERROR;
  814. return bwb_zline( l );
  815. }
  816. if( line_read_integer_expression( l, &record_number ) == FALSE )
  817. {
  818. WARN_BAD_RECORD_NUMBER;
  819. return bwb_zline( l );
  820. }
  821. if( record_number <= 0 )
  822. {
  823. WARN_BAD_RECORD_NUMBER;
  824. return bwb_zline( l );
  825. }
  826. record_number--; /* BASIC to C */
  827. offset = record_number;
  828. offset *= My->CurrentFile->width;
  829. if (fseek(My->CurrentFile->cfp, offset, SEEK_SET) != 0)
  830. {
  831. WARN_BAD_RECORD_NUMBER;
  832. return bwb_zline( l );
  833. }
  834. }
  835. /* if( TRUE ) */
  836. {
  837. int i;
  838. for (i = 0; i < My->CurrentFile->width; i++)
  839. {
  840. int c;
  841. c = fgetc( My->CurrentFile->cfp );
  842. if( /* EOF */ c < 0 )
  843. {
  844. c = BasicNulChar;
  845. }
  846. My->CurrentFile->buffer[i] = c;
  847. }
  848. }
  849. field_get( My->CurrentFile );
  850. /* OK */
  851. return bwb_zline( l );
  852. }
  853. WARN_SYNTAX_ERROR;
  854. return bwb_zline(l);
  855. }
  856. LineType *
  857. bwb_INPUT(LineType * l)
  858. {
  859. int is_prompt;
  860. int suppress_qm;
  861. char tbuf[BasicStringLengthMax + 1];
  862. char pstring[BasicStringLengthMax + 1];
  863. int Loop;
  864. int LastPosition;
  865. bwx_DEBUG(__FUNCTION__);
  866. My->CurrentFile = My->SYSIN;
  867. pstring[0] = BasicNulChar;
  868. if ( line_skip_char(l,BasicFileNumberPrefix) )
  869. {
  870. /* INPUT # X */
  871. int FileNumber;
  872. if( line_read_integer_expression(l, &FileNumber) == FALSE )
  873. {
  874. WARN_SYNTAX_ERROR;
  875. return bwb_zline(l);
  876. }
  877. if ( line_skip_comma(l) )
  878. {
  879. /* OK */
  880. }
  881. else
  882. {
  883. WARN_SYNTAX_ERROR;
  884. return bwb_zline(l);
  885. }
  886. if( FileNumber < 0 )
  887. {
  888. /* "INPUT # -1" is an error */
  889. WARN_BAD_FILE_NUMBER;
  890. return bwb_zline(l);
  891. }
  892. if( FileNumber > 0 )
  893. {
  894. /* normal file */
  895. My->CurrentFile = find_file_by_number( FileNumber );
  896. if( My->CurrentFile == NULL )
  897. {
  898. WARN_BAD_FILE_NUMBER;
  899. return bwb_zline(l);
  900. }
  901. if ((My->CurrentFile->mode & DEVMODE_READ) == 0)
  902. {
  903. WARN_BAD_FILE_NUMBER;
  904. return bwb_zline(l);
  905. }
  906. return bwb_xinp(l, My->CurrentFile->cfp, ',' );
  907. }
  908. /* "INPUT #0, varlist" is the same as "INPUT varlist" */
  909. }
  910. /* from this point we presume that input is from My->SYSIN */
  911. /* check for a semicolon or a quotation mark, not in first position:
  912. * this should indicate a prompt string */
  913. suppress_qm = is_prompt = FALSE;
  914. line_skip_spaces(l);
  915. if( line_skip_comma( l ) )
  916. {
  917. /* INPUT ; "prompt" ... */
  918. /* INPUT , "prompt" ... */
  919. suppress_qm = TRUE;
  920. }
  921. if( line_peek_char( l, BasicQuoteChar ) )
  922. {
  923. is_prompt = TRUE;
  924. }
  925. /* get prompt string and print it */
  926. if (is_prompt == TRUE)
  927. {
  928. /* get string element */
  929. inp_const(l->buffer, pstring, &(l->position)); /* bwb_INPUT prompt */
  930. /* advance past semicolon to beginning of variable */
  931. /*--------------------------------------------------------*/
  932. /* Since inp_const was just called and inp_adv is called */
  933. /* within that, it will have already noted and passed the */
  934. /* comma by the time it gets here. Therefore one must */
  935. /* refer instead to the last returned value for inp_adv! */
  936. /* (JBV, 10/95) */
  937. /*--------------------------------------------------------*/
  938. /* suppress_qm = inp_adv( l->buffer, &( l->position ) ); */
  939. suppress_qm = My->last_inp_adv_rval;
  940. } /* end condition: prompt string */
  941. /* print out the question mark delimiter unless it has been suppressed */
  942. if (suppress_qm != TRUE)
  943. {
  944. pstring[ BasicStringLengthMax - 2 ] = BasicNulChar;
  945. bwb_strcat(pstring, "? ");
  946. }
  947. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
  948. {
  949. /*
  950. CBASIC-II: INPUT "prompt" ; LINE variable$
  951. */
  952. if( line_skip_word( l, "LINE" ) )
  953. {
  954. /* INPUT "prompt" ; LINE variable$ */
  955. VariableType * v;
  956. if( (v = line_read_scalar( l )) == NULL )
  957. {
  958. WARN_SYNTAX_ERROR;
  959. return bwb_zline( l );
  960. }
  961. if ( VAR_IS_STRING( v ) )
  962. {
  963. VariantType variant;
  964. bwx_input(pstring, tbuf);
  965. bwb_stripcr(tbuf);
  966. variant.TypeChar = '$';
  967. variant.Buffer = tbuf;
  968. variant.Length = bwb_strlen( variant.Buffer );
  969. if( var_set( v, &variant ) == FALSE )
  970. {
  971. WARN_VARIABLE_NOT_DECLARED;
  972. return bwb_zline( l );
  973. }
  974. return bwb_zline( l );
  975. }
  976. WARN_TYPE_MISMATCH;
  977. return bwb_zline( l );
  978. }
  979. }
  980. Loop = TRUE;
  981. LastPosition = l->position;
  982. while (Loop == TRUE)
  983. {
  984. /* read a line into the input buffer */
  985. int Result;
  986. bwx_input(pstring, tbuf);
  987. bwb_stripcr(tbuf);
  988. /* reset print column to account for LF at end of fgets() */
  989. ResetConsoleColumn();
  990. l->position = LastPosition;
  991. Result = inp_str( /* l, */ tbuf, l->buffer, &(l->position), TRUE); /* bwb_INPUT */
  992. if( Result > 0 ) /* bwb_INPUT */
  993. {
  994. /* successful input, FAKE run */
  995. l->position = LastPosition;
  996. Result = inp_str( /* l, */ tbuf, l->buffer, &(l->position), FALSE); /* bwb_INPUT */
  997. if( Result > 0 )
  998. {
  999. /* successful input, REAL run */
  1000. Loop = FALSE;
  1001. }
  1002. }
  1003. else
  1004. if( Result < 0 )
  1005. {
  1006. /* syntax error, FAKE run */
  1007. Loop = FALSE;
  1008. }
  1009. else
  1010. {
  1011. fputs( "*** Retry INPUT ***\n", My->SYSOUT->cfp );
  1012. }
  1013. } /* while( Loop == TRUE ) */
  1014. return bwb_zline(l);;
  1015. }
  1016. static int file_read_value( FILE * f, char delimit, VariableType *v )
  1017. {
  1018. char tbuf[BasicStringLengthMax + 1];
  1019. int c; /* character */
  1020. /* advance beyond whitespace or comma in data buffer */
  1021. /* Advance to next line if end of buffer */
  1022. /* advance beyond whitespace in data buffer */
  1023. /* leading whitespace is NOT part of the DATA item */
  1024. do
  1025. {
  1026. c = fgetc(f);
  1027. if (c < 0)
  1028. {
  1029. /* EOF */
  1030. return FALSE;
  1031. }
  1032. if( c == delimit )
  1033. {
  1034. break;
  1035. }
  1036. }
  1037. while ( ! bwb_isgraph(c) );
  1038. /* now at last we have a variable in v that needs to
  1039. * be assigned data from the data_buffer at position
  1040. * My->data_pos. What remains to be done is to
  1041. * get one single bit of data, a string constant or
  1042. * numerical constant, into the small buffer */
  1043. {
  1044. int string; /* a quoted string */
  1045. int s_pos;
  1046. int loop;
  1047. string = FALSE;
  1048. s_pos = 0;
  1049. loop = TRUE;
  1050. /* build the constant string */
  1051. while (loop == TRUE)
  1052. {
  1053. if (c == delimit)
  1054. {
  1055. if (string == FALSE)
  1056. {
  1057. /* end of argument */
  1058. loop = FALSE;
  1059. }
  1060. else
  1061. {
  1062. /* internal comma is
  1063. * part of the DATA
  1064. * item */
  1065. tbuf[s_pos] = c;
  1066. ++s_pos;
  1067. }
  1068. }
  1069. else
  1070. if ( ! bwb_isprint(c) )
  1071. {
  1072. /* END-OF-LINE */
  1073. loop = FALSE;
  1074. }
  1075. else
  1076. if (c == BasicQuoteChar)
  1077. {
  1078. /* Once we finish reading a
  1079. * quoted string, we want
  1080. * to continue reading spaces
  1081. * until EOL or comma */
  1082. if (string == TRUE)
  1083. {
  1084. string = FALSE;
  1085. }
  1086. else
  1087. {
  1088. string = TRUE;
  1089. }
  1090. tbuf[s_pos] = c;
  1091. ++s_pos;
  1092. }
  1093. else
  1094. {
  1095. tbuf[s_pos] = c;
  1096. ++s_pos;
  1097. }
  1098. if (loop == TRUE)
  1099. {
  1100. /* read another character */
  1101. c = fgetc(f);
  1102. if (c < 0)
  1103. {
  1104. /* EOF */
  1105. return FALSE;
  1106. }
  1107. }
  1108. }
  1109. if (string == FALSE)
  1110. {
  1111. /* trailing whitespace is NOT part of
  1112. * the DATA item */
  1113. while (s_pos > 0 && tbuf[s_pos - 1] == ' ')
  1114. {
  1115. s_pos--;
  1116. }
  1117. }
  1118. tbuf[s_pos] = BasicNulChar;
  1119. /* clean-up quoted string */
  1120. if (s_pos > 0 && tbuf[0] == BasicQuoteChar)
  1121. {
  1122. /* not an empty string */
  1123. char *Q;
  1124. Q = bwb_strrchr(&tbuf[1], BasicQuoteChar);
  1125. if (Q != NULL)
  1126. {
  1127. *Q = BasicNulChar;
  1128. }
  1129. bwb_strcpy(tbuf, &(tbuf[1]) );
  1130. }
  1131. }
  1132. /* if( TRUE ) */
  1133. {
  1134. VariantType variant;
  1135. variant.TypeChar = v->VariableTypeChar;
  1136. if ( VAR_IS_STRING( v ) )
  1137. {
  1138. variant.Buffer = tbuf;
  1139. variant.Length = bwb_strlen( variant.Buffer );
  1140. }
  1141. else
  1142. {
  1143. /* N = VAL( A$ ) */
  1144. BasicNumberType Value = 0;
  1145. if (tbuf[0] != BasicNulChar)
  1146. {
  1147. int ScanResult;
  1148. ScanResult = sscanf(tbuf, BasicNumberScanFormat, &Value);
  1149. if (ScanResult != 1)
  1150. {
  1151. /* not a number */
  1152. Value = 0;
  1153. }
  1154. else
  1155. {
  1156. /* OK */
  1157. }
  1158. }
  1159. variant.Number = Value;
  1160. }
  1161. if( var_set( v, &variant ) == FALSE )
  1162. {
  1163. WARN_VARIABLE_NOT_DECLARED;
  1164. return FALSE;
  1165. }
  1166. }
  1167. /* OK */
  1168. return TRUE;
  1169. }
  1170. static LineType * bwb_xinp(LineType * l, FILE * f, char delimit)
  1171. {
  1172. /* INPUT # is similar to READ, where each file line is a DATA line */
  1173. int main_loop;
  1174. VariableType *v;
  1175. bwx_DEBUG(__FUNCTION__);
  1176. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
  1177. {
  1178. /*
  1179. CBASIC-II: READ # filenumber [, recnum ] ; LINE variable$
  1180. */
  1181. if( line_skip_word( l, "LINE" ) )
  1182. {
  1183. /* INPUT "prompt" ; LINE variable$ */
  1184. VariableType * v;
  1185. if( (v = line_read_scalar( l )) == NULL )
  1186. {
  1187. WARN_SYNTAX_ERROR;
  1188. return bwb_zline( l );
  1189. }
  1190. if ( VAR_IS_STRING( v ) )
  1191. {
  1192. char tbuf[ BasicStringLengthMax + 1 ];
  1193. if( fgets( tbuf, BasicStringLengthMax, f ) == NULL || feof( f ) )
  1194. {
  1195. /* IF END # file_number THEN line_number */
  1196. if( My->CurrentFile->EOF_LineNumber > 0 )
  1197. {
  1198. LineType *x;
  1199. x = find_line_number( My->CurrentFile->EOF_LineNumber, TRUE ); /* not found in the cache */
  1200. if (x != NULL)
  1201. {
  1202. /* FOUND */
  1203. line_skip_eol(l);
  1204. x->position = 0;
  1205. return x;
  1206. }
  1207. /* NOT FOUND */
  1208. WARN_UNDEFINED_LINE;
  1209. return bwb_zline(l);
  1210. }
  1211. }
  1212. bwb_stripcr(tbuf);
  1213. /* if( TRUE ) */
  1214. {
  1215. VariantType variant;
  1216. variant.TypeChar = '$';
  1217. variant.Buffer = tbuf;
  1218. variant.Length = bwb_strlen( variant.Buffer );
  1219. if( var_set( v, &variant ) == FALSE )
  1220. {
  1221. WARN_VARIABLE_NOT_DECLARED;
  1222. return bwb_zline( l );
  1223. }
  1224. }
  1225. return bwb_zline( l );
  1226. }
  1227. WARN_TYPE_MISMATCH;
  1228. return bwb_zline( l );
  1229. }
  1230. }
  1231. /* Process each variable read from the READ statement */
  1232. main_loop = TRUE;
  1233. while (main_loop == TRUE)
  1234. {
  1235. int adv_loop;
  1236. /* first check position in l->buffer and advance beyond
  1237. * whitespace */
  1238. adv_loop = TRUE;
  1239. while (adv_loop == TRUE)
  1240. {
  1241. switch (l->buffer[l->position])
  1242. {
  1243. case ',': /* variable seperator */
  1244. case ' ': /* whitespace */
  1245. ++l->position;
  1246. break;
  1247. case BasicNulChar:
  1248. adv_loop = FALSE; /* break out of advance
  1249. * loop */
  1250. main_loop = FALSE; /* break out of main
  1251. * loop */
  1252. break;
  1253. default: /* anything else */
  1254. adv_loop = FALSE; /* break out of advance
  1255. * loop */
  1256. break;
  1257. }
  1258. }
  1259. /* be sure main_loop id still valid after checking the line */
  1260. if (main_loop == TRUE)
  1261. {
  1262. /* Read a variable name */
  1263. if( (v = line_read_scalar( l )) == NULL )
  1264. {
  1265. WARN_SYNTAX_ERROR;
  1266. return bwb_zline(l);
  1267. }
  1268. /* Read a file value */
  1269. if( file_read_value( f, delimit, v ) == FALSE )
  1270. {
  1271. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
  1272. {
  1273. /* IF END # file_number THEN line_number */
  1274. if( My->CurrentFile->EOF_LineNumber > 0 )
  1275. {
  1276. LineType *x;
  1277. x = find_line_number( My->CurrentFile->EOF_LineNumber, TRUE ); /* not found in the cache */
  1278. if (x != NULL)
  1279. {
  1280. /* FOUND */
  1281. line_skip_eol(l);
  1282. x->position = 0;
  1283. return x;
  1284. }
  1285. /* NOT FOUND */
  1286. WARN_UNDEFINED_LINE;
  1287. return bwb_zline(l);
  1288. }
  1289. }
  1290. WARN_INPUT_PAST_END;
  1291. return bwb_zline(l);
  1292. }
  1293. /* OK */
  1294. } /* end of remainder of main loop */
  1295. } /* end of main_loop */
  1296. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) && My->CurrentFile->mode & DEVMODE_RANDOM )
  1297. {
  1298. /*
  1299. CBASIC-II: RANDOM file reads always acccess a complete record
  1300. */
  1301. long ByteOffset;
  1302. /* advance to the end-of-record */
  1303. if( My->CurrentFile->width <= 0 )
  1304. {
  1305. WARN_FIELD_OVERFLOW;
  1306. return bwb_zline(l);
  1307. }
  1308. ByteOffset = ftell( My->CurrentFile->cfp );
  1309. ByteOffset %= My->CurrentFile->width;
  1310. if( ByteOffset != 0 )
  1311. {
  1312. long RecordNumber;
  1313. RecordNumber = ftell( My->CurrentFile->cfp );
  1314. RecordNumber /= My->CurrentFile->width;
  1315. RecordNumber ++;
  1316. RecordNumber *= My->CurrentFile->width;
  1317. fseek( My->CurrentFile->cfp, RecordNumber, SEEK_SET );
  1318. }
  1319. }
  1320. return bwb_zline(l);
  1321. }
  1322. /***************************************************************
  1323. FUNCTION: inp_str()
  1324. DESCRIPTION: This function does INPUT processing
  1325. from a determined string of input
  1326. data and a determined variable list
  1327. (both in memory). This presupposes
  1328. that input has been taken from My->SYSIN,
  1329. not from a disk file or device.
  1330. ***************************************************************/
  1331. static int inp_str( /* LineType * l, */ char *input_buffer, char *var_list, int *vl_position, int IsFake)
  1332. {
  1333. int i;
  1334. int loop;
  1335. char ttbuf[BasicStringLengthMax + 1]; /* build element */
  1336. int ReadAllVars;
  1337. int ReadAllData;
  1338. bwx_DEBUG(__FUNCTION__);
  1339. ReadAllVars = FALSE;
  1340. ReadAllData = FALSE;
  1341. /* Read elements in input_buffer and assign them to variables in var_list */
  1342. i = 0;
  1343. loop = TRUE;
  1344. while (loop == TRUE)
  1345. {
  1346. VariableType *v;
  1347. register int n;
  1348. n = 0;
  1349. ttbuf[0] = BasicNulChar;
  1350. buff_skip_spaces( input_buffer, &i );
  1351. buff_skip_spaces( var_list, vl_position );
  1352. /* get a variable name from the list */
  1353. if( (v = buff_read_scalar( var_list, vl_position )) == NULL )
  1354. {
  1355. WARN_SYNTAX_ERROR;
  1356. return -1; /* FATAL */
  1357. }
  1358. /* build string from input buffer in ttbuf */
  1359. if( VAR_IS_STRING( v ) )
  1360. {
  1361. /* STRING */
  1362. if( input_buffer[ i ] == BasicQuoteChar )
  1363. {
  1364. /* QUOTED STRING */
  1365. int q = 0; /* number of quotes */
  1366. i++;
  1367. q++;
  1368. while( input_buffer[ i ] )
  1369. {
  1370. if( input_buffer[ i ] == BasicQuoteChar )
  1371. {
  1372. i++; /* quote */
  1373. q++;
  1374. if( input_buffer[ i ] == BasicQuoteChar )
  1375. {
  1376. /* embedded string "...""..." */
  1377. q++;
  1378. }
  1379. else
  1380. {
  1381. /* properly terminated string "...xx..." */
  1382. break;
  1383. }
  1384. }
  1385. ttbuf[ n ] = input_buffer[ i ];
  1386. n++;
  1387. i++;
  1388. }
  1389. ttbuf[ n ] = BasicNulChar;
  1390. /* process QUOTED response */
  1391. if (My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* INPUT allows empty string */ )
  1392. {
  1393. /* silently ignore */
  1394. }
  1395. else
  1396. {
  1397. /* an ODD number of quotes is an ERROR */
  1398. if( q & 1 )
  1399. {
  1400. fputs( "*** Type Mismatch ***\n", My->SYSOUT->cfp) ;
  1401. return FALSE; /* RETRY */
  1402. }
  1403. }
  1404. }
  1405. else
  1406. {
  1407. /* UNQUOTED STRING */
  1408. while( input_buffer[ i ] )
  1409. {
  1410. if( input_buffer[ i ] == ',' )
  1411. {
  1412. break;
  1413. }
  1414. ttbuf[ n ] = input_buffer[ i ];
  1415. n++;
  1416. i++;
  1417. }
  1418. ttbuf[ n ] = BasicNulChar;
  1419. /* RTRIM */
  1420. while( n > 0 && ttbuf[ n - 1 ] == ' ' )
  1421. {
  1422. ttbuf[ n - 1 ] = BasicNulChar;
  1423. n--;
  1424. }
  1425. /* process EMPTY response */
  1426. if (My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* INPUT allows empty string */ )
  1427. {
  1428. /* silently ignore */
  1429. }
  1430. else
  1431. {
  1432. /* an EMPTY response is an ERROR */
  1433. if (ttbuf[0] == BasicNulChar)
  1434. {
  1435. fputs( "*** Type Mismatch ***\n", My->SYSOUT->cfp );
  1436. return FALSE; /* RETRY */
  1437. }
  1438. }
  1439. /* process UNQUOTED response */
  1440. if (My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* INPUT allows unquoted strings */ )
  1441. {
  1442. /* silently ignore */
  1443. }
  1444. else
  1445. {
  1446. /* if was NOT quoted, then the only valid chars are ' ', '+', '-', '.', digit, letter */
  1447. char *P;
  1448. P = ttbuf;
  1449. while (*P != BasicNulChar)
  1450. {
  1451. char C;
  1452. C = *P;
  1453. P++;
  1454. /* switch */
  1455. if (C == ' ' || C == '+' || C == '-' || C == '.' || bwb_isdigit(C) || bwb_isalpha(C))
  1456. {
  1457. /* OK */
  1458. }
  1459. else
  1460. {
  1461. /* ERROR */
  1462. fputs( "*** Type Mismatch ***\n", My->SYSOUT->cfp );
  1463. return FALSE; /* RETRY */
  1464. }
  1465. }
  1466. }
  1467. }
  1468. }
  1469. else
  1470. {
  1471. /* NUMBER */
  1472. while( input_buffer[ i ] )
  1473. {
  1474. if( input_buffer[ i ] == ',' )
  1475. {
  1476. break;
  1477. }
  1478. ttbuf[ n ] = input_buffer[ i ];
  1479. n++;
  1480. i++;
  1481. }
  1482. ttbuf[ n ] = BasicNulChar;
  1483. /* RTRIM */
  1484. while( n > 0 && ttbuf[ n - 1 ] == ' ' )
  1485. {
  1486. ttbuf[ n - 1 ] = BasicNulChar;
  1487. n--;
  1488. }
  1489. /* process EMPTY response */
  1490. if (My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* INPUT allows empty string */ )
  1491. {
  1492. /* silently ignore */
  1493. }
  1494. else
  1495. {
  1496. /* an EMPTY response is an ERROR */
  1497. if (ttbuf[0] == BasicNulChar)
  1498. {
  1499. fputs( "*** Type Mismatch ***\n", My->SYSOUT->cfp );
  1500. return FALSE; /* RETRY */
  1501. }
  1502. }
  1503. }
  1504. /* perform type-specific assignment */
  1505. {
  1506. int ResultCode;
  1507. ResultCode = inp_assign(ttbuf, v, IsFake, TRUE); /* inp_str, bwb_INPUT */
  1508. switch (ResultCode)
  1509. {
  1510. case RESULT_OK:
  1511. break;
  1512. case RESULT_UNKNOWN:
  1513. WARN_INTERNAL_ERROR;
  1514. return -1; /* FATAL */
  1515. /* break; */
  1516. case RESULT_TYPE_MMISMATCH:
  1517. fputs("*** Type Mismatch ***\n", My->SYSOUT->cfp );
  1518. return FALSE; /* RETRY */
  1519. /* break; */
  1520. case RESULT_ARITHMETIC_OVERFLOW:
  1521. fputs("*** Overflow ***\n", My->SYSOUT->cfp );
  1522. return FALSE; /* RETRY */
  1523. /* break; */
  1524. }
  1525. }
  1526. /* OK */
  1527. /* check for commas in variable list and advance */
  1528. buff_skip_spaces(var_list, vl_position);
  1529. switch (var_list[*vl_position])
  1530. {
  1531. case BasicNulChar:
  1532. loop = FALSE;
  1533. ReadAllVars = TRUE;
  1534. break;
  1535. case ',':
  1536. ++(*vl_position);
  1537. break;
  1538. }
  1539. buff_skip_spaces(var_list, vl_position);
  1540. /* check for commas in input list and advance */
  1541. buff_skip_spaces(input_buffer, &i);
  1542. switch (input_buffer[i])
  1543. {
  1544. case BasicNulChar:
  1545. loop = FALSE;
  1546. ReadAllData = TRUE;
  1547. break;
  1548. case ',':
  1549. ++i;
  1550. break;
  1551. }
  1552. buff_skip_spaces(input_buffer, &i);
  1553. }
  1554. /* return */
  1555. if (ReadAllVars == TRUE && ReadAllData == TRUE)
  1556. {
  1557. return 1; /* SUCCESS */
  1558. }
  1559. /* READ/DATA mismatch */
  1560. fputs("*** Count Mismatch ***\n", My->SYSOUT->cfp );
  1561. return FALSE; /* RETRY */
  1562. }
  1563. /***************************************************************
  1564. FUNCTION: inp_assign()
  1565. DESCRIPTION: This function assigns the value of a
  1566. numerical or string constant to a
  1567. variable.
  1568. ***************************************************************/
  1569. static int inp_assign(char *b, VariableType * v, int IsFake, int IsInput)
  1570. {
  1571. VariantType variant;
  1572. bwx_DEBUG(__FUNCTION__);
  1573. variant.TypeChar = v->VariableTypeChar;
  1574. if( VAR_IS_STRING( v ) )
  1575. {
  1576. /* STRING */
  1577. if (IsFake == TRUE)
  1578. {
  1579. }
  1580. else
  1581. {
  1582. variant.Buffer = b;
  1583. variant.Length = bwb_strlen( variant.Buffer );
  1584. if( var_set( v, &variant ) == FALSE )
  1585. {
  1586. WARN_VARIABLE_NOT_DECLARED;
  1587. return RESULT_UNKNOWN;
  1588. }
  1589. }
  1590. if( My->CurrentVersion->OptionVersionBitmask & ( E78 ) && IsInput == TRUE )
  1591. {
  1592. if (bwb_strchr(b, BasicQuoteChar) != NULL)
  1593. {
  1594. /* ECMA-55 forbids embedded quotes on INPUT */
  1595. return RESULT_TYPE_MMISMATCH;
  1596. }
  1597. }
  1598. return RESULT_OK;
  1599. }
  1600. /* NUMBER */
  1601. if (b[0] == BasicNulChar)
  1602. {
  1603. /* empty input value */
  1604. if (IsFake == TRUE)
  1605. {
  1606. }
  1607. else
  1608. {
  1609. variant.Number = 0.0;
  1610. if( var_set( v, &variant ) == FALSE )
  1611. {
  1612. WARN_VARIABLE_NOT_DECLARED;
  1613. return RESULT_UNKNOWN;
  1614. }
  1615. }
  1616. if (My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* INPUT empty numeric is zero */ )
  1617. {
  1618. return RESULT_OK;
  1619. }
  1620. return RESULT_TYPE_MMISMATCH;
  1621. }
  1622. else
  1623. {
  1624. int ResultCode;
  1625. if (IsFake == TRUE)
  1626. {
  1627. inp_numconst(b, &ResultCode);
  1628. }
  1629. else
  1630. {
  1631. variant.Number = inp_numconst(b, &ResultCode);
  1632. if( var_set( v, &variant ) == FALSE )
  1633. {
  1634. WARN_VARIABLE_NOT_DECLARED;
  1635. return RESULT_UNKNOWN;
  1636. }
  1637. }
  1638. return ResultCode;
  1639. }
  1640. return RESULT_UNKNOWN;
  1641. }
  1642. /***************************************************************
  1643. FUNCTION: inp_adv()
  1644. DESCRIPTION: This function advances the string pointer
  1645. past whitespace and the item delimiter
  1646. (comma).
  1647. ***************************************************************/
  1648. int
  1649. inp_adv(char *b, int *c)
  1650. {
  1651. int rval;
  1652. bwx_DEBUG(__FUNCTION__);
  1653. rval = FALSE;
  1654. while (TRUE)
  1655. {
  1656. switch (b[*c])
  1657. {
  1658. case ' ': /* whitespace */
  1659. case ';': /* semicolon, end of prompt string */
  1660. ++*c;
  1661. break;
  1662. case ',': /* comma, variable delimiter */
  1663. rval = TRUE;
  1664. ++*c;
  1665. break;
  1666. case BasicNulChar: /* end of line */
  1667. rval = TRUE;
  1668. My->last_inp_adv_rval = rval; /* JBV */
  1669. return rval;
  1670. default:
  1671. My->last_inp_adv_rval = rval; /* JBV */
  1672. return rval;
  1673. }
  1674. }
  1675. /* return 0; */ /* never reached */
  1676. }
  1677. /***************************************************************
  1678. FUNCTION: inp_const()
  1679. DESCRIPTION: This function reads a numerical or string
  1680. constant from <m_buffer> into <s_buffer>,
  1681. incrementing <position> appropriately.
  1682. ***************************************************************/
  1683. static int inp_const(char *m_buffer, char *s_buffer, int *position)
  1684. {
  1685. int string;
  1686. int s_pos;
  1687. int loop;
  1688. bwx_DEBUG(__FUNCTION__);
  1689. /* leading whitespace is NOT part of the DATA item */
  1690. buff_skip_spaces(m_buffer,position);
  1691. /* first detect string constant */
  1692. string = FALSE;
  1693. if ( buff_skip_char( m_buffer,position, BasicQuoteChar) )
  1694. {
  1695. string = TRUE;
  1696. }
  1697. /* build the constant string */
  1698. s_pos = 0;
  1699. s_buffer[s_pos] = BasicNulChar;
  1700. loop = TRUE;
  1701. while (loop == TRUE)
  1702. {
  1703. switch (m_buffer[*position])
  1704. {
  1705. case BasicNulChar: /* end of string */
  1706. return TRUE;
  1707. /* internal whitespace is part of the DATA item */
  1708. case ',': /* or end of argument */
  1709. if (string == FALSE)
  1710. {
  1711. /* trailing whitespace is NOT part of the DATA item */
  1712. while (s_pos > 0 && s_buffer[s_pos - 1] == ' ')
  1713. {
  1714. s_pos--;
  1715. s_buffer[s_pos] = BasicNulChar;
  1716. }
  1717. return TRUE;
  1718. }
  1719. else
  1720. {
  1721. s_buffer[s_pos] = m_buffer[*position];
  1722. ++(*position);
  1723. ++s_pos;
  1724. s_buffer[s_pos] = BasicNulChar;
  1725. }
  1726. break;
  1727. case BasicQuoteChar:
  1728. /* quote character */
  1729. if (string == TRUE)
  1730. {
  1731. /* same as the starting quote character; examples are "..." and '...' */
  1732. ++(*position); /* advance beyond quotation mark */
  1733. if( My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* INPUT quotes */ )
  1734. {
  1735. if( m_buffer[*position] == BasicQuoteChar )
  1736. {
  1737. /* embedded string "...""..." */
  1738. s_buffer[s_pos] = m_buffer[*position];
  1739. ++(*position);
  1740. ++s_pos;
  1741. s_buffer[s_pos] = BasicNulChar;
  1742. break;
  1743. }
  1744. }
  1745. /* properly terminated "...xx..." */
  1746. inp_adv(m_buffer, position);
  1747. return TRUE;
  1748. }
  1749. else
  1750. {
  1751. WARN_TYPE_MISMATCH;
  1752. return FALSE;
  1753. }
  1754. default:
  1755. s_buffer[s_pos] = m_buffer[*position];
  1756. ++(*position);
  1757. ++s_pos;
  1758. s_buffer[s_pos] = BasicNulChar;
  1759. break;
  1760. }
  1761. }
  1762. return FALSE;
  1763. }
  1764. /***************************************************************
  1765. FUNCTION: bwb_LINE()
  1766. DESCRIPTION: This function implements the BASIC LINE
  1767. INPUT statement.
  1768. SYNTAX: LINE INPUT [[#] device-number,]["prompt string";] string-variable$
  1769. ***************************************************************/
  1770. LineType *
  1771. bwb_LINE(LineType * l)
  1772. {
  1773. int FileNumber;
  1774. VariableType *v;
  1775. FILE *inp_device;
  1776. char tbuf[BasicStringLengthMax + 1];
  1777. char pstring[BasicStringLengthMax + 1];
  1778. bwx_DEBUG(__FUNCTION__);
  1779. /* assign default values */
  1780. My->CurrentFile = My->SYSIN;
  1781. inp_device = My->SYSIN->cfp;
  1782. pstring[0] = BasicNulChar;
  1783. /* advance to first element (INPUT statement) */
  1784. if( line_skip_word(l, "INPUT") == FALSE )
  1785. {
  1786. WARN_SYNTAX_ERROR;
  1787. return bwb_zline(l);
  1788. }
  1789. line_skip_spaces(l);
  1790. /* check for semicolon in first position */
  1791. if (line_skip_comma(l))
  1792. {
  1793. line_skip_spaces(l);
  1794. }
  1795. else
  1796. if ( line_skip_char(l, BasicFileNumberPrefix) )
  1797. {
  1798. if( line_read_integer_expression(l, &FileNumber) == FALSE )
  1799. {
  1800. WARN_SYNTAX_ERROR;
  1801. return bwb_zline(l);
  1802. }
  1803. if( FileNumber < 0 )
  1804. {
  1805. /* "LINE INPUT # -1" is an error */
  1806. WARN_BAD_FILE_NUMBER;
  1807. return bwb_zline(l);
  1808. }
  1809. if( FileNumber > 0 )
  1810. {
  1811. /* normal file */
  1812. My->CurrentFile = find_file_by_number( FileNumber );
  1813. if( My->CurrentFile == NULL )
  1814. {
  1815. WARN_BAD_FILE_NUMBER;
  1816. return bwb_zline(l);
  1817. }
  1818. if ((My->CurrentFile->mode & DEVMODE_READ) == 0)
  1819. {
  1820. WARN_BAD_FILE_NUMBER;
  1821. return bwb_zline(l);
  1822. }
  1823. if (My->CurrentFile->cfp == NULL)
  1824. {
  1825. WARN_BAD_FILE_NUMBER;
  1826. return bwb_zline(l);
  1827. }
  1828. inp_device = My->CurrentFile->cfp;
  1829. }
  1830. }
  1831. /* check for comma */
  1832. if ( line_skip_comma(l) )
  1833. {
  1834. line_skip_spaces(l);
  1835. }
  1836. /* check for quotation mark indicating prompt */
  1837. if ( line_peek_char(l,BasicQuoteChar))
  1838. {
  1839. inp_const(l->buffer, pstring, &(l->position)); /* bwb_LINE prompt */
  1840. }
  1841. /* read the variable for assignment */
  1842. if( (v = line_read_scalar( l )) == NULL )
  1843. {
  1844. WARN_SYNTAX_ERROR;
  1845. return bwb_zline(l);
  1846. }
  1847. if ( VAR_IS_STRING( v ) )
  1848. {
  1849. /* OK */
  1850. }
  1851. else
  1852. {
  1853. /* ERROR */
  1854. WARN_TYPE_MISMATCH;
  1855. return bwb_zline(l);
  1856. }
  1857. /* read a line of text into the bufffer */
  1858. if (inp_device == My->SYSIN->cfp)
  1859. {
  1860. bwx_input(pstring, tbuf);
  1861. }
  1862. else
  1863. {
  1864. fgets(tbuf, BasicStringLengthMax, inp_device);
  1865. }
  1866. bwb_stripcr(tbuf);
  1867. /* if( TRUE ) */
  1868. {
  1869. VariantType variant;
  1870. variant.TypeChar = '$';
  1871. variant.Buffer = tbuf;
  1872. variant.Length = bwb_strlen( variant.Buffer );
  1873. if( var_set( v, &variant ) == FALSE )
  1874. {
  1875. WARN_VARIABLE_NOT_DECLARED;
  1876. return bwb_zline( l );
  1877. }
  1878. }
  1879. return bwb_zline(l);
  1880. }
  1881. /***************************************************************
  1882. FUNCTION: inp_numconst()
  1883. DESCRIPTION: This function interprets a numerical
  1884. constant. Added by JBV 10/95
  1885. ***************************************************************/
  1886. BasicNumberType
  1887. inp_numconst(char *expression, int *ResultCode)
  1888. {
  1889. int base; /* numerical base for the constant */
  1890. BasicNumberType mantissa;
  1891. int exponent; /* exponent for floating point number */
  1892. int man_start; /* starting point of mantissa */
  1893. int s_pos; /* position in build string */
  1894. int build_loop;
  1895. int need_pm;
  1896. unsigned int u;
  1897. int IsRounded = FALSE;
  1898. /* Expression stack stuff */
  1899. /* char type; */
  1900. BasicNumberType nval;
  1901. char string[BasicStringLengthMax + 1];
  1902. int pos_adv;
  1903. /* initialize the variable if necessary */
  1904. bwx_DEBUG(__FUNCTION__);
  1905. mantissa = 0;
  1906. need_pm = FALSE;
  1907. nval = 0;
  1908. /* check the first character(s) to determine numerical base and
  1909. * starting point of the mantissa */
  1910. switch (expression[0])
  1911. {
  1912. case '-':
  1913. case '+':
  1914. case '0':
  1915. case '1':
  1916. case '2':
  1917. case '3':
  1918. case '4':
  1919. case '5':
  1920. case '6':
  1921. case '7':
  1922. case '8':
  1923. case '9':
  1924. case '.':
  1925. base = 10; /* decimal constant */
  1926. man_start = 0; /* starts at position 0 */
  1927. need_pm = FALSE;
  1928. break;
  1929. case '&': /* hex or octal constant */
  1930. if (bwb_toupper(expression[1] == 'H') )
  1931. {
  1932. base = 16; /* hexadecimal constant */
  1933. man_start = 2; /* starts at position 2 */
  1934. }
  1935. else
  1936. {
  1937. base = 8; /* octal constant */
  1938. if (bwb_toupper(expression[1] == 'O') )
  1939. {
  1940. man_start = 2; /* starts at position 2 */
  1941. }
  1942. else
  1943. {
  1944. man_start = 1; /* starts at position 1 */
  1945. }
  1946. }
  1947. break;
  1948. default:
  1949. *ResultCode = RESULT_TYPE_MMISMATCH;
  1950. return 0;
  1951. }
  1952. /* now build the mantissa according to the numerical base */
  1953. switch (base)
  1954. {
  1955. case 10: /* decimal constant */
  1956. /* initialize counters */
  1957. pos_adv = man_start;
  1958. /* type = NUMBER; */
  1959. string[0] = BasicNulChar;
  1960. s_pos = 0;
  1961. exponent = 0;
  1962. build_loop = TRUE;
  1963. /* loop to build the string */
  1964. while (build_loop == TRUE)
  1965. {
  1966. switch (expression[pos_adv])
  1967. {
  1968. case '-': /* prefixed plus or minus */
  1969. case '+':
  1970. /* in the first position, a plus or minus
  1971. * sign can be added to the beginning of the
  1972. * string to be scanned */
  1973. if (pos_adv == man_start)
  1974. {
  1975. string[s_pos] = expression[pos_adv];
  1976. ++pos_adv; /* advance to next
  1977. * character */
  1978. ++s_pos;
  1979. string[s_pos] = BasicNulChar;
  1980. }
  1981. /* but in any other position, the plus or
  1982. * minus sign must be taken as an operator
  1983. * and thus as terminating the string to be
  1984. * scanned */
  1985. else
  1986. {
  1987. build_loop = FALSE;
  1988. }
  1989. break;
  1990. case '.': /* note at least single precision */
  1991. case '0': /* or ordinary digit */
  1992. case '1':
  1993. case '2':
  1994. case '3':
  1995. case '4':
  1996. case '5':
  1997. case '6':
  1998. case '7':
  1999. case '8':
  2000. case '9':
  2001. string[s_pos] = expression[pos_adv];
  2002. ++pos_adv; /* advance to next character */
  2003. ++s_pos;
  2004. string[s_pos] = BasicNulChar;
  2005. break;
  2006. case BasicCurrencySuffix:
  2007. case BasicLongSuffix:
  2008. case BasicIntegerSuffix:
  2009. case BasicByteSuffix:
  2010. IsRounded = TRUE;
  2011. /* fall thru */
  2012. case BasicDoubleSuffix:
  2013. case BasicSingleSuffix:
  2014. if( My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* TypeChars in constants */ )
  2015. {
  2016. ++pos_adv; /* advance to next character */
  2017. /* type = NUMBER; */
  2018. exponent = FALSE;
  2019. build_loop = FALSE;
  2020. }
  2021. else
  2022. {
  2023. *ResultCode = RESULT_TYPE_MMISMATCH;
  2024. return 0;
  2025. }
  2026. break;
  2027. case 'D': /* exponential, double precision */
  2028. case 'd':
  2029. if( My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* 'D' is exponential */ )
  2030. {
  2031. ++pos_adv; /* advance to next character */
  2032. /* type = NUMBER; */
  2033. exponent = TRUE;
  2034. build_loop = FALSE;
  2035. }
  2036. else
  2037. {
  2038. *ResultCode = RESULT_TYPE_MMISMATCH;
  2039. return 0;
  2040. }
  2041. break;
  2042. case 'E': /* exponential, single precision */
  2043. case 'e':
  2044. ++pos_adv; /* advance to next character */
  2045. /* type = NUMBER; */
  2046. exponent = TRUE;
  2047. build_loop = FALSE;
  2048. break;
  2049. case BasicNulChar:
  2050. build_loop = FALSE;
  2051. break;
  2052. default:
  2053. /* not numeric */
  2054. /* ERROR messages are displayed by the
  2055. * calling routine */
  2056. *ResultCode = RESULT_TYPE_MMISMATCH;
  2057. return 0;
  2058. /* break; */
  2059. }
  2060. }
  2061. /* assign the value to the mantissa variable */
  2062. sscanf(string, BasicNumberScanFormat, &mantissa);
  2063. /* test if integer bounds have been exceeded */
  2064. /* read the exponent if there is one */
  2065. if (exponent == TRUE)
  2066. {
  2067. /* allow a plus or minus once at the beginning */
  2068. need_pm = TRUE;
  2069. /* initialize counters */
  2070. string[0] = BasicNulChar;
  2071. s_pos = 0;
  2072. build_loop = TRUE;
  2073. /* loop to build the string */
  2074. while (build_loop == TRUE)
  2075. {
  2076. switch (expression[pos_adv])
  2077. {
  2078. case '-': /* prefixed plus or minus */
  2079. case '+':
  2080. if (need_pm == TRUE) /* only allow once */
  2081. {
  2082. string[s_pos] = expression[pos_adv];
  2083. ++pos_adv; /* advance to next
  2084. * character */
  2085. ++s_pos;
  2086. string[s_pos] = BasicNulChar;
  2087. }
  2088. else
  2089. {
  2090. build_loop = FALSE;
  2091. }
  2092. break;
  2093. case '0': /* or ordinary digit */
  2094. case '1':
  2095. case '2':
  2096. case '3':
  2097. case '4':
  2098. case '5':
  2099. case '6':
  2100. case '7':
  2101. case '8':
  2102. case '9':
  2103. string[s_pos] = expression[pos_adv];
  2104. ++pos_adv; /* advance to next
  2105. * character */
  2106. ++s_pos;
  2107. string[s_pos] = BasicNulChar;
  2108. need_pm = FALSE;
  2109. break;
  2110. case BasicCurrencySuffix:
  2111. case BasicLongSuffix:
  2112. case BasicIntegerSuffix:
  2113. case BasicByteSuffix:
  2114. IsRounded = TRUE;
  2115. /* fall-thru */
  2116. case BasicDoubleSuffix:
  2117. case BasicSingleSuffix:
  2118. if( My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* TypeChars in constants */ )
  2119. {
  2120. ++pos_adv; /* advance to next character */
  2121. }
  2122. build_loop = FALSE;
  2123. break;
  2124. default: /* anything else, terminate */
  2125. build_loop = FALSE;
  2126. break;
  2127. }
  2128. } /* end of build loop for exponent */
  2129. /* assign the value to the user variable */
  2130. sscanf(string, BasicNumberScanFormat, &nval);
  2131. } /* end of exponent search */
  2132. if (nval == 0)
  2133. {
  2134. nval = mantissa;
  2135. }
  2136. else
  2137. {
  2138. nval = mantissa * pow(10.0, nval);
  2139. }
  2140. if( My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* TypeChars in constants */ )
  2141. {
  2142. /* 1.2% == 1 */
  2143. if( IsRounded )
  2144. {
  2145. nval = bwb_rint( nval );
  2146. }
  2147. }
  2148. break;
  2149. case 8: /* octal constant */
  2150. /* initialize counters */
  2151. pos_adv = man_start;
  2152. /* type = NUMBER; */
  2153. string[0] = BasicNulChar;
  2154. s_pos = 0;
  2155. exponent = 0;
  2156. build_loop = TRUE;
  2157. /* loop to build the string */
  2158. while (build_loop == TRUE)
  2159. {
  2160. switch (expression[pos_adv])
  2161. {
  2162. case '0': /* or ordinary digit */
  2163. case '1':
  2164. case '2':
  2165. case '3':
  2166. case '4':
  2167. case '5':
  2168. case '6':
  2169. case '7':
  2170. string[s_pos] = expression[pos_adv];
  2171. ++pos_adv; /* advance to next character */
  2172. ++s_pos;
  2173. string[s_pos] = BasicNulChar;
  2174. break;
  2175. case BasicDoubleSuffix:
  2176. case BasicSingleSuffix:
  2177. case BasicCurrencySuffix:
  2178. case BasicLongSuffix:
  2179. case BasicIntegerSuffix:
  2180. case BasicByteSuffix:
  2181. if( My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* TypeChars in constants */ )
  2182. {
  2183. ++pos_adv; /* advance to next character */
  2184. }
  2185. build_loop = FALSE;
  2186. break;
  2187. default: /* anything else, terminate */
  2188. build_loop = FALSE;
  2189. break;
  2190. }
  2191. }
  2192. /* now scan the string to determine the number */
  2193. sscanf(string, "%o", &u);
  2194. nval = u;
  2195. break;
  2196. case 16: /* hexadecimal constant */
  2197. /* initialize counters */
  2198. pos_adv = man_start;
  2199. /* type = NUMBER; */
  2200. string[0] = BasicNulChar;
  2201. s_pos = 0;
  2202. exponent = 0;
  2203. build_loop = TRUE;
  2204. /* loop to build the string */
  2205. while (build_loop == TRUE)
  2206. {
  2207. switch (expression[pos_adv])
  2208. {
  2209. case '0': /* or ordinary digit */
  2210. case '1':
  2211. case '2':
  2212. case '3':
  2213. case '4':
  2214. case '5':
  2215. case '6':
  2216. case '7':
  2217. case '8':
  2218. case '9':
  2219. case 'A':
  2220. case 'a':
  2221. case 'B':
  2222. case 'b':
  2223. case 'C':
  2224. case 'c':
  2225. case 'D':
  2226. case 'd':
  2227. case 'E':
  2228. case 'e':
  2229. case 'F': /* Don't forget these! (JBV) */
  2230. case 'f':
  2231. string[s_pos] = expression[pos_adv];
  2232. ++pos_adv; /* advance to next character */
  2233. ++s_pos;
  2234. string[s_pos] = BasicNulChar;
  2235. break;
  2236. case BasicDoubleSuffix:
  2237. case BasicSingleSuffix:
  2238. case BasicCurrencySuffix:
  2239. case BasicLongSuffix:
  2240. case BasicIntegerSuffix:
  2241. case BasicByteSuffix:
  2242. if( My->CurrentVersion->OptionFlags & OPTION_BUGS_ON /* TypeChars in constants */ )
  2243. {
  2244. ++pos_adv; /* advance to next character */
  2245. }
  2246. build_loop = FALSE;
  2247. break;
  2248. default: /* anything else, terminate */
  2249. build_loop = FALSE;
  2250. break;
  2251. }
  2252. }
  2253. /* now scan the string to determine the number */
  2254. sscanf(string, "%x", &u);
  2255. nval = u;
  2256. break;
  2257. }
  2258. /* check Value */
  2259. if (isnan(nval))
  2260. {
  2261. nval = 0;
  2262. /* ERROR messages are displayed by the calling routine */
  2263. *ResultCode = RESULT_TYPE_MMISMATCH;
  2264. }
  2265. else
  2266. if (isinf(nval))
  2267. {
  2268. if (nval < 0)
  2269. {
  2270. nval = -(DBL_MAX); /* FLT_MAX */
  2271. }
  2272. else
  2273. {
  2274. nval = (DBL_MAX); /* FLT_MAX */
  2275. }
  2276. /* ERROR messages are displayed by the calling routine */
  2277. *ResultCode = RESULT_ARITHMETIC_OVERFLOW;
  2278. }
  2279. else
  2280. {
  2281. *ResultCode = RESULT_OK;
  2282. }
  2283. return nval;
  2284. }
  2285. static int read_data(VariableType *v)
  2286. {
  2287. int ResultCode;
  2288. char tbuf[BasicStringLengthMax + 1];
  2289. /* advance beyond whitespace or comma in data buffer */
  2290. inp_adv( My->data_line->buffer, &My->data_pos );
  2291. /* Advance to next line if end of buffer */
  2292. if ( buff_is_eol( My->data_line->buffer, &My->data_pos ) )
  2293. {
  2294. /* end of buffer */
  2295. My->data_line = My->data_line->next;
  2296. My->data_pos = My->data_line->Startpos;
  2297. }
  2298. while ( My->data_line->cmdnum != C_DATA)
  2299. {
  2300. if ( My->data_line == &My->bwb_end )
  2301. {
  2302. /* halt */
  2303. WARN_OUT_OF_DATA;
  2304. return FALSE;
  2305. }
  2306. My->data_line = My->data_line->next;
  2307. My->data_pos = My->data_line->Startpos;
  2308. }
  2309. /* leading whitespace is NOT part of the DATA item */
  2310. buff_skip_spaces( My->data_line->buffer, &My->data_pos );
  2311. if ( buff_is_eol( My->data_line->buffer, &My->data_pos ) )
  2312. {
  2313. /* end of buffer */
  2314. WARN_OUT_OF_DATA;
  2315. return FALSE;
  2316. }
  2317. /* now at last we have a variable in v that needs to
  2318. * be assigned data from the data_buffer at position
  2319. * My->data_pos. What remains to be done is to
  2320. * get one single bit of data, a string constant or
  2321. * numerical constant, into the small buffer */
  2322. if( buff_peek_char( My->data_line->buffer, &My->data_pos, BasicQuoteChar) )
  2323. {
  2324. if ( VAR_IS_STRING( v ) )
  2325. {
  2326. /* OK */
  2327. }
  2328. else
  2329. {
  2330. /* ERROR */
  2331. WARN_TYPE_MISMATCH;
  2332. return FALSE;
  2333. }
  2334. }
  2335. inp_const(My->data_line->buffer, tbuf, &My->data_pos); /* read_data , bwb_READ , bwb_MAT_READ */
  2336. if (My->CurrentVersion->OptionFlags & OPTION_COVERAGE_ON)
  2337. {
  2338. /* this line has been READ */
  2339. My->data_line->LineFlags |= LINE_EXECUTED;
  2340. }
  2341. /* finally assign the data to the variable */
  2342. ResultCode = inp_assign(tbuf, v, FALSE, FALSE); /* read_data , bwb_READ , bwb_MAT_READ */
  2343. switch (ResultCode)
  2344. {
  2345. case RESULT_OK:
  2346. break;
  2347. case RESULT_UNKNOWN:
  2348. WARN_INTERNAL_ERROR;
  2349. return FALSE;
  2350. /* break; */
  2351. case RESULT_TYPE_MMISMATCH:
  2352. WARN_TYPE_MISMATCH;
  2353. return FALSE;
  2354. /* break; */
  2355. case RESULT_ARITHMETIC_OVERFLOW:
  2356. bwb_Warning_Overflow("*** Arithmetic Overflow ***");
  2357. break;
  2358. }
  2359. /* OK */
  2360. return TRUE;
  2361. }
  2362. static LineType * file_read_matrix( LineType * l )
  2363. {
  2364. /* MAT READ arrayname [;|,] */
  2365. /* Array must be 1, 2 or 3 dimensions */
  2366. /* Array may be either NUMBER or STRING */
  2367. VariableType *v;
  2368. bwx_DEBUG(__FUNCTION__);
  2369. My->LastInputCount = 0;
  2370. line_skip_spaces( l );
  2371. while( bwb_isalpha( l->buffer[l->position] ) )
  2372. {
  2373. My->LastInputCount = 0;
  2374. if( (v = line_read_matrix( l )) == NULL)
  2375. {
  2376. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2377. return bwb_zline(l);
  2378. }
  2379. /* variable MUST be an array of 1, 2 or 3 dimensions */
  2380. if (v->dimensions < 1)
  2381. {
  2382. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2383. return bwb_zline(l);
  2384. }
  2385. if(v->dimensions > 3)
  2386. {
  2387. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2388. return bwb_zline(l);
  2389. }
  2390. /* both arrays are of the same size */
  2391. /* allow user to use either item seperator */
  2392. if( line_skip_comma(l) )
  2393. {
  2394. /* force printing col-by-col */
  2395. }
  2396. else
  2397. {
  2398. /* force concatenating the columns */
  2399. }
  2400. /* READ array */
  2401. switch( v->dimensions )
  2402. {
  2403. case 1:
  2404. {
  2405. /*
  2406. OPTION BASE 0
  2407. DIM A(5)
  2408. ...
  2409. MAT READ A
  2410. ...
  2411. FOR I = 0 TO 5
  2412. READ A(I)
  2413. NEXT I
  2414. ...
  2415. */
  2416. for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
  2417. {
  2418. if ( My->CurrentFile == My->SYSIN)
  2419. {
  2420. if( read_data(v) == FALSE )
  2421. {
  2422. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2423. return bwb_zline(l);
  2424. }
  2425. }
  2426. else
  2427. {
  2428. if( file_read_value( My->CurrentFile->cfp, My->CurrentFile->delimit, v ) == FALSE )
  2429. {
  2430. WARN_INPUT_PAST_END;
  2431. return bwb_zline(l);
  2432. }
  2433. }
  2434. /* OK */
  2435. My->LastInputCount++;
  2436. }
  2437. }
  2438. break;
  2439. case 2:
  2440. {
  2441. /*
  2442. OPTION BASE 0
  2443. DIM B(2,3)
  2444. ...
  2445. MAT READ B
  2446. ...
  2447. FOR I = 0 TO 2
  2448. FOR J = 0 TO 3
  2449. READ B(I,J)
  2450. NEXT J
  2451. PRINT
  2452. NEXT I
  2453. ...
  2454. */
  2455. for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
  2456. {
  2457. for( v->array_pos[1] = v->LBOUND[1]; v->array_pos[1] <= v->UBOUND[1]; v->array_pos[1]++ )
  2458. {
  2459. if ( My->CurrentFile == My->SYSIN)
  2460. {
  2461. if( read_data(v) == FALSE )
  2462. {
  2463. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2464. return bwb_zline(l);
  2465. }
  2466. }
  2467. else
  2468. {
  2469. if( file_read_value( My->CurrentFile->cfp, My->CurrentFile->delimit, v ) == FALSE )
  2470. {
  2471. WARN_INPUT_PAST_END;
  2472. return bwb_zline(l);
  2473. }
  2474. }
  2475. /* OK */
  2476. My->LastInputCount++;
  2477. }
  2478. }
  2479. }
  2480. break;
  2481. case 3:
  2482. {
  2483. /*
  2484. OPTION BASE 0
  2485. DIM C(2,3,4)
  2486. ...
  2487. MAT READ C
  2488. ...
  2489. FOR I = 0 TO 2
  2490. FOR J = 0 TO 3
  2491. FOR K = 0 TO 4
  2492. READ C(I,J,K)
  2493. NEXT K
  2494. PRINT
  2495. NEXT J
  2496. PRINT
  2497. NEXT I
  2498. ...
  2499. */
  2500. for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
  2501. {
  2502. for( v->array_pos[1] = v->LBOUND[1]; v->array_pos[1] <= v->UBOUND[1]; v->array_pos[1]++ )
  2503. {
  2504. for( v->array_pos[2] = v->LBOUND[2]; v->array_pos[2] <= v->UBOUND[2]; v->array_pos[2]++ )
  2505. {
  2506. if ( My->CurrentFile == My->SYSIN)
  2507. {
  2508. if( read_data(v) == FALSE )
  2509. {
  2510. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2511. return bwb_zline(l);
  2512. }
  2513. }
  2514. else
  2515. {
  2516. if( file_read_value( My->CurrentFile->cfp, My->CurrentFile->delimit, v ) == FALSE )
  2517. {
  2518. WARN_INPUT_PAST_END;
  2519. return bwb_zline(l);
  2520. }
  2521. }
  2522. /* OK */
  2523. My->LastInputCount++;
  2524. }
  2525. }
  2526. }
  2527. }
  2528. break;
  2529. }
  2530. /* skip spaces */
  2531. line_skip_spaces(l);
  2532. /* process the next variable, if any */
  2533. }
  2534. return bwb_zline(l);
  2535. }
  2536. LineType *
  2537. bwb_MAT_GET(LineType * l)
  2538. {
  2539. /* MAT GET filename$ , matrix [, ...] */
  2540. VariantType E;
  2541. VariantType *e = &E;
  2542. bwx_DEBUG(__FUNCTION__);
  2543. My->CurrentFile = My->SYSIN;
  2544. line_skip_spaces(l);
  2545. if( line_read_expression( l, e ) == FALSE )
  2546. {
  2547. WARN_SYNTAX_ERROR;
  2548. return bwb_zline(l);
  2549. }
  2550. if( e->TypeChar == BasicStringSuffix )
  2551. {
  2552. /* STRING */
  2553. /* MAT GET filename$ ... */
  2554. if( is_empty_filename( e->Buffer ) )
  2555. {
  2556. /* "MAT GET # 0" is an error */
  2557. WARN_BAD_FILE_NUMBER;
  2558. return bwb_zline(l);
  2559. }
  2560. My->CurrentFile = find_file_by_name( e->Buffer );
  2561. if( My->CurrentFile == NULL )
  2562. {
  2563. /* implicitly OPEN for reading */
  2564. My->CurrentFile = file_new();
  2565. My->CurrentFile->cfp = fopen(e->Buffer, "r");
  2566. if( My->CurrentFile->cfp == NULL )
  2567. {
  2568. /* bad file name */
  2569. WARN_BAD_FILE_NUMBER;
  2570. return bwb_zline(l);
  2571. }
  2572. My->CurrentFile->FileNumber = file_next_number();
  2573. My->CurrentFile->mode = DEVMODE_INPUT;
  2574. My->CurrentFile->width = 0;
  2575. /* WIDTH == RECLEN */
  2576. My->CurrentFile->col = 1;
  2577. My->CurrentFile->row = 1;
  2578. My->CurrentFile->delimit = ',';
  2579. My->CurrentFile->buffer = NULL;
  2580. bwb_strcpy(My->CurrentFile->filename, e->Buffer);
  2581. }
  2582. }
  2583. else
  2584. {
  2585. /* NUMBER -- file must already be OPEN */
  2586. /* GET filenumber ... */
  2587. if( e->Number < 0 )
  2588. {
  2589. /* "MAT GET # -1" is an error */
  2590. WARN_BAD_FILE_NUMBER;
  2591. return bwb_zline(l);
  2592. }
  2593. if( e->Number == 0 )
  2594. {
  2595. /* "MAT GET # 0" is an error */
  2596. WARN_BAD_FILE_NUMBER;
  2597. return bwb_zline(l);
  2598. }
  2599. /* normal file */
  2600. My->CurrentFile = find_file_by_number( (int) bwb_rint( e->Number ) );
  2601. if( My->CurrentFile == NULL )
  2602. {
  2603. /* file not OPEN */
  2604. WARN_BAD_FILE_NUMBER;
  2605. return bwb_zline(l);
  2606. }
  2607. }
  2608. RELEASE( e );
  2609. if( My->CurrentFile == NULL )
  2610. {
  2611. WARN_BAD_FILE_NUMBER;
  2612. return bwb_zline(l);
  2613. }
  2614. if (( My->CurrentFile->mode & DEVMODE_READ) == 0)
  2615. {
  2616. WARN_BAD_FILE_NUMBER;
  2617. return bwb_zline(l);
  2618. }
  2619. if ( line_skip_comma(l) )
  2620. {
  2621. /* OK */
  2622. }
  2623. else
  2624. {
  2625. WARN_SYNTAX_ERROR;
  2626. return bwb_zline(l);
  2627. }
  2628. return file_read_matrix( l );
  2629. }
  2630. LineType *
  2631. bwb_MAT_READ(LineType * l)
  2632. {
  2633. /* MAT READ arrayname [;|,] */
  2634. /* Array must be 1, 2 or 3 dimensions */
  2635. /* Array may be either NUMBER or STRING */
  2636. bwx_DEBUG(__FUNCTION__);
  2637. My->CurrentFile = My->SYSIN;
  2638. My->LastInputCount = 0;
  2639. if ( line_skip_char(l,BasicFileNumberPrefix) )
  2640. {
  2641. /* MAT READ # filenum, varlist */
  2642. int FileNumber;
  2643. if( line_read_integer_expression(l, &FileNumber) == FALSE )
  2644. {
  2645. WARN_SYNTAX_ERROR;
  2646. return bwb_zline(l);
  2647. }
  2648. if ( line_skip_comma(l) )
  2649. {
  2650. /* OK */
  2651. }
  2652. else
  2653. {
  2654. WARN_SYNTAX_ERROR;
  2655. return bwb_zline(l);
  2656. }
  2657. My->CurrentFile = find_file_by_number( FileNumber );
  2658. if( My->CurrentFile == NULL )
  2659. {
  2660. WARN_BAD_FILE_NUMBER;
  2661. return bwb_zline(l);
  2662. }
  2663. if ( My->CurrentFile != My->SYSIN)
  2664. {
  2665. if ((My->CurrentFile->mode & DEVMODE_READ) == 0)
  2666. {
  2667. WARN_BAD_FILE_NUMBER;
  2668. return bwb_zline(l);
  2669. }
  2670. if (My->CurrentFile->cfp == NULL)
  2671. {
  2672. WARN_BAD_FILE_NUMBER;
  2673. return bwb_zline(l);
  2674. }
  2675. }
  2676. /* "MAT READ # 0, varlist" is the same as "MAT READ varlist" */
  2677. line_skip_spaces(l);
  2678. }
  2679. return file_read_matrix( l );
  2680. }
  2681. static int input_data(VariableType *v, char *Buffer)
  2682. {
  2683. char *C;
  2684. char c;
  2685. int ResultCode;
  2686. if( Buffer[0] == BasicNulChar )
  2687. {
  2688. /* Get more data */
  2689. bwx_input("?", Buffer );
  2690. if( Buffer[0] == BasicNulChar )
  2691. {
  2692. return FALSE;
  2693. }
  2694. }
  2695. /* process data */
  2696. /* data seperator is an unquoted comma (,) */
  2697. C = Buffer;
  2698. while( *C != BasicNulChar && *C != ',' )
  2699. {
  2700. if( *C == BasicQuoteChar )
  2701. {
  2702. /* skip leading quote */
  2703. C++;
  2704. while( *C != BasicNulChar && *C != BasicQuoteChar )
  2705. {
  2706. /* skip string constant */
  2707. C++;
  2708. }
  2709. if( *C == BasicQuoteChar )
  2710. {
  2711. /* skip trailing quote */
  2712. C++;
  2713. }
  2714. }
  2715. else
  2716. {
  2717. C++;
  2718. }
  2719. }
  2720. c = *C; /* either a comma (,) or a NUL (0) */
  2721. *C = BasicNulChar;
  2722. CleanLine( Buffer );
  2723. if( Buffer[0] == BasicQuoteChar )
  2724. {
  2725. /* remove quotes */
  2726. char *E;
  2727. E = Buffer;
  2728. E++;
  2729. E = bwb_strchr(E, BasicQuoteChar);
  2730. if( E != NULL )
  2731. {
  2732. *E = BasicNulChar;
  2733. }
  2734. E = Buffer;
  2735. E++;
  2736. bwb_strcpy(Buffer,E);
  2737. }
  2738. ResultCode = inp_assign(Buffer, v, FALSE, FALSE); /* input_data , bwb_MAT_INPUT */
  2739. switch (ResultCode)
  2740. {
  2741. case RESULT_OK:
  2742. break;
  2743. case RESULT_UNKNOWN:
  2744. WARN_INTERNAL_ERROR;
  2745. return FALSE;
  2746. /* break; */
  2747. case RESULT_TYPE_MMISMATCH:
  2748. fputs("*** Type Mismatch ***\n", My->SYSOUT->cfp );
  2749. return FALSE;
  2750. /* break; */
  2751. case RESULT_ARITHMETIC_OVERFLOW:
  2752. fputs("*** Overflow ***\n", My->SYSOUT->cfp );
  2753. return FALSE;
  2754. /* break; */
  2755. }
  2756. /* OK */
  2757. if( c == BasicNulChar )
  2758. {
  2759. /* we have consumed the entire buffer */
  2760. Buffer[0] = BasicNulChar;
  2761. }
  2762. else
  2763. if( c == ',' )
  2764. {
  2765. /* shift the buffer left, just past the comma (,) */
  2766. C++;
  2767. bwb_strcpy(Buffer,C);
  2768. }
  2769. else
  2770. {
  2771. WARN_INTERNAL_ERROR;
  2772. return FALSE;
  2773. }
  2774. return TRUE;
  2775. }
  2776. LineType *
  2777. bwb_MAT_INPUT(LineType * l)
  2778. {
  2779. /* MAT INPUT arrayname [;|,] */
  2780. /* Array must be 1, 2 or 3 dimensions */
  2781. /* Array may be either NUMBER or STRING */
  2782. VariableType *v;
  2783. char tbuf[BasicStringLengthMax + 1];
  2784. bwx_DEBUG(__FUNCTION__);
  2785. My->CurrentFile = My->SYSIN;
  2786. My->LastInputCount = 0;
  2787. if ( line_skip_char(l,BasicFileNumberPrefix) )
  2788. {
  2789. /* MAT INPUT # filenum, varlist */
  2790. int FileNumber;
  2791. if( line_read_integer_expression(l, &FileNumber) == FALSE )
  2792. {
  2793. WARN_SYNTAX_ERROR;
  2794. return bwb_zline(l);
  2795. }
  2796. if ( line_skip_comma(l) )
  2797. {
  2798. /* OK */
  2799. }
  2800. else
  2801. {
  2802. WARN_SYNTAX_ERROR;
  2803. return bwb_zline(l);
  2804. }
  2805. My->CurrentFile = find_file_by_number( FileNumber );
  2806. if( My->CurrentFile == NULL )
  2807. {
  2808. WARN_BAD_FILE_NUMBER;
  2809. return bwb_zline(l);
  2810. }
  2811. if ( My->CurrentFile != My->SYSIN)
  2812. {
  2813. if ((My->CurrentFile->mode & DEVMODE_READ) == 0)
  2814. {
  2815. WARN_BAD_FILE_NUMBER;
  2816. return bwb_zline(l);
  2817. }
  2818. if (My->CurrentFile->cfp == NULL)
  2819. {
  2820. WARN_BAD_FILE_NUMBER;
  2821. return bwb_zline(l);
  2822. }
  2823. }
  2824. /* "MAT INPUT # 0, varlist" is the same as "MAT INPUT varlist" */
  2825. line_skip_spaces(l);
  2826. }
  2827. while( bwb_isalpha( l->buffer[l->position] ) )
  2828. {
  2829. My->LastInputCount = 0;
  2830. if( (v = line_read_matrix( l )) == NULL)
  2831. {
  2832. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2833. return bwb_zline(l);
  2834. }
  2835. /* variable MUST be an array of 1, 2 or 3 dimensions */
  2836. if (v->dimensions < 1)
  2837. {
  2838. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2839. return bwb_zline(l);
  2840. }
  2841. if(v->dimensions > 3)
  2842. {
  2843. WARN_SUBSCRIPT_OUT_OF_RANGE;
  2844. return bwb_zline(l);
  2845. }
  2846. /* allow user to use either item seperator */
  2847. if( line_skip_comma(l) )
  2848. {
  2849. /* force printing col-by-col */
  2850. }
  2851. else
  2852. {
  2853. /* force concatenating the columns */
  2854. }
  2855. /* INPUT array */
  2856. tbuf[0] = BasicNulChar;
  2857. switch( v->dimensions )
  2858. {
  2859. case 1:
  2860. {
  2861. /*
  2862. OPTION BASE 0
  2863. DIM A(5)
  2864. ...
  2865. MAT INPUT A
  2866. ...
  2867. FOR I = 0 TO 5
  2868. INPUT A(I)
  2869. NEXT I
  2870. ...
  2871. */
  2872. My->LastInputCount = 0;
  2873. for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
  2874. {
  2875. if ( My->CurrentFile == My->SYSIN)
  2876. {
  2877. if( input_data(v,tbuf) == FALSE )
  2878. {
  2879. /*
  2880. WARN_INPUT_PAST_END;
  2881. */
  2882. return bwb_zline(l);
  2883. }
  2884. }
  2885. else
  2886. {
  2887. if( file_read_value( My->CurrentFile->cfp, ',', v ) == FALSE )
  2888. {
  2889. WARN_INPUT_PAST_END;
  2890. return bwb_zline(l);
  2891. }
  2892. }
  2893. /* OK */
  2894. My->LastInputCount++;
  2895. }
  2896. }
  2897. break;
  2898. case 2:
  2899. {
  2900. /*
  2901. OPTION BASE 0
  2902. DIM B(2,3)
  2903. ...
  2904. MAT INPUT B
  2905. ...
  2906. FOR I = 0 TO 2
  2907. FOR J = 0 TO 3
  2908. INPUT B(I,J)
  2909. NEXT J
  2910. PRINT
  2911. NEXT I
  2912. ...
  2913. */
  2914. My->LastInputCount = 0;
  2915. for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
  2916. {
  2917. for( v->array_pos[1] = v->LBOUND[1]; v->array_pos[1] <= v->UBOUND[1]; v->array_pos[1]++ )
  2918. {
  2919. if ( My->CurrentFile == My->SYSIN)
  2920. {
  2921. if( input_data(v,tbuf) == FALSE )
  2922. {
  2923. /*
  2924. WARN_INPUT_PAST_END;
  2925. */
  2926. return bwb_zline(l);
  2927. }
  2928. }
  2929. else
  2930. {
  2931. if( file_read_value( My->CurrentFile->cfp, ',', v ) == FALSE )
  2932. {
  2933. WARN_INPUT_PAST_END;
  2934. return bwb_zline(l);
  2935. }
  2936. }
  2937. /* OK */
  2938. My->LastInputCount++;
  2939. }
  2940. }
  2941. }
  2942. break;
  2943. case 3:
  2944. {
  2945. /*
  2946. OPTION BASE 0
  2947. DIM C(2,3,4)
  2948. ...
  2949. MAT INPUT C
  2950. ...
  2951. FOR I = 0 TO 2
  2952. FOR J = 0 TO 3
  2953. FOR K = 0 TO 4
  2954. INPUT C(I,J,K)
  2955. NEXT K
  2956. PRINT
  2957. NEXT J
  2958. PRINT
  2959. NEXT I
  2960. ...
  2961. */
  2962. My->LastInputCount = 0;
  2963. for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
  2964. {
  2965. for( v->array_pos[1] = v->LBOUND[1]; v->array_pos[1] <= v->UBOUND[1]; v->array_pos[1]++ )
  2966. {
  2967. for( v->array_pos[2] = v->LBOUND[2]; v->array_pos[2] <= v->UBOUND[2]; v->array_pos[2]++ )
  2968. {
  2969. if ( My->CurrentFile == My->SYSIN)
  2970. {
  2971. if( input_data(v,tbuf) == FALSE )
  2972. {
  2973. /*
  2974. WARN_INPUT_PAST_END;
  2975. */
  2976. return bwb_zline(l);
  2977. }
  2978. }
  2979. else
  2980. {
  2981. if( file_read_value( My->CurrentFile->cfp, ',', v ) == FALSE )
  2982. {
  2983. WARN_INPUT_PAST_END;
  2984. return bwb_zline(l);
  2985. }
  2986. }
  2987. /* OK */
  2988. My->LastInputCount++;
  2989. }
  2990. }
  2991. }
  2992. }
  2993. break;
  2994. }
  2995. /* skip spaces */
  2996. line_skip_spaces(l);
  2997. /* process the next variable, if any */
  2998. }
  2999. return bwb_zline(l);
  3000. }
  3001. /* EOF */