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.
 
 
 
 
 
 

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