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.
 
 
 
 
 
 

4890 lines
106 KiB

  1. /***************************************************************
  2. bwb_cmd.c Miscellaneous Commands
  3. for Bywater BASIC Interpreter
  4. Copyright (c) 1993, Ted A. Campbell
  5. Bywater Software
  6. email: tcamp@delphi.com
  7. Copyright and Permissions Information:
  8. All U.S. and international rights are claimed by the author,
  9. Ted A. Campbell.
  10. This software is released under the terms of the GNU General
  11. Public License (GPL), which is distributed with this software
  12. in the file "COPYING". The GPL specifies the terms under
  13. which users may copy and use the software in this distribution.
  14. A separate license is available for commercial distribution,
  15. for information on which you should contact the author.
  16. ***************************************************************/
  17. /*---------------------------------------------------------------*/
  18. /* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */
  19. /* 11/1995 (eidetics@cerf.net). */
  20. /* */
  21. /* Those additionally marked with "DD" were at the suggestion of */
  22. /* Dale DePriest (daled@cadence.com). */
  23. /* */
  24. /* Version 3.00 by Howard Wulf, AF5NE */
  25. /* */
  26. /*---------------------------------------------------------------*/
  27. #include "bwbasic.h"
  28. static int
  29. xl_line(FILE * file, struct bwb_line * l);
  30. static int
  31. LastLineNumber = -1;
  32. /***************************************************************
  33. FUNCTION: bwb_rem()
  34. DESCRIPTION: This C function implements the BASIC rem
  35. (REMark) command, ignoring the remainder
  36. of the line.
  37. ***************************************************************/
  38. struct bwb_line *
  39. bwb_REM(struct bwb_line * l)
  40. {
  41. bwx_DEBUG(__FUNCTION__);
  42. adv_eos(l->buffer, &(l->position));
  43. return bwb_zline(l);
  44. }
  45. /***************************************************************
  46. FUNCTION: bwb_let()
  47. DESCRIPTION: This C function implements the BASIC
  48. LET assignment command, even if LET
  49. is implied and not explicit.
  50. SYNTAX: LET variable = expression
  51. ***************************************************************/
  52. struct bwb_line *
  53. bwb_LET(struct bwb_line * l)
  54. {
  55. bwx_DEBUG(__FUNCTION__);
  56. /* Call the expression interpreter to evaluate the assignment */
  57. bwb_exp(l->buffer, TRUE, &(l->position));
  58. if (ERROR_PENDING)
  59. {
  60. return bwb_zline(l);
  61. }
  62. return bwb_zline(l);
  63. }
  64. /***************************************************************
  65. FUNCTION: bwb_go
  66. DESCRIPTION: This C function implements the BASIC
  67. GO command, branching appropriately to
  68. GOTO or GOSUB.
  69. ***************************************************************/
  70. struct bwb_line *
  71. bwb_GO(struct bwb_line * l)
  72. {
  73. bwx_DEBUG(__FUNCTION__);
  74. bwb_error(err_syntax);
  75. return bwb_zline(l);
  76. }
  77. /***************************************************************
  78. FUNCTION: bwb_goto
  79. DESCRIPTION: This C function implements the BASIC
  80. GOTO command.
  81. SYNTAX: GOTO line | label
  82. ***************************************************************/
  83. struct bwb_line *
  84. bwb_GOTO(struct bwb_line * l)
  85. {
  86. struct bwb_line *x;
  87. char tbuf[BasicStringLengthMax + 1];
  88. bwx_DEBUG(__FUNCTION__);
  89. adv_ws(l->buffer, &(l->position));
  90. adv_element(l->buffer, &(l->position), tbuf);
  91. /* check for target label */
  92. x = find_label(tbuf);
  93. if (x != NULL)
  94. {
  95. x->position = 0;
  96. return x;
  97. }
  98. return bwb_zline(l);
  99. }
  100. /***************************************************************
  101. FUNCTION: bwb_gosub()
  102. DESCRIPTION: This function implements the BASIC GOSUB
  103. command.
  104. SYNTAX: GOSUB line | label
  105. ***************************************************************/
  106. struct bwb_line *
  107. bwb_GOSUB(struct bwb_line * l)
  108. {
  109. struct bwb_line *x;
  110. char tbuf[BasicStringLengthMax + 1];
  111. bwx_DEBUG(__FUNCTION__);
  112. adv_ws(l->buffer, &(l->position));
  113. adv_element(l->buffer, &(l->position), tbuf);
  114. x = find_label(tbuf);
  115. if (x != NULL)
  116. {
  117. bwb_zline(l);
  118. bwb_incexec();
  119. /* set the new position to x and return x */
  120. x->position = 0;
  121. bwb_setexec(x, 0, EXEC_GOSUB);
  122. return x;
  123. }
  124. return bwb_zline(l);
  125. }
  126. /***************************************************************
  127. FUNCTION: bwb_return()
  128. DESCRIPTION: This function implements the BASIC RETURN
  129. command.
  130. SYNTAX: RETURN
  131. ***************************************************************/
  132. struct bwb_line *
  133. bwb_RETURN(struct bwb_line * l)
  134. {
  135. bwx_DEBUG(__FUNCTION__);
  136. while (CURTASK excs[CURTASK exsc].code != EXEC_GOSUB)
  137. {
  138. bwb_decexec();
  139. if (CURTASK excs[CURTASK exsc].code == EXEC_NORM) /* End of the line? */
  140. {
  141. bwb_error(err_retnogosub);
  142. }
  143. }
  144. /* decrement the EXEC stack counter */
  145. bwb_decexec();
  146. return CURTASK excs[CURTASK exsc].line;
  147. }
  148. /***************************************************************
  149. FUNCTION: bwb_on
  150. DESCRIPTION: This function implements the BASIC ON...
  151. GOTO or ON...GOSUB statements.
  152. It will also detect the ON ERROR... statement
  153. and pass execution to bwb_onerror().
  154. SYNTAX: ON variable GOTO|GOSUB line|label[,...]
  155. ***************************************************************/
  156. struct bwb_line *
  157. bwb_ON(struct bwb_line * l)
  158. {
  159. struct bwb_line *x;
  160. char tbuf[BasicStringLengthMax + 1];
  161. int p;
  162. struct exp_ese *rvar;
  163. int v;
  164. int loop;
  165. int num_lines;
  166. int command;
  167. bwx_DEBUG(__FUNCTION__);
  168. /* Check for argument */
  169. adv_ws(l->buffer, &(l->position));
  170. if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar)
  171. {
  172. bwb_error(err_incomplete);
  173. return bwb_zline(l);
  174. }
  175. /* get the variable name, numerical constant, or expression */
  176. adv_element(l->buffer, &(l->position), tbuf);
  177. /* evaluate the variable name or constant */
  178. p = 0;
  179. rvar = bwb_exp(tbuf, FALSE, &p);
  180. if (ERROR_PENDING)
  181. {
  182. return bwb_zline(l);
  183. }
  184. v = exp_getival(rvar);
  185. /* Get GOTO or GOSUB statements */
  186. adv_element(l->buffer, &(l->position), tbuf);
  187. if (strcasecmp(tbuf, "GO") == 0)
  188. {
  189. adv_ws(l->buffer, &(l->position));
  190. adv_element(l->buffer, &(l->position), tbuf);
  191. if (strcasecmp(tbuf, "TO") == 0)
  192. {
  193. command = C_GOTO;
  194. }
  195. else
  196. if (strcasecmp(tbuf, "SUB") == 0)
  197. {
  198. command = C_GOSUB;
  199. }
  200. else
  201. {
  202. sprintf(bwb_ebuf, ERR_ONNOGOTO);
  203. bwb_error(bwb_ebuf);
  204. return bwb_zline(l);
  205. }
  206. }
  207. else
  208. if (strcasecmp(tbuf, "GOTO") == 0)
  209. {
  210. command = C_GOTO;
  211. }
  212. else
  213. if (strcasecmp(tbuf, "GOSUB") == 0)
  214. {
  215. command = C_GOSUB;
  216. }
  217. else
  218. {
  219. sprintf(bwb_ebuf, ERR_ONNOGOTO);
  220. bwb_error(bwb_ebuf);
  221. return bwb_zline(l);
  222. }
  223. if (v < 1)
  224. {
  225. if (OptionFlags & OPTION_BUGS_ON)
  226. {
  227. /* fall-thru to next line without error */
  228. /* advance to end of segment */
  229. adv_eos(l->buffer, &(l->position));
  230. }
  231. else
  232. {
  233. /* ERROR */
  234. bwb_error(err_valoorange);
  235. }
  236. return bwb_zline(l);
  237. }
  238. num_lines = 0;
  239. loop = TRUE;
  240. while (loop == TRUE)
  241. {
  242. /* read a line|label */
  243. inp_adv(l->buffer, &(l->position));
  244. adv_element(l->buffer, &(l->position), tbuf);
  245. num_lines++;
  246. if (num_lines == v)
  247. {
  248. loop = FALSE;
  249. }
  250. /* check for end of line */
  251. adv_ws(l->buffer, &(l->position));
  252. if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar)
  253. {
  254. loop = FALSE;
  255. }
  256. }
  257. /* advance to end of segment */
  258. adv_eos(l->buffer, &(l->position));
  259. /* Be sure value is in range */
  260. if (v > num_lines)
  261. {
  262. if (OptionFlags & OPTION_BUGS_ON)
  263. {
  264. /* fall-thru to next line without error */
  265. /* advance to end of segment */
  266. adv_eos(l->buffer, &(l->position));
  267. }
  268. else
  269. {
  270. /* ERROR */
  271. bwb_error(err_valoorange);
  272. }
  273. return bwb_zline(l);
  274. }
  275. x = find_label(tbuf);
  276. if (x == NULL)
  277. {
  278. return bwb_zline(l);
  279. }
  280. if (command == C_GOTO)
  281. {
  282. x->position = 0;
  283. bwb_setexec(x, 0, CURTASK excs[CURTASK exsc].code);
  284. return x;
  285. }
  286. else
  287. if (command == C_GOSUB)
  288. {
  289. /* save current stack level */
  290. bwb_setexec(l, l->position, CURTASK excs[CURTASK exsc].code);
  291. /* increment exec stack */
  292. bwb_incexec();
  293. /* set the new position to x and return x */
  294. x->position = 0;
  295. bwb_setexec(x, 0, EXEC_GOSUB);
  296. return x;
  297. }
  298. sprintf(bwb_ebuf, "in bwb_on(): invalid value for command.");
  299. bwb_error(bwb_ebuf);
  300. return bwb_zline(l);
  301. }
  302. /***************************************************************
  303. FUNCTION: bwb_stop()
  304. DESCRIPTION: This C function implements the BASIC
  305. STOP command, interrupting program flow
  306. at a specific point.
  307. SYNTAX: STOP
  308. ***************************************************************/
  309. struct bwb_line *
  310. bwb_STOP(struct bwb_line * l)
  311. {
  312. bwx_DEBUG(__FUNCTION__);
  313. stopped_line = l->number;
  314. bwx_STOP();
  315. return bwb_END(l);
  316. }
  317. /***************************************************************
  318. FUNCTION: bwb_xend()
  319. DESCRIPTION: This C function implements the BASIC
  320. END command, checking for END SUB
  321. or END FUNCTION, else stopping program
  322. execution for a simple END command.
  323. ***************************************************************/
  324. struct bwb_line *
  325. bwb_END(struct bwb_line * l)
  326. {
  327. /* a simple END statement */
  328. bwx_DEBUG(__FUNCTION__);
  329. stopped_line = l->number;
  330. break_handler();
  331. return &CURTASK bwb_end;
  332. }
  333. /***************************************************************
  334. FUNCTION: bwb_run()
  335. DESCRIPTION: This C function implements the BASIC
  336. RUN command.
  337. Even though RUN is not a core statement,
  338. the function bwb_run() is called from
  339. core, so it must be present for a minimal
  340. implementation.
  341. SYNTAX: RUN [line]|[file-name]
  342. ***************************************************************/
  343. struct bwb_line *
  344. bwb_RUN(struct bwb_line * l)
  345. {
  346. struct bwb_line *current;
  347. bwx_DEBUG(__FUNCTION__);
  348. /* see if there is an element */
  349. current = NULL;
  350. adv_ws(l->buffer, &(l->position));
  351. if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar)
  352. {
  353. current = CURTASK bwb_start.next;
  354. var_CLEAR();
  355. }
  356. else
  357. {
  358. struct exp_ese *e;
  359. e = bwb_exp(l->buffer, FALSE, &(l->position));
  360. if (ERROR_PENDING)
  361. {
  362. return bwb_zline(l);
  363. }
  364. if (e->type == STRING)
  365. {
  366. /* check its type: if it is a STRING, open the file
  367. * and execute it */
  368. FILE *input;
  369. char tbuf[BasicStringLengthMax + 1];
  370. bwb_NEW(l); /* clear memory */
  371. str_btoc(tbuf, exp_getsval(e)); /* get string in tbuf */
  372. if ((input = fopen(tbuf, "r")) == NULL) /* open file */
  373. {
  374. sprintf(bwb_ebuf, err_openfile, tbuf);
  375. bwb_error(bwb_ebuf);
  376. }
  377. bwb_fload(input); /* load program */
  378. current = &CURTASK bwb_start; /* JBV */
  379. }
  380. else
  381. {
  382. /* check its type: if it is a NUMBER, execute the
  383. * line */
  384. int go_lnumber; /* line number to go to */
  385. struct bwb_line *x;
  386. go_lnumber = exp_getival(e);
  387. for (x = CURTASK bwb_start.next; x != &CURTASK bwb_end; x = x->next)
  388. {
  389. if (x->number == go_lnumber)
  390. {
  391. current = x;
  392. }
  393. }
  394. if (current == NULL)
  395. {
  396. sprintf(bwb_ebuf, err_lnnotfound, go_lnumber);
  397. bwb_error(bwb_ebuf);
  398. return &CURTASK bwb_end;
  399. }
  400. }
  401. }
  402. bwb_scan();
  403. current->position = 0;
  404. CURTASK exsc = 0;
  405. bwb_setexec(current, 0, EXEC_NORM);
  406. /* RUN */
  407. bwb_Warning_Clear();
  408. stopped_line = 0;
  409. SetOnError(0);
  410. return current;
  411. }
  412. /***************************************************************
  413. FUNCTION: bwb_cont()
  414. DESCRIPTION: This C function implements the BASIC
  415. CONT command.
  416. SYNTAX: CONT
  417. ***************************************************************/
  418. struct bwb_line *
  419. bwb_CONT(struct bwb_line * l)
  420. {
  421. struct bwb_line *current, *x;
  422. bwx_DEBUG(__FUNCTION__);
  423. /* see if there is an element */
  424. current = NULL;
  425. if (stopped_line > 0)
  426. {
  427. for (x = CURTASK bwb_start.next; (x != &CURTASK bwb_end) && (current == NULL); x = x->next)
  428. {
  429. if (x->number > stopped_line)
  430. {
  431. current = x;
  432. }
  433. }
  434. }
  435. if (current == NULL)
  436. {
  437. /* same as "RUN" */
  438. current = CURTASK bwb_start.next;
  439. }
  440. bwb_scan();
  441. current->position = 0;
  442. CURTASK exsc = 0;
  443. bwb_setexec(current, 0, EXEC_NORM);
  444. /* CONT */
  445. stopped_line = 0;
  446. return current;
  447. }
  448. /***************************************************************
  449. FUNCTION: bwb_new()
  450. DESCRIPTION: This C function implements the BASIC
  451. NEW command.
  452. Even though NEW is not a core statement,
  453. the function bwb_run() is called from
  454. core, so it must be present for a minimal
  455. implementation.
  456. SYNTAX: NEW
  457. ***************************************************************/
  458. struct bwb_line *
  459. bwb_NEW(struct bwb_line * l)
  460. {
  461. bwx_DEBUG(__FUNCTION__);
  462. /* clear program in memory */
  463. bwb_xnew(&bwb_start);
  464. /* clear all variables */
  465. var_CLEAR();
  466. /* NEW */
  467. bwb_Warning_Clear();
  468. stopped_line = 0;
  469. SetOnError(0);
  470. return bwb_zline(l);
  471. }
  472. /* End of Core Functions Section */
  473. /***************************************************************
  474. FUNCTION: bwb_system()
  475. DESCRIPTION: This C function implements the BASIC
  476. SYSTEM command, exiting to the operating
  477. system (or calling program). It is also
  478. called by the QUIT command, a functional
  479. equivalent for SYSTEM in Bywater BASIC.
  480. SYNTAX: SYSTEM
  481. QUIT
  482. ***************************************************************/
  483. struct bwb_line *
  484. bwb_QUIT(struct bwb_line * l)
  485. {
  486. bwx_DEBUG(__FUNCTION__);
  487. return bwb_SYSTEM(l);
  488. }
  489. struct bwb_line *
  490. bwb_SYSTEM(struct bwb_line * l)
  491. {
  492. bwx_DEBUG(__FUNCTION__);
  493. prn_xprintf("\n");
  494. bwx_terminate();
  495. return &CURTASK bwb_end;/* to make LINT happy */
  496. }
  497. /***************************************************************
  498. FUNCTION: bwb_load()
  499. DESCRIPTION: This C function implements the BASIC
  500. LOAD command.
  501. SYNTAX: LOAD [file-name]
  502. ***************************************************************/
  503. struct bwb_line *
  504. bwb_LOAD(struct bwb_line * l)
  505. {
  506. bwx_DEBUG(__FUNCTION__);
  507. /* clear current contents */
  508. bwb_NEW(l);
  509. /* call xload function to load program in memory */
  510. bwb_xload(l);
  511. return bwb_zline(l);
  512. }
  513. /***************************************************************
  514. FUNCTION: bwb_xload()
  515. DESCRIPTION: This C function loads a BASIC program
  516. into memory.
  517. ***************************************************************/
  518. struct bwb_line *
  519. bwb_xload(struct bwb_line * l)
  520. {
  521. FILE *loadfile;
  522. bwx_DEBUG(__FUNCTION__);
  523. /* Get an argument for filename */
  524. adv_ws(l->buffer, &(l->position));
  525. if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar)
  526. {
  527. /* default is the last filename used by LOAD or SAVE */
  528. }
  529. else
  530. {
  531. /* Section added by JBV (bug found by DD) */
  532. struct exp_ese *e; /* JBV */
  533. e = bwb_exp(l->buffer, FALSE, &(l->position));
  534. if (ERROR_PENDING)
  535. {
  536. return bwb_zline(l);
  537. }
  538. if (e->type != STRING)
  539. {
  540. sprintf(bwb_ebuf, "in bwb_xload(): Missing filespec");
  541. bwb_error(bwb_ebuf);
  542. return bwb_zline(l);
  543. }
  544. str_btoc(CURTASK progfile, exp_getsval(e)); /* JBV */
  545. }
  546. if (strlen(CURTASK progfile) == 0)
  547. {
  548. bwb_error(err_nofn); /* Added by JBV (bug found by DD) */
  549. return bwb_zline(l);
  550. }
  551. if ((loadfile = fopen(CURTASK progfile, "r")) == NULL)
  552. {
  553. sprintf(bwb_ebuf, err_openfile, CURTASK progfile);
  554. bwb_error(bwb_ebuf);
  555. return bwb_zline(l);
  556. }
  557. bwb_fload(loadfile);
  558. return bwb_zline(l);
  559. }
  560. /***************************************************************
  561. FUNCTION: bwb_save()
  562. DESCRIPTION: This C function implements the BASIC
  563. SAVE command.
  564. SYNTAX: SAVE [file-name]
  565. ***************************************************************/
  566. #define CSAVE_VERSION_1 0x20150218
  567. struct bwb_line *
  568. bwb_CSAVE_(struct bwb_line * l)
  569. {
  570. /* CSAVE* NumericArrayName */
  571. char tbuf[BasicStringLengthMax + 1];
  572. struct bwb_variable *v;
  573. FILE *f;
  574. unsigned long n;
  575. unsigned long t;
  576. bwx_DEBUG(__FUNCTION__);
  577. bwb_getvarname(l->buffer, tbuf, &(l->position));
  578. v = var_find(tbuf);
  579. if (v == NULL)
  580. {
  581. bwb_error(err_syntax);
  582. return bwb_zline(l);
  583. }
  584. /* variable MUST be numeric */
  585. if (v->type == STRING)
  586. {
  587. bwb_error(err_syntax);
  588. return bwb_zline(l);
  589. }
  590. /* variable MUST be an array */
  591. if ((v->dimensions == 1) && (v->array_sizes[0] == 1))
  592. {
  593. bwb_error(err_syntax);
  594. return bwb_zline(l);
  595. }
  596. /* * variable storage is a mess, * we bypass that tradition here. */
  597. t = 1;
  598. for (n = 0; n < v->dimensions; n++)
  599. {
  600. t *= v->array_sizes[n];
  601. }
  602. if (t <= 1)
  603. {
  604. bwb_error(err_syntax);
  605. return bwb_zline(l);
  606. }
  607. /* open file */
  608. f = fopen(v->name, "w");
  609. if (f == NULL)
  610. {
  611. bwb_error(err_syntax);
  612. return bwb_zline(l);
  613. }
  614. /* write version number */
  615. n = CSAVE_VERSION_1;
  616. fwrite(&n, sizeof(long), 1, f);
  617. /* write total number of elements */
  618. fwrite(&t, sizeof(long), 1, f);
  619. /* write data */
  620. fwrite(v->memnum, sizeof(BasicNumberType), t, f);
  621. /* OK */
  622. fclose(f);
  623. return bwb_zline(l);
  624. }
  625. struct bwb_line *
  626. bwb_CLOAD_(struct bwb_line * l)
  627. {
  628. /* CLOAD* NumericArrayName */
  629. char tbuf[BasicStringLengthMax + 1];
  630. struct bwb_variable *v;
  631. FILE *f;
  632. unsigned long n;
  633. unsigned long t;
  634. bwx_DEBUG(__FUNCTION__);
  635. bwb_getvarname(l->buffer, tbuf, &(l->position));
  636. v = var_find(tbuf);
  637. if (v == NULL)
  638. {
  639. bwb_error(err_syntax);
  640. return bwb_zline(l);
  641. }
  642. /* variable MUST be numeric */
  643. if (v->type == STRING)
  644. {
  645. bwb_error(err_syntax);
  646. return bwb_zline(l);
  647. }
  648. /* variable MUST be an array */
  649. if ((v->dimensions == 1) && (v->array_sizes[0] == 1))
  650. {
  651. bwb_error(err_syntax);
  652. return bwb_zline(l);
  653. }
  654. /* variable storage is a mess, we bypass that tradition here. */
  655. t = 1;
  656. for (n = 0; n < v->dimensions; n++)
  657. {
  658. t *= v->array_sizes[n];
  659. }
  660. if (t <= 1)
  661. {
  662. bwb_error(err_syntax);
  663. return bwb_zline(l);
  664. }
  665. /* open file */
  666. f = fopen(v->name, "r");
  667. if (f == NULL)
  668. {
  669. bwb_error(err_syntax);
  670. return bwb_zline(l);
  671. }
  672. /* read version number */
  673. n = 0;
  674. fread(&n, sizeof(long), 1, f);
  675. if (n != CSAVE_VERSION_1)
  676. {
  677. fclose(f);
  678. bwb_error("Bad File");
  679. return bwb_zline(l);
  680. }
  681. /* read total number of elements */
  682. n = 0;
  683. fread(&n, sizeof(long), 1, f);
  684. if (n != t)
  685. {
  686. fclose(f);
  687. bwb_error("Size Mismatch");
  688. return bwb_zline(l);
  689. }
  690. /* read data */
  691. fread(v->memnum, sizeof(BasicNumberType), t, f);
  692. /* OK */
  693. fclose(f);
  694. return bwb_zline(l);
  695. }
  696. struct bwb_line *
  697. bwb_CSAVE(struct bwb_line * l)
  698. {
  699. /* CSAVE [filename$] */
  700. bwx_DEBUG(__FUNCTION__);
  701. return bwb_SAVE(l);
  702. }
  703. struct bwb_line *
  704. bwb_CLOAD(struct bwb_line * l)
  705. {
  706. /* CLOAD [filename$] */
  707. bwx_DEBUG(__FUNCTION__);
  708. return bwb_LOAD(l);
  709. }
  710. struct bwb_line *
  711. bwb_SAVE(struct bwb_line * l)
  712. {
  713. FILE *outfile;
  714. bwx_DEBUG(__FUNCTION__);
  715. /* Get an argument for filename */
  716. adv_ws(l->buffer, &(l->position));
  717. if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar)
  718. {
  719. /* default is the last filename used by LOAD or SAVE */
  720. }
  721. else
  722. {
  723. /* Section added by JBV (bug found by DD) */
  724. struct exp_ese *e; /* JBV */
  725. e = bwb_exp(l->buffer, FALSE, &(l->position));
  726. if (ERROR_PENDING)
  727. {
  728. return bwb_zline(l);
  729. }
  730. if (e->type != STRING)
  731. {
  732. sprintf(bwb_ebuf, "in bwb_save(): Missing filespec");
  733. bwb_error(bwb_ebuf);
  734. return bwb_zline(l);
  735. }
  736. str_btoc(CURTASK progfile, exp_getsval(e)); /* JBV */
  737. }
  738. if (strlen(CURTASK progfile) == 0)
  739. {
  740. bwb_error(err_nofn); /* Added by JBV (bug found by DD) */
  741. return bwb_zline(l);
  742. }
  743. if ((outfile = fopen(CURTASK progfile, "w")) == NULL)
  744. {
  745. sprintf(bwb_ebuf, err_openfile, CURTASK progfile);
  746. bwb_error(bwb_ebuf);
  747. return bwb_zline(l);
  748. }
  749. bwb_xlist(l, outfile);
  750. fclose(outfile);
  751. return bwb_zline(l);
  752. }
  753. /***************************************************************
  754. FUNCTION: bwb_list()
  755. DESCRIPTION: This C function implements the BASIC
  756. LIST command.
  757. SYNTAX: LIST line[-line]
  758. ***************************************************************/
  759. struct bwb_line *
  760. bwb_LIST(struct bwb_line * l)
  761. {
  762. bwx_DEBUG(__FUNCTION__);
  763. bwb_xlist(l, stdout);
  764. return bwb_zline(l);
  765. }
  766. /***************************************************************
  767. FUNCTION: bwb_xlist()
  768. DESCRIPTION: This C function lists the program in
  769. memory to a specified output device.
  770. ***************************************************************/
  771. struct bwb_line *
  772. bwb_xlist(struct bwb_line * l, FILE * file)
  773. {
  774. struct bwb_line *start, *end, *current;
  775. BasicLineNumberType s, e;
  776. int f, r;
  777. bwx_DEBUG(__FUNCTION__);
  778. /* Default first value */
  779. start = CURTASK bwb_start.next;
  780. s = BasicLineNumberMin;
  781. /* Default last value */
  782. end = &CURTASK bwb_end;
  783. e = BasicLineNumberMax;
  784. /* Parse parameters */
  785. r = bwb_numseq(&(l->buffer[l->position]), &s, &e);
  786. /*
  787. r example
  788. = ================
  789. 0 LIST
  790. 1 LIST 1000
  791. 4 LIST -
  792. 5 LIST 1000-
  793. 6 LIST -9000
  794. 7 LIST 1000-9000
  795. */
  796. if (r == 1)
  797. {
  798. /* LIST 1000 */
  799. e = s;
  800. }
  801. /* advance to the end of the segment */
  802. adv_eos(l->buffer, &(l->position));
  803. /* abort if either number is out of range */
  804. if (s < BasicLineNumberMin || s > BasicLineNumberMax)
  805. {
  806. /* LIST 99999- */
  807. sprintf(bwb_ebuf, err_lnnotfound, s);
  808. bwb_error(bwb_ebuf);
  809. return bwb_zline(l);
  810. }
  811. if (e < BasicLineNumberMin || e > BasicLineNumberMax)
  812. {
  813. /* LIST -99999 */
  814. sprintf(bwb_ebuf, err_lnnotfound, e);
  815. bwb_error(bwb_ebuf);
  816. return bwb_zline(l);
  817. }
  818. if (s > e)
  819. {
  820. /* LIST 9999-1 */
  821. sprintf(bwb_ebuf, err_lnnotfound, s);
  822. bwb_error(bwb_ebuf);
  823. return bwb_zline(l);
  824. }
  825. /* find the first line that actually exists that is >= START */
  826. f = FALSE;
  827. for (current = CURTASK bwb_start.next; (f == FALSE) && (current != &CURTASK bwb_end); current = current->next)
  828. {
  829. if (current->number >= s)
  830. {
  831. f = TRUE;
  832. start = current;
  833. }
  834. }
  835. /* "start" now points at the first line that actually exists that is
  836. * >= START */
  837. if (r == 1)
  838. {
  839. /* LIST 999 */
  840. if (s != start->number)
  841. {
  842. /* THE SPECIFIED LINE DOES NOT EXIST */
  843. f = FALSE;
  844. }
  845. }
  846. /* check and see if a line number was found */
  847. if (f == FALSE)
  848. {
  849. if (l->number > 0)
  850. {
  851. /* this is an executing program */
  852. sprintf(bwb_ebuf, err_lnnotfound, s);
  853. bwb_error(bwb_ebuf);
  854. }
  855. return bwb_zline(l);
  856. }
  857. f = FALSE;
  858. if (e > s)
  859. {
  860. /* find the last line that actually exists that is <= END */
  861. for (current = start; current != &CURTASK bwb_end; current = current->next)
  862. {
  863. if (current->number <= e)
  864. {
  865. f = TRUE;
  866. end = current;
  867. }
  868. }
  869. }
  870. else
  871. {
  872. /* e == s */
  873. f = TRUE;
  874. end = start;
  875. }
  876. /* "end" now points at the last line that actually exists that is <=
  877. * END */
  878. if (r == 6 || r == 7)
  879. {
  880. /* LIST -999 */
  881. if (e < end->number)
  882. {
  883. /* THERE ARE NO LINES LESS THAN SPECIFIED */
  884. f = FALSE;
  885. }
  886. }
  887. /* "end" is always after "start" */
  888. end = end->next;
  889. while (end->number <= e)
  890. {
  891. end = end->next;
  892. }
  893. /* * "end" now points at the first line * that actually exists that
  894. * is > END */
  895. /* check and see if a line number was found */
  896. if (f == FALSE)
  897. {
  898. if (l->number > 0)
  899. {
  900. /* this is an executing program */
  901. sprintf(bwb_ebuf, err_lnnotfound, e);
  902. bwb_error(bwb_ebuf);
  903. }
  904. return bwb_zline(l);
  905. }
  906. /* now go through and list appropriate lines */
  907. bwb_scan();
  908. LastLineNumber = -1;
  909. for (current = start; current != end; current = current->next)
  910. {
  911. xl_line(file, current);
  912. }
  913. fprintf(file, "\n");
  914. return bwb_zline(l);
  915. }
  916. /***************************************************************
  917. FUNCTION: xl_line()
  918. DESCRIPTION: This function lists a single program
  919. line to a specified device of file.
  920. It is called by bwb_xlist();
  921. ***************************************************************/
  922. static int
  923. xl_line(FILE * file, struct bwb_line * l)
  924. {
  925. bwx_DEBUG(__FUNCTION__);
  926. if ((file == stdout) || (file == stderr))
  927. {
  928. char tbuf[32];
  929. if (LastLineNumber == l->number)
  930. {
  931. strcpy(tbuf, " :");
  932. }
  933. else
  934. {
  935. sprintf(tbuf, "%5d:", l->number);
  936. }
  937. prn_xprintf(tbuf);
  938. if (OptionFlags & OPTION_COVERAGE_ON)
  939. {
  940. #if 0
  941. sprintf(tbuf, "%c:", l->Coverage);
  942. prn_xprintf(tbuf);
  943. #endif
  944. if( l->LineFlags & LINE_EXECUTED )
  945. {
  946. prn_xprintf("*");
  947. }
  948. else
  949. {
  950. prn_xprintf(" ");
  951. }
  952. prn_xprintf(":");
  953. }
  954. if (OptionIndentValue > 0)
  955. {
  956. int i;
  957. for (i = 0; i < l->Indention; i++)
  958. {
  959. int j;
  960. for (j = 0; j < OptionIndentValue; j++)
  961. {
  962. prn_xprintf(" ");
  963. }
  964. }
  965. }
  966. prn_xprintf(l->buffer);
  967. prn_xprintf("\n");
  968. }
  969. else
  970. {
  971. #if 0
  972. if (LastLineNumber == l->number)
  973. {
  974. fprintf(file, "%s\n", l->buffer);
  975. }
  976. else
  977. {
  978. fprintf(file, "%d %s\n", l->number, l->buffer);
  979. }
  980. #endif
  981. if (LastLineNumber == l->number && OptionStatementChar != '\0' )
  982. {
  983. fprintf(file, "%c", OptionStatementChar);
  984. }
  985. else
  986. if(LastLineNumber == -1 )
  987. {
  988. /* first line, do nothing */
  989. }
  990. else
  991. {
  992. fprintf(file, "\n");
  993. }
  994. if( l->LineFlags & LINE_NUMBERED )
  995. {
  996. fprintf(file, "%d ", l->number);
  997. }
  998. fprintf(file, "%s", l->buffer);
  999. }
  1000. LastLineNumber = l->number;
  1001. return TRUE;
  1002. }
  1003. /***************************************************************
  1004. FUNCTION: bwb_delete()
  1005. DESCRIPTION: This C function implements the BASIC
  1006. DELETE command for interactive programming,
  1007. deleting a specified program line (or lines)
  1008. from memory.
  1009. SYNTAX: DELETE line[-line]
  1010. ***************************************************************/
  1011. struct bwb_line *
  1012. bwb_DELETE(struct bwb_line * l)
  1013. {
  1014. struct bwb_line *start, *end, *current, *previous, *p, *next;
  1015. BasicLineNumberType s, e;
  1016. int f, r;
  1017. bwx_DEBUG(__FUNCTION__);
  1018. /* Default first value */
  1019. start = CURTASK bwb_start.next;
  1020. s = BasicLineNumberMin;
  1021. /* Default last value */
  1022. end = &CURTASK bwb_end;
  1023. e = BasicLineNumberMax;
  1024. /* Default previous value */
  1025. previous = p = &CURTASK bwb_start;
  1026. r = bwb_numseq(&(l->buffer[l->position]), &s, &e);
  1027. /*
  1028. r example
  1029. = ================
  1030. 0 DELETE
  1031. 1 DELETE 1000
  1032. 4 DELETE -
  1033. 5 DELETE 1000-
  1034. 6 DELETE -9000
  1035. 7 DELETE 1000-9000
  1036. */
  1037. if (r == 1)
  1038. {
  1039. /* DELETE 1000 */
  1040. e = s;
  1041. }
  1042. /* advance to the end of the segment */
  1043. adv_eos(l->buffer, &(l->position));
  1044. /* abort if either number is out of range */
  1045. if (s < BasicLineNumberMin || s > BasicLineNumberMax)
  1046. {
  1047. /* DELETE 99999- */
  1048. sprintf(bwb_ebuf, err_lnnotfound, s);
  1049. bwb_error(bwb_ebuf);
  1050. return bwb_zline(l);
  1051. }
  1052. if (e < BasicLineNumberMin || e > BasicLineNumberMax)
  1053. {
  1054. /* DELETE -99999 */
  1055. sprintf(bwb_ebuf, err_lnnotfound, e);
  1056. bwb_error(bwb_ebuf);
  1057. return bwb_zline(l);
  1058. }
  1059. if (s > e)
  1060. {
  1061. /* DELETE 9999-1 */
  1062. sprintf(bwb_ebuf, err_lnnotfound, s);
  1063. bwb_error(bwb_ebuf);
  1064. return bwb_zline(l);
  1065. }
  1066. /* find the first line that exists that is >= START */
  1067. f = FALSE;
  1068. for (current = CURTASK bwb_start.next; (f == FALSE) && (current != &CURTASK bwb_end); current = current->next)
  1069. {
  1070. if (current->number >= s)
  1071. {
  1072. f = TRUE;
  1073. previous = p;
  1074. start = current;
  1075. }
  1076. p = current;
  1077. }
  1078. /* "start" now points at the first line that actually exists that is
  1079. * >= START */
  1080. /* "previous" now points at the first line that actually exists that
  1081. * is < START */
  1082. if (r == 1)
  1083. {
  1084. /* DELETE 1000 */
  1085. if (s != start->number)
  1086. {
  1087. /* THE SPECIFIED LINE DOES NOT EXIST */
  1088. f = FALSE;
  1089. }
  1090. }
  1091. /* check and see if a line number was found */
  1092. if (f == FALSE)
  1093. {
  1094. if (l->number > 0)
  1095. {
  1096. /* this is an executing program */
  1097. sprintf(bwb_ebuf, err_lnnotfound, s);
  1098. bwb_error(bwb_ebuf);
  1099. }
  1100. return bwb_zline(l);
  1101. }
  1102. f = FALSE;
  1103. if (e > s)
  1104. {
  1105. /* find the last line that actually exists that is <= END */
  1106. for (current = start; current != &CURTASK bwb_end; current = current->next)
  1107. {
  1108. if (current->number <= e)
  1109. {
  1110. f = TRUE;
  1111. end = current;
  1112. }
  1113. }
  1114. }
  1115. else
  1116. {
  1117. /* e == s */
  1118. f = TRUE;
  1119. end = start;
  1120. }
  1121. /* "end" now points at the last line that actually exists that is <=
  1122. * END */
  1123. if (r == 6 || r == 7)
  1124. {
  1125. /* DELETE -999 */
  1126. /* DELETE 1-999 */
  1127. if (e < end->number)
  1128. {
  1129. /* THERE ARE NO LINES LESS THAN SPECIFIED */
  1130. f = FALSE;
  1131. }
  1132. }
  1133. /* "end" is always after "start" */
  1134. end = end->next;
  1135. while (end->number <= e)
  1136. {
  1137. end = end->next;
  1138. }
  1139. /* * "end" now points at the first line * that actually exists * that
  1140. * is > END */
  1141. /* check and see if a line number was found */
  1142. if (f == FALSE)
  1143. {
  1144. if (l->number > 0)
  1145. {
  1146. /* this is an executing program */
  1147. sprintf(bwb_ebuf, err_lnnotfound, e);
  1148. bwb_error(bwb_ebuf);
  1149. }
  1150. return bwb_zline(l);
  1151. }
  1152. if (l->number > 0)
  1153. {
  1154. /* This is an executing progrram. So make sure DELETE removes
  1155. * structured commands completely. The BASIC program must
  1156. * delete all of a structured command. Do not allow a
  1157. * dangling FOR, NEXT, and so on, since that is just a FATAL
  1158. * error waiting to happen. FOR - NEXT DO - LOOP WHILE - WEND
  1159. * UNTIL - UEND IF - END IF SELECT CASE - END SELECT */
  1160. s = start->number;
  1161. e = end->number;
  1162. current = start;
  1163. while ((current != end) && (current != &CURTASK bwb_end))
  1164. {
  1165. if (current->OtherLine != NULL)
  1166. {
  1167. /* this line is either the Top or the Bottomm
  1168. * of a structured command */
  1169. /* verify the other end of the block is also
  1170. * in the DELETE range */
  1171. int n;
  1172. n = current->OtherLine->number;
  1173. if (n < s || n >= e)
  1174. {
  1175. sprintf(bwb_ebuf,
  1176. "Cannot delete at %d because %d is not included"
  1177. ,current->number
  1178. ,n
  1179. );
  1180. bwb_error(bwb_ebuf);
  1181. return bwb_zline(l);
  1182. }
  1183. }
  1184. current = current->next;
  1185. }
  1186. }
  1187. else
  1188. {
  1189. /* The user is executing DELETE interactively, Allow user to
  1190. * DELETE whatever they want. Whenever user attempts to run,
  1191. * bwb_scan() will find any mismatch. */
  1192. }
  1193. /* now go through and delete appropriate lines */
  1194. current = start;
  1195. while ((current != end) && (current != &CURTASK bwb_end))
  1196. {
  1197. next = current->next;
  1198. if (current == l)
  1199. {
  1200. l = previous;
  1201. }
  1202. if (current->OtherLine != NULL)
  1203. {
  1204. /* remove any existing structured command linkage */
  1205. current->OtherLine->OtherLine = NULL;
  1206. current->OtherLine = NULL;
  1207. }
  1208. bwb_freeline(current);
  1209. current = next;
  1210. }
  1211. /* previous should now be set to the line previous to the first in
  1212. * the omission list */
  1213. previous->next = current;
  1214. CURTASK rescan = TRUE; /* program needs to be scanned again */
  1215. bwb_scan();
  1216. return bwb_zline(l);
  1217. }
  1218. /***************************************************************
  1219. FUNCTION: bwb_donum()
  1220. DESCRIPTION: This function implements the BASIC DO
  1221. NUM command, numbering all program lines
  1222. in memory in increments of 10 beginning
  1223. at 10.
  1224. SYNTAX: DO NUM
  1225. ***************************************************************/
  1226. #if 0
  1227. struct bwb_line *
  1228. bwb_donum(struct bwb_line * l)
  1229. {
  1230. struct bwb_line *current;
  1231. register int lnumber;
  1232. bwx_DEBUG(__FUNCTION__);
  1233. lnumber = 10;
  1234. for (current = bwb_start.next; current != &bwb_end; current = current->next)
  1235. {
  1236. current->number = lnumber;
  1237. lnumber += 10;
  1238. if (lnumber > BasicLineNumberMax)
  1239. {
  1240. return bwb_zline(l);
  1241. }
  1242. }
  1243. return bwb_zline(l);
  1244. }
  1245. /***************************************************************
  1246. FUNCTION: bwb_dounnum()
  1247. DESCRIPTION: This function implements the BASIC DO
  1248. UNNUM command, removing all line numbers
  1249. from the program in memory.
  1250. SYNTAX: DO UNNUM
  1251. ***************************************************************/
  1252. struct bwb_line *
  1253. bwb_dounnum(struct bwb_line * l)
  1254. {
  1255. struct bwb_line *current;
  1256. bwx_DEBUG(__FUNCTION__);
  1257. for (current = bwb_start.next; current != &bwb_end; current = current->next)
  1258. {
  1259. current->number = 0;
  1260. }
  1261. return bwb_zline(l);
  1262. }
  1263. #endif /* 0 */
  1264. /***************************************************************
  1265. FUNCTION: bwb_chain()
  1266. DESCRIPTION: This C function implements the BASIC
  1267. CHAIN command.
  1268. SYNTAX: CHAIN "file-name" | file-name$
  1269. ***************************************************************/
  1270. struct bwb_line *
  1271. bwb_CHAIN(struct bwb_line * l)
  1272. {
  1273. /* based upon bwb_xload() */
  1274. FILE *loadfile;
  1275. struct exp_ese *e;
  1276. bwx_DEBUG(__FUNCTION__);
  1277. /* Get an argument for filename */
  1278. adv_ws(l->buffer, &(l->position));
  1279. if (l->buffer[l->position] == '\0' || l->buffer[l->position] == OptionCommentChar)
  1280. {
  1281. bwb_error(err_nofn); /* Added by JBV (bug found by DD) */
  1282. return bwb_zline(l);
  1283. }
  1284. /* The file-name may be any string expression */
  1285. e = bwb_exp(l->buffer, FALSE, &(l->position));
  1286. if (ERROR_PENDING)
  1287. {
  1288. return bwb_zline(l);
  1289. }
  1290. if (e->type != STRING)
  1291. {
  1292. sprintf(bwb_ebuf, "in bwb_chain(): Missing filespec");
  1293. bwb_error(bwb_ebuf);
  1294. return bwb_zline(l);
  1295. }
  1296. /* save the filename */
  1297. str_btoc(CURTASK progfile, exp_getsval(e));
  1298. /* deallocate all variables except common ones */
  1299. var_delcvars();
  1300. /* remove old program from memory */
  1301. bwb_xnew(&bwb_start);
  1302. /* call xload function to load new program in memory */
  1303. if ((loadfile = fopen(CURTASK progfile, "r")) == NULL)
  1304. {
  1305. sprintf(bwb_ebuf, err_openfile, CURTASK progfile);
  1306. bwb_error(bwb_ebuf);
  1307. return bwb_zline(l);
  1308. }
  1309. bwb_fload(loadfile);
  1310. bwb_scan();
  1311. /* reset all stack counters */
  1312. CURTASK exsc = 0;
  1313. CURTASK expsc = 0;
  1314. /* run the program */
  1315. /* CHAIN */
  1316. bwb_Warning_Clear();
  1317. stopped_line = 0;
  1318. SetOnError(0);
  1319. CURTASK bwb_start.position = 0;
  1320. bwb_setexec(&CURTASK bwb_start, 0, EXEC_NORM);
  1321. return &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. struct bwb_line *
  1332. bwb_MERGE(struct bwb_line * l)
  1333. {
  1334. bwx_DEBUG(__FUNCTION__);
  1335. /* call xload function to merge program in memory */
  1336. bwb_xload(l);
  1337. return bwb_zline(l);
  1338. }
  1339. void
  1340. SetOnError(int LineNumber)
  1341. {
  1342. /* scan the stack looking for a FUNCTION/SUB */
  1343. int i;
  1344. bwx_DEBUG(__FUNCTION__);
  1345. i = CURTASK exsc;
  1346. while (i > 0)
  1347. {
  1348. struct bwb_line *current;
  1349. current = CURTASK excs[i].LoopTopLine;
  1350. if (current != NULL)
  1351. {
  1352. switch (current->cmdnum)
  1353. {
  1354. case C_FUNCTION:
  1355. case C_SUB:
  1356. /* FOUND */
  1357. /* we are in a FUNCTION/SUB, so this is LOCAL */
  1358. CURTASK excs[i].OnErrorGoto = LineNumber;
  1359. return;
  1360. break;
  1361. }
  1362. }
  1363. i--;
  1364. }
  1365. /* NOT FOUND */
  1366. /* we are NOT in a FUNCTION/SUB */
  1367. CURTASK excs[0].OnErrorGoto = LineNumber;
  1368. }
  1369. int
  1370. GetOnError(void)
  1371. {
  1372. /* scan the stack looking for a FUNCTION/SUB */
  1373. int i;
  1374. bwx_DEBUG(__FUNCTION__);
  1375. i = CURTASK exsc;
  1376. while (i >= 0)
  1377. {
  1378. if (CURTASK excs[i].OnErrorGoto != 0)
  1379. {
  1380. /* FOUND */
  1381. return CURTASK excs[i].OnErrorGoto;
  1382. }
  1383. i--;
  1384. }
  1385. /* NOT FOUND */
  1386. return 0;
  1387. }
  1388. /***************************************************************
  1389. FUNCTION: bwb_onerror()
  1390. DESCRIPTION: This C function implements the BASIC
  1391. ON ERROR GOSUB command.
  1392. SYNTAX: ON ERROR GOSUB line | label
  1393. ***************************************************************/
  1394. struct bwb_line *
  1395. bwb_ON_ERROR_GOTO(struct bwb_line * l)
  1396. {
  1397. /* ON ERROR GOTO line */
  1398. struct bwb_line *x;
  1399. char tbuf[BasicStringLengthMax + 1];
  1400. /* get the line number */
  1401. adv_ws(l->buffer, &(l->position));
  1402. adv_element(l->buffer, &(l->position), tbuf);
  1403. if (strcasecmp(tbuf, "0") == 0)
  1404. {
  1405. SetOnError(0);
  1406. return bwb_zline(l);
  1407. }
  1408. x = find_label(tbuf);
  1409. if (x != NULL)
  1410. {
  1411. SetOnError(x->number);
  1412. return bwb_zline(l);
  1413. }
  1414. bwb_error(err_syntax);
  1415. return bwb_zline(l);
  1416. }
  1417. struct bwb_line *
  1418. bwb_ON_ERROR_GOSUB(struct bwb_line * l)
  1419. {
  1420. /* ON ERROR GOSUB line */
  1421. struct bwb_line *x;
  1422. char tbuf[BasicStringLengthMax + 1];
  1423. /* get the line number */
  1424. adv_ws(l->buffer, &(l->position));
  1425. adv_element(l->buffer, &(l->position), tbuf);
  1426. if (strcasecmp(tbuf, "0") == 0)
  1427. {
  1428. SetOnError(0);
  1429. return bwb_zline(l);
  1430. }
  1431. x = find_label(tbuf);
  1432. if (x != NULL)
  1433. {
  1434. SetOnError(x->number);
  1435. return bwb_zline(l);
  1436. }
  1437. bwb_error(err_syntax);
  1438. return bwb_zline(l);
  1439. }
  1440. struct bwb_line *
  1441. bwb_ON_ERROR_RESUME_NEXT(struct bwb_line * l)
  1442. {
  1443. SetOnError(-1);
  1444. return bwb_zline(l);
  1445. }
  1446. struct bwb_line *
  1447. bwb_ON_ERROR_RETURN_NEXT(struct bwb_line * l)
  1448. {
  1449. SetOnError(-1);
  1450. return bwb_zline(l);
  1451. }
  1452. struct bwb_line *
  1453. bwb_ON_TIMER(struct bwb_line * l)
  1454. {
  1455. /* ON TIMER(...) GOSUB ... TIMER ON ... */
  1456. char tbuf[BasicStringLengthMax + 1];
  1457. int p;
  1458. struct exp_ese *rvar;
  1459. BasicNumberType v;
  1460. BasicNumberType minv;
  1461. bwx_DEBUG(__FUNCTION__);
  1462. /* turn off the TIMER - so syntax errors will NOT fire the timer */
  1463. bwb_Timer_Off();
  1464. tmr_gotol = 0;
  1465. tmr_count = 0;
  1466. /* get the SECOMDS parameter */
  1467. adv_element(l->buffer, &(l->position), tbuf);
  1468. p = 0;
  1469. rvar = bwb_exp(tbuf, FALSE, &p);
  1470. if (ERROR_PENDING)
  1471. {
  1472. return bwb_zline(l);
  1473. }
  1474. v = exp_getnval(rvar);
  1475. minv = 1;
  1476. minv /= CLOCKS_PER_SEC;
  1477. if (v > minv)
  1478. {
  1479. /* get the GOSUB keyword */
  1480. adv_ws(l->buffer, &(l->position));
  1481. adv_element(l->buffer, &(l->position), tbuf);
  1482. if (strcasecmp(tbuf, "GOSUB") == 0)
  1483. {
  1484. /* ON TIMER(X) GOSUB line */
  1485. struct bwb_line *x;
  1486. /* get the line number */
  1487. adv_ws(l->buffer, &(l->position));
  1488. adv_element(l->buffer, &(l->position), tbuf);
  1489. x = find_label(tbuf);
  1490. if (x != NULL)
  1491. {
  1492. tmr_gotol = x->number;
  1493. tmr_count = v;
  1494. return bwb_zline(l);
  1495. }
  1496. }
  1497. }
  1498. bwb_error(err_syntax);
  1499. return bwb_zline(l);
  1500. }
  1501. struct bwb_line *
  1502. bwb_TIMER(struct bwb_line * l)
  1503. {
  1504. bwx_DEBUG(__FUNCTION__);
  1505. /* turn off the TIMER - so syntax errors will NOT fire the timer */
  1506. bwb_Timer_Off();
  1507. bwb_error(err_syntax);
  1508. return bwb_zline(l);
  1509. }
  1510. struct bwb_line *
  1511. bwb_TIMER_OFF(struct bwb_line * l)
  1512. {
  1513. bwx_DEBUG(__FUNCTION__);
  1514. /* turn off the TIMER - so syntax errors will NOT fire the timer */
  1515. bwb_Timer_Off();
  1516. /* TIMER OFF */
  1517. tmr_gotol = 0;
  1518. tmr_count = 0;
  1519. return bwb_zline(l);
  1520. }
  1521. struct bwb_line *
  1522. bwb_TIMER_ON(struct bwb_line * l)
  1523. {
  1524. bwx_DEBUG(__FUNCTION__);
  1525. /* turn off the TIMER - so syntax errors will NOT fire the timer */
  1526. bwb_Timer_Off();
  1527. /* TIMER ON */
  1528. if (tmr_count > 0 && tmr_gotol > 0)
  1529. {
  1530. tmr_expires = bwx_TIMER(tmr_count);
  1531. bwb_Timer_On();
  1532. }
  1533. return bwb_zline(l);
  1534. }
  1535. struct bwb_line *
  1536. bwb_TIMER_STOP(struct bwb_line * l)
  1537. {
  1538. bwx_DEBUG(__FUNCTION__);
  1539. /* turn off the TIMER - so syntax errors will NOT fire the timer */
  1540. bwb_Timer_Off();
  1541. /* TIMER STOP */
  1542. return bwb_zline(l);
  1543. }
  1544. /***************************************************************
  1545. FUNCTION: bwb_resume()
  1546. DESCRIPTION: This C function implements the BASIC
  1547. RESUME command.
  1548. SYNTAX: RESUME [ 0 | NEXT | line | label ]
  1549. ***************************************************************/
  1550. struct bwb_line *
  1551. bwb_RESUME(struct bwb_line * l)
  1552. {
  1553. char tbuf[BasicStringLengthMax + 1];
  1554. struct bwb_line *x = NULL;
  1555. bwx_DEBUG(__FUNCTION__);
  1556. if (err_number == 0) /* RESUME without ERR are FATAL */
  1557. {
  1558. sprintf(bwb_ebuf, "RESUME WITHOUT ERR AT %d", CURTASK number);
  1559. bwb_error(bwb_ebuf);
  1560. return bwb_zline(l);
  1561. }
  1562. if (err_line == NULL)
  1563. {
  1564. /* RESUME without ERL are FATAL */
  1565. sprintf(bwb_ebuf, "RESUME WITHOUT ERL AT %d", CURTASK number);
  1566. bwb_error(bwb_ebuf);
  1567. return bwb_zline(l);
  1568. }
  1569. if (err_line->number == 0)
  1570. {
  1571. /* RESUME without ERL are FATAL */
  1572. sprintf(bwb_ebuf, "RESUME WITHOUT ERL AT %d", CURTASK number);
  1573. bwb_error(bwb_ebuf);
  1574. return bwb_zline(l);
  1575. }
  1576. /* Get optional argument for RESUME */
  1577. adv_ws(l->buffer, &(l->position));
  1578. adv_element(l->buffer, &(l->position), tbuf);
  1579. if (strlen(tbuf) == 0 || strcasecmp(tbuf, "0") == 0)
  1580. {
  1581. /* RESUME [0] */
  1582. /* Execution resumes at the statement which caused the error */
  1583. x = err_line;
  1584. }
  1585. else
  1586. if (strcasecmp(tbuf, "NEXT") == 0)
  1587. {
  1588. /* RESUME NEXT */
  1589. /* Execution resumes at the statement immediately following
  1590. * the one which caused the error */
  1591. x = err_line->next;
  1592. }
  1593. else
  1594. {
  1595. /* RESUME line|label */
  1596. x = find_label(tbuf);
  1597. }
  1598. if (x != NULL)
  1599. {
  1600. bwb_Warning_Clear();
  1601. x->position = 0;
  1602. return x;
  1603. }
  1604. return bwb_zline(l);
  1605. }
  1606. /***************************************************************
  1607. FUNCTION: bwb_xnew()
  1608. DESCRIPTION: Clears the program in memory, but does not
  1609. deallocate all variables.
  1610. ***************************************************************/
  1611. void
  1612. bwb_xnew(struct bwb_line * l)
  1613. {
  1614. struct bwb_line *current, *previous;
  1615. int wait;
  1616. bwx_DEBUG(__FUNCTION__);
  1617. previous = NULL; /* JBV */
  1618. wait = TRUE;
  1619. for (current = l->next; current != &CURTASK bwb_end; current = current->next)
  1620. {
  1621. if (wait != TRUE)
  1622. {
  1623. /* Revised to FREE pass-thru call by JBV */
  1624. FREE(previous, "bwb_xnew");
  1625. }
  1626. wait = FALSE;
  1627. previous = current;
  1628. }
  1629. l->next = &bwb_end;
  1630. }
  1631. /***************************************************************
  1632. FUNCTION: bwb_cmds()
  1633. DESCRIPTION: This function implements a CMD command,
  1634. which lists all commands implemented.
  1635. It is not part of a BASIC specification,
  1636. but is used for debugging bwBASIC.
  1637. SYNTAX: CMDS
  1638. ***************************************************************/
  1639. struct bwb_line *
  1640. bwb_CMDS(struct bwb_line * l)
  1641. {
  1642. register int n;
  1643. int t;
  1644. bwx_DEBUG(__FUNCTION__);
  1645. prn_iprintf("BWBASIC COMMANDS AVAILABLE:\n");
  1646. /* run through the command table and print comand names */
  1647. t = 0;
  1648. for (n = 0; n < NUM_COMMANDS; ++n)
  1649. {
  1650. prn_iprintf(bwb_cmdtable[n].name);
  1651. if (t < 4)
  1652. {
  1653. prn_iprintf("\t");
  1654. t++;
  1655. }
  1656. else
  1657. {
  1658. prn_iprintf("\n");
  1659. t = 0;
  1660. }
  1661. }
  1662. if (t > 0)
  1663. {
  1664. prn_iprintf("\n");
  1665. }
  1666. return bwb_zline(l);
  1667. }
  1668. static void
  1669. CommandUniqueID(int i, char *UniqueID)
  1670. {
  1671. char *C;
  1672. bwx_DEBUG(__FUNCTION__);
  1673. strcpy(UniqueID, "C_");
  1674. if (strcasecmp(bwb_cmdtable[i].name, "?") == 0)
  1675. {
  1676. strcat(UniqueID, "QUEST");
  1677. }
  1678. else
  1679. {
  1680. strcat(UniqueID, bwb_cmdtable[i].name);
  1681. }
  1682. C = UniqueID;
  1683. while (*C != '\0')
  1684. {
  1685. if (!isalnum(*C))
  1686. *C = '_';
  1687. C++;
  1688. }
  1689. }
  1690. static void
  1691. CommandVector(int i, char *Vector)
  1692. {
  1693. char *C;
  1694. bwx_DEBUG(__FUNCTION__);
  1695. strcpy(Vector, "bwb_");
  1696. if (strcasecmp(bwb_cmdtable[i].name, "?") == 0)
  1697. {
  1698. strcat(Vector, "QUEST");
  1699. }
  1700. else
  1701. {
  1702. strcat(Vector, bwb_cmdtable[i].name);
  1703. }
  1704. C = Vector;
  1705. while (*C != '\0')
  1706. {
  1707. if (!isalnum(*C))
  1708. *C = '_';
  1709. C++;
  1710. }
  1711. }
  1712. static void
  1713. CommandOptionVersion(int n, char *OutputLine)
  1714. {
  1715. int i;
  1716. int j;
  1717. bwx_DEBUG(__FUNCTION__);
  1718. strcpy(OutputLine, "");
  1719. j = 0;
  1720. for (i = 0; i < NUM_VERSIONS; i++)
  1721. {
  1722. if (bwb_cmdtable[n].OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask)
  1723. {
  1724. if (j > 0)
  1725. {
  1726. strcat(OutputLine, " | ");
  1727. }
  1728. strcat(OutputLine, bwb_vertable[i].ID);
  1729. j++;
  1730. }
  1731. }
  1732. }
  1733. void
  1734. SortAllCommands(void)
  1735. {
  1736. static int IsSorted = FALSE;
  1737. bwx_DEBUG(__FUNCTION__);
  1738. if (IsSorted == FALSE)
  1739. {
  1740. int i;
  1741. for (i = 0; i < NUM_COMMANDS - 1; i++)
  1742. {
  1743. int j;
  1744. int k;
  1745. k = i;
  1746. for (j = i + 1; j < NUM_COMMANDS; j++)
  1747. {
  1748. if (strcasecmp(bwb_cmdtable[j].name, bwb_cmdtable[k].name) < 0)
  1749. {
  1750. k = j;
  1751. }
  1752. }
  1753. if (k > i)
  1754. {
  1755. struct bwb_command t;
  1756. memcpy(&t, &(bwb_cmdtable[i]), sizeof(struct bwb_command));
  1757. memcpy(&(bwb_cmdtable[i]), &(bwb_cmdtable[k]), sizeof(struct bwb_command));
  1758. memcpy(&(bwb_cmdtable[k]), &t, sizeof(struct bwb_command));
  1759. }
  1760. }
  1761. IsSorted = TRUE;
  1762. }
  1763. }
  1764. void
  1765. SortAllFunctions(void)
  1766. {
  1767. static int IsSorted = FALSE;
  1768. bwx_DEBUG(__FUNCTION__);
  1769. if (IsSorted == FALSE)
  1770. {
  1771. int i;
  1772. for (i = 0; i < NUM_FUNCTIONS - 1; i++)
  1773. {
  1774. int j;
  1775. int k;
  1776. k = i;
  1777. for (j = i + 1; j < NUM_FUNCTIONS; j++)
  1778. {
  1779. int n;
  1780. n = strcasecmp(bwb_prefuncs[j].Name, bwb_prefuncs[k].Name);
  1781. if (n < 0)
  1782. {
  1783. k = j;
  1784. }
  1785. else
  1786. if (n == 0)
  1787. {
  1788. if (bwb_prefuncs[j].ParameterCount < bwb_prefuncs[k].ParameterCount)
  1789. {
  1790. k = j;
  1791. }
  1792. }
  1793. }
  1794. if (k > i)
  1795. {
  1796. struct bwb_function t;
  1797. memcpy(&t, &(bwb_prefuncs[i]), sizeof(struct bwb_function));
  1798. memcpy(&(bwb_prefuncs[i]), &(bwb_prefuncs[k]), sizeof(struct bwb_function));
  1799. memcpy(&(bwb_prefuncs[k]), &t, sizeof(struct bwb_function));
  1800. }
  1801. }
  1802. IsSorted = TRUE;
  1803. }
  1804. }
  1805. void
  1806. DumpAllCommandUniqueID(void)
  1807. {
  1808. register int i;
  1809. char tbuf[BasicStringLengthMax + 1];
  1810. bwx_DEBUG(__FUNCTION__);
  1811. prn_lprintf("/* COMMANDS */\n");
  1812. /* run through the command table and print comand #define */
  1813. for (i = 0; i < NUM_COMMANDS; i++)
  1814. {
  1815. char *Syntax;
  1816. char UniqueID[BasicNameLengthMax + 1];
  1817. CommandUniqueID(i, UniqueID);
  1818. Syntax = bwb_cmdtable[i].name;
  1819. sprintf(tbuf, "#define %-30s %3d /* %-30s */\n", UniqueID, i + 1, Syntax);
  1820. prn_lprintf(tbuf);
  1821. }
  1822. sprintf(tbuf, "#define NUM_COMMANDS %d\n", i);
  1823. prn_lprintf(tbuf);
  1824. }
  1825. static void
  1826. ProcessEscapeChars(const char *Input, char *Output)
  1827. {
  1828. int n;
  1829. bwx_DEBUG(__FUNCTION__);
  1830. n = 0;
  1831. while (*Input != '\0')
  1832. {
  1833. switch (*Input)
  1834. {
  1835. case '\n':
  1836. *Output = '\\';
  1837. Output++;
  1838. *Output = 'n';
  1839. Output++;
  1840. break;
  1841. case '\t':
  1842. *Output = '\\';
  1843. Output++;
  1844. *Output = 't';
  1845. Output++;
  1846. break;
  1847. case '\"':
  1848. *Output = '\\';
  1849. Output++;
  1850. *Output = '"';
  1851. Output++;
  1852. break;
  1853. default:
  1854. *Output = *Input;
  1855. Output++;
  1856. break;
  1857. }
  1858. Input++;
  1859. *Output = '\0';
  1860. n++;
  1861. if (n > 60)
  1862. {
  1863. *Output = '\"';
  1864. Output++;
  1865. *Output = '\n';
  1866. Output++;
  1867. *Output = '\"';
  1868. Output++;
  1869. *Output = '\0';
  1870. n = 0;
  1871. }
  1872. }
  1873. }
  1874. void
  1875. DumpAllCommandTableDefinitions(void)
  1876. {
  1877. /* generate bwd_cmd.c */
  1878. int i;
  1879. bwx_DEBUG(__FUNCTION__);
  1880. prn_lprintf("/* COMMAND TABLE */\n\n");
  1881. prn_lprintf("#include \"bwbasic.h\"\n\n");
  1882. prn_lprintf("struct bwb_command bwb_cmdtable[ NUM_COMMANDS ] =\n");
  1883. prn_lprintf("{\n");
  1884. /* run through the command table and print comand #define */
  1885. for (i = 0; i < NUM_COMMANDS; i++)
  1886. {
  1887. char tbuf[BasicStringLengthMax + 1];
  1888. prn_lprintf("{\n");
  1889. prn_lprintf(" ");
  1890. CommandUniqueID(i, tbuf);
  1891. prn_lprintf(tbuf);
  1892. prn_lprintf(", /* UniqueID */\n");
  1893. prn_lprintf(" ");
  1894. prn_lprintf("\"");
  1895. ProcessEscapeChars(bwb_cmdtable[i].Syntax, tbuf);
  1896. prn_lprintf(tbuf);
  1897. prn_lprintf("\"");
  1898. prn_lprintf(", /* Syntax */\n");
  1899. prn_lprintf(" ");
  1900. prn_lprintf("\"");
  1901. ProcessEscapeChars(bwb_cmdtable[i].Description, tbuf);
  1902. prn_lprintf(tbuf);
  1903. prn_lprintf("\"");
  1904. prn_lprintf(", /* Description */\n");
  1905. prn_lprintf(" ");
  1906. prn_lprintf("\"");
  1907. prn_lprintf(bwb_cmdtable[i].name);
  1908. prn_lprintf("\"");
  1909. prn_lprintf(", /* Name */\n");
  1910. prn_lprintf(" ");
  1911. CommandOptionVersion(i, tbuf);
  1912. prn_lprintf(tbuf);
  1913. prn_lprintf(" /* OptionVersionBitmask */\n");
  1914. prn_lprintf("},\n");
  1915. }
  1916. prn_lprintf("};\n\n");
  1917. }
  1918. void
  1919. DumpAllCommandSwitchStatement(void)
  1920. {
  1921. int i;
  1922. bwx_DEBUG(__FUNCTION__);
  1923. /* run through the command table and print comand #define */
  1924. prn_lprintf("/* SWITCH */\n");
  1925. prn_lprintf("struct bwb_line *bwb_vector( struct bwb_line *l )\n");
  1926. prn_lprintf("{\n");
  1927. prn_lprintf(" ");
  1928. prn_lprintf("struct bwb_line *r;\n");
  1929. prn_lprintf(" ");
  1930. prn_lprintf("switch( l->cmdnum )\n");
  1931. prn_lprintf(" ");
  1932. prn_lprintf("{\n");
  1933. for (i = 0; i < NUM_COMMANDS; i++)
  1934. {
  1935. char tbuf[BasicNameLengthMax + 1];
  1936. prn_lprintf(" ");
  1937. prn_lprintf("case ");
  1938. CommandUniqueID(i, tbuf);
  1939. prn_lprintf(tbuf);
  1940. prn_lprintf(":\n");
  1941. prn_lprintf(" ");
  1942. prn_lprintf(" ");
  1943. prn_lprintf("r = ");
  1944. CommandVector(i, tbuf);
  1945. prn_lprintf(tbuf);
  1946. prn_lprintf("( l );\n");
  1947. prn_lprintf(" ");
  1948. prn_lprintf(" ");
  1949. prn_lprintf("break;\n");
  1950. }
  1951. prn_lprintf(" ");
  1952. prn_lprintf("default:\n");
  1953. prn_lprintf(" ");
  1954. prn_lprintf(" ");
  1955. prn_lprintf("sprintf( bwb_ebuf, \"in bwb_vector(), INTERNAL ERROR: %d not in switch\", l->cmdnum );\n");
  1956. prn_lprintf(" ");
  1957. prn_lprintf(" ");
  1958. prn_lprintf("bwb_error( bwb_ebuf );\n");
  1959. prn_lprintf(" ");
  1960. prn_lprintf(" ");
  1961. prn_lprintf("r = l;\n");
  1962. prn_lprintf(" ");
  1963. prn_lprintf(" ");
  1964. prn_lprintf("break;\n");
  1965. prn_lprintf(" ");
  1966. prn_lprintf("}\n");
  1967. prn_lprintf(" ");
  1968. prn_lprintf("return r;\n");
  1969. prn_lprintf("}\n");
  1970. }
  1971. void
  1972. DumpOneCommandSyntax(int n, int lp)
  1973. {
  1974. char tbuf[BasicStringLengthMax + 1];
  1975. bwx_DEBUG(__FUNCTION__);
  1976. if (n < 0 || n >= NUM_COMMANDS)
  1977. {
  1978. return;
  1979. }
  1980. /* NAME */
  1981. {
  1982. sprintf(tbuf, " SYNTAX: %s\n", bwb_cmdtable[n].Syntax);
  1983. if (lp)
  1984. {
  1985. prn_lprintf(tbuf);
  1986. }
  1987. else
  1988. {
  1989. prn_xprintf(tbuf);
  1990. }
  1991. }
  1992. /* DESCRIPTION */
  1993. {
  1994. sprintf(tbuf, "DESCRIPTION: %s\n", bwb_cmdtable[n].Description);
  1995. if (lp)
  1996. {
  1997. prn_lprintf(tbuf);
  1998. }
  1999. else
  2000. {
  2001. prn_xprintf(tbuf);
  2002. }
  2003. }
  2004. /* COMPATIBILITY */
  2005. if (lp)
  2006. {
  2007. int i;
  2008. sprintf(tbuf, " VERSIONS:\n");
  2009. if (lp)
  2010. {
  2011. prn_lprintf(tbuf);
  2012. }
  2013. else
  2014. {
  2015. prn_xprintf(tbuf);
  2016. }
  2017. for (i = 0; i < NUM_VERSIONS; i++)
  2018. {
  2019. char X;
  2020. if (bwb_cmdtable[n].OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask)
  2021. {
  2022. /* SUPPORTED */
  2023. X = 'X';
  2024. }
  2025. else
  2026. {
  2027. /* NOT SUPPORTED */
  2028. X = '_';
  2029. }
  2030. sprintf(tbuf, " [%c] %s\n", X, bwb_vertable[i].Name);
  2031. if (lp)
  2032. {
  2033. prn_lprintf(tbuf);
  2034. }
  2035. else
  2036. {
  2037. prn_xprintf(tbuf);
  2038. }
  2039. }
  2040. }
  2041. }
  2042. void
  2043. DumpAllCommandSyntax(void)
  2044. {
  2045. /* for the C maintainer */
  2046. int n;
  2047. bwx_DEBUG(__FUNCTION__);
  2048. for (n = 0; n < NUM_COMMANDS; n++)
  2049. {
  2050. prn_lprintf("------------------------------------------------------------\n");
  2051. DumpOneCommandSyntax(n, TRUE);
  2052. }
  2053. prn_lprintf("------------------------------------------------------------\n");
  2054. }
  2055. void
  2056. DumpAllCommandHtmlTable(void)
  2057. {
  2058. /* generate bwd_cmd.htm */
  2059. int i;
  2060. int j;
  2061. bwx_DEBUG(__FUNCTION__);
  2062. /* LEGEND */
  2063. prn_lprintf("<h1>LEGEND</h1><br>\n");
  2064. prn_lprintf("<table>\n");
  2065. prn_lprintf("<tr>");
  2066. prn_lprintf("<td>");
  2067. prn_lprintf("<b>");
  2068. prn_lprintf("ID");
  2069. prn_lprintf("</b>");
  2070. prn_lprintf("</td>");
  2071. prn_lprintf("<td>");
  2072. prn_lprintf("<b>");
  2073. prn_lprintf("NAME");
  2074. prn_lprintf("</b>");
  2075. prn_lprintf("</td>");
  2076. prn_lprintf("<td>");
  2077. prn_lprintf("<b>");
  2078. prn_lprintf("DESCRIPTION");
  2079. prn_lprintf("</b>");
  2080. prn_lprintf("</td>");
  2081. prn_lprintf("</tr>\n");
  2082. for (j = 0; j < NUM_VERSIONS; j++)
  2083. {
  2084. prn_lprintf("<tr>");
  2085. prn_lprintf("<td>");
  2086. prn_lprintf(bwb_vertable[j].ID);
  2087. prn_lprintf("</td>");
  2088. prn_lprintf("<td>");
  2089. prn_lprintf(bwb_vertable[j].Name);
  2090. prn_lprintf("</td>");
  2091. prn_lprintf("<td>");
  2092. prn_lprintf(bwb_vertable[j].Description);
  2093. prn_lprintf("</td>");
  2094. prn_lprintf("</tr>\n");
  2095. }
  2096. prn_lprintf("</table>\n");
  2097. prn_lprintf("<hr>\n");
  2098. /* DETAILS */
  2099. prn_lprintf("<h1>DETAILS</h1><br>\n");
  2100. prn_lprintf("<table>\n");
  2101. prn_lprintf("<tr>");
  2102. prn_lprintf("<td>");
  2103. prn_lprintf("<b>");
  2104. prn_lprintf("COMMAND");
  2105. prn_lprintf("</b>");
  2106. prn_lprintf("</td>");
  2107. for (j = 0; j < NUM_VERSIONS; j++)
  2108. {
  2109. prn_lprintf("<td>");
  2110. prn_lprintf("<b>");
  2111. prn_lprintf(bwb_vertable[j].ID);
  2112. prn_lprintf("</b>");
  2113. prn_lprintf("</td>");
  2114. }
  2115. prn_lprintf("</tr>\n");
  2116. /* run through the command table and print comand -vs- OPTION VERSION */
  2117. for (i = 0; i < NUM_COMMANDS; i++)
  2118. {
  2119. prn_lprintf("<tr>");
  2120. prn_lprintf("<td>");
  2121. prn_lprintf(bwb_cmdtable[i].name);
  2122. prn_lprintf("</td>");
  2123. for (j = 0; j < NUM_VERSIONS; j++)
  2124. {
  2125. prn_lprintf("<td>");
  2126. if (bwb_cmdtable[i].OptionVersionBitmask & bwb_vertable[j].OptionVersionBitmask)
  2127. {
  2128. prn_lprintf("X");
  2129. }
  2130. else
  2131. {
  2132. prn_lprintf(" ");
  2133. }
  2134. prn_lprintf("</td>");
  2135. }
  2136. prn_lprintf("</tr>\n");
  2137. }
  2138. prn_lprintf("</table>\n");
  2139. prn_lprintf("\n");
  2140. }
  2141. struct bwb_line *
  2142. bwb_HELP(struct bwb_line * l)
  2143. {
  2144. /* HELP ... */
  2145. int n;
  2146. char tbuf[BasicStringLengthMax + 1];
  2147. int Found;
  2148. char * C;
  2149. bwx_DEBUG(__FUNCTION__);
  2150. Found = FALSE;
  2151. C = l->buffer;
  2152. C += l->position;
  2153. strcpy( tbuf, C );
  2154. C = strchr( tbuf, OptionCommentChar );
  2155. if( C != NULL )
  2156. {
  2157. *C = '\0';
  2158. }
  2159. /* RTRIM$ */
  2160. C = tbuf;
  2161. if (*C != 0)
  2162. {
  2163. /* not an empty line, so remove one (or more) trailing spaces */
  2164. char *E;
  2165. E = strchr(tbuf, 0);
  2166. E--;
  2167. while (E >= tbuf && *E == ' ')
  2168. {
  2169. *E = 0;
  2170. E--;
  2171. }
  2172. }
  2173. /* EXACT match */
  2174. for (n = 0; n < NUM_COMMANDS; n++)
  2175. {
  2176. if (strcasecmp(bwb_cmdtable[n].name, tbuf) == 0)
  2177. {
  2178. prn_xprintf("------------------------------------------------------------\n");
  2179. DumpOneCommandSyntax(n, FALSE);
  2180. Found = TRUE;
  2181. }
  2182. }
  2183. for (n = 0; n < NUM_FUNCTIONS; n++)
  2184. {
  2185. if (strcasecmp(bwb_prefuncs[n].Name, tbuf) == 0)
  2186. {
  2187. prn_xprintf("------------------------------------------------------------\n");
  2188. DumpOneFunctionSyntax(n, FALSE);
  2189. Found = TRUE;
  2190. }
  2191. }
  2192. if (Found == FALSE)
  2193. {
  2194. /* PARTIAL match */
  2195. int Length;
  2196. Length = strlen(tbuf);
  2197. for (n = 0; n < NUM_COMMANDS; n++)
  2198. {
  2199. if (strncasecmp(bwb_cmdtable[n].name, tbuf, Length) == 0)
  2200. {
  2201. if (Found == FALSE)
  2202. {
  2203. prn_xprintf("The following topics are a partial match:\n");
  2204. }
  2205. prn_xprintf(bwb_cmdtable[n].name);
  2206. prn_xprintf("\t");
  2207. Found = TRUE;
  2208. }
  2209. }
  2210. for (n = 0; n < NUM_FUNCTIONS; n++)
  2211. {
  2212. if (strncasecmp(bwb_prefuncs[n].Name, tbuf, Length) == 0)
  2213. {
  2214. if (Found == FALSE)
  2215. {
  2216. prn_xprintf("The following topics are a partial match:\n");
  2217. }
  2218. prn_xprintf(bwb_prefuncs[n].Name);
  2219. prn_xprintf("\t");
  2220. Found = TRUE;
  2221. }
  2222. }
  2223. if (Found == TRUE)
  2224. {
  2225. /* match */
  2226. prn_xprintf("\n");
  2227. }
  2228. }
  2229. if (Found == FALSE)
  2230. {
  2231. /* NO match */
  2232. prn_xprintf("No help found.\n");
  2233. }
  2234. adv_eos(l->buffer, &(l->position));
  2235. return bwb_zline(l);
  2236. }
  2237. int
  2238. NumberValueCheck(unsigned long ParameterTests, BasicNumberType X)
  2239. {
  2240. BasicNumberType XR; /* rounded value */
  2241. bwx_DEBUG(__FUNCTION__);
  2242. /* check for invalid numeric value */
  2243. if (isnan(X))
  2244. {
  2245. /* INTERNAL ERROR */
  2246. return -1;
  2247. }
  2248. /* VALID NUMERIC VALUE */
  2249. XR = rint(X);
  2250. ParameterTests &= 0x0000000F;
  2251. switch (ParameterTests)
  2252. {
  2253. case P1ERR:
  2254. {
  2255. /* INTERNAL ERROR */
  2256. return -1;
  2257. }
  2258. break;
  2259. case P1ANY:
  2260. if (XR < -DBL_MAX || XR > DBL_MAX)
  2261. {
  2262. /* ERROR */
  2263. return -1;
  2264. }
  2265. else
  2266. {
  2267. /* OK */
  2268. return 0;
  2269. }
  2270. case P1BYT:
  2271. if (XR < 0 || XR > UCHAR_MAX)
  2272. {
  2273. /* ERROR */
  2274. return -1;
  2275. }
  2276. else
  2277. {
  2278. /* OK */
  2279. return 0;
  2280. }
  2281. break;
  2282. case P1INT:
  2283. if (XR < SHRT_MIN || XR > SHRT_MAX)
  2284. {
  2285. /* ERROR */
  2286. return -1;
  2287. }
  2288. else
  2289. {
  2290. /* OK */
  2291. return 0;
  2292. }
  2293. break;
  2294. case P1LNG:
  2295. if (XR < LONG_MIN || XR > LONG_MAX)
  2296. {
  2297. /* ERROR */
  2298. return -1;
  2299. }
  2300. else
  2301. {
  2302. /* OK */
  2303. return 0;
  2304. }
  2305. break;
  2306. case P1CUR:
  2307. if (XR < LONG_MIN || XR > LONG_MAX)
  2308. {
  2309. /* ERROR */
  2310. return -1;
  2311. }
  2312. else
  2313. {
  2314. /* OK */
  2315. return 0;
  2316. }
  2317. break;
  2318. case P1FLT:
  2319. if (X < -FLT_MAX || X > FLT_MAX)
  2320. {
  2321. /* ERROR */
  2322. return -1;
  2323. }
  2324. else
  2325. {
  2326. /* OK */
  2327. return 0;
  2328. }
  2329. break;
  2330. case P1DBL:
  2331. if (X < -DBL_MAX || X > DBL_MAX)
  2332. {
  2333. /* ERROR */
  2334. return -1;
  2335. }
  2336. else
  2337. {
  2338. /* OK */
  2339. return 0;
  2340. }
  2341. break;
  2342. case P1DEV:
  2343. /* BasicFileNumberMax must be <= INT16_MAX */
  2344. if (XR < 0 || XR > BasicFileNumberMax)
  2345. {
  2346. /* ERROR */
  2347. return -1;
  2348. }
  2349. else
  2350. {
  2351. /* OK */
  2352. return 0;
  2353. }
  2354. break;
  2355. case P1LEN:
  2356. /* BasicStringLengthMax must be <= INT16_MAX */
  2357. if (XR < 0 || XR > BasicStringLengthMax)
  2358. {
  2359. /* ERROR */
  2360. return -1;
  2361. }
  2362. else
  2363. {
  2364. /* OK */
  2365. return 0;
  2366. }
  2367. break;
  2368. case P1POS:
  2369. /* BasicStringLengthMax must be <= INT16_MAX */
  2370. if (XR < 1 || XR > BasicStringLengthMax)
  2371. {
  2372. /* ERROR */
  2373. return -1;
  2374. }
  2375. else
  2376. {
  2377. /* OK */
  2378. return 0;
  2379. }
  2380. break;
  2381. case P1COM:
  2382. /* Number of COMx: ports must be <= INT16_MAX */
  2383. if (XR == 1 || XR == 2 || XR == 3 || XR == 4)
  2384. {
  2385. /* OK */
  2386. return 0;
  2387. }
  2388. break;
  2389. case P1LPT:
  2390. /* Number of LPTx: ports must be <= INT16_MAX */
  2391. if (XR == 0 || XR == 1 || XR == 2 || XR == 3)
  2392. {
  2393. /* OK */
  2394. return 0;
  2395. }
  2396. break;
  2397. case P1GTZ:
  2398. if (X > 0)
  2399. {
  2400. /* OK */
  2401. return 0;
  2402. }
  2403. break;
  2404. case P1GEZ:
  2405. if (X >= 0)
  2406. {
  2407. /* OK */
  2408. return 0;
  2409. }
  2410. break;
  2411. case P1NEZ:
  2412. if (X != 0)
  2413. {
  2414. /* OK */
  2415. return 0;
  2416. }
  2417. break;
  2418. }
  2419. /* ERROR */
  2420. return -1;
  2421. }
  2422. int
  2423. StringLengthCheck(unsigned long ParameterTests, int s)
  2424. {
  2425. bwx_DEBUG(__FUNCTION__);
  2426. /* check for invalid string length */
  2427. if (s < 0 || s > BasicStringLengthMax)
  2428. {
  2429. /* INTERNAL ERROR */
  2430. return -1;
  2431. }
  2432. /* VALID STRING LENGTH */
  2433. ParameterTests &= 0x0000000F;
  2434. switch (ParameterTests)
  2435. {
  2436. case P1ERR:
  2437. {
  2438. /* INTERNAL ERROR */
  2439. return -1;
  2440. }
  2441. break;
  2442. case P1ANY:
  2443. {
  2444. /* OK */
  2445. return 0;
  2446. }
  2447. break;
  2448. case P1BYT:
  2449. if (s >= sizeof(BasicByteType))
  2450. {
  2451. /* OK */
  2452. return 0;
  2453. }
  2454. break;
  2455. case P1INT:
  2456. if (s >= sizeof(BasicIntegerType))
  2457. {
  2458. /* OK */
  2459. return 0;
  2460. }
  2461. break;
  2462. case P1LNG:
  2463. if (s >= sizeof(BasicLongType))
  2464. {
  2465. /* OK */
  2466. return 0;
  2467. }
  2468. break;
  2469. case P1CUR:
  2470. if (s >= sizeof(BasicCurrencyType))
  2471. {
  2472. /* OK */
  2473. return 0;
  2474. }
  2475. break;
  2476. case P1FLT:
  2477. if (s >= sizeof(BasicSingleType))
  2478. {
  2479. /* OK */
  2480. return 0;
  2481. }
  2482. break;
  2483. case P1DBL:
  2484. if (s >= sizeof(BasicDoubleType))
  2485. {
  2486. /* OK */
  2487. return 0;
  2488. }
  2489. break;
  2490. case P1DEV:
  2491. case P1LEN:
  2492. case P1POS:
  2493. case P1GEZ:
  2494. case P1GTZ:
  2495. case P1NEZ:
  2496. {
  2497. /* ERROR */
  2498. return -1;
  2499. }
  2500. break;
  2501. }
  2502. /* ERROR */
  2503. return -1;
  2504. }
  2505. void
  2506. FunctionDefinitionCheck(struct bwb_function * f)
  2507. {
  2508. /* function definition check -- look for obvious errors */
  2509. char bwb_ebuf[BasicStringLengthMax + 1];
  2510. bwx_DEBUG(__FUNCTION__);
  2511. /* sanity check */
  2512. if (f->ParameterCount == PNONE)
  2513. {
  2514. /* function has NO parameters */
  2515. if (f->ParameterTypes == PNONE)
  2516. {
  2517. /* OK */
  2518. }
  2519. else
  2520. {
  2521. /* oops */
  2522. sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTypes <%s>\n", f->Name);
  2523. prn_xprintf(bwb_ebuf);
  2524. }
  2525. if (f->ParameterTests == PNONE)
  2526. {
  2527. /* OK */
  2528. }
  2529. else
  2530. {
  2531. /* oops */
  2532. sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s>\n", f->Name);
  2533. prn_xprintf(bwb_ebuf);
  2534. }
  2535. }
  2536. else
  2537. {
  2538. /* function HAS parameters */
  2539. int i;
  2540. unsigned long ParameterTests;
  2541. ParameterTests = f->ParameterTests;
  2542. for (i = 0; i < f->ParameterCount; i++)
  2543. {
  2544. /* sanity check this parameter */
  2545. unsigned long thischeck;
  2546. thischeck = ParameterTests & 0x0000000F;
  2547. /* verify parameter check */
  2548. if (f->ParameterTypes & (1 << i))
  2549. {
  2550. /* STRING */
  2551. if (thischeck >= P1ANY && thischeck <= P1DBL)
  2552. {
  2553. /* OK */
  2554. }
  2555. else
  2556. {
  2557. /* oops */
  2558. sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s> parameter %d\n", f->Name, i + 1);
  2559. prn_xprintf(bwb_ebuf);
  2560. }
  2561. }
  2562. else
  2563. {
  2564. /* NUMBER */
  2565. if (thischeck >= P1ANY && thischeck <= P1NEZ)
  2566. {
  2567. /* OK */
  2568. }
  2569. else
  2570. {
  2571. /* oops */
  2572. sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s> parameter %d\n", f->Name, i + 1);
  2573. prn_xprintf(bwb_ebuf);
  2574. }
  2575. }
  2576. ParameterTests = ParameterTests >> 4;
  2577. }
  2578. if (ParameterTests != 0)
  2579. {
  2580. /* oops */
  2581. sprintf(bwb_ebuf, "in fnc_init(): invalid ParameterTests <%s> parameter %d\n", f->Name, i + 1);
  2582. prn_xprintf(bwb_ebuf);
  2583. }
  2584. }
  2585. }
  2586. void
  2587. FunctionUniqueID(struct bwb_function * f, char *UniqueID)
  2588. {
  2589. /* generate the function's UniqueID */
  2590. /* manual fixup required for duplicates */
  2591. char *D; /* location of $ */
  2592. char NumVar;
  2593. char StrVar;
  2594. bwx_DEBUG(__FUNCTION__);
  2595. NumVar = 'X';
  2596. StrVar = 'A';
  2597. /* F_ */
  2598. strcpy(UniqueID, "F_");
  2599. /* NAME */
  2600. strcat(UniqueID, f->Name);
  2601. D = strchr(UniqueID, BasicStringSuffix);
  2602. if (D == NULL)
  2603. {
  2604. /* NOT FOUND */
  2605. }
  2606. else
  2607. {
  2608. /* FOUND */
  2609. *D = 0; /* remove it */
  2610. }
  2611. /* PARAMETERS */
  2612. if (f->ParameterCount == PNONE)
  2613. {
  2614. /* function has NO parameters */
  2615. }
  2616. else
  2617. {
  2618. /* function HAS parameters */
  2619. int i;
  2620. unsigned int ParameterTypes;
  2621. /* unsigned long ParameterTests; */
  2622. ParameterTypes = f->ParameterTypes;
  2623. /* ParameterTests = f->ParameterTests; */
  2624. for (i = 0; i < f->ParameterCount; i++)
  2625. {
  2626. char VarName[BasicNameLengthMax + 1];
  2627. /* sanity check this parameter */
  2628. /* unsigned long thischeck; thischeck =
  2629. * ParameterTests & 0x0000000F; */
  2630. /* verify parameter check */
  2631. if (ParameterTypes & 1)
  2632. {
  2633. /* STRING */
  2634. sprintf(VarName, "_%c", StrVar);
  2635. StrVar++;
  2636. }
  2637. else
  2638. {
  2639. /* NUMBER */
  2640. sprintf(VarName, "_%c", NumVar);
  2641. NumVar++;
  2642. }
  2643. strcat(UniqueID, VarName);
  2644. ParameterTypes = ParameterTypes >> 1;
  2645. /* ParameterTests = ParameterTests >> 4; */
  2646. }
  2647. }
  2648. /* RETURN TYPE */
  2649. switch (f->ReturnType)
  2650. {
  2651. case STRING:
  2652. strcat(UniqueID, "_S");
  2653. break;
  2654. case NUMBER:
  2655. strcat(UniqueID, "_N");
  2656. break;
  2657. default:
  2658. strcat(UniqueID, "_INTERNAL ERROR");
  2659. break;
  2660. }
  2661. /* fixup illegal characters, "DEF FN" "BLOAD:", "CLOAD*" */
  2662. {
  2663. char *P;
  2664. P = UniqueID;
  2665. while (*P)
  2666. {
  2667. if (isalnum(*P))
  2668. {
  2669. /* OK */
  2670. }
  2671. else
  2672. {
  2673. /* FIXUP */
  2674. *P = '_';
  2675. }
  2676. P++;
  2677. }
  2678. }
  2679. }
  2680. void
  2681. FunctionSyntax(struct bwb_function * f, char *Syntax)
  2682. {
  2683. /* generate the function's Syntax */
  2684. char NumVar;
  2685. char StrVar;
  2686. bwx_DEBUG(__FUNCTION__);
  2687. NumVar = 'X';
  2688. StrVar = 'A';
  2689. /* RETURN TYPE */
  2690. switch (f->ReturnType)
  2691. {
  2692. case STRING:
  2693. strcpy(Syntax, "S$ = ");
  2694. break;
  2695. case NUMBER:
  2696. strcpy(Syntax, "N = ");
  2697. break;
  2698. default:
  2699. strcpy(Syntax, "INTERNAL ERROR = ");
  2700. break;
  2701. }
  2702. /* NAME */
  2703. strcat(Syntax, f->Name);
  2704. /* PARAMETERS */
  2705. if (f->ParameterCount == PNONE)
  2706. {
  2707. /* function has NO parameters */
  2708. }
  2709. else
  2710. {
  2711. /* function HAS parameters */
  2712. int i;
  2713. unsigned int ParameterTypes;
  2714. /* unsigned long ParameterTests; */
  2715. ParameterTypes = f->ParameterTypes;
  2716. /* ParameterTests = f->ParameterTests; */
  2717. switch (f->ReturnType)
  2718. {
  2719. case STRING:
  2720. strcat(Syntax, "( ");
  2721. break;
  2722. case NUMBER:
  2723. strcat(Syntax, "( ");
  2724. break;
  2725. default:
  2726. strcat(Syntax, "INTERNAL ERROR( ");
  2727. break;
  2728. }
  2729. for (i = 0; i < f->ParameterCount; i++)
  2730. {
  2731. char VarName[BasicNameLengthMax + 1];
  2732. /* sanity check this parameter */
  2733. /* unsigned long thischeck; thischeck =
  2734. * ParameterTests & 0x0000000F; */
  2735. if (i > 0)
  2736. {
  2737. strcat(Syntax, ", ");
  2738. }
  2739. /* verify parameter check */
  2740. if (ParameterTypes & 1)
  2741. {
  2742. /* STRING */
  2743. sprintf(VarName, "%c$", StrVar);
  2744. StrVar++;
  2745. }
  2746. else
  2747. {
  2748. /* NUMBER */
  2749. sprintf(VarName, "%c", NumVar);
  2750. NumVar++;
  2751. }
  2752. strcat(Syntax, VarName);
  2753. ParameterTypes = ParameterTypes >> 1;
  2754. /* ParameterTests = ParameterTests >> 4; */
  2755. }
  2756. switch (f->ReturnType)
  2757. {
  2758. case STRING:
  2759. strcat(Syntax, " )");
  2760. break;
  2761. case NUMBER:
  2762. strcat(Syntax, " )");
  2763. break;
  2764. default:
  2765. strcat(Syntax, " INTERNAL ERROR)");
  2766. break;
  2767. }
  2768. }
  2769. }
  2770. void
  2771. DumpAllFuctionUniqueID(void)
  2772. {
  2773. /* for the C maintainer */
  2774. char tbuf[BasicStringLengthMax + 1];
  2775. int i;
  2776. bwx_DEBUG(__FUNCTION__);
  2777. prn_lprintf("/* FUNCTIONS */\n");
  2778. for (i = 0; i < NUM_FUNCTIONS; i++)
  2779. {
  2780. char UniqueID[BasicStringLengthMax + 1];
  2781. char Syntax[BasicStringLengthMax + 1];
  2782. FunctionUniqueID(&(bwb_prefuncs[i]), UniqueID);
  2783. FunctionSyntax(&(bwb_prefuncs[i]), Syntax);
  2784. sprintf(tbuf, "#define %-30s %3d /* %-30s */\n", UniqueID, i + 1, Syntax);
  2785. prn_lprintf(tbuf);
  2786. }
  2787. sprintf(tbuf, "#define NUM_FUNCTIONS %d\n", i);
  2788. prn_lprintf(tbuf);
  2789. }
  2790. void
  2791. DumpAllFunctionSwitch(void)
  2792. {
  2793. /* for the C maintainer */
  2794. int i;
  2795. bwx_DEBUG(__FUNCTION__);
  2796. prn_lprintf("/* SWITCH */\n");
  2797. prn_lprintf("switch( UniqueID )\n");
  2798. prn_lprintf("{\n");
  2799. for (i = 0; i < NUM_FUNCTIONS; i++)
  2800. {
  2801. char tbuf[BasicStringLengthMax + 1];
  2802. prn_lprintf("case ");
  2803. FunctionUniqueID(&(bwb_prefuncs[i]), tbuf);
  2804. prn_lprintf(tbuf);
  2805. prn_lprintf(":\n");
  2806. prn_lprintf(" break;\n");
  2807. }
  2808. prn_lprintf("}\n");
  2809. }
  2810. static const char *ParameterRangeID[16] =
  2811. {
  2812. "P%dERR",
  2813. "P%dANY",
  2814. "P%dBYT",
  2815. "P%dINT",
  2816. "P%dLNG",
  2817. "P%dCUR",
  2818. "P%dFLT",
  2819. "P%dDBL",
  2820. "P%dDEV",
  2821. "P%dLEN",
  2822. "P%dPOS",
  2823. "P%dCOM",
  2824. "P%dLPT",
  2825. "P%dGTZ",
  2826. "P%dGEZ",
  2827. "P%dNEZ",
  2828. };
  2829. static const char *NumberVariableRange[16] =
  2830. {
  2831. /* P1ERR */ " PARAMETER: %c is a number, INTERNAL ERROR",
  2832. /* P1ANY */ " PARAMETER: %c is a number",
  2833. /* P1BYT */ " PARAMETER: %c is a number, [0,255]",
  2834. /* P1INT */ " PARAMETER: %c is a number, [MININT,MAXINT]",
  2835. /* P1LNG */ " PARAMETER: %c is a number, [MINLNG,MAXLNG]",
  2836. /* P1CUR */ " PARAMETER: %c is a number, [MINCUR,MAXCUR]",
  2837. /* P1FLT */ " PARAMETER: %c is a number, [MINFLT,MAXFLT]",
  2838. /* P1DBL */ " PARAMETER: %c is a number, [MINDBL,MAXDBL]",
  2839. /* P1DEV */ " PARAMETER: %c is a number, [1,MAXDEV]",
  2840. /* P1LEN */ " PARAMETER: %c is a number, [0,MAXLEN]",
  2841. /* P1POS */ " PARAMETER: %c is a number, [1,MAXLEN]",
  2842. /* P1COM */ " PARAMETER: %c is a number, [1,4]",
  2843. /* P1LPT */ " PARAMETER: %c is a number, [0,3]",
  2844. /* P1GTZ */ " PARAMETER: %c is a number, > 0",
  2845. /* P1GEZ */ " PARAMETER: %c is a number, >= 0",
  2846. /* P1NEZ */ " PARAMETER: %c is a number, <> 0",
  2847. };
  2848. static const char *StringVariableRange[16] =
  2849. {
  2850. /* P1ERR */ " PARAMETER: %c$ is a string, INTERNAL ERROR",
  2851. /* P1ANY */ " PARAMETER: %c$ is a string, LEN >= 0",
  2852. /* P1BYT */ " PARAMETER: %c$ is a string, LEN >= 1",
  2853. /* P1INT */ " PARAMETER: %c$ is a string, LEN >= sizeof(INT)",
  2854. /* P1LNG */ " PARAMETER: %c$ is a string, LEN >= sizeof(LNG)",
  2855. /* P1CUR */ " PARAMETER: %c$ is a string, LEN >= sizeof(CUR)",
  2856. /* P1FLT */ " PARAMETER: %c$ is a string, LEN >= sizeof(FLT)",
  2857. /* P1DBL */ " PARAMETER: %c$ is a string, LEN >= sizeof(DBL)",
  2858. /* P1DEV */ " PARAMETER: %c$ is a string, RESERVED",
  2859. /* P1LEN */ " PARAMETER: %c$ is a string, RESERVED",
  2860. /* P1POS */ " PARAMETER: %c$ is a string, RESERVED",
  2861. /* P1COM */ " PARAMETER: %c$ is a string, RESERVED",
  2862. /* P1LPT */ " PARAMETER: %c$ is a string, RESERVED",
  2863. /* P1GTZ */ " PARAMETER: %c$ is a string, RESERVED",
  2864. /* P1GEZ */ " PARAMETER: %c$ is a string, RESERVED",
  2865. /* P1NEZ */ " PARAMETER: %c$ is a string, RESERVED",
  2866. };
  2867. void
  2868. DumpAllFuctionTableDefinitions(void)
  2869. {
  2870. /* generate bwd_fun.c */
  2871. int n;
  2872. bwx_DEBUG(__FUNCTION__);
  2873. prn_lprintf("/* FUNCTION TABLE */\n\n");
  2874. prn_lprintf("#include \"bwbasic.h\"\n\n");
  2875. prn_lprintf("struct bwb_function bwb_prefuncs[ NUM_FUNCTIONS ] =\n");
  2876. prn_lprintf("{\n");
  2877. for (n = 0; n < NUM_FUNCTIONS; n++)
  2878. {
  2879. int i;
  2880. int j;
  2881. char tbuf[BasicStringLengthMax + 1];
  2882. char UniqueID[BasicStringLengthMax + 1];
  2883. char Syntax[BasicStringLengthMax + 1];
  2884. struct bwb_function *f;
  2885. f = &(bwb_prefuncs[n]);
  2886. FunctionUniqueID(f, UniqueID);
  2887. FunctionSyntax(f, Syntax);
  2888. prn_lprintf("{\n");
  2889. sprintf(tbuf, " %s, /* UniqueID */\n", UniqueID);
  2890. prn_lprintf(tbuf);
  2891. sprintf(tbuf, " \"%s\", /* Syntax */\n", Syntax);
  2892. prn_lprintf(tbuf);
  2893. prn_lprintf(" ");
  2894. prn_lprintf("\"");
  2895. ProcessEscapeChars(f->Description, tbuf);
  2896. prn_lprintf(tbuf);
  2897. prn_lprintf("\"");
  2898. prn_lprintf(", /* Description */\n");
  2899. sprintf(tbuf, " \"%s\", /* Name */\n", f->Name);
  2900. prn_lprintf(tbuf);
  2901. switch (f->ReturnType)
  2902. {
  2903. case STRING:
  2904. sprintf(tbuf, " %s, /* ReturnType */\n", "STRING");
  2905. break;
  2906. case NUMBER:
  2907. sprintf(tbuf, " %s, /* ReturnType */\n", "NUMBER");
  2908. break;
  2909. default:
  2910. sprintf(tbuf, " %s, /* ReturnType */\n", "INTERNAL ERROR");
  2911. break;
  2912. }
  2913. prn_lprintf(tbuf);
  2914. sprintf(tbuf, " %d, /* ParameterCount */\n", f->ParameterCount);
  2915. prn_lprintf(tbuf);
  2916. if (f->ParameterCount == 0)
  2917. {
  2918. sprintf(tbuf, " %s, /* ParameterTypes */\n", "PNONE");
  2919. prn_lprintf(tbuf);
  2920. sprintf(tbuf, " %s, /* ParameterTests */\n", "PNONE");
  2921. prn_lprintf(tbuf);
  2922. }
  2923. else
  2924. {
  2925. strcpy(tbuf, " ");
  2926. for (i = 0; i < f->ParameterCount; i++)
  2927. {
  2928. int ParameterTypes;
  2929. ParameterTypes = f->ParameterTypes >> i;
  2930. ParameterTypes &= 0x1;
  2931. if (i > 0)
  2932. {
  2933. strcat(tbuf, " | ");
  2934. }
  2935. if (ParameterTypes)
  2936. {
  2937. sprintf(strchr(tbuf, 0), "P%dSTR", i + 1);
  2938. }
  2939. else
  2940. {
  2941. sprintf(strchr(tbuf, 0), "P%dNUM", i + 1);
  2942. }
  2943. }
  2944. strcat(tbuf, ", /* ParameterTypes */\n");
  2945. prn_lprintf(tbuf);
  2946. strcpy(tbuf, " ");
  2947. for (i = 0; i < f->ParameterCount; i++)
  2948. {
  2949. unsigned int ParameterTests;
  2950. ParameterTests = f->ParameterTests >> (i * 4);
  2951. ParameterTests &= 0xF;
  2952. if (i > 0)
  2953. {
  2954. strcat(tbuf, " | ");
  2955. }
  2956. sprintf(strchr(tbuf, 0), ParameterRangeID[ParameterTests], i + 1);
  2957. }
  2958. strcat(tbuf, ", /* ParameterTests */\n");
  2959. prn_lprintf(tbuf);
  2960. }
  2961. sprintf(tbuf, " %s, /* NextPointer */\n", "NULL");
  2962. prn_lprintf(tbuf);
  2963. strcpy(tbuf, " ");
  2964. j = 0;
  2965. for (i = 0; i < NUM_VERSIONS; i++)
  2966. {
  2967. if (f->OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask)
  2968. {
  2969. if (j > 0)
  2970. {
  2971. strcat(tbuf, " | ");
  2972. }
  2973. strcat(tbuf, bwb_vertable[i].ID);
  2974. j++;
  2975. }
  2976. }
  2977. strcat(tbuf, " /* OptionVersionBitmask */\n");
  2978. prn_lprintf(tbuf);
  2979. prn_lprintf("},\n");
  2980. }
  2981. prn_lprintf("};\n\n");
  2982. }
  2983. void
  2984. DumpOneFunctionSyntax(int n, int lp)
  2985. {
  2986. char tbuf[BasicStringLengthMax + 1];
  2987. struct bwb_function *f;
  2988. bwx_DEBUG(__FUNCTION__);
  2989. if (n < 0 || n >= NUM_FUNCTIONS)
  2990. {
  2991. return;
  2992. }
  2993. f = &(bwb_prefuncs[n]);
  2994. /* NAME */
  2995. {
  2996. char UniqueID[BasicStringLengthMax + 1];
  2997. char Syntax[BasicStringLengthMax + 1];
  2998. FunctionUniqueID(f, UniqueID);
  2999. FunctionSyntax(f, Syntax);
  3000. sprintf(tbuf, " SYNTAX: %s\n", Syntax);
  3001. if (lp)
  3002. {
  3003. prn_lprintf(tbuf);
  3004. }
  3005. else
  3006. {
  3007. prn_xprintf(tbuf);
  3008. }
  3009. }
  3010. /* PARAMETERS */
  3011. if (f->ParameterCount == PNONE)
  3012. {
  3013. /* function has NO parameters */
  3014. }
  3015. else
  3016. {
  3017. /* function HAS parameters */
  3018. int i;
  3019. unsigned int ParameterTypes;
  3020. unsigned long ParameterTests;
  3021. char NumVar;
  3022. char StrVar;
  3023. ParameterTypes = f->ParameterTypes;
  3024. ParameterTests = f->ParameterTests;
  3025. NumVar = 'X';
  3026. StrVar = 'A';
  3027. for (i = 0; i < f->ParameterCount; i++)
  3028. {
  3029. /* sanity check this parameter */
  3030. unsigned long thischeck;
  3031. thischeck = ParameterTests & 0x0000000F;
  3032. /* verify parameter check */
  3033. if (ParameterTypes & 1)
  3034. {
  3035. /* STRING */
  3036. sprintf(tbuf, StringVariableRange[thischeck], StrVar);
  3037. StrVar++;
  3038. }
  3039. else
  3040. {
  3041. /* NUMBER */
  3042. sprintf(tbuf, NumberVariableRange[thischeck], NumVar);
  3043. NumVar++;
  3044. }
  3045. if (lp)
  3046. {
  3047. prn_lprintf(tbuf);
  3048. }
  3049. else
  3050. {
  3051. prn_xprintf(tbuf);
  3052. }
  3053. if (lp)
  3054. {
  3055. prn_lprintf("\n");
  3056. }
  3057. else
  3058. {
  3059. prn_xprintf("\n");
  3060. }
  3061. ParameterTypes = ParameterTypes >> 1;
  3062. ParameterTests = ParameterTests >> 4;
  3063. }
  3064. }
  3065. /* DESCRIPTION */
  3066. {
  3067. sprintf(tbuf, "DESCRIPTION: %s\n", f->Description);
  3068. if (lp)
  3069. {
  3070. prn_lprintf(tbuf);
  3071. }
  3072. else
  3073. {
  3074. prn_xprintf(tbuf);
  3075. }
  3076. }
  3077. /* COMPATIBILITY */
  3078. if (lp)
  3079. {
  3080. int i;
  3081. sprintf(tbuf, " VERSIONS:\n");
  3082. if (lp)
  3083. {
  3084. prn_lprintf(tbuf);
  3085. }
  3086. else
  3087. {
  3088. prn_xprintf(tbuf);
  3089. }
  3090. for (i = 0; i < NUM_VERSIONS; i++)
  3091. {
  3092. char X;
  3093. if (f->OptionVersionBitmask & bwb_vertable[i].OptionVersionBitmask)
  3094. {
  3095. /* SUPPORTED */
  3096. X = 'X';
  3097. }
  3098. else
  3099. {
  3100. /* NOT SUPPORTED */
  3101. X = '_';
  3102. }
  3103. sprintf(tbuf, " [%c] %s\n", X, bwb_vertable[i].Name);
  3104. if (lp)
  3105. {
  3106. prn_lprintf(tbuf);
  3107. }
  3108. else
  3109. {
  3110. prn_xprintf(tbuf);
  3111. }
  3112. }
  3113. }
  3114. }
  3115. void
  3116. DumpAllFuctionSyntax(void)
  3117. {
  3118. /* for the C maintainer */
  3119. int n;
  3120. bwx_DEBUG(__FUNCTION__);
  3121. for (n = 0; n < NUM_FUNCTIONS; n++)
  3122. {
  3123. prn_lprintf("------------------------------------------------------------\n");
  3124. DumpOneFunctionSyntax(n, TRUE);
  3125. }
  3126. prn_lprintf("------------------------------------------------------------\n");
  3127. }
  3128. void
  3129. DumpAllFunctionHtmlTable(void)
  3130. {
  3131. /* generate bwd_cmd.htm */
  3132. int i;
  3133. int j;
  3134. bwx_DEBUG(__FUNCTION__);
  3135. /* LEGEND */
  3136. prn_lprintf("<h1>LEGEND</h1><br>\n");
  3137. prn_lprintf("<table>\n");
  3138. prn_lprintf("<tr>");
  3139. prn_lprintf("<td>");
  3140. prn_lprintf("<b>");
  3141. prn_lprintf("ID");
  3142. prn_lprintf("</b>");
  3143. prn_lprintf("</td>");
  3144. prn_lprintf("<td>");
  3145. prn_lprintf("<b>");
  3146. prn_lprintf("NAME");
  3147. prn_lprintf("</b>");
  3148. prn_lprintf("</td>");
  3149. prn_lprintf("<td>");
  3150. prn_lprintf("<b>");
  3151. prn_lprintf("DESCRIPTION");
  3152. prn_lprintf("</b>");
  3153. prn_lprintf("</td>");
  3154. prn_lprintf("</tr>\n");
  3155. for (j = 0; j < NUM_VERSIONS; j++)
  3156. {
  3157. prn_lprintf("<tr>");
  3158. prn_lprintf("<td>");
  3159. prn_lprintf(bwb_vertable[j].ID);
  3160. prn_lprintf("</td>");
  3161. prn_lprintf("<td>");
  3162. prn_lprintf(bwb_vertable[j].Name);
  3163. prn_lprintf("</td>");
  3164. prn_lprintf("<td>");
  3165. prn_lprintf(bwb_vertable[j].Description);
  3166. prn_lprintf("</td>");
  3167. prn_lprintf("</tr>\n");
  3168. }
  3169. prn_lprintf("</table>\n");
  3170. prn_lprintf("<hr>\n");
  3171. /* DETAILS */
  3172. prn_lprintf("<h1>DETAILS</h1><br>\n");
  3173. prn_lprintf("<table>\n");
  3174. prn_lprintf("<tr>");
  3175. prn_lprintf("<td>");
  3176. prn_lprintf("<b>");
  3177. prn_lprintf("FUNCTION");
  3178. prn_lprintf("</b>");
  3179. prn_lprintf("</td>");
  3180. for (j = 0; j < NUM_VERSIONS; j++)
  3181. {
  3182. prn_lprintf("<td>");
  3183. prn_lprintf("<b>");
  3184. prn_lprintf(bwb_vertable[j].ID);
  3185. prn_lprintf("</b>");
  3186. prn_lprintf("</td>");
  3187. }
  3188. prn_lprintf("</tr>\n");
  3189. /* run through the command table and print comand -vs- OPTION VERSION */
  3190. for (i = 0; i < NUM_FUNCTIONS; i++)
  3191. {
  3192. prn_lprintf("<tr>");
  3193. prn_lprintf("<td>");
  3194. prn_lprintf(bwb_prefuncs[i].Name);
  3195. prn_lprintf("</td>");
  3196. for (j = 0; j < NUM_VERSIONS; j++)
  3197. {
  3198. prn_lprintf("<td>");
  3199. if (bwb_prefuncs[i].OptionVersionBitmask & bwb_vertable[j].OptionVersionBitmask)
  3200. {
  3201. prn_lprintf("X");
  3202. }
  3203. else
  3204. {
  3205. prn_lprintf(" ");
  3206. }
  3207. prn_lprintf("</td>");
  3208. }
  3209. prn_lprintf("</tr>\n");
  3210. }
  3211. prn_lprintf("</table>\n");
  3212. prn_lprintf("\n");
  3213. }
  3214. struct bwb_line *
  3215. bwb_DEF_SUB(struct bwb_line * l)
  3216. {
  3217. /* user is executing a function, such as 100 COS X, as though it were
  3218. * a command */
  3219. /* this applies to both intrinsic functions and user defined
  3220. * functions and subroutines */
  3221. /* no special parsing is required, just add () around the parameters */
  3222. char Buffer[BasicStringLengthMax + 1];
  3223. int i;
  3224. char *C;
  3225. char *F;
  3226. bwx_DEBUG(__FUNCTION__);
  3227. i = 0;
  3228. C = l->buffer;
  3229. C += l->position;
  3230. F = Buffer;
  3231. while (*C == ' ')
  3232. {
  3233. /* skip leading spaces before name */
  3234. C++;
  3235. }
  3236. /* these should not happen */
  3237. if (*C == '\0' || *C == OptionCommentChar)
  3238. {
  3239. bwb_error("bwb_DEF_SUB, INTERNAL null");
  3240. return bwb_zline(l);
  3241. }
  3242. if (!isalpha(*C))
  3243. {
  3244. bwb_error("bwb_DEF_SUB, INTERNAL isalpha");
  3245. return bwb_zline(l);
  3246. }
  3247. if (strlen(C) + 2 > BasicStringLengthMax)
  3248. {
  3249. bwb_error("Ibwb_DEF_SUB, NTERNAL strlen");
  3250. return bwb_zline(l);
  3251. }
  3252. /* OK */
  3253. while (isalpha(*C))
  3254. {
  3255. /* copy command name */
  3256. *F = *C;
  3257. F++;
  3258. C++;
  3259. }
  3260. if (*C == BasicStringSuffix)
  3261. {
  3262. /* copy command name */
  3263. *F = *C;
  3264. F++;
  3265. C++;
  3266. }
  3267. while (*C == ' ')
  3268. {
  3269. /* skip trailing spaces after name */
  3270. C++;
  3271. }
  3272. /* left paren */
  3273. *F = '(';
  3274. F++;
  3275. while (*C != '\0')
  3276. {
  3277. /* copy parameters */
  3278. if( *C == '"' )
  3279. {
  3280. /* quoted string */
  3281. {
  3282. /* leading quote */
  3283. *F = *C;
  3284. F++;
  3285. C++;
  3286. }
  3287. while( *C != '\0' && *C != '"' )
  3288. {
  3289. /* copy inclosed string */
  3290. *F = *C;
  3291. F++;
  3292. C++;
  3293. }
  3294. if( *C == '"' )
  3295. {
  3296. /* trailing quote */
  3297. *F = *C;
  3298. F++;
  3299. C++;
  3300. }
  3301. }
  3302. else
  3303. if( *C == OptionCommentChar )
  3304. {
  3305. /* comment */
  3306. while( *C != '\0' )
  3307. {
  3308. /* skip to end of line */
  3309. C++;
  3310. }
  3311. }
  3312. else
  3313. if( *C == ' ' )
  3314. {
  3315. /* skip unquoted spaces */
  3316. C++;
  3317. }
  3318. else
  3319. {
  3320. /* normal char, so copy it */
  3321. *F = *C;
  3322. F++;
  3323. C++;
  3324. }
  3325. }
  3326. /* right paren */
  3327. *F = ')';
  3328. F++;
  3329. /* terminate */
  3330. *F = '\0';
  3331. /* Call the expression interpreter to evaluate the function */
  3332. /* prn_xprintf(Buffer); */
  3333. bwb_exp(Buffer, FALSE, &i);
  3334. if (ERROR_PENDING)
  3335. {
  3336. /* prn_xprintf("oops"); */
  3337. }
  3338. adv_eos(l->buffer, &(l->position));
  3339. return bwb_zline(l);
  3340. }
  3341. /***************************************************************
  3342. FUNCTION: bwb_zline()
  3343. DESCRIPTION: This function is called at the exit from
  3344. Bywater BASIC command functions. It returns
  3345. a pointer to the current position in the current line.
  3346. ***************************************************************/
  3347. struct bwb_line *
  3348. bwb_zline(struct bwb_line * l)
  3349. {
  3350. bwx_DEBUG(__FUNCTION__);
  3351. /* skip trailing spaces */
  3352. while (l->buffer[l->position] == ' ')
  3353. l->position++;
  3354. /* skip trailing comment */
  3355. if (l->buffer[l->position] == OptionCommentChar)
  3356. {
  3357. /* COMMENT */
  3358. while (l->buffer[l->position] != 0)
  3359. l->position++;
  3360. }
  3361. /* usually, but NOT always, we are at the end of the line */
  3362. return l;
  3363. }
  3364. /***************************************************************
  3365. FUNCTION: fnc_fncs()
  3366. DESCRIPTION: This C function is used for debugging
  3367. purposes; it prints a list of all defined
  3368. functions.
  3369. SYNTAX: FNCS
  3370. ***************************************************************/
  3371. struct bwb_line *
  3372. bwb_FNCS(struct bwb_line * l)
  3373. {
  3374. register int n;
  3375. int t;
  3376. bwx_DEBUG(__FUNCTION__);
  3377. prn_iprintf("BWBASIC FUNCTIONS AVAILABLE:\n");
  3378. /* run through the command table and print comand names */
  3379. t = 0;
  3380. for (n = 0; n < NUM_FUNCTIONS; ++n)
  3381. {
  3382. prn_iprintf(bwb_prefuncs[n].Name);
  3383. if (t < 4)
  3384. {
  3385. prn_iprintf("\t");
  3386. t++;
  3387. }
  3388. else
  3389. {
  3390. prn_iprintf("\n");
  3391. t = 0;
  3392. }
  3393. }
  3394. if (t > 0)
  3395. {
  3396. prn_iprintf("\n");
  3397. }
  3398. return bwb_zline(l);
  3399. }
  3400. struct bwb_line *
  3401. bwb_MAINTAINER(struct bwb_line * l)
  3402. {
  3403. int ShowHelp;
  3404. char tbuf[BasicStringLengthMax + 1];
  3405. bwx_DEBUG(__FUNCTION__);
  3406. ShowHelp = TRUE;
  3407. adv_element(l->buffer, &(l->position), tbuf);
  3408. if (strcasecmp(tbuf, "CMDS") == 0)
  3409. {
  3410. adv_element(l->buffer, &(l->position), tbuf);
  3411. if (strcasecmp(tbuf, "HTML") == 0)
  3412. {
  3413. DumpAllCommandHtmlTable();
  3414. ShowHelp = FALSE;
  3415. }
  3416. else
  3417. if (strcasecmp(tbuf, "ID") == 0)
  3418. {
  3419. DumpAllCommandUniqueID();
  3420. ShowHelp = FALSE;
  3421. }
  3422. else
  3423. if (strcasecmp(tbuf, "MANUAL") == 0)
  3424. {
  3425. DumpAllCommandSyntax();
  3426. ShowHelp = FALSE;
  3427. }
  3428. else
  3429. if (strcasecmp(tbuf, "SWITCH") == 0)
  3430. {
  3431. DumpAllCommandSwitchStatement();
  3432. ShowHelp = FALSE;
  3433. }
  3434. else
  3435. if (strcasecmp(tbuf, "TABLE") == 0)
  3436. {
  3437. DumpAllCommandTableDefinitions();
  3438. ShowHelp = FALSE;
  3439. }
  3440. }
  3441. else
  3442. if (strcasecmp(tbuf, "FNCS") == 0)
  3443. {
  3444. adv_element(l->buffer, &(l->position), tbuf);
  3445. if (strcasecmp(tbuf, "HTML") == 0)
  3446. {
  3447. DumpAllFunctionHtmlTable();
  3448. ShowHelp = FALSE;
  3449. }
  3450. else
  3451. if (strcasecmp(tbuf, "ID") == 0)
  3452. {
  3453. DumpAllFuctionUniqueID();
  3454. ShowHelp = FALSE;
  3455. }
  3456. else
  3457. if (strcasecmp(tbuf, "MANUAL") == 0)
  3458. {
  3459. DumpAllFuctionSyntax();
  3460. ShowHelp = FALSE;
  3461. }
  3462. else
  3463. if (strcasecmp(tbuf, "SWITCH") == 0)
  3464. {
  3465. DumpAllFunctionSwitch();
  3466. ShowHelp = FALSE;
  3467. }
  3468. else
  3469. if (strcasecmp(tbuf, "TABLE") == 0)
  3470. {
  3471. DumpAllFuctionTableDefinitions();
  3472. ShowHelp = FALSE;
  3473. }
  3474. }
  3475. else
  3476. if (strcasecmp(tbuf, "DEBUG") == 0)
  3477. {
  3478. adv_element(l->buffer, &(l->position), tbuf);
  3479. if (strcasecmp(tbuf, "ON") == 0)
  3480. {
  3481. MaintainerDebugOn = TRUE;
  3482. ShowHelp = FALSE;
  3483. }
  3484. else
  3485. if (strcasecmp(tbuf, "OFF") == 0)
  3486. {
  3487. MaintainerDebugOn = FALSE;
  3488. ShowHelp = FALSE;
  3489. }
  3490. }
  3491. else
  3492. if (strcasecmp(tbuf, "STACK") == 0)
  3493. {
  3494. /* * dump the current execution stack, * Leftmost is the
  3495. * bottom, * Rigthmost is the top. */
  3496. int i;
  3497. for (i = 0; i <= CURTASK exsc; i++)
  3498. {
  3499. struct bwb_line *l;
  3500. l = CURTASK excs[i].line;
  3501. if (l != NULL)
  3502. {
  3503. char LineNumber[32];
  3504. sprintf(LineNumber, "%d:", l->number);
  3505. prn_xprintf(LineNumber);
  3506. }
  3507. }
  3508. prn_xprintf("\n");
  3509. ShowHelp = FALSE;
  3510. }
  3511. if (ShowHelp == TRUE)
  3512. {
  3513. prn_xprintf("MAINTAINER is a command intended for the C maintainer.\n");
  3514. prn_xprintf("It is used when making global changes to the internal tables.\n");
  3515. prn_xprintf("This command is subject to change without notice, at any time.\n");
  3516. prn_xprintf("Currently, the valid statements are:\n\n");
  3517. prn_xprintf("MAINTAINER CMDS HTML ' dump COMMAND vs VERSION as HTML table\n");
  3518. prn_xprintf("MAINTAINER CMDS ID ' dump COMMAND #defines for UniqueID\n");
  3519. prn_xprintf("MAINTAINER CMDS MANUAL ' dump COMMAND manual\n");
  3520. prn_xprintf("MAINTAINER CMDS SWITCH ' dump COMMAND switch(UniqueID)\n");
  3521. prn_xprintf("MAINTAINER CMDS TABLE ' dump COMMAND table\n");
  3522. prn_xprintf("MAINTAINER FNCS HTML ' dump FUNCTION vs VERSION as HTML table\n");
  3523. prn_xprintf("MAINTAINER FNCS ID ' dump FUNCTION #defines for UniqueID\n");
  3524. prn_xprintf("MAINTAINER FNCS MANUAL ' dump FUNCTION manual\n");
  3525. prn_xprintf("MAINTAINER FNCS SWITCH ' dump FUNCTION switch(UniqueID)\n");
  3526. prn_xprintf("MAINTAINER FNCS TABLE ' dump FUNCTION table\n");
  3527. prn_xprintf("MAINTAINER DEBUG ON ' enable degug tracing\n");
  3528. prn_xprintf("MAINTAINER DEBUG OFF ' disable degug tracing\n");
  3529. prn_xprintf("MAINTAINER STACK ' dump the BASIC stack\n");
  3530. }
  3531. return bwb_zline(l);
  3532. }
  3533. /***************************************************************
  3534. FUNCTION: fnc_init()
  3535. DESCRIPTION: This command initializes the function
  3536. linked list, placing all predefined functions
  3537. in the list.
  3538. ***************************************************************/
  3539. int
  3540. fnc_init(int task)
  3541. {
  3542. register int n;
  3543. struct bwb_function *f;
  3544. bwx_DEBUG(__FUNCTION__);
  3545. strcpy(LOCALTASK fnc_start.Name, "FNC_START");
  3546. LOCALTASK fnc_start.ReturnType = 'X';
  3547. strcpy(LOCALTASK fnc_end.Name, "FNC_END");
  3548. LOCALTASK fnc_end.ReturnType = 'x';
  3549. LOCALTASK fnc_end.next = &LOCALTASK fnc_end;
  3550. f = &LOCALTASK fnc_start;
  3551. /* now go through each of the preestablished functions and set up
  3552. * links between them; from this point the program address the
  3553. * functions only as a linked list (not as an array) */
  3554. for (n = 0; n < NUM_FUNCTIONS; ++n)
  3555. {
  3556. f->next = &(bwb_prefuncs[n]);
  3557. f = f->next;
  3558. FunctionDefinitionCheck(f);
  3559. }
  3560. /* link the last pointer to the end; this completes the list */
  3561. f->next = &LOCALTASK fnc_end;
  3562. return TRUE;
  3563. }
  3564. void
  3565. fnc_add_deffn(struct fslte * F)
  3566. {
  3567. struct bwb_function *f;
  3568. struct bwb_function *n;
  3569. bwx_DEBUG(__FUNCTION__);
  3570. /* get memory for fslt structure */
  3571. if ((f = CALLOC(1, sizeof(struct bwb_function), "fnc_add_deffn")) == NULL)
  3572. {
  3573. bwb_error("in fnc_add_deffn(): failed to get memory for bwb_function structure");
  3574. return;
  3575. }
  3576. strcpy(f->Name, F->name);
  3577. if (strchr(F->name, BasicStringSuffix) != NULL)
  3578. {
  3579. f->ReturnType = STRING;
  3580. }
  3581. else
  3582. {
  3583. f->ReturnType = NUMBER;
  3584. }
  3585. f->ReturnType |= (F->line->cmdnum & 0x00FF) << 8; /* UniqueID is a line
  3586. * number */
  3587. f->UniqueID = F->line->number;
  3588. f->ParameterCount = F->ParameterCount; /* 0..32, 0xFF == VARIANT */
  3589. f->ParameterTypes = F->ParameterTypes;
  3590. f->OptionVersionBitmask = OptionVersion;
  3591. /* establish linkages */
  3592. n = CURTASK fnc_start.next;
  3593. CURTASK fnc_start.next = f;
  3594. f->next = n;
  3595. }
  3596. static struct fslte *
  3597. fslt_find_by_line(int LineNumber)
  3598. {
  3599. struct fslte *f;
  3600. bwx_DEBUG(__FUNCTION__);
  3601. /* SEARCH */
  3602. for (f = CURTASK fslt_start.next; f != &CURTASK fslt_end; f = f->next)
  3603. {
  3604. if (f->line->number == LineNumber)
  3605. {
  3606. /* FOUND */
  3607. return f;
  3608. }
  3609. }
  3610. /* NOT FOUND */
  3611. return NULL;
  3612. }
  3613. /*
  3614. The generic handler for user defined functions.
  3615. When called by exp_function(), f->id will be set to the line number of a specific DEF USR.
  3616. */
  3617. struct bwb_variable *
  3618. fnc_deffn(int argc, struct bwb_variable * argv, int unique_id)
  3619. {
  3620. struct fslte *f;
  3621. struct bwb_variable *v;
  3622. struct bwb_variable *argn;
  3623. int i;
  3624. struct bwb_line *call_line;
  3625. int save_elevel;
  3626. bwx_DEBUG(__FUNCTION__);
  3627. /* initialize the variable if necessary */
  3628. f = fslt_find_by_line(unique_id);
  3629. /* these errors should not occur */
  3630. if (f == NULL)
  3631. {
  3632. sprintf(bwb_ebuf, "INTERNAL ERROR, f == NULL");
  3633. bwb_error(bwb_ebuf);
  3634. return NULL;
  3635. }
  3636. if (argv == NULL)
  3637. {
  3638. sprintf(bwb_ebuf, "INTERNAL ERROR, argv == NULL");
  3639. bwb_error(bwb_ebuf);
  3640. return NULL;
  3641. }
  3642. if (f->ParameterCount == 0xFF)
  3643. {
  3644. /* VARIANT */
  3645. }
  3646. else
  3647. if (argc != f->ParameterCount)
  3648. {
  3649. sprintf(bwb_ebuf, "INTERNAL ERROR, argc != f->ParameterCount");
  3650. bwb_error(bwb_ebuf);
  3651. return NULL;
  3652. }
  3653. if (f->ParameterCount == 0xFF)
  3654. {
  3655. /* VARIANT */
  3656. f->local_variable = argv;
  3657. }
  3658. else
  3659. if (argc > 0)
  3660. {
  3661. v = f->local_variable;
  3662. argn = argv;
  3663. for (i = 0; i < argc; i++)
  3664. {
  3665. argn = argn->next;
  3666. if (v == NULL)
  3667. {
  3668. sprintf(bwb_ebuf, "INTERNAL ERROR, v == NULL");
  3669. bwb_error(bwb_ebuf);
  3670. return NULL;
  3671. }
  3672. if (argn == NULL)
  3673. {
  3674. sprintf(bwb_ebuf, "INTERNAL ERROR, argn == NULL");
  3675. bwb_error(bwb_ebuf);
  3676. return NULL;
  3677. }
  3678. if (v->type != argn->type)
  3679. {
  3680. sprintf(bwb_ebuf, "INTERNAL ERROR, v->type != argn->type");
  3681. bwb_error(bwb_ebuf);
  3682. return NULL;
  3683. }
  3684. /* NEW ... */
  3685. if (strlen(v->name) > 0)
  3686. {
  3687. /* FIXME: this is a hack - the variable type
  3688. * should be determined when the variable is
  3689. * created */
  3690. char *E;
  3691. char e;
  3692. int IsError;
  3693. IsError = 0;
  3694. E = strchr(v->name, '\0');
  3695. E--;
  3696. e = *E;
  3697. /* sprintf( bwb_ebuf, "LAST CHAR is %c, TYPE
  3698. * is %c", e, v->type ); puts( bwb_ebuf ); */
  3699. /* so the following code is easier to read
  3700. * and maintain */
  3701. #define PARAM_NUMBER *argn->memnum
  3702. #define PARAM_LENGTH argn->memstr->length
  3703. #define PARAM_BUFFER argn->memstr->sbuffer
  3704. /* check actual values versus formal
  3705. * parameter type */
  3706. switch (e)
  3707. {
  3708. case BasicStringSuffix:
  3709. IsError = StringLengthCheck(P1ANY, PARAM_LENGTH);
  3710. break;
  3711. case BasicDoubleSuffix:
  3712. IsError = NumberValueCheck(P1DBL, PARAM_NUMBER);
  3713. break;
  3714. case BasicSingleSuffix:
  3715. IsError = NumberValueCheck(P1FLT, PARAM_NUMBER);
  3716. break;
  3717. case BasicCurrencySuffix:
  3718. IsError = NumberValueCheck(P1CUR, PARAM_NUMBER);
  3719. break;
  3720. case BasicLongSuffix:
  3721. IsError = NumberValueCheck(P1LNG, PARAM_NUMBER);
  3722. break;
  3723. case BasicIntegerSuffix:
  3724. IsError = NumberValueCheck(P1INT, PARAM_NUMBER);
  3725. break;
  3726. }
  3727. if (IsError != 0)
  3728. {
  3729. sprintf(bwb_ebuf, "ILLEGAL FUUNCTION CALL: %s(%s)", f->name, v->name);
  3730. bwb_Warning_InvalidParameter(bwb_ebuf);
  3731. return argv;
  3732. }
  3733. }
  3734. /* ...NEW */
  3735. v = v->next;
  3736. }
  3737. }
  3738. /* OK */
  3739. call_line = f->line; /* line to call for function */
  3740. call_line->position = f->startpos;
  3741. if (call_line->cmdnum == C_DEF)
  3742. {
  3743. adv_ws(call_line->buffer, &call_line->position);
  3744. if (call_line->buffer[call_line->position] != '=')
  3745. {
  3746. sprintf(bwb_ebuf, "*** INTERNAL ERROR #%d (%s) ***", 5, "call_line->buffer[ ] != '='");
  3747. bwb_error(bwb_ebuf);
  3748. return argv;
  3749. }
  3750. call_line->position++; /* NOTE - we skip past the '=' sign */
  3751. }
  3752. /* PUSH STACK */
  3753. save_elevel = CURTASK exsc;
  3754. bwb_incexec();
  3755. bwb_setexec(call_line, call_line->position, EXEC_FUNCTION);
  3756. /* create variable chain */
  3757. if (f->ParameterCount == 0xFF)
  3758. {
  3759. /* VARIANT */
  3760. }
  3761. else
  3762. if (argc > 0)
  3763. {
  3764. struct bwb_variable *source = NULL; /* source variable */
  3765. source = f->local_variable;
  3766. argn = argv;
  3767. for (i = 0; i < argc; i++)
  3768. {
  3769. argn = argn->next;
  3770. /* copy the name */
  3771. strcpy(argn->name, source->name);
  3772. source = source->next;
  3773. }
  3774. }
  3775. if (call_line->cmdnum == C_DEF)
  3776. {
  3777. struct exp_ese *e;
  3778. /* the function return variable is hidden */
  3779. CURTASK excs[CURTASK exsc].local_variable = argv->next;
  3780. e = bwb_exp(call_line->buffer, FALSE, &call_line->position);
  3781. bwb_etov(argv, e);
  3782. /* break variable chain */
  3783. CURTASK excs[CURTASK exsc].local_variable = NULL;
  3784. /* POP STACK */
  3785. bwb_decexec();
  3786. }
  3787. else
  3788. {
  3789. /* the function return variable is visible */
  3790. CURTASK excs[CURTASK exsc].local_variable = argv;
  3791. /* exp_isfn() uses these to determine use of the function
  3792. * name as a variable */
  3793. CURTASK excs[CURTASK exsc].LoopTopLine = call_line;
  3794. CURTASK excs[CURTASK exsc].LoopBottomLine = call_line->OtherLine;
  3795. /* execute until function returns */
  3796. while (CURTASK exsc > save_elevel)
  3797. {
  3798. bwb_execline();
  3799. }
  3800. }
  3801. if (f->ParameterCount == 0xFF)
  3802. {
  3803. /* VARIANT */
  3804. f->local_variable = NULL;
  3805. }
  3806. return argv;
  3807. }
  3808. /***************************************************************
  3809. FUNCTION: fnc_find()
  3810. DESCRIPTION: This C function attempts to locate
  3811. a BASIC function with the specified name.
  3812. If successful, it returns a pointer to
  3813. the C structure for the BASIC function,
  3814. if not successful, it returns NULL.
  3815. ***************************************************************/
  3816. struct bwb_function *
  3817. fnc_find(char *name)
  3818. {
  3819. struct bwb_function *f;
  3820. bwx_DEBUG(__FUNCTION__);
  3821. if (strlen(name) == 0)
  3822. {
  3823. return NULL;
  3824. }
  3825. for (f = CURTASK fnc_start.next; f != &CURTASK fnc_end; f = f->next)
  3826. {
  3827. if (OptionVersion & f->OptionVersionBitmask)
  3828. if (strcasecmp(f->Name, name) == 0)
  3829. {
  3830. return f;
  3831. }
  3832. }
  3833. /* search has failed: return NULL */
  3834. return NULL;
  3835. }
  3836. struct bwb_function *
  3837. fnc_find_exact(char *name, int ParameterCount, int ParameterTypes)
  3838. {
  3839. struct bwb_function *f;
  3840. bwx_DEBUG(__FUNCTION__);
  3841. for (f = CURTASK fnc_start.next; f != &CURTASK fnc_end; f = f->next)
  3842. {
  3843. if (OptionVersion & f->OptionVersionBitmask)
  3844. {
  3845. if (f->ParameterCount == ParameterCount)
  3846. {
  3847. if (f->ParameterTypes == ParameterTypes)
  3848. {
  3849. if (strcasecmp(f->Name, name) == 0)
  3850. {
  3851. return f;
  3852. }
  3853. }
  3854. }
  3855. }
  3856. }
  3857. /* search has failed: return NULL */
  3858. return NULL;
  3859. }
  3860. struct bwb_variable *
  3861. var_free(struct bwb_variable * v)
  3862. {
  3863. /* // Release all the memory associated with a specific variable. //
  3864. * This function returns NULL, so you can use it like this: // v
  3865. * = var_new(...); // ... // v = var_free( v ); */
  3866. bwx_DEBUG(__FUNCTION__);
  3867. if (v != NULL)
  3868. {
  3869. if (v->next != NULL)
  3870. {
  3871. /* This allows variable chains to be easily released. */
  3872. v->next = var_free(v->next);
  3873. }
  3874. /* cleanup this variable */
  3875. if (v->memnum != NULL)
  3876. {
  3877. FREE(v->memnum, "var_free");
  3878. v->memnum = NULL;
  3879. }
  3880. if (v->memstr != NULL)
  3881. {
  3882. int j;
  3883. for (j = 0; j < v->array_units; ++j)
  3884. {
  3885. if (v->memstr[j].sbuffer != NULL)
  3886. {
  3887. FREE(v->memstr[j].sbuffer, "var_free");
  3888. v->memstr[j].sbuffer = NULL;
  3889. }
  3890. v->memstr[j].rab = FALSE;
  3891. v->memstr[j].length = 0;
  3892. }
  3893. FREE(v->memstr, "var_free");
  3894. v->memstr = NULL;
  3895. }
  3896. if (v->array_sizes != NULL)
  3897. {
  3898. FREE(v->array_sizes, "var_free");
  3899. v->array_sizes = NULL;
  3900. }
  3901. if (v->array_pos != NULL)
  3902. {
  3903. FREE(v->array_pos, "var_free");
  3904. v->array_pos = NULL;
  3905. }
  3906. }
  3907. return NULL;
  3908. }
  3909. struct bwb_function *
  3910. fnc_find_by_id(int unique_id)
  3911. {
  3912. /* NOTE: This should ONLY search the INTRINSIC functions, not USER
  3913. * functions */
  3914. int i;
  3915. bwx_DEBUG(__FUNCTION__);
  3916. for (i = 0; i < NUM_FUNCTIONS; i++)
  3917. {
  3918. if (bwb_prefuncs[i].UniqueID == unique_id)
  3919. {
  3920. /* FOUND */
  3921. return &(bwb_prefuncs[i]);
  3922. }
  3923. }
  3924. /* NOT FOUND */
  3925. return NULL;
  3926. }
  3927. struct bwb_line *
  3928. bwb_CHANGE(struct bwb_line * l)
  3929. {
  3930. /* * CHANGE A$ TO X * CHANGE X TO A$ */
  3931. char tbuf[BasicStringLengthMax + 1];
  3932. struct bwb_variable *v = NULL;
  3933. struct bwb_variable *A = NULL;
  3934. struct bwb_variable *X = NULL;
  3935. int IsStringToArray = FALSE;
  3936. bwx_DEBUG(__FUNCTION__);
  3937. if (OptionFlags & OPTION_BASE_ONE)
  3938. {
  3939. bwb_error("CHANGE is only valid for OPTION BASE 0");
  3940. return bwb_zline(l);
  3941. }
  3942. /* get 1st variable */
  3943. adv_ws(l->buffer, &(l->position));
  3944. bwb_getvarname(l->buffer, tbuf, &(l->position));
  3945. v = var_find(tbuf);
  3946. if (v == NULL)
  3947. {
  3948. bwb_error(err_syntax);
  3949. return bwb_zline(l);
  3950. }
  3951. if (v->type == STRING)
  3952. {
  3953. A = v;
  3954. IsStringToArray = TRUE;
  3955. }
  3956. else
  3957. {
  3958. /* variable MUST be an array */
  3959. if ((v->dimensions == 1) && (v->array_sizes[0] == 1))
  3960. {
  3961. bwb_error(err_syntax);
  3962. return bwb_zline(l);
  3963. }
  3964. X = v;
  3965. IsStringToArray = FALSE;
  3966. }
  3967. /* get "TO" */
  3968. adv_ws(l->buffer, &(l->position));
  3969. adv_element(l->buffer, &(l->position), tbuf);
  3970. if (strcasecmp(tbuf, "TO") != 0)
  3971. {
  3972. bwb_error(err_syntax);
  3973. return bwb_zline(l);
  3974. }
  3975. /* get 2nd variable */
  3976. adv_ws(l->buffer, &(l->position));
  3977. bwb_getvarname(l->buffer, tbuf, &(l->position));
  3978. v = var_find(tbuf);
  3979. if (v == NULL)
  3980. {
  3981. bwb_error(err_syntax);
  3982. return bwb_zline(l);
  3983. }
  3984. if (v->type == STRING)
  3985. {
  3986. A = v;
  3987. if (IsStringToArray == TRUE)
  3988. {
  3989. bwb_error(err_syntax);
  3990. return bwb_zline(l);
  3991. }
  3992. }
  3993. else
  3994. {
  3995. /* variable MUST be an array */
  3996. if ((v->dimensions == 1) && (v->array_sizes[0] == 1))
  3997. {
  3998. bwb_error(err_syntax);
  3999. return bwb_zline(l);
  4000. }
  4001. X = v;
  4002. if (IsStringToArray == FALSE)
  4003. {
  4004. bwb_error(err_syntax);
  4005. return bwb_zline(l);
  4006. }
  4007. }
  4008. if (IsStringToArray)
  4009. {
  4010. /* CHANGE A$ TO X */
  4011. int i;
  4012. int n;
  4013. char *a;
  4014. BasicNumberType *x;
  4015. unsigned long t;
  4016. if (A->memstr == NULL)
  4017. {
  4018. bwb_error("String Variable not allocated");
  4019. return bwb_zline(l);
  4020. }
  4021. if (A->memstr->sbuffer == NULL)
  4022. {
  4023. bwb_error("String Variable not allocated");
  4024. return bwb_zline(l);
  4025. }
  4026. /* variable storage is a mess, we bypass that tradition here. */
  4027. t = 1;
  4028. for (n = 0; n < X->dimensions; n++)
  4029. {
  4030. t *= X->array_sizes[n];
  4031. }
  4032. if (t <= A->memstr->length)
  4033. {
  4034. bwb_error("Numeric Array too small");
  4035. return bwb_zline(l);
  4036. }
  4037. n = A->memstr->length;
  4038. a = A->memstr->sbuffer;
  4039. x = X->memnum;
  4040. *x = n;
  4041. x++;
  4042. for (i = 0; i < n; i++)
  4043. {
  4044. char C;
  4045. BasicNumberType V;
  4046. C = *a;
  4047. V = C;
  4048. *x = V;
  4049. x++;
  4050. a++;
  4051. }
  4052. }
  4053. else
  4054. {
  4055. /* CHANGE X TO A$ */
  4056. int i;
  4057. int n;
  4058. char *a;
  4059. BasicNumberType *x;
  4060. unsigned long t;
  4061. if (A->memstr == NULL)
  4062. {
  4063. bwb_error("String Variable not allocated");
  4064. return bwb_zline(l);
  4065. }
  4066. if (A->memstr->sbuffer == NULL)
  4067. {
  4068. bwb_error("String Variable not allocated");
  4069. return bwb_zline(l);
  4070. }
  4071. /* variable storage is a mess, we bypass that tradition here. */
  4072. t = 1;
  4073. for (n = 0; n < X->dimensions; n++)
  4074. {
  4075. t *= X->array_sizes[n];
  4076. }
  4077. if (t <= 1)
  4078. {
  4079. bwb_error("Numeric Array to small");
  4080. return bwb_zline(l);
  4081. }
  4082. if (t > BasicStringLengthMax)
  4083. {
  4084. bwb_error("Numeric Array too large");
  4085. return bwb_zline(l);
  4086. }
  4087. /* n = A->memstr->length; */
  4088. a = A->memstr->sbuffer;
  4089. x = X->memnum;
  4090. n = *x;
  4091. x++;
  4092. for (i = 0; i < n; i++)
  4093. {
  4094. char C;
  4095. BasicNumberType V;
  4096. V = *x;
  4097. C = V;
  4098. *a = C;
  4099. x++;
  4100. a++;
  4101. }
  4102. }
  4103. return bwb_zline(l);
  4104. }
  4105. /* EOF */