ChipMaster's bwBASIC This also includes history going back to v2.10. *WARN* some binary files might have been corrupted by CRLF.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2275 lines
48 KiB

  1. /***************************************************************
  2. bwb_cmd.c Miscellaneous Commands
  3. for Bywater BASIC Interpreter
  4. Commands: RUN
  5. LET
  6. LOAD
  7. MERGE
  8. CHAIN
  9. NEW
  10. RENUM
  11. SAVE
  12. LIST
  13. GOTO
  14. GOSUB
  15. RETURN
  16. ON
  17. STOP
  18. END
  19. SYSTEM
  20. TRON
  21. TROFF
  22. DELETE
  23. RANDOMIZE
  24. ENVIRON
  25. CMDS (*debugging)
  26. Copyright (c) 1993, Ted A. Campbell
  27. Bywater Software
  28. email: tcamp@delphi.com
  29. Copyright and Permissions Information:
  30. All U.S. and international rights are claimed by the author,
  31. Ted A. Campbell.
  32. This software is released under the terms of the GNU General
  33. Public License (GPL), which is distributed with this software
  34. in the file "COPYING". The GPL specifies the terms under
  35. which users may copy and use the software in this distribution.
  36. A separate license is available for commercial distribution,
  37. for information on which you should contact the author.
  38. ***************************************************************/
  39. /*---------------------------------------------------------------*/
  40. /* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */
  41. /* 11/1995 (eidetics@cerf.net). */
  42. /* */
  43. /* Those additionally marked with "DD" were at the suggestion of */
  44. /* Dale DePriest (daled@cadence.com). */
  45. /*---------------------------------------------------------------*/
  46. #include <stdio.h>
  47. #include <math.h>
  48. #include <ctype.h>
  49. #include "bwbasic.h"
  50. #include "bwb_mes.h"
  51. #if HAVE_SIGNAL
  52. #include <signal.h>
  53. #endif
  54. char err_gosubl[ MAXVARNAMESIZE + 1 ] = { '\0' }; /* line for error GOSUB */
  55. #if ANSI_C
  56. extern struct bwb_line *bwb_xnew( struct bwb_line *l );
  57. extern struct bwb_line *bwb_onerror( struct bwb_line *l );
  58. struct bwb_line *bwb_donum( struct bwb_line *l );
  59. struct bwb_line *bwb_dounnum( struct bwb_line *l );
  60. static int xl_line( FILE *file, struct bwb_line *l );
  61. #else
  62. extern struct bwb_line *bwb_xnew();
  63. extern struct bwb_line *bwb_onerror();
  64. struct bwb_line *bwb_donum();
  65. struct bwb_line *bwb_dounnum();
  66. static int xl_line();
  67. #endif
  68. /***************************************************************
  69. FUNCTION: bwb_null()
  70. DESCRIPTION: This is a null command function body, and
  71. can be used as the basis for developing
  72. new BASIC commands.
  73. ***************************************************************/
  74. #if ANSI_C
  75. struct bwb_line *
  76. bwb_null( struct bwb_line *l )
  77. #else
  78. struct bwb_line *
  79. bwb_null( l )
  80. struct bwb_line *l;
  81. #endif
  82. {
  83. #if INTENSIVE_DEBUG
  84. sprintf( bwb_ebuf, "in bwb_null(): NULL command" );
  85. bwb_debug( bwb_ebuf );
  86. #endif
  87. #if MULTISEG_LINES
  88. adv_eos( l->buffer, &( l->position ));
  89. #endif
  90. return bwb_zline( l );
  91. }
  92. /***************************************************************
  93. FUNCTION: bwb_rem()
  94. DESCRIPTION: This C function implements the BASIC rem
  95. (REMark) command, ignoring the remainder
  96. of the line.
  97. ***************************************************************/
  98. #if ANSI_C
  99. struct bwb_line *
  100. bwb_rem( struct bwb_line *l )
  101. #else
  102. struct bwb_line *
  103. bwb_rem( l )
  104. struct bwb_line *l;
  105. #endif
  106. {
  107. #if INTENSIVE_DEBUG
  108. sprintf( bwb_ebuf, "in bwb_rem(): REM command" );
  109. bwb_debug( bwb_ebuf );
  110. #endif
  111. /* do not use bwb_zline() here; blank out remainder of line */
  112. l->next->position = 0;
  113. return l->next;
  114. }
  115. /***************************************************************
  116. FUNCTION: bwb_let()
  117. DESCRIPTION: This C function implements the BASIC
  118. LET assignment command, even if LET
  119. is implied and not explicit.
  120. SYNTAX: LET variable = expression
  121. ***************************************************************/
  122. #if ANSI_C
  123. struct bwb_line *
  124. bwb_let( struct bwb_line *l )
  125. #else
  126. struct bwb_line *
  127. bwb_let( l )
  128. struct bwb_line *l;
  129. #endif
  130. {
  131. #if INTENSIVE_DEBUG
  132. sprintf( bwb_ebuf, "in bwb_let(): pos <%d> line <%s>",
  133. l->position, l->buffer );
  134. bwb_debug( bwb_ebuf );
  135. #endif
  136. /* Call the expression interpreter to evaluate the assignment */
  137. bwb_exp( l->buffer, TRUE, &( l->position ) );
  138. return bwb_zline( l );
  139. }
  140. /***************************************************************
  141. FUNCTION: bwb_go
  142. DESCRIPTION: This C function implements the BASIC
  143. GO command, branching appropriately to
  144. GOTO or GOSUB.
  145. ***************************************************************/
  146. #if ANSI_C
  147. struct bwb_line *
  148. bwb_go( struct bwb_line *l )
  149. #else
  150. struct bwb_line *
  151. bwb_go( l )
  152. struct bwb_line *l;
  153. #endif
  154. {
  155. char tbuf[ MAXSTRINGSIZE + 1 ];
  156. adv_element( l->buffer, &( l->position ), tbuf );
  157. bwb_strtoupper( tbuf );
  158. if ( strcmp( tbuf, CMD_XSUB ) == 0 )
  159. {
  160. return bwb_gosub( l );
  161. }
  162. if ( strcmp( tbuf, CMD_XTO ) == 0 )
  163. {
  164. return bwb_goto( l );
  165. }
  166. #if PROG_ERRORS
  167. sprintf( bwb_ebuf, "in bwb_go(): Nonsense following GO" );
  168. bwb_error( bwb_ebuf );
  169. #else
  170. bwb_error( err_syntax );
  171. #endif
  172. return bwb_zline( l );
  173. }
  174. /***************************************************************
  175. FUNCTION: bwb_goto
  176. DESCRIPTION: This C function implements the BASIC
  177. GOTO command.
  178. SYNTAX: GOTO line | label
  179. ***************************************************************/
  180. #if ANSI_C
  181. struct bwb_line *
  182. bwb_goto( struct bwb_line *l )
  183. #else
  184. struct bwb_line *
  185. bwb_goto( l )
  186. struct bwb_line *l;
  187. #endif
  188. {
  189. struct bwb_line *x;
  190. char tbuf[ MAXSTRINGSIZE + 1 ];
  191. #if INTENSIVE_DEBUG
  192. sprintf( bwb_ebuf, "in bwb_goto(): entered function" );
  193. bwb_debug( bwb_ebuf );
  194. #endif
  195. /* Check for argument */
  196. adv_ws( l->buffer, &( l->position ) );
  197. switch( l->buffer[ l->position ] )
  198. {
  199. case '\0':
  200. case '\n':
  201. case '\r':
  202. case ':':
  203. bwb_error( err_noln );
  204. return bwb_zline( l );
  205. default:
  206. break;
  207. }
  208. adv_element( l->buffer, &( l->position ), tbuf );
  209. #if INTENSIVE_DEBUG
  210. sprintf( bwb_ebuf, "in bwb_goto(): buffer has <%s>", tbuf );
  211. bwb_debug( bwb_ebuf );
  212. #endif
  213. /* check for target label */
  214. #if STRUCT_CMDS
  215. if ( isalpha( tbuf[ 0 ] ))
  216. {
  217. #if INTENSIVE_DEBUG
  218. sprintf( bwb_ebuf, "in bwb_goto(): found LABEL, <%s>", tbuf );
  219. bwb_debug( bwb_ebuf );
  220. #endif
  221. x = find_label( tbuf );
  222. x->position = 0;
  223. return x;
  224. }
  225. else
  226. {
  227. for ( x = &CURTASK bwb_start; x != &CURTASK bwb_end; x = x->next )
  228. {
  229. if ( x->number == atoi( tbuf ) )
  230. {
  231. /* found the requested number */
  232. #if INTENSIVE_DEBUG
  233. sprintf( bwb_ebuf, "in bwb_goto(): returning line <%d>", x->number );
  234. bwb_debug( bwb_ebuf );
  235. #endif
  236. x->position = 0;
  237. return x;
  238. }
  239. }
  240. }
  241. #else
  242. for ( x = &CURTASK bwb_start; x != &CURTASK bwb_end; x = x->next )
  243. {
  244. if ( x->number == atoi( tbuf ) )
  245. {
  246. /* found the requested number */
  247. #if INTENSIVE_DEBUG
  248. sprintf( bwb_ebuf, "in bwb_goto(): returning line <%d>", x->number );
  249. bwb_debug( bwb_ebuf );
  250. #endif
  251. x->position = 0;
  252. return x;
  253. }
  254. }
  255. #endif
  256. sprintf( bwb_ebuf, err_lnnotfound, atoi( tbuf ) );
  257. bwb_error( bwb_ebuf );
  258. return bwb_zline( l );
  259. }
  260. /***************************************************************
  261. FUNCTION: bwb_gosub()
  262. DESCRIPTION: This function implements the BASIC GOSUB
  263. command.
  264. SYNTAX: GOSUB line | label
  265. ***************************************************************/
  266. #if ANSI_C
  267. struct bwb_line *
  268. bwb_gosub( struct bwb_line *l )
  269. #else
  270. struct bwb_line *
  271. bwb_gosub( l )
  272. struct bwb_line *l;
  273. #endif
  274. {
  275. struct bwb_line *x;
  276. char atbuf[ MAXSTRINGSIZE + 1 ];
  277. /* Check for argument */
  278. adv_ws( l->buffer, &( l->position ) );
  279. switch( l->buffer[ l->position ] )
  280. {
  281. case '\0':
  282. case '\n':
  283. case '\r':
  284. case ':':
  285. sprintf( bwb_ebuf, err_noln );
  286. bwb_error( bwb_ebuf );
  287. return bwb_zline( l );
  288. default:
  289. break;
  290. }
  291. /* get the target line number in tbuf */
  292. adv_element( l->buffer, &( l->position ), atbuf );
  293. #if MULTISEG_LINES
  294. adv_eos( l->buffer, &( l->position ));
  295. #endif
  296. /* check for a label rather than line number */
  297. #if STRUCT_CMDS
  298. if ( isalpha( atbuf[ 0 ] ))
  299. {
  300. x = find_label( atbuf );
  301. #if MULTISEG_LINES
  302. CURTASK excs[ CURTASK exsc ].position = l->position;
  303. #endif
  304. bwb_incexec();
  305. /* set the new position to x and return x */
  306. x->cmdnum = -1;
  307. x->marked = FALSE;
  308. x->position = 0;
  309. bwb_setexec( x, 0, EXEC_GOSUB );
  310. return x;
  311. }
  312. #endif
  313. for ( x = &CURTASK bwb_start; x != &CURTASK bwb_end; x = x->next )
  314. {
  315. if ( x->number == atoi( atbuf ))
  316. {
  317. /* this is the line we are looking for */
  318. #if MULTISEG_LINES
  319. CURTASK excs[ CURTASK exsc ].position = l->position;
  320. #endif
  321. /* increment the EXEC stack */
  322. bwb_incexec();
  323. /* set the new position to x and return x */
  324. x->cmdnum = -1;
  325. x->marked = FALSE;
  326. x->position = 0;
  327. bwb_setexec( x, 0, EXEC_GOSUB );
  328. return x;
  329. }
  330. }
  331. /* the requested line was not found */
  332. sprintf( bwb_ebuf, err_lnnotfound, atoi( atbuf ) );
  333. bwb_error( bwb_ebuf );
  334. return bwb_zline( l );
  335. }
  336. /***************************************************************
  337. FUNCTION: bwb_return()
  338. DESCRIPTION: This function implements the BASIC RETURN
  339. command.
  340. SYNTAX: RETURN
  341. ***************************************************************/
  342. #if ANSI_C
  343. struct bwb_line *
  344. bwb_return( struct bwb_line *l )
  345. #else
  346. struct bwb_line *
  347. bwb_return( l )
  348. struct bwb_line *l;
  349. #endif
  350. {
  351. #if INTENSIVE_DEBUG
  352. sprintf( bwb_ebuf, "in bwb_return() at line <%d> cmdnum <%d>",
  353. l->number, l->cmdnum );
  354. bwb_debug( bwb_ebuf );
  355. #endif
  356. /* see if old position was "GOSUB" */
  357. if ( CURTASK excs[ CURTASK exsc ].code != EXEC_GOSUB )
  358. {
  359. bwb_error( err_retnogosub );
  360. }
  361. /* decrement the EXEC stack counter */
  362. bwb_decexec();
  363. /* restore position and return old line */
  364. #if MULTISEG_LINES
  365. CURTASK excs[ CURTASK exsc ].line->position
  366. = CURTASK excs[ CURTASK exsc ].position;
  367. return CURTASK excs[ CURTASK exsc ].line;
  368. #else
  369. CURTASK excs[ CURTASK exsc ].line->next->position = 0;
  370. return CURTASK excs[ CURTASK exsc ].line->next;
  371. #endif
  372. }
  373. /***************************************************************
  374. FUNCTION: bwb_on
  375. DESCRIPTION: This function implements the BASIC ON...
  376. GOTO or ON...GOSUB statements.
  377. It will also detect the ON ERROR... statement
  378. and pass execution to bwb_onerror().
  379. SYNTAX: ON variable GOTO|GOSUB line[,line,line,...]
  380. LIMITATION: As implemented here, the ON...GOSUB|GOTO
  381. command recognizes line numbers only
  382. (not labels).
  383. ***************************************************************/
  384. #if ANSI_C
  385. struct bwb_line *
  386. bwb_on( struct bwb_line *l )
  387. #else
  388. struct bwb_line *
  389. bwb_on( l )
  390. struct bwb_line *l;
  391. #endif
  392. {
  393. struct bwb_line *oline, *x;
  394. char varname[ MAXVARNAMESIZE + 1 ];
  395. char tbuf[ MAXSTRINGSIZE + 1 ];
  396. static int p;
  397. struct exp_ese *rvar;
  398. int v;
  399. int loop;
  400. int num_lines;
  401. int command;
  402. int lines[ MAX_GOLINES ];
  403. char sbuf[ 7 ];
  404. /* Check for argument */
  405. adv_ws( l->buffer, &( l->position ) );
  406. switch( l->buffer[ l->position ] )
  407. {
  408. case '\0':
  409. case '\n':
  410. case '\r':
  411. case ':':
  412. sprintf( bwb_ebuf, err_incomplete );
  413. bwb_error( bwb_ebuf );
  414. return bwb_zline( l );
  415. default:
  416. break;
  417. }
  418. /* get the variable name or numerical constant */
  419. adv_element( l->buffer, &( l->position ), varname );
  420. /* check for ON ERROR statement */
  421. #if COMMON_CMDS
  422. strncpy( sbuf, varname, 6 );
  423. bwb_strtoupper( sbuf );
  424. if ( strcmp( sbuf, CMD_XERROR ) == 0 )
  425. {
  426. #if INTENSIVE_DEBUG
  427. sprintf( bwb_ebuf, "in bwb_on(): detected ON ERROR" );
  428. bwb_debug( bwb_ebuf );
  429. #endif
  430. return bwb_onerror( l );
  431. }
  432. #endif /* COMMON_CMDS */
  433. /* evaluate the variable name or constant */
  434. p = 0;
  435. rvar = bwb_exp( varname, FALSE, &p );
  436. v = (int) exp_getnval( rvar );
  437. #if INTENSIVE_DEBUG
  438. sprintf( bwb_ebuf, "in bwb_on(): value is <%d>", v );
  439. bwb_debug( bwb_ebuf );
  440. #endif
  441. /* Get GOTO or GOSUB statements */
  442. adv_element( l->buffer, &( l->position ), tbuf );
  443. bwb_strtoupper( tbuf );
  444. if ( strncmp( tbuf, CMD_GOTO, (size_t) strlen( CMD_GOTO ) ) == 0 )
  445. {
  446. command = getcmdnum( CMD_GOTO );
  447. }
  448. else if ( strncmp( tbuf, CMD_GOSUB, (size_t) strlen( CMD_GOSUB ) ) == 0 )
  449. {
  450. command = getcmdnum( CMD_GOSUB );
  451. }
  452. else
  453. {
  454. sprintf( bwb_ebuf, ERR_ONNOGOTO );
  455. bwb_error( bwb_ebuf );
  456. return bwb_zline( l );
  457. }
  458. num_lines = 0;
  459. loop = TRUE;
  460. while( loop == TRUE )
  461. {
  462. /* read a line number */
  463. inp_adv( l->buffer, &( l->position ) );
  464. adv_element( l->buffer, &( l->position ), tbuf );
  465. lines[ num_lines ] = atoi( tbuf );
  466. ++num_lines;
  467. if ( num_lines >= MAX_GOLINES )
  468. {
  469. loop = FALSE;
  470. }
  471. /* check for end of line */
  472. adv_ws( l->buffer, &( l->position ) );
  473. switch( l->buffer[ l->position ] )
  474. {
  475. case '\0':
  476. case '\n':
  477. case '\r':
  478. case ':':
  479. loop = FALSE;
  480. break;
  481. }
  482. }
  483. /* advance to end of segment */
  484. #if MULTISEG_LINES
  485. adv_eos( l->buffer, &( l->position ) );
  486. #endif
  487. /* Be sure value is in range */
  488. if ( ( v < 1 ) || ( v > num_lines ))
  489. {
  490. sprintf( bwb_ebuf, err_valoorange );
  491. bwb_error( bwb_ebuf );
  492. return bwb_zline( l );
  493. }
  494. if ( command == getcmdnum( CMD_GOTO ))
  495. {
  496. #if INTENSIVE_DEBUG
  497. sprintf( bwb_ebuf, "in bwb_on(): executing ON...GOTO" );
  498. bwb_debug( bwb_ebuf );
  499. #endif
  500. oline = NULL;
  501. for ( x = &CURTASK bwb_start; x != &CURTASK bwb_end; x = x->next )
  502. {
  503. if ( x->number == lines[ v - 1 ] )
  504. {
  505. /* found the requested number */
  506. #if INTENSIVE_DEBUG
  507. sprintf( bwb_ebuf, "in bwb_on(): returning line <%d>", x->number );
  508. bwb_debug( bwb_ebuf );
  509. #endif
  510. oline = x;
  511. }
  512. }
  513. if ( oline == NULL )
  514. {
  515. bwb_error( err_lnnotfound );
  516. return bwb_zline( l );
  517. }
  518. oline->position = 0;
  519. bwb_setexec( oline, 0, CURTASK excs[ CURTASK exsc ].code );
  520. return oline;
  521. }
  522. else if ( command == getcmdnum( CMD_GOSUB ))
  523. {
  524. #if INTENSIVE_DEBUG
  525. sprintf( bwb_ebuf, "in bwb_on(): executing ON...GOSUB" );
  526. bwb_debug( bwb_ebuf );
  527. #endif
  528. /* save current stack level */
  529. bwb_setexec( l, l->position, CURTASK excs[ CURTASK exsc ].code );
  530. /* increment exec stack */
  531. bwb_incexec();
  532. /* get memory for line and buffer */
  533. /* Revised to CALLOC pass-thru call by JBV */
  534. if ( ( oline = CALLOC( 1, sizeof( struct bwb_line ), "bwb_on") ) == NULL )
  535. {
  536. #if PROG_ERRORS
  537. bwb_error( "in bwb_on(): failed to find memory for oline" );
  538. #else
  539. bwb_error( err_getmem );
  540. #endif
  541. }
  542. /* Revised to CALLOC pass-thru call by JBV */
  543. if ( ( oline->buffer = CALLOC( 1, MAXSTRINGSIZE + 1, "bwb_on") ) == NULL )
  544. {
  545. #if PROG_ERRORS
  546. bwb_error( "in bwb_on(): failed to find memory for oline buffer" );
  547. #else
  548. bwb_error( err_getmem );
  549. #endif
  550. }
  551. CURTASK excs[ CURTASK exsc ].while_line = oline;
  552. sprintf( oline->buffer, "%s %d", CMD_GOSUB, lines[ v - 1 ] );
  553. oline->marked = FALSE;
  554. oline->position = 0;
  555. oline->next = l->next;
  556. bwb_setexec( oline, 0, EXEC_ON );
  557. return oline;
  558. }
  559. else
  560. {
  561. #if PROG_ERRORS
  562. sprintf( bwb_ebuf, "in bwb_on(): invalid value for command." );
  563. bwb_error( bwb_ebuf );
  564. #else
  565. bwb_error( err_syntax );
  566. #endif
  567. return bwb_zline( l );
  568. }
  569. }
  570. /***************************************************************
  571. FUNCTION: bwb_stop()
  572. DESCRIPTION: This C function implements the BASIC
  573. STOP command, interrupting program flow
  574. at a specific point.
  575. SYNTAX: STOP
  576. ***************************************************************/
  577. #if ANSI_C
  578. struct bwb_line *
  579. bwb_stop( struct bwb_line *l )
  580. #else
  581. struct bwb_line *
  582. bwb_stop( l )
  583. struct bwb_line *l;
  584. #endif
  585. {
  586. #if HAVE_SIGNAL
  587. #if HAVE_RAISE
  588. raise( SIGINT );
  589. #else
  590. kill( getpid(), SIGINT );
  591. #endif
  592. #endif
  593. return bwb_xend( l );
  594. }
  595. /***************************************************************
  596. FUNCTION: bwb_xend()
  597. DESCRIPTION: This C function implements the BASIC
  598. END command, checking for END SUB
  599. or END FUNCTION, else stopping program
  600. execution for a simple END command.
  601. ***************************************************************/
  602. #if ANSI_C
  603. struct bwb_line *
  604. bwb_xend( struct bwb_line *l )
  605. #else
  606. struct bwb_line *
  607. bwb_xend( l )
  608. struct bwb_line *l;
  609. #endif
  610. {
  611. #if STRUCT_CMDS
  612. char tbuf[ MAXSTRINGSIZE + 1 ];
  613. #endif
  614. #if INTENSIVE_DEBUG
  615. sprintf( bwb_ebuf, "in bwb_xend(): entered funtion" );
  616. bwb_debug( bwb_ebuf );
  617. #endif
  618. /* Detect END SUB or END FUNCTION here */
  619. #if STRUCT_CMDS
  620. adv_element( l->buffer, &( l->position ), tbuf );
  621. bwb_strtoupper( tbuf );
  622. if ( strcmp( tbuf, CMD_XSUB ) == 0 )
  623. {
  624. return bwb_endsub( l );
  625. }
  626. if ( strcmp( tbuf, CMD_XFUNCTION ) == 0 )
  627. {
  628. return bwb_endfnc( l );
  629. }
  630. if ( strcmp( tbuf, CMD_XIF ) == 0 )
  631. {
  632. return bwb_endif( l );
  633. }
  634. if ( strcmp( tbuf, CMD_XSELECT ) == 0 )
  635. {
  636. return bwb_endselect( l );
  637. }
  638. #endif /* STRUCT_CMDS */
  639. /* else a simple END statement */
  640. break_handler();
  641. return &CURTASK bwb_end;
  642. }
  643. /***************************************************************
  644. FUNCTION: bwb_do()
  645. DESCRIPTION: This C function implements the BASIC DO
  646. command, also checking for the DO NUM
  647. and DO UNNUM commands for interactive
  648. programming environment.
  649. ***************************************************************/
  650. #if ANSI_C
  651. struct bwb_line *
  652. bwb_do( struct bwb_line *l )
  653. #else
  654. struct bwb_line *
  655. bwb_do( l )
  656. struct bwb_line *l;
  657. #endif
  658. {
  659. char tbuf[ MAXSTRINGSIZE + 1 ];
  660. adv_element( l->buffer, &( l->position ), tbuf );
  661. bwb_strtoupper( tbuf );
  662. /* if there is no argument (with STRUCT_CMDS) then we have a
  663. DO-LOOP structure: pass on to bwb_doloop() in bwb_stc.c */
  664. #if STRUCT_CMDS
  665. if ( strlen( tbuf ) == 0 )
  666. {
  667. return bwb_doloop( l );
  668. }
  669. if ( strcmp( tbuf, CMD_WHILE ) == 0 )
  670. {
  671. return bwb_while( l );
  672. }
  673. #endif
  674. #if INTERACTIVE
  675. if ( strcmp( tbuf, CMD_XNUM ) == 0 )
  676. {
  677. return bwb_donum( l );
  678. }
  679. if ( strcmp( tbuf, CMD_XUNNUM ) == 0 )
  680. {
  681. return bwb_dounnum( l );
  682. }
  683. #endif /* INTERACTIVE */
  684. /* if none of these occurred, then presume an error */
  685. bwb_error( err_syntax );
  686. return bwb_zline( l );
  687. }
  688. /***************************************************************
  689. FUNCTION: bwb_run()
  690. DESCRIPTION: This C function implements the BASIC
  691. RUN command.
  692. Even though RUN is not a core statement,
  693. the function bwb_run() is called from
  694. core, so it must be present for a minimal
  695. implementation.
  696. SYNTAX: RUN [line]|[file-name]
  697. ***************************************************************/
  698. #if ANSI_C
  699. struct bwb_line *
  700. bwb_run( struct bwb_line *l )
  701. #else
  702. struct bwb_line *
  703. bwb_run( l )
  704. struct bwb_line *l;
  705. #endif
  706. {
  707. struct bwb_line *current, *x;
  708. int go_lnumber; /* line number to go to */
  709. char tbuf[ MAXSTRINGSIZE + 1 ];
  710. struct exp_ese *e;
  711. FILE *input;
  712. #if INTENSIVE_DEBUG
  713. sprintf( bwb_ebuf, "in bwb_run(): entered function. buffer <%s> pos <%d>",
  714. l->buffer, l->position );
  715. bwb_debug( bwb_ebuf );
  716. #endif
  717. /* see if there is an element */
  718. current = NULL;
  719. adv_ws( l->buffer, &( l->position ) );
  720. #if INTENSIVE_DEBUG
  721. sprintf( bwb_ebuf, "in bwb_run(): check buffer <%s> pos <%d> char <0x%x>",
  722. l->buffer, l->position, l->buffer[ l->position ] );
  723. bwb_debug( bwb_ebuf );
  724. #endif
  725. switch ( l->buffer[ l->position ] )
  726. {
  727. case '\0':
  728. case '\n':
  729. case '\r':
  730. case ':':
  731. #if INTENSIVE_DEBUG
  732. sprintf( bwb_ebuf, "in bwb_run(): no argument; begin at start.next" );
  733. bwb_debug( bwb_ebuf );
  734. #endif
  735. current = CURTASK bwb_start.next;
  736. e = NULL;
  737. break;
  738. default:
  739. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  740. break;
  741. }
  742. /* check its type: if it is a string, open the file and execute it */
  743. if (( e != NULL ) && ( e->type == STRING ))
  744. {
  745. bwb_new( l ); /* clear memory */
  746. str_btoc( tbuf, exp_getsval( e ) ); /* get string in tbuf */
  747. if ( ( input = fopen( tbuf, "r" )) == NULL ) /* open file */
  748. {
  749. sprintf( bwb_ebuf, err_openfile, tbuf );
  750. bwb_error( bwb_ebuf );
  751. }
  752. bwb_fload( input ); /* load program */
  753. /* Next line removed by JBV (unnecessary recursion asks for trouble) */
  754. /* bwb_run( &CURTASK bwb_start ); */ /* and call bwb_run() recursively */
  755. current = &CURTASK bwb_start; /* JBV */
  756. }
  757. /* else if it is a line number, execute the program in memory
  758. at that line number */
  759. /* Removed by JBV */
  760. /* else
  761. { */
  762. /* Removed by JBV */
  763. /* if ( current == NULL )
  764. { */
  765. /* Added expression type check and changed loop boundaries (JBV) */
  766. if (( e != NULL ) && ( e->type != STRING ))
  767. {
  768. go_lnumber = (int) exp_getnval( e );
  769. #if INTENSIVE_DEBUG
  770. sprintf( bwb_ebuf, "in bwb_run(): element detected <%s>, lnumber <%d>",
  771. tbuf, go_lnumber );
  772. bwb_debug( bwb_ebuf );
  773. #endif
  774. for ( x = CURTASK bwb_start.next; x != &CURTASK bwb_end; x = x->next )
  775. {
  776. if ( x->number == go_lnumber )
  777. {
  778. current = x;
  779. }
  780. }
  781. }
  782. /* } */ /* Removed by JBV */
  783. if ( current == NULL )
  784. {
  785. sprintf( bwb_ebuf, err_lnnotfound, go_lnumber );
  786. bwb_error( bwb_ebuf );
  787. return &CURTASK bwb_end;
  788. }
  789. #if INTENSIVE_DEBUG
  790. sprintf( bwb_ebuf, "in bwb_run(): ready to run starting at line %d",
  791. current->number );
  792. bwb_debug( bwb_ebuf );
  793. #endif
  794. if ( CURTASK rescan == TRUE )
  795. {
  796. bwb_scan();
  797. }
  798. current->position = 0;
  799. CURTASK exsc = 0;
  800. bwb_setexec( current, 0, EXEC_NORM );
  801. /* } */ /* Removed by JBV */
  802. #if INTENSIVE_DEBUG
  803. sprintf( bwb_ebuf, "in bwb_run(): function complete." );
  804. bwb_debug( bwb_ebuf );
  805. #endif
  806. return current;
  807. }
  808. /***************************************************************
  809. FUNCTION: bwb_new()
  810. DESCRIPTION: This C function implements the BASIC
  811. NEW command.
  812. Even though NEW is not a core statement,
  813. the function bwb_run() is called from
  814. core, so it must be present for a minimal
  815. implementation.
  816. SYNTAX: NEW
  817. ***************************************************************/
  818. #if ANSI_C
  819. struct bwb_line *
  820. bwb_new( struct bwb_line *l )
  821. #else
  822. struct bwb_line *
  823. bwb_new( l )
  824. struct bwb_line *l;
  825. #endif
  826. {
  827. /* clear program in memory */
  828. bwb_xnew( l );
  829. /* clear all variables */
  830. bwb_clear( l );
  831. return bwb_zline( l );
  832. }
  833. /* End of Core Functions Section */
  834. #if INTERACTIVE
  835. /***************************************************************
  836. FUNCTION: bwb_system()
  837. DESCRIPTION: This C function implements the BASIC
  838. SYSTEM command, exiting to the operating
  839. system (or calling program). It is also
  840. called by the QUIT command, a functional
  841. equivalent for SYSTEM in Bywater BASIC.
  842. SYNTAX: SYSTEM
  843. QUIT
  844. ***************************************************************/
  845. #if ANSI_C
  846. struct bwb_line *
  847. bwb_system( struct bwb_line *l )
  848. #else
  849. struct bwb_line *
  850. bwb_system( l )
  851. struct bwb_line *l;
  852. #endif
  853. {
  854. prn_xprintf( stdout, "\n" );
  855. #if INTENSIVE_DEBUG
  856. bwb_debug( "in bwb_system(): ready to exit" );
  857. #endif
  858. bwx_terminate();
  859. return &CURTASK bwb_end; /* to make LINT happy */
  860. }
  861. /***************************************************************
  862. FUNCTION: bwb_load()
  863. DESCRIPTION: This C function implements the BASIC
  864. LOAD command.
  865. SYNTAX: LOAD file-name
  866. ***************************************************************/
  867. #if ANSI_C
  868. struct bwb_line *
  869. bwb_load( struct bwb_line *l )
  870. #else
  871. struct bwb_line *
  872. bwb_load( l )
  873. struct bwb_line *l;
  874. #endif
  875. {
  876. /* clear current contents */
  877. bwb_new( l );
  878. /* call xload function to load program in memory */
  879. bwb_xload( l );
  880. return bwb_zline( l );
  881. }
  882. /***************************************************************
  883. FUNCTION: bwb_xload()
  884. DESCRIPTION: This C function loads a BASIC program
  885. into memory.
  886. ***************************************************************/
  887. #if ANSI_C
  888. struct bwb_line *
  889. bwb_xload( struct bwb_line *l )
  890. #else
  891. struct bwb_line *
  892. bwb_xload( l )
  893. struct bwb_line *l;
  894. #endif
  895. {
  896. FILE *loadfile;
  897. struct exp_ese *e; /* JBV */
  898. /* Get an argument for filename */
  899. adv_ws( l->buffer, &( l->position ) );
  900. switch( l->buffer[ l->position ] )
  901. {
  902. case '\0':
  903. case '\n':
  904. case '\r':
  905. case ':':
  906. bwb_error( err_nofn ); /* Added by JBV (bug found by DD) */
  907. return bwb_zline( l );
  908. default:
  909. break;
  910. }
  911. /* Section added by JBV (bug found by DD) */
  912. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  913. if ( e->type != STRING )
  914. {
  915. #if PROG_ERRORS
  916. sprintf( bwb_ebuf, "in bwb_xload(): Missing filespec" );
  917. bwb_error( bwb_ebuf );
  918. #else
  919. bwb_error( err_syntax );
  920. #endif
  921. return bwb_zline( l );
  922. }
  923. /* This line removed by JBV (no longer required) */
  924. /* bwb_const( l->buffer, CURTASK progfile, &( l->position ) ); */
  925. str_btoc( CURTASK progfile, exp_getsval( e ) ); /* JBV */
  926. if ( ( loadfile = fopen( CURTASK progfile, "r" )) == NULL )
  927. {
  928. sprintf( bwb_ebuf, err_openfile, CURTASK progfile );
  929. bwb_error( bwb_ebuf );
  930. return bwb_zline( l );
  931. }
  932. bwb_fload( loadfile );
  933. return bwb_zline( l );
  934. }
  935. /***************************************************************
  936. FUNCTION: bwb_save()
  937. DESCRIPTION: This C function implements the BASIC
  938. SAVE command.
  939. SYNTAX: SAVE file-name
  940. ***************************************************************/
  941. #if ANSI_C
  942. struct bwb_line *
  943. bwb_save( struct bwb_line *l )
  944. #else
  945. struct bwb_line *
  946. bwb_save( l )
  947. struct bwb_line *l;
  948. #endif
  949. {
  950. FILE *outfile;
  951. static char filename[ MAXARGSIZE ];
  952. struct exp_ese *e; /* JBV */
  953. #if INTENSIVE_DEBUG
  954. sprintf( bwb_ebuf, "in bwb_save(): entered function." );
  955. bwb_debug( bwb_ebuf );
  956. #endif
  957. /* Get an argument for filename */
  958. adv_ws( l->buffer, &( l->position ) );
  959. switch( l->buffer[ l->position ] )
  960. {
  961. case '\0':
  962. case '\n':
  963. case '\r':
  964. case ':':
  965. bwb_error( err_nofn );
  966. return bwb_zline( l );
  967. default:
  968. break;
  969. }
  970. /* Section added by JBV (bug found by DD) */
  971. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  972. if ( e->type != STRING )
  973. {
  974. #if PROG_ERRORS
  975. sprintf( bwb_ebuf, "in bwb_save(): Missing filespec" );
  976. bwb_error( bwb_ebuf );
  977. #else
  978. bwb_error( err_syntax );
  979. #endif
  980. return bwb_zline( l );
  981. }
  982. /* This line removed by JBV (no longer required) */
  983. /* bwb_const( l->buffer, filename, &( l->position ) ); */
  984. str_btoc( filename, exp_getsval( e ) ); /* JBV */
  985. if ( ( outfile = fopen( filename, "w" )) == NULL )
  986. {
  987. sprintf( bwb_ebuf, err_openfile, filename );
  988. bwb_error( bwb_ebuf );
  989. return bwb_zline( l );
  990. }
  991. bwb_xlist( l, outfile );
  992. fclose( outfile );
  993. return bwb_zline( l );
  994. }
  995. /***************************************************************
  996. FUNCTION: bwb_list()
  997. DESCRIPTION: This C function implements the BASIC
  998. LIST command.
  999. SYNTAX: LIST line[-line]
  1000. ***************************************************************/
  1001. #if ANSI_C
  1002. struct bwb_line *
  1003. bwb_list( struct bwb_line *l )
  1004. #else
  1005. struct bwb_line *
  1006. bwb_list( l )
  1007. struct bwb_line *l;
  1008. #endif
  1009. {
  1010. bwb_xlist( l, stdout );
  1011. return bwb_zline( l );
  1012. }
  1013. /***************************************************************
  1014. FUNCTION: bwb_xlist()
  1015. DESCRIPTION: This C function lists the program in
  1016. memory to a specified output device.
  1017. ***************************************************************/
  1018. #if ANSI_C
  1019. struct bwb_line *
  1020. bwb_xlist( struct bwb_line *l, FILE *file )
  1021. #else
  1022. struct bwb_line *
  1023. bwb_xlist( l, file )
  1024. struct bwb_line *l;
  1025. FILE *file;
  1026. #endif
  1027. {
  1028. struct bwb_line *start, *end, *current;
  1029. int s, e;
  1030. int f, r;
  1031. start = CURTASK bwb_start.next;
  1032. end = &CURTASK bwb_end;
  1033. r = bwb_numseq( &( l->buffer[ l->position ] ), &s, &e );
  1034. /* advance to the end of the segment */
  1035. #if MULTISEG_LINES
  1036. adv_eos( l->buffer, &( l->position ));
  1037. #endif
  1038. if (( r == FALSE ) || ( s == 0 ))
  1039. {
  1040. s = CURTASK bwb_start.next->number;
  1041. }
  1042. if ( e == 0 )
  1043. {
  1044. e = s;
  1045. }
  1046. if ( r == FALSE )
  1047. {
  1048. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1049. {
  1050. if ( current->next == &CURTASK bwb_end )
  1051. {
  1052. e = current->number;
  1053. }
  1054. }
  1055. }
  1056. #if INTENSIVE_DEBUG
  1057. sprintf( bwb_ebuf, "in bwb_xlist(): LBUFFER sequence is %d-%d", s, e );
  1058. bwb_debug( bwb_ebuf );
  1059. #endif
  1060. /* abort if either number == (MAXLINENO + 1) which denotes CURTASK bwb_end */
  1061. if ( ( s == (MAXLINENO + 1)) || ( e == (MAXLINENO + 1 ) ) )
  1062. {
  1063. return bwb_zline( l );
  1064. }
  1065. /* Now try to find the actual lines in memory */
  1066. f = FALSE;
  1067. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1068. {
  1069. if ( current != l )
  1070. {
  1071. if (( current->number == s ) && ( f == FALSE ))
  1072. {
  1073. f = TRUE;
  1074. start = current;
  1075. #if INTENSIVE_DEBUG
  1076. sprintf( bwb_ebuf, "in bwb_xlist(): start line number is <%d>",
  1077. s );
  1078. bwb_debug( bwb_ebuf );
  1079. #endif
  1080. }
  1081. }
  1082. }
  1083. /* check and see if a line number was found */
  1084. if ( f == FALSE )
  1085. {
  1086. sprintf( bwb_ebuf, err_lnnotfound, s );
  1087. bwb_error( bwb_ebuf );
  1088. return bwb_zline( l );
  1089. }
  1090. if ( e >= s )
  1091. {
  1092. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1093. {
  1094. if ( current != l )
  1095. {
  1096. if ( current->number == e )
  1097. {
  1098. #if INTENSIVE_DEBUG
  1099. sprintf( bwb_ebuf, "in bwb_xlist(): end line number is <%d>",
  1100. current->next->number );
  1101. bwb_debug( bwb_ebuf );
  1102. #endif
  1103. end = current->next;
  1104. }
  1105. }
  1106. }
  1107. }
  1108. else
  1109. {
  1110. end = start;
  1111. }
  1112. #if INTENSIVE_DEBUG
  1113. sprintf( bwb_ebuf, "in bwb_xlist(): line sequence is <%d-%d>",
  1114. start->number, end->number );
  1115. bwb_debug( bwb_ebuf );
  1116. #endif
  1117. /* previous should now be set to the line previous to the
  1118. first in the omission list */
  1119. /* now go through and list appropriate lines */
  1120. if ( start == end )
  1121. {
  1122. #if INTENSIVE_DEBUG
  1123. sprintf( bwb_ebuf, "in bwb_xlist(): start == end" );
  1124. bwb_debug( bwb_ebuf );
  1125. #endif
  1126. xl_line( file, start );
  1127. }
  1128. else
  1129. {
  1130. for ( current = start; current != end; current = current->next )
  1131. {
  1132. xl_line( file, current );
  1133. }
  1134. }
  1135. return bwb_zline( l );
  1136. }
  1137. /***************************************************************
  1138. FUNCTION: xl_line()
  1139. DESCRIPTION: This function lists a single program
  1140. line to a specified device of file.
  1141. It is called by bwb_xlist();
  1142. ***************************************************************/
  1143. #if ANSI_C
  1144. static int
  1145. xl_line( FILE *file, struct bwb_line *l )
  1146. #else
  1147. static int
  1148. xl_line( file, l )
  1149. FILE *file;
  1150. struct bwb_line *l;
  1151. #endif
  1152. {
  1153. char tbuf[ MAXSTRINGSIZE + 1 ];
  1154. if (( file == stdout ) || ( file == stderr ))
  1155. {
  1156. if ( l->xnum == (char) TRUE ) /* Better recast this one (JBV) */
  1157. {
  1158. sprintf( tbuf, "%7d: %s\n", l->number, l->buffer );
  1159. }
  1160. else
  1161. {
  1162. sprintf( tbuf, " : %s\n", l->buffer );
  1163. }
  1164. prn_xprintf( file, tbuf );
  1165. }
  1166. else
  1167. {
  1168. if ( l->xnum == (char) TRUE ) /* Better recast this one (JBV) */
  1169. {
  1170. fprintf( file, "%d %s\n", l->number, l->buffer );
  1171. }
  1172. else
  1173. {
  1174. fprintf( file, "%s\n", l->buffer );
  1175. }
  1176. }
  1177. return TRUE;
  1178. }
  1179. /***************************************************************
  1180. FUNCTION: bwb_delete()
  1181. DESCRIPTION: This C function implements the BASIC
  1182. DELETE command for interactive programming,
  1183. deleting a specified program line (or lines)
  1184. from memory.
  1185. SYNTAX: DELETE line[-line]
  1186. ***************************************************************/
  1187. #if ANSI_C
  1188. struct bwb_line *
  1189. bwb_delete( struct bwb_line *l )
  1190. #else
  1191. struct bwb_line *
  1192. bwb_delete( l )
  1193. struct bwb_line *l;
  1194. #endif
  1195. {
  1196. struct bwb_line *start, *end, *current, *previous, *p, *next;
  1197. static int s, e;
  1198. int f;
  1199. previous = &CURTASK bwb_start;
  1200. start = CURTASK bwb_start.next;
  1201. end = &CURTASK bwb_end;
  1202. bwb_numseq( &( l->buffer[ l->position ] ), &s, &e );
  1203. #if INTENSIVE_DEBUG
  1204. sprintf( bwb_ebuf, "in bwb_delete(): LBUFFER sequence is %d-%d", s, e );
  1205. bwb_debug( bwb_ebuf );
  1206. #endif
  1207. /* advance to the end of the segment */
  1208. #if MULTISEG_LINES
  1209. adv_eos( l->buffer, &( l->position ));
  1210. #endif
  1211. /* Now try to find the actual lines in memory */
  1212. previous = p = &CURTASK bwb_start;
  1213. f = FALSE;
  1214. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1215. {
  1216. if ( current != l )
  1217. {
  1218. /* Following line revised by JBV */
  1219. if (( current->xnum == (char) TRUE ) && ( current->number == s ))
  1220. {
  1221. f = TRUE;
  1222. previous = p;
  1223. start = current;
  1224. #if INTENSIVE_DEBUG
  1225. sprintf( bwb_ebuf, "in bwb_delete(): start line number is <%d>",
  1226. s );
  1227. bwb_debug( bwb_ebuf );
  1228. #endif
  1229. }
  1230. }
  1231. p = current;
  1232. }
  1233. /* check and see if a line number was found */
  1234. if ( f == FALSE )
  1235. {
  1236. sprintf( bwb_ebuf, err_lnnotfound, s );
  1237. bwb_error( bwb_ebuf );
  1238. return bwb_zline( l );
  1239. }
  1240. if ( e > s )
  1241. {
  1242. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1243. {
  1244. if ( current != l )
  1245. {
  1246. /* Following line revised by JBV */
  1247. if (( current->xnum == (char) TRUE) && ( current->number == e ))
  1248. {
  1249. #if INTENSIVE_DEBUG
  1250. sprintf( bwb_ebuf, "in bwb_delete(): end line number is <%d>",
  1251. e );
  1252. bwb_debug( bwb_ebuf );
  1253. #endif
  1254. end = current->next;
  1255. }
  1256. }
  1257. }
  1258. }
  1259. else
  1260. {
  1261. end = start->next;
  1262. }
  1263. /* previous should now be set to the line previous to the
  1264. first in the omission list */
  1265. /* now go through and delete appropriate lines */
  1266. current = start;
  1267. while (( current != end ) && ( current != &CURTASK bwb_end ))
  1268. {
  1269. next = current->next;
  1270. #if INTENSIVE_DEBUG
  1271. sprintf( bwb_ebuf, "in bwb_delete(): deleting line %d",
  1272. current->number );
  1273. bwb_debug( bwb_ebuf );
  1274. #endif
  1275. /* free line memory */
  1276. bwb_freeline( current );
  1277. /* recycle */
  1278. current = next;
  1279. }
  1280. /* reset link */
  1281. previous->next = current;
  1282. return bwb_zline( l );
  1283. }
  1284. /***************************************************************
  1285. FUNCTION: bwb_donum()
  1286. DESCRIPTION: This function implements the BASIC DO
  1287. NUM command, numbering all program lines
  1288. in memory in increments of 10 beginning
  1289. at 10.
  1290. SYNTAX: DO NUM
  1291. ***************************************************************/
  1292. #if ANSI_C
  1293. struct bwb_line *
  1294. bwb_donum( struct bwb_line *l )
  1295. #else
  1296. struct bwb_line *
  1297. bwb_donum( l )
  1298. struct bwb_line *l;
  1299. #endif
  1300. {
  1301. struct bwb_line *current;
  1302. register int lnumber;
  1303. lnumber = 10;
  1304. for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  1305. {
  1306. current->number = lnumber;
  1307. current->xnum = TRUE;
  1308. lnumber += 10;
  1309. if ( lnumber >= MAXLINENO )
  1310. {
  1311. return bwb_zline( l );
  1312. }
  1313. }
  1314. return bwb_zline( l );
  1315. }
  1316. /***************************************************************
  1317. FUNCTION: bwb_dounnum()
  1318. DESCRIPTION: This function implements the BASIC DO
  1319. UNNUM command, removing all line numbers
  1320. from the program in memory.
  1321. SYNTAX: DO UNNUM
  1322. ***************************************************************/
  1323. #if ANSI_C
  1324. struct bwb_line *
  1325. bwb_dounnum( struct bwb_line *l )
  1326. #else
  1327. struct bwb_line *
  1328. bwb_dounnum( l )
  1329. struct bwb_line *l;
  1330. #endif
  1331. {
  1332. struct bwb_line *current;
  1333. for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  1334. {
  1335. current->number = 0;
  1336. current->xnum = FALSE;
  1337. }
  1338. return bwb_zline( l );
  1339. }
  1340. #endif /* INTERACTIVE */
  1341. #if COMMON_CMDS
  1342. /***************************************************************
  1343. FUNCTION: bwb_chain()
  1344. DESCRIPTION: This C function implements the BASIC
  1345. CHAIN command.
  1346. SYNTAX: CHAIN file-name
  1347. ***************************************************************/
  1348. #if ANSI_C
  1349. struct bwb_line *
  1350. bwb_chain( struct bwb_line *l )
  1351. #else
  1352. struct bwb_line *
  1353. bwb_chain( l )
  1354. struct bwb_line *l;
  1355. #endif
  1356. {
  1357. /* deallocate all variables except common ones */
  1358. var_delcvars();
  1359. /* remove old program from memory */
  1360. bwb_xnew( l );
  1361. /* call xload function to load new program in memory */
  1362. bwb_xload( l );
  1363. /* reset all stack counters */
  1364. CURTASK exsc = -1;
  1365. CURTASK expsc = 0;
  1366. CURTASK xtxtsc = 0;
  1367. /* run the program */
  1368. return bwb_run( &CURTASK bwb_start );
  1369. }
  1370. /***************************************************************
  1371. FUNCTION: bwb_merge()
  1372. DESCRIPTION: This C function implements the BASIC
  1373. MERGE command, merging command lines from
  1374. a specified file into the program in memory
  1375. without deleting the lines already in memory.
  1376. SYNTAX: MERGE file-name
  1377. ***************************************************************/
  1378. #if ANSI_C
  1379. struct bwb_line *
  1380. bwb_merge( struct bwb_line *l )
  1381. #else
  1382. struct bwb_line *
  1383. bwb_merge( l )
  1384. struct bwb_line *l;
  1385. #endif
  1386. {
  1387. /* call xload function to merge program in memory */
  1388. bwb_xload( l );
  1389. return bwb_zline( l );
  1390. }
  1391. /***************************************************************
  1392. FUNCTION: bwb_onerror()
  1393. DESCRIPTION: This C function implements the BASIC
  1394. ON ERROR GOSUB command.
  1395. SYNTAX: ON ERROR GOSUB line | label
  1396. ***************************************************************/
  1397. #if ANSI_C
  1398. struct bwb_line *
  1399. bwb_onerror( struct bwb_line *l )
  1400. #else
  1401. struct bwb_line *
  1402. bwb_onerror( l )
  1403. struct bwb_line *l;
  1404. #endif
  1405. {
  1406. char tbuf[ MAXSTRINGSIZE + 1 ];
  1407. #if INTENSIVE_DEBUG
  1408. sprintf( bwb_ebuf, "in bwb_onerror(): entered function" );
  1409. bwb_debug( bwb_ebuf );
  1410. #endif
  1411. /* get the GOSUB STATEMENT */
  1412. adv_element( l->buffer, &( l->position ), tbuf );
  1413. /* check for GOSUB statement */
  1414. bwb_strtoupper( tbuf );
  1415. if ( strcmp( tbuf, CMD_GOSUB ) != 0 )
  1416. {
  1417. #if PROG_ERRORS
  1418. sprintf( bwb_ebuf, "in bwb_onerror(): GOSUB statement missing" );
  1419. bwb_error( bwb_ebuf );
  1420. #else
  1421. bwb_error( err_syntax );
  1422. #endif
  1423. return bwb_zline( l );
  1424. }
  1425. /* get the GOSUB line */
  1426. adv_element( l->buffer, &( l->position ), err_gosubl );
  1427. return bwb_zline( l );
  1428. }
  1429. /***************************************************************
  1430. FUNCTION: bwb_tron()
  1431. DESCRIPTION: This function implements the BASIC TRON
  1432. command, turning the trace mechanism on.
  1433. SYNTAX: TRON
  1434. ***************************************************************/
  1435. #if ANSI_C
  1436. struct bwb_line *
  1437. bwb_tron( struct bwb_line *l )
  1438. #else
  1439. struct bwb_line *
  1440. bwb_tron( l )
  1441. struct bwb_line *l;
  1442. #endif
  1443. {
  1444. bwb_trace = TRUE;
  1445. prn_xprintf( stdout, "Trace is ON\n" );
  1446. return bwb_zline( l );
  1447. }
  1448. /***************************************************************
  1449. FUNCTION: bwb_troff()
  1450. DESCRIPTION: This function implements the BASIC TROFF
  1451. command, turning the trace mechanism off.
  1452. SYNTAX: TROFF
  1453. ***************************************************************/
  1454. #if ANSI_C
  1455. struct bwb_line *
  1456. bwb_troff( struct bwb_line *l )
  1457. #else
  1458. struct bwb_line *
  1459. bwb_troff( l )
  1460. struct bwb_line *l;
  1461. #endif
  1462. {
  1463. bwb_trace = FALSE;
  1464. prn_xprintf( stdout, "Trace is OFF\n" );
  1465. return bwb_zline( l );
  1466. }
  1467. #endif /* COMMON_CMDS */
  1468. /***************************************************************
  1469. FUNCTION: bwb_randomize()
  1470. DESCRIPTION: This function implements the BASIC
  1471. RANDOMIZE command, seeding the pseudo-
  1472. random number generator.
  1473. SYNTAX: RANDOMIZE number
  1474. ***************************************************************/
  1475. #if ANSI_C
  1476. struct bwb_line *
  1477. bwb_randomize( struct bwb_line *l )
  1478. #else
  1479. struct bwb_line *
  1480. bwb_randomize( l )
  1481. struct bwb_line *l;
  1482. #endif
  1483. {
  1484. register unsigned n;
  1485. struct exp_ese *e;
  1486. /* Check for argument */
  1487. adv_ws( l->buffer, &( l->position ) );
  1488. switch( l->buffer[ l->position ] )
  1489. {
  1490. case '\0':
  1491. case '\n':
  1492. case '\r':
  1493. #if MULTISEG_LINES
  1494. case ':':
  1495. #endif
  1496. n = (unsigned) 1;
  1497. break;
  1498. default:
  1499. n = (unsigned) 0;
  1500. break;
  1501. }
  1502. /* get the argument in tbuf */
  1503. if ( n == (unsigned) 0 )
  1504. {
  1505. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  1506. n = (unsigned) exp_getnval( e );
  1507. }
  1508. #if INTENSIVE_DEBUG
  1509. sprintf( bwb_ebuf, "in bwb_randomize(): argument is <%d>", n );
  1510. bwb_debug( bwb_ebuf );
  1511. #endif
  1512. srand( n );
  1513. return bwb_zline( l );
  1514. }
  1515. /***************************************************************
  1516. FUNCTION: bwb_xnew()
  1517. DESCRIPTION: Clears the program in memory, but does not
  1518. deallocate all variables.
  1519. ***************************************************************/
  1520. #if ANSI_C
  1521. struct bwb_line *
  1522. bwb_xnew( struct bwb_line *l )
  1523. #else
  1524. struct bwb_line *
  1525. bwb_xnew( l )
  1526. struct bwb_line *l;
  1527. #endif
  1528. {
  1529. struct bwb_line *current, *previous;
  1530. int wait;
  1531. wait = TRUE;
  1532. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1533. {
  1534. if ( wait != TRUE )
  1535. {
  1536. /* Revised to FREE pass-thru call by JBV */
  1537. FREE( previous, "bwb_xnew" );
  1538. previous = NULL; /* JBV */
  1539. }
  1540. wait = FALSE;
  1541. previous = current;
  1542. }
  1543. CURTASK bwb_start.next = &CURTASK bwb_end;
  1544. return bwb_zline( l );
  1545. }
  1546. #if UNIX_CMDS
  1547. /***************************************************************
  1548. FUNCTION: bwb_environ()
  1549. DESCRIPTION: This C function implements the BASIC
  1550. ENVIRON command, assigning a string
  1551. value to an environment variable.
  1552. SYNTAX: ENVIRON variable-string$ = string$
  1553. ***************************************************************/
  1554. #if ANSI_C
  1555. struct bwb_line *
  1556. bwb_environ( struct bwb_line *l )
  1557. #else
  1558. struct bwb_line *
  1559. bwb_environ( l )
  1560. struct bwb_line *l;
  1561. #endif
  1562. {
  1563. static char tbuf[ MAXSTRINGSIZE + 1 ];
  1564. char tmp[ MAXSTRINGSIZE + 1 ];
  1565. register int i;
  1566. int pos;
  1567. struct exp_ese *e;
  1568. /* find the equals sign */
  1569. for ( i = 0; ( l->buffer[ l->position ] != '=' ) && ( l->buffer[ l->position ] != '\0' ); ++i )
  1570. {
  1571. tbuf[ i ] = l->buffer[ l->position ];
  1572. tbuf[ i + 1 ] = '\0';
  1573. ++( l->position );
  1574. }
  1575. #if INTENSIVE_DEBUG
  1576. sprintf( bwb_ebuf, "in bwb_environ(): variable string is <%s>", tbuf );
  1577. bwb_debug( bwb_ebuf );
  1578. #endif
  1579. /* get the value string to be assigned */
  1580. pos = 0;
  1581. e = bwb_exp( tbuf, FALSE, &pos );
  1582. str_btoc( tbuf, exp_getsval( e ) );
  1583. #if INTENSIVE_DEBUG
  1584. sprintf( bwb_ebuf, "in bwb_environ(): variable string resolves to <%s>", tbuf );
  1585. bwb_debug( bwb_ebuf );
  1586. #endif
  1587. /* find the equals sign */
  1588. adv_ws( l->buffer, &( l->position ) );
  1589. if ( l->buffer[ l->position ] != '=' )
  1590. {
  1591. #if PROG_ERRORS
  1592. sprintf( bwb_ebuf, "in bwb_environ(): failed to find equal sign" );
  1593. bwb_error( bwb_ebuf );
  1594. #else
  1595. bwb_error( err_syntax );
  1596. #endif
  1597. return bwb_zline( l );
  1598. }
  1599. ++( l->position );
  1600. /* get the value string to be assigned */
  1601. e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1602. str_btoc( tmp, exp_getsval( e ) );
  1603. #if INTENSIVE_DEBUG
  1604. sprintf( bwb_ebuf, "in bwb_environ(): value string resolves to <%s>", tmp );
  1605. bwb_debug( bwb_ebuf );
  1606. #endif
  1607. /* construct string */
  1608. strcat( tbuf, "=" );
  1609. strcat( tbuf, tmp );
  1610. #if INTENSIVE_DEBUG
  1611. sprintf( bwb_ebuf, "in bwb_environ(): assignment string is <%s>", tbuf );
  1612. bwb_debug( bwb_ebuf );
  1613. #endif
  1614. /* now assign value to variable */
  1615. if ( putenv( tbuf ) == -1 )
  1616. {
  1617. bwb_error( err_opsys );
  1618. return bwb_zline( l );
  1619. }
  1620. /* return */
  1621. return bwb_zline( l );
  1622. }
  1623. #endif /* UNIX_CMDS */
  1624. /***************************************************************
  1625. FUNCTION: bwb_cmds()
  1626. DESCRIPTION: This function implements a CMD command,
  1627. which lists all commands implemented.
  1628. It is not part of a BASIC specification,
  1629. but is used for debugging bwBASIC.
  1630. SYNTAX: CMDS
  1631. ***************************************************************/
  1632. #if PERMANENT_DEBUG
  1633. #if ANSI_C
  1634. struct bwb_line *
  1635. bwb_cmds( struct bwb_line *l )
  1636. #else
  1637. struct bwb_line *
  1638. bwb_cmds( l )
  1639. struct bwb_line *l;
  1640. #endif
  1641. {
  1642. register int n;
  1643. char tbuf[ MAXSTRINGSIZE + 1 ];
  1644. prn_xprintf( stdout, "BWBASIC COMMANDS AVAILABLE: \n" );
  1645. /* run through the command table and print comand names */
  1646. for ( n = 0; n < COMMANDS; ++n )
  1647. {
  1648. sprintf( tbuf, "%s \n", bwb_cmdtable[ n ].name );
  1649. prn_xprintf( stdout, tbuf );
  1650. }
  1651. return bwb_zline( l );
  1652. }
  1653. #endif
  1654. /***************************************************************
  1655. FUNCTION: getcmdnum()
  1656. DESCRIPTION: This function returns the number associated
  1657. with a specified command (cmdstr) in the
  1658. command table.
  1659. ***************************************************************/
  1660. #if ANSI_C
  1661. int
  1662. getcmdnum( char *cmdstr )
  1663. #else
  1664. int
  1665. getcmdnum( cmdstr )
  1666. char *cmdstr;
  1667. #endif
  1668. {
  1669. register int c;
  1670. for ( c = 0; c < COMMANDS; ++c )
  1671. {
  1672. if ( strcmp( bwb_cmdtable[ c ].name, cmdstr ) == 0 )
  1673. {
  1674. return c;
  1675. }
  1676. }
  1677. return -1;
  1678. }
  1679. /***************************************************************
  1680. FUNCTION: bwb_zline()
  1681. DESCRIPTION: This function is called at the exit from
  1682. Bywater BASIC command functions. If
  1683. MULTISEG_LINES is TRUE, then it returns
  1684. a pointer to the current line; otherwise it
  1685. sets the position in the next line to zero
  1686. and returns a pointer to the next line.
  1687. ***************************************************************/
  1688. #if ANSI_C
  1689. extern struct bwb_line *
  1690. bwb_zline( struct bwb_line *l )
  1691. #else
  1692. struct bwb_line *
  1693. bwb_zline( l )
  1694. struct bwb_line *l;
  1695. #endif
  1696. {
  1697. #if MULTISEG_LINES
  1698. /* l->marked = FALSE; */
  1699. return l;
  1700. #else
  1701. l->next->position = 0;
  1702. return l->next;
  1703. #endif
  1704. }