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.
 
 
 
 
 
 

2293 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. /* JBV 1/20/97 */
  358. /*
  359. if ( CURTASK excs[ CURTASK exsc ].code != EXEC_GOSUB )
  360. {
  361. bwb_error( err_retnogosub );
  362. }
  363. */
  364. /*--------------------------------------------------------------*/
  365. /* Make sure we are at the right stack level! */
  366. /* If we aren't (which could happen for legit reasons), fix the */
  367. /* exec stack. */
  368. /* JBV, 1/20/97 */
  369. /*--------------------------------------------------------------*/
  370. while ( CURTASK excs[ CURTASK exsc ].code != EXEC_GOSUB )
  371. {
  372. bwb_decexec();
  373. if ( CURTASK excs[ CURTASK exsc ].code == EXEC_NORM ) /* End of the line? */
  374. {
  375. bwb_error( err_retnogosub );
  376. }
  377. }
  378. /* decrement the EXEC stack counter */
  379. bwb_decexec();
  380. /* restore position and return old line */
  381. #if MULTISEG_LINES
  382. CURTASK excs[ CURTASK exsc ].line->position
  383. = CURTASK excs[ CURTASK exsc ].position;
  384. return CURTASK excs[ CURTASK exsc ].line;
  385. #else
  386. CURTASK excs[ CURTASK exsc ].line->next->position = 0;
  387. return CURTASK excs[ CURTASK exsc ].line->next;
  388. #endif
  389. }
  390. /***************************************************************
  391. FUNCTION: bwb_on
  392. DESCRIPTION: This function implements the BASIC ON...
  393. GOTO or ON...GOSUB statements.
  394. It will also detect the ON ERROR... statement
  395. and pass execution to bwb_onerror().
  396. SYNTAX: ON variable GOTO|GOSUB line[,line,line,...]
  397. LIMITATION: As implemented here, the ON...GOSUB|GOTO
  398. command recognizes line numbers only
  399. (not labels).
  400. ***************************************************************/
  401. #if ANSI_C
  402. struct bwb_line *
  403. bwb_on( struct bwb_line *l )
  404. #else
  405. struct bwb_line *
  406. bwb_on( l )
  407. struct bwb_line *l;
  408. #endif
  409. {
  410. struct bwb_line *oline, *x;
  411. char varname[ MAXVARNAMESIZE + 1 ];
  412. char tbuf[ MAXSTRINGSIZE + 1 ];
  413. static int p;
  414. struct exp_ese *rvar;
  415. int v;
  416. int loop;
  417. int num_lines;
  418. int command;
  419. int lines[ MAX_GOLINES ];
  420. char sbuf[ 7 ];
  421. /* Check for argument */
  422. adv_ws( l->buffer, &( l->position ) );
  423. switch( l->buffer[ l->position ] )
  424. {
  425. case '\0':
  426. case '\n':
  427. case '\r':
  428. case ':':
  429. sprintf( bwb_ebuf, err_incomplete );
  430. bwb_error( bwb_ebuf );
  431. return bwb_zline( l );
  432. default:
  433. break;
  434. }
  435. /* get the variable name or numerical constant */
  436. adv_element( l->buffer, &( l->position ), varname );
  437. /* check for ON ERROR statement */
  438. #if COMMON_CMDS
  439. strncpy( sbuf, varname, 6 );
  440. bwb_strtoupper( sbuf );
  441. if ( strcmp( sbuf, CMD_XERROR ) == 0 )
  442. {
  443. #if INTENSIVE_DEBUG
  444. sprintf( bwb_ebuf, "in bwb_on(): detected ON ERROR" );
  445. bwb_debug( bwb_ebuf );
  446. #endif
  447. return bwb_onerror( l );
  448. }
  449. #endif /* COMMON_CMDS */
  450. /* evaluate the variable name or constant */
  451. p = 0;
  452. rvar = bwb_exp( varname, FALSE, &p );
  453. v = (int) exp_getnval( rvar );
  454. #if INTENSIVE_DEBUG
  455. sprintf( bwb_ebuf, "in bwb_on(): value is <%d>", v );
  456. bwb_debug( bwb_ebuf );
  457. #endif
  458. /* Get GOTO or GOSUB statements */
  459. adv_element( l->buffer, &( l->position ), tbuf );
  460. bwb_strtoupper( tbuf );
  461. if ( strncmp( tbuf, CMD_GOTO, (size_t) strlen( CMD_GOTO ) ) == 0 )
  462. {
  463. command = getcmdnum( CMD_GOTO );
  464. }
  465. else if ( strncmp( tbuf, CMD_GOSUB, (size_t) strlen( CMD_GOSUB ) ) == 0 )
  466. {
  467. command = getcmdnum( CMD_GOSUB );
  468. }
  469. else
  470. {
  471. sprintf( bwb_ebuf, ERR_ONNOGOTO );
  472. bwb_error( bwb_ebuf );
  473. return bwb_zline( l );
  474. }
  475. num_lines = 0;
  476. loop = TRUE;
  477. while( loop == TRUE )
  478. {
  479. /* read a line number */
  480. inp_adv( l->buffer, &( l->position ) );
  481. adv_element( l->buffer, &( l->position ), tbuf );
  482. lines[ num_lines ] = atoi( tbuf );
  483. ++num_lines;
  484. if ( num_lines >= MAX_GOLINES )
  485. {
  486. loop = FALSE;
  487. }
  488. /* check for end of line */
  489. adv_ws( l->buffer, &( l->position ) );
  490. switch( l->buffer[ l->position ] )
  491. {
  492. case '\0':
  493. case '\n':
  494. case '\r':
  495. case ':':
  496. loop = FALSE;
  497. break;
  498. }
  499. }
  500. /* advance to end of segment */
  501. #if MULTISEG_LINES
  502. adv_eos( l->buffer, &( l->position ) );
  503. #endif
  504. /* Be sure value is in range */
  505. if ( ( v < 1 ) || ( v > num_lines ))
  506. {
  507. sprintf( bwb_ebuf, err_valoorange );
  508. bwb_error( bwb_ebuf );
  509. return bwb_zline( l );
  510. }
  511. if ( command == getcmdnum( CMD_GOTO ))
  512. {
  513. #if INTENSIVE_DEBUG
  514. sprintf( bwb_ebuf, "in bwb_on(): executing ON...GOTO" );
  515. bwb_debug( bwb_ebuf );
  516. #endif
  517. oline = NULL;
  518. for ( x = &CURTASK bwb_start; x != &CURTASK bwb_end; x = x->next )
  519. {
  520. if ( x->number == lines[ v - 1 ] )
  521. {
  522. /* found the requested number */
  523. #if INTENSIVE_DEBUG
  524. sprintf( bwb_ebuf, "in bwb_on(): returning line <%d>", x->number );
  525. bwb_debug( bwb_ebuf );
  526. #endif
  527. oline = x;
  528. }
  529. }
  530. if ( oline == NULL )
  531. {
  532. bwb_error( err_lnnotfound );
  533. return bwb_zline( l );
  534. }
  535. oline->position = 0;
  536. bwb_setexec( oline, 0, CURTASK excs[ CURTASK exsc ].code );
  537. return oline;
  538. }
  539. else if ( command == getcmdnum( CMD_GOSUB ))
  540. {
  541. #if INTENSIVE_DEBUG
  542. sprintf( bwb_ebuf, "in bwb_on(): executing ON...GOSUB" );
  543. bwb_debug( bwb_ebuf );
  544. #endif
  545. /* save current stack level */
  546. bwb_setexec( l, l->position, CURTASK excs[ CURTASK exsc ].code );
  547. /* increment exec stack */
  548. bwb_incexec();
  549. /* get memory for line and buffer */
  550. /* Revised to CALLOC pass-thru call by JBV */
  551. if ( ( oline = CALLOC( 1, sizeof( struct bwb_line ), "bwb_on") ) == NULL )
  552. {
  553. #if PROG_ERRORS
  554. bwb_error( "in bwb_on(): failed to find memory for oline" );
  555. #else
  556. bwb_error( err_getmem );
  557. #endif
  558. }
  559. /* Revised to CALLOC pass-thru call by JBV */
  560. if ( ( oline->buffer = CALLOC( 1, MAXSTRINGSIZE + 1, "bwb_on") ) == NULL )
  561. {
  562. #if PROG_ERRORS
  563. bwb_error( "in bwb_on(): failed to find memory for oline buffer" );
  564. #else
  565. bwb_error( err_getmem );
  566. #endif
  567. }
  568. CURTASK excs[ CURTASK exsc ].while_line = oline;
  569. sprintf( oline->buffer, "%s %d", CMD_GOSUB, lines[ v - 1 ] );
  570. oline->marked = FALSE;
  571. oline->position = 0;
  572. oline->next = l->next;
  573. bwb_setexec( oline, 0, EXEC_ON );
  574. return oline;
  575. }
  576. else
  577. {
  578. #if PROG_ERRORS
  579. sprintf( bwb_ebuf, "in bwb_on(): invalid value for command." );
  580. bwb_error( bwb_ebuf );
  581. #else
  582. bwb_error( err_syntax );
  583. #endif
  584. return bwb_zline( l );
  585. }
  586. }
  587. /***************************************************************
  588. FUNCTION: bwb_stop()
  589. DESCRIPTION: This C function implements the BASIC
  590. STOP command, interrupting program flow
  591. at a specific point.
  592. SYNTAX: STOP
  593. ***************************************************************/
  594. #if ANSI_C
  595. struct bwb_line *
  596. bwb_stop( struct bwb_line *l )
  597. #else
  598. struct bwb_line *
  599. bwb_stop( l )
  600. struct bwb_line *l;
  601. #endif
  602. {
  603. #if HAVE_SIGNAL
  604. #if HAVE_RAISE
  605. raise( SIGINT );
  606. #else
  607. kill( getpid(), SIGINT );
  608. #endif
  609. #endif
  610. return bwb_xend( l );
  611. }
  612. /***************************************************************
  613. FUNCTION: bwb_xend()
  614. DESCRIPTION: This C function implements the BASIC
  615. END command, checking for END SUB
  616. or END FUNCTION, else stopping program
  617. execution for a simple END command.
  618. ***************************************************************/
  619. #if ANSI_C
  620. struct bwb_line *
  621. bwb_xend( struct bwb_line *l )
  622. #else
  623. struct bwb_line *
  624. bwb_xend( l )
  625. struct bwb_line *l;
  626. #endif
  627. {
  628. #if STRUCT_CMDS
  629. char tbuf[ MAXSTRINGSIZE + 1 ];
  630. #endif
  631. #if INTENSIVE_DEBUG
  632. sprintf( bwb_ebuf, "in bwb_xend(): entered funtion" );
  633. bwb_debug( bwb_ebuf );
  634. #endif
  635. /* Detect END SUB or END FUNCTION here */
  636. #if STRUCT_CMDS
  637. adv_element( l->buffer, &( l->position ), tbuf );
  638. bwb_strtoupper( tbuf );
  639. if ( strcmp( tbuf, CMD_XSUB ) == 0 )
  640. {
  641. return bwb_endsub( l );
  642. }
  643. if ( strcmp( tbuf, CMD_XFUNCTION ) == 0 )
  644. {
  645. return bwb_endfnc( l );
  646. }
  647. if ( strcmp( tbuf, CMD_XIF ) == 0 )
  648. {
  649. return bwb_endif( l );
  650. }
  651. if ( strcmp( tbuf, CMD_XSELECT ) == 0 )
  652. {
  653. return bwb_endselect( l );
  654. }
  655. #endif /* STRUCT_CMDS */
  656. /* else a simple END statement */
  657. break_handler();
  658. return &CURTASK bwb_end;
  659. }
  660. /***************************************************************
  661. FUNCTION: bwb_do()
  662. DESCRIPTION: This C function implements the BASIC DO
  663. command, also checking for the DO NUM
  664. and DO UNNUM commands for interactive
  665. programming environment.
  666. ***************************************************************/
  667. #if ANSI_C
  668. struct bwb_line *
  669. bwb_do( struct bwb_line *l )
  670. #else
  671. struct bwb_line *
  672. bwb_do( l )
  673. struct bwb_line *l;
  674. #endif
  675. {
  676. char tbuf[ MAXSTRINGSIZE + 1 ];
  677. adv_element( l->buffer, &( l->position ), tbuf );
  678. bwb_strtoupper( tbuf );
  679. /* if there is no argument (with STRUCT_CMDS) then we have a
  680. DO-LOOP structure: pass on to bwb_doloop() in bwb_stc.c */
  681. #if STRUCT_CMDS
  682. if ( strlen( tbuf ) == 0 )
  683. {
  684. return bwb_doloop( l );
  685. }
  686. if ( strcmp( tbuf, CMD_WHILE ) == 0 )
  687. {
  688. return bwb_while( l );
  689. }
  690. #endif
  691. #if INTERACTIVE
  692. if ( strcmp( tbuf, CMD_XNUM ) == 0 )
  693. {
  694. return bwb_donum( l );
  695. }
  696. if ( strcmp( tbuf, CMD_XUNNUM ) == 0 )
  697. {
  698. return bwb_dounnum( l );
  699. }
  700. #endif /* INTERACTIVE */
  701. /* if none of these occurred, then presume an error */
  702. bwb_error( err_syntax );
  703. return bwb_zline( l );
  704. }
  705. /***************************************************************
  706. FUNCTION: bwb_run()
  707. DESCRIPTION: This C function implements the BASIC
  708. RUN command.
  709. Even though RUN is not a core statement,
  710. the function bwb_run() is called from
  711. core, so it must be present for a minimal
  712. implementation.
  713. SYNTAX: RUN [line]|[file-name]
  714. ***************************************************************/
  715. #if ANSI_C
  716. struct bwb_line *
  717. bwb_run( struct bwb_line *l )
  718. #else
  719. struct bwb_line *
  720. bwb_run( l )
  721. struct bwb_line *l;
  722. #endif
  723. {
  724. struct bwb_line *current, *x;
  725. int go_lnumber; /* line number to go to */
  726. char tbuf[ MAXSTRINGSIZE + 1 ];
  727. struct exp_ese *e;
  728. FILE *input;
  729. #if INTENSIVE_DEBUG
  730. sprintf( bwb_ebuf, "in bwb_run(): entered function. buffer <%s> pos <%d>",
  731. l->buffer, l->position );
  732. bwb_debug( bwb_ebuf );
  733. #endif
  734. /* see if there is an element */
  735. current = NULL;
  736. adv_ws( l->buffer, &( l->position ) );
  737. #if INTENSIVE_DEBUG
  738. sprintf( bwb_ebuf, "in bwb_run(): check buffer <%s> pos <%d> char <0x%x>",
  739. l->buffer, l->position, l->buffer[ l->position ] );
  740. bwb_debug( bwb_ebuf );
  741. #endif
  742. switch ( l->buffer[ l->position ] )
  743. {
  744. case '\0':
  745. case '\n':
  746. case '\r':
  747. case ':':
  748. #if INTENSIVE_DEBUG
  749. sprintf( bwb_ebuf, "in bwb_run(): no argument; begin at start.next" );
  750. bwb_debug( bwb_ebuf );
  751. #endif
  752. current = CURTASK bwb_start.next;
  753. e = NULL;
  754. break;
  755. default:
  756. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  757. break;
  758. }
  759. /* check its type: if it is a string, open the file and execute it */
  760. if (( e != NULL ) && ( e->type == STRING ))
  761. {
  762. bwb_new( l ); /* clear memory */
  763. str_btoc( tbuf, exp_getsval( e ) ); /* get string in tbuf */
  764. if ( ( input = fopen( tbuf, "r" )) == NULL ) /* open file */
  765. {
  766. sprintf( bwb_ebuf, err_openfile, tbuf );
  767. bwb_error( bwb_ebuf );
  768. }
  769. bwb_fload( input ); /* load program */
  770. /* Next line removed by JBV (unnecessary recursion asks for trouble) */
  771. /* bwb_run( &CURTASK bwb_start ); */ /* and call bwb_run() recursively */
  772. current = &CURTASK bwb_start; /* JBV */
  773. }
  774. /* else if it is a line number, execute the program in memory
  775. at that line number */
  776. /* Removed by JBV */
  777. /* else
  778. { */
  779. /* Removed by JBV */
  780. /* if ( current == NULL )
  781. { */
  782. /* Added expression type check and changed loop boundaries (JBV) */
  783. if (( e != NULL ) && ( e->type != STRING ))
  784. {
  785. go_lnumber = (int) exp_getnval( e );
  786. #if INTENSIVE_DEBUG
  787. sprintf( bwb_ebuf, "in bwb_run(): element detected <%s>, lnumber <%d>",
  788. tbuf, go_lnumber );
  789. bwb_debug( bwb_ebuf );
  790. #endif
  791. for ( x = CURTASK bwb_start.next; x != &CURTASK bwb_end; x = x->next )
  792. {
  793. if ( x->number == go_lnumber )
  794. {
  795. current = x;
  796. }
  797. }
  798. }
  799. /* } */ /* Removed by JBV */
  800. if ( current == NULL )
  801. {
  802. sprintf( bwb_ebuf, err_lnnotfound, go_lnumber );
  803. bwb_error( bwb_ebuf );
  804. return &CURTASK bwb_end;
  805. }
  806. #if INTENSIVE_DEBUG
  807. sprintf( bwb_ebuf, "in bwb_run(): ready to run starting at line %d",
  808. current->number );
  809. bwb_debug( bwb_ebuf );
  810. #endif
  811. if ( CURTASK rescan == TRUE )
  812. {
  813. bwb_scan();
  814. }
  815. current->position = 0;
  816. CURTASK exsc = 0;
  817. bwb_setexec( current, 0, EXEC_NORM );
  818. /* } */ /* Removed by JBV */
  819. #if INTENSIVE_DEBUG
  820. sprintf( bwb_ebuf, "in bwb_run(): function complete." );
  821. bwb_debug( bwb_ebuf );
  822. #endif
  823. return current;
  824. }
  825. /***************************************************************
  826. FUNCTION: bwb_new()
  827. DESCRIPTION: This C function implements the BASIC
  828. NEW command.
  829. Even though NEW is not a core statement,
  830. the function bwb_run() is called from
  831. core, so it must be present for a minimal
  832. implementation.
  833. SYNTAX: NEW
  834. ***************************************************************/
  835. #if ANSI_C
  836. struct bwb_line *
  837. bwb_new( struct bwb_line *l )
  838. #else
  839. struct bwb_line *
  840. bwb_new( l )
  841. struct bwb_line *l;
  842. #endif
  843. {
  844. /* clear program in memory */
  845. bwb_xnew( l );
  846. /* clear all variables */
  847. bwb_clear( l );
  848. return bwb_zline( l );
  849. }
  850. /* End of Core Functions Section */
  851. #if INTERACTIVE
  852. /***************************************************************
  853. FUNCTION: bwb_system()
  854. DESCRIPTION: This C function implements the BASIC
  855. SYSTEM command, exiting to the operating
  856. system (or calling program). It is also
  857. called by the QUIT command, a functional
  858. equivalent for SYSTEM in Bywater BASIC.
  859. SYNTAX: SYSTEM
  860. QUIT
  861. ***************************************************************/
  862. #if ANSI_C
  863. struct bwb_line *
  864. bwb_system( struct bwb_line *l )
  865. #else
  866. struct bwb_line *
  867. bwb_system( l )
  868. struct bwb_line *l;
  869. #endif
  870. {
  871. prn_xprintf( stdout, "\n" );
  872. #if INTENSIVE_DEBUG
  873. bwb_debug( "in bwb_system(): ready to exit" );
  874. #endif
  875. bwx_terminate();
  876. return &CURTASK bwb_end; /* to make LINT happy */
  877. }
  878. /***************************************************************
  879. FUNCTION: bwb_load()
  880. DESCRIPTION: This C function implements the BASIC
  881. LOAD command.
  882. SYNTAX: LOAD file-name
  883. ***************************************************************/
  884. #if ANSI_C
  885. struct bwb_line *
  886. bwb_load( struct bwb_line *l )
  887. #else
  888. struct bwb_line *
  889. bwb_load( l )
  890. struct bwb_line *l;
  891. #endif
  892. {
  893. /* clear current contents */
  894. bwb_new( l );
  895. /* call xload function to load program in memory */
  896. bwb_xload( l );
  897. return bwb_zline( l );
  898. }
  899. /***************************************************************
  900. FUNCTION: bwb_xload()
  901. DESCRIPTION: This C function loads a BASIC program
  902. into memory.
  903. ***************************************************************/
  904. #if ANSI_C
  905. struct bwb_line *
  906. bwb_xload( struct bwb_line *l )
  907. #else
  908. struct bwb_line *
  909. bwb_xload( l )
  910. struct bwb_line *l;
  911. #endif
  912. {
  913. FILE *loadfile;
  914. struct exp_ese *e; /* JBV */
  915. /* Get an argument for filename */
  916. adv_ws( l->buffer, &( l->position ) );
  917. switch( l->buffer[ l->position ] )
  918. {
  919. case '\0':
  920. case '\n':
  921. case '\r':
  922. case ':':
  923. bwb_error( err_nofn ); /* Added by JBV (bug found by DD) */
  924. return bwb_zline( l );
  925. default:
  926. break;
  927. }
  928. /* Section added by JBV (bug found by DD) */
  929. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  930. if ( e->type != STRING )
  931. {
  932. #if PROG_ERRORS
  933. sprintf( bwb_ebuf, "in bwb_xload(): Missing filespec" );
  934. bwb_error( bwb_ebuf );
  935. #else
  936. bwb_error( err_syntax );
  937. #endif
  938. return bwb_zline( l );
  939. }
  940. /* This line removed by JBV (no longer required) */
  941. /* bwb_const( l->buffer, CURTASK progfile, &( l->position ) ); */
  942. str_btoc( CURTASK progfile, exp_getsval( e ) ); /* JBV */
  943. if ( ( loadfile = fopen( CURTASK progfile, "r" )) == NULL )
  944. {
  945. sprintf( bwb_ebuf, err_openfile, CURTASK progfile );
  946. bwb_error( bwb_ebuf );
  947. return bwb_zline( l );
  948. }
  949. bwb_fload( loadfile );
  950. return bwb_zline( l );
  951. }
  952. /***************************************************************
  953. FUNCTION: bwb_save()
  954. DESCRIPTION: This C function implements the BASIC
  955. SAVE command.
  956. SYNTAX: SAVE file-name
  957. ***************************************************************/
  958. #if ANSI_C
  959. struct bwb_line *
  960. bwb_save( struct bwb_line *l )
  961. #else
  962. struct bwb_line *
  963. bwb_save( l )
  964. struct bwb_line *l;
  965. #endif
  966. {
  967. FILE *outfile;
  968. static char filename[ MAXARGSIZE ];
  969. struct exp_ese *e; /* JBV */
  970. #if INTENSIVE_DEBUG
  971. sprintf( bwb_ebuf, "in bwb_save(): entered function." );
  972. bwb_debug( bwb_ebuf );
  973. #endif
  974. /* Get an argument for filename */
  975. adv_ws( l->buffer, &( l->position ) );
  976. switch( l->buffer[ l->position ] )
  977. {
  978. case '\0':
  979. case '\n':
  980. case '\r':
  981. case ':':
  982. bwb_error( err_nofn );
  983. return bwb_zline( l );
  984. default:
  985. break;
  986. }
  987. /* Section added by JBV (bug found by DD) */
  988. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  989. if ( e->type != STRING )
  990. {
  991. #if PROG_ERRORS
  992. sprintf( bwb_ebuf, "in bwb_save(): Missing filespec" );
  993. bwb_error( bwb_ebuf );
  994. #else
  995. bwb_error( err_syntax );
  996. #endif
  997. return bwb_zline( l );
  998. }
  999. /* This line removed by JBV (no longer required) */
  1000. /* bwb_const( l->buffer, filename, &( l->position ) ); */
  1001. str_btoc( filename, exp_getsval( e ) ); /* JBV */
  1002. if ( ( outfile = fopen( filename, "w" )) == NULL )
  1003. {
  1004. sprintf( bwb_ebuf, err_openfile, filename );
  1005. bwb_error( bwb_ebuf );
  1006. return bwb_zline( l );
  1007. }
  1008. bwb_xlist( l, outfile );
  1009. fclose( outfile );
  1010. return bwb_zline( l );
  1011. }
  1012. /***************************************************************
  1013. FUNCTION: bwb_list()
  1014. DESCRIPTION: This C function implements the BASIC
  1015. LIST command.
  1016. SYNTAX: LIST line[-line]
  1017. ***************************************************************/
  1018. #if ANSI_C
  1019. struct bwb_line *
  1020. bwb_list( struct bwb_line *l )
  1021. #else
  1022. struct bwb_line *
  1023. bwb_list( l )
  1024. struct bwb_line *l;
  1025. #endif
  1026. {
  1027. bwb_xlist( l, stdout );
  1028. return bwb_zline( l );
  1029. }
  1030. /***************************************************************
  1031. FUNCTION: bwb_xlist()
  1032. DESCRIPTION: This C function lists the program in
  1033. memory to a specified output device.
  1034. ***************************************************************/
  1035. #if ANSI_C
  1036. struct bwb_line *
  1037. bwb_xlist( struct bwb_line *l, FILE *file )
  1038. #else
  1039. struct bwb_line *
  1040. bwb_xlist( l, file )
  1041. struct bwb_line *l;
  1042. FILE *file;
  1043. #endif
  1044. {
  1045. struct bwb_line *start, *end, *current;
  1046. int s, e;
  1047. int f, r;
  1048. start = CURTASK bwb_start.next;
  1049. end = &CURTASK bwb_end;
  1050. r = bwb_numseq( &( l->buffer[ l->position ] ), &s, &e );
  1051. /* advance to the end of the segment */
  1052. #if MULTISEG_LINES
  1053. adv_eos( l->buffer, &( l->position ));
  1054. #endif
  1055. if (( r == FALSE ) || ( s == 0 ))
  1056. {
  1057. s = CURTASK bwb_start.next->number;
  1058. }
  1059. if ( e == 0 )
  1060. {
  1061. e = s;
  1062. }
  1063. if ( r == FALSE )
  1064. {
  1065. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1066. {
  1067. if ( current->next == &CURTASK bwb_end )
  1068. {
  1069. e = current->number;
  1070. }
  1071. }
  1072. }
  1073. #if INTENSIVE_DEBUG
  1074. sprintf( bwb_ebuf, "in bwb_xlist(): LBUFFER sequence is %d-%d", s, e );
  1075. bwb_debug( bwb_ebuf );
  1076. #endif
  1077. /* abort if either number == (MAXLINENO + 1) which denotes CURTASK bwb_end */
  1078. if ( ( s == (MAXLINENO + 1)) || ( e == (MAXLINENO + 1 ) ) )
  1079. {
  1080. return bwb_zline( l );
  1081. }
  1082. /* Now try to find the actual lines in memory */
  1083. f = FALSE;
  1084. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1085. {
  1086. if ( current != l )
  1087. {
  1088. if (( current->number == s ) && ( f == FALSE ))
  1089. {
  1090. f = TRUE;
  1091. start = current;
  1092. #if INTENSIVE_DEBUG
  1093. sprintf( bwb_ebuf, "in bwb_xlist(): start line number is <%d>",
  1094. s );
  1095. bwb_debug( bwb_ebuf );
  1096. #endif
  1097. }
  1098. }
  1099. }
  1100. /* check and see if a line number was found */
  1101. if ( f == FALSE )
  1102. {
  1103. sprintf( bwb_ebuf, err_lnnotfound, s );
  1104. bwb_error( bwb_ebuf );
  1105. return bwb_zline( l );
  1106. }
  1107. if ( e >= s )
  1108. {
  1109. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1110. {
  1111. if ( current != l )
  1112. {
  1113. if ( current->number == e )
  1114. {
  1115. #if INTENSIVE_DEBUG
  1116. sprintf( bwb_ebuf, "in bwb_xlist(): end line number is <%d>",
  1117. current->next->number );
  1118. bwb_debug( bwb_ebuf );
  1119. #endif
  1120. end = current->next;
  1121. }
  1122. }
  1123. }
  1124. }
  1125. else
  1126. {
  1127. end = start;
  1128. }
  1129. #if INTENSIVE_DEBUG
  1130. sprintf( bwb_ebuf, "in bwb_xlist(): line sequence is <%d-%d>",
  1131. start->number, end->number );
  1132. bwb_debug( bwb_ebuf );
  1133. #endif
  1134. /* previous should now be set to the line previous to the
  1135. first in the omission list */
  1136. /* now go through and list appropriate lines */
  1137. if ( start == end )
  1138. {
  1139. #if INTENSIVE_DEBUG
  1140. sprintf( bwb_ebuf, "in bwb_xlist(): start == end" );
  1141. bwb_debug( bwb_ebuf );
  1142. #endif
  1143. xl_line( file, start );
  1144. }
  1145. else
  1146. {
  1147. for ( current = start; current != end; current = current->next )
  1148. {
  1149. xl_line( file, current );
  1150. }
  1151. }
  1152. return bwb_zline( l );
  1153. }
  1154. /***************************************************************
  1155. FUNCTION: xl_line()
  1156. DESCRIPTION: This function lists a single program
  1157. line to a specified device of file.
  1158. It is called by bwb_xlist();
  1159. ***************************************************************/
  1160. #if ANSI_C
  1161. static int
  1162. xl_line( FILE *file, struct bwb_line *l )
  1163. #else
  1164. static int
  1165. xl_line( file, l )
  1166. FILE *file;
  1167. struct bwb_line *l;
  1168. #endif
  1169. {
  1170. char tbuf[ MAXSTRINGSIZE + 1 ];
  1171. if (( file == stdout ) || ( file == stderr ))
  1172. {
  1173. if ( l->xnum == (char) TRUE ) /* Better recast this one (JBV) */
  1174. {
  1175. sprintf( tbuf, "%7d: %s\n", l->number, l->buffer );
  1176. }
  1177. else
  1178. {
  1179. sprintf( tbuf, " : %s\n", l->buffer );
  1180. }
  1181. prn_xprintf( file, tbuf );
  1182. }
  1183. else
  1184. {
  1185. if ( l->xnum == (char) TRUE ) /* Better recast this one (JBV) */
  1186. {
  1187. fprintf( file, "%d %s\n", l->number, l->buffer );
  1188. }
  1189. else
  1190. {
  1191. fprintf( file, "%s\n", l->buffer );
  1192. }
  1193. }
  1194. return TRUE;
  1195. }
  1196. /***************************************************************
  1197. FUNCTION: bwb_delete()
  1198. DESCRIPTION: This C function implements the BASIC
  1199. DELETE command for interactive programming,
  1200. deleting a specified program line (or lines)
  1201. from memory.
  1202. SYNTAX: DELETE line[-line]
  1203. ***************************************************************/
  1204. #if ANSI_C
  1205. struct bwb_line *
  1206. bwb_delete( struct bwb_line *l )
  1207. #else
  1208. struct bwb_line *
  1209. bwb_delete( l )
  1210. struct bwb_line *l;
  1211. #endif
  1212. {
  1213. struct bwb_line *start, *end, *current, *previous, *p, *next;
  1214. static int s, e;
  1215. int f;
  1216. previous = &CURTASK bwb_start;
  1217. start = CURTASK bwb_start.next;
  1218. end = &CURTASK bwb_end;
  1219. bwb_numseq( &( l->buffer[ l->position ] ), &s, &e );
  1220. #if INTENSIVE_DEBUG
  1221. sprintf( bwb_ebuf, "in bwb_delete(): LBUFFER sequence is %d-%d", s, e );
  1222. bwb_debug( bwb_ebuf );
  1223. #endif
  1224. /* advance to the end of the segment */
  1225. #if MULTISEG_LINES
  1226. adv_eos( l->buffer, &( l->position ));
  1227. #endif
  1228. /* Now try to find the actual lines in memory */
  1229. previous = p = &CURTASK bwb_start;
  1230. f = FALSE;
  1231. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1232. {
  1233. if ( current != l )
  1234. {
  1235. /* Following line revised by JBV */
  1236. if (( current->xnum == (char) TRUE ) && ( current->number == s ))
  1237. {
  1238. f = TRUE;
  1239. previous = p;
  1240. start = current;
  1241. #if INTENSIVE_DEBUG
  1242. sprintf( bwb_ebuf, "in bwb_delete(): start line number is <%d>",
  1243. s );
  1244. bwb_debug( bwb_ebuf );
  1245. #endif
  1246. }
  1247. }
  1248. p = current;
  1249. }
  1250. /* check and see if a line number was found */
  1251. if ( f == FALSE )
  1252. {
  1253. sprintf( bwb_ebuf, err_lnnotfound, s );
  1254. bwb_error( bwb_ebuf );
  1255. return bwb_zline( l );
  1256. }
  1257. if ( e > s )
  1258. {
  1259. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1260. {
  1261. if ( current != l )
  1262. {
  1263. /* Following line revised by JBV */
  1264. if (( current->xnum == (char) TRUE) && ( current->number == e ))
  1265. {
  1266. #if INTENSIVE_DEBUG
  1267. sprintf( bwb_ebuf, "in bwb_delete(): end line number is <%d>",
  1268. e );
  1269. bwb_debug( bwb_ebuf );
  1270. #endif
  1271. end = current->next;
  1272. }
  1273. }
  1274. }
  1275. }
  1276. else
  1277. {
  1278. end = start->next;
  1279. }
  1280. /* previous should now be set to the line previous to the
  1281. first in the omission list */
  1282. /* now go through and delete appropriate lines */
  1283. current = start;
  1284. while (( current != end ) && ( current != &CURTASK bwb_end ))
  1285. {
  1286. next = current->next;
  1287. #if INTENSIVE_DEBUG
  1288. sprintf( bwb_ebuf, "in bwb_delete(): deleting line %d",
  1289. current->number );
  1290. bwb_debug( bwb_ebuf );
  1291. #endif
  1292. /* free line memory */
  1293. bwb_freeline( current );
  1294. /* recycle */
  1295. current = next;
  1296. }
  1297. /* reset link */
  1298. previous->next = current;
  1299. return bwb_zline( l );
  1300. }
  1301. /***************************************************************
  1302. FUNCTION: bwb_donum()
  1303. DESCRIPTION: This function implements the BASIC DO
  1304. NUM command, numbering all program lines
  1305. in memory in increments of 10 beginning
  1306. at 10.
  1307. SYNTAX: DO NUM
  1308. ***************************************************************/
  1309. #if ANSI_C
  1310. struct bwb_line *
  1311. bwb_donum( struct bwb_line *l )
  1312. #else
  1313. struct bwb_line *
  1314. bwb_donum( l )
  1315. struct bwb_line *l;
  1316. #endif
  1317. {
  1318. struct bwb_line *current;
  1319. register int lnumber;
  1320. lnumber = 10;
  1321. for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  1322. {
  1323. current->number = lnumber;
  1324. current->xnum = TRUE;
  1325. lnumber += 10;
  1326. if ( lnumber >= MAXLINENO )
  1327. {
  1328. return bwb_zline( l );
  1329. }
  1330. }
  1331. return bwb_zline( l );
  1332. }
  1333. /***************************************************************
  1334. FUNCTION: bwb_dounnum()
  1335. DESCRIPTION: This function implements the BASIC DO
  1336. UNNUM command, removing all line numbers
  1337. from the program in memory.
  1338. SYNTAX: DO UNNUM
  1339. ***************************************************************/
  1340. #if ANSI_C
  1341. struct bwb_line *
  1342. bwb_dounnum( struct bwb_line *l )
  1343. #else
  1344. struct bwb_line *
  1345. bwb_dounnum( l )
  1346. struct bwb_line *l;
  1347. #endif
  1348. {
  1349. struct bwb_line *current;
  1350. for ( current = bwb_start.next; current != &bwb_end; current = current->next )
  1351. {
  1352. current->number = 0;
  1353. current->xnum = FALSE;
  1354. }
  1355. return bwb_zline( l );
  1356. }
  1357. #endif /* INTERACTIVE */
  1358. #if COMMON_CMDS
  1359. /***************************************************************
  1360. FUNCTION: bwb_chain()
  1361. DESCRIPTION: This C function implements the BASIC
  1362. CHAIN command.
  1363. SYNTAX: CHAIN file-name
  1364. ***************************************************************/
  1365. #if ANSI_C
  1366. struct bwb_line *
  1367. bwb_chain( struct bwb_line *l )
  1368. #else
  1369. struct bwb_line *
  1370. bwb_chain( l )
  1371. struct bwb_line *l;
  1372. #endif
  1373. {
  1374. /* deallocate all variables except common ones */
  1375. var_delcvars();
  1376. /* remove old program from memory */
  1377. bwb_xnew( l );
  1378. /* call xload function to load new program in memory */
  1379. bwb_xload( l );
  1380. /* reset all stack counters */
  1381. CURTASK exsc = -1;
  1382. CURTASK expsc = 0;
  1383. CURTASK xtxtsc = 0;
  1384. /* run the program */
  1385. return bwb_run( &CURTASK bwb_start );
  1386. }
  1387. /***************************************************************
  1388. FUNCTION: bwb_merge()
  1389. DESCRIPTION: This C function implements the BASIC
  1390. MERGE command, merging command lines from
  1391. a specified file into the program in memory
  1392. without deleting the lines already in memory.
  1393. SYNTAX: MERGE file-name
  1394. ***************************************************************/
  1395. #if ANSI_C
  1396. struct bwb_line *
  1397. bwb_merge( struct bwb_line *l )
  1398. #else
  1399. struct bwb_line *
  1400. bwb_merge( l )
  1401. struct bwb_line *l;
  1402. #endif
  1403. {
  1404. /* call xload function to merge program in memory */
  1405. bwb_xload( l );
  1406. return bwb_zline( l );
  1407. }
  1408. /***************************************************************
  1409. FUNCTION: bwb_onerror()
  1410. DESCRIPTION: This C function implements the BASIC
  1411. ON ERROR GOSUB command.
  1412. SYNTAX: ON ERROR GOSUB line | label
  1413. ***************************************************************/
  1414. #if ANSI_C
  1415. struct bwb_line *
  1416. bwb_onerror( struct bwb_line *l )
  1417. #else
  1418. struct bwb_line *
  1419. bwb_onerror( l )
  1420. struct bwb_line *l;
  1421. #endif
  1422. {
  1423. char tbuf[ MAXSTRINGSIZE + 1 ];
  1424. #if INTENSIVE_DEBUG
  1425. sprintf( bwb_ebuf, "in bwb_onerror(): entered function" );
  1426. bwb_debug( bwb_ebuf );
  1427. #endif
  1428. /* get the GOSUB STATEMENT */
  1429. adv_element( l->buffer, &( l->position ), tbuf );
  1430. /* check for GOSUB statement */
  1431. bwb_strtoupper( tbuf );
  1432. if ( strcmp( tbuf, CMD_GOSUB ) != 0 )
  1433. {
  1434. #if PROG_ERRORS
  1435. sprintf( bwb_ebuf, "in bwb_onerror(): GOSUB statement missing" );
  1436. bwb_error( bwb_ebuf );
  1437. #else
  1438. bwb_error( err_syntax );
  1439. #endif
  1440. return bwb_zline( l );
  1441. }
  1442. /* get the GOSUB line */
  1443. adv_element( l->buffer, &( l->position ), err_gosubl );
  1444. return bwb_zline( l );
  1445. }
  1446. /***************************************************************
  1447. FUNCTION: bwb_tron()
  1448. DESCRIPTION: This function implements the BASIC TRON
  1449. command, turning the trace mechanism on.
  1450. SYNTAX: TRON
  1451. ***************************************************************/
  1452. #if ANSI_C
  1453. struct bwb_line *
  1454. bwb_tron( struct bwb_line *l )
  1455. #else
  1456. struct bwb_line *
  1457. bwb_tron( l )
  1458. struct bwb_line *l;
  1459. #endif
  1460. {
  1461. bwb_trace = TRUE;
  1462. prn_xprintf( stdout, "Trace is ON\n" );
  1463. return bwb_zline( l );
  1464. }
  1465. /***************************************************************
  1466. FUNCTION: bwb_troff()
  1467. DESCRIPTION: This function implements the BASIC TROFF
  1468. command, turning the trace mechanism off.
  1469. SYNTAX: TROFF
  1470. ***************************************************************/
  1471. #if ANSI_C
  1472. struct bwb_line *
  1473. bwb_troff( struct bwb_line *l )
  1474. #else
  1475. struct bwb_line *
  1476. bwb_troff( l )
  1477. struct bwb_line *l;
  1478. #endif
  1479. {
  1480. bwb_trace = FALSE;
  1481. prn_xprintf( stdout, "Trace is OFF\n" );
  1482. return bwb_zline( l );
  1483. }
  1484. #endif /* COMMON_CMDS */
  1485. /***************************************************************
  1486. FUNCTION: bwb_randomize()
  1487. DESCRIPTION: This function implements the BASIC
  1488. RANDOMIZE command, seeding the pseudo-
  1489. random number generator.
  1490. SYNTAX: RANDOMIZE number
  1491. ***************************************************************/
  1492. #if ANSI_C
  1493. struct bwb_line *
  1494. bwb_randomize( struct bwb_line *l )
  1495. #else
  1496. struct bwb_line *
  1497. bwb_randomize( l )
  1498. struct bwb_line *l;
  1499. #endif
  1500. {
  1501. register unsigned n;
  1502. struct exp_ese *e;
  1503. /* Check for argument */
  1504. adv_ws( l->buffer, &( l->position ) );
  1505. switch( l->buffer[ l->position ] )
  1506. {
  1507. case '\0':
  1508. case '\n':
  1509. case '\r':
  1510. #if MULTISEG_LINES
  1511. case ':':
  1512. #endif
  1513. n = (unsigned) 1;
  1514. break;
  1515. default:
  1516. n = (unsigned) 0;
  1517. break;
  1518. }
  1519. /* get the argument in tbuf */
  1520. if ( n == (unsigned) 0 )
  1521. {
  1522. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  1523. n = (unsigned) exp_getnval( e );
  1524. }
  1525. #if INTENSIVE_DEBUG
  1526. sprintf( bwb_ebuf, "in bwb_randomize(): argument is <%d>", n );
  1527. bwb_debug( bwb_ebuf );
  1528. #endif
  1529. srand( n );
  1530. return bwb_zline( l );
  1531. }
  1532. /***************************************************************
  1533. FUNCTION: bwb_xnew()
  1534. DESCRIPTION: Clears the program in memory, but does not
  1535. deallocate all variables.
  1536. ***************************************************************/
  1537. #if ANSI_C
  1538. struct bwb_line *
  1539. bwb_xnew( struct bwb_line *l )
  1540. #else
  1541. struct bwb_line *
  1542. bwb_xnew( l )
  1543. struct bwb_line *l;
  1544. #endif
  1545. {
  1546. struct bwb_line *current, *previous;
  1547. int wait;
  1548. wait = TRUE;
  1549. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  1550. {
  1551. if ( wait != TRUE )
  1552. {
  1553. /* Revised to FREE pass-thru call by JBV */
  1554. FREE( previous, "bwb_xnew" );
  1555. previous = NULL; /* JBV */
  1556. }
  1557. wait = FALSE;
  1558. previous = current;
  1559. }
  1560. CURTASK bwb_start.next = &CURTASK bwb_end;
  1561. return bwb_zline( l );
  1562. }
  1563. #if UNIX_CMDS
  1564. /***************************************************************
  1565. FUNCTION: bwb_environ()
  1566. DESCRIPTION: This C function implements the BASIC
  1567. ENVIRON command, assigning a string
  1568. value to an environment variable.
  1569. SYNTAX: ENVIRON variable-string$ = string$
  1570. ***************************************************************/
  1571. #if ANSI_C
  1572. struct bwb_line *
  1573. bwb_environ( struct bwb_line *l )
  1574. #else
  1575. struct bwb_line *
  1576. bwb_environ( l )
  1577. struct bwb_line *l;
  1578. #endif
  1579. {
  1580. static char tbuf[ MAXSTRINGSIZE + 1 ];
  1581. char tmp[ MAXSTRINGSIZE + 1 ];
  1582. register int i;
  1583. int pos;
  1584. struct exp_ese *e;
  1585. /* find the equals sign */
  1586. for ( i = 0; ( l->buffer[ l->position ] != '=' ) && ( l->buffer[ l->position ] != '\0' ); ++i )
  1587. {
  1588. tbuf[ i ] = l->buffer[ l->position ];
  1589. tbuf[ i + 1 ] = '\0';
  1590. ++( l->position );
  1591. }
  1592. #if INTENSIVE_DEBUG
  1593. sprintf( bwb_ebuf, "in bwb_environ(): variable string is <%s>", tbuf );
  1594. bwb_debug( bwb_ebuf );
  1595. #endif
  1596. /* get the value string to be assigned */
  1597. pos = 0;
  1598. e = bwb_exp( tbuf, FALSE, &pos );
  1599. str_btoc( tbuf, exp_getsval( e ) );
  1600. #if INTENSIVE_DEBUG
  1601. sprintf( bwb_ebuf, "in bwb_environ(): variable string resolves to <%s>", tbuf );
  1602. bwb_debug( bwb_ebuf );
  1603. #endif
  1604. /* find the equals sign */
  1605. adv_ws( l->buffer, &( l->position ) );
  1606. if ( l->buffer[ l->position ] != '=' )
  1607. {
  1608. #if PROG_ERRORS
  1609. sprintf( bwb_ebuf, "in bwb_environ(): failed to find equal sign" );
  1610. bwb_error( bwb_ebuf );
  1611. #else
  1612. bwb_error( err_syntax );
  1613. #endif
  1614. return bwb_zline( l );
  1615. }
  1616. ++( l->position );
  1617. /* get the value string to be assigned */
  1618. e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1619. str_btoc( tmp, exp_getsval( e ) );
  1620. #if INTENSIVE_DEBUG
  1621. sprintf( bwb_ebuf, "in bwb_environ(): value string resolves to <%s>", tmp );
  1622. bwb_debug( bwb_ebuf );
  1623. #endif
  1624. /* construct string */
  1625. strcat( tbuf, "=" );
  1626. strcat( tbuf, tmp );
  1627. #if INTENSIVE_DEBUG
  1628. sprintf( bwb_ebuf, "in bwb_environ(): assignment string is <%s>", tbuf );
  1629. bwb_debug( bwb_ebuf );
  1630. #endif
  1631. /* now assign value to variable */
  1632. if ( putenv( tbuf ) == -1 )
  1633. {
  1634. bwb_error( err_opsys );
  1635. return bwb_zline( l );
  1636. }
  1637. /* return */
  1638. return bwb_zline( l );
  1639. }
  1640. #endif /* UNIX_CMDS */
  1641. /***************************************************************
  1642. FUNCTION: bwb_cmds()
  1643. DESCRIPTION: This function implements a CMD command,
  1644. which lists all commands implemented.
  1645. It is not part of a BASIC specification,
  1646. but is used for debugging bwBASIC.
  1647. SYNTAX: CMDS
  1648. ***************************************************************/
  1649. #if PERMANENT_DEBUG
  1650. #if ANSI_C
  1651. struct bwb_line *
  1652. bwb_cmds( struct bwb_line *l )
  1653. #else
  1654. struct bwb_line *
  1655. bwb_cmds( l )
  1656. struct bwb_line *l;
  1657. #endif
  1658. {
  1659. register int n;
  1660. char tbuf[ MAXSTRINGSIZE + 1 ];
  1661. prn_xprintf( stdout, "BWBASIC COMMANDS AVAILABLE: \n" );
  1662. /* run through the command table and print comand names */
  1663. for ( n = 0; n < COMMANDS; ++n )
  1664. {
  1665. sprintf( tbuf, "%s \n", bwb_cmdtable[ n ].name );
  1666. prn_xprintf( stdout, tbuf );
  1667. }
  1668. return bwb_zline( l );
  1669. }
  1670. #endif
  1671. /***************************************************************
  1672. FUNCTION: getcmdnum()
  1673. DESCRIPTION: This function returns the number associated
  1674. with a specified command (cmdstr) in the
  1675. command table.
  1676. ***************************************************************/
  1677. #if ANSI_C
  1678. int
  1679. getcmdnum( char *cmdstr )
  1680. #else
  1681. int
  1682. getcmdnum( cmdstr )
  1683. char *cmdstr;
  1684. #endif
  1685. {
  1686. register int c;
  1687. for ( c = 0; c < COMMANDS; ++c )
  1688. {
  1689. if ( strcmp( bwb_cmdtable[ c ].name, cmdstr ) == 0 )
  1690. {
  1691. return c;
  1692. }
  1693. }
  1694. return -1;
  1695. }
  1696. /***************************************************************
  1697. FUNCTION: bwb_zline()
  1698. DESCRIPTION: This function is called at the exit from
  1699. Bywater BASIC command functions. If
  1700. MULTISEG_LINES is TRUE, then it returns
  1701. a pointer to the current line; otherwise it
  1702. sets the position in the next line to zero
  1703. and returns a pointer to the next line.
  1704. ***************************************************************/
  1705. #if ANSI_C
  1706. extern struct bwb_line *
  1707. bwb_zline( struct bwb_line *l )
  1708. #else
  1709. struct bwb_line *
  1710. bwb_zline( l )
  1711. struct bwb_line *l;
  1712. #endif
  1713. {
  1714. #if MULTISEG_LINES
  1715. /* l->marked = FALSE; */
  1716. return l;
  1717. #else
  1718. l->next->position = 0;
  1719. return l->next;
  1720. #endif
  1721. }