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.
 
 
 
 
 
 

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