home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume40 / bwbasic / part11 < prev    next >
Encoding:
Text File  |  1993-10-29  |  47.5 KB  |  1,925 lines

  1. Newsgroups: comp.sources.misc
  2. From: tcamp@delphi.com (Ted A. Campbell)
  3. Subject: v40i062:  bwbasic - Bywater BASIC interpreter version 2.10, Part11/15
  4. Message-ID: <1993Oct29.162735.4089@sparky.sterling.com>
  5. X-Md4-Signature: 4154a6babb92c2a72c627e0330b65f42
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Fri, 29 Oct 1993 16:27:35 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: tcamp@delphi.com (Ted A. Campbell)
  12. Posting-number: Volume 40, Issue 62
  13. Archive-name: bwbasic/part11
  14. Environment: UNIX, DOS
  15. Supersedes: bwbasic: Volume 33, Issue 37-47
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  bwbasic-2.10/bwb_prn.c bwbasic-2.10/bwb_tcc.c
  22. #   bwbasic-2.10/bwbtest/abs.bas bwbasic-2.10/bwbtest/chain1.bas
  23. #   bwbasic-2.10/bwbtest/chain2.bas bwbasic-2.10/bwbtest/dim.bas
  24. #   bwbasic-2.10/bwbtest/doloop.bas bwbasic-2.10/bwbtest/err.bas
  25. #   bwbasic-2.10/bwbtest/ifline.bas bwbasic-2.10/bwbtest/lof.bas
  26. #   bwbasic-2.10/bwbtest/loopuntl.bas
  27. # Wrapped by kent@sparky on Thu Oct 21 10:47:51 1993
  28. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  29. echo If this archive is complete, you will see the following message:
  30. echo '          "shar: End of archive 11 (of 15)."'
  31. if test -f 'bwbasic-2.10/bwb_prn.c' -a "${1}" != "-c" ; then 
  32.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwb_prn.c'\"
  33. else
  34.   echo shar: Extracting \"'bwbasic-2.10/bwb_prn.c'\" \(38372 characters\)
  35.   sed "s/^X//" >'bwbasic-2.10/bwb_prn.c' <<'END_OF_FILE'
  36. X/***************************************************************
  37. X
  38. X    bwb_prn.c       Print and Error-Handling Commands
  39. X                        for Bywater BASIC Interpreter
  40. X
  41. X                        Copyright (c) 1993, Ted A. Campbell
  42. X                        Bywater Software
  43. X
  44. X                        email: tcamp@delphi.com
  45. X
  46. X        Copyright and Permissions Information:
  47. X
  48. X        All U.S. and international rights are claimed by the author,
  49. X        Ted A. Campbell.
  50. X
  51. X    This software is released under the terms of the GNU General
  52. X    Public License (GPL), which is distributed with this software
  53. X    in the file "COPYING".  The GPL specifies the terms under
  54. X    which users may copy and use the software in this distribution.
  55. X
  56. X    A separate license is available for commercial distribution,
  57. X    for information on which you should contact the author.
  58. X
  59. X***************************************************************/
  60. X
  61. X#include <stdio.h>
  62. X#include <ctype.h>
  63. X#include <math.h>
  64. X
  65. X#include "bwbasic.h"
  66. X#include "bwb_mes.h"
  67. X
  68. X/* Prototypes for functions visible only to this file */
  69. X
  70. Xint prn_col = 1;
  71. Xstatic int prn_width = 80;    /* default width for stdout */
  72. X
  73. Xstruct prn_fmt
  74. X   {
  75. X   int type;            /* STRING, NUMBER, SINGLE, or NUMBER */
  76. X   int exponential;        /* TRUE = use exponential notation */
  77. X   int right_justified;        /* TRUE = right justified else left justified */
  78. X   int width;            /* width of main section */
  79. X   int precision;        /* width after decimal point */
  80. X   int commas;                  /* use commas every three steps */
  81. X   int sign;            /* prefix sign to number */
  82. X   int money;            /* prefix money sign to number */
  83. X   int fill;            /* ASCII value for fill character, normally ' ' */
  84. X   int minus;            /* postfix minus sign to number */
  85. X   };
  86. X
  87. X#if ANSI_C
  88. Xstatic int prn_cr( char *buffer, FILE *f );
  89. Xstatic struct prn_fmt *get_prnfmt( char *buffer, int *position, FILE *f );
  90. Xstatic int bwb_xerror( char *message );
  91. Xstatic int xxputc( FILE *f, char c );
  92. Xstatic int xxxputc( FILE *f, char c );
  93. Xstatic struct bwb_variable * bwb_esetovar( struct exp_ese *e );
  94. X#else
  95. Xstatic int prn_cr();
  96. Xstatic struct prn_fmt *get_prnfmt();
  97. Xstatic int bwb_xerror();
  98. Xstatic int xxputc();
  99. Xstatic int xxxputc();
  100. Xstatic struct bwb_variable * bwb_esetovar();
  101. X#endif
  102. X
  103. X
  104. X/***************************************************************
  105. X
  106. X        FUNCTION:       bwb_print()
  107. X
  108. X        DESCRIPTION:    This function implements the BASIC PRINT
  109. X                        command.
  110. X
  111. X    SYNTAX:        PRINT [# device-number,][USING format-string$;] expressions...
  112. X
  113. X***************************************************************/
  114. X
  115. X#if ANSI_C
  116. Xstruct bwb_line *
  117. Xbwb_print( struct bwb_line *l )
  118. X#else
  119. Xstruct bwb_line *
  120. Xbwb_print( l )
  121. X   struct bwb_line *l;
  122. X#endif
  123. X   {
  124. X   FILE *fp;
  125. X   static int pos;
  126. X   int req_devnumber;
  127. X   struct exp_ese *v;
  128. X   static char *s_buffer;              /* small, temporary buffer */
  129. X   static int init = FALSE;
  130. X
  131. X#if INTENSIVE_DEBUG
  132. X   sprintf( bwb_ebuf, "in bwb_print(): enter function" );
  133. X   bwb_debug( bwb_ebuf );
  134. X#endif
  135. X
  136. X   /* initialize buffers if necessary */
  137. X
  138. X   if ( init == FALSE )
  139. X      {
  140. X      init = TRUE;
  141. X      if ( ( s_buffer = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  142. X         {
  143. X#if PROG_ERRORS
  144. X         bwb_error( "in bwb_print(): failed to get memory for s_buffer" );
  145. X#else
  146. X         bwb_error( err_getmem );
  147. X#endif
  148. X         }
  149. X      }
  150. X
  151. X   /* advance beyond whitespace and check for the '#' sign */
  152. X
  153. X   adv_ws( l->buffer, &( l->position ) );
  154. X
  155. X#if COMMON_CMDS
  156. X   if ( l->buffer[ l->position ] == '#' )
  157. X      {
  158. X      ++( l->position );
  159. X      adv_element( l->buffer, &( l->position ), s_buffer );
  160. X      pos = 0;
  161. X      v = bwb_exp( s_buffer, FALSE, &pos );
  162. X      adv_ws( l->buffer, &( l->position ) );
  163. X      if ( l->buffer[ l->position ] == ',' )
  164. X         {
  165. X         ++( l->position );
  166. X         }
  167. X      else
  168. X         {
  169. X#if PROG_ERRORS
  170. X     bwb_error( "in bwb_print(): no comma after #n" );
  171. X#else
  172. X         bwb_error( err_syntax );
  173. X#endif
  174. X         return bwb_zline( l );
  175. X         }
  176. X
  177. X      req_devnumber = (int) exp_getnval( v );
  178. X
  179. X      /* check the requested device number */
  180. X
  181. X      if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  182. X         {
  183. X#if PROG_ERRORS
  184. X         bwb_error( "in bwb_input(): Requested device number is out of range." );
  185. X#else
  186. X         bwb_error( err_devnum );
  187. X#endif
  188. X         return bwb_zline( l );
  189. X         }
  190. X
  191. X      if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  192. X         ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ))
  193. X         {
  194. X#if PROG_ERRORS
  195. X         bwb_error( "in bwb_input(): Requested device number is not open." );
  196. X#else
  197. X         bwb_error( err_devnum );
  198. X#endif
  199. X
  200. X         return bwb_zline( l );
  201. X         }
  202. X
  203. X      if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT )
  204. X         {
  205. X#if PROG_ERRORS
  206. X         bwb_error( "in bwb_print(): Requested device is not open for OUTPUT." );
  207. X#else
  208. X         bwb_error( err_devnum );
  209. X#endif
  210. X
  211. X         return bwb_zline( l );
  212. X         }
  213. X
  214. X#if INTENSIVE_DEBUG
  215. X      sprintf( bwb_ebuf, "in bwb_print(): device number is <%d>",
  216. X         req_devnumber );
  217. X      bwb_debug( bwb_ebuf );
  218. X#endif
  219. X
  220. X      /* look up the requested device in the device table */
  221. X
  222. X      fp = dev_table[ req_devnumber ].cfp;
  223. X
  224. X      }
  225. X
  226. X   else
  227. X      {
  228. X      fp = stdout;
  229. X      }
  230. X
  231. X#else
  232. X   fp = stdout;
  233. X#endif                /* COMMON_CMDS */
  234. X
  235. X   bwb_xprint( l, fp );
  236. X
  237. X   return bwb_zline( l );
  238. X   }
  239. X
  240. X/***************************************************************
  241. X
  242. X        FUNCTION:       bwb_xprint()
  243. X
  244. X    DESCRIPTION:    This function implements the BASIC PRINT
  245. X            command, utilizing a specified file our
  246. X            output device.
  247. X
  248. X***************************************************************/
  249. X
  250. X#if ANSI_C
  251. Xint
  252. Xbwb_xprint( struct bwb_line *l, FILE *f )
  253. X#else
  254. Xint
  255. Xbwb_xprint( l, f )
  256. X   struct bwb_line *l;
  257. X   FILE *f;
  258. X#endif
  259. X   {
  260. X   struct exp_ese *e;
  261. X   int loop;
  262. X   static int p;
  263. X   static int fs_pos;
  264. X   struct prn_fmt *format;
  265. X   static char *format_string;
  266. X   static char *output_string;
  267. X   static char *element;
  268. X   static char *prnbuf;
  269. X   static int init = FALSE;
  270. X#if INTENSIVE_DEBUG || TEST_BSTRING
  271. X   bstring *b;
  272. X#endif
  273. X
  274. X   /* initialize buffers if necessary */
  275. X
  276. X   if ( init == FALSE )
  277. X      {
  278. X      init = TRUE;
  279. X      if ( ( format_string = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  280. X         {
  281. X#if PROG_ERRORS
  282. X         bwb_error( "in bwb_xprint(): failed to get memory for format_string" );
  283. X#else
  284. X         bwb_error( err_getmem );
  285. X#endif
  286. X         }
  287. X      if ( ( output_string = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  288. X         {
  289. X#if PROG_ERRORS
  290. X         bwb_error( "in bwb_xprint(): failed to get memory for output_string" );
  291. X#else
  292. X         bwb_error( err_getmem );
  293. X#endif
  294. X         }
  295. X      if ( ( element = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  296. X         {
  297. X#if PROG_ERRORS
  298. X         bwb_error( "in bwb_xprint(): failed to get memory for element buffer" );
  299. X#else
  300. X         bwb_error( err_getmem );
  301. X#endif
  302. X         }
  303. X      if ( ( prnbuf = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  304. X         {
  305. X#if PROG_ERRORS
  306. X         bwb_error( "in bwb_xprint(): failed to get memory for prnbuf" );
  307. X#else
  308. X         bwb_error( err_getmem );
  309. X#endif
  310. X         }
  311. X      }
  312. X
  313. X   /* Detect USING Here */
  314. X
  315. X   fs_pos = -1;
  316. X
  317. X   /* get "USING" in format_string */
  318. X
  319. X   p = l->position;
  320. X   adv_element( l->buffer, &p, format_string );
  321. X   bwb_strtoupper( format_string );
  322. X
  323. X#if COMMON_CMDS
  324. X
  325. X   /* check to be sure */
  326. X
  327. X   if ( strcmp( format_string, CMD_XUSING ) == 0 )
  328. X      {
  329. X      l->position = p;
  330. X      adv_ws( l->buffer, &( l->position ) );
  331. X
  332. X      /* now get the format string in format_string */
  333. X
  334. X      e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  335. X      if ( e->type == STRING )
  336. X         {
  337. X
  338. X         /* copy the format string to buffer */
  339. X
  340. X         str_btoc( format_string, exp_getsval( e ) );
  341. X
  342. X         /* look for ';' after format string */
  343. X
  344. X         fs_pos = 0;
  345. X         adv_ws( l->buffer, &( l->position ) );
  346. X         if ( l->buffer[ l->position ] == ';' )
  347. X            {
  348. X            ++l->position;
  349. X            adv_ws( l->buffer, &( l->position ) );
  350. X            }
  351. X         else
  352. X            {
  353. X#if PROG_ERRORS
  354. X            bwb_error( "Failed to find \";\" after format string in PRINT USING" );
  355. X#else
  356. X            bwb_error( err_syntax );
  357. X#endif
  358. X            return FALSE;
  359. X            }
  360. X
  361. X#if INTENSIVE_DEBUG
  362. X         sprintf( bwb_ebuf, "in bwb_xprint(): Found USING, format string <%s>",
  363. X            format_string );
  364. X         bwb_debug( bwb_ebuf );
  365. X#endif
  366. X
  367. X         }
  368. X
  369. X      else
  370. X         {
  371. X#if PROG_ERRORS
  372. X         bwb_error( "Failed to find format string after PRINT USING" );
  373. X#else
  374. X         bwb_error( err_syntax );
  375. X#endif
  376. X         return FALSE;
  377. X         }
  378. X      }
  379. X
  380. X#endif             /* COMMON_CMDS */
  381. X
  382. X   /* if no arguments, simply print CR and return */
  383. X
  384. X   adv_ws( l->buffer, &( l->position ) );
  385. X   switch( l->buffer[ l->position ] )
  386. X      {
  387. X      case '\0':
  388. X      case '\n':
  389. X      case '\r':
  390. X      case ':':
  391. X         prn_xprintf( f, "\n" );
  392. X         return TRUE;
  393. X      default:
  394. X         break;
  395. X      }
  396. X
  397. X   /* LOOP THROUGH PRINT ELEMENTS */
  398. X
  399. X   loop = TRUE;
  400. X   while( loop == TRUE )
  401. X      {
  402. X
  403. X      /* resolve the string */
  404. X
  405. X      e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  406. X
  407. X#if INTENSIVE_DEBUG
  408. X      sprintf( bwb_ebuf, "in bwb_xprint(): op <%d> type <%d>",
  409. X         e->operation, e->type );
  410. X      bwb_debug( bwb_ebuf );
  411. X#endif
  412. X
  413. X      /* an OP_NULL probably indicates a terminating ';', but this
  414. X         will be detected later, so we can ignore it for now */
  415. X
  416. X      if ( e->operation != OP_NULL )
  417. X         {
  418. X#if TEST_BSTRING
  419. X         b = exp_getsval( e );
  420. X         sprintf( bwb_ebuf, "in bwb_xprint(): bstring name is <%s>",
  421. X            b->name );
  422. X         bwb_debug( bwb_ebuf );
  423. X#endif
  424. X         str_btoc( element, exp_getsval( e ) );
  425. X         }
  426. X      else
  427. X         {
  428. X         element[ 0 ] = '\0';
  429. X         }
  430. X
  431. X#if INTENSIVE_DEBUG
  432. X      sprintf( bwb_ebuf, "in bwb_xprint(): element <%s>",
  433. X         element );
  434. X      bwb_debug( bwb_ebuf );
  435. X#endif
  436. X
  437. X      /* print with format if there is one */
  438. X
  439. X      if (( fs_pos > -1 ) && ( strlen( element ) > 0 ))
  440. X         {
  441. X
  442. X#if COMMON_CMDS
  443. X
  444. X         format = get_prnfmt( format_string, &fs_pos, f );
  445. X
  446. X#if INTENSIVE_DEBUG
  447. X     sprintf( bwb_ebuf, "in bwb_xprint(): format type <%d> width <%d>",
  448. X            format->type, format->width );
  449. X         bwb_debug( bwb_ebuf );
  450. X#endif
  451. X
  452. X         switch( format->type )
  453. X            {
  454. X            case STRING:
  455. X               if ( e->type != STRING )
  456. X                  {
  457. X#if PROG_ERRORS
  458. X                  bwb_error( "Type mismatch in PRINT USING" );
  459. X#else
  460. X                  bwb_error( err_mismatch );
  461. X#endif
  462. X                  }
  463. X               sprintf( output_string, "%.*s", format->width,
  464. X                  element );
  465. X
  466. X#if INTENSIVE_DEBUG
  467. X               sprintf( bwb_ebuf, "in bwb_xprint(): output string <%s>",
  468. X                  output_string );
  469. X               bwb_debug( bwb_ebuf );
  470. X#endif
  471. X
  472. X               prn_xprintf( f, output_string );
  473. X               break;
  474. X
  475. X        case NUMBER:
  476. X               if ( e->type == STRING )
  477. X                  {
  478. X#if PROG_ERRORS
  479. X                  bwb_error( "Type mismatch in PRINT USING" );
  480. X#else
  481. X                  bwb_error( err_mismatch );
  482. X#endif
  483. X                  }
  484. X
  485. X           if ( format->exponential == TRUE )
  486. X          {
  487. X          sprintf( output_string, "%e",
  488. X             exp_getnval( e ) );
  489. X          }
  490. X           else
  491. X          {
  492. X          sprintf( output_string, "%*.*f",
  493. X             format->width, format->precision, exp_getnval( e ) );
  494. X          }
  495. X
  496. X#if INTENSIVE_DEBUG
  497. X           sprintf( bwb_ebuf, "in bwb_xprint(): output number <%f> string <%s>",
  498. X          exp_getnval( e ), output_string );
  499. X           bwb_debug( bwb_ebuf );
  500. X#endif
  501. X
  502. X               prn_xprintf( f, output_string );
  503. X               break;
  504. X
  505. X        default:
  506. X#if PROG_ERRORS
  507. X               sprintf( bwb_ebuf, "in bwb_xprint(): get_prnfmt() returns unknown type <%c>",
  508. X                  format->type );
  509. X               bwb_error( bwb_ebuf );
  510. X#else
  511. X               bwb_error( err_mismatch );
  512. X#endif
  513. X               break;
  514. X            }
  515. X
  516. X#endif            /* COMMON_CMDS */
  517. X
  518. X         }
  519. X
  520. X      /* not a format string: use defaults */
  521. X
  522. X      else if ( strlen( element ) > 0 )
  523. X         {
  524. X
  525. X         switch( e->type )
  526. X            {
  527. X            case STRING:
  528. X               prn_xprintf( f, element );
  529. X               break;
  530. X            default:
  531. X#if NUMBER_DOUBLE
  532. X               sprintf( prnbuf, " %.*lf", prn_precision( bwb_esetovar( e )),
  533. X                  exp_getnval( e ) );
  534. X#else
  535. X               sprintf( prnbuf, " %.*f", prn_precision( bwb_esetovar( e )),
  536. X                  exp_getnval( e ) );
  537. X#endif
  538. X               prn_xprintf( f, prnbuf );
  539. X               break;
  540. X            }
  541. X         }
  542. X
  543. X      /* check the position to see if the loop should continue */
  544. X
  545. X      adv_ws( l->buffer, &( l->position ) );
  546. X      switch( l->buffer[ l->position ] )
  547. X         {
  548. X#if OLDSTUFF
  549. X         case ':':        /* end of line segment */
  550. X        loop = FALSE;
  551. X        break;
  552. X         case '\0':        /* end of buffer */
  553. X         case '\n':
  554. X         case '\r':
  555. X        loop = FALSE;
  556. X            break;
  557. X#endif
  558. X         case ',':        /* tab over */
  559. X            xputc( f, '\t' );
  560. X            ++l->position;
  561. X            adv_ws( l->buffer, &( l->position ) );
  562. X            break;
  563. X         case ';':        /* concatenate strings */
  564. X            ++l->position;
  565. X            adv_ws( l->buffer, &( l->position ) );
  566. X            break;
  567. X         default:
  568. X            loop = FALSE;
  569. X            break;
  570. X         }
  571. X
  572. X      }                /* end of loop through print elements */
  573. X
  574. X   /* call prn_cr() to print a CR if it is not overridden by a
  575. X      concluding ';' mark */
  576. X
  577. X   prn_cr( l->buffer, f );
  578. X
  579. X   return TRUE;
  580. X
  581. X   }                            /* end of function bwb_xprint() */
  582. X
  583. X#if COMMON_CMDS
  584. X
  585. X/***************************************************************
  586. X
  587. X        FUNCTION:       get_prnfmt()
  588. X
  589. X    DESCRIPTION:    This function gets the PRINT USING
  590. X            format string, returning a structure
  591. X            to the format.
  592. X
  593. X***************************************************************/
  594. X
  595. X#if ANSI_C
  596. Xstatic struct prn_fmt *
  597. Xget_prnfmt( char *buffer, int *position, FILE *f )
  598. X#else
  599. Xstatic struct prn_fmt *
  600. Xget_prnfmt( buffer, position, f )
  601. X   char *buffer;
  602. X   int *position;
  603. X   FILE *f;
  604. X#endif
  605. X   {
  606. X   static struct prn_fmt retstruct;
  607. X   int loop;
  608. X
  609. X   /* set some defaults */
  610. X
  611. X   retstruct.precision = 0;
  612. X   retstruct.type = FALSE;
  613. X   retstruct.exponential = FALSE;
  614. X   retstruct.right_justified = FALSE;
  615. X   retstruct.commas = FALSE;
  616. X   retstruct.sign = FALSE;
  617. X   retstruct.money = FALSE;
  618. X   retstruct.fill = ' ';
  619. X   retstruct.minus = FALSE;
  620. X   retstruct.width = 0;
  621. X
  622. X   /* check for negative position */
  623. X
  624. X   if ( *position < 0 )
  625. X      {
  626. X      return &retstruct;
  627. X      }
  628. X
  629. X   /* advance past whitespace */
  630. X
  631. X   adv_ws( buffer, position );
  632. X
  633. X   /* check first character: a lost can be decided right here */
  634. X
  635. X   loop = TRUE;
  636. X   while( loop == TRUE )
  637. X      {
  638. X
  639. X#if INTENSIVE_DEBUG
  640. X      sprintf( bwb_ebuf, "in get_prnfmt(): loop, buffer <%s>",
  641. X         &( buffer[ *position ] ) );
  642. X      bwb_debug( bwb_ebuf );
  643. X#endif
  644. X
  645. X      switch( buffer[ *position ] )
  646. X         {
  647. X         case ' ':        /* end of this format segment */
  648. X            loop = FALSE;
  649. X            break;
  650. X         case '\0':        /* end of format string */
  651. X         case '\n':
  652. X         case '\r':
  653. X            *position = -1;
  654. X            return &retstruct;
  655. X         case '_':        /* print next character as literal */
  656. X            ++( *position );
  657. X            xputc( f, buffer[ *position ] );
  658. X            ++( *position );
  659. X            break;
  660. X
  661. X     case '!':
  662. X            retstruct.type = STRING;
  663. X            retstruct.width = 1;
  664. X            return &retstruct;
  665. X
  666. X     case '\\':
  667. X
  668. X#if INTENSIVE_DEBUG
  669. X            sprintf( bwb_ebuf, "in get_prnfmt(): found \\" );
  670. X            bwb_debug( bwb_ebuf );
  671. X#endif
  672. X
  673. X        retstruct.type = STRING;
  674. X        ++retstruct.width;
  675. X        ++( *position );
  676. X        for ( ; buffer[ *position ] == ' '; ++( *position ) )
  677. X               {
  678. X               ++retstruct.width;
  679. X               }
  680. X            if ( buffer[ *position ] == '\\' )
  681. X           {
  682. X           ++retstruct.width;
  683. X               ++( *position );
  684. X               }
  685. X            return &retstruct;
  686. X         case '$':
  687. X            ++( *position );
  688. X            retstruct.money = TRUE;
  689. X            if ( buffer[ *position ] == '$' )
  690. X               {
  691. X               ++( *position );
  692. X               }
  693. X            break;
  694. X         case '*':
  695. X            ++( *position );
  696. X            retstruct.fill = '*';
  697. X            if ( buffer[ *position ] == '*' )
  698. X               {
  699. X               ++( *position );
  700. X               }
  701. X            break;
  702. X         case '+':
  703. X            ++( *position );
  704. X            retstruct.sign = TRUE;
  705. X            break;
  706. X         case '#':
  707. X            retstruct.type = NUMBER;        /* for now */
  708. X            ++( *position );
  709. X            for ( retstruct.width = 1; buffer[ *position ] == '#'; ++( *position ) )
  710. X               {
  711. X               ++retstruct.width;
  712. X               }
  713. X            if ( buffer[ *position ] == ',' )
  714. X               {
  715. X               retstruct.commas = TRUE;
  716. X               }
  717. X            if ( buffer[ *position ] == '.' )
  718. X               {
  719. X           retstruct.type = NUMBER;
  720. X           ++retstruct.width;
  721. X               ++( *position );
  722. X               for ( retstruct.precision = 0; buffer[ *position ] == '#'; ++( *position ) )
  723. X                  {
  724. X          ++retstruct.precision;
  725. X          ++retstruct.width;
  726. X                  }
  727. X               }
  728. X            if ( buffer[ *position ] == '-' )
  729. X               {
  730. X               retstruct.minus = TRUE;
  731. X               ++( *position );
  732. X               }
  733. X            return &retstruct;
  734. X
  735. X     case '^':
  736. X            retstruct.type = NUMBER;
  737. X            retstruct.exponential = TRUE;
  738. X            for ( retstruct.width = 1; buffer[ *position ] == '^'; ++( *position ) )
  739. X               {
  740. X               ++retstruct.width;
  741. X               }
  742. X            return &retstruct;
  743. X
  744. X         }
  745. X      }                    /* end of loop */
  746. X
  747. X   return &retstruct;
  748. X   }
  749. X
  750. X#endif
  751. X
  752. X/***************************************************************
  753. X
  754. X        FUNCTION:       prn_cr()
  755. X
  756. X    DESCRIPTION:    This function outputs a carriage-return
  757. X            to a specified file or output device.
  758. X
  759. X***************************************************************/
  760. X
  761. X#if ANSI_C
  762. Xstatic int
  763. Xprn_cr( char *buffer, FILE *f )
  764. X#else
  765. Xstatic int
  766. Xprn_cr( buffer, f )
  767. X   char *buffer;
  768. X   FILE *f;
  769. X#endif
  770. X   {
  771. X   register int c;
  772. X   int loop;
  773. X
  774. X   /* find the end of the buffer */
  775. X
  776. X   for ( c = 0; buffer[ c ] != '\0'; ++c )
  777. X      {
  778. X      }
  779. X
  780. X#if INTENSIVE_DEBUG
  781. X   sprintf( bwb_ebuf, "in prn_cr(): initial c is <%d>", c );
  782. X   bwb_debug( bwb_ebuf );
  783. X#endif
  784. X
  785. X   /* back up through any whitespace */
  786. X
  787. X   loop = TRUE;
  788. X   while ( loop == TRUE )
  789. X      {
  790. X      switch( buffer[ c ] )
  791. X         {
  792. X         case ' ':                              /* if whitespace */
  793. X         case '\t':
  794. X         case 0:
  795. X
  796. X#if INTENSIVE_DEBUG
  797. X            sprintf( bwb_ebuf, "in prn_cr(): backup: c is <%d>, char <%c>[0x%x]",
  798. X               c, buffer[ c ], buffer[ c ] );
  799. X            bwb_debug( bwb_ebuf );
  800. X#endif
  801. X
  802. X            --c;                                /* back up */
  803. X            if ( c < 0 )                        /* check position */
  804. X               {
  805. X               loop = FALSE;
  806. X               }
  807. X            break;
  808. X
  809. X         default:                               /* else break out */
  810. X#if INTENSIVE_DEBUG
  811. X            sprintf( bwb_ebuf, "in prn_cr(): breakout: c is <%d>, char <%c>[0x%x]",
  812. X               c, buffer[ c ], buffer[ c ] );
  813. X            bwb_debug( bwb_ebuf );
  814. X#endif
  815. X            loop = FALSE;
  816. X            break;
  817. X         }
  818. X      }
  819. X
  820. X   if ( buffer[ c ] == ';' )
  821. X      {
  822. X
  823. X#if INTENSIVE_DEBUG
  824. X      sprintf( bwb_ebuf, "in prn_cr(): concluding <;> detected." );
  825. X      bwb_debug( bwb_ebuf );
  826. X#endif
  827. X
  828. X      return FALSE;
  829. X      }
  830. X
  831. X   else
  832. X      {
  833. X      prn_xprintf( f, "\n" );
  834. X      return TRUE;
  835. X      }
  836. X
  837. X   }
  838. X
  839. X/***************************************************************
  840. X
  841. X        FUNCTION:       prn_xprintf()
  842. X
  843. X    DESCRIPTION:    This function outputs a null-terminated
  844. X            string to a specified file or output
  845. X            device.
  846. X
  847. X***************************************************************/
  848. X
  849. X#if ANSI_C
  850. Xint
  851. Xprn_xprintf( FILE *f, char *buffer )
  852. X#else
  853. Xint
  854. Xprn_xprintf( f, buffer )
  855. X   FILE *f;
  856. X   char *buffer;
  857. X#endif
  858. X   {
  859. X   char *p;
  860. X
  861. X   /* DO NOT try anything so stupid as to run bwb_debug() from
  862. X      here, because it will create an endless loop. And don't
  863. X      ask how I know. */
  864. X
  865. X   for ( p = buffer; *p != '\0'; ++p )
  866. X      {
  867. X      xputc( f, *p );
  868. X      }
  869. X
  870. X   return TRUE;
  871. X
  872. X   }
  873. X
  874. X/***************************************************************
  875. X
  876. X        FUNCTION:       xputc()
  877. X
  878. X    DESCRIPTION:    This function outputs a character to a
  879. X            specified file or output device, expanding
  880. X            TABbed output approriately.
  881. X
  882. X***************************************************************/
  883. X
  884. X#if ANSI_C
  885. Xint
  886. Xxputc( FILE *f, char c )
  887. X#else
  888. Xint
  889. Xxputc( f, c )
  890. X   FILE *f;
  891. X   char c;
  892. X#endif
  893. X   {
  894. X   static int tab_pending = FALSE;
  895. X
  896. X   /* check for pending TAB */
  897. X
  898. X   if ( tab_pending == TRUE )
  899. X      {
  900. X      if ( (int) c < ( * prn_getcol( f ) ) )
  901. X         {
  902. X         xxputc( f, '\n' );
  903. X         }
  904. X      while( ( * prn_getcol( f )) < (int) c )
  905. X         {
  906. X         xxputc( f, ' ' );
  907. X         }
  908. X      tab_pending = FALSE;
  909. X      return TRUE;
  910. X      }
  911. X
  912. X   /* check c for specific output options */
  913. X
  914. X   switch( c )
  915. X      {
  916. X      case PRN_TAB:
  917. X         tab_pending = TRUE;
  918. X         break;
  919. X
  920. X      case '\t':
  921. X         while( ( (* prn_getcol( f )) % 14 ) != 0 )
  922. X            {
  923. X            xxputc( f, ' ' );
  924. X            }
  925. X         break;
  926. X
  927. X      default:
  928. X         xxputc( f, c );
  929. X         break;
  930. X      }
  931. X
  932. X   return TRUE;
  933. X
  934. X   }
  935. X
  936. X/***************************************************************
  937. X
  938. X        FUNCTION:       xxputc()
  939. X
  940. X    DESCRIPTION:    This function outputs a character to a
  941. X            specified file or output device, checking
  942. X            to be sure the PRINT width is within
  943. X            the bounds specified for that device.
  944. X
  945. X***************************************************************/
  946. X
  947. X#if ANSI_C
  948. Xstatic int
  949. Xxxputc( FILE *f, char c )
  950. X#else
  951. Xstatic int
  952. Xxxputc( f, c )
  953. X   FILE *f;
  954. X   char c;
  955. X#endif
  956. X   {
  957. X
  958. X   /* check to see if width has been exceeded */
  959. X
  960. X   if ( * prn_getcol( f ) >= prn_getwidth( f ))
  961. X      {
  962. X      xxxputc( f, '\n' );                 /* output LF */
  963. X      * prn_getcol( f ) = 1;        /* and reset */
  964. X      }
  965. X
  966. X   /* adjust the column counter */
  967. X
  968. X   if ( c == '\n' )
  969. X      {
  970. X      * prn_getcol( f ) = 1;
  971. X      }
  972. X   else
  973. X      {
  974. X      ++( * prn_getcol( f ));
  975. X      }
  976. X
  977. X   /* now output the character */
  978. X
  979. X   return xxxputc( f, c );
  980. X
  981. X   }
  982. X
  983. X/***************************************************************
  984. X
  985. X    FUNCTION:       xxxputc()
  986. X
  987. X    DESCRIPTION:    This function sends a character to a
  988. X            specified file or output device.
  989. X
  990. X***************************************************************/
  991. X
  992. X#if ANSI_C
  993. Xstatic int
  994. Xxxxputc( FILE *f, char c )
  995. X#else
  996. Xstatic int
  997. Xxxxputc( f, c )
  998. X   FILE *f;
  999. X   char c;
  1000. X#endif
  1001. X   {
  1002. X   if (( f == stdout ) || ( f == stderr ))
  1003. X      {
  1004. X      return bwx_putc( c );
  1005. X      }
  1006. X   else
  1007. X      {
  1008. X      return fputc( c, f );
  1009. X      }
  1010. X   }
  1011. X
  1012. X/***************************************************************
  1013. X
  1014. X        FUNCTION:       prn_getcol()
  1015. X
  1016. X    DESCRIPTION:    This function returns a pointer to an
  1017. X            integer containing the current PRINT
  1018. X            column for a specified file or device.
  1019. X
  1020. X***************************************************************/
  1021. X
  1022. X#if ANSI_C
  1023. Xint *
  1024. Xprn_getcol( FILE *f )
  1025. X#else
  1026. Xint *
  1027. Xprn_getcol( f )
  1028. X   FILE *f;
  1029. X#endif
  1030. X   {
  1031. X   register int n;
  1032. X   static int dummy_pos;
  1033. X
  1034. X   if (( f == stdout ) || ( f == stderr ))
  1035. X      {
  1036. X      return &prn_col;
  1037. X      }
  1038. X
  1039. X#if COMMON_CMDS
  1040. X   for ( n = 0; n < DEF_DEVICES; ++n )
  1041. X      {
  1042. X      if ( dev_table[ n ].cfp == f )
  1043. X         {
  1044. X         return &( dev_table[ n ].col );
  1045. X         }
  1046. X      }
  1047. X#endif
  1048. X
  1049. X   /* search failed */
  1050. X
  1051. X#if PROG_ERRORS
  1052. X   bwb_error( "in prn_getcol(): failed to find file pointer" );
  1053. X#else
  1054. X   bwb_error( err_devnum );
  1055. X#endif
  1056. X
  1057. X   return &dummy_pos;
  1058. X
  1059. X   }
  1060. X
  1061. X/***************************************************************
  1062. X
  1063. X        FUNCTION:       prn_getwidth()
  1064. X
  1065. X    DESCRIPTION:    This function returns the PRINT width for
  1066. X            a specified file or output device.
  1067. X
  1068. X***************************************************************/
  1069. X
  1070. X#if ANSI_C
  1071. Xint
  1072. Xprn_getwidth( FILE *f )
  1073. X#else
  1074. Xint
  1075. Xprn_getwidth( f )
  1076. X   FILE *f;
  1077. X#endif
  1078. X   {
  1079. X   register int n;
  1080. X
  1081. X   if (( f == stdout ) || ( f == stderr ))
  1082. X      {
  1083. X      return prn_width;
  1084. X      }
  1085. X
  1086. X#if COMMON_CMDS
  1087. X   for ( n = 0; n < DEF_DEVICES; ++n )
  1088. X      {
  1089. X      if ( dev_table[ n ].cfp == f )
  1090. X         {
  1091. X         return dev_table[ n ].width;
  1092. X         }
  1093. X      }
  1094. X#endif
  1095. X
  1096. X   /* search failed */
  1097. X
  1098. X#if PROG_ERRORS
  1099. X   bwb_error( "in prn_getwidth(): failed to find file pointer" );
  1100. X#else
  1101. X   bwb_error( err_devnum );
  1102. X#endif
  1103. X
  1104. X   return 1;
  1105. X
  1106. X   }
  1107. X
  1108. X/***************************************************************
  1109. X
  1110. X        FUNCTION:       prn_precision()
  1111. X
  1112. X    DESCRIPTION:    This function returns the level of precision
  1113. X            required for a specified numerical value.
  1114. X
  1115. X***************************************************************/
  1116. X
  1117. X#if ANSI_C
  1118. Xint
  1119. Xprn_precision( struct bwb_variable *v )
  1120. X#else
  1121. Xint
  1122. Xprn_precision( v )
  1123. X   struct bwb_variable *v;
  1124. X#endif
  1125. X   {
  1126. X   int max_precision = 6;
  1127. X   bnumber nval, d;
  1128. X   int r;
  1129. X
  1130. X   /* check for double value */
  1131. X
  1132. X   if ( v->type == NUMBER )
  1133. X      {
  1134. X      max_precision = 12;
  1135. X      }
  1136. X
  1137. X   /* get the value in nval */
  1138. X
  1139. X   nval = (bnumber) fabs( (double) var_getnval( v ) );
  1140. X
  1141. X   /* cycle through until precision is found */
  1142. X
  1143. X   d = (bnumber) 1;
  1144. X   for ( r = 0; r < max_precision; ++r )
  1145. X      {
  1146. X
  1147. X#if INTENSIVE_DEBUG
  1148. X      sprintf( bwb_ebuf, "in prn_precision(): fmod( %f, %f ) = %.12f",
  1149. X         nval, d, fmod( nval, d ) );
  1150. X      bwb_debug( bwb_ebuf );
  1151. X#endif
  1152. X
  1153. X      if ( fmod( nval, d ) < 0.0000001 )
  1154. X         {
  1155. X         return r;
  1156. X         }
  1157. X      d /= 10;
  1158. X      }
  1159. X
  1160. X   /* return */
  1161. X
  1162. X   return r;
  1163. X
  1164. X   }
  1165. X
  1166. X/***************************************************************
  1167. X
  1168. X        FUNCTION:       bwb_debug()
  1169. X
  1170. X        DESCRIPTION:    This function is called to display
  1171. X                        debugging messages in Bywater BASIC.
  1172. X                        It does not break out at the current
  1173. X                        point (as bwb_error() does).
  1174. X
  1175. X***************************************************************/
  1176. X
  1177. X#if PERMANENT_DEBUG
  1178. X
  1179. X#if ANSI_C
  1180. Xint
  1181. Xbwb_debug( char *message )
  1182. X#else
  1183. Xint
  1184. Xbwb_debug( message )
  1185. X   char *message;
  1186. X#endif
  1187. X   {
  1188. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1189. X
  1190. X   fflush( stdout );
  1191. X   fflush( errfdevice );
  1192. X   if ( prn_col != 1 )
  1193. X      {
  1194. X      prn_xprintf( errfdevice, "\n" );
  1195. X      }
  1196. X   sprintf( tbuf, "DEBUG %s\n", message );
  1197. X   prn_xprintf( errfdevice, tbuf );
  1198. X
  1199. X   return TRUE;
  1200. X   }
  1201. X#endif
  1202. X
  1203. X#if COMMON_CMDS
  1204. X
  1205. X/***************************************************************
  1206. X
  1207. X        FUNCTION:       bwb_lerror()
  1208. X
  1209. X        DESCRIPTION:    This function implements the BASIC ERROR
  1210. X                        command.
  1211. X
  1212. X***************************************************************/
  1213. X
  1214. X#if ANSI_C
  1215. Xstruct bwb_line *
  1216. Xbwb_lerror( struct bwb_line *l )
  1217. X#else
  1218. Xstruct bwb_line *
  1219. Xbwb_lerror( l )
  1220. X   struct bwb_line *l;
  1221. X#endif
  1222. X   {
  1223. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1224. X   int n;
  1225. X
  1226. X#if INTENSIVE_DEBUG
  1227. X   sprintf( bwb_ebuf, "in bwb_lerror(): entered function " );
  1228. X   bwb_debug( bwb_ebuf );
  1229. X#endif
  1230. X
  1231. X   /* Check for argument */
  1232. X
  1233. X   adv_ws( l->buffer, &( l->position ) );
  1234. X   switch( l->buffer[ l->position ] )
  1235. X      {
  1236. X      case '\0':
  1237. X      case '\n':
  1238. X      case '\r':
  1239. X      case ':':
  1240. X         bwb_error( err_incomplete );
  1241. X         return bwb_zline( l );
  1242. X      default:
  1243. X         break;
  1244. X      }
  1245. X
  1246. X   /* get the variable name or numerical constant */
  1247. X
  1248. X   adv_element( l->buffer, &( l->position ), tbuf );
  1249. X   n = atoi( tbuf );
  1250. X
  1251. X#if INTENSIVE_DEBUG
  1252. X   sprintf( bwb_ebuf, "in bwb_lerror(): error number is <%d> ", n );
  1253. X   bwb_debug( bwb_ebuf );
  1254. X#endif
  1255. X
  1256. X   /* check the line number value */
  1257. X
  1258. X   if ( ( n < 0 ) || ( n >= N_ERRORS ))
  1259. X      {
  1260. X      sprintf( bwb_ebuf, "Error number %d is out of range", n );
  1261. X      bwb_xerror( bwb_ebuf );
  1262. X      return bwb_zline( l );
  1263. X      }
  1264. X
  1265. X   bwb_xerror( err_table[ n ] );
  1266. X
  1267. X   return bwb_zline( l );
  1268. X
  1269. X   }
  1270. X
  1271. X/***************************************************************
  1272. X
  1273. X        FUNCTION:       bwb_width()
  1274. X
  1275. X    DESCRIPTION:    This C function implements the BASIC WIDTH
  1276. X            command, setting the maximum output width
  1277. X            for a specified file or output device.
  1278. X
  1279. X    SYNTAX:        WIDTH [# device-number,] number
  1280. X
  1281. X***************************************************************/
  1282. X
  1283. X#if ANSI_C
  1284. Xstruct bwb_line *
  1285. Xbwb_width( struct bwb_line *l )
  1286. X#else
  1287. Xstruct bwb_line *
  1288. Xbwb_width( l )
  1289. X   struct bwb_line *l;
  1290. X#endif
  1291. X   {
  1292. X   int req_devnumber;
  1293. X   int req_width;
  1294. X   struct exp_ese *e;
  1295. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1296. X   int pos;
  1297. X
  1298. X   /* detect device number if present */
  1299. X
  1300. X   req_devnumber = -1;
  1301. X   adv_ws( l->buffer, &( l->position ) );
  1302. X
  1303. X   if ( l->buffer[ l->position ] == '#' )
  1304. X      {
  1305. X      ++( l->position );
  1306. X      adv_element( l->buffer, &( l->position ), tbuf );
  1307. X      pos = 0;
  1308. X      e = bwb_exp( tbuf, FALSE, &pos );
  1309. X      adv_ws( l->buffer, &( l->position ) );
  1310. X      if ( l->buffer[ l->position ] == ',' )
  1311. X         {
  1312. X         ++( l->position );
  1313. X         }
  1314. X      else
  1315. X         {
  1316. X#if PROG_ERRORS
  1317. X         bwb_error( "in bwb_width(): no comma after#n" );
  1318. X#else
  1319. X         bwb_error( err_syntax );
  1320. X#endif
  1321. X         return bwb_zline( l );
  1322. X         }
  1323. X
  1324. X      req_devnumber = (int) exp_getnval( e );
  1325. X
  1326. X      /* check the requested device number */
  1327. X
  1328. X      if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1329. X         {
  1330. X#if PROG_ERRORS
  1331. X         bwb_error( "in bwb_width(): Requested device number is out of range." );
  1332. X#else
  1333. X         bwb_error( err_devnum );
  1334. X#endif
  1335. X         return bwb_zline( l );
  1336. X         }
  1337. X
  1338. X#if INTENSIVE_DEBUG
  1339. X      sprintf( bwb_ebuf, "in bwb_width(): device number is <%d>",
  1340. X         req_devnumber );
  1341. X      bwb_debug( bwb_ebuf );
  1342. X#endif
  1343. X
  1344. X      }
  1345. X
  1346. X   /* read the width requested */
  1347. X
  1348. X   e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1349. X   req_width = (int) exp_getnval( e );
  1350. X
  1351. X   /* check the width */
  1352. X
  1353. X   if ( ( req_width < 1 ) || ( req_width > 255 ))
  1354. X      {
  1355. X#if PROG_ERRORS
  1356. X      bwb_error( "in bwb_width(): Requested width is out of range (1-255)" );
  1357. X#else
  1358. X      bwb_error( err_valoorange );
  1359. X#endif
  1360. X      }
  1361. X
  1362. X   /* assign the width */
  1363. X
  1364. X   if ( req_devnumber == -1 )
  1365. X      {
  1366. X      prn_width = req_width;
  1367. X      }
  1368. X   else
  1369. X      {
  1370. X      dev_table[ req_devnumber ].width = req_width;
  1371. X      }
  1372. X
  1373. X   /* return */
  1374. X
  1375. X   return bwb_zline( l );
  1376. X   }
  1377. X
  1378. X#endif            /* COMMON_CMDS */
  1379. X
  1380. X/***************************************************************
  1381. X
  1382. X        FUNCTION:       bwb_error()
  1383. X
  1384. X        DESCRIPTION:    This function is called to handle errors
  1385. X                        in Bywater BASIC.  It displays the error
  1386. X                        message, then calls the break_handler()
  1387. X                        routine.
  1388. X
  1389. X***************************************************************/
  1390. X
  1391. X#if ANSI_C
  1392. Xint
  1393. Xbwb_error( char *message )
  1394. X#else
  1395. Xint
  1396. Xbwb_error( message )
  1397. X   char *message;
  1398. X#endif
  1399. X   {
  1400. X   register int e;
  1401. X   static char tbuf[ MAXSTRINGSIZE + 1 ];    /* must be permanent */
  1402. X   static struct bwb_line eline;
  1403. X   int save_elevel;
  1404. X   struct bwb_line *cur_l;
  1405. X   int cur_mode;
  1406. X
  1407. X   /* try to find the error message to identify the error number */
  1408. X
  1409. X   err_number = -1;            /* just for now */
  1410. X   err_line = CURTASK number;        /* set error line number */
  1411. X
  1412. X   for ( e = 0; e < N_ERRORS; ++e )
  1413. X      {
  1414. X      if ( message == err_table[ e ] )    /* set error number */
  1415. X         {
  1416. X         err_number = e;
  1417. X         e = N_ERRORS;            /* break out of loop quickly */
  1418. X         }
  1419. X      }
  1420. X
  1421. X   /* set the position in the current line to the end */
  1422. X
  1423. X   while( is_eol( bwb_l->buffer, &( bwb_l->position ) ) != TRUE )
  1424. X      {
  1425. X      ++( bwb_l->position );
  1426. X      }
  1427. X
  1428. X   /* if err_gosubl is not set, then use xerror routine */
  1429. X
  1430. X   if ( strlen( err_gosubl ) == 0 )
  1431. X      {
  1432. X      return bwb_xerror( message );
  1433. X      }
  1434. X
  1435. X#if INTENSIVE_DEBUG
  1436. X   fprintf( stderr, "!!!!! USER_CALLED ERROR HANDLER\n" );
  1437. X#endif
  1438. X
  1439. X   /* save line and mode */
  1440. X
  1441. X   cur_l = bwb_l;
  1442. X   cur_mode = CURTASK excs[ CURTASK exsc ].code;
  1443. X
  1444. X   /* err_gosubl is set; call user-defined error subroutine */
  1445. X
  1446. X   sprintf( tbuf, "%s %s", CMD_GOSUB, err_gosubl );
  1447. X   eline.next = &CURTASK bwb_end;
  1448. X   eline.position = 0;
  1449. X   eline.marked = FALSE;
  1450. X   eline.buffer = tbuf;
  1451. X   bwb_setexec( &eline, 0, EXEC_NORM );
  1452. X
  1453. X   /* must be executed now */
  1454. X
  1455. X   save_elevel = CURTASK exsc;
  1456. X   bwb_execline();              /* This is a call to GOSUB and will increment
  1457. X                   the exsc counter above save_elevel */
  1458. X
  1459. X   while ( CURTASK exsc != save_elevel )        /* loop until return from GOSUB loop */
  1460. X      {
  1461. X      bwb_execline();
  1462. X      }
  1463. X
  1464. X   cur_l->next->position = 0;
  1465. X   bwb_setexec( cur_l->next, 0, cur_mode );
  1466. X
  1467. X   return TRUE;
  1468. X
  1469. X   }
  1470. X
  1471. X/***************************************************************
  1472. X
  1473. X        FUNCTION:       bwb_xerror()
  1474. X
  1475. X        DESCRIPTION:    This function is called by bwb_error()
  1476. X                        in Bywater BASIC.  It displays the error
  1477. X                        message, then calls the break_handler()
  1478. X                        routine.
  1479. X
  1480. X***************************************************************/
  1481. X
  1482. X#if ANSI_C
  1483. Xstatic int
  1484. Xbwb_xerror( char *message )
  1485. X#else
  1486. Xstatic int
  1487. Xbwb_xerror( message )
  1488. X   char *message;
  1489. X#endif
  1490. X   {
  1491. X
  1492. X   bwx_errmes( message );
  1493. X
  1494. X   break_handler();
  1495. X
  1496. X   return FALSE;
  1497. X   }
  1498. X
  1499. X/***************************************************************
  1500. X
  1501. X        FUNCTION:       bwb_esetovar()
  1502. X
  1503. X        DESCRIPTION:    This function converts the value in expression
  1504. X            stack 'e' to a bwBASIC variable structure.
  1505. X
  1506. X***************************************************************/
  1507. X
  1508. X#if ANSI_C
  1509. Xstatic struct bwb_variable *
  1510. Xbwb_esetovar( struct exp_ese *e )
  1511. X#else
  1512. Xstatic struct bwb_variable *
  1513. Xbwb_esetovar( e )
  1514. X   struct exp_ese *e;
  1515. X#endif
  1516. X   {
  1517. X   static struct bwb_variable b;
  1518. X
  1519. X   var_make( &b, e->type );
  1520. X
  1521. X   switch( e->type )
  1522. X      {
  1523. X      case STRING:
  1524. X         str_btob( var_findsval( &b, b.array_pos ), exp_getsval( e ) );
  1525. X         break;
  1526. X      default:
  1527. X         * var_findnval( &b, b.array_pos ) = e->nval;
  1528. X         break;
  1529. X      }
  1530. X
  1531. X   return &b;
  1532. X
  1533. X   }
  1534. X
  1535. X#if COMMON_CMDS
  1536. X
  1537. X/***************************************************************
  1538. X
  1539. X        FUNCTION:       bwb_write()
  1540. X
  1541. X    DESCRIPTION:    This C function implements the BASIC WRITE
  1542. X            command.
  1543. X
  1544. X    SYNTAX:        WRITE [# device-number,] element [, element ]....
  1545. X
  1546. X***************************************************************/
  1547. X
  1548. X#if ANSI_C
  1549. Xstruct bwb_line *
  1550. Xbwb_write( struct bwb_line *l )
  1551. X#else
  1552. Xstruct bwb_line *
  1553. Xbwb_write( l )
  1554. X   struct bwb_line *l;
  1555. X#endif
  1556. X   {
  1557. X   struct exp_ese *e;
  1558. X   int req_devnumber;
  1559. X   int pos;
  1560. X   FILE *fp;
  1561. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1562. X   int loop;
  1563. X   static struct bwb_variable nvar;
  1564. X   static int init = FALSE;
  1565. X
  1566. X   /* initialize variable if necessary */
  1567. X
  1568. X   if ( init == FALSE )
  1569. X      {
  1570. X      init = TRUE;
  1571. X      var_make( &nvar, NUMBER );
  1572. X      }
  1573. X
  1574. X   /* detect device number if present */
  1575. X
  1576. X   adv_ws( l->buffer, &( l->position ) );
  1577. X
  1578. X   if ( l->buffer[ l->position ] == '#' )
  1579. X      {
  1580. X      ++( l->position );
  1581. X      adv_element( l->buffer, &( l->position ), tbuf );
  1582. X      pos = 0;
  1583. X      e = bwb_exp( tbuf, FALSE, &pos );
  1584. X      adv_ws( l->buffer, &( l->position ) );
  1585. X      if ( l->buffer[ l->position ] == ',' )
  1586. X         {
  1587. X         ++( l->position );
  1588. X         }
  1589. X      else
  1590. X         {
  1591. X#if PROG_ERRORS
  1592. X         bwb_error( "in bwb_write(): no comma after#n" );
  1593. X#else
  1594. X         bwb_error( err_syntax );
  1595. X#endif
  1596. X         return bwb_zline( l );
  1597. X         }
  1598. X
  1599. X      req_devnumber = (int) exp_getnval( e );
  1600. X
  1601. X      /* check the requested device number */
  1602. X
  1603. X      if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1604. X         {
  1605. X#if PROG_ERRORS
  1606. X         bwb_error( "in bwb_write(): Requested device number is out of range." );
  1607. X#else
  1608. X         bwb_error( err_devnum );
  1609. X#endif
  1610. X         return bwb_zline( l );
  1611. X         }
  1612. X
  1613. X      if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  1614. X         ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ))
  1615. X         {
  1616. X#if PROG_ERRORS
  1617. X         bwb_error( "in bwb_write(): Requested device number is not open." );
  1618. X#else
  1619. X         bwb_error( err_devnum );
  1620. X#endif
  1621. X
  1622. X         return bwb_zline( l );
  1623. X         }
  1624. X
  1625. X      if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT )
  1626. X         {
  1627. X#if PROG_ERRORS
  1628. X         bwb_error( "in bwb_write(): Requested device is not open for OUTPUT." );
  1629. X#else
  1630. X         bwb_error( err_devnum );
  1631. X#endif
  1632. X
  1633. X         return bwb_zline( l );
  1634. X         }
  1635. X
  1636. X#if INTENSIVE_DEBUG
  1637. X      sprintf( bwb_ebuf, "in bwb_write(): device number is <%d>",
  1638. X         req_devnumber );
  1639. X      bwb_debug( bwb_ebuf );
  1640. X#endif
  1641. X
  1642. X      /* look up the requested device in the device table */
  1643. X
  1644. X      fp = dev_table[ req_devnumber ].cfp;
  1645. X
  1646. X      }
  1647. X
  1648. X   else
  1649. X      {
  1650. X      fp = stdout;
  1651. X      }
  1652. X
  1653. X   /* be sure there is an element to print */
  1654. X
  1655. X   adv_ws( l->buffer, &( l->position ) );
  1656. X   loop = TRUE;
  1657. X   switch( l->buffer[ l->position ] )
  1658. X      {
  1659. X      case '\n':
  1660. X      case '\r':
  1661. X      case '\0':
  1662. X      case ':':
  1663. X         loop = FALSE;
  1664. X         break;
  1665. X      }
  1666. X
  1667. X   /* loop through elements */
  1668. X
  1669. X   while ( loop == TRUE )
  1670. X      {
  1671. X
  1672. X      /* get the next element */
  1673. X
  1674. X      e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1675. X
  1676. X      /* perform type-specific output */
  1677. X
  1678. X      switch( e->type )
  1679. X         {
  1680. X         case STRING:
  1681. X            xputc( fp, '\"' );
  1682. X            str_btoc( tbuf, exp_getsval( e ) );
  1683. X            prn_xprintf( fp, tbuf );
  1684. X            xputc( fp, '\"' );
  1685. X#if INTENSIVE_DEBUG
  1686. X            sprintf( bwb_ebuf, "in bwb_write(): output string element <\"%s\">",
  1687. X               tbuf );
  1688. X            bwb_debug( bwb_ebuf );
  1689. X#endif
  1690. X            break;
  1691. X         default:
  1692. X            * var_findnval( &nvar, nvar.array_pos ) =
  1693. X               exp_getnval( e );
  1694. X#if NUMBER_DOUBLE
  1695. X            sprintf( tbuf, " %.*lf", prn_precision( &nvar ),
  1696. X               var_getnval( &nvar ) );
  1697. X#else
  1698. X            sprintf( tbuf, " %.*f", prn_precision( &nvar ),
  1699. X               var_getnval( &nvar ) );
  1700. X#endif
  1701. X            prn_xprintf( fp, tbuf );
  1702. X#if INTENSIVE_DEBUG
  1703. X            sprintf( bwb_ebuf, "in bwb_write(): output numerical element <%s>",
  1704. X               tbuf );
  1705. X            bwb_debug( bwb_ebuf );
  1706. X#endif
  1707. X            break;
  1708. X         }                /* end of case for type-specific output */
  1709. X
  1710. X      /* seek a comma at end of element */
  1711. X
  1712. X      adv_ws( l->buffer, &( l->position ) );
  1713. X      if ( l->buffer[ l->position ] == ',' )
  1714. X         {
  1715. X         xputc( fp, ',' );
  1716. X         ++( l->position );
  1717. X         }
  1718. X
  1719. X      /* no comma: end the loop */
  1720. X
  1721. X      else
  1722. X         {
  1723. X         loop = FALSE;
  1724. X         }
  1725. X
  1726. X      }                    /* end of loop through elements */
  1727. X
  1728. X   /* print LF */
  1729. X
  1730. X   xputc( fp, '\n' );
  1731. X
  1732. X   /* return */
  1733. X
  1734. X   return bwb_zline( l );
  1735. X   }
  1736. X
  1737. X#endif
  1738. X
  1739. END_OF_FILE
  1740.   if test 38372 -ne `wc -c <'bwbasic-2.10/bwb_prn.c'`; then
  1741.     echo shar: \"'bwbasic-2.10/bwb_prn.c'\" unpacked with wrong size!
  1742.   fi
  1743.   # end of 'bwbasic-2.10/bwb_prn.c'
  1744. fi
  1745. if test -f 'bwbasic-2.10/bwb_tcc.c' -a "${1}" != "-c" ; then 
  1746.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwb_tcc.c'\"
  1747. else
  1748.   echo shar: Extracting \"'bwbasic-2.10/bwb_tcc.c'\" \(167 characters\)
  1749.   sed "s/^X//" >'bwbasic-2.10/bwb_tcc.c' <<'END_OF_FILE'
  1750. X/* This is for Borland Turbo C++ only: it requests the linker to
  1751. X   establish a larger-than-usual stack of 8192 bytes for bwBASIC */
  1752. X
  1753. Xextern unsigned _stklen = 8192U;
  1754. END_OF_FILE
  1755.   if test 167 -ne `wc -c <'bwbasic-2.10/bwb_tcc.c'`; then
  1756.     echo shar: \"'bwbasic-2.10/bwb_tcc.c'\" unpacked with wrong size!
  1757.   fi
  1758.   # end of 'bwbasic-2.10/bwb_tcc.c'
  1759. fi
  1760. if test -f 'bwbasic-2.10/bwbtest/abs.bas' -a "${1}" != "-c" ; then 
  1761.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/abs.bas'\"
  1762. else
  1763.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/abs.bas'\" \(154 characters\)
  1764.   sed "s/^X//" >'bwbasic-2.10/bwbtest/abs.bas' <<'END_OF_FILE'
  1765. X10 rem ABS.BAS -- Test ABS() function
  1766. X20 X = -1.23456789
  1767. X30 ABSX = ABS( X )
  1768. X40 print "The absolute value of "; X; " is"; ABSX
  1769. X50 print "Is that correct?"
  1770. END_OF_FILE
  1771.   if test 154 -ne `wc -c <'bwbasic-2.10/bwbtest/abs.bas'`; then
  1772.     echo shar: \"'bwbasic-2.10/bwbtest/abs.bas'\" unpacked with wrong size!
  1773.   fi
  1774.   # end of 'bwbasic-2.10/bwbtest/abs.bas'
  1775. fi
  1776. if test -f 'bwbasic-2.10/bwbtest/chain1.bas' -a "${1}" != "-c" ; then 
  1777.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/chain1.bas'\"
  1778. else
  1779.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/chain1.bas'\" \(177 characters\)
  1780.   sed "s/^X//" >'bwbasic-2.10/bwbtest/chain1.bas' <<'END_OF_FILE'
  1781. XREM CHAIN1.BAS
  1782. Xprint "This is program CHAIN1.BAS"
  1783. XX = 5.6789
  1784. Xcommon X
  1785. Xprint "The value of X is";X
  1786. Xprint "We shall no pass execution to program CHAIN2.BAS..."
  1787. Xchain "chain2.bas"
  1788. END_OF_FILE
  1789.   if test 177 -ne `wc -c <'bwbasic-2.10/bwbtest/chain1.bas'`; then
  1790.     echo shar: \"'bwbasic-2.10/bwbtest/chain1.bas'\" unpacked with wrong size!
  1791.   fi
  1792.   # end of 'bwbasic-2.10/bwbtest/chain1.bas'
  1793. fi
  1794. if test -f 'bwbasic-2.10/bwbtest/chain2.bas' -a "${1}" != "-c" ; then 
  1795.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/chain2.bas'\"
  1796. else
  1797.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/chain2.bas'\" \(121 characters\)
  1798.   sed "s/^X//" >'bwbasic-2.10/bwbtest/chain2.bas' <<'END_OF_FILE'
  1799. XREM CHAIN2.BAS
  1800. Xprint "This is program CHAIN2.BAS"
  1801. Xprint "The value of X is now";X
  1802. Xprint "This concludes our CHAIN test."
  1803. END_OF_FILE
  1804.   if test 121 -ne `wc -c <'bwbasic-2.10/bwbtest/chain2.bas'`; then
  1805.     echo shar: \"'bwbasic-2.10/bwbtest/chain2.bas'\" unpacked with wrong size!
  1806.   fi
  1807.   # end of 'bwbasic-2.10/bwbtest/chain2.bas'
  1808. fi
  1809. if test -f 'bwbasic-2.10/bwbtest/dim.bas' -a "${1}" != "-c" ; then 
  1810.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/dim.bas'\"
  1811. else
  1812.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/dim.bas'\" \(121 characters\)
  1813.   sed "s/^X//" >'bwbasic-2.10/bwbtest/dim.bas' <<'END_OF_FILE'
  1814. X10 DIM n(5) 
  1815. X20 FOR i = 0 to 5 
  1816. X30 LET n(i) = i + 2 
  1817. X40 PRINT "The value at position ";i;" is ";n(i) 
  1818. X50 NEXT i 
  1819. X60 END 
  1820. END_OF_FILE
  1821.   if test 121 -ne `wc -c <'bwbasic-2.10/bwbtest/dim.bas'`; then
  1822.     echo shar: \"'bwbasic-2.10/bwbtest/dim.bas'\" unpacked with wrong size!
  1823.   fi
  1824.   # end of 'bwbasic-2.10/bwbtest/dim.bas'
  1825. fi
  1826. if test -f 'bwbasic-2.10/bwbtest/doloop.bas' -a "${1}" != "-c" ; then 
  1827.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/doloop.bas'\"
  1828. else
  1829.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/doloop.bas'\" \(95 characters\)
  1830.   sed "s/^X//" >'bwbasic-2.10/bwbtest/doloop.bas' <<'END_OF_FILE'
  1831. X10 i = 0
  1832. X20 do
  1833. X30 i = i + 1
  1834. X40 print "i is";i
  1835. X50 if i > 12 then exit do
  1836. X60 loop
  1837. X70 print "End"
  1838. END_OF_FILE
  1839.   if test 95 -ne `wc -c <'bwbasic-2.10/bwbtest/doloop.bas'`; then
  1840.     echo shar: \"'bwbasic-2.10/bwbtest/doloop.bas'\" unpacked with wrong size!
  1841.   fi
  1842.   # end of 'bwbasic-2.10/bwbtest/doloop.bas'
  1843. fi
  1844. if test -f 'bwbasic-2.10/bwbtest/err.bas' -a "${1}" != "-c" ; then 
  1845.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/err.bas'\"
  1846. else
  1847.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/err.bas'\" \(33 characters\)
  1848.   sed "s/^X//" >'bwbasic-2.10/bwbtest/err.bas' <<'END_OF_FILE'
  1849. X10 dim n(5)
  1850. X20 print n(7)
  1851. X30 end
  1852. END_OF_FILE
  1853.   if test 33 -ne `wc -c <'bwbasic-2.10/bwbtest/err.bas'`; then
  1854.     echo shar: \"'bwbasic-2.10/bwbtest/err.bas'\" unpacked with wrong size!
  1855.   fi
  1856.   # end of 'bwbasic-2.10/bwbtest/err.bas'
  1857. fi
  1858. if test -f 'bwbasic-2.10/bwbtest/ifline.bas' -a "${1}" != "-c" ; then 
  1859.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/ifline.bas'\"
  1860. else
  1861.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/ifline.bas'\" \(144 characters\)
  1862.   sed "s/^X//" >'bwbasic-2.10/bwbtest/ifline.bas' <<'END_OF_FILE'
  1863. X10 rem test if then followed by line number
  1864. X20 if 5 = 5 then 80
  1865. X30 print "The statement failed"
  1866. X40 stop
  1867. X80 print "The program succeeded"
  1868. X90 end
  1869. END_OF_FILE
  1870.   if test 144 -ne `wc -c <'bwbasic-2.10/bwbtest/ifline.bas'`; then
  1871.     echo shar: \"'bwbasic-2.10/bwbtest/ifline.bas'\" unpacked with wrong size!
  1872.   fi
  1873.   # end of 'bwbasic-2.10/bwbtest/ifline.bas'
  1874. fi
  1875. if test -f 'bwbasic-2.10/bwbtest/lof.bas' -a "${1}" != "-c" ; then 
  1876.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/lof.bas'\"
  1877. else
  1878.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/lof.bas'\" \(137 characters\)
  1879.   sed "s/^X//" >'bwbasic-2.10/bwbtest/lof.bas' <<'END_OF_FILE'
  1880. X10 print "Test LOF() Function"
  1881. X20 input "Filename";F$
  1882. X30 open "i", 1, F$
  1883. X40 print "Length of file ";F$;" is ";LOF(1);" bytes"
  1884. X50 close 1
  1885. END_OF_FILE
  1886.   if test 137 -ne `wc -c <'bwbasic-2.10/bwbtest/lof.bas'`; then
  1887.     echo shar: \"'bwbasic-2.10/bwbtest/lof.bas'\" unpacked with wrong size!
  1888.   fi
  1889.   # end of 'bwbasic-2.10/bwbtest/lof.bas'
  1890. fi
  1891. if test -f 'bwbasic-2.10/bwbtest/loopuntl.bas' -a "${1}" != "-c" ; then 
  1892.   echo shar: Will not clobber existing file \"'bwbasic-2.10/bwbtest/loopuntl.bas'\"
  1893. else
  1894.   echo shar: Extracting \"'bwbasic-2.10/bwbtest/loopuntl.bas'\" \(96 characters\)
  1895.   sed "s/^X//" >'bwbasic-2.10/bwbtest/loopuntl.bas' <<'END_OF_FILE'
  1896. X10 rem LOOPUNTL.BAS
  1897. X20 i = 0
  1898. X30 do
  1899. X40 i = i + 1
  1900. X50 print "Value of i is";i
  1901. X60 loop until i > 12
  1902. END_OF_FILE
  1903.   if test 96 -ne `wc -c <'bwbasic-2.10/bwbtest/loopuntl.bas'`; then
  1904.     echo shar: \"'bwbasic-2.10/bwbtest/loopuntl.bas'\" unpacked with wrong size!
  1905.   fi
  1906.   # end of 'bwbasic-2.10/bwbtest/loopuntl.bas'
  1907. fi
  1908. echo shar: End of archive 11 \(of 15\).
  1909. cp /dev/null ark11isdone
  1910. MISSING=""
  1911. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
  1912.     if test ! -f ark${I}isdone ; then
  1913.     MISSING="${MISSING} ${I}"
  1914.     fi
  1915. done
  1916. if test "${MISSING}" = "" ; then
  1917.     echo You have unpacked all 15 archives.
  1918.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1919. else
  1920.     echo You still must unpack the following archives:
  1921.     echo "        " ${MISSING}
  1922. fi
  1923. exit 0
  1924. exit 0 # Just in case...
  1925.