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.
 
 
 
 
 
 

1883 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. /* check for pending TAB */
  857. if ( tab_pending == TRUE )
  858. {
  859. if ( (int) c < ( * prn_getcol( f ) ) )
  860. {
  861. xxputc( f, '\n' );
  862. }
  863. while( ( * prn_getcol( f )) < (int) c )
  864. {
  865. xxputc( f, ' ' );
  866. }
  867. tab_pending = FALSE;
  868. return TRUE;
  869. }
  870. /* check c for specific output options */
  871. switch( c )
  872. {
  873. case PRN_TAB:
  874. tab_pending = TRUE;
  875. break;
  876. case '\t':
  877. while( ( (* prn_getcol( f )) % 14 ) != 0 )
  878. {
  879. xxputc( f, ' ' );
  880. }
  881. break;
  882. default:
  883. xxputc( f, c );
  884. break;
  885. }
  886. return TRUE;
  887. }
  888. /***************************************************************
  889. FUNCTION: xxputc()
  890. DESCRIPTION: This function outputs a character to a
  891. specified file or output device, checking
  892. to be sure the PRINT width is within
  893. the bounds specified for that device.
  894. ***************************************************************/
  895. #if ANSI_C
  896. static int
  897. xxputc( FILE *f, char c )
  898. #else
  899. static int
  900. xxputc( f, c )
  901. FILE *f;
  902. char c;
  903. #endif
  904. {
  905. /* check to see if width has been exceeded */
  906. if ( * prn_getcol( f ) >= prn_getwidth( f ))
  907. {
  908. xxxputc( f, '\n' ); /* output LF */
  909. * prn_getcol( f ) = 1; /* and reset */
  910. }
  911. /* adjust the column counter */
  912. if ( c == '\n' )
  913. {
  914. * prn_getcol( f ) = 1;
  915. }
  916. else
  917. {
  918. ++( * prn_getcol( f ));
  919. }
  920. /* now output the character */
  921. return xxxputc( f, c );
  922. }
  923. /***************************************************************
  924. FUNCTION: xxxputc()
  925. DESCRIPTION: This function sends a character to a
  926. specified file or output device.
  927. ***************************************************************/
  928. #if ANSI_C
  929. static int
  930. xxxputc( FILE *f, char c )
  931. #else
  932. static int
  933. xxxputc( f, c )
  934. FILE *f;
  935. char c;
  936. #endif
  937. {
  938. if (( f == stdout ) || ( f == stderr ))
  939. {
  940. return bwx_putc( c );
  941. }
  942. else
  943. {
  944. return fputc( c, f );
  945. }
  946. }
  947. /***************************************************************
  948. FUNCTION: prn_getcol()
  949. DESCRIPTION: This function returns a pointer to an
  950. integer containing the current PRINT
  951. column for a specified file or device.
  952. ***************************************************************/
  953. #if ANSI_C
  954. int *
  955. prn_getcol( FILE *f )
  956. #else
  957. int *
  958. prn_getcol( f )
  959. FILE *f;
  960. #endif
  961. {
  962. register int n;
  963. static int dummy_pos;
  964. if (( f == stdout ) || ( f == stderr ))
  965. {
  966. return &prn_col;
  967. }
  968. #if COMMON_CMDS
  969. for ( n = 0; n < DEF_DEVICES; ++n )
  970. {
  971. if ( dev_table[ n ].cfp == f )
  972. {
  973. return &( dev_table[ n ].col );
  974. }
  975. }
  976. #endif
  977. /* search failed */
  978. #if PROG_ERRORS
  979. bwb_error( "in prn_getcol(): failed to find file pointer" );
  980. #else
  981. bwb_error( err_devnum );
  982. #endif
  983. return &dummy_pos;
  984. }
  985. /***************************************************************
  986. FUNCTION: prn_getwidth()
  987. DESCRIPTION: This function returns the PRINT width for
  988. a specified file or output device.
  989. ***************************************************************/
  990. #if ANSI_C
  991. int
  992. prn_getwidth( FILE *f )
  993. #else
  994. int
  995. prn_getwidth( f )
  996. FILE *f;
  997. #endif
  998. {
  999. register int n;
  1000. if (( f == stdout ) || ( f == stderr ))
  1001. {
  1002. return prn_width;
  1003. }
  1004. #if COMMON_CMDS
  1005. for ( n = 0; n < DEF_DEVICES; ++n )
  1006. {
  1007. if ( dev_table[ n ].cfp == f )
  1008. {
  1009. return dev_table[ n ].width;
  1010. }
  1011. }
  1012. #endif
  1013. /* search failed */
  1014. #if PROG_ERRORS
  1015. bwb_error( "in prn_getwidth(): failed to find file pointer" );
  1016. #else
  1017. bwb_error( err_devnum );
  1018. #endif
  1019. return 1;
  1020. }
  1021. /***************************************************************
  1022. FUNCTION: prn_precision()
  1023. DESCRIPTION: This function returns the level of precision
  1024. required for a specified numerical value.
  1025. ***************************************************************/
  1026. #if ANSI_C
  1027. int
  1028. prn_precision( struct bwb_variable *v )
  1029. #else
  1030. int
  1031. prn_precision( v )
  1032. struct bwb_variable *v;
  1033. #endif
  1034. {
  1035. int max_precision = 6;
  1036. bnumber nval, d;
  1037. int r;
  1038. /* check for double value */
  1039. if ( v->type == NUMBER )
  1040. {
  1041. max_precision = 12;
  1042. }
  1043. /* get the value in nval */
  1044. nval = (bnumber) fabs( (double) var_getnval( v ) );
  1045. /* cycle through until precision is found */
  1046. d = (bnumber) 1;
  1047. for ( r = 0; r < max_precision; ++r )
  1048. {
  1049. #if INTENSIVE_DEBUG
  1050. sprintf( bwb_ebuf, "in prn_precision(): fmod( %f, %f ) = %.12f",
  1051. nval, d, fmod( (double) nval, (double) d ) );
  1052. bwb_debug( bwb_ebuf );
  1053. #endif
  1054. if ( fmod( (double) nval, (double) d ) < 0.0000001 ) /* JBV */
  1055. {
  1056. return r;
  1057. }
  1058. d /= 10;
  1059. }
  1060. /* return */
  1061. return r;
  1062. }
  1063. /***************************************************************
  1064. FUNCTION: bwb_debug()
  1065. DESCRIPTION: This function is called to display
  1066. debugging messages in Bywater BASIC.
  1067. It does not break out at the current
  1068. point (as bwb_error() does).
  1069. ***************************************************************/
  1070. #if PERMANENT_DEBUG
  1071. #if ANSI_C
  1072. int
  1073. bwb_debug( char *message )
  1074. #else
  1075. int
  1076. bwb_debug( message )
  1077. char *message;
  1078. #endif
  1079. {
  1080. char tbuf[ MAXSTRINGSIZE + 1 ];
  1081. fflush( stdout );
  1082. fflush( errfdevice );
  1083. if ( prn_col != 1 )
  1084. {
  1085. prn_xprintf( errfdevice, "\n" );
  1086. }
  1087. sprintf( tbuf, "DEBUG %s\n", message );
  1088. prn_xprintf( errfdevice, tbuf );
  1089. return TRUE;
  1090. }
  1091. #endif
  1092. #if COMMON_CMDS
  1093. /***************************************************************
  1094. FUNCTION: bwb_lerror()
  1095. DESCRIPTION: This function implements the BASIC ERROR
  1096. command.
  1097. ***************************************************************/
  1098. #if ANSI_C
  1099. struct bwb_line *
  1100. bwb_lerror( struct bwb_line *l )
  1101. #else
  1102. struct bwb_line *
  1103. bwb_lerror( l )
  1104. struct bwb_line *l;
  1105. #endif
  1106. {
  1107. char tbuf[ MAXSTRINGSIZE + 1 ];
  1108. int n;
  1109. struct exp_ese *e; /* JBV */
  1110. int pos; /* JBV */
  1111. #if INTENSIVE_DEBUG
  1112. sprintf( bwb_ebuf, "in bwb_lerror(): entered function " );
  1113. bwb_debug( bwb_ebuf );
  1114. #endif
  1115. /* Check for argument */
  1116. adv_ws( l->buffer, &( l->position ) );
  1117. switch( l->buffer[ l->position ] )
  1118. {
  1119. case '\0':
  1120. case '\n':
  1121. case '\r':
  1122. case ':':
  1123. bwb_error( err_incomplete );
  1124. return bwb_zline( l );
  1125. default:
  1126. break;
  1127. }
  1128. /* get the variable name or numerical constant */
  1129. adv_element( l->buffer, &( l->position ), tbuf );
  1130. /* n = atoi( tbuf ); */ /* Removed by JBV */
  1131. /* Added by JBV */
  1132. pos = 0;
  1133. e = bwb_exp( tbuf, FALSE, &pos );
  1134. n = (int) exp_getnval( e );
  1135. #if INTENSIVE_DEBUG
  1136. sprintf( bwb_ebuf, "in bwb_lerror(): error number is <%d> ", n );
  1137. bwb_debug( bwb_ebuf );
  1138. #endif
  1139. /* check the line number value */
  1140. if ( ( n < 0 ) || ( n >= N_ERRORS ))
  1141. {
  1142. sprintf( bwb_ebuf, "Error number %d is out of range", n );
  1143. bwb_xerror( bwb_ebuf );
  1144. return bwb_zline( l );
  1145. }
  1146. bwb_xerror( err_table[ n ] );
  1147. return bwb_zline( l );
  1148. }
  1149. /***************************************************************
  1150. FUNCTION: bwb_width()
  1151. DESCRIPTION: This C function implements the BASIC WIDTH
  1152. command, setting the maximum output width
  1153. for a specified file or output device.
  1154. SYNTAX: WIDTH [# device-number,] number
  1155. ***************************************************************/
  1156. #if ANSI_C
  1157. struct bwb_line *
  1158. bwb_width( struct bwb_line *l )
  1159. #else
  1160. struct bwb_line *
  1161. bwb_width( l )
  1162. struct bwb_line *l;
  1163. #endif
  1164. {
  1165. int req_devnumber;
  1166. int req_width;
  1167. struct exp_ese *e;
  1168. char tbuf[ MAXSTRINGSIZE + 1 ];
  1169. int pos;
  1170. /* detect device number if present */
  1171. req_devnumber = -1;
  1172. adv_ws( l->buffer, &( l->position ) );
  1173. if ( l->buffer[ l->position ] == '#' )
  1174. {
  1175. ++( l->position );
  1176. adv_element( l->buffer, &( l->position ), tbuf );
  1177. pos = 0;
  1178. e = bwb_exp( tbuf, FALSE, &pos );
  1179. adv_ws( l->buffer, &( l->position ) );
  1180. if ( l->buffer[ l->position ] == ',' )
  1181. {
  1182. ++( l->position );
  1183. }
  1184. else
  1185. {
  1186. #if PROG_ERRORS
  1187. bwb_error( "in bwb_width(): no comma after#n" );
  1188. #else
  1189. bwb_error( err_syntax );
  1190. #endif
  1191. return bwb_zline( l );
  1192. }
  1193. req_devnumber = (int) exp_getnval( e );
  1194. /* check the requested device number */
  1195. if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1196. {
  1197. #if PROG_ERRORS
  1198. bwb_error( "in bwb_width(): Requested device number is out of range." );
  1199. #else
  1200. bwb_error( err_devnum );
  1201. #endif
  1202. return bwb_zline( l );
  1203. }
  1204. #if INTENSIVE_DEBUG
  1205. sprintf( bwb_ebuf, "in bwb_width(): device number is <%d>",
  1206. req_devnumber );
  1207. bwb_debug( bwb_ebuf );
  1208. #endif
  1209. }
  1210. /* read the width requested */
  1211. e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1212. req_width = (int) exp_getnval( e );
  1213. /* check the width */
  1214. if ( ( req_width < 1 ) || ( req_width > 255 ))
  1215. {
  1216. #if PROG_ERRORS
  1217. bwb_error( "in bwb_width(): Requested width is out of range (1-255)" );
  1218. #else
  1219. bwb_error( err_valoorange );
  1220. #endif
  1221. }
  1222. /* assign the width */
  1223. if ( req_devnumber == -1 )
  1224. {
  1225. prn_width = req_width;
  1226. }
  1227. else
  1228. {
  1229. dev_table[ req_devnumber ].width = req_width;
  1230. }
  1231. /* return */
  1232. return bwb_zline( l );
  1233. }
  1234. #endif /* COMMON_CMDS */
  1235. /***************************************************************
  1236. FUNCTION: bwb_error()
  1237. DESCRIPTION: This function is called to handle errors
  1238. in Bywater BASIC. It displays the error
  1239. message, then calls the break_handler()
  1240. routine.
  1241. ***************************************************************/
  1242. #if ANSI_C
  1243. int
  1244. bwb_error( char *message )
  1245. #else
  1246. int
  1247. bwb_error( message )
  1248. char *message;
  1249. #endif
  1250. {
  1251. register int e;
  1252. static char tbuf[ MAXSTRINGSIZE + 1 ]; /* must be permanent */
  1253. static struct bwb_line eline;
  1254. int save_elevel;
  1255. struct bwb_line *cur_l;
  1256. int cur_mode;
  1257. /* try to find the error message to identify the error number */
  1258. err_number = -1; /* just for now */
  1259. err_line = CURTASK number; /* set error line number */
  1260. for ( e = 0; e < N_ERRORS; ++e )
  1261. {
  1262. if ( message == err_table[ e ] ) /* set error number */
  1263. {
  1264. err_number = e;
  1265. e = N_ERRORS; /* break out of loop quickly */
  1266. }
  1267. }
  1268. /* set the position in the current line to the end */
  1269. while( is_eol( bwb_l->buffer, &( bwb_l->position ) ) != TRUE )
  1270. {
  1271. ++( bwb_l->position );
  1272. }
  1273. /* if err_gosubl is not set, then use xerror routine */
  1274. if ( strlen( err_gosubl ) == 0 )
  1275. {
  1276. return bwb_xerror( message );
  1277. }
  1278. #if INTENSIVE_DEBUG
  1279. fprintf( stderr, "!!!!! USER_CALLED ERROR HANDLER\n" );
  1280. #endif
  1281. /* save line and mode */
  1282. cur_l = bwb_l;
  1283. cur_mode = CURTASK excs[ CURTASK exsc ].code;
  1284. /* err_gosubl is set; call user-defined error subroutine */
  1285. sprintf( tbuf, "%s %s", CMD_GOSUB, err_gosubl );
  1286. eline.next = &CURTASK bwb_end;
  1287. eline.position = 0;
  1288. eline.marked = FALSE;
  1289. eline.buffer = tbuf;
  1290. bwb_setexec( &eline, 0, EXEC_NORM );
  1291. /* must be executed now */
  1292. save_elevel = CURTASK exsc;
  1293. bwb_execline(); /* This is a call to GOSUB and will increment
  1294. the exsc counter above save_elevel */
  1295. while ( CURTASK exsc != save_elevel ) /* loop until return from GOSUB loop */
  1296. {
  1297. bwb_execline();
  1298. }
  1299. cur_l->next->position = 0;
  1300. bwb_setexec( cur_l->next, 0, cur_mode );
  1301. return TRUE;
  1302. }
  1303. /***************************************************************
  1304. FUNCTION: bwb_xerror()
  1305. DESCRIPTION: This function is called by bwb_error()
  1306. in Bywater BASIC. It displays the error
  1307. message, then calls the break_handler()
  1308. routine.
  1309. ***************************************************************/
  1310. #if ANSI_C
  1311. static int
  1312. bwb_xerror( char *message )
  1313. #else
  1314. static int
  1315. bwb_xerror( message )
  1316. char *message;
  1317. #endif
  1318. {
  1319. bwx_errmes( message );
  1320. break_handler();
  1321. return FALSE;
  1322. }
  1323. /***************************************************************
  1324. FUNCTION: bwb_esetovar()
  1325. DESCRIPTION: This function converts the value in expression
  1326. stack 'e' to a bwBASIC variable structure.
  1327. ***************************************************************/
  1328. #if ANSI_C
  1329. static struct bwb_variable *
  1330. bwb_esetovar( struct exp_ese *e )
  1331. #else
  1332. static struct bwb_variable *
  1333. bwb_esetovar( e )
  1334. struct exp_ese *e;
  1335. #endif
  1336. {
  1337. static struct bwb_variable b;
  1338. var_make( &b, e->type );
  1339. switch( e->type )
  1340. {
  1341. case STRING:
  1342. str_btob( var_findsval( &b, b.array_pos ), exp_getsval( e ) );
  1343. break;
  1344. default:
  1345. * var_findnval( &b, b.array_pos ) = e->nval;
  1346. break;
  1347. }
  1348. return &b;
  1349. }
  1350. #if COMMON_CMDS
  1351. /***************************************************************
  1352. FUNCTION: bwb_write()
  1353. DESCRIPTION: This C function implements the BASIC WRITE
  1354. command.
  1355. SYNTAX: WRITE [# device-number,] element [, element ]....
  1356. ***************************************************************/
  1357. #if ANSI_C
  1358. struct bwb_line *
  1359. bwb_write( struct bwb_line *l )
  1360. #else
  1361. struct bwb_line *
  1362. bwb_write( l )
  1363. struct bwb_line *l;
  1364. #endif
  1365. {
  1366. struct exp_ese *e;
  1367. int req_devnumber;
  1368. int pos;
  1369. FILE *fp;
  1370. char tbuf[ MAXSTRINGSIZE + 1 ];
  1371. int loop;
  1372. static struct bwb_variable nvar;
  1373. static int init = FALSE;
  1374. /* initialize variable if necessary */
  1375. if ( init == FALSE )
  1376. {
  1377. init = TRUE;
  1378. var_make( &nvar, NUMBER );
  1379. }
  1380. /* detect device number if present */
  1381. adv_ws( l->buffer, &( l->position ) );
  1382. if ( l->buffer[ l->position ] == '#' )
  1383. {
  1384. ++( l->position );
  1385. adv_element( l->buffer, &( l->position ), tbuf );
  1386. pos = 0;
  1387. e = bwb_exp( tbuf, FALSE, &pos );
  1388. adv_ws( l->buffer, &( l->position ) );
  1389. if ( l->buffer[ l->position ] == ',' )
  1390. {
  1391. ++( l->position );
  1392. }
  1393. else
  1394. {
  1395. #if PROG_ERRORS
  1396. bwb_error( "in bwb_write(): no comma after#n" );
  1397. #else
  1398. bwb_error( err_syntax );
  1399. #endif
  1400. return bwb_zline( l );
  1401. }
  1402. req_devnumber = (int) exp_getnval( e );
  1403. /* check the requested device number */
  1404. if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1405. {
  1406. #if PROG_ERRORS
  1407. bwb_error( "in bwb_write(): Requested device number is out of range." );
  1408. #else
  1409. bwb_error( err_devnum );
  1410. #endif
  1411. return bwb_zline( l );
  1412. }
  1413. if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  1414. ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ))
  1415. {
  1416. #if PROG_ERRORS
  1417. bwb_error( "in bwb_write(): Requested device number is not open." );
  1418. #else
  1419. bwb_error( err_devnum );
  1420. #endif
  1421. return bwb_zline( l );
  1422. }
  1423. if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT )
  1424. {
  1425. #if PROG_ERRORS
  1426. bwb_error( "in bwb_write(): Requested device is not open for OUTPUT." );
  1427. #else
  1428. bwb_error( err_devnum );
  1429. #endif
  1430. return bwb_zline( l );
  1431. }
  1432. #if INTENSIVE_DEBUG
  1433. sprintf( bwb_ebuf, "in bwb_write(): device number is <%d>",
  1434. req_devnumber );
  1435. bwb_debug( bwb_ebuf );
  1436. #endif
  1437. /* look up the requested device in the device table */
  1438. fp = dev_table[ req_devnumber ].cfp;
  1439. }
  1440. else
  1441. {
  1442. fp = stdout;
  1443. }
  1444. /* be sure there is an element to print */
  1445. adv_ws( l->buffer, &( l->position ) );
  1446. loop = TRUE;
  1447. switch( l->buffer[ l->position ] )
  1448. {
  1449. case '\n':
  1450. case '\r':
  1451. case '\0':
  1452. case ':':
  1453. loop = FALSE;
  1454. break;
  1455. }
  1456. /* loop through elements */
  1457. while ( loop == TRUE )
  1458. {
  1459. /* get the next element */
  1460. e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1461. /* perform type-specific output */
  1462. switch( e->type )
  1463. {
  1464. case STRING:
  1465. xputc( fp, '\"' );
  1466. str_btoc( tbuf, exp_getsval( e ) );
  1467. prn_xprintf( fp, tbuf );
  1468. xputc( fp, '\"' );
  1469. #if INTENSIVE_DEBUG
  1470. sprintf( bwb_ebuf, "in bwb_write(): output string element <\"%s\">",
  1471. tbuf );
  1472. bwb_debug( bwb_ebuf );
  1473. #endif
  1474. break;
  1475. default:
  1476. * var_findnval( &nvar, nvar.array_pos ) =
  1477. exp_getnval( e );
  1478. #if NUMBER_DOUBLE
  1479. sprintf( tbuf, " %.*lf", prn_precision( &nvar ),
  1480. var_getnval( &nvar ) );
  1481. #else
  1482. sprintf( tbuf, " %.*f", prn_precision( &nvar ),
  1483. var_getnval( &nvar ) );
  1484. #endif
  1485. prn_xprintf( fp, tbuf );
  1486. #if INTENSIVE_DEBUG
  1487. sprintf( bwb_ebuf, "in bwb_write(): output numerical element <%s>",
  1488. tbuf );
  1489. bwb_debug( bwb_ebuf );
  1490. #endif
  1491. break;
  1492. } /* end of case for type-specific output */
  1493. /* seek a comma at end of element */
  1494. adv_ws( l->buffer, &( l->position ) );
  1495. if ( l->buffer[ l->position ] == ',' )
  1496. {
  1497. xputc( fp, ',' );
  1498. ++( l->position );
  1499. }
  1500. /* no comma: end the loop */
  1501. else
  1502. {
  1503. loop = FALSE;
  1504. }
  1505. } /* end of loop through elements */
  1506. /* print LF */
  1507. xputc( fp, '\n' );
  1508. /* return */
  1509. return bwb_zline( l );
  1510. }
  1511. #endif