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.
 
 
 
 
 
 

1900 lines
45 KiB

  1. /***************************************************************
  2. bwb_prn.c Print and Error-Handling Commands
  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. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <math.h>
  24. #include "bwbasic.h"
  25. #include "bwb_mes.h"
  26. /* Prototypes for functions visible only to this file */
  27. int prn_col = 1;
  28. static int prn_width = 80; /* default width for stdout */
  29. struct prn_fmt
  30. {
  31. int type; /* STRING, NUMBER, SINGLE, or NUMBER */
  32. int exponential; /* TRUE = use exponential notation */
  33. int right_justified; /* TRUE = right justified else left justified */
  34. int width; /* width of main section */
  35. int precision; /* width after decimal point */
  36. int commas; /* use commas every three steps */
  37. int sign; /* prefix sign to number */
  38. int money; /* prefix money sign to number */
  39. int fill; /* ASCII value for fill character, normally ' ' */
  40. int minus; /* postfix minus sign to number */
  41. };
  42. #if ANSI_C
  43. static int prn_cr( char *buffer, FILE *f );
  44. static struct prn_fmt *get_prnfmt( char *buffer, int *position, FILE *f );
  45. static int bwb_xerror( char *message );
  46. static int xxputc( FILE *f, char c );
  47. static int xxxputc( FILE *f, char c );
  48. static struct bwb_variable * bwb_esetovar( struct exp_ese *e );
  49. #else
  50. static int prn_cr();
  51. static struct prn_fmt *get_prnfmt();
  52. static int bwb_xerror();
  53. static int xxputc();
  54. static int xxxputc();
  55. static struct bwb_variable * bwb_esetovar();
  56. #endif
  57. /***************************************************************
  58. FUNCTION: bwb_print()
  59. DESCRIPTION: This function implements the BASIC PRINT
  60. command.
  61. SYNTAX: PRINT [# device-number,][USING format-string$;] expressions...
  62. ***************************************************************/
  63. #if ANSI_C
  64. struct bwb_line *
  65. bwb_print( struct bwb_line *l )
  66. #else
  67. struct bwb_line *
  68. bwb_print( l )
  69. struct bwb_line *l;
  70. #endif
  71. {
  72. FILE *fp;
  73. static int pos;
  74. int req_devnumber;
  75. struct exp_ese *v;
  76. static char *s_buffer; /* small, temporary buffer */
  77. static int init = FALSE;
  78. #if INTENSIVE_DEBUG
  79. sprintf( bwb_ebuf, "in bwb_print(): enter function" );
  80. bwb_debug( bwb_ebuf );
  81. #endif
  82. /* initialize buffers if necessary */
  83. if ( init == FALSE )
  84. {
  85. init = TRUE;
  86. /* Revised to CALLOC pass-thru call by JBV */
  87. if ( ( s_buffer = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_print") ) == NULL )
  88. {
  89. #if PROG_ERRORS
  90. bwb_error( "in bwb_print(): failed to get memory for s_buffer" );
  91. #else
  92. bwb_error( err_getmem );
  93. #endif
  94. }
  95. }
  96. /* advance beyond whitespace and check for the '#' sign */
  97. adv_ws( l->buffer, &( l->position ) );
  98. #if COMMON_CMDS
  99. if ( l->buffer[ l->position ] == '#' )
  100. {
  101. ++( l->position );
  102. adv_element( l->buffer, &( l->position ), s_buffer );
  103. pos = 0;
  104. v = bwb_exp( s_buffer, FALSE, &pos );
  105. adv_ws( l->buffer, &( l->position ) );
  106. if ( l->buffer[ l->position ] == ',' )
  107. {
  108. ++( l->position );
  109. }
  110. else
  111. {
  112. #if PROG_ERRORS
  113. bwb_error( "in bwb_print(): no comma after #n" );
  114. #else
  115. bwb_error( err_syntax );
  116. #endif
  117. return bwb_zline( l );
  118. }
  119. req_devnumber = (int) exp_getnval( v );
  120. /* check the requested device number */
  121. if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  122. {
  123. #if PROG_ERRORS
  124. bwb_error( "in bwb_input(): Requested device number is out of range." );
  125. #else
  126. bwb_error( err_devnum );
  127. #endif
  128. return bwb_zline( l );
  129. }
  130. if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  131. ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ))
  132. {
  133. #if PROG_ERRORS
  134. bwb_error( "in bwb_input(): Requested device number is not open." );
  135. #else
  136. bwb_error( err_devnum );
  137. #endif
  138. return bwb_zline( l );
  139. }
  140. if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT )
  141. {
  142. #if PROG_ERRORS
  143. bwb_error( "in bwb_print(): Requested device is not open for OUTPUT." );
  144. #else
  145. bwb_error( err_devnum );
  146. #endif
  147. return bwb_zline( l );
  148. }
  149. #if INTENSIVE_DEBUG
  150. sprintf( bwb_ebuf, "in bwb_print(): device number is <%d>",
  151. req_devnumber );
  152. bwb_debug( bwb_ebuf );
  153. #endif
  154. /* look up the requested device in the device table */
  155. fp = dev_table[ req_devnumber ].cfp;
  156. }
  157. else
  158. {
  159. fp = stdout;
  160. }
  161. #else
  162. fp = stdout;
  163. #endif /* COMMON_CMDS */
  164. bwb_xprint( l, fp );
  165. return bwb_zline( l );
  166. }
  167. /***************************************************************
  168. FUNCTION: bwb_xprint()
  169. DESCRIPTION: This function implements the BASIC PRINT
  170. command, utilizing a specified file our
  171. output device.
  172. ***************************************************************/
  173. #if ANSI_C
  174. int
  175. bwb_xprint( struct bwb_line *l, FILE *f )
  176. #else
  177. int
  178. bwb_xprint( l, f )
  179. struct bwb_line *l;
  180. FILE *f;
  181. #endif
  182. {
  183. struct exp_ese *e;
  184. int loop;
  185. static int p;
  186. static int fs_pos;
  187. struct prn_fmt *format;
  188. static char *format_string;
  189. static char *output_string;
  190. static char *element;
  191. static char *prnbuf;
  192. static int init = FALSE;
  193. register int i, j; /* JBV */
  194. int dig_pos, dec_pos; /* JBV */
  195. char tbuf[ MAXSTRINGSIZE + 1 ]; /* JBV */
  196. #if INTENSIVE_DEBUG || TEST_BSTRING
  197. bstring *b;
  198. #endif
  199. /* initialize buffers if necessary */
  200. if ( init == FALSE )
  201. {
  202. init = TRUE;
  203. /* Revised to CALLOC pass-thru call by JBV */
  204. if ( ( format_string = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL )
  205. {
  206. #if PROG_ERRORS
  207. bwb_error( "in bwb_xprint(): failed to get memory for format_string" );
  208. #else
  209. bwb_error( err_getmem );
  210. #endif
  211. }
  212. /* Revised to CALLOC pass-thru call by JBV */
  213. if ( ( output_string = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL )
  214. {
  215. #if PROG_ERRORS
  216. bwb_error( "in bwb_xprint(): failed to get memory for output_string" );
  217. #else
  218. bwb_error( err_getmem );
  219. #endif
  220. }
  221. /* Revised to CALLOC pass-thru call by JBV */
  222. if ( ( element = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL )
  223. {
  224. #if PROG_ERRORS
  225. bwb_error( "in bwb_xprint(): failed to get memory for element buffer" );
  226. #else
  227. bwb_error( err_getmem );
  228. #endif
  229. }
  230. /* Revised to CALLOC pass-thru call by JBV */
  231. if ( ( prnbuf = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL )
  232. {
  233. #if PROG_ERRORS
  234. bwb_error( "in bwb_xprint(): failed to get memory for prnbuf" );
  235. #else
  236. bwb_error( err_getmem );
  237. #endif
  238. }
  239. }
  240. /* Detect USING Here */
  241. fs_pos = -1;
  242. /* get "USING" in format_string */
  243. p = l->position;
  244. adv_element( l->buffer, &p, format_string );
  245. bwb_strtoupper( format_string );
  246. #if COMMON_CMDS
  247. /* check to be sure */
  248. if ( strcmp( format_string, CMD_XUSING ) == 0 )
  249. {
  250. l->position = p;
  251. adv_ws( l->buffer, &( l->position ) );
  252. /* now get the format string in format_string */
  253. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  254. if ( e->type == STRING )
  255. {
  256. /* copy the format string to buffer */
  257. str_btoc( format_string, exp_getsval( e ) );
  258. /* look for ';' after format string */
  259. fs_pos = 0;
  260. adv_ws( l->buffer, &( l->position ) );
  261. if ( l->buffer[ l->position ] == ';' )
  262. {
  263. ++l->position;
  264. adv_ws( l->buffer, &( l->position ) );
  265. }
  266. else
  267. {
  268. #if PROG_ERRORS
  269. bwb_error( "Failed to find \";\" after format string in PRINT USING" );
  270. #else
  271. bwb_error( err_syntax );
  272. #endif
  273. return FALSE;
  274. }
  275. #if INTENSIVE_DEBUG
  276. sprintf( bwb_ebuf, "in bwb_xprint(): Found USING, format string <%s>",
  277. format_string );
  278. bwb_debug( bwb_ebuf );
  279. #endif
  280. }
  281. else
  282. {
  283. #if PROG_ERRORS
  284. bwb_error( "Failed to find format string after PRINT USING" );
  285. #else
  286. bwb_error( err_syntax );
  287. #endif
  288. return FALSE;
  289. }
  290. }
  291. #endif /* COMMON_CMDS */
  292. /* if no arguments, simply print CR and return */
  293. adv_ws( l->buffer, &( l->position ) );
  294. switch( l->buffer[ l->position ] )
  295. {
  296. case '\0':
  297. case '\n':
  298. case '\r':
  299. case ':':
  300. prn_xprintf( f, "\n" );
  301. return TRUE;
  302. default:
  303. break;
  304. }
  305. /* LOOP THROUGH PRINT ELEMENTS */
  306. loop = TRUE;
  307. while( loop == TRUE )
  308. {
  309. /* resolve the string */
  310. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  311. #if INTENSIVE_DEBUG
  312. sprintf( bwb_ebuf, "in bwb_xprint(): op <%d> type <%d>",
  313. e->operation, e->type );
  314. bwb_debug( bwb_ebuf );
  315. #endif
  316. /* an OP_NULL probably indicates a terminating ';', but this
  317. will be detected later, so we can ignore it for now */
  318. if ( e->operation != OP_NULL )
  319. {
  320. #if TEST_BSTRING
  321. b = exp_getsval( e );
  322. sprintf( bwb_ebuf, "in bwb_xprint(): bstring name is <%s>",
  323. b->name );
  324. bwb_debug( bwb_ebuf );
  325. #endif
  326. str_btoc( element, exp_getsval( e ) );
  327. }
  328. else
  329. {
  330. element[ 0 ] = '\0';
  331. }
  332. #if INTENSIVE_DEBUG
  333. sprintf( bwb_ebuf, "in bwb_xprint(): element <%s>",
  334. element );
  335. bwb_debug( bwb_ebuf );
  336. #endif
  337. /* print with format if there is one */
  338. if (( fs_pos > -1 ) && ( strlen( element ) > 0 ))
  339. {
  340. #if COMMON_CMDS
  341. format = get_prnfmt( format_string, &fs_pos, f );
  342. #if INTENSIVE_DEBUG
  343. sprintf( bwb_ebuf, "in bwb_xprint(): format type <%d> width <%d>",
  344. format->type, format->width );
  345. bwb_debug( bwb_ebuf );
  346. #endif
  347. switch( format->type )
  348. {
  349. case STRING:
  350. if ( e->type != STRING )
  351. {
  352. #if PROG_ERRORS
  353. bwb_error( "Type mismatch in PRINT USING" );
  354. #else
  355. bwb_error( err_mismatch );
  356. #endif
  357. }
  358. if ( format->width == -1 ) /* JBV */
  359. sprintf( output_string, "%s", element );
  360. else sprintf( output_string, "%.*s", format->width, element );
  361. #if INTENSIVE_DEBUG
  362. sprintf( bwb_ebuf, "in bwb_xprint(): output string <%s>",
  363. output_string );
  364. bwb_debug( bwb_ebuf );
  365. #endif
  366. prn_xxprintf( f, output_string ); /* Was prn_xprintf (JBV) */
  367. break;
  368. case NUMBER:
  369. if ( e->type == STRING )
  370. {
  371. #if PROG_ERRORS
  372. bwb_error( "Type mismatch in PRINT USING" );
  373. #else
  374. bwb_error( err_mismatch );
  375. #endif
  376. }
  377. if ( format->exponential == TRUE )
  378. {
  379. /*------------------------------------------------------*/
  380. /* NOTE: Width and fill have no effect on C exponential */
  381. /* format (JBV) */
  382. /*------------------------------------------------------*/
  383. if ( format->sign == TRUE ) /* Added by JBV */
  384. sprintf( output_string, "%+e", exp_getnval( e ) );
  385. else
  386. sprintf( output_string, "%e", exp_getnval( e ) );
  387. }
  388. else
  389. {
  390. /*---------------------------------------------------*/
  391. /* NOTE: Minus, commas, and money are only valid for */
  392. /* floating point format (JBV) */
  393. /*---------------------------------------------------*/
  394. if ( format->sign == TRUE ) /* Added by JBV */
  395. sprintf( output_string, "%+*.*f",
  396. format->width, format->precision, exp_getnval( e ) );
  397. else if ( format->minus == TRUE ) /* Added by JBV */
  398. {
  399. sprintf( output_string, "%*.*f",
  400. format->width, format->precision, exp_getnval( e ) );
  401. for (i = 0; i < strlen( output_string ); ++i )
  402. {
  403. if ( output_string[ i ] != ' ' )
  404. {
  405. if ( output_string[ i ] == '-' )
  406. {
  407. output_string[ i ] = ' ';
  408. strcat( output_string, "-" );
  409. }
  410. else strcat( output_string, " " );
  411. break;
  412. }
  413. }
  414. }
  415. else
  416. sprintf( output_string, "%*.*f",
  417. format->width, format->precision, exp_getnval( e ) );
  418. if ( format->commas == TRUE ) /* Added by JBV */
  419. {
  420. dig_pos = -1;
  421. dec_pos = -1;
  422. for ( i = 0; i < strlen( output_string ); ++i )
  423. {
  424. if ( ( isdigit( output_string[ i ] ) != 0 )
  425. && ( dig_pos == -1 ) )
  426. dig_pos = i;
  427. if ( ( output_string[ i ] == '.' )
  428. && ( dec_pos == -1 ) )
  429. dec_pos = i;
  430. if ( ( dig_pos != -1 ) && ( dec_pos != -1 ) ) break;
  431. }
  432. if ( dec_pos == -1 ) dec_pos = strlen( output_string );
  433. j = 0;
  434. for ( i = 0; i < strlen( output_string ); ++i )
  435. {
  436. if ( ( ( dec_pos - i ) % 3 == 0 )
  437. && ( i > dig_pos ) && ( i < dec_pos ) )
  438. {
  439. tbuf[ j ] = ',';
  440. ++j;
  441. tbuf[ j ] = '\0';
  442. }
  443. tbuf[ j ] = output_string[ i ];
  444. ++j;
  445. tbuf[ j ] = '\0';
  446. }
  447. strcpy( output_string,
  448. &tbuf[ strlen( tbuf ) - strlen( output_string ) ] );
  449. }
  450. if ( format->money == TRUE ) /* Added by JBV */
  451. {
  452. for ( i = 0; i < strlen( output_string ); ++i )
  453. {
  454. if ( output_string[ i ] != ' ' )
  455. {
  456. if ( i > 0 )
  457. {
  458. if ( isdigit( output_string[ i ] ) == 0 )
  459. {
  460. output_string[ i - 1 ]
  461. = output_string[ i ];
  462. output_string[ i ] = '$';
  463. }
  464. else output_string[ i - 1 ] = '$';
  465. }
  466. break;
  467. }
  468. }
  469. }
  470. }
  471. if ( format->fill == '*' ) /* Added by JBV */
  472. for ( i = 0; i < strlen( output_string ); ++i )
  473. {
  474. if ( output_string[ i ] != ' ' ) break;
  475. output_string[ i ] = '*';
  476. }
  477. #if INTENSIVE_DEBUG
  478. sprintf( bwb_ebuf, "in bwb_xprint(): output number <%f> string <%s>",
  479. exp_getnval( e ), output_string );
  480. bwb_debug( bwb_ebuf );
  481. #endif
  482. prn_xxprintf( f, output_string ); /* Was prn_xprintf (JBV) */
  483. break;
  484. default:
  485. #if PROG_ERRORS
  486. sprintf( bwb_ebuf, "in bwb_xprint(): get_prnfmt() returns unknown type <%c>",
  487. format->type );
  488. bwb_error( bwb_ebuf );
  489. #else
  490. bwb_error( err_mismatch );
  491. #endif
  492. break;
  493. }
  494. #endif /* COMMON_CMDS */
  495. }
  496. /* not a format string: use defaults */
  497. else if ( strlen( element ) > 0 )
  498. {
  499. switch( e->type )
  500. {
  501. case STRING:
  502. prn_xprintf( f, element );
  503. break;
  504. default:
  505. #if NUMBER_DOUBLE
  506. sprintf( prnbuf, " %.*lf", prn_precision( bwb_esetovar( e )),
  507. exp_getnval( e ) );
  508. #else
  509. sprintf( prnbuf, " %.*f", prn_precision( bwb_esetovar( e )),
  510. exp_getnval( e ) );
  511. #endif
  512. prn_xprintf( f, prnbuf );
  513. break;
  514. }
  515. }
  516. /* check the position to see if the loop should continue */
  517. adv_ws( l->buffer, &( l->position ) );
  518. switch( l->buffer[ l->position ] )
  519. {
  520. #if OLDSTUFF
  521. case ':': /* end of line segment */
  522. loop = FALSE;
  523. break;
  524. case '\0': /* end of buffer */
  525. case '\n':
  526. case '\r':
  527. loop = FALSE;
  528. break;
  529. #endif
  530. case ',': /* tab over */
  531. /* Tab only if there's no format specification! (JBV) */
  532. if (( fs_pos == -1 ) || ( strlen( element ) == 0 ))
  533. xputc( f, '\t' );
  534. ++l->position;
  535. adv_ws( l->buffer, &( l->position ) );
  536. break;
  537. case ';': /* concatenate strings */
  538. ++l->position;
  539. adv_ws( l->buffer, &( l->position ) );
  540. break;
  541. default:
  542. loop = FALSE;
  543. break;
  544. }
  545. } /* end of loop through print elements */
  546. if (( fs_pos > -1 ) && ( strlen( element ) > 0 ))
  547. format = get_prnfmt( format_string, &fs_pos, f ); /* Finish up (JBV) */
  548. /* call prn_cr() to print a CR if it is not overridden by a
  549. concluding ';' mark */
  550. prn_cr( l->buffer, f );
  551. return TRUE;
  552. } /* end of function bwb_xprint() */
  553. #if COMMON_CMDS
  554. /***************************************************************
  555. FUNCTION: get_prnfmt()
  556. DESCRIPTION: This function gets the PRINT USING
  557. format string, returning a structure
  558. to the format.
  559. ***************************************************************/
  560. #if ANSI_C
  561. static struct prn_fmt *
  562. get_prnfmt( char *buffer, int *position, FILE *f )
  563. #else
  564. static struct prn_fmt *
  565. get_prnfmt( buffer, position, f )
  566. char *buffer;
  567. int *position;
  568. FILE *f;
  569. #endif
  570. {
  571. static struct prn_fmt retstruct;
  572. int loop;
  573. /* set some defaults */
  574. retstruct.precision = 0;
  575. retstruct.type = FALSE;
  576. retstruct.exponential = FALSE;
  577. retstruct.right_justified = FALSE;
  578. retstruct.commas = FALSE;
  579. retstruct.sign = FALSE;
  580. retstruct.money = FALSE;
  581. retstruct.fill = ' ';
  582. retstruct.minus = FALSE;
  583. retstruct.width = 0;
  584. /* check for negative position */
  585. if ( *position < 0 )
  586. {
  587. return &retstruct;
  588. }
  589. /* advance past whitespace */
  590. /* adv_ws( buffer, position ); */ /* Don't think we want this (JBV) */
  591. /* check first character: a lost can be decided right here */
  592. loop = TRUE;
  593. while( loop == TRUE )
  594. {
  595. #if INTENSIVE_DEBUG
  596. sprintf( bwb_ebuf, "in get_prnfmt(): loop, buffer <%s>",
  597. &( buffer[ *position ] ) );
  598. bwb_debug( bwb_ebuf );
  599. #endif
  600. switch( buffer[ *position ] )
  601. {
  602. case ' ': /* end of this format segment */
  603. xxputc( f, buffer[ *position ] ); /* Gotta output it (JBV) */
  604. ++( *position ); /* JBV */
  605. if (retstruct.type != FALSE) loop = FALSE; /* JBV */
  606. break;
  607. case '\0': /* end of format string */
  608. case '\n':
  609. case '\r':
  610. *position = -1;
  611. return &retstruct;
  612. case '_': /* print next character as literal */
  613. ++( *position );
  614. xxputc( f, buffer[ *position ] ); /* Not xputc, no tabs (JBV) */
  615. ++( *position );
  616. break;
  617. case '!':
  618. retstruct.type = STRING;
  619. retstruct.width = 1;
  620. ++( *position ); /* JBV */
  621. return &retstruct;
  622. case '&': /* JBV */
  623. retstruct.type = STRING;
  624. retstruct.width = -1;
  625. ++( *position );
  626. return &retstruct;
  627. case '\\':
  628. #if INTENSIVE_DEBUG
  629. sprintf( bwb_ebuf, "in get_prnfmt(): found \\" );
  630. bwb_debug( bwb_ebuf );
  631. #endif
  632. retstruct.type = STRING;
  633. ++retstruct.width;
  634. ++( *position );
  635. for ( ; buffer[ *position ] == ' '; ++( *position ) )
  636. {
  637. ++retstruct.width;
  638. }
  639. if ( buffer[ *position ] == '\\' )
  640. {
  641. ++retstruct.width;
  642. ++( *position );
  643. }
  644. return &retstruct;
  645. case '$':
  646. ++retstruct.width; /* JBV */
  647. ++( *position );
  648. retstruct.money = TRUE;
  649. if ( buffer[ *position ] == '$' )
  650. {
  651. ++retstruct.width; /* JBV */
  652. ++( *position );
  653. }
  654. break;
  655. case '*':
  656. ++retstruct.width; /* JBV */
  657. ++( *position );
  658. retstruct.fill = '*';
  659. if ( buffer[ *position ] == '*' )
  660. {
  661. ++retstruct.width; /* JBV */
  662. ++( *position );
  663. }
  664. break;
  665. case '+':
  666. ++( *position );
  667. retstruct.sign = TRUE;
  668. break;
  669. case '#':
  670. retstruct.type = NUMBER; /* for now */
  671. /* ++( *position ); */ /* Removed by JBV */
  672. /* The initial condition shouldn't be retstruct.width = 1 (JBV) */
  673. for ( ; buffer[ *position ] == '#'; ++( *position ) )
  674. {
  675. ++retstruct.width;
  676. }
  677. if ( buffer[ *position ] == ',' )
  678. {
  679. retstruct.commas = TRUE;
  680. ++retstruct.width; /* JBV */
  681. ++( *position ); /* JBV */
  682. }
  683. if ( buffer[ *position ] == '.' )
  684. {
  685. retstruct.type = NUMBER;
  686. ++retstruct.width;
  687. ++( *position );
  688. for ( retstruct.precision = 0; buffer[ *position ] == '#'; ++( *position ) )
  689. {
  690. ++retstruct.precision;
  691. ++retstruct.width;
  692. }
  693. }
  694. if ( buffer[ *position ] == '-' )
  695. {
  696. retstruct.minus = TRUE;
  697. ++( *position );
  698. }
  699. return &retstruct;
  700. case '^':
  701. retstruct.type = NUMBER;
  702. retstruct.exponential = TRUE;
  703. for ( retstruct.width = 1; buffer[ *position ] == '^'; ++( *position ) )
  704. {
  705. ++retstruct.width;
  706. }
  707. return &retstruct;
  708. default: /* JBV */
  709. xxputc( f, buffer[ *position ] ); /* Gotta output it (JBV) */
  710. ++( *position );
  711. break;
  712. }
  713. } /* end of loop */
  714. return &retstruct;
  715. }
  716. #endif
  717. /***************************************************************
  718. FUNCTION: prn_cr()
  719. DESCRIPTION: This function outputs a carriage-return
  720. to a specified file or output device.
  721. ***************************************************************/
  722. #if ANSI_C
  723. static int
  724. prn_cr( char *buffer, FILE *f )
  725. #else
  726. static int
  727. prn_cr( buffer, f )
  728. char *buffer;
  729. FILE *f;
  730. #endif
  731. {
  732. register int c;
  733. int loop;
  734. /* find the end of the buffer */
  735. for ( c = 0; buffer[ c ] != '\0'; ++c )
  736. {
  737. }
  738. #if INTENSIVE_DEBUG
  739. sprintf( bwb_ebuf, "in prn_cr(): initial c is <%d>", c );
  740. bwb_debug( bwb_ebuf );
  741. #endif
  742. /* back up through any whitespace */
  743. loop = TRUE;
  744. while ( loop == TRUE )
  745. {
  746. switch( buffer[ c ] )
  747. {
  748. case ' ': /* if whitespace */
  749. case '\t':
  750. case 0:
  751. #if INTENSIVE_DEBUG
  752. sprintf( bwb_ebuf, "in prn_cr(): backup: c is <%d>, char <%c>[0x%x]",
  753. c, buffer[ c ], buffer[ c ] );
  754. bwb_debug( bwb_ebuf );
  755. #endif
  756. --c; /* back up */
  757. if ( c < 0 ) /* check position */
  758. {
  759. loop = FALSE;
  760. }
  761. break;
  762. default: /* else break out */
  763. #if INTENSIVE_DEBUG
  764. sprintf( bwb_ebuf, "in prn_cr(): breakout: c is <%d>, char <%c>[0x%x]",
  765. c, buffer[ c ], buffer[ c ] );
  766. bwb_debug( bwb_ebuf );
  767. #endif
  768. loop = FALSE;
  769. break;
  770. }
  771. }
  772. if ( buffer[ c ] == ';' )
  773. {
  774. #if INTENSIVE_DEBUG
  775. sprintf( bwb_ebuf, "in prn_cr(): concluding <;> detected." );
  776. bwb_debug( bwb_ebuf );
  777. #endif
  778. return FALSE;
  779. }
  780. else
  781. {
  782. prn_xprintf( f, "\n" );
  783. return TRUE;
  784. }
  785. }
  786. /***************************************************************
  787. FUNCTION: prn_xprintf()
  788. DESCRIPTION: This function outputs a null-terminated
  789. string to a specified file or output
  790. device.
  791. ***************************************************************/
  792. #if ANSI_C
  793. int
  794. prn_xprintf( FILE *f, char *buffer )
  795. #else
  796. int
  797. prn_xprintf( f, buffer )
  798. FILE *f;
  799. char *buffer;
  800. #endif
  801. {
  802. char *p;
  803. /* DO NOT try anything so stupid as to run bwb_debug() from
  804. here, because it will create an endless loop. And don't
  805. ask how I know. */
  806. for ( p = buffer; *p != '\0'; ++p )
  807. {
  808. xputc( f, *p );
  809. }
  810. return TRUE;
  811. }
  812. /***************************************************************
  813. FUNCTION: prn_xxprintf()
  814. DESCRIPTION: This function outputs a null-terminated
  815. string to a specified file or output
  816. device without expanding tabs.
  817. Added by JBV 10/95
  818. ***************************************************************/
  819. #if ANSI_C
  820. int
  821. prn_xxprintf( FILE *f, char *buffer )
  822. #else
  823. int
  824. prn_xxprintf( f, buffer )
  825. FILE *f;
  826. char *buffer;
  827. #endif
  828. {
  829. char *p;
  830. /* DO NOT try anything so stupid as to run bwb_debug() from
  831. here, because it will create an endless loop. And don't
  832. ask how I know. */
  833. for ( p = buffer; *p != '\0'; ++p )
  834. {
  835. xxputc( f, *p );
  836. }
  837. return TRUE;
  838. }
  839. /***************************************************************
  840. FUNCTION: xputc()
  841. DESCRIPTION: This function outputs a character to a
  842. specified file or output device, expanding
  843. TABbed output approriately.
  844. ***************************************************************/
  845. #if ANSI_C
  846. int
  847. xputc( FILE *f, char c )
  848. #else
  849. int
  850. xputc( f, c )
  851. FILE *f;
  852. char c;
  853. #endif
  854. {
  855. static int tab_pending = FALSE;
  856. /*--------------------------------------------------------------------*/
  857. /* Don't expand tabs if not printing to stdout or stderr (JBV 9/4/97) */
  858. /*--------------------------------------------------------------------*/
  859. if (( f != stdout ) && ( f != stderr ))
  860. {
  861. xxputc( f, c );
  862. return TRUE;
  863. }
  864. /* check for pending TAB */
  865. if ( tab_pending == TRUE )
  866. {
  867. if ( (int) c < ( * prn_getcol( f ) ) )
  868. {
  869. xxputc( f, '\n' );
  870. }
  871. while( ( * prn_getcol( f )) < (int) c )
  872. {
  873. xxputc( f, ' ' );
  874. }
  875. tab_pending = FALSE;
  876. return TRUE;
  877. }
  878. /* check c for specific output options */
  879. switch( c )
  880. {
  881. case PRN_TAB:
  882. tab_pending = TRUE;
  883. break;
  884. case '\t':
  885. while( ( (* prn_getcol( f )) % 14 ) != 0 )
  886. {
  887. xxputc( f, ' ' );
  888. }
  889. break;
  890. default:
  891. xxputc( f, c );
  892. break;
  893. }
  894. return TRUE;
  895. }
  896. /***************************************************************
  897. FUNCTION: xxputc()
  898. DESCRIPTION: This function outputs a character to a
  899. specified file or output device, checking
  900. to be sure the PRINT width is within
  901. the bounds specified for that device.
  902. ***************************************************************/
  903. #if ANSI_C
  904. static int
  905. xxputc( FILE *f, char c )
  906. #else
  907. static int
  908. xxputc( f, c )
  909. FILE *f;
  910. char c;
  911. #endif
  912. {
  913. /*--------------------------------------------------------------------*/
  914. /* Don't check width if not printing to stdout or stderr (JBV 9/4/97) */
  915. /*--------------------------------------------------------------------*/
  916. if (( f != stdout ) && ( f != stderr ))
  917. {
  918. return xxxputc( f, c );
  919. }
  920. /* check to see if width has been exceeded */
  921. if ( * prn_getcol( f ) >= prn_getwidth( f ))
  922. {
  923. xxxputc( f, '\n' ); /* output LF */
  924. * prn_getcol( f ) = 1; /* and reset */
  925. }
  926. /* adjust the column counter */
  927. if ( c == '\n' )
  928. {
  929. * prn_getcol( f ) = 1;
  930. }
  931. else
  932. {
  933. ++( * prn_getcol( f ));
  934. }
  935. /* now output the character */
  936. return xxxputc( f, c );
  937. }
  938. /***************************************************************
  939. FUNCTION: xxxputc()
  940. DESCRIPTION: This function sends a character to a
  941. specified file or output device.
  942. ***************************************************************/
  943. #if ANSI_C
  944. static int
  945. xxxputc( FILE *f, char c )
  946. #else
  947. static int
  948. xxxputc( f, c )
  949. FILE *f;
  950. char c;
  951. #endif
  952. {
  953. if (( f == stdout ) || ( f == stderr ))
  954. {
  955. return bwx_putc( c );
  956. }
  957. else
  958. {
  959. return fputc( c, f );
  960. }
  961. }
  962. /***************************************************************
  963. FUNCTION: prn_getcol()
  964. DESCRIPTION: This function returns a pointer to an
  965. integer containing the current PRINT
  966. column for a specified file or device.
  967. ***************************************************************/
  968. #if ANSI_C
  969. int *
  970. prn_getcol( FILE *f )
  971. #else
  972. int *
  973. prn_getcol( f )
  974. FILE *f;
  975. #endif
  976. {
  977. register int n;
  978. static int dummy_pos;
  979. if (( f == stdout ) || ( f == stderr ))
  980. {
  981. return &prn_col;
  982. }
  983. #if COMMON_CMDS
  984. for ( n = 0; n < DEF_DEVICES; ++n )
  985. {
  986. if ( dev_table[ n ].cfp == f )
  987. {
  988. return &( dev_table[ n ].col );
  989. }
  990. }
  991. #endif
  992. /* search failed */
  993. #if PROG_ERRORS
  994. bwb_error( "in prn_getcol(): failed to find file pointer" );
  995. #else
  996. bwb_error( err_devnum );
  997. #endif
  998. return &dummy_pos;
  999. }
  1000. /***************************************************************
  1001. FUNCTION: prn_getwidth()
  1002. DESCRIPTION: This function returns the PRINT width for
  1003. a specified file or output device.
  1004. ***************************************************************/
  1005. #if ANSI_C
  1006. int
  1007. prn_getwidth( FILE *f )
  1008. #else
  1009. int
  1010. prn_getwidth( f )
  1011. FILE *f;
  1012. #endif
  1013. {
  1014. register int n;
  1015. if (( f == stdout ) || ( f == stderr ))
  1016. {
  1017. return prn_width;
  1018. }
  1019. #if COMMON_CMDS
  1020. for ( n = 0; n < DEF_DEVICES; ++n )
  1021. {
  1022. if ( dev_table[ n ].cfp == f )
  1023. {
  1024. return dev_table[ n ].width;
  1025. }
  1026. }
  1027. #endif
  1028. /* search failed */
  1029. #if PROG_ERRORS
  1030. bwb_error( "in prn_getwidth(): failed to find file pointer" );
  1031. #else
  1032. bwb_error( err_devnum );
  1033. #endif
  1034. return 1;
  1035. }
  1036. /***************************************************************
  1037. FUNCTION: prn_precision()
  1038. DESCRIPTION: This function returns the level of precision
  1039. required for a specified numerical value.
  1040. ***************************************************************/
  1041. #if ANSI_C
  1042. int
  1043. prn_precision( struct bwb_variable *v )
  1044. #else
  1045. int
  1046. prn_precision( v )
  1047. struct bwb_variable *v;
  1048. #endif
  1049. {
  1050. int max_precision = 6;
  1051. bnumber nval, d;
  1052. int r;
  1053. /* check for double value */
  1054. if ( v->type == NUMBER )
  1055. {
  1056. max_precision = 12;
  1057. }
  1058. /* get the value in nval */
  1059. nval = (bnumber) fabs( (double) var_getnval( v ) );
  1060. /* cycle through until precision is found */
  1061. d = (bnumber) 1;
  1062. for ( r = 0; r < max_precision; ++r )
  1063. {
  1064. #if INTENSIVE_DEBUG
  1065. sprintf( bwb_ebuf, "in prn_precision(): fmod( %f, %f ) = %.12f",
  1066. nval, d, fmod( (double) nval, (double) d ) );
  1067. bwb_debug( bwb_ebuf );
  1068. #endif
  1069. if ( fmod( (double) nval, (double) d ) < 0.0000001 ) /* JBV */
  1070. {
  1071. return r;
  1072. }
  1073. d /= 10;
  1074. }
  1075. /* return */
  1076. return r;
  1077. }
  1078. /***************************************************************
  1079. FUNCTION: bwb_debug()
  1080. DESCRIPTION: This function is called to display
  1081. debugging messages in Bywater BASIC.
  1082. It does not break out at the current
  1083. point (as bwb_error() does).
  1084. ***************************************************************/
  1085. #if PERMANENT_DEBUG
  1086. #if ANSI_C
  1087. int
  1088. bwb_debug( char *message )
  1089. #else
  1090. int
  1091. bwb_debug( message )
  1092. char *message;
  1093. #endif
  1094. {
  1095. char tbuf[ MAXSTRINGSIZE + 1 ];
  1096. fflush( stdout );
  1097. fflush( errfdevice );
  1098. if ( prn_col != 1 )
  1099. {
  1100. prn_xprintf( errfdevice, "\n" );
  1101. }
  1102. sprintf( tbuf, "DEBUG %s\n", message );
  1103. prn_xprintf( errfdevice, tbuf );
  1104. return TRUE;
  1105. }
  1106. #endif
  1107. #if COMMON_CMDS
  1108. /***************************************************************
  1109. FUNCTION: bwb_lerror()
  1110. DESCRIPTION: This function implements the BASIC ERROR
  1111. command.
  1112. ***************************************************************/
  1113. #if ANSI_C
  1114. struct bwb_line *
  1115. bwb_lerror( struct bwb_line *l )
  1116. #else
  1117. struct bwb_line *
  1118. bwb_lerror( l )
  1119. struct bwb_line *l;
  1120. #endif
  1121. {
  1122. char tbuf[ MAXSTRINGSIZE + 1 ];
  1123. int n;
  1124. struct exp_ese *e; /* JBV */
  1125. int pos; /* JBV */
  1126. #if INTENSIVE_DEBUG
  1127. sprintf( bwb_ebuf, "in bwb_lerror(): entered function " );
  1128. bwb_debug( bwb_ebuf );
  1129. #endif
  1130. /* Check for argument */
  1131. adv_ws( l->buffer, &( l->position ) );
  1132. switch( l->buffer[ l->position ] )
  1133. {
  1134. case '\0':
  1135. case '\n':
  1136. case '\r':
  1137. case ':':
  1138. bwb_error( err_incomplete );
  1139. return bwb_zline( l );
  1140. default:
  1141. break;
  1142. }
  1143. /* get the variable name or numerical constant */
  1144. adv_element( l->buffer, &( l->position ), tbuf );
  1145. /* n = atoi( tbuf ); */ /* Removed by JBV */
  1146. /* Added by JBV */
  1147. pos = 0;
  1148. e = bwb_exp( tbuf, FALSE, &pos );
  1149. n = (int) exp_getnval( e );
  1150. #if INTENSIVE_DEBUG
  1151. sprintf( bwb_ebuf, "in bwb_lerror(): error number is <%d> ", n );
  1152. bwb_debug( bwb_ebuf );
  1153. #endif
  1154. /* check the line number value */
  1155. if ( ( n < 0 ) || ( n >= N_ERRORS ))
  1156. {
  1157. sprintf( bwb_ebuf, "Error number %d is out of range", n );
  1158. bwb_xerror( bwb_ebuf );
  1159. return bwb_zline( l );
  1160. }
  1161. bwb_xerror( err_table[ n ] );
  1162. return bwb_zline( l );
  1163. }
  1164. /***************************************************************
  1165. FUNCTION: bwb_width()
  1166. DESCRIPTION: This C function implements the BASIC WIDTH
  1167. command, setting the maximum output width
  1168. for a specified file or output device.
  1169. SYNTAX: WIDTH [# device-number,] number
  1170. ***************************************************************/
  1171. #if ANSI_C
  1172. struct bwb_line *
  1173. bwb_width( struct bwb_line *l )
  1174. #else
  1175. struct bwb_line *
  1176. bwb_width( l )
  1177. struct bwb_line *l;
  1178. #endif
  1179. {
  1180. int req_devnumber;
  1181. int req_width;
  1182. struct exp_ese *e;
  1183. char tbuf[ MAXSTRINGSIZE + 1 ];
  1184. int pos;
  1185. /* detect device number if present */
  1186. req_devnumber = -1;
  1187. adv_ws( l->buffer, &( l->position ) );
  1188. if ( l->buffer[ l->position ] == '#' )
  1189. {
  1190. ++( l->position );
  1191. adv_element( l->buffer, &( l->position ), tbuf );
  1192. pos = 0;
  1193. e = bwb_exp( tbuf, FALSE, &pos );
  1194. adv_ws( l->buffer, &( l->position ) );
  1195. if ( l->buffer[ l->position ] == ',' )
  1196. {
  1197. ++( l->position );
  1198. }
  1199. else
  1200. {
  1201. #if PROG_ERRORS
  1202. bwb_error( "in bwb_width(): no comma after#n" );
  1203. #else
  1204. bwb_error( err_syntax );
  1205. #endif
  1206. return bwb_zline( l );
  1207. }
  1208. req_devnumber = (int) exp_getnval( e );
  1209. /* check the requested device number */
  1210. if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1211. {
  1212. #if PROG_ERRORS
  1213. bwb_error( "in bwb_width(): Requested device number is out of range." );
  1214. #else
  1215. bwb_error( err_devnum );
  1216. #endif
  1217. return bwb_zline( l );
  1218. }
  1219. #if INTENSIVE_DEBUG
  1220. sprintf( bwb_ebuf, "in bwb_width(): device number is <%d>",
  1221. req_devnumber );
  1222. bwb_debug( bwb_ebuf );
  1223. #endif
  1224. }
  1225. /* read the width requested */
  1226. e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1227. req_width = (int) exp_getnval( e );
  1228. /* check the width */
  1229. if ( ( req_width < 1 ) || ( req_width > 255 ))
  1230. {
  1231. #if PROG_ERRORS
  1232. bwb_error( "in bwb_width(): Requested width is out of range (1-255)" );
  1233. #else
  1234. bwb_error( err_valoorange );
  1235. #endif
  1236. }
  1237. /* assign the width */
  1238. if ( req_devnumber == -1 )
  1239. {
  1240. prn_width = req_width;
  1241. }
  1242. else
  1243. {
  1244. dev_table[ req_devnumber ].width = req_width;
  1245. }
  1246. /* return */
  1247. return bwb_zline( l );
  1248. }
  1249. #endif /* COMMON_CMDS */
  1250. /***************************************************************
  1251. FUNCTION: bwb_error()
  1252. DESCRIPTION: This function is called to handle errors
  1253. in Bywater BASIC. It displays the error
  1254. message, then calls the break_handler()
  1255. routine.
  1256. ***************************************************************/
  1257. #if ANSI_C
  1258. int
  1259. bwb_error( char *message )
  1260. #else
  1261. int
  1262. bwb_error( message )
  1263. char *message;
  1264. #endif
  1265. {
  1266. register int e;
  1267. static char tbuf[ MAXSTRINGSIZE + 1 ]; /* must be permanent */
  1268. static struct bwb_line eline;
  1269. int save_elevel;
  1270. struct bwb_line *cur_l;
  1271. int cur_mode;
  1272. /* try to find the error message to identify the error number */
  1273. err_number = -1; /* just for now */
  1274. err_line = CURTASK number; /* set error line number */
  1275. for ( e = 0; e < N_ERRORS; ++e )
  1276. {
  1277. if ( message == err_table[ e ] ) /* set error number */
  1278. {
  1279. err_number = e;
  1280. e = N_ERRORS; /* break out of loop quickly */
  1281. }
  1282. }
  1283. /* set the position in the current line to the end */
  1284. while( is_eol( bwb_l->buffer, &( bwb_l->position ) ) != TRUE )
  1285. {
  1286. ++( bwb_l->position );
  1287. }
  1288. /* if err_gosubl is not set, then use xerror routine */
  1289. if ( strlen( err_gosubl ) == 0 )
  1290. {
  1291. return bwb_xerror( message );
  1292. }
  1293. #if INTENSIVE_DEBUG
  1294. fprintf( stderr, "!!!!! USER_CALLED ERROR HANDLER\n" );
  1295. #endif
  1296. /* save line and mode */
  1297. cur_l = bwb_l;
  1298. cur_mode = CURTASK excs[ CURTASK exsc ].code;
  1299. /* err_gosubl is set; call user-defined error subroutine */
  1300. sprintf( tbuf, "%s %s", CMD_GOSUB, err_gosubl );
  1301. eline.next = &CURTASK bwb_end;
  1302. eline.position = 0;
  1303. eline.marked = FALSE;
  1304. eline.buffer = tbuf;
  1305. bwb_setexec( &eline, 0, EXEC_NORM );
  1306. /* must be executed now */
  1307. save_elevel = CURTASK exsc;
  1308. bwb_execline(); /* This is a call to GOSUB and will increment
  1309. the exsc counter above save_elevel */
  1310. while ( CURTASK exsc != save_elevel ) /* loop until return from GOSUB loop */
  1311. {
  1312. bwb_execline();
  1313. }
  1314. cur_l->next->position = 0;
  1315. bwb_setexec( cur_l->next, 0, cur_mode );
  1316. return TRUE;
  1317. }
  1318. /***************************************************************
  1319. FUNCTION: bwb_xerror()
  1320. DESCRIPTION: This function is called by bwb_error()
  1321. in Bywater BASIC. It displays the error
  1322. message, then calls the break_handler()
  1323. routine.
  1324. ***************************************************************/
  1325. #if ANSI_C
  1326. static int
  1327. bwb_xerror( char *message )
  1328. #else
  1329. static int
  1330. bwb_xerror( message )
  1331. char *message;
  1332. #endif
  1333. {
  1334. bwx_errmes( message );
  1335. break_handler();
  1336. return FALSE;
  1337. }
  1338. /***************************************************************
  1339. FUNCTION: bwb_esetovar()
  1340. DESCRIPTION: This function converts the value in expression
  1341. stack 'e' to a bwBASIC variable structure.
  1342. ***************************************************************/
  1343. #if ANSI_C
  1344. static struct bwb_variable *
  1345. bwb_esetovar( struct exp_ese *e )
  1346. #else
  1347. static struct bwb_variable *
  1348. bwb_esetovar( e )
  1349. struct exp_ese *e;
  1350. #endif
  1351. {
  1352. static struct bwb_variable b;
  1353. var_make( &b, e->type );
  1354. switch( e->type )
  1355. {
  1356. case STRING:
  1357. str_btob( var_findsval( &b, b.array_pos ), exp_getsval( e ) );
  1358. break;
  1359. default:
  1360. * var_findnval( &b, b.array_pos ) = e->nval;
  1361. break;
  1362. }
  1363. return &b;
  1364. }
  1365. #if COMMON_CMDS
  1366. /***************************************************************
  1367. FUNCTION: bwb_write()
  1368. DESCRIPTION: This C function implements the BASIC WRITE
  1369. command.
  1370. SYNTAX: WRITE [# device-number,] element [, element ]....
  1371. ***************************************************************/
  1372. #if ANSI_C
  1373. struct bwb_line *
  1374. bwb_write( struct bwb_line *l )
  1375. #else
  1376. struct bwb_line *
  1377. bwb_write( l )
  1378. struct bwb_line *l;
  1379. #endif
  1380. {
  1381. struct exp_ese *e;
  1382. int req_devnumber;
  1383. int pos;
  1384. FILE *fp;
  1385. char tbuf[ MAXSTRINGSIZE + 1 ];
  1386. int loop;
  1387. static struct bwb_variable nvar;
  1388. static int init = FALSE;
  1389. /* initialize variable if necessary */
  1390. if ( init == FALSE )
  1391. {
  1392. init = TRUE;
  1393. var_make( &nvar, NUMBER );
  1394. }
  1395. /* detect device number if present */
  1396. adv_ws( l->buffer, &( l->position ) );
  1397. if ( l->buffer[ l->position ] == '#' )
  1398. {
  1399. ++( l->position );
  1400. adv_element( l->buffer, &( l->position ), tbuf );
  1401. pos = 0;
  1402. e = bwb_exp( tbuf, FALSE, &pos );
  1403. adv_ws( l->buffer, &( l->position ) );
  1404. if ( l->buffer[ l->position ] == ',' )
  1405. {
  1406. ++( l->position );
  1407. }
  1408. else
  1409. {
  1410. #if PROG_ERRORS
  1411. bwb_error( "in bwb_write(): no comma after#n" );
  1412. #else
  1413. bwb_error( err_syntax );
  1414. #endif
  1415. return bwb_zline( l );
  1416. }
  1417. req_devnumber = (int) exp_getnval( e );
  1418. /* check the requested device number */
  1419. if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1420. {
  1421. #if PROG_ERRORS
  1422. bwb_error( "in bwb_write(): Requested device number is out of range." );
  1423. #else
  1424. bwb_error( err_devnum );
  1425. #endif
  1426. return bwb_zline( l );
  1427. }
  1428. if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  1429. ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ))
  1430. {
  1431. #if PROG_ERRORS
  1432. bwb_error( "in bwb_write(): Requested device number is not open." );
  1433. #else
  1434. bwb_error( err_devnum );
  1435. #endif
  1436. return bwb_zline( l );
  1437. }
  1438. if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT )
  1439. {
  1440. #if PROG_ERRORS
  1441. bwb_error( "in bwb_write(): Requested device is not open for OUTPUT." );
  1442. #else
  1443. bwb_error( err_devnum );
  1444. #endif
  1445. return bwb_zline( l );
  1446. }
  1447. #if INTENSIVE_DEBUG
  1448. sprintf( bwb_ebuf, "in bwb_write(): device number is <%d>",
  1449. req_devnumber );
  1450. bwb_debug( bwb_ebuf );
  1451. #endif
  1452. /* look up the requested device in the device table */
  1453. fp = dev_table[ req_devnumber ].cfp;
  1454. }
  1455. else
  1456. {
  1457. fp = stdout;
  1458. }
  1459. /* be sure there is an element to print */
  1460. adv_ws( l->buffer, &( l->position ) );
  1461. loop = TRUE;
  1462. switch( l->buffer[ l->position ] )
  1463. {
  1464. case '\n':
  1465. case '\r':
  1466. case '\0':
  1467. case ':':
  1468. loop = FALSE;
  1469. break;
  1470. }
  1471. /* loop through elements */
  1472. while ( loop == TRUE )
  1473. {
  1474. /* get the next element */
  1475. e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1476. /* perform type-specific output */
  1477. switch( e->type )
  1478. {
  1479. case STRING:
  1480. xputc( fp, '\"' );
  1481. str_btoc( tbuf, exp_getsval( e ) );
  1482. prn_xprintf( fp, tbuf );
  1483. xputc( fp, '\"' );
  1484. #if INTENSIVE_DEBUG
  1485. sprintf( bwb_ebuf, "in bwb_write(): output string element <\"%s\">",
  1486. tbuf );
  1487. bwb_debug( bwb_ebuf );
  1488. #endif
  1489. break;
  1490. default:
  1491. * var_findnval( &nvar, nvar.array_pos ) =
  1492. exp_getnval( e );
  1493. #if NUMBER_DOUBLE
  1494. sprintf( tbuf, " %.*lf", prn_precision( &nvar ),
  1495. var_getnval( &nvar ) );
  1496. #else
  1497. sprintf( tbuf, " %.*f", prn_precision( &nvar ),
  1498. var_getnval( &nvar ) );
  1499. #endif
  1500. prn_xprintf( fp, tbuf );
  1501. #if INTENSIVE_DEBUG
  1502. sprintf( bwb_ebuf, "in bwb_write(): output numerical element <%s>",
  1503. tbuf );
  1504. bwb_debug( bwb_ebuf );
  1505. #endif
  1506. break;
  1507. } /* end of case for type-specific output */
  1508. /* seek a comma at end of element */
  1509. adv_ws( l->buffer, &( l->position ) );
  1510. if ( l->buffer[ l->position ] == ',' )
  1511. {
  1512. xputc( fp, ',' );
  1513. ++( l->position );
  1514. }
  1515. /* no comma: end the loop */
  1516. else
  1517. {
  1518. loop = FALSE;
  1519. }
  1520. } /* end of loop through elements */
  1521. /* print LF */
  1522. xputc( fp, '\n' );
  1523. /* return */
  1524. return bwb_zline( l );
  1525. }
  1526. #endif