home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / bwbasic / part11 < prev    next >
Encoding:
Text File  |  1992-11-03  |  55.3 KB  |  2,198 lines

  1. Newsgroups: comp.sources.misc
  2. From: tcamp@acpub.duke.edu (Ted A. Campbell)
  3. Subject:  v33i047:  bwbasic - Bywater BASIC interpreter version 1.10, Part11/11
  4. Message-ID: <1992Nov5.041050.21069@sparky.imd.sterling.com>
  5. X-Md4-Signature: a2e48a31078d2522a739b3dfa1c42ac4
  6. Date: Thu, 5 Nov 1992 04:10:50 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tcamp@acpub.duke.edu (Ted A. Campbell)
  10. Posting-number: Volume 33, Issue 47
  11. Archive-name: bwbasic/part11
  12. Environment: ANSI-C
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  bwb_cnd.c bwbasic.c
  19. # Wrapped by kent@sparky on Wed Nov  4 21:34:29 1992
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 11 (of 11)."'
  23. if test -f 'bwb_cnd.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'bwb_cnd.c'\"
  25. else
  26.   echo shar: Extracting \"'bwb_cnd.c'\" \(26951 characters\)
  27.   sed "s/^X//" >'bwb_cnd.c' <<'END_OF_FILE'
  28. X/***************************************************************
  29. X
  30. X        bwb_cnd.c       Conditional Expressions and Commands
  31. X                        for Bywater BASIC Interpreter
  32. X
  33. X                        Copyright (c) 1992, Ted A. Campbell
  34. X
  35. X                        Bywater Software
  36. X                        P. O. Box 4023
  37. X                        Duke Station
  38. X                        Durham, NC  27706
  39. X
  40. X                        email: tcamp@acpub.duke.edu
  41. X
  42. X        Copyright and Permissions Information:
  43. X
  44. X        All U.S. and international copyrights are claimed by the
  45. X        author. The author grants permission to use this code
  46. X        and software based on it under the following conditions:
  47. X        (a) in general, the code and software based upon it may be
  48. X        used by individuals and by non-profit organizations; (b) it
  49. X        may also be utilized by governmental agencies in any country,
  50. X        with the exception of military agencies; (c) the code and/or
  51. X        software based upon it may not be sold for a profit without
  52. X        an explicit and specific permission from the author, except
  53. X        that a minimal fee may be charged for media on which it is
  54. X        copied, and for copying and handling; (d) the code must be
  55. X        distributed in the form in which it has been released by the
  56. X        author; and (e) the code and software based upon it may not
  57. X        be used for illegal activities.
  58. X
  59. X***************************************************************/
  60. X
  61. X#include <stdio.h>
  62. X#include <stdlib.h>
  63. X#include <math.h>
  64. X#include <ctype.h>
  65. X#include <string.h>
  66. X
  67. X#include "bwbasic.h"
  68. X#include "bwb_mes.h"
  69. X
  70. X/* global variables visible to this file only */
  71. X
  72. Xstatic struct bwb_line * ws[ WHILELEVELS ];             /* WHILE stack */
  73. Xint ws_counter = 0;                                     /* WHILE stack counter */
  74. X
  75. Xint fs_counter = 0;                                     /* FOR stack counter */
  76. X
  77. X/* declarations of functions visible to this file only */
  78. X
  79. Xstatic int cnd_thenels( char *buffer, int position, int *then, int *els );
  80. Xstatic int cnd_tostep( char *buffer, int position, int *to, int *step );
  81. Xstatic struct bwb_line *find_wend( struct bwb_line *l );
  82. Xstatic int var_setival( struct bwb_variable *v, int i );
  83. Xstatic int dec_fsc( int level );
  84. X
  85. X/***    IF-THEN-ELSE ***/
  86. X
  87. X/***************************************************************
  88. X
  89. X        FUNCTION:       bwb_if()
  90. X
  91. X        DESCRIPTION:    This function handles the BASIC IF
  92. X                        statement.
  93. X
  94. X***************************************************************/
  95. X
  96. Xstruct bwb_line *
  97. Xbwb_if( struct bwb_line *l )
  98. X   {
  99. X   register int i, n;
  100. X   int then, els;
  101. X   int pos;
  102. X   struct exp_ese *e;
  103. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  104. X   char then_buffer[ MAXSTRINGSIZE + 1 ];    /* hold THEN statement */
  105. X   char elb_buffer[ MAXSTRINGSIZE + 1 ];     /* hold ELSE statement */
  106. X
  107. X   #if INTENSIVE_DEBUG
  108. X   sprintf( bwb_ebuf, "in bwb_if(): entry, line <%d> buffer <%s>",
  109. X      l->number, &( l->buffer[ l->position ] ) );
  110. X   bwb_debug( bwb_ebuf );
  111. X   #endif
  112. X
  113. X   /* Call bwb_exp() to evaluate the condition. This should return
  114. X      with position set to the "THEN" statement */
  115. X
  116. X   e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  117. X
  118. X   #if INTENSIVE_DEBUG
  119. X   sprintf( bwb_ebuf, "in bwb_if(): line <%d> condition returns <%d>",
  120. X      l->number, exp_getival( e ) );
  121. X   bwb_debug( bwb_ebuf );
  122. X   #endif
  123. X
  124. X   /* test for "THEN" and "ELSE" statements */
  125. X
  126. X   cnd_thenels( l->buffer, l->position, &then, &els );
  127. X
  128. X   #if INTENSIVE_DEBUG
  129. X   sprintf( bwb_ebuf, "in bwb_if(): return from cnd_thenelse, line is <%s>", 
  130. X      l->buffer );
  131. X   bwb_debug( bwb_ebuf );
  132. X   #endif
  133. X
  134. X   if ( then != FALSE )
  135. X      {
  136. X      if ( els != FALSE )
  137. X         {
  138. X         then_buffer[ 0 ] = '\0';
  139. X         n = 0;
  140. X         for ( i = (then + 4); i < els; ++i )
  141. X            {
  142. X            then_buffer[ n ] = l->buffer[ i ];
  143. X            ++n;
  144. X            then_buffer[ n ] = '\0';
  145. X            }
  146. X         }
  147. X      else
  148. X         {
  149. X         then_buffer[ 0 ] = '\0';
  150. X         n = 0;
  151. X         for ( i = (then + 4); l->buffer[ i ] != '\0'; ++i )
  152. X            {
  153. X            then_buffer[ n ] = l->buffer[ i ];
  154. X            ++n;
  155. X            then_buffer[ n ] = '\0';
  156. X            }
  157. X         }
  158. X
  159. X      }
  160. X
  161. X   /* test for THEN line-number */
  162. X
  163. X   pos = 0;
  164. X   adv_ws( then_buffer, &pos );
  165. X   adv_element( then_buffer, &pos, tbuf );
  166. X   if ( ( tbuf[ 0 ] >= '0' ) && ( tbuf[ 0 ] <= '9' ))
  167. X      {
  168. X      sprintf( tbuf, "GOSUB %s", then_buffer );
  169. X      strcpy( then_buffer, tbuf );
  170. X      }
  171. X
  172. X   #if INTENSIVE_DEBUG
  173. X   sprintf( bwb_ebuf, "in bwb_if(): THEN statement is <%s>", then_buffer );
  174. X   bwb_debug( bwb_ebuf );
  175. X   #endif
  176. X
  177. X   #if INTENSIVE_DEBUG
  178. X   sprintf( bwb_ebuf, "in bwb_if(): found THEN statement, line is <%s>", 
  179. X      l->buffer );
  180. X   bwb_debug( bwb_ebuf );
  181. X   #endif
  182. X
  183. X   if ( els != FALSE )
  184. X      {
  185. X      elb_buffer[ 0 ] = '\0';
  186. X      n = 0;
  187. X      for ( i = (els + 4); l->buffer[ i ] != '\0'; ++i )
  188. X         {
  189. X         elb_buffer[ n ] = l->buffer[ i ];
  190. X         ++n;
  191. X         elb_buffer[ n ] = '\0';
  192. X         }
  193. X
  194. X      #if INTENSIVE_DEBUG
  195. X      sprintf( bwb_ebuf, "in bwb_if(): ELSE statement is <%s>", elb_buffer );
  196. X      bwb_debug( bwb_ebuf );
  197. X      #endif
  198. X
  199. X      }
  200. X
  201. X   #if INTENSIVE_DEBUG
  202. X   sprintf( bwb_ebuf, "in bwb_if(): searched for ELSE statement, line is <%s>", 
  203. X      l->buffer );
  204. X   bwb_debug( bwb_ebuf );
  205. X   #endif
  206. X
  207. X   /* evaluate and execute */
  208. X
  209. X   if ( exp_getival( e ) != FALSE )
  210. X      {
  211. X      if ( then == FALSE )
  212. X         {
  213. X         #if PROG_ERRORS
  214. X         sprintf( bwb_ebuf, "IF without THEN" );
  215. X         bwb_error( bwb_ebuf );
  216. X         #else
  217. X         bwb_error( err_syntax );
  218. X         #endif
  219. X         }
  220. X      else
  221. X         {
  222. X     #if INTENSIVE_DEBUG
  223. X     sprintf( bwb_ebuf, "in bwb_if(): executing then buffer <%s>",
  224. X        then_buffer );
  225. X     bwb_debug( bwb_ebuf );
  226. X     #endif
  227. X     return cnd_xpline( l, then_buffer );
  228. X     }
  229. X      }
  230. X   else
  231. X      {
  232. X      if ( els != FALSE )
  233. X         {
  234. X     #if INTENSIVE_DEBUG
  235. X     sprintf( bwb_ebuf, "in bwb_if(): executing else buffer <%s>",
  236. X        elb_buffer );
  237. X     bwb_debug( bwb_ebuf );
  238. X     #endif
  239. X     return cnd_xpline( l, elb_buffer );
  240. X     }
  241. X      }
  242. X
  243. X   /* if neither then nor else were found */
  244. X
  245. X   l->next->position = 0;
  246. X   return l->next;
  247. X
  248. X   }
  249. X
  250. X/***************************************************************
  251. X
  252. X        FUNCTION:       cnd_thenelse()
  253. X
  254. X        DESCRIPTION:    This function searches through the
  255. X                        <buffer> beginning at point <position>
  256. X                        and attempts to find positions of THEN
  257. X                        and ELSE statements.
  258. X
  259. X***************************************************************/
  260. X
  261. Xint
  262. Xcnd_thenels( char *buffer, int position, int *then, int *els )
  263. X   {
  264. X   int loop, t_pos, b_pos, p_word;
  265. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  266. X
  267. X   #if INTENSIVE_DEBUG
  268. X   sprintf( bwb_ebuf, "in cnd_thenelse(): entry, line is <%s>", buffer );
  269. X   bwb_debug( bwb_ebuf );
  270. X   #endif
  271. X
  272. X   /* set then and els to FALSE initially */
  273. X
  274. X   *then = *els = FALSE;
  275. X
  276. X   /* loop to find words */
  277. X
  278. X   p_word = b_pos = position;
  279. X   t_pos = 0;
  280. X   tbuf[ 0 ] = '\0';
  281. X   loop = TRUE;
  282. X   while( loop == TRUE )
  283. X      {
  284. X
  285. X      switch( buffer[ b_pos ] )
  286. X         {
  287. X         case '\0':                     /* end of string */
  288. X            return TRUE;
  289. X         case ' ':                      /* whitespace = end of word */
  290. X         case '\t':
  291. X
  292. X            #if INTENSIVE_DEBUG
  293. X            sprintf( bwb_ebuf, "in cnd_thenels(): word is <%s>", tbuf );
  294. X            bwb_debug( bwb_ebuf );
  295. X            #endif
  296. X
  297. X            if ( strncmp( tbuf, "THEN", (size_t) 4 ) == 0 )
  298. X               {
  299. X
  300. X               #if INTENSIVE_DEBUG
  301. X               sprintf( bwb_ebuf, "in cnd_thenels(): THEN found at position <%d>.",
  302. X                  p_word );
  303. X               bwb_debug( bwb_ebuf );
  304. X               sprintf( bwb_ebuf, "in cnd_thenelse(): after THEN, line is <%s>", buffer );
  305. X               bwb_debug( bwb_ebuf );
  306. X               #endif
  307. X
  308. X               *then = p_word;
  309. X               }
  310. X            else if ( strncmp( tbuf, "ELSE", (size_t) 4 ) == 0 )
  311. X               {
  312. X
  313. X               #if INTENSIVE_DEBUG
  314. X               sprintf( bwb_ebuf, "in cnd_thenels(): ELSE found at position <%d>.",
  315. X                  p_word );
  316. X               bwb_debug( bwb_ebuf );
  317. X               sprintf( bwb_ebuf, "in cnd_thenelse(): after ELSE, line is <%s>", buffer );
  318. X               bwb_debug( bwb_ebuf );
  319. X               #endif
  320. X
  321. X               *els = p_word;
  322. X               }
  323. X            ++b_pos;
  324. X            p_word = b_pos;
  325. X            t_pos = 0;
  326. X            tbuf[ 0 ] = '\0';
  327. X            break;
  328. X
  329. X         default:
  330. X            if ( islower( buffer[ b_pos ] ) != FALSE )
  331. X               {
  332. X               tbuf[ t_pos ] = toupper( buffer[ b_pos ] );
  333. X               }
  334. X            else
  335. X               {
  336. X               tbuf[ t_pos ] = buffer[ b_pos ];
  337. X               }
  338. X            ++b_pos;
  339. X            ++t_pos;
  340. X            tbuf[ t_pos ] = '\0';
  341. X            break;
  342. X         }
  343. X
  344. X      }
  345. X
  346. X   #if INTENSIVE_DEBUG
  347. X   sprintf( bwb_ebuf, "in cnd_thenelse(): exit, line is <%s>", buffer );
  348. X   bwb_debug( bwb_ebuf );
  349. X   #endif
  350. X
  351. X   return FALSE;
  352. X
  353. X   }
  354. X
  355. X/***************************************************************
  356. X
  357. X        FUNCTION:       cnd_xpline()
  358. X
  359. X        DESCRIPTION:    This function interprets a portion of a
  360. X                        command line.
  361. X
  362. X***************************************************************/
  363. X
  364. Xstruct bwb_line *
  365. Xcnd_xpline( struct bwb_line *l, char *buffer )
  366. X   {
  367. X   char l_buffer[ MAXSTRINGSIZE + 1 ];
  368. X   struct bwb_line *nl;
  369. X   struct bwb_line *rl;
  370. X
  371. X   if ( ( nl = calloc( 1, sizeof( struct bwb_line ) ) ) == NULL )
  372. X      {
  373. X      bwb_error( err_getmem );
  374. X      return l;
  375. X      }
  376. X
  377. X   strncpy( l_buffer, buffer, MAXSTRINGSIZE );
  378. X
  379. X   nl->marked = FALSE;
  380. X   nl->next = l->next;
  381. X   nl->number = l->number;
  382. X   nl->position = 0;
  383. X   nl->buffer = l_buffer;
  384. X
  385. X   #if INTENSIVE_DEBUG
  386. X   sprintf( bwb_ebuf, "in cnd_xpline(): interpret line portion <%s>",
  387. X      nl->buffer );
  388. X   bwb_debug( bwb_ebuf );
  389. X   #endif
  390. X
  391. X   rl = bwb_xline( nl );
  392. X
  393. X   if ( nl->cmdnum == getcmdnum( "GOTO" ) )
  394. X      {
  395. X      return rl;
  396. X      }
  397. X   
  398. X   else if ( nl->cmdnum == getcmdnum( "GOSUB" ) )
  399. X      {
  400. X      return rl;
  401. X      }
  402. X   
  403. X   else if ( nl->cmdnum == getcmdnum( "RETURN" ) )
  404. X      {
  405. X      #if INTENSIVE_DEBUG
  406. X      sprintf( bwb_ebuf, "in cnd_xpline(): RETURN returning line <%d>",
  407. X         rl->number );
  408. X      bwb_debug( bwb_ebuf );
  409. X      #endif
  410. X
  411. X      l->cmdnum = getcmdnum( "RETURN" );
  412. X      l->marked = FALSE;
  413. X
  414. X      return rl;
  415. X      }
  416. X   
  417. X   /* in all other cases, return the next line after the current one */
  418. X
  419. X   l->next->position = 0;
  420. X   return l->next;
  421. X
  422. X   }
  423. X
  424. X/***    WHILE-WEND ***/
  425. X
  426. X/***************************************************************
  427. X
  428. X        FUNCTION:       bwb_while()
  429. X
  430. X        DESCRIPTION:    This function handles the BASIC WHILE
  431. X                        statement.
  432. X
  433. X***************************************************************/
  434. X
  435. Xstruct bwb_line *
  436. Xbwb_while( struct bwb_line *l )
  437. X   {
  438. X   register int n;
  439. X   struct bwb_line *wendnext;
  440. X   struct exp_ese *e;
  441. X
  442. X   /* find the WEND statement */
  443. X
  444. X   wendnext = find_wend( l );
  445. X   if ( wendnext == NULL )
  446. X      {
  447. X      l->next->position = 0;                           /* error routine has already been called */
  448. X      return l->next;                           /* error routine has already been called */
  449. X      }
  450. X
  451. X   /* call bwb_exp() to interpret the expression */
  452. X
  453. X   e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  454. X
  455. X   if ( exp_getival( e ) == TRUE )
  456. X      {
  457. X      ws[ ws_counter ] = l;
  458. X      ++ws_counter;
  459. X      l->next->position = 0;
  460. X      return l->next;
  461. X      }
  462. X   else
  463. X      {
  464. X      wendnext->position = 0;
  465. X      return wendnext;
  466. X      }
  467. X
  468. X   }
  469. X
  470. X/***************************************************************
  471. X
  472. X        FUNCTION:       bwb_wend()
  473. X
  474. X        DESCRIPTION:    This function handles the BASIC WEND
  475. X                        statement.
  476. X
  477. X***************************************************************/
  478. X
  479. Xstruct bwb_line *
  480. Xbwb_wend( struct bwb_line *l )
  481. X   {
  482. X
  483. X   if ( ws_counter <= 0 )
  484. X      {
  485. X      #if PROG_ERRORS
  486. X      sprintf( bwb_ebuf, "in bwb_wend(): WEND without WHILE" );
  487. X      bwb_error( bwb_ebuf );
  488. X      #else
  489. X      bwb_error( err_syntax  );
  490. X      #endif
  491. X      l->next->position = 0;
  492. X      return l->next;
  493. X      }
  494. X
  495. X   --ws_counter;
  496. X   ws[ ws_counter ]->position = 0;
  497. X   return ws[ ws_counter ];
  498. X   }
  499. X
  500. X/***************************************************************
  501. X
  502. X        FUNCTION:       find_wend()
  503. X
  504. X        DESCRIPTION:    This function searches for a line containing
  505. X                        a WEND statement corresponding to a previous
  506. X                        WHILE statement.
  507. X
  508. X***************************************************************/
  509. X
  510. Xstruct bwb_line *
  511. Xfind_wend( struct bwb_line *l )
  512. X   {
  513. X   struct bwb_line *current;
  514. X   register int w_level;
  515. X   int position;
  516. X
  517. X   w_level = 1;
  518. X   for ( current = l->next; current != &bwb_end; current = current->next )
  519. X      {
  520. X      position = 0;
  521. X      line_start( current->buffer, &position, &( current->lnpos ),
  522. X         &( current->lnum ),
  523. X         &( current->cmdpos ),
  524. X         &( current->cmdnum ),
  525. X         &( current->startpos ) );
  526. X      current->position = current->startpos;
  527. X
  528. X      if ( current->cmdnum > -1 )
  529. X         {
  530. X
  531. X         if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_while )
  532. X            {
  533. X            ++w_level;
  534. X
  535. X            #if INTENSIVE_DEBUG
  536. X            sprintf( bwb_ebuf, "in bwb_wend(): found WHILE at line %d, level %d",
  537. X               current->number, w_level );
  538. X            bwb_debug( bwb_ebuf );
  539. X            #endif
  540. X
  541. X            }
  542. X         else if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_wend )
  543. X            {
  544. X            --w_level;
  545. X
  546. X            #if INTENSIVE_DEBUG
  547. X            sprintf( bwb_ebuf, "in bwb_wend(): found WEND at line %d, level %d",
  548. X               current->number, w_level );
  549. X            bwb_debug( bwb_ebuf );
  550. X            #endif
  551. X
  552. X            if ( w_level == 0 )
  553. X               {
  554. X               return current->next;
  555. X               }
  556. X            }
  557. X         }
  558. X      }
  559. X
  560. X   #if PROG_ERRORS
  561. X   sprintf( bwb_ebuf, "WHILE without WEND" );
  562. X   bwb_error( bwb_ebuf );
  563. X   #else
  564. X   bwb_error( err_syntax  );
  565. X   #endif
  566. X
  567. X   return NULL;
  568. X
  569. X   }
  570. X
  571. X/***    FOR-NEXT ***/
  572. X
  573. X/***************************************************************
  574. X
  575. X        FUNCTION:       bwb_for()
  576. X
  577. X        DESCRIPTION:    This function handles the BASIC FOR
  578. X                        statement.
  579. X
  580. X    LIMITATION:    As implemented here, the NEXT statement
  581. X            must be at the beginning of a program
  582. X            line; a NEXT statement following a colon
  583. X            will not be recognized and may cause the
  584. X            program to hang up.
  585. X
  586. X***************************************************************/
  587. X
  588. Xstruct bwb_line *
  589. Xbwb_for( struct bwb_line *l )
  590. X   {
  591. X   register int n;
  592. X   int e, loop;
  593. X   int to, step, p;
  594. X   struct exp_ese *exp;
  595. X   struct bwb_variable *v;
  596. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  597. X
  598. X   /* get the variable name */
  599. X
  600. X   exp_getvfname( &( l->buffer[ l->startpos ] ), tbuf );
  601. X   v = var_find( tbuf );
  602. X
  603. X   #if INTENSIVE_DEBUG
  604. X   sprintf( bwb_ebuf, "in bwb_for(): variable name <%s>.", v->name );
  605. X   bwb_debug( bwb_ebuf );
  606. X   #endif
  607. X
  608. X   /* increment the FOR stack counter and check it */
  609. X
  610. X   ++fs_counter;                                /* increment the counter */
  611. X   if ( fs_counter >= FORLEVELS )
  612. X      {
  613. X      #if PROG_ERRORS
  614. X      sprintf( bwb_ebuf, "Maximum FOR levels exceeded." );
  615. X      bwb_error( bwb_ebuf );
  616. X      #else
  617. X      bwb_error( err_overflow );
  618. X      #endif
  619. X      l->next->position = 0;
  620. X      return l->next;
  621. X      }
  622. X
  623. X   /* initialize the FOR stack element for this level */
  624. X
  625. X   fs[ fs_counter ].nextline = l;               /* set next line for loop */
  626. X   fs[ fs_counter ].variable = v;            /* set variable */
  627. X   fs[ fs_counter ].step = 1;                   /* set default step */
  628. X   l->position += strlen( tbuf );           /* set current position to end of variable */
  629. X
  630. X   /* at this point one should find an equals sign ('=') */
  631. X
  632. X   loop = TRUE;
  633. X   while( loop == TRUE )
  634. X      {
  635. X      switch( l->buffer[ l->position ] )
  636. X         {
  637. X         case '=':                              /* found equals sign; continue */
  638. X            ++l->position;
  639. X            loop = FALSE;
  640. X            break;
  641. X         case ' ':                              /* whitespace */
  642. X         case '\t':
  643. X            ++l->position;
  644. X            break;
  645. X         default:
  646. X            #if PROG_ERRORS
  647. X            sprintf( bwb_ebuf, "in bwb_for(): failed to find equals sign, buf <%s>",
  648. X               &( l->buffer[ l->position ] ) );
  649. X            bwb_error( bwb_ebuf );
  650. X            #else
  651. X            bwb_error( err_syntax );
  652. X            #endif
  653. X            l->next->position = 0;
  654. X            return l->next;
  655. X         }
  656. X      }
  657. X
  658. X   /* Find the TO and STEP statements */
  659. X
  660. X   cnd_tostep( l->buffer, l->position, &to, &step );
  661. X
  662. X   /* if there is no TO statement, then an error has ocurred */
  663. X
  664. X   if ( to < 1 )
  665. X      {
  666. X      #if PROG_ERRORS
  667. X      sprintf( bwb_ebuf, "FOR statement without TO" );
  668. X      bwb_error( bwb_ebuf );
  669. X      #else
  670. X      bwb_error( err_syntax  );
  671. X      #endif
  672. X      l->next->position = 0;
  673. X      return l->next;
  674. X      }
  675. X
  676. X   /* copy initial value to small buffer and evaluate it */
  677. X
  678. X   tbuf[ 0 ] = '\0';
  679. X   p = 0;
  680. X   for ( n = l->position; n < to; ++n )
  681. X      {
  682. X      tbuf[ p ] = l->buffer[ n ];
  683. X      ++p;
  684. X      ++l->position;
  685. X      tbuf[ p ] = '\0';
  686. X      }
  687. X
  688. X   #if INTENSIVE_DEBUG
  689. X   sprintf( bwb_ebuf, "in bwb_for(): initial value string <%s>",
  690. X      tbuf );
  691. X   bwb_debug( bwb_ebuf );
  692. X   #endif
  693. X
  694. X   p = 0;
  695. X   exp = bwb_exp( tbuf, FALSE, &p );
  696. X   var_setival( fs[ fs_counter ].variable, exp_getival( exp ) );
  697. X
  698. X   #if INTENSIVE_DEBUG
  699. X   sprintf( bwb_ebuf, "in bwb_for(): initial value <%d> pos <%d>",
  700. X      exp_getival( exp ), l->position );
  701. X   bwb_debug( bwb_ebuf );
  702. X   #endif
  703. X
  704. X   /* copy target value to small buffer and evaluate it */
  705. X
  706. X   tbuf[ 0 ] = '\0';
  707. X   p = 0;
  708. X   l->position = to + 2;
  709. X   if ( step < 1 )
  710. X      {
  711. X      e = strlen( l->buffer );
  712. X      }
  713. X   else
  714. X      {
  715. X      e = step - 1;
  716. X      }
  717. X
  718. X   loop = TRUE;
  719. X   n = l->position;
  720. X   while( loop == TRUE )
  721. X      {
  722. X      tbuf[ p ] = l->buffer[ n ];
  723. X      ++p;
  724. X      ++l->position;
  725. X      tbuf[ p ] = '\0';
  726. X
  727. X      if ( n >= e )
  728. X          {
  729. X          loop = FALSE;
  730. X          }
  731. X
  732. X      ++n;
  733. X
  734. X      if ( l->buffer[ n ] == ':' )
  735. X         {
  736. X         loop = FALSE;
  737. X         }
  738. X
  739. X      }
  740. X
  741. X   #if INTENSIVE_DEBUG
  742. X   sprintf( bwb_ebuf, "in bwb_for(): target value string <%s>",
  743. X      tbuf );
  744. X   bwb_debug( bwb_ebuf );
  745. X   #endif
  746. X
  747. X   p = 0;
  748. X   exp = bwb_exp( tbuf, FALSE, &p );
  749. X   fs[ fs_counter ].target = exp_getival( exp );
  750. X
  751. X   #if INTENSIVE_DEBUG
  752. X   sprintf( bwb_ebuf, "in bwb_for(): target value <%d> pos <%d>",
  753. X      exp_getival( exp ), l->position );
  754. X   bwb_debug( bwb_ebuf );
  755. X   #endif
  756. X
  757. X   /* If there is a STEP statement, copy it to the small buffer
  758. X      and evaluate it */
  759. X
  760. X   if ( step > 1 )
  761. X      {
  762. X      tbuf[ 0 ] = '\0';
  763. X      p = 0;
  764. X      l->position = step + 4;
  765. X
  766. X      for ( n = l->position; n < strlen( l->buffer ); ++n )
  767. X         {
  768. X         tbuf[ p ] = l->buffer[ n ];
  769. X         ++p;
  770. X         ++l->position;
  771. X         tbuf[ p ] = '\0';
  772. X         }
  773. X
  774. X      #if INTENSIVE_DEBUG
  775. X      sprintf( bwb_ebuf, "in bwb_for(): step value string <%s>",
  776. X         tbuf );
  777. X      bwb_debug( bwb_ebuf );
  778. X      #endif
  779. X
  780. X      p = 0;
  781. X      exp = bwb_exp( tbuf, FALSE, &p );
  782. X      fs[ fs_counter ].step = exp_getival( exp );
  783. X
  784. X      #if INTENSIVE_DEBUG
  785. X      sprintf( bwb_ebuf, "in bwb_for(): step value <%d>",
  786. X         exp_getival( exp ) );
  787. X      bwb_debug( bwb_ebuf );
  788. X      #endif
  789. X
  790. X      }
  791. X
  792. X   /* set position in current line for reset */
  793. X
  794. X   fs[ fs_counter ].position = l->position;     /* position for reset */
  795. X
  796. X   #if INTENSIVE_DEBUG
  797. X   sprintf( bwb_ebuf, "in bwb_for(): ready to exit, position <%d>",
  798. X      l->position );
  799. X   bwb_debug( bwb_ebuf );
  800. X   #endif
  801. X
  802. X   /* proceed with processing */
  803. X
  804. X   l->next->position = 0;
  805. X   return l->next;
  806. X
  807. X   }
  808. X
  809. X/***************************************************************
  810. X
  811. X        FUNCTION:       bwb_next()
  812. X
  813. X        DESCRIPTION:    This function handles the BASIC NEXT
  814. X                        statement.
  815. X
  816. X    LIMITATION:    As implemented here, the NEXT statement
  817. X            must be at the beginning of a program
  818. X            line; a NEXT statement following a colon
  819. X            will not be recognized and may cause the
  820. X            program to hang up.
  821. X
  822. X***************************************************************/
  823. X
  824. Xstruct bwb_line *
  825. Xbwb_next( struct bwb_line *l )
  826. X   {
  827. X   register int c;
  828. X   int stack_level;
  829. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  830. X
  831. X   /* Check the integrity of the FOR stack */
  832. X
  833. X   if ( fs_counter <= 0 )
  834. X      {
  835. X      #if PROG_ERRORS
  836. X      sprintf( bwb_ebuf, "NEXT without FOR" );
  837. X      bwb_error( bwb_ebuf );
  838. X      #else
  839. X      bwb_error( err_nf );
  840. X      #endif
  841. X      l->next->position = 0;
  842. X      return l->next;
  843. X      }
  844. X
  845. X   /* Check for argument */
  846. X
  847. X   adv_ws( l->buffer, &( l->position ) );
  848. X   switch( l->buffer[ l->position ] )
  849. X      {
  850. X      case '\0':
  851. X      case '\n':
  852. X      case '\r':
  853. X      case ':':
  854. X         #if PROG_ERRORS
  855. X         sprintf( bwb_ebuf, "at line %d: NEXT: no variable specified.",
  856. X            l->number );
  857. X         bwb_error( bwb_ebuf );
  858. X         #else
  859. X         bwb_error( err_syntax );
  860. X         #endif
  861. X         l->next->position = 0;
  862. X         return l->next;
  863. X      default:
  864. X         break;
  865. X      }
  866. X
  867. X   adv_element( l->buffer, &( l->position ), tbuf );
  868. X
  869. X   stack_level = 0;
  870. X   for ( c = 1; c <= fs_counter; ++c )
  871. X      {
  872. X      if ( strcmp( tbuf, fs[ c ].variable->name ) == 0 )
  873. X         {
  874. X         stack_level = c;
  875. X         }
  876. X      }
  877. X   if ( stack_level == 0  )
  878. X      {
  879. X      #if PROG_ERRORS
  880. X      sprintf( bwb_ebuf, "NEXT has invalid variable" );
  881. X      bwb_error( bwb_ebuf );
  882. X      #else
  883. X      bwb_error( err_syntax );
  884. X      #endif
  885. X      l->next->position = 0;
  886. X      return l->next;
  887. X      }
  888. X
  889. X   /* we now have a valid stack level; now increment the variable value */
  890. X
  891. X   var_setival( fs[ stack_level ].variable,
  892. X      var_getival( fs[ stack_level ].variable ) + fs[ stack_level ].step );
  893. X
  894. X   #if INTENSIVE_DEBUG
  895. X   sprintf( bwb_ebuf, "in bwb_next(): variable <%s> is <%d>",
  896. X      fs[ stack_level ].variable->name,
  897. X      var_getival( fs[ stack_level ].variable ) );
  898. X   bwb_debug( bwb_ebuf );
  899. X   #endif
  900. X
  901. X   /* check for completion of the loop */
  902. X
  903. X   if ( fs[ stack_level ].step > 0 )            /* if step is positive */
  904. X      {
  905. X      if ( var_getival( fs[ stack_level ].variable )
  906. X         > fs[ stack_level ].target )
  907. X         {
  908. X
  909. X         /* decrement the FOR stack counter and return */
  910. X
  911. X         dec_fsc( stack_level );
  912. X         l->next->position = 0;
  913. X         return l->next;
  914. X         }
  915. X      }
  916. X   else                                         /* if step is negative */
  917. X      {
  918. X      if ( var_getival( fs[ stack_level ].variable )
  919. X         < fs[ stack_level ].target )
  920. X         {
  921. X
  922. X         /* decrement the FOR stack counter and return */
  923. X
  924. X         dec_fsc( stack_level );
  925. X         l->next->position = 0;
  926. X         return l->next;
  927. X         }
  928. X      }
  929. X
  930. X   /* Target not reached: return to the top of the FOR loop */
  931. X
  932. X   fs[ stack_level ].nextline->position = fs[ stack_level ].position;
  933. X
  934. X   #if INTENSIVE_DEBUG
  935. X   sprintf( bwb_ebuf, "in bwb_next(): return to line <%d> position <%d> char <%c>",
  936. X      fs[ stack_level ].nextline->number,
  937. X      fs[ stack_level ].nextline->position,
  938. X      fs[ stack_level ].nextline->buffer[ fs[ stack_level ].nextline->position ] );
  939. X   bwb_debug( bwb_ebuf );
  940. X   #endif
  941. X
  942. X   return fs[ stack_level ].nextline;
  943. X
  944. X   }
  945. X
  946. X/***************************************************************
  947. X
  948. X        FUNCTION:       cnd_tostep()
  949. X
  950. X        DESCRIPTION:    This function searches through the
  951. X                        <buffer> beginning at point <position>
  952. X                        and attempts to find positions of TO
  953. X                        and STEP statements.
  954. X
  955. X***************************************************************/
  956. X
  957. Xint
  958. Xcnd_tostep( char *buffer, int position, int *to, int *step )
  959. X   {
  960. X   int loop, t_pos, b_pos, p_word;
  961. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  962. X
  963. X   /* set then and els to FALSE initially */
  964. X
  965. X   *to = *step = FALSE;
  966. X
  967. X   /* loop to find words */
  968. X
  969. X   p_word = b_pos = position;
  970. X   t_pos = 0;
  971. X   tbuf[ 0 ] = '\0';
  972. X   loop = TRUE;
  973. X   while ( loop == TRUE )
  974. X      {
  975. X
  976. X      switch( buffer[ b_pos ] )
  977. X         {
  978. X         case '\0':                     /* end of string */
  979. X         case ':':            /* end of line segment */
  980. X            return TRUE;
  981. X         case ' ':                      /* whitespace = end of word */
  982. X         case '\t':
  983. X
  984. X            #if INTENSIVE_DEBUG
  985. X            sprintf( bwb_ebuf, "in cnd_tostep(): word is <%s>", tbuf );
  986. X            bwb_debug( bwb_ebuf );
  987. X            #endif
  988. X
  989. X            if ( strncmp( tbuf, "TO", (size_t) 2 ) == 0 )
  990. X               {
  991. X
  992. X               #if INTENSIVE_DEBUG
  993. X               sprintf( bwb_ebuf, "in cnd_tostep(): TO found at position <%d>.",
  994. X                  p_word );
  995. X               bwb_debug( bwb_ebuf );
  996. X               #endif
  997. X
  998. X               *to = p_word;
  999. X               }
  1000. X            else if ( strncmp( tbuf, "STEP", (size_t) 4 ) == 0 )
  1001. X               {
  1002. X
  1003. X               #if INTENSIVE_DEBUG
  1004. X               sprintf( bwb_ebuf, "in cnd_tostep(): STEP found at position <%d>.",
  1005. X                  p_word );
  1006. X               bwb_debug( bwb_ebuf );
  1007. X               #endif
  1008. X
  1009. X               *step = p_word;
  1010. X               }
  1011. X            ++b_pos;
  1012. X            p_word = b_pos;
  1013. X            t_pos = 0;
  1014. X            tbuf[ 0 ] = '\0';
  1015. X            break;
  1016. X
  1017. X         default:
  1018. X            if ( islower( buffer[ b_pos ] ) != FALSE )
  1019. X               {
  1020. X               tbuf[ t_pos ] = toupper( buffer[ b_pos ] );
  1021. X               }
  1022. X            else
  1023. X               {
  1024. X               tbuf[ t_pos ] = buffer[ b_pos ];
  1025. X               }
  1026. X            ++b_pos;
  1027. X            ++t_pos;
  1028. X            tbuf[ t_pos ] = '\0';
  1029. X            break;
  1030. X         }
  1031. X
  1032. X      }
  1033. X
  1034. X   return TRUE;
  1035. X
  1036. X   }
  1037. X
  1038. Xint
  1039. Xvar_setival( struct bwb_variable *v, int i )
  1040. X   {
  1041. X
  1042. X   switch( v->type )
  1043. X      {
  1044. X      case INTEGER:
  1045. X         * var_findival( v, v->array_pos ) = i;
  1046. X         break;
  1047. X      case DOUBLE:
  1048. X         * var_finddval( v, v->array_pos ) = (double) i;
  1049. X         break;
  1050. X      case SINGLE:
  1051. X         * var_findfval( v, v->array_pos ) = (float) i;
  1052. X         break;
  1053. X      default:
  1054. X         #if INTENSIVE_DEBUG
  1055. X         sprintf( bwb_ebuf, "in var_setival(): variable <%s> is not a number",
  1056. X            v->name );
  1057. X         bwb_error( bwb_ebuf );
  1058. X         #else
  1059. X         bwb_error( err_mismatch );
  1060. X         #endif
  1061. X      }
  1062. X
  1063. X   /* successful assignment */
  1064. X
  1065. X   return TRUE;
  1066. X
  1067. X   }
  1068. X
  1069. Xint
  1070. Xdec_fsc( int level )
  1071. X   {
  1072. X   register int l;
  1073. X
  1074. X   --fs_counter;
  1075. X   if ( fs_counter < 0 )
  1076. X      {
  1077. X      fs_counter = 0;
  1078. X      #if PROG_ERRORS
  1079. X      sprintf( bwb_ebuf, "FOR stack counter decremented below 0." );
  1080. X      bwb_error( bwb_ebuf );
  1081. X      #else
  1082. X      bwb_error( err_overflow );
  1083. X      #endif
  1084. X      return FALSE;
  1085. X      }
  1086. X
  1087. X   /* pull down the FOR stack if necessary */
  1088. X
  1089. X   l = level;
  1090. X   while( l <= fs_counter )
  1091. X      {
  1092. X      memcpy( &( fs[ l ] ), &( fs[ l + 1 ] ), sizeof( struct fse ) );
  1093. X      }
  1094. X
  1095. X   /* return */
  1096. X
  1097. X   return TRUE;
  1098. X
  1099. X   }
  1100. X
  1101. END_OF_FILE
  1102.   if test 26951 -ne `wc -c <'bwb_cnd.c'`; then
  1103.     echo shar: \"'bwb_cnd.c'\" unpacked with wrong size!
  1104.   fi
  1105.   # end of 'bwb_cnd.c'
  1106. fi
  1107. if test -f 'bwbasic.c' -a "${1}" != "-c" ; then 
  1108.   echo shar: Will not clobber existing file \"'bwbasic.c'\"
  1109. else
  1110.   echo shar: Extracting \"'bwbasic.c'\" \(25417 characters\)
  1111.   sed "s/^X//" >'bwbasic.c' <<'END_OF_FILE'
  1112. X/***************************************************************
  1113. X
  1114. X        bwbasic.c       Main Program File
  1115. X                        for Bywater BASIC Interpreter
  1116. X
  1117. X                        Copyright (c) 1992, Ted A. Campbell
  1118. X
  1119. X            "I was no programmer, neither was I a
  1120. X            programmer's son; but I was an herdman
  1121. X            and a gatherer of sycomore fruit."
  1122. X                 - Amos 7:14b AV, slightly adapted
  1123. X
  1124. X                        Bywater Software
  1125. X                        P. O. Box 4023
  1126. X                        Duke Station
  1127. X                        Durham, NC  27706
  1128. X
  1129. X                        email: tcamp@acpub.duke.edu
  1130. X
  1131. X        Copyright and Permissions Information:
  1132. X
  1133. X        All U.S. and international copyrights are claimed by the
  1134. X        author. The author grants permission to use this code
  1135. X        and software based on it under the following conditions:
  1136. X        (a) in general, the code and software based upon it may be
  1137. X        used by individuals and by non-profit organizations; (b) it
  1138. X        may also be utilized by governmental agencies in any country,
  1139. X        with the exception of military agencies; (c) the code and/or
  1140. X        software based upon it may not be sold for a profit without
  1141. X        an explicit and specific permission from the author, except
  1142. X        that a minimal fee may be charged for media on which it is
  1143. X        copied, and for copying and handling; (d) the code must be
  1144. X        distributed in the form in which it has been released by the
  1145. X        author; and (e) the code and software based upon it may not
  1146. X        be used for illegal activities.
  1147. X
  1148. X***************************************************************/
  1149. X
  1150. X#include <stdio.h>
  1151. X#include <stdlib.h>
  1152. X#include <ctype.h>
  1153. X#include <string.h>
  1154. X#include <math.h>
  1155. X#include <signal.h>
  1156. X#include <setjmp.h>
  1157. X
  1158. X#include "bwbasic.h"
  1159. X#include "bwb_mes.h"
  1160. X
  1161. Xchar bwb_progfile[ MAXARGSIZE ];
  1162. Xstruct bwb_line bwb_start, bwb_end;
  1163. Xchar *bwb_ebuf;                /* error buffer */
  1164. Xstatic char *read_line;
  1165. Xint bwb_trace = FALSE;
  1166. Xint bwb_number = 0;
  1167. Xstruct bwb_line *bwb_l;
  1168. X
  1169. Xstruct xtxtsl
  1170. X   {
  1171. X   int  position;
  1172. X   struct bwb_line l;
  1173. X   };
  1174. X
  1175. Xstruct xtxtsl *xtxts;                /* eXecute TeXT stack */
  1176. Xstruct exp_ese *exp_es;            /* expression stack */
  1177. Xstruct ufsel *ufs;                  /* user function stack */
  1178. Xstruct fse *fs;                         /* FOR stack */
  1179. X
  1180. Xint xtxtsc = -1;                        /* eXecute TeXT stack counter */
  1181. X
  1182. XFILE *errfdevice;                       /* output device for error messages */
  1183. Xstatic jmp_buf mark;
  1184. Xstatic int program_run = FALSE;        /* has the command-line program ben run? */
  1185. X
  1186. X/* Prototypes for functions visible only to this file */
  1187. X
  1188. X#if COMMAND_SHELL
  1189. Xextern int bwb_shell( struct bwb_line *l );
  1190. X#endif
  1191. X
  1192. Xextern int is_ln( char *buffer );
  1193. X
  1194. X/***************************************************************
  1195. X
  1196. X        FUNCTION:       main()
  1197. X
  1198. X        DESCRIPTION:    As in any C program, main() is the basic
  1199. X                        function from which the rest of the
  1200. X                        program is called.
  1201. X
  1202. X    PRAYER:        Everlasting God,
  1203. X
  1204. X            Thine eternal Logos is the main() function
  1205. X            from which all things have their being
  1206. X            and unto which all things shall return;
  1207. X            all subroutines are restless until they
  1208. X            find their rest in thee.
  1209. X
  1210. X            Grant that users of this software may
  1211. X            apply it for good purposes; grant
  1212. X            unto programmers searching its ways that
  1213. X            they may not be entirely confounded; and
  1214. X            grant that all our work may be unto thy
  1215. X            glory. Amen.
  1216. X
  1217. X***************************************************************/
  1218. X
  1219. Xvoid
  1220. Xmain( int argc, char **argv )
  1221. X   {
  1222. X   static FILE *input = NULL;
  1223. X   static int jump_set = FALSE;
  1224. X   static char start_buf[] = "\0";
  1225. X   static char end_buf[] = "\0";
  1226. X   register int n;
  1227. X   #if REDIRECT_STDERR
  1228. X   FILE *newerr;
  1229. X   #endif
  1230. X
  1231. X   /* set some initial variables */
  1232. X
  1233. X   bwb_start.number = 0;
  1234. X   bwb_start.next = &bwb_end;
  1235. X   bwb_end.number = MAXLINENO;
  1236. X   bwb_end.next = &bwb_end;
  1237. X   bwb_start.buffer = start_buf;
  1238. X   bwb_end.buffer = end_buf;
  1239. X   data_line = &bwb_start;
  1240. X   data_pos = 0;
  1241. X
  1242. X   /* Memory allocation for various tables */
  1243. X
  1244. X   /* eXecute TeXT stack */
  1245. X
  1246. X   if ( ( xtxts = calloc( XTXTSTACKSIZE, sizeof( struct xtxtsl ) ) ) == NULL )
  1247. X      {
  1248. X      bwb_error( err_getmem );
  1249. X      }
  1250. X
  1251. X   /* expression stack */
  1252. X
  1253. X   if ( ( exp_es = calloc( ESTACKSIZE, sizeof( struct exp_ese ) ) ) == NULL )
  1254. X      {
  1255. X      bwb_error( err_getmem );
  1256. X      }
  1257. X
  1258. X   /* user-defined function stack */
  1259. X
  1260. X   if ( ( ufs = calloc( UFNCSTACKSIZE, sizeof( struct ufsel ) ) ) == NULL )
  1261. X      {
  1262. X      bwb_error( err_getmem );
  1263. X      }
  1264. X
  1265. X   /* FOR-NEXT stack */
  1266. X
  1267. X   if ( ( fs = calloc( FORLEVELS, sizeof( struct fse ) ) ) == NULL )
  1268. X      {
  1269. X      bwb_error( err_getmem );
  1270. X      }
  1271. X
  1272. X   /* GOSUB-RETURN stack */
  1273. X
  1274. X   if ( ( bwb_gss = calloc( GOSUBLEVELS, sizeof( struct gsse ) ) ) == NULL )
  1275. X      {
  1276. X      bwb_error( err_getmem );
  1277. X      }
  1278. X
  1279. X   /* character buffers */
  1280. X
  1281. X   if ( ( bwb_ebuf = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  1282. X      {
  1283. X      bwb_error( err_getmem );
  1284. X      }
  1285. X   if ( ( read_line = calloc( MAXREADLINESIZE + 1, sizeof(char) ) ) == NULL )
  1286. X      {
  1287. X      bwb_error( err_getmem );
  1288. X      }
  1289. X
  1290. X   /* Variable and function table initializations */
  1291. X
  1292. X   var_init();                  /* initialize variable chain */
  1293. X
  1294. X   fnc_init();                  /* initialize function chain */
  1295. X
  1296. X   #if TEST_BSTRING
  1297. X   for ( n = 0; n < ESTACKSIZE; ++n )
  1298. X      {
  1299. X      sprintf( exp_es[ n ].sval.name, "<Exp stack bstring %d>", n );
  1300. X      }
  1301. X   #endif
  1302. X
  1303. X   /* assign memory for the device table */
  1304. X
  1305. X   if ( ( dev_table = calloc( DEF_DEVICES, sizeof( struct dev_element ) ) ) == NULL )
  1306. X      {
  1307. X      bwb_error( err_getmem );
  1308. X      exit(-1);
  1309. X      }
  1310. X
  1311. X   /* initialize all devices to DEVMODE_AVAILABLE */
  1312. X
  1313. X   for ( n = 0; n < DEF_DEVICES; ++n )
  1314. X      {
  1315. X      dev_table[ n ].mode = DEVMODE_AVAILABLE;
  1316. X      dev_table[ n ].reclen = -1;
  1317. X      dev_table[ n ].cfp = NULL;
  1318. X      dev_table[ n ].buffer = NULL;
  1319. X      dev_table[ n ].width = DEF_WIDTH;
  1320. X      dev_table[ n ].col = 1;
  1321. X      }
  1322. X
  1323. X   /* Signon message */
  1324. X
  1325. X   sprintf( bwb_ebuf, "\r%s %s\n", MES_SIGNON, VERSION );
  1326. X   xprintf( stdout, bwb_ebuf );
  1327. X   sprintf( bwb_ebuf, "\r%s\n", MES_COPYRIGHT );
  1328. X   xprintf( stdout, bwb_ebuf );
  1329. X   #if PERMANENT_DEBUG
  1330. X   sprintf( bwb_ebuf, "\r%s\n", "DEBUGGING MODE" );
  1331. X   xprintf( stdout, bwb_ebuf );
  1332. X   #else
  1333. X   sprintf( bwb_ebuf, "\r%s\n", MES_LANGUAGE );
  1334. X   xprintf( stdout, bwb_ebuf );
  1335. X   #endif
  1336. X
  1337. X   /* Redirect stderr if specified */
  1338. X
  1339. X   #if REDIRECT_STDERR
  1340. X   newerr = freopen( ERRFILE, "w", stderr );
  1341. X   if ( newerr == NULL )
  1342. X      {
  1343. X      sprintf( bwb_ebuf, "Failed to redirect error messages to file <%s>\n",
  1344. X         ERRFILE );
  1345. X      xprintf( stdout, bwb_ebuf );
  1346. X      errfdevice = stdout;
  1347. X      }
  1348. X   else
  1349. X      {
  1350. X      sprintf( bwb_ebuf, "NOTE: Error messages are redirected to file <%s>\n",
  1351. X         ERRFILE );
  1352. X      xprintf( errfdevice, bwb_ebuf );
  1353. X      errfdevice = stderr;
  1354. X      }
  1355. X   #else
  1356. X   errfdevice = stdout;
  1357. X   #endif
  1358. X
  1359. X   #if INTENSIVE_DEBUG
  1360. X   sprintf( bwb_ebuf, "in main(): Ready to save jump MARKER" );
  1361. X   bwb_debug( bwb_ebuf );
  1362. X   getchar();
  1363. X   #endif
  1364. X
  1365. X   /* set a buffer for jump: program execution returns to this point
  1366. X      in case of a jump (error, interrupt, or finish program) */
  1367. X
  1368. X   signal( SIGINT, break_mes );
  1369. X   setjmp( mark );
  1370. X
  1371. X   #if THEOLDWAY
  1372. X   if ( jump_set == FALSE )
  1373. X      {
  1374. X      signal( SIGINT, break_mes );
  1375. X      setjmp( mark );
  1376. X      jump_set = TRUE;
  1377. X      }
  1378. X   #endif
  1379. X
  1380. X   #if INTENSIVE_DEBUG
  1381. X   sprintf( bwb_ebuf, "in main(): Return from jump MARKER, program run <%d>",
  1382. X      program_run );
  1383. X   bwb_debug( bwb_ebuf );
  1384. X   getchar();
  1385. X   #endif
  1386. X
  1387. X   /* check to see if there is a program file: but do this only the first
  1388. X      time around! */
  1389. X
  1390. X   if (( argc > 1 ) && ( program_run == FALSE ))
  1391. X      {
  1392. X      program_run = TRUE;            /* don't do it again */
  1393. X      if ( ( input = fopen( argv[ 1 ], "r" )) == NULL )
  1394. X         {
  1395. X         strcpy( bwb_progfile, argv[ 1 ] );
  1396. X         strcat( bwb_progfile, ".bas" );
  1397. X         if ( ( input = fopen( bwb_progfile, "r" )) == NULL )
  1398. X            {
  1399. X            bwb_progfile[ 0 ] = 0;
  1400. X            sprintf( bwb_ebuf, err_openfile, argv[ 1 ] );
  1401. X            bwb_error( bwb_ebuf );
  1402. X            }
  1403. X         }
  1404. X      if ( input != NULL )
  1405. X         {
  1406. X         strcpy( bwb_progfile, argv[ 1 ] );
  1407. X         #if INTENSIVE_DEBUG
  1408. X         sprintf( bwb_ebuf, "in main(): progfile is <%s>.", bwb_progfile );
  1409. X         bwb_debug( bwb_ebuf );
  1410. X         #endif
  1411. X         bwb_fload( input );
  1412. X         bwb_run( &bwb_start );
  1413. X         }
  1414. X      }
  1415. X
  1416. X   /* Main Program Loop */
  1417. X
  1418. X   while( TRUE )
  1419. X      {
  1420. X
  1421. X      /* take input from keyboard */
  1422. X
  1423. X      bwb_gets( read_line );
  1424. X
  1425. X      /* If there is no line number, execute the line as received */
  1426. X
  1427. X      if ( is_ln( read_line ) == FALSE )
  1428. X         {
  1429. X         bwb_xtxtline( read_line );
  1430. X         }
  1431. X
  1432. X      /* If there is a line number, add the line to the file in memory */
  1433. X
  1434. X      else
  1435. X         {
  1436. X         bwb_ladd( read_line, TRUE );
  1437. X         }
  1438. X
  1439. X      }
  1440. X
  1441. X   }
  1442. X
  1443. X/***************************************************************
  1444. X
  1445. X        FUNCTION:       bwb_fload()
  1446. X
  1447. X        DESCRIPTION: This function loads a BASIC program
  1448. X        file into memory.
  1449. X
  1450. X***************************************************************/
  1451. X
  1452. Xbwb_fload( FILE *file )
  1453. X   {
  1454. X
  1455. X   while ( feof( file ) == FALSE )
  1456. X      {
  1457. X      read_line[ 0 ] = '\0';
  1458. X      if ( file == stdin )
  1459. X         {
  1460. X         fflush( file );
  1461. X         }
  1462. X      fgets( read_line, MAXREADLINESIZE, file );
  1463. X      if ( file == stdin )
  1464. X         {
  1465. X         * prn_getcol( stdout ) = 1;        /* reset column */
  1466. X         }
  1467. X      bwb_stripcr( read_line );
  1468. X      bwb_ladd( read_line, FALSE );
  1469. X      }
  1470. X
  1471. X   /* close file stream */
  1472. X
  1473. X   fclose( file );
  1474. X
  1475. X   return TRUE;
  1476. X   }
  1477. X
  1478. X/***************************************************************
  1479. X
  1480. X        FUNCTION:       bwb_ladd()
  1481. X
  1482. X        DESCRIPTION:    This function adds a new line (in the
  1483. X                        buffer) to the program in memory.
  1484. X
  1485. X***************************************************************/
  1486. X
  1487. Xbwb_ladd( char *buffer, int replace )
  1488. X   {
  1489. X   struct bwb_line *l, *previous;
  1490. X   register int n, a;
  1491. X   static char *s_buffer;
  1492. X   static int init = FALSE;
  1493. X   static int prev_num = 0;
  1494. X
  1495. X   #if INTENSIVE_DEBUG
  1496. X   sprintf( bwb_ebuf, "in bwb_ladd(): ready to get memory for <%s>",
  1497. X      buffer );
  1498. X   bwb_debug( bwb_ebuf );
  1499. X   #endif
  1500. X
  1501. X   /* get memory for temporary buffer if necessary */
  1502. X
  1503. X   if ( init == FALSE )
  1504. X      {
  1505. X      init = TRUE;
  1506. X      if ( ( s_buffer = calloc( (size_t) MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  1507. X         {
  1508. X         bwb_error( err_getmem );
  1509. X         return FALSE;
  1510. X         }
  1511. X      }
  1512. X
  1513. X   /* get memory for this line */
  1514. X
  1515. X   if ( ( l = (struct bwb_line *) calloc( (size_t) 1, sizeof( struct bwb_line ) )) == NULL )
  1516. X      {
  1517. X      bwb_error( err_getmem );
  1518. X      return FALSE;
  1519. X      }
  1520. X
  1521. X   #if INTENSIVE_DEBUG
  1522. X   sprintf( bwb_ebuf, "in bwb_ladd(): got memory." );
  1523. X   bwb_debug( bwb_ebuf );
  1524. X   #endif
  1525. X
  1526. X   /* allocate memory and assign buffer to line buffer */
  1527. X
  1528. X   ln_asbuf( l, buffer );
  1529. X
  1530. X   /* get the first element and test for a line number */
  1531. X
  1532. X   adv_element( l->buffer, &( l->position ), s_buffer );
  1533. X
  1534. X   /* note that line is not yet marked */
  1535. X
  1536. X   l->marked = FALSE;
  1537. X
  1538. X   /* set line number in line structure */
  1539. X
  1540. X   if ( is_numconst( s_buffer ) == TRUE )
  1541. X      {
  1542. X      l->number = atoi( s_buffer );
  1543. X      prev_num = l->number;
  1544. X      }
  1545. X   else
  1546. X      {
  1547. X
  1548. X      #if INTENSIVE_DEBUG
  1549. X      sprintf( bwb_ebuf, "in bwb_ladd(): line is not numbered, using prev <%d>",
  1550. X         prev_num );
  1551. X      bwb_debug( bwb_ebuf );
  1552. X      #endif
  1553. X
  1554. X      l->number = prev_num;
  1555. X      }
  1556. X
  1557. X   /* find the place of the current line */
  1558. X
  1559. X   for ( previous = &bwb_start; previous != &bwb_end; previous = previous->next )
  1560. X      {
  1561. X
  1562. X      /* replace a previously existing line */
  1563. X
  1564. X      if (( previous->number == l->number ) && ( replace == TRUE ))
  1565. X         {
  1566. X
  1567. X         #if INTENSIVE_DEBUG
  1568. X         sprintf( bwb_ebuf, "in bwb_ladd(): writing to previous number." );
  1569. X         bwb_debug( bwb_ebuf );
  1570. X         #endif
  1571. X
  1572. X         /* allocate memory and assign buffer to line buffer */
  1573. X
  1574. X         ln_asbuf( previous, buffer );
  1575. X
  1576. X         /* free the current line */
  1577. X
  1578. X         free( l );
  1579. X
  1580. X         /* and return */
  1581. X
  1582. X         return TRUE;
  1583. X
  1584. X         }
  1585. X
  1586. X      /* add after previously existing line: this is to allow unnumbered
  1587. X         lines that follow in sequence after a previously numbered line */
  1588. X
  1589. X      else if (( previous->number == l->number ) && ( replace == FALSE ))
  1590. X         {
  1591. X         #if INTENSIVE_DEBUG
  1592. X         sprintf( bwb_ebuf, "in bwb_ladd(): adding doubled number <%d>",
  1593. X            l->number );
  1594. X         bwb_debug( bwb_ebuf);
  1595. X         #endif
  1596. X         l->next = previous->next;
  1597. X         previous->next = l;
  1598. X         return TRUE;
  1599. X         }
  1600. X
  1601. X      /* add a new line */
  1602. X
  1603. X      else if ( ( previous->number < l->number )
  1604. X         && ( previous->next->number > l->number ))
  1605. X         {
  1606. X         l->next = previous->next;
  1607. X         previous->next = l;
  1608. X
  1609. X         #if INTENSIVE_DEBUG
  1610. X         sprintf( bwb_ebuf, "in bwb_ladd(): added new line <%d> buffer <%s>",
  1611. X            l->number, l->buffer );
  1612. X         bwb_debug( bwb_ebuf );
  1613. X         #endif
  1614. X
  1615. X         return TRUE;
  1616. X         }
  1617. X
  1618. X      }
  1619. X
  1620. X   sprintf( bwb_ebuf, ERR_LINENO );
  1621. X   bwb_error( bwb_ebuf );
  1622. X   return FALSE;
  1623. X
  1624. X   }
  1625. X
  1626. X/***************************************************************
  1627. X
  1628. X        FUNCTION:       bwb_shell()
  1629. X
  1630. X        DESCRIPTION:
  1631. X
  1632. X***************************************************************/
  1633. X
  1634. X#if COMMAND_SHELL
  1635. Xint
  1636. Xbwb_shell( struct bwb_line *l )
  1637. X   {
  1638. X   static char *s_buffer;
  1639. X   static int init = FALSE;
  1640. X   static int position;
  1641. X
  1642. X   /* get memory for temporary buffer if necessary */
  1643. X
  1644. X   if ( init == FALSE )
  1645. X      {
  1646. X      init = TRUE;
  1647. X      if ( ( s_buffer = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  1648. X         {
  1649. X         bwb_error( err_getmem );
  1650. X         return FALSE;
  1651. X         }
  1652. X      }
  1653. X
  1654. X   /* get the first element and check for a line number */
  1655. X
  1656. X   #if INTENSIVE_DEBUG
  1657. X   sprintf( bwb_ebuf, "in bwb_shell(): line buffer is <%s>.", l->buffer );
  1658. X   bwb_debug( bwb_ebuf );
  1659. X   #endif
  1660. X
  1661. X   position = 0;
  1662. X   adv_element( l->buffer, &position, s_buffer );
  1663. X   if ( is_numconst( s_buffer ) != TRUE )                  /* not a line number */
  1664. X      {
  1665. X
  1666. X      #if INTENSIVE_DEBUG
  1667. X      sprintf( bwb_ebuf, "in bwb_shell(): no line number, command <%s>.",
  1668. X         l->buffer );
  1669. X      bwb_debug( bwb_ebuf );
  1670. X      #endif
  1671. X
  1672. X      if ( system( l->buffer ) == 0 )
  1673. X         {
  1674. X         return TRUE;
  1675. X         }
  1676. X      else
  1677. X         {
  1678. X         return FALSE;
  1679. X         }
  1680. X      }
  1681. X
  1682. X   else                                         /* advance past line number */
  1683. X      {
  1684. X      adv_ws( l->buffer, &position );           /* advance past whitespace */
  1685. X
  1686. X      #if INTENSIVE_DEBUG
  1687. X      sprintf( bwb_ebuf, "in bwb_shell(): line number, command <%s>.",
  1688. X         l->buffer );
  1689. X      bwb_debug( bwb_ebuf );
  1690. X      #endif
  1691. X
  1692. X      if ( system( &( l->buffer[ position ] ) ) == 0 )
  1693. X         {
  1694. X         return TRUE;
  1695. X         }
  1696. X      else
  1697. X         {
  1698. X         return FALSE;
  1699. X         }
  1700. X      }
  1701. X   }
  1702. X#endif
  1703. X
  1704. X/***************************************************************
  1705. X
  1706. X        FUNCTION:       bwb_xtxtline()
  1707. X
  1708. X        DESCRIPTION:    This function executes a text line, i.e.,
  1709. X                        places it in memory and then calls
  1710. X                        bwb_xline() to execute it.
  1711. X
  1712. X***************************************************************/
  1713. X
  1714. Xstruct bwb_line *
  1715. Xbwb_xtxtline( char *buffer )
  1716. X   {
  1717. X   struct bwb_line *c;
  1718. X   register int n, a;
  1719. X   char *p;
  1720. X   int loop;
  1721. X
  1722. X   #if INTENSIVE_DEBUG
  1723. X   sprintf( bwb_ebuf, "in bwb_xtxtline(): received <%s>", buffer );
  1724. X   bwb_debug( bwb_ebuf );
  1725. X   #endif
  1726. X
  1727. X   /* increment xtxt stack counter */
  1728. X
  1729. X   if ( xtxtsc >= XTXTSTACKSIZE )
  1730. X      {
  1731. X      sprintf( bwb_ebuf, "Exceeded maximum xtxt stack <%d>",
  1732. X         xtxtsc );
  1733. X      return &bwb_end;
  1734. X      }
  1735. X
  1736. X   ++xtxtsc;
  1737. X
  1738. X   /* advance past whitespace */
  1739. X
  1740. X   p = buffer;
  1741. X   loop = TRUE;
  1742. X   while( loop == TRUE )
  1743. X      {
  1744. X
  1745. X      switch( *p )
  1746. X         {
  1747. X         case '\0':                     /* end of string */
  1748. X
  1749. X            #if INTENSIVE_DEBUG
  1750. X            sprintf( bwb_ebuf, "Null command line received." );
  1751. X            bwb_debug( bwb_ebuf );
  1752. X            #endif
  1753. X            --xtxtsc;
  1754. X            return &bwb_end;
  1755. X         case ' ':                      /* whitespace */
  1756. X         case '\t':
  1757. X            ++p;
  1758. X            break;
  1759. X         default:
  1760. X            loop = FALSE;
  1761. X            break;
  1762. X         }
  1763. X
  1764. X      }
  1765. X
  1766. X   #if INTENSIVE_DEBUG
  1767. X   sprintf( bwb_ebuf, "in bwb_xtxtline(): ready to get memory" );
  1768. X   bwb_debug( bwb_ebuf );
  1769. X   #endif
  1770. X
  1771. X   if ( xtxts[ xtxtsc ].l.buffer != NULL )
  1772. X      {
  1773. X      #if INTENSIVE_DEBUG
  1774. X      sprintf( bwb_ebuf, "in bwb_xtxtline(): freeing buffer memory" );
  1775. X      bwb_debug( bwb_ebuf );
  1776. X      #endif
  1777. X      free( xtxts[ xtxtsc ].l.buffer );
  1778. X      }
  1779. X
  1780. X   /* copy the whole line to the line structure buffer */
  1781. X
  1782. X   ln_asbuf( &( xtxts[ xtxtsc ].l ), buffer );
  1783. X
  1784. X   #if INTENSIVE_DEBUG
  1785. X   sprintf( bwb_ebuf, "in bwb_xtxtline(): copied to line buffer <%s>.",
  1786. X      xtxts[ xtxtsc ].l.buffer );
  1787. X   bwb_debug( bwb_ebuf );
  1788. X   #endif
  1789. X
  1790. X   /* set line number in line structure */
  1791. X
  1792. X   xtxts[ xtxtsc ].l.number = 0;
  1793. X   xtxts[ xtxtsc ].l.marked = FALSE;
  1794. X
  1795. X   /* execute the line as BASIC command line */
  1796. X
  1797. X   xtxts[ xtxtsc ].l.next = &bwb_end;
  1798. X   c = &( xtxts[ xtxtsc ].l );
  1799. X   c->position = 0;
  1800. X
  1801. X   do
  1802. X      {
  1803. X/*      xtxts[ xtxtsc ].position = 0; */
  1804. X      c = bwb_xline( c );
  1805. X      }
  1806. X
  1807. X   while( c != &bwb_end );
  1808. X
  1809. X   /* decrement xtxt stack counter */
  1810. X
  1811. X   --xtxtsc;
  1812. X
  1813. X   return c;
  1814. X
  1815. X   }
  1816. X
  1817. X/***************************************************************
  1818. X
  1819. X        FUNCTION:       bwb_xline()
  1820. X
  1821. X        DESCRIPTION:    This function executes a single line of
  1822. X                        the program in memory.
  1823. X
  1824. X***************************************************************/
  1825. X
  1826. Xstruct bwb_line *
  1827. Xbwb_xline( struct bwb_line *l )
  1828. X   {
  1829. X   int loop, extended_line;
  1830. X   struct bwb_line *r;
  1831. X
  1832. X   #if INTENSIVE_DEBUG
  1833. X   sprintf( bwb_ebuf, "in bwb_xline(): buffer <%s>",
  1834. X      &( l->buffer[ l->position ] ) );
  1835. X   bwb_debug( bwb_ebuf );
  1836. X   #endif
  1837. X
  1838. X   /* Print line number if trace is on */
  1839. X
  1840. X   if ( bwb_trace == TRUE )
  1841. X      {
  1842. X      if ( l->number > 0 )
  1843. X         {
  1844. X         sprintf( bwb_ebuf, "[ %d ]", l->number );
  1845. X         xprintf( errfdevice, bwb_ebuf );
  1846. X         }
  1847. X      }
  1848. X
  1849. X   /* Set current line for error/break handling */
  1850. X
  1851. X   bwb_number = l->number;
  1852. X   bwb_l = l;
  1853. X   extended_line = FALSE;
  1854. X
  1855. X   /* advance past whitespace and segment delimiter */
  1856. X
  1857. X   if ( l->buffer[ l->position ] == ':' )
  1858. X      {
  1859. X      ++( l->position );
  1860. X      }
  1861. X   adv_ws( l->buffer, &( l->position ) );
  1862. X   if ( l->buffer[ l->position ] == ':' )
  1863. X      {
  1864. X      ++( l->position );
  1865. X      adv_ws( l->buffer, &( l->position ) );
  1866. X      }
  1867. X
  1868. X   /* Loop through line segments delimited by ':' */
  1869. X
  1870. X   loop = TRUE;
  1871. X   r = l->next;
  1872. X
  1873. X   while ( loop == TRUE )
  1874. X      {
  1875. X
  1876. X      /* set loop to false: it will be set to TRUE later if needed */
  1877. X
  1878. X      loop = FALSE;
  1879. X
  1880. X      /* set positions in buffer */
  1881. X
  1882. X      #if MARK_LINES
  1883. X      if ( ( l->marked != TRUE ) || ( l->position > l->startpos ))
  1884. X     {
  1885. X     line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  1886. X        &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  1887. X     l->marked = TRUE;
  1888. X     }
  1889. X      else
  1890. X         {
  1891. X         #if INTENSIVE_DEBUG
  1892. X         sprintf( bwb_ebuf, "in bwb_xline(): line <%d> is already marked",
  1893. X             l->number );
  1894. X         bwb_debug( bwb_ebuf );
  1895. X         #endif
  1896. X         }
  1897. X      #else
  1898. X      line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  1899. X         &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  1900. X      #endif
  1901. X
  1902. X      if ( l->position < l->startpos )
  1903. X         {
  1904. X         l->position = l->startpos;
  1905. X         }
  1906. X
  1907. X      /* if there is a BASIC command in the line, execute it here */
  1908. X
  1909. X      if ( l->cmdnum > -1 )
  1910. X         {
  1911. X
  1912. X         #if INTENSIVE_DEBUG
  1913. X         sprintf( bwb_ebuf, "in bwb_xline(): executing <%s>", l->buffer );
  1914. X         bwb_debug( bwb_ebuf );
  1915. X         #endif
  1916. X
  1917. X         /* execute the command vector */
  1918. X
  1919. X         r = ( bwb_cmdtable[ l->cmdnum ].vector ) ( l );
  1920. X
  1921. X     #if INTENSIVE_DEBUG
  1922. X     if ( l->cmdnum == getcmdnum( "GOSUB" ) )
  1923. X        {
  1924. X        sprintf( bwb_ebuf, "in bwb_xline(): returning from GOSUB, position <%d>",
  1925. X           l->position );
  1926. X        bwb_debug( bwb_ebuf );
  1927. X            }
  1928. X     #endif
  1929. X
  1930. X         /* If the command was RETURN OR GOTO, then we must break out of
  1931. X            the loop at this point; the rest of the line is irrelevant */
  1932. X
  1933. X         if ( l->cmdnum == getcmdnum( "RETURN" ) )
  1934. X            {
  1935. X        #if INTENSIVE_DEBUG
  1936. X        sprintf( bwb_ebuf, "in bwb_xline(): returning from RETURN command, ret line <%d>",
  1937. X           r->number );
  1938. X        bwb_debug( bwb_ebuf );
  1939. X        #endif
  1940. X        r->cmdnum = getcmdnum( "RETURN" );
  1941. X        r->marked = FALSE;
  1942. X        return r;            /* break out; return now */
  1943. X        }
  1944. X
  1945. X         else if ( l->cmdnum == getcmdnum( "GOTO" ) )
  1946. X            {
  1947. X        #if INTENSIVE_DEBUG
  1948. X            sprintf( bwb_ebuf, "in bwb_xline(): returning from GOTO command, ret line <%d>",
  1949. X               r->number );
  1950. X            bwb_debug( bwb_ebuf );
  1951. X            #endif
  1952. X            return r;
  1953. X            }
  1954. X         }
  1955. X
  1956. X      else if ( l->buffer[ l->position ] == ':' )
  1957. X         {
  1958. X         l->marked = FALSE;
  1959. X         }                /* do nothing */
  1960. X
  1961. X      /* No BASIC command; try to execute it as a shell command */
  1962. X
  1963. X      #if COMMAND_SHELL
  1964. X      else
  1965. X     {
  1966. X
  1967. X     #if INTENSIVE_DEBUG
  1968. X     sprintf( bwb_ebuf, "Breaking out to shell, line num <%d> buf <%s> cmd <%d> pos <%d>",
  1969. X        l->number, &( l->buffer[ l->position ] ), l->cmdnum, l->position );
  1970. X     bwb_debug( bwb_ebuf );
  1971. X     getchar();
  1972. X     #endif
  1973. X
  1974. X     bwb_shell( l );
  1975. X     }
  1976. X
  1977. X      #else                /* COMMAND_SHELL == FALSE */
  1978. X
  1979. X      else
  1980. X        {
  1981. X        bwb_error( err_uc );
  1982. X        }
  1983. X
  1984. X      #endif
  1985. X
  1986. X      /* detect if the current character is ':', in which case loop
  1987. X         back through to execute it */
  1988. X
  1989. X      #if INTENSIVE_DEBUG
  1990. X      sprintf( bwb_ebuf, "in bwb_xline(): remaining line is <%s>",
  1991. X         &( l->buffer[ l->position ] ) );
  1992. X      bwb_debug( bwb_ebuf );
  1993. X      #endif
  1994. X
  1995. X      adv_ws( l->buffer, &( l->position ) );
  1996. X      if ( l->buffer[ l->position ] == ':' )
  1997. X         {
  1998. X
  1999. X     #if INTENSIVE_DEBUG
  2000. X     sprintf( bwb_ebuf, "in bwb_xline(): line <%d> found \':\'",
  2001. X        l->number );
  2002. X         bwb_debug( bwb_ebuf );
  2003. X         #endif
  2004. X
  2005. X     ++l->position;
  2006. X     l->marked = FALSE;
  2007. X     extended_line = TRUE;
  2008. X         loop = TRUE;
  2009. X         }
  2010. X
  2011. X      else if ( extended_line == TRUE )
  2012. X     {
  2013. X     l->marked = FALSE;
  2014. X     }
  2015. X
  2016. X      }                                 /* end of loop through line */
  2017. X
  2018. X   /* return the value in r */
  2019. X
  2020. X   #if INTENSIVE_DEBUG
  2021. X   if ( r->cmdnum == getcmdnum( "RETURN" ) )
  2022. X      {
  2023. X      bwb_debug( "in bwb_xline(): returning RETURN cmdnum" );
  2024. X      }
  2025. X   #endif
  2026. X
  2027. X   return r;
  2028. X
  2029. X   }
  2030. X
  2031. X/***************************************************************
  2032. X
  2033. X        FUNCTION:       ln_asbuf()
  2034. X
  2035. X        DESCRIPTION:    This function allocates memory and copies
  2036. X            a null-terminated string to a line buffer.
  2037. X
  2038. X***************************************************************/
  2039. X
  2040. Xint
  2041. Xln_asbuf( struct bwb_line *l, char *s )
  2042. X   {
  2043. X
  2044. X   #ifdef DONTDOIT
  2045. X   if ( l->buffer != NULL )
  2046. X      {
  2047. X      free( l->buffer );
  2048. X      }
  2049. X   #endif
  2050. X
  2051. X   if ( ( l->buffer = calloc( strlen( s ) + 2, sizeof( char ) ) )
  2052. X      == NULL )
  2053. X      {
  2054. X      bwb_error( err_getmem );
  2055. X      return FALSE;
  2056. X      }
  2057. X
  2058. X   /* copy the whole line to the line structure buffer */
  2059. X
  2060. X   strcpy( l->buffer, s );
  2061. X
  2062. X   #if INTENSIVE_DEBUG
  2063. X   sprintf( bwb_ebuf, "in ln_asbuf(): allocated buffer <%s>", l->buffer );
  2064. X   bwb_debug( bwb_ebuf );
  2065. X   #endif
  2066. X
  2067. X   /* strip CR from the buffer */
  2068. X
  2069. X   bwb_stripcr( l->buffer );
  2070. X
  2071. X   return TRUE;
  2072. X
  2073. X   }
  2074. X
  2075. X/***************************************************************
  2076. X
  2077. X        FUNCTION:       bwb_gets()
  2078. X
  2079. X        DESCRIPTION:    This function reads a single line from
  2080. X                        the specified buffer.
  2081. X
  2082. X***************************************************************/
  2083. X
  2084. Xbwb_gets( char *buffer )
  2085. X   {
  2086. X   bwb_number = 0;
  2087. X   sprintf( bwb_ebuf, "\r%s\n", PROMPT );
  2088. X   xprintf( stdout, bwb_ebuf );
  2089. X   fflush( stdin );
  2090. X   fgets( buffer, MAXREADLINESIZE, stdin );
  2091. X   * prn_getcol( stdout ) = 1;            /* reset column */
  2092. X   return TRUE;
  2093. X   }
  2094. X
  2095. X/***************************************************************
  2096. X
  2097. X        FUNCTION:       break_mes()
  2098. X
  2099. X        DESCRIPTION:    This function is called (a) by a SIGINT
  2100. X                        signal or (b) by error-handling routines.
  2101. X
  2102. X***************************************************************/
  2103. X
  2104. Xvoid
  2105. Xbreak_mes( int x )
  2106. X   {
  2107. X   static char *tmp_buffer;
  2108. X   static int init = FALSE;
  2109. X
  2110. X   /* get memory for temporary buffer if necessary */
  2111. X
  2112. X   if ( init == FALSE )
  2113. X      {
  2114. X      init = TRUE;
  2115. X      if ( ( tmp_buffer = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  2116. X         {
  2117. X         bwb_error( err_getmem );
  2118. X         }
  2119. X      }
  2120. X
  2121. X   exp_esc = 0;
  2122. X
  2123. X   sprintf( tmp_buffer, "\r%s %d\n", MES_BREAK, bwb_number );
  2124. X   xprintf( errfdevice, tmp_buffer );
  2125. X
  2126. X   break_handler();
  2127. X
  2128. X   }
  2129. X
  2130. Xvoid
  2131. Xbreak_handler( void )
  2132. X   {
  2133. X
  2134. X   /* zero all stack counters */
  2135. X
  2136. X   exp_esc = 0;
  2137. X   bwb_gssc = 0;
  2138. X   ufsc = 0;
  2139. X   ws_counter = 0;
  2140. X   fs_counter = 0;
  2141. X   xtxtsc = 0;
  2142. X
  2143. X   /* jump back to mark */
  2144. X
  2145. X   longjmp( mark, -1 );
  2146. X
  2147. X   }
  2148. X
  2149. X
  2150. Xint
  2151. Xis_ln( char *buffer )
  2152. X   {
  2153. X   static int position;
  2154. X
  2155. X   position = 0;
  2156. X   adv_ws( buffer, &position );
  2157. X   switch( buffer[ position ] )
  2158. X      {
  2159. X      case '0':
  2160. X      case '1':
  2161. X      case '2':
  2162. X      case '3':
  2163. X      case '4':
  2164. X      case '5':
  2165. X      case '6':
  2166. X      case '7':
  2167. X      case '8':
  2168. X      case '9':
  2169. X         return TRUE;
  2170. X      default:
  2171. X         return FALSE;
  2172. X      }
  2173. X   }
  2174. X
  2175. END_OF_FILE
  2176.   if test 25417 -ne `wc -c <'bwbasic.c'`; then
  2177.     echo shar: \"'bwbasic.c'\" unpacked with wrong size!
  2178.   fi
  2179.   # end of 'bwbasic.c'
  2180. fi
  2181. echo shar: End of archive 11 \(of 11\).
  2182. cp /dev/null ark11isdone
  2183. MISSING=""
  2184. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2185.     if test ! -f ark${I}isdone ; then
  2186.     MISSING="${MISSING} ${I}"
  2187.     fi
  2188. done
  2189. if test "${MISSING}" = "" ; then
  2190.     echo You have unpacked all 11 archives.
  2191.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2192. else
  2193.     echo You still must unpack the following archives:
  2194.     echo "        " ${MISSING}
  2195. fi
  2196. exit 0
  2197. exit 0 # Just in case...
  2198.