ChipMaster's bwBASIC This also includes history going back to v2.10. *WARN* some binary files might have been corrupted by CRLF.
 
 
 
 
 
 

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