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.
 
 
 
 
 
 

3678 lines
87 KiB

  1. /***************************************************************
  2. bwbasic.c Main Program File
  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. /* Version 3.10 by Howard Wulf, AF5NE */
  27. /* */
  28. /* Version 3.20 by Howard Wulf, AF5NE */
  29. /* */
  30. /* Version 3.20d by Ken Martin */
  31. /* */
  32. /*---------------------------------------------------------------*/
  33. #include "bwbasic.h"
  34. static void break_handler (void);
  35. static void break_mes (int x);
  36. static int bwb_init (void);
  37. static void bwb_initialize_warnings (void);
  38. static void bwb_interact (void);
  39. static int bwb_ladd (char *buffer, LineType * p, int IsUser);
  40. static void bwb_single_step (char *buffer);
  41. static void bwb_xtxtline (char *buffer);
  42. static int bwx_signon (void);
  43. static void execute_profile (char *FileName);
  44. static void execute_program (char *FileName);
  45. static char *FindClassicStatementEnd (char *C);
  46. static int FixQuotes (char *tbuf);
  47. static void ImportClassicIfThenElse (char *InBuffer);
  48. static int is_ln (char *buffer);
  49. static int is_numconst (char *buffer);
  50. static void mark_preset_variables (void);
  51. static FILE *nice_open (char *BaseName);
  52. static void process_basic_line (char *buffer);
  53. GlobalType *My = NULL;
  54. static char *Banner[] = {
  55. "######## ## ## ## ## ### ######## ######## ######## ",
  56. "## ## ## ## ## ## ## ## ## ## ## ## ## ",
  57. "## ## #### ## ## ## ## ## ## ## ## ## ",
  58. "######## ## ## ## ## ## ## ## ###### ######## ",
  59. "## ## ## ## ## ## ######### ## ## ## ## ",
  60. "## ## ## ## ## ## ## ## ## ## ## ## ",
  61. "######## ## ### ### ## ## ## ######## ## ## ",
  62. " ",
  63. " ######## ### ###### #### ###### ",
  64. " ## ## ## ## ## ## ## ## ##",
  65. " ## ## ## ## ## ## ## ",
  66. " ######## ## ## ###### ## ## ",
  67. " ## ## ######### ## ## ## ",
  68. " ## ## ## ## ## ## ## ## ##",
  69. " ######## ## ## ###### #### ###### ",
  70. " ",
  71. "Bywater BASIC Interpreter, version 3.20d ",
  72. "Copyright (c) 1993, Ted A. Campbell ",
  73. "Copyright (c) 1995-1997 , Jon B. Volkoff ",
  74. "Copyright (c) 2014-2017 , Howard Wulf, AF5NE ",
  75. " 2019-2020 , Ken Martin ",
  76. " ",
  77. NULL
  78. };
  79. #define NUM_WARNINGS 80
  80. static char *ERROR4[NUM_WARNINGS];
  81. static void
  82. bwb_initialize_warnings (void)
  83. {
  84. int i;
  85. for (i = 0; i < NUM_WARNINGS; i++)
  86. {
  87. ERROR4[i] = NULL;
  88. }
  89. /* Error code tree */
  90. ERROR4[1] = "NEXT without FOR";
  91. ERROR4[2] = "Syntax error";
  92. ERROR4[3] = "RETURN without GOSUB";
  93. ERROR4[4] = "Out of DATA";
  94. ERROR4[5] = "Illegal function call";
  95. ERROR4[6] = "Overflow";
  96. ERROR4[7] = "Out of memory";
  97. ERROR4[8] = "Undefined line";
  98. ERROR4[9] = "Subscript out of range";
  99. ERROR4[10] = "Redimensioned array";
  100. ERROR4[11] = "Division by zero";
  101. ERROR4[12] = "Illegal direct";
  102. ERROR4[13] = "Type mismatch";
  103. ERROR4[14] = "Out of string space";
  104. ERROR4[15] = "String too long";
  105. ERROR4[16] = "String formula too complex";
  106. ERROR4[17] = "Can't continue";
  107. ERROR4[18] = "Undefined user function";
  108. ERROR4[19] = "No RESUME";
  109. ERROR4[20] = "RESUME without error";
  110. ERROR4[21] = "Unprintable error";
  111. ERROR4[22] = "Missing operand";
  112. ERROR4[23] = "Line buffer overflow";
  113. ERROR4[26] = "FOR without NEXT";
  114. ERROR4[27] = "Bad DATA";
  115. ERROR4[29] = "WHILE without WEND";
  116. ERROR4[30] = "WEND without WHILE";
  117. ERROR4[31] = "EXIT FUNCTION without FUNCTION";
  118. ERROR4[32] = "END FUNCTION without FUNCTION";
  119. ERROR4[33] = "EXIT SUB without SUB";
  120. ERROR4[34] = "END SUB without SUB";
  121. ERROR4[35] = "EXIT FOR without FOR";
  122. ERROR4[50] = "Field overflow";
  123. ERROR4[51] = "Internal error";
  124. ERROR4[52] = "Bad file number";
  125. ERROR4[53] = "File not found";
  126. ERROR4[54] = "Bad file mode";
  127. ERROR4[55] = "File already open";
  128. ERROR4[57] = "Disk I/O error";
  129. ERROR4[58] = "File already exists";
  130. ERROR4[61] = "Disk full";
  131. ERROR4[62] = "Input past end";
  132. ERROR4[63] = "Bad record number";
  133. ERROR4[64] = "Bad file name";
  134. ERROR4[66] = "Direct statement in file";
  135. ERROR4[67] = "Too many files";
  136. ERROR4[70] = "Variable Not Declared";
  137. ERROR4[73] = "Advanced Feature";
  138. }
  139. /***************************************************************
  140. FUNCTION: bwx_terminate()
  141. DESCRIPTION: This function terminates program execution.
  142. ***************************************************************/
  143. void
  144. bwx_terminate (void)
  145. {
  146. exit (0);
  147. }
  148. /***************************************************************
  149. FUNCTION: break_handler()
  150. DESCRIPTION: This function is called by break_mes()
  151. and handles program interruption by break
  152. (or by the STOP command).
  153. ***************************************************************/
  154. static void
  155. break_handler (void)
  156. {
  157. /*
  158. **
  159. **
  160. */
  161. assert( My != NULL );
  162. My->AutomaticLineNumber = 0;
  163. My->AutomaticLineIncrement = 0;
  164. if (My->IsInteractive)
  165. {
  166. /* INTERACTIVE: terminate program */
  167. /* reset all stack counters */
  168. bwb_clrexec ();
  169. SetOnError (0);
  170. My->ERR = -1; /* in break_handler() */
  171. /* reset the break handler */
  172. signal (SIGINT, break_mes);
  173. longjmp (My->mark, -1);
  174. return;
  175. }
  176. /* NOT INTERACTIVE: terminate immediately */
  177. bwx_terminate ();
  178. }
  179. /***************************************************************
  180. FUNCTION: break_mes()
  181. DESCRIPTION: This function is called (a) by a SIGINT
  182. signal or (b) by bwb_STOP via bwx_STOP.
  183. It prints an error message then calls
  184. break_handler() to terminate the program.
  185. ***************************************************************/
  186. static void
  187. break_mes (int x /* Parameter 'x' is never used */ )
  188. {
  189. /*
  190. **
  191. ** break_mes is FATAL.
  192. ** x == SIGINT for control-C
  193. ** x == 0 for bwx_STOP
  194. **
  195. */
  196. assert( My != NULL );
  197. assert( My->SYSOUT != NULL );
  198. assert( My->SYSOUT->cfp != NULL );
  199. assert( My->CurrentVersion != NULL );
  200. if (My->ERR < 0) /* in break_mes(), do not make a bad situation worse */
  201. {
  202. /* an error has already ben reported */
  203. }
  204. else
  205. {
  206. fputc ('\n', My->SYSOUT->cfp);
  207. ResetConsoleColumn ();
  208. if (My->CurrentVersion->OptionVersionValue & (C77))
  209. {
  210. if (is_empty_string (My->ProgramFilename) == FALSE)
  211. {
  212. fprintf (My->SYSOUT->cfp, "FILE:%s, ", My->ProgramFilename);
  213. }
  214. }
  215. fprintf (My->SYSOUT->cfp, "Program interrupted");
  216. if (My->ThisLine) /* break_mes */
  217. {
  218. if (My->ThisLine->LineFlags & (LINE_USER)) /* break_mes */
  219. {
  220. /* don't print the line number */
  221. }
  222. else
  223. {
  224. fprintf (My->SYSOUT->cfp, " at line %d", My->ThisLine->number); /* break_mes */
  225. }
  226. }
  227. fputc ('\n', My->SYSOUT->cfp);
  228. ResetConsoleColumn ();
  229. fflush (My->SYSOUT->cfp);
  230. }
  231. break_handler ();
  232. }
  233. extern void
  234. bwx_STOP (int IsShowMessage)
  235. {
  236. if (IsShowMessage)
  237. {
  238. break_mes (0);
  239. }
  240. else
  241. {
  242. break_handler ();
  243. }
  244. }
  245. static int
  246. bwx_signon (void)
  247. {
  248. /*
  249. **
  250. ** Display a sign-on banner.
  251. ** NOT called if a file is provided on the command line.
  252. **
  253. */
  254. int i;
  255. assert( My != NULL );
  256. assert( My->SYSOUT != NULL );
  257. assert( My->SYSOUT->cfp != NULL );
  258. for (i = 0; Banner[i] != NULL; i++)
  259. {
  260. fprintf (My->SYSOUT->cfp, "%s\n", Banner[i]);
  261. }
  262. ResetConsoleColumn ();
  263. return TRUE;
  264. }
  265. DoubleType
  266. bwx_TIMER (DoubleType Seconds)
  267. {
  268. /*
  269. **
  270. ** Return a number representing Seconds in the future. Seconds >= 0.
  271. ** Seconds may be non-integer, such as 0.001 or 86399.999. The
  272. ** maximum allowed Seconds is MAXDBL. This is used two ways:
  273. **
  274. ** 1) in bwb_TIMER(), the ON TIMER count (>0) is used to determine
  275. ** the expiration time. In this case, simply return what the value
  276. ** will be in the future. Note that ON TIMER enforces
  277. ** Seconds > (1 / CLOCKS_PER_SEC), and
  278. **
  279. ** 2) in bwb_execline(), zero (=0) is used to determine the current
  280. ** time and compare it to #1. In this case, simply return what the
  281. ** value is now.
  282. **
  283. ** Both the resolution of the timer, and the frequency of update,
  284. ** are implementation defined.
  285. **
  286. */
  287. if (Seconds < 0)
  288. {
  289. WARN_INTERNAL_ERROR;
  290. return 0;
  291. }
  292. else
  293. {
  294. DoubleType Result;
  295. Result = clock ();
  296. assert (CLOCKS_PER_SEC > 0);
  297. Result /= CLOCKS_PER_SEC;
  298. if (Seconds > 0)
  299. {
  300. Result += Seconds;
  301. }
  302. return Result;
  303. }
  304. }
  305. void
  306. CleanLine (char *buffer)
  307. {
  308. /*
  309. **
  310. ** cleanup the line, so it is easier to parse
  311. **
  312. */
  313. char *newbuffer;
  314. if (is_empty_string (buffer))
  315. {
  316. /* do nothing */
  317. return;
  318. }
  319. /* remove CR/LF */
  320. newbuffer = bwb_strchr (buffer, '\r');
  321. if (newbuffer != NULL)
  322. {
  323. *newbuffer = NulChar;
  324. }
  325. newbuffer = bwb_strchr (buffer, '\n');
  326. if (newbuffer != NULL)
  327. {
  328. *newbuffer = NulChar;
  329. }
  330. /* remove ALL embedded control characters */
  331. /* if you want a control character, then use CHR$ */
  332. newbuffer = buffer;
  333. while (*newbuffer != NulChar)
  334. {
  335. if (bwb_isprint (*newbuffer))
  336. {
  337. /* OK */
  338. }
  339. else
  340. {
  341. *newbuffer = ' ';
  342. }
  343. newbuffer++;
  344. }
  345. /* LTRIM$ */
  346. newbuffer = buffer;
  347. if (*newbuffer != NulChar)
  348. {
  349. /* not an empty line, so remove one (or more) leading spaces */
  350. while (*newbuffer == ' ')
  351. {
  352. newbuffer++;
  353. }
  354. if (newbuffer > buffer)
  355. {
  356. bwb_strcpy (buffer, newbuffer);
  357. }
  358. }
  359. /* RTRIM$ */
  360. newbuffer = buffer;
  361. if (*newbuffer != NulChar)
  362. {
  363. /* not an empty line, so remove one (or more) trailing spaces */
  364. char *E;
  365. E = bwb_strchr (newbuffer, NulChar);
  366. E--;
  367. while (E >= newbuffer && *E == ' ')
  368. {
  369. *E = NulChar;
  370. E--;
  371. }
  372. }
  373. }
  374. static int
  375. bwb_init (void)
  376. {
  377. /*
  378. **
  379. ** initialize Bywater BASIC
  380. **
  381. */
  382. int n;
  383. static char start_buf[] = "";
  384. static char end_buf[] = "";
  385. /* Memory allocation */
  386. if ((My = (GlobalType *) calloc (1, sizeof (GlobalType))) == NULL)
  387. {
  388. return FALSE;
  389. }
  390. if ((My->MaxLenBuffer =
  391. (char *) calloc (MAXLEN + 1 /* NulChar */ , sizeof (char))) == NULL)
  392. {
  393. return FALSE;
  394. }
  395. if ((My->NumLenBuffer =
  396. (char *) calloc (NUMLEN + 1 /* NulChar */ , sizeof (char))) == NULL)
  397. {
  398. return FALSE;
  399. }
  400. if ((My->ConsoleOutput =
  401. (char *) calloc (MAX_LINE_LENGTH + 1 /* NulChar */ ,
  402. sizeof (char))) == NULL)
  403. {
  404. return FALSE;
  405. }
  406. if ((My->ConsoleInput =
  407. (char *) calloc (MAX_LINE_LENGTH + 1 /* NulChar */ ,
  408. sizeof (char))) == NULL)
  409. {
  410. return FALSE;
  411. }
  412. if ((My->SYSIN = (FileType *) calloc (1, sizeof (FileType))) == NULL)
  413. {
  414. return FALSE;
  415. }
  416. if ((My->SYSOUT = (FileType *) calloc (1, sizeof (FileType))) == NULL)
  417. {
  418. return FALSE;
  419. }
  420. if ((My->SYSPRN = (FileType *) calloc (1, sizeof (FileType))) == NULL)
  421. {
  422. return FALSE;
  423. }
  424. if ((My->StartMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL)
  425. {
  426. return FALSE;
  427. }
  428. if ((My->UserMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL)
  429. {
  430. return FALSE;
  431. }
  432. if ((My->EndMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL)
  433. {
  434. return FALSE;
  435. }
  436. if ((My->EndMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL)
  437. {
  438. return FALSE;
  439. }
  440. if ((My->ERROR4 =
  441. (char *) calloc (MAX_ERR_LENGTH + 1 /* NulChar */ ,
  442. sizeof (char))) == NULL)
  443. {
  444. return FALSE;
  445. }
  446. My->CurrentVersion = &bwb_vertable[0];
  447. My->IsInteractive = TRUE;
  448. My->OptionSleepDouble = 1;
  449. My->OptionIndentInteger = 2;
  450. My->OptionTerminalType = C_OPTION_TERMINAL_NONE;
  451. My->OptionRoundType = C_OPTION_ROUND_BANK;
  452. My->NextValidLineNumber = MINLIN;
  453. My->IncludeLevel = 0; /* %INCLUDE */
  454. My->IsCommandLineFile = FALSE;
  455. My->ExternalInputFile = NULL; /* for automated testing, --TAPE command line parameter */
  456. My->IsPrinter = FALSE; /* CBASIC-II: CONSOLE and LPRINTER commands */
  457. My->OptionPromptString = DEF_PROMPT;
  458. My->OptionEditString = DEF_EDITOR;
  459. My->OptionFilesString = DEF_FILES;
  460. My->OptionRenumString = DEF_RENUM;
  461. My->OptionExtensionString = DEF_EXTENSION;
  462. My->OptionScaleInteger = 0;
  463. My->OptionDigitsInteger = SIGNIFICANT_DIGITS;
  464. My->OptionZoneInteger = ZONE_WIDTH;
  465. My->UseParameterString = NULL;
  466. My->ProgramFilename = NULL;
  467. My->StartMarker->number = MINLIN - 1;
  468. My->StartMarker->next = My->EndMarker;
  469. My->StartMarker->position = 0;
  470. My->StartMarker->buffer = start_buf;
  471. My->EndMarker->number = MAXLIN + 1;
  472. My->EndMarker->next = My->EndMarker;
  473. My->EndMarker->position = 0;
  474. My->EndMarker->buffer = end_buf;
  475. My->UserMarker->number = MINLIN - 1;
  476. My->UserMarker->next = My->EndMarker;
  477. My->UserMarker->position = 0;
  478. My->UserMarker->buffer = NULL;
  479. My->DataLine = My->EndMarker;
  480. My->DataPosition = 0;
  481. My->StackHead = NULL;
  482. My->StackDepthInteger = 0;
  483. My->FieldHead = NULL;
  484. My->VirtualHead = NULL;
  485. My->FileHead = NULL;
  486. My->ThisLine = My->StartMarker; /* bwb_init */
  487. My->SYSIN->DevMode = DEVMODE_INPUT;
  488. My->SYSIN->width = 80;
  489. My->SYSIN->col = 1;
  490. My->SYSIN->row = 1;
  491. My->SYSIN->delimit = ',';
  492. My->SYSIN->cfp = stdin;
  493. My->SYSOUT->DevMode = DEVMODE_OUTPUT;
  494. My->SYSOUT->width = 80;
  495. My->SYSOUT->col = 1;
  496. My->SYSOUT->row = 1;
  497. My->SYSOUT->delimit = ',';
  498. My->SYSOUT->cfp = stdout;
  499. My->SYSPRN->DevMode = DEVMODE_OUTPUT;
  500. My->SYSPRN->width = 80;
  501. My->SYSPRN->col = 1;
  502. My->SYSPRN->row = 1;
  503. My->SYSPRN->delimit = ',';
  504. My->SYSPRN->cfp = stderr;
  505. My->LPRINT_NULLS = 0;
  506. My->SCREEN_ROWS = 24;
  507. /* OPEN #0 is an ERROR. */
  508. /* CLOSE #0 is an ERROR. */
  509. /* WIDTH #0, 80 is the same as WIDTH 80. */
  510. /* LPRINT and LLIST are sent to bwx_LPRINT() */
  511. /* default variable type */
  512. for (n = 0; n < 26; n++)
  513. {
  514. My->DefaultVariableType[n] = DoubleTypeCode;
  515. }
  516. /* default COMMAND$(0-9) */
  517. for (n = 0; n < 10; n++)
  518. {
  519. My->COMMAND4[n] = NULL;
  520. }
  521. /* initialize tables of variables, functions */
  522. bwb_initialize_warnings ();
  523. SortAllCommands ();
  524. SortAllFunctions ();
  525. SortAllOperators ();
  526. var_init ();
  527. IntrinsicFunction_init ();
  528. UserFunction_init ();
  529. OptionVersionSet (0);
  530. /* OK */
  531. return TRUE;
  532. }
  533. /***************************************************************
  534. FUNCTION: main()
  535. DESCRIPTION: As in any C program, main() is the basic
  536. function from which the rest of the
  537. program is called. Some environments,
  538. however, provide their own main() functions
  539. (Microsoft Windows (tm) is an example).
  540. In these cases, the following code will
  541. have to be included in the initialization
  542. function that is called by the environment.
  543. ***************************************************************/
  544. static void
  545. process_basic_line (char *buffer)
  546. {
  547. CleanLine (buffer);
  548. if (is_empty_string (buffer))
  549. {
  550. /* empty -- do nothing */
  551. }
  552. else if (is_ln (buffer) == FALSE)
  553. {
  554. /* If there is no line number, then execute the line as received */
  555. /* RUN */
  556. WARN_CLEAR; /* process_basic_line */
  557. SetOnError (0);
  558. bwb_xtxtline (buffer); /* process_basic_line */
  559. }
  560. else if (is_numconst (buffer) == TRUE)
  561. {
  562. /*-----------------------------------------------------------------*/
  563. /* Another possibility: if buffer is a numeric constant, */
  564. /* then delete the indicated line number (JBV) */
  565. /*-----------------------------------------------------------------*/
  566. /* 100 */
  567. int LineNumber;
  568. LineNumber = atoi (buffer);
  569. WARN_CLEAR; /* process_basic_line */
  570. SetOnError (0);
  571. sprintf (buffer, "delete %d", LineNumber);
  572. bwb_xtxtline (buffer); /* process_basic_line */
  573. }
  574. else
  575. {
  576. /* If there is a line number, then add it to the BASIC program */
  577. /* 100 REM */
  578. bwb_ladd (buffer, My->StartMarker, FALSE);
  579. }
  580. }
  581. static void
  582. bwb_single_step (char *buffer)
  583. {
  584. assert( My != NULL );
  585. assert (buffer != NULL);
  586. process_basic_line (buffer);
  587. while (My->StackHead != NULL)
  588. {
  589. bwb_execline ();
  590. }
  591. }
  592. static void
  593. mark_preset_variables (void)
  594. {
  595. /* mark all existing variables as preset */
  596. /* this includes all variables declared in any PROFILE */
  597. VariableType *v;
  598. assert( My != NULL );
  599. for (v = My->VariableHead; v != NULL; v = v->next)
  600. {
  601. v->VariableFlags |= VARIABLE_PRESET;
  602. v->VariableFlags |= VARIABLE_COMMON;
  603. }
  604. }
  605. static void
  606. execute_profile (char *FileName)
  607. {
  608. FILE *profile;
  609. assert( My != NULL );
  610. assert (FileName != NULL);
  611. My->NextValidLineNumber = MINLIN;
  612. #ifdef LINUX
  613. /* Begin 20200806 ChipMaster@YeOlPiShack.net Patch --
  614. *
  615. * on *nix check the current folder, user's home folder and then /etc for
  616. * the profile script
  617. *
  618. * WARN: I assume that $HOME and FileName are reasonably sized. If one
  619. * or the other are oversized then an attempt to load a weird-named
  620. * script will happen.
  621. *
  622. * 1 to open [profile.bas]
  623. * 2 to open [/home/$USER/profile.bas]
  624. * 3 to open [/etc/profile.bas]
  625. * */
  626. char pname[1024];
  627. pname[0]=pname[sizeof(pname)-1]=0;
  628. profile = fopen (FileName, "r");
  629. if(profile == NULL) {
  630. strncpy(pname, getenv("HOME"), sizeof(pname)-1);
  631. if(pname[0]) {
  632. strncat(strcat(pname, "/"), FileName, sizeof(pname)-strlen(pname)-1);
  633. profile = fopen (pname, "r");
  634. }
  635. }
  636. if(profile == NULL) {
  637. strncat(strcpy(pname, "/etc/"), FileName, sizeof(pname)-6);
  638. profile = fopen(pname, "r");
  639. }
  640. #else
  641. profile = fopen (FileName, "r");
  642. #endif
  643. /* End 20200806 Patch */
  644. if (profile == NULL)
  645. {
  646. /* NOT FOUND */
  647. /* OPTIONAL */
  648. return;
  649. }
  650. /* FOUND */
  651. if (My->IsInteractive)
  652. {
  653. /*
  654. **
  655. ** set a buffer for jump: program execution returns to this point in
  656. ** case of a jump (error, interrupt, or finish program)
  657. **
  658. */
  659. My->program_run = 0;
  660. signal (SIGINT, break_mes);
  661. setjmp (My->mark);
  662. if (My->program_run > 0)
  663. {
  664. /* error in PROFILE */
  665. exit (1);
  666. }
  667. My->program_run++;
  668. }
  669. /*
  670. The profile only exists to allow executing OPTION ... commands.
  671. No other use is supported.
  672. */
  673. {
  674. char *tbuf;
  675. int tlen;
  676. tbuf = My->ConsoleInput;
  677. tlen = MAX_LINE_LENGTH;
  678. while (fgets (tbuf, tlen, profile)) /* execute_profile */
  679. {
  680. tbuf[tlen] = NulChar;
  681. bwb_single_step (tbuf); /* in execute_profile() */
  682. }
  683. bwb_fclose (profile);
  684. mark_preset_variables ();
  685. }
  686. }
  687. static void
  688. execute_program (char *FileName)
  689. {
  690. assert( My != NULL );
  691. assert( My->SYSOUT != NULL );
  692. assert( My->SYSOUT->cfp != NULL );
  693. assert (FileName != NULL);
  694. My->NextValidLineNumber = MINLIN;
  695. My->IsCommandLineFile = TRUE;
  696. if (bwb_fload (FileName) == FALSE)
  697. {
  698. fprintf (My->SYSOUT->cfp, "Failed to open file %s\n", FileName);
  699. /* the file load has failed, so do NOT run the program */
  700. exit (1);
  701. }
  702. if (My->ERR < 0 /* in execute_program(), file load failed */ )
  703. {
  704. /* the file load has failed, so do NOT run the program */
  705. exit (1);
  706. }
  707. bwb_RUN (My->StartMarker);
  708. }
  709. extern int
  710. main (int argc, char **argv)
  711. {
  712. int i;
  713. assert (argc >= 0);
  714. assert (argv != NULL);
  715. if (bwb_init () == FALSE)
  716. {
  717. /* FATAL */
  718. puts ("Out of memory");
  719. return 1;
  720. }
  721. assert( My != NULL );
  722. assert( My->SYSOUT != NULL );
  723. assert( My->SYSOUT->cfp != NULL );
  724. assert( My->SYSIN != NULL );
  725. assert( My->SYSIN->cfp != NULL );
  726. /* Signon message banner */
  727. if (argc < 2)
  728. {
  729. /* no parameters */
  730. if (My->IsInteractive)
  731. {
  732. bwx_signon ();
  733. }
  734. else
  735. {
  736. /* if INTERACTIVE is FALSE, then we must have a program file */
  737. fputs ("Program file not specified\n", My->SYSOUT->cfp);
  738. return 1;
  739. }
  740. }
  741. if (My->IsInteractive)
  742. {
  743. /*
  744. **
  745. ** set a buffer for jump: program execution returns to this point in
  746. ** case of a jump (error, interrupt, or finish program)
  747. **
  748. */
  749. My->program_run = 0;
  750. signal (SIGINT, break_mes);
  751. setjmp (My->mark);
  752. if (My->program_run > 0)
  753. {
  754. /* error in profile */
  755. return 1;
  756. }
  757. My->program_run++;
  758. }
  759. #if PROFILE
  760. execute_profile (PROFILENAME);
  761. #endif
  762. /* check to see if there is a program file: but do
  763. * this only the first time around! */
  764. for (i = 1; i < argc; i++)
  765. {
  766. /*
  767. SYNTAX:
  768. bwbasic [ --profile profile.bas ] [ --tape tapefile.inp ] [ program.bas ]
  769. */
  770. if (bwb_stricmp (argv[i], "--profile") == 0
  771. || bwb_stricmp (argv[i], "-p") == 0
  772. || bwb_stricmp (argv[i], "/profile") == 0
  773. || bwb_stricmp (argv[i], "/p") == 0)
  774. {
  775. i++;
  776. if (i < argc)
  777. {
  778. /* --profile profile.bas */
  779. execute_profile (argv[i]);
  780. }
  781. }
  782. else
  783. if (bwb_stricmp (argv[i], "--tape") == 0
  784. || bwb_stricmp (argv[i], "-t") == 0
  785. || bwb_stricmp (argv[i], "/tape") == 0
  786. || bwb_stricmp (argv[i], "/t") == 0)
  787. {
  788. i++;
  789. if (i < argc)
  790. {
  791. /* --tape tapefile.inp */
  792. My->ExternalInputFile = fopen (argv[i], "r");
  793. }
  794. }
  795. else
  796. {
  797. /* program.bas */
  798. {
  799. int j;
  800. int n;
  801. j = i;
  802. for (n = 0; n < 10 && j < argc; n++, j++)
  803. {
  804. My->COMMAND4[n] = argv[j];
  805. }
  806. }
  807. execute_program (argv[i]);
  808. break;
  809. }
  810. }
  811. if (My->IsInteractive)
  812. {
  813. /*
  814. **
  815. ** set a buffer for jump: program execution returns to this point in
  816. ** case of a jump (error, interrupt, or finish program)
  817. **
  818. */
  819. My->program_run = 0;
  820. signal (SIGINT, break_mes);
  821. setjmp (My->mark);
  822. if (My->program_run > 0)
  823. {
  824. /* error in console mode */
  825. }
  826. My->program_run++;
  827. }
  828. /* main program loop */
  829. My->NextValidLineNumber = MINLIN;
  830. while (!feof (My->SYSIN->cfp)) /* condition !feof( My->SYSIN->cfp ) added in v1.11 */
  831. {
  832. bwb_mainloop ();
  833. }
  834. bwx_terminate (); /* allow ^D (Unix) exit with grace */
  835. return 0;
  836. }
  837. /***************************************************************
  838. FUNCTION: bwb_interact()
  839. DESCRIPTION: This function gets a line from the user
  840. and processes it.
  841. ***************************************************************/
  842. static void
  843. bwb_interact (void)
  844. {
  845. char *tbuf;
  846. int tlen;
  847. assert( My != NULL );
  848. tbuf = My->ConsoleInput;
  849. tlen = MAX_LINE_LENGTH;
  850. My->NextValidLineNumber = MINLIN;
  851. /* take input from keyboard */
  852. if (My->AutomaticLineNumber > 0 && My->AutomaticLineIncrement > 0)
  853. {
  854. /* AUTO 100, 10 */
  855. char *zbuf; /* end of the prompt, start of the response */
  856. int zlen; /* length of the prompt */
  857. char LineExists;
  858. LineType *l;
  859. LineExists = ' ';
  860. for (l = My->StartMarker->next; l != My->EndMarker; l = l->next)
  861. {
  862. if (l->number == My->AutomaticLineNumber)
  863. {
  864. /* FOUND */
  865. LineExists = '*';
  866. break;
  867. }
  868. else if (l->number > My->AutomaticLineNumber)
  869. {
  870. /* NOT FOUND */
  871. LineExists = ' ';
  872. break;
  873. }
  874. }
  875. sprintf (tbuf, "%d%c", My->AutomaticLineNumber, LineExists);
  876. zbuf = bwb_strchr (tbuf, NulChar);
  877. zlen = bwb_strlen (tbuf);
  878. bwx_input (tbuf, FALSE, zbuf, tlen - zlen);
  879. zbuf[-1] = ' '; /* remove LineExists indicator */
  880. CleanLine (zbuf); /* JBV */
  881. if (is_empty_string (zbuf))
  882. {
  883. /* empty response */
  884. if (LineExists == '*')
  885. {
  886. /*
  887. An empty response with an existing line,
  888. causes AUTO to continue with the next line,
  889. leaving the current line intact.
  890. */
  891. My->AutomaticLineNumber += My->AutomaticLineIncrement;
  892. }
  893. else
  894. {
  895. /*
  896. An empty response with a non-existing line,
  897. causes AUTO to terminate.
  898. */
  899. My->AutomaticLineNumber = 0;
  900. My->AutomaticLineIncrement = 0;
  901. }
  902. }
  903. else
  904. {
  905. /* non-empty response */
  906. if (bwb_stricmp (zbuf, "MAN") == 0)
  907. {
  908. /* MAN terminates AUTO mode */
  909. My->AutomaticLineNumber = 0;
  910. My->AutomaticLineIncrement = 0;
  911. }
  912. else
  913. {
  914. /* overwrite any existing line */
  915. bwb_ladd (tbuf, My->StartMarker, FALSE);
  916. My->AutomaticLineNumber += My->AutomaticLineIncrement;
  917. }
  918. }
  919. }
  920. else
  921. {
  922. bwx_input (My->OptionPromptString, FALSE, tbuf, tlen);
  923. process_basic_line (tbuf);
  924. }
  925. }
  926. /***************************************************************
  927. FUNCTION: bwb_fload()
  928. DESCRIPTION: This function loads a BASIC program
  929. file into memory given a FILE pointer.
  930. ***************************************************************/
  931. static int
  932. FixQuotes (char *tbuf)
  933. {
  934. /* fix unbalanced quotes */
  935. /* 'tbuf' shall be declared "char tbuf[ tlen + 1]". */
  936. int p;
  937. int QuoteCount;
  938. int tlen;
  939. assert( My != NULL );
  940. assert( My->CurrentVersion != NULL );
  941. assert (tbuf != NULL);
  942. QuoteCount = 0;
  943. tlen = MAX_LINE_LENGTH;
  944. tbuf[tlen] = NulChar;
  945. p = 0;
  946. while (tbuf[p])
  947. {
  948. if (tbuf[p] == My->CurrentVersion->OptionQuoteChar)
  949. {
  950. QuoteCount++;
  951. }
  952. p++;
  953. }
  954. if (QuoteCount & 1)
  955. {
  956. /* odd == missing trailing quote */
  957. if (p < tlen)
  958. {
  959. /* we have room to put the missig quote */
  960. tbuf[p] = My->CurrentVersion->OptionQuoteChar;
  961. p++;
  962. tbuf[p] = NulChar;
  963. }
  964. else
  965. {
  966. /* we cannot fix it */
  967. return FALSE;
  968. }
  969. }
  970. /* OK */
  971. return TRUE;
  972. }
  973. static FILE *
  974. nice_open (char *BaseName)
  975. {
  976. FILE *file;
  977. assert( My != NULL );
  978. if (BaseName == NULL)
  979. {
  980. BaseName = My->ProgramFilename;
  981. }
  982. if (is_empty_string (BaseName))
  983. {
  984. WARN_BAD_FILE_NAME;
  985. return NULL;
  986. }
  987. file = fopen (BaseName, "r");
  988. if (file == NULL)
  989. if (is_empty_string (My->OptionExtensionString) == FALSE)
  990. {
  991. char *FileName;
  992. FileName = bwb_strdup2 (BaseName, My->OptionExtensionString);
  993. if (FileName == NULL)
  994. {
  995. WARN_OUT_OF_MEMORY;
  996. return NULL;
  997. }
  998. file = fopen (FileName, "r");
  999. if (file == NULL)
  1000. {
  1001. free (FileName);
  1002. }
  1003. else if (BaseName == My->ProgramFilename)
  1004. {
  1005. if (My->ProgramFilename != NULL)
  1006. {
  1007. free (My->ProgramFilename);
  1008. }
  1009. My->ProgramFilename = FileName;
  1010. }
  1011. }
  1012. return file;
  1013. }
  1014. extern int
  1015. bwb_fload (char *FileName)
  1016. {
  1017. /*
  1018. **
  1019. ** Load a BASIC program from the specified 'FileName'.
  1020. ** If 'FileName' is NULL, then load from My->ProgramFilename,
  1021. **
  1022. */
  1023. char *Magic_Word; /* SYNTAX: %INCLUDE literal.file.name */
  1024. int Magic_Length;
  1025. FILE *file;
  1026. char *tbuf;
  1027. int tlen;
  1028. Magic_Word = "%INCLUDE "; /* SYNTAX: %INCLUDE literal.file.name */
  1029. Magic_Length = bwb_strlen (Magic_Word);
  1030. tbuf = My->MaxLenBuffer;
  1031. tlen = MAXLEN;
  1032. /*
  1033. Just in case you are wondering...
  1034. Although this handles the most common cases, it does not
  1035. handle all possible cases.
  1036. The correct solution is to provide the actual filename (with extension),
  1037. as it exists in the operating system.
  1038. */
  1039. file = nice_open (FileName);
  1040. if (file == NULL)
  1041. {
  1042. WARN_BAD_FILE_NAME;
  1043. return FALSE;
  1044. }
  1045. My->NextValidLineNumber = MINLIN;
  1046. while (fgets (tbuf, tlen, file)) /* bwb_fload */
  1047. {
  1048. tbuf[tlen] = NulChar;
  1049. CleanLine (tbuf);
  1050. if (is_empty_string (tbuf))
  1051. {
  1052. /* ignore */
  1053. }
  1054. else if (bwb_strnicmp (tbuf, Magic_Word, Magic_Length) == 0)
  1055. {
  1056. /* %iNCLUDE */
  1057. int Result;
  1058. int p;
  1059. char varname[NameLengthMax + 1];
  1060. p = Magic_Length;
  1061. if (buff_read_varname (tbuf, &p, varname) == FALSE)
  1062. {
  1063. fprintf (My->SYSOUT->cfp, "%s Filename\n", Magic_Word);
  1064. ResetConsoleColumn ();
  1065. return FALSE;
  1066. }
  1067. My->IncludeLevel++; /* %INCLUDE */
  1068. Result = bwb_fload (varname);
  1069. My->IncludeLevel--; /* %INCLUDE */
  1070. if (Result == FALSE)
  1071. {
  1072. fprintf (My->SYSOUT->cfp, "%s %s Failed\n", Magic_Word, varname);
  1073. ResetConsoleColumn ();
  1074. return FALSE;
  1075. }
  1076. }
  1077. else
  1078. {
  1079. /* normal */
  1080. bwb_ladd (tbuf, My->StartMarker, FALSE);
  1081. }
  1082. }
  1083. /* close file stream */
  1084. bwb_fclose (file); /* file != NULL */
  1085. My->NextValidLineNumber = MINLIN;
  1086. return TRUE;
  1087. }
  1088. static char *
  1089. FindClassicStatementEnd (char *C)
  1090. {
  1091. /*
  1092. ** find the end of the current statement
  1093. */
  1094. assert( My != NULL );
  1095. assert( My->CurrentVersion != NULL );
  1096. assert (C != NULL);
  1097. if (My->CurrentVersion->OptionStatementChar == NulChar
  1098. && My->CurrentVersion->OptionCommentChar == NulChar)
  1099. {
  1100. /* DO NOTHING: Multi-statment lines are not possible */
  1101. return NULL;
  1102. }
  1103. /* skip line number */
  1104. while (bwb_isdigit (*C))
  1105. {
  1106. C++;
  1107. }
  1108. /* skip spaces */
  1109. while (*C == ' ')
  1110. {
  1111. C++;
  1112. }
  1113. if (IS_CHAR (*C, My->CurrentVersion->OptionCommentChar))
  1114. {
  1115. /* The entire line is a comment */
  1116. return NULL;
  1117. }
  1118. if (bwb_strnicmp (C, "REM", 3) == 0)
  1119. {
  1120. /* The entire line is a comment */
  1121. return NULL;
  1122. }
  1123. if ((My->CurrentVersion->OptionFlags & OPTION_LABELS_ON)
  1124. && (My->CurrentVersion->OptionStatementChar != NulChar))
  1125. {
  1126. /* determine if this line is a LABEL */
  1127. int p;
  1128. char label[NameLengthMax + 1];
  1129. p = 0;
  1130. if (buff_read_label (C, &p, label))
  1131. {
  1132. if (buff_skip_char (C, &p, My->CurrentVersion->OptionStatementChar))
  1133. {
  1134. if (buff_is_eol (C, &p))
  1135. {
  1136. /* The entire line is a label */
  1137. /* LABEL : \0 */
  1138. return NULL;
  1139. }
  1140. }
  1141. }
  1142. }
  1143. /* not a special case, so split on the first unquoted
  1144. * OptionCommentChar or OptionStatementChar */
  1145. while (*C != NulChar)
  1146. {
  1147. if (*C == My->CurrentVersion->OptionQuoteChar)
  1148. {
  1149. /* skip leading quote */
  1150. C++;
  1151. while (*C != NulChar && *C != My->CurrentVersion->OptionQuoteChar)
  1152. {
  1153. /* skip string constant */
  1154. C++;
  1155. }
  1156. if (*C == My->CurrentVersion->OptionQuoteChar)
  1157. {
  1158. /* skip trailing quote */
  1159. C++;
  1160. }
  1161. }
  1162. else if (IS_CHAR (*C, My->CurrentVersion->OptionCommentChar) /* ', ! */ )
  1163. {
  1164. /* FOUND */
  1165. return C;
  1166. }
  1167. else
  1168. if (IS_CHAR (*C, My->CurrentVersion->OptionStatementChar) /* :, \ */ )
  1169. {
  1170. /* FOUND */
  1171. return C;
  1172. }
  1173. else
  1174. {
  1175. C++;
  1176. }
  1177. }
  1178. /* NOT FOUND */
  1179. return NULL;
  1180. }
  1181. static void
  1182. ImportClassicIfThenElse (char *InBuffer)
  1183. {
  1184. /*
  1185. **
  1186. ** Determine the type of IF command:
  1187. **
  1188. ** a) STANDARD:
  1189. ** IF x THEN line ELSE line
  1190. **
  1191. ** b) CLASSIC:
  1192. ** IF x THEN stmt(s) ELSE stmt(s)
  1193. **
  1194. ** c) STRUCTURED:
  1195. ** IF x THEN
  1196. ** stmts
  1197. ** ELSE
  1198. ** stmts
  1199. ** END IF
  1200. **
  1201. ** The STANDARD and STRUCTURED forms
  1202. ** are natively supported.
  1203. **
  1204. ** The CLASSIC form is converted to
  1205. ** the STRUCTURED form.
  1206. **
  1207. */
  1208. int i;
  1209. int nIF = 0;
  1210. int nTHEN = 0;
  1211. int nELSE = 0;
  1212. int nENDIF = 0;
  1213. #define NO_COMMAND 0
  1214. #define IF_COMMAND 1
  1215. #define THEN_COMMAND 2
  1216. #define ELSE_COMMAND 3
  1217. #define ENDIF_COMMAND 4
  1218. int LastCommand = NO_COMMAND;
  1219. const char *REM = "REM ";
  1220. const char *IF = "IF ";
  1221. const char *THEN = "THEN ";
  1222. const char *THEN2 = "THEN";
  1223. const char *ELSE = "ELSE ";
  1224. const char *ENDIF = "END IF";
  1225. const char *GOTO = "GOTO ";
  1226. const char *DATA = "DATA ";
  1227. const char *CASE = "CASE ";
  1228. char *OutBuffer = My->ConsoleOutput;
  1229. char *Input;
  1230. char *Output;
  1231. char LastChar = My->CurrentVersion->OptionStatementChar;
  1232. int REM_len = bwb_strlen (REM);
  1233. int IF_len = bwb_strlen (IF);
  1234. int THEN_len = bwb_strlen (THEN);
  1235. int THEN2_len = bwb_strlen (THEN2);
  1236. int ELSE_len = bwb_strlen (ELSE);
  1237. int ENDIF_len = bwb_strlen (ENDIF);
  1238. int GOTO_len = bwb_strlen (GOTO);
  1239. int DATA_len = bwb_strlen (DATA);
  1240. int CASE_len = bwb_strlen (CASE);
  1241. #define OUTPUTCHAR( c ) { *Output = c; Output++; }
  1242. #define COPYCHAR { LastChar = *Input; *Output = *Input; Output++; Input++; }
  1243. #define COPY_LINENUMBER while( bwb_isdigit( *Input ) ) COPYCHAR;
  1244. #define COPY_SPACES while( *Input == ' ' ) COPYCHAR;
  1245. #define COPY_IF for( i = 0; i < IF_len; i++ ) COPYCHAR;
  1246. #define COPY_THEN for( i = 0; i < THEN_len; i++ ) COPYCHAR;
  1247. #define COPY_THEN2 for( i = 0; i < THEN2_len; i++ ) COPYCHAR;
  1248. #define COPY_ELSE for( i = 0; i < ELSE_len; i++ ) COPYCHAR;
  1249. #define COPY_ENDIF for( i = 0; i < ENDIF_len; i++ ) COPYCHAR;
  1250. #define FORCE_ENDIF for( i = 0; i < ENDIF_len; i++ ) OUTPUTCHAR( ENDIF[ i ] );
  1251. #define FORCE_GOTO for( i = 0; i < GOTO_len; i++ ) OUTPUTCHAR( GOTO[ i ] );
  1252. #define FORCE_COLON if( LastChar != My->CurrentVersion->OptionStatementChar ) OUTPUTCHAR( My->CurrentVersion->OptionStatementChar );
  1253. assert( My != NULL );
  1254. assert( My->CurrentVersion != NULL );
  1255. assert (InBuffer != NULL);
  1256. Input = InBuffer;
  1257. Output = OutBuffer;
  1258. if (My->CurrentVersion->OptionStatementChar == NulChar)
  1259. {
  1260. /* DO NOTHING: All IFs must be STANDARD or STRUCTURED */
  1261. return;
  1262. }
  1263. COPY_LINENUMBER;
  1264. COPY_SPACES;
  1265. LastChar = My->CurrentVersion->OptionStatementChar;
  1266. while (*Input != NulChar)
  1267. {
  1268. if (*Input == My->CurrentVersion->OptionCommentChar)
  1269. {
  1270. /* comment */
  1271. break;
  1272. }
  1273. else if (*Input == My->CurrentVersion->OptionQuoteChar)
  1274. {
  1275. /* string constant */
  1276. COPYCHAR;
  1277. while (*Input != NulChar
  1278. && *Input != My->CurrentVersion->OptionQuoteChar)
  1279. {
  1280. COPYCHAR;
  1281. }
  1282. if (*Input == My->CurrentVersion->OptionQuoteChar)
  1283. {
  1284. COPYCHAR;
  1285. }
  1286. else
  1287. {
  1288. /* add missing Quote */
  1289. OUTPUTCHAR (My->CurrentVersion->OptionQuoteChar);
  1290. }
  1291. COPY_SPACES;
  1292. }
  1293. else if (bwb_isalnum (LastChar))
  1294. {
  1295. /* can NOT be the start of a command */
  1296. COPYCHAR;
  1297. }
  1298. else if (!bwb_isalpha (*Input))
  1299. {
  1300. /* can NOT be the start of a command */
  1301. COPYCHAR;
  1302. }
  1303. else if (bwb_strnicmp (Input, REM, REM_len) == 0)
  1304. {
  1305. break;
  1306. }
  1307. else if (bwb_strnicmp (Input, DATA, DATA_len) == 0)
  1308. {
  1309. /* DATA ... */
  1310. break;
  1311. }
  1312. else if (bwb_strnicmp (Input, CASE, CASE_len) == 0)
  1313. {
  1314. /* CASE ... */
  1315. break;
  1316. }
  1317. else if (bwb_strnicmp (Input, IF, IF_len) == 0)
  1318. {
  1319. /* IF */
  1320. LastCommand = IF_COMMAND;
  1321. nIF++;
  1322. COPY_IF;
  1323. COPY_SPACES;
  1324. }
  1325. else if (bwb_strnicmp (Input, GOTO, GOTO_len) == 0 && nIF > nTHEN)
  1326. {
  1327. /* IF x GOTO line ELSE line */
  1328. LastCommand = THEN_COMMAND;
  1329. nTHEN++;
  1330. COPY_THEN;
  1331. COPY_SPACES;
  1332. COPY_LINENUMBER;
  1333. COPY_SPACES;
  1334. if (bwb_strnicmp (Input, ELSE, ELSE_len) == 0)
  1335. {
  1336. /* ELSE line */
  1337. COPY_ELSE;
  1338. COPY_SPACES;
  1339. COPY_LINENUMBER;
  1340. COPY_SPACES;
  1341. }
  1342. /* IS STANDARD, NOT CLASSIC */
  1343. nENDIF++;
  1344. LastCommand = ENDIF_COMMAND;
  1345. }
  1346. else if (bwb_strnicmp (Input, THEN, THEN_len) == 0)
  1347. {
  1348. /* THEN */
  1349. LastCommand = THEN_COMMAND;
  1350. nTHEN++;
  1351. COPY_THEN;
  1352. COPY_SPACES;
  1353. if (bwb_isdigit (*Input))
  1354. {
  1355. /* STANDARD: IF x THEN line ELSE line */
  1356. char *SavedInput;
  1357. char *SavedOutput;
  1358. SavedInput = Input;
  1359. SavedOutput = Output;
  1360. COPY_LINENUMBER;
  1361. COPY_SPACES;
  1362. if (bwb_strnicmp (Input, ELSE, ELSE_len) == 0)
  1363. {
  1364. /* ELSE line */
  1365. COPY_ELSE;
  1366. COPY_SPACES;
  1367. if (bwb_isdigit (*Input))
  1368. {
  1369. COPY_LINENUMBER;
  1370. COPY_SPACES;
  1371. /* IS STANDARD, NOT CLASSIC */
  1372. nENDIF++;
  1373. LastCommand = ENDIF_COMMAND;
  1374. }
  1375. else
  1376. {
  1377. /* IF x THEN line ELSE stmts */
  1378. Input = SavedInput;
  1379. Output = SavedOutput;
  1380. FORCE_COLON;
  1381. FORCE_GOTO;
  1382. COPY_LINENUMBER;
  1383. COPY_SPACES;
  1384. }
  1385. }
  1386. else
  1387. {
  1388. /* IS STANDARD, NOT CLASSIC */
  1389. nENDIF++;
  1390. LastCommand = ENDIF_COMMAND;
  1391. }
  1392. }
  1393. else
  1394. if (*Input == My->CurrentVersion->OptionCommentChar
  1395. || *Input == NulChar)
  1396. {
  1397. /* IS STRUCTURED, NOT CLASSIC */
  1398. nENDIF++;
  1399. LastCommand = ENDIF_COMMAND;
  1400. }
  1401. else
  1402. {
  1403. /* CLASSIC: IF x THEN stmts ELSE stmts */
  1404. }
  1405. FORCE_COLON;
  1406. }
  1407. else if (bwb_strnicmp (Input, THEN2, THEN2_len) == 0)
  1408. {
  1409. /* trailing THEN ? */
  1410. char *PeekInput;
  1411. PeekInput = Input;
  1412. PeekInput += THEN2_len;
  1413. while (*PeekInput == ' ')
  1414. {
  1415. PeekInput++;
  1416. }
  1417. if (*PeekInput == My->CurrentVersion->OptionCommentChar
  1418. || *PeekInput == NulChar)
  1419. {
  1420. /* IS STRUCTURED, NOT CLASSIC */
  1421. nTHEN++;
  1422. COPY_THEN2;
  1423. nENDIF++;
  1424. LastCommand = ENDIF_COMMAND;
  1425. FORCE_COLON;
  1426. }
  1427. else
  1428. {
  1429. /* THEN line */
  1430. }
  1431. }
  1432. else if (bwb_strnicmp (Input, ELSE, ELSE_len) == 0)
  1433. {
  1434. /* ELSE */
  1435. if (LastCommand == ELSE_COMMAND)
  1436. {
  1437. /* we need an ENDIF here */
  1438. FORCE_COLON;
  1439. FORCE_ENDIF;
  1440. FORCE_COLON;
  1441. nENDIF++;
  1442. }
  1443. LastCommand = ELSE_COMMAND;
  1444. nELSE++;
  1445. FORCE_COLON;
  1446. COPY_ELSE;
  1447. FORCE_COLON;
  1448. COPY_SPACES;
  1449. if (bwb_isdigit (*Input))
  1450. {
  1451. /* IF x THEN stmts ELSE line */
  1452. FORCE_GOTO;
  1453. COPY_LINENUMBER;
  1454. COPY_SPACES;
  1455. }
  1456. FORCE_COLON;
  1457. }
  1458. else if (bwb_strnicmp (Input, ENDIF, ENDIF_len) == 0)
  1459. {
  1460. /* ENDIF */
  1461. LastCommand = ENDIF_COMMAND;
  1462. nENDIF++;
  1463. COPY_ENDIF;
  1464. FORCE_COLON;
  1465. }
  1466. else
  1467. {
  1468. /* was NOT the start of a command */
  1469. COPYCHAR;
  1470. }
  1471. }
  1472. /* end of input */
  1473. if (nENDIF < nIF)
  1474. {
  1475. while (nENDIF < nIF)
  1476. {
  1477. /* we need trailing ENDIF's */
  1478. nENDIF++;
  1479. FORCE_COLON;
  1480. FORCE_ENDIF;
  1481. }
  1482. }
  1483. /* fixup trailing REMark command */
  1484. if (bwb_strnicmp (Input, REM, REM_len) == 0)
  1485. {
  1486. /* REMark */
  1487. /* 100 A=1 REMark */
  1488. /* 100 A=1:REMark */
  1489. /* 100 A=1'REMark */
  1490. FORCE_COLON;
  1491. }
  1492. /* copy the comments */
  1493. while (*Input != NulChar)
  1494. {
  1495. COPYCHAR;
  1496. /* cppcheck: (style) Variable 'LastChar' is assigned a value that is never used. */
  1497. }
  1498. OUTPUTCHAR (NulChar);
  1499. bwb_strcpy (InBuffer, OutBuffer);
  1500. }
  1501. /***************************************************************
  1502. FUNCTION: bwb_ladd()
  1503. DESCRIPTION: This function adds a new line (in the
  1504. buffer) to the program in memory.
  1505. ***************************************************************/
  1506. static int
  1507. bwb_ladd (char *buffer, LineType * p, int IsUser)
  1508. {
  1509. LineType *l;
  1510. LineType *previous;
  1511. char *newbuffer;
  1512. char *NextStatement;
  1513. char *ThisStatement;
  1514. int Replace;
  1515. char BreakChar;
  1516. assert( My != NULL );
  1517. assert( My->SYSOUT != NULL );
  1518. assert( My->SYSOUT->cfp != NULL );
  1519. assert( My->CurrentVersion != NULL );
  1520. assert (buffer != NULL);
  1521. assert (p != NULL);
  1522. Replace = TRUE;
  1523. BreakChar = NulChar;
  1524. CleanLine (buffer);
  1525. if (is_empty_string (buffer))
  1526. {
  1527. /* silengtly ignore blank lines */
  1528. return FALSE;
  1529. }
  1530. /*
  1531. from here, the line WILL be added so the user can EDIT it,
  1532. we just complain and refuse to run if any error is detected.
  1533. */
  1534. My->IsScanRequired = TRUE; /* program needs to be scanned again */
  1535. /* AUTO-FIX UNBALANCED QUOTES */
  1536. if (FixQuotes (buffer) == FALSE)
  1537. {
  1538. /* ERROR */
  1539. fprintf (My->SYSOUT->cfp, "UNBALANCED QUOTES: %s\n", buffer);
  1540. ResetConsoleColumn ();
  1541. My->ERR = -1; /* bwb_ladd, UNBALANCED QUOTES */
  1542. }
  1543. if (IS_CHAR (*buffer, My->CurrentVersion->OptionStatementChar))
  1544. {
  1545. /* part of a multi-statement line */
  1546. }
  1547. else if (IS_CHAR (*buffer, My->CurrentVersion->OptionCommentChar))
  1548. {
  1549. /* part of a multi-statement line */
  1550. }
  1551. else
  1552. {
  1553. ImportClassicIfThenElse (buffer);
  1554. }
  1555. ThisStatement = buffer;
  1556. NextStatement = NULL;
  1557. BreakChar = NulChar;
  1558. do
  1559. {
  1560. if (BreakChar == NulChar)
  1561. {
  1562. /* first pass thru the do{} while loop, do nothing */
  1563. }
  1564. else if (IS_CHAR (BreakChar, My->CurrentVersion->OptionCommentChar))
  1565. {
  1566. /* ThisStatment will turn out to be the last 08082020 Ken ? */
  1567. * ThisStatement = My->CurrentVersion->OptionCommentChar;
  1568. }
  1569. else if (IS_CHAR (BreakChar, My->CurrentVersion->OptionStatementChar))
  1570. {
  1571. /* we are NOT the last statement, skip over the OptionStatementChar */
  1572. ThisStatement++;
  1573. }
  1574. else
  1575. {
  1576. /* Internal Error */
  1577. }
  1578. if (BreakChar == NulChar
  1579. && IS_CHAR (*buffer, My->CurrentVersion->OptionStatementChar))
  1580. {
  1581. /* first pass thru and line begins with colon */
  1582. /* part of a multi-statement line */
  1583. NextStatement = NULL;
  1584. if (My->NextValidLineNumber > 1)
  1585. {
  1586. My->NextValidLineNumber--;
  1587. }
  1588. Replace = FALSE;
  1589. }
  1590. else
  1591. if (BreakChar == NulChar
  1592. && IS_CHAR (*buffer, My->CurrentVersion->OptionCommentChar))
  1593. {
  1594. /* first pass thru and line begins with apostrophe */
  1595. /* part of a multi-statement line */
  1596. NextStatement = NULL;
  1597. if (My->NextValidLineNumber > 1)
  1598. {
  1599. My->NextValidLineNumber--;
  1600. }
  1601. Replace = FALSE;
  1602. }
  1603. else
  1604. {
  1605. NextStatement = FindClassicStatementEnd (ThisStatement);
  1606. }
  1607. if (NextStatement == NULL)
  1608. {
  1609. /* we are the last statement */
  1610. }
  1611. else
  1612. {
  1613. /* another statement follows */
  1614. BreakChar = *NextStatement;
  1615. *NextStatement = NulChar;
  1616. }
  1617. CleanLine (ThisStatement);
  1618. if (is_empty_string (ThisStatement) == FALSE)
  1619. {
  1620. /* get memory for this line */
  1621. if ((l = (LineType *) calloc (1, sizeof (LineType))) == NULL)
  1622. {
  1623. /* ERROR */
  1624. fprintf (My->SYSOUT->cfp, "Out of memory\n");
  1625. ResetConsoleColumn ();
  1626. My->ERR = -1; /* bwb_ladd, Out of memory */
  1627. return FALSE;
  1628. }
  1629. /* this line has not been executed or numbered */
  1630. l->LineFlags = 0;
  1631. if (IsUser)
  1632. {
  1633. l->LineFlags |= LINE_USER;
  1634. }
  1635. l->IncludeLevel = My->IncludeLevel; /* %INCLUDE */
  1636. l->position = 0;
  1637. /*
  1638. **
  1639. ** ALL lines have a line number.
  1640. ** If a line number is not provided,
  1641. ** then the next available line number is assigned.
  1642. **
  1643. */
  1644. newbuffer = ThisStatement;
  1645. l->number = My->NextValidLineNumber;
  1646. if (buff_read_line_number (newbuffer, &(l->position), &l->number))
  1647. {
  1648. if (l->number < My->NextValidLineNumber)
  1649. {
  1650. /* ERROR */
  1651. fprintf (My->SYSOUT->cfp, "%d < %d - LINE OUT OF ORDER: %s\n",
  1652. l->number, My->NextValidLineNumber, buffer);
  1653. ResetConsoleColumn ();
  1654. My->ERR = -1; /* bwb_ladd, LINE OUT OF ORDER */
  1655. l->number = My->NextValidLineNumber; /* sane default */
  1656. }
  1657. else if (l->number < MINLIN || l->number > MAXLIN)
  1658. {
  1659. /* ERROR */
  1660. fprintf (My->SYSOUT->cfp, "INVALID LINE NUMBER: %s\n", buffer);
  1661. ResetConsoleColumn ();
  1662. My->ERR = -1; /* bwb_ladd, INVALID LINE NUMBER */
  1663. l->number = My->NextValidLineNumber; /* sane default */
  1664. }
  1665. else
  1666. {
  1667. /* OK */
  1668. My->NextValidLineNumber = l->number;
  1669. l->LineFlags |= LINE_NUMBERED; /* line was manually numbered */
  1670. }
  1671. /* A SPACE IS REQUIRED AFTER THE LINE NUMBER -- NO EXCEPTIONS */
  1672. if (newbuffer[l->position] != ' ')
  1673. {
  1674. /* ERROR */
  1675. fprintf (My->SYSOUT->cfp, "MISSING SPACE AFTER LINE NUMBER: %s\n",
  1676. buffer);
  1677. ResetConsoleColumn ();
  1678. My->ERR = -1; /* bwb_ladd, MISSING SPACE AFTER LINE NUMBER */
  1679. }
  1680. /* newuffer does NOT contain the line number */
  1681. newbuffer += l->position;
  1682. }
  1683. /* the next valid line number is this line number plus one */
  1684. CleanLine (newbuffer);
  1685. if (*newbuffer != NulChar
  1686. && *newbuffer == My->CurrentVersion->OptionStatementChar)
  1687. {
  1688. /* this is part of a multi-statement line */
  1689. newbuffer++;
  1690. CleanLine (newbuffer);
  1691. }
  1692. /*
  1693. **
  1694. ** copy into the line buffer
  1695. **
  1696. */
  1697. if (l->buffer != NULL)
  1698. {
  1699. free (l->buffer);
  1700. l->buffer = NULL; /* JBV */
  1701. }
  1702. if ((l->buffer =
  1703. (char *) calloc (bwb_strlen (newbuffer) + 1 /* NulChar */ ,
  1704. sizeof (char))) == NULL)
  1705. {
  1706. /* ERROR */
  1707. fprintf (My->SYSOUT->cfp, "Out of memory\n");
  1708. ResetConsoleColumn ();
  1709. My->ERR = -1; /* bwb_ladd, Out of memory */
  1710. return FALSE; /* we cannot determine the command */
  1711. }
  1712. bwb_strcpy (l->buffer, newbuffer);
  1713. /*
  1714. **
  1715. ** determine command
  1716. **
  1717. */
  1718. line_start (l);
  1719. if (l->cmdnum)
  1720. {
  1721. /* OK */
  1722. }
  1723. else
  1724. {
  1725. /* ERROR */
  1726. fprintf (My->SYSOUT->cfp,
  1727. "ILLEGAL COMMAND AFTER LINE NUMBER: %d %s\n", l->number,
  1728. l->buffer);
  1729. ResetConsoleColumn ();
  1730. My->ERR = -1; /* bwb_ladd, ILLEGAL COMMAND AFTER LINE NUMBER */
  1731. }
  1732. /*
  1733. **
  1734. ** add the line to the linked-list of lines
  1735. **
  1736. */
  1737. for (previous = p; previous != My->EndMarker; previous = previous->next)
  1738. {
  1739. if (previous->number == l->number)
  1740. {
  1741. if (Replace == TRUE)
  1742. {
  1743. /* REPLACE 'previous' */
  1744. while (previous->number == l->number)
  1745. {
  1746. LineType *z;
  1747. z = previous;
  1748. previous = previous->next;
  1749. bwb_freeline (z);
  1750. }
  1751. l->next = previous;
  1752. p->next = l;
  1753. }
  1754. else
  1755. {
  1756. /* APPEND after 'previous' */
  1757. while (previous->next->number == l->number)
  1758. {
  1759. previous = previous->next;
  1760. }
  1761. l->next = previous->next;
  1762. previous->next = l;
  1763. }
  1764. break;
  1765. }
  1766. else
  1767. if (previous->number < l->number
  1768. && l->number < previous->next->number)
  1769. {
  1770. /* INSERT BETWEEN 'previous' AND 'previous->next' */
  1771. l->next = previous->next;
  1772. previous->next = l;
  1773. break;
  1774. }
  1775. p = previous;
  1776. }
  1777. }
  1778. /* another statement may follow */
  1779. ThisStatement = NextStatement;
  1780. Replace = FALSE;
  1781. }
  1782. while (ThisStatement != NULL);
  1783. My->NextValidLineNumber++;
  1784. return TRUE;
  1785. }
  1786. /***************************************************************
  1787. FUNCTION: bwb_xtxtline()
  1788. DESCRIPTION: This function executes a text line, i.e.,
  1789. places it in memory and then relinquishes
  1790. control.
  1791. ***************************************************************/
  1792. static void
  1793. bwb_xtxtline (char *buffer)
  1794. {
  1795. assert( My != NULL );
  1796. assert (buffer != NULL);
  1797. /* remove old program from memory */
  1798. bwb_xnew (My->UserMarker);
  1799. CleanLine (buffer);
  1800. if (is_empty_string (buffer))
  1801. {
  1802. /* silengtly ignore blank lines */
  1803. return;
  1804. }
  1805. /* add to the user line list */
  1806. bwb_ladd (buffer, My->UserMarker, TRUE);
  1807. /* execute the line as BASIC command line */
  1808. if (bwb_incexec ())
  1809. {
  1810. My->StackHead->line = My->UserMarker->next; /* and set current line in it */
  1811. My->StackHead->ExecCode = EXEC_NORM;
  1812. }
  1813. }
  1814. /***************************************************************
  1815. FUNCTION: bwb_incexec()
  1816. DESCRIPTION: This function increments the EXEC
  1817. stack counter.
  1818. ***************************************************************/
  1819. int
  1820. bwb_incexec (void)
  1821. {
  1822. StackType *StackItem;
  1823. assert( My != NULL );
  1824. if (My->StackDepthInteger >= EXECLEVELS)
  1825. {
  1826. WARN_OUT_OF_MEMORY;
  1827. return FALSE;
  1828. }
  1829. if ((StackItem = (StackType *) calloc (1, sizeof (StackType))) == NULL)
  1830. {
  1831. WARN_OUT_OF_MEMORY;
  1832. return FALSE;
  1833. }
  1834. StackItem->ExecCode = EXEC_NORM; /* sane default */
  1835. StackItem->line = My->ThisLine; /* bwb_incexec */
  1836. StackItem->LoopTopLine = NULL;
  1837. StackItem->local_variable = NULL;
  1838. StackItem->OnErrorGoto = 0;
  1839. StackItem->next = My->StackHead;
  1840. My->StackHead = StackItem;
  1841. My->StackDepthInteger++;
  1842. return TRUE;
  1843. }
  1844. /***************************************************************
  1845. FUNCTION: bwb_decexec()
  1846. DESCRIPTION: This function decrements the EXEC
  1847. stack counter.
  1848. ***************************************************************/
  1849. void
  1850. bwb_clrexec (void)
  1851. {
  1852. assert( My != NULL );
  1853. while (My->StackHead != NULL)
  1854. {
  1855. bwb_decexec ();
  1856. }
  1857. }
  1858. void
  1859. bwb_decexec (void)
  1860. {
  1861. StackType *StackItem;
  1862. assert( My != NULL );
  1863. if (My->StackHead == NULL)
  1864. {
  1865. WARN_RETURN_WITHOUT_GOSUB;
  1866. return;
  1867. }
  1868. StackItem = My->StackHead;
  1869. My->StackHead = StackItem->next;
  1870. free (StackItem);
  1871. My->StackDepthInteger--;
  1872. }
  1873. /***************************************************************
  1874. FUNCTION: bwb_mainloop()
  1875. DESCRIPTION: This C function performs one iteration
  1876. of the interpreter. In a non-preemptive
  1877. scheduler, this function should be called
  1878. by the scheduler, not by bwBASIC code.
  1879. ***************************************************************/
  1880. void
  1881. bwb_mainloop (void)
  1882. {
  1883. assert( My != NULL );
  1884. if (My->StackHead)
  1885. {
  1886. /* BASIC program running */
  1887. bwb_execline (); /* execute one line of program */
  1888. return;
  1889. }
  1890. /* BASIC program completed */
  1891. if (My->ExternalInputFile != NULL)
  1892. {
  1893. /* for automated testing, --TAPE command line parameter */
  1894. if (bwb_is_eof (My->ExternalInputFile) == FALSE)
  1895. {
  1896. /* --TAPE command line parameter is active */
  1897. bwb_interact (); /* get user interaction */
  1898. return;
  1899. }
  1900. }
  1901. /* TAPE command inactive or completed */
  1902. if (My->IsCommandLineFile)
  1903. {
  1904. /* BASIC program was started from command line */
  1905. bwx_terminate ();
  1906. return;
  1907. }
  1908. /* BASIC program was not started from command line */
  1909. if (My->IsInteractive)
  1910. {
  1911. /* interactive */
  1912. bwb_interact (); /* get user interaction */
  1913. return;
  1914. }
  1915. /* non-interactive */
  1916. bwx_terminate ();
  1917. }
  1918. /***************************************************************
  1919. FUNCTION: bwb_execline()
  1920. DESCRIPTION: This function executes a single line of
  1921. a program in memory. This function is
  1922. called by bwb_mainloop().
  1923. ***************************************************************/
  1924. extern int
  1925. bwx_Error (int ERR, char *ErrorMessage)
  1926. {
  1927. /*
  1928. ERR is the error number
  1929. ErrorMessage is used to override the default error
  1930. message, and is usually NULL
  1931. */
  1932. assert( My != NULL );
  1933. switch (ERR)
  1934. {
  1935. case 0:
  1936. /*
  1937. **
  1938. ** Clear any existing error
  1939. **
  1940. */
  1941. My->IsErrorPending = FALSE; /* bwx_Error, ERR == 0 */
  1942. My->ERR = 0; /* bwx_Error, ERR == 0 */
  1943. My->ERL = NULL; /* bwx_Error, ERR == 0 */
  1944. bwb_strcpy (My->ERROR4, ""); /* bwx_Error, ERR == 0 */
  1945. return FALSE;
  1946. case 6: /* WARN_OVERFLOW */
  1947. case 11: /* WARN_DIVISION_BY_ZERO */
  1948. case 15: /* WARN_STRING_TOO_LONG */
  1949. /*
  1950. **
  1951. ** Behavior depends upon whether an Error handler is active.
  1952. **
  1953. */
  1954. if (GetOnError () == 0)
  1955. {
  1956. /*
  1957. **
  1958. ** Error handler is NOT active.
  1959. ** Do NOT set ERL, ERR, and ERROR$.
  1960. ** Continue processing.
  1961. **
  1962. */
  1963. if (ErrorMessage == NULL)
  1964. {
  1965. /* use the default error message */
  1966. if (ERR > 0 && ERR < NUM_WARNINGS)
  1967. {
  1968. ErrorMessage = ERROR4[ERR];
  1969. }
  1970. }
  1971. if (ErrorMessage != NULL)
  1972. {
  1973. if (bwb_strlen (ErrorMessage) > 0)
  1974. {
  1975. fprintf (My->SYSOUT->cfp, "%s\n", ErrorMessage);
  1976. ResetConsoleColumn ();
  1977. }
  1978. }
  1979. return FALSE; /* continue processing */
  1980. }
  1981. /*
  1982. **
  1983. ** Error handler IS active.
  1984. ** Fall-thru to set ERL, ERR, and ERROR$.
  1985. ** Abort processing.
  1986. **
  1987. */
  1988. }
  1989. if (My->IsErrorPending == FALSE) /* no errors pending */
  1990. {
  1991. /*
  1992. **
  1993. ** only keep the first pending error to occur
  1994. **
  1995. */
  1996. My->IsErrorPending = TRUE; /* bwx_Error, ERR != 0 */
  1997. My->ERR = ERR; /* bwx_Error, ERR != 0 */
  1998. My->ERL = NULL; /* bwx_Error, ERR != 0 */
  1999. bwb_strcpy (My->ERROR4, ""); /* bwx_Error, ERR != 0 */
  2000. if (My->StackHead)
  2001. {
  2002. My->ERL = My->StackHead->line;
  2003. }
  2004. if (ErrorMessage == NULL)
  2005. {
  2006. /* use the default error message */
  2007. if (ERR > 0 && ERR < NUM_WARNINGS)
  2008. {
  2009. ErrorMessage = ERROR4[ERR];
  2010. }
  2011. }
  2012. if (ErrorMessage != NULL)
  2013. {
  2014. if (bwb_strlen (ErrorMessage) > MAX_ERR_LENGTH)
  2015. {
  2016. ErrorMessage[MAX_ERR_LENGTH] = NulChar;
  2017. }
  2018. bwb_strcpy (My->ERROR4, ErrorMessage);
  2019. }
  2020. }
  2021. return TRUE; /* abort processing */
  2022. }
  2023. void
  2024. bwb_execline (void)
  2025. {
  2026. LineType *r, *l;
  2027. assert( My != NULL );
  2028. assert( My->SYSOUT != NULL );
  2029. assert( My->SYSOUT->cfp != NULL );
  2030. assert( My->CurrentVersion != NULL );
  2031. if (My->StackHead == NULL) /* in bwb_execline(), FATAL ERROR PENDING */
  2032. {
  2033. return;
  2034. }
  2035. l = My->StackHead->line;
  2036. /* if the line is My->EndMarker, then break out of EXEC loops */
  2037. if (l == NULL || l == My->EndMarker || My->ERR < 0) /* in bwb_execline(), FATAL ERROR PENDING */
  2038. {
  2039. bwb_clrexec ();
  2040. return;
  2041. }
  2042. My->ThisLine = l; /* bwb_execline */
  2043. /* Print line number if trace is on */
  2044. if (My->IsTraceOn == TRUE)
  2045. {
  2046. if (l->LineFlags & (LINE_USER))
  2047. {
  2048. /* USER line in console */
  2049. }
  2050. else if (l->number > 0)
  2051. {
  2052. fprintf (My->SYSOUT->cfp, "[ %d %s ]", l->number, l->buffer);
  2053. }
  2054. }
  2055. l->position = l->Startpos;
  2056. /* if there is a BASIC command in the line, execute it here */
  2057. if (l->cmdnum)
  2058. {
  2059. /* OK */
  2060. }
  2061. else
  2062. {
  2063. WARN_ILLEGAL_DIRECT;
  2064. l->cmdnum = C_REM;
  2065. }
  2066. /* l->cmdnum != 0 */
  2067. if (l->LineFlags & LINE_BREAK)
  2068. {
  2069. /* BREAK line */
  2070. l->LineFlags &= ~LINE_BREAK;
  2071. My->ContinueLine = l;
  2072. bwx_STOP (TRUE);
  2073. return;
  2074. }
  2075. /* advance beyond whitespace */
  2076. line_skip_spaces (l); /* keep this */
  2077. /* execute the command vector */
  2078. if (My->CurrentVersion->OptionFlags & (OPTION_COVERAGE_ON))
  2079. {
  2080. /* We do this here so "END" and "STOP" are marked */
  2081. if (l->cmdnum == C_DATA)
  2082. {
  2083. /* DATA lines are marked when they are READ */
  2084. }
  2085. else
  2086. {
  2087. /* this line was executed */
  2088. l->LineFlags |= LINE_EXECUTED;
  2089. }
  2090. }
  2091. r = bwb_vector (l);
  2092. if (r == NULL)
  2093. {
  2094. WARN_INTERNAL_ERROR;
  2095. return;
  2096. }
  2097. assert (r != NULL);
  2098. if (My->ERR < 0) /* in bwb_execline(), FATAL ERROR PENDING */
  2099. {
  2100. /* FATAL */
  2101. bwb_clrexec ();
  2102. return;
  2103. }
  2104. if (My->IsErrorPending /* Keep This */ )
  2105. {
  2106. /* we are probably not at the end-of-the-line */
  2107. }
  2108. else if (r == l)
  2109. {
  2110. /* we should be at the end-of-the-line */
  2111. if (line_is_eol (l))
  2112. {
  2113. /* OK */
  2114. }
  2115. else
  2116. {
  2117. WARN_SYNTAX_ERROR;
  2118. return;
  2119. }
  2120. }
  2121. else
  2122. {
  2123. /* we are probably not at the end-of-the-line */
  2124. }
  2125. if (My->IsErrorPending /* Keep This */ )
  2126. {
  2127. /*
  2128. **
  2129. ** a NON-FATAL ERROR has occurred. ERR, ERL, and ERROR$ were
  2130. ** already set using bwb_warning(ERR,ERROR$)
  2131. **
  2132. */
  2133. int err_gotol;
  2134. My->IsErrorPending = FALSE; /* Error Recognized */
  2135. err_gotol = GetOnError ();
  2136. if (l->LineFlags & (LINE_USER))
  2137. {
  2138. /*
  2139. **
  2140. ** ---------------------------------------------------------------------
  2141. ** USER line in console
  2142. ** ---------------------------------------------------------------------
  2143. **
  2144. ** fall thru to the DEFAULT ERROR HANDLER
  2145. **
  2146. */
  2147. }
  2148. else if (l->number == 0)
  2149. {
  2150. /* fall thru to the DEFAULT ERROR HANDLER */
  2151. }
  2152. else if (My->ERL == NULL)
  2153. {
  2154. /* fall thru to the DEFAULT ERROR HANDLER */
  2155. }
  2156. else if (My->ERL->number == 0)
  2157. {
  2158. /* fall thru to the DEFAULT ERROR HANDLER */
  2159. }
  2160. else if (err_gotol == -1)
  2161. {
  2162. /*
  2163. **
  2164. ** ---------------------------------------------------------------------
  2165. ** ON ERROR RESUME NEXT
  2166. ** ---------------------------------------------------------------------
  2167. **
  2168. */
  2169. assert (r != NULL);
  2170. assert (r->next != NULL);
  2171. r->next->position = 0;
  2172. assert (My->StackHead != NULL);
  2173. My->StackHead->line = r->next;
  2174. return;
  2175. }
  2176. else if (err_gotol == 0)
  2177. {
  2178. /*
  2179. **
  2180. ** ---------------------------------------------------------------------
  2181. ** ON ERROR GOTO 0
  2182. ** ---------------------------------------------------------------------
  2183. **
  2184. ** fall thru to the DEFAULT ERROR HANDLER
  2185. **
  2186. */
  2187. }
  2188. else if (err_gotol == My->ERL->number)
  2189. {
  2190. /*
  2191. **
  2192. ** ---------------------------------------------------------------------
  2193. ** RECURSION
  2194. ** ---------------------------------------------------------------------
  2195. **
  2196. ** For example:
  2197. ** 10 ON ERROR GOTO 20
  2198. ** 20 ERROR 1
  2199. **
  2200. ** fall thru to the DEFAULT ERROR HANDLER
  2201. **
  2202. */
  2203. }
  2204. else
  2205. {
  2206. /* USER ERROR HANDLER SPECIFIED */
  2207. /* find the user-specified error handler and jump there */
  2208. LineType *x;
  2209. for (x = My->StartMarker->next; x != My->EndMarker; x = x->next)
  2210. {
  2211. if (x->number == err_gotol)
  2212. {
  2213. /* FOUND */
  2214. if (My->CurrentVersion->OptionFlags & (OPTION_ERROR_GOSUB))
  2215. {
  2216. /*
  2217. **
  2218. ** ---------------------------------------------------------------
  2219. ** OPTION ERROR GOSUB
  2220. ** ---------------------------------------------------------------
  2221. **
  2222. ** RETURN should act like RESUME NEXT...
  2223. ** Execution resumes at the statement immediately following
  2224. ** the one which caused the error.
  2225. ** For structured commands, this is the bottom line of the structure.
  2226. **
  2227. */
  2228. switch (l->cmdnum)
  2229. {
  2230. case C_IF8THEN:
  2231. /* skip to END_IF */
  2232. assert (l->OtherLine != NULL);
  2233. for (l = l->OtherLine; l->cmdnum != C_END_IF; l = l->OtherLine);
  2234. break;
  2235. case C_SELECT_CASE:
  2236. /* skip to END_SELECT */
  2237. assert (l->OtherLine != NULL);
  2238. for (l = l->OtherLine; l->cmdnum != C_END_SELECT;
  2239. l = l->OtherLine);
  2240. break;
  2241. default:
  2242. l = l->next;
  2243. }
  2244. l->position = 0;
  2245. My->StackHead->line = l;
  2246. if (bwb_incexec ())
  2247. {
  2248. x->position = 0;
  2249. assert (My->StackHead != NULL);
  2250. My->StackHead->line = x;
  2251. My->StackHead->ExecCode = EXEC_GOSUB;
  2252. }
  2253. else
  2254. {
  2255. /* ERROR -- OUT OF MEMORY */
  2256. assert (My->StackHead != NULL);
  2257. My->StackHead->line = My->EndMarker;
  2258. }
  2259. }
  2260. else
  2261. {
  2262. /*
  2263. **
  2264. ** ---------------------------------------------------------------
  2265. ** OPTION ERROR GOTO
  2266. ** ---------------------------------------------------------------
  2267. **
  2268. */
  2269. x->position = 0; /* start of line */
  2270. assert (My->StackHead != NULL);
  2271. My->StackHead->line = x;
  2272. }
  2273. return;
  2274. }
  2275. }
  2276. /* NOT FOUND */
  2277. /* fall thru to the DEFAULT ERROR HANDLER */
  2278. }
  2279. /*
  2280. **
  2281. ** -----------------------------------------------------------------------
  2282. ** DEFAULT ERROR HANDLER (FATAL)
  2283. ** -----------------------------------------------------------------------
  2284. **
  2285. */
  2286. /*
  2287. **
  2288. ** display error message
  2289. **
  2290. */
  2291. if (l->LineFlags & (LINE_USER) || l->number <= 0)
  2292. {
  2293. /* USER line in console */
  2294. fprintf (My->SYSOUT->cfp, "\nERROR: %s\n", My->ERROR4);
  2295. ResetConsoleColumn ();
  2296. }
  2297. else
  2298. {
  2299. /* BASIC program line */
  2300. fprintf (My->SYSOUT->cfp, "\nERROR in line %d: %s\n", l->number,
  2301. My->ERROR4);
  2302. ResetConsoleColumn ();
  2303. /*
  2304. **
  2305. ** display stack trace
  2306. **
  2307. */
  2308. if (My->CurrentVersion->OptionFlags & (OPTION_TRACE_ON))
  2309. {
  2310. /*
  2311. ** Dump the BASIC stack trace when a FATAL error occurs.
  2312. ** First line is the TOP of the stack.
  2313. ** Last line is the BOTTOM of the stack.
  2314. */
  2315. StackType *StackItem;
  2316. fprintf (My->SYSOUT->cfp, "\nSTACK TRACE:\n");
  2317. for (StackItem = My->StackHead; StackItem != NULL;
  2318. StackItem = StackItem->next)
  2319. {
  2320. LineType *l;
  2321. l = StackItem->line;
  2322. if (l != NULL)
  2323. {
  2324. if (MINLIN <= l->number && l->number <= MAXLIN)
  2325. {
  2326. /* BASIC program line */
  2327. if (l->buffer == NULL)
  2328. {
  2329. fprintf (My->SYSOUT->cfp, "%d\n", l->number);
  2330. }
  2331. else
  2332. {
  2333. fprintf (My->SYSOUT->cfp, "%d:%s\n", l->number, l->buffer);
  2334. }
  2335. }
  2336. }
  2337. }
  2338. ResetConsoleColumn ();
  2339. }
  2340. }
  2341. My->AutomaticLineNumber = 0;
  2342. My->AutomaticLineIncrement = 0;
  2343. if (My->IsInteractive)
  2344. {
  2345. /* INTERACTIVE: terminate program */
  2346. /* reset all stack counters */
  2347. bwb_clrexec ();
  2348. SetOnError (0);
  2349. My->ERR = -1; /* in bwb_execline(), default error handler */
  2350. /* reset the break handler */
  2351. signal (SIGINT, break_mes);
  2352. return;
  2353. }
  2354. /* NOT INTERACTIVE: terminate immediately */
  2355. bwx_terminate ();
  2356. return; /* never reached */
  2357. }
  2358. if (l->number > 0)
  2359. {
  2360. /* These events only occur in running programs */
  2361. if (My->IsTimerOn)
  2362. {
  2363. /* TIMER ON */
  2364. if (My->OnTimerCount > 0)
  2365. {
  2366. if (bwx_TIMER (0) > My->OnTimerExpires)
  2367. {
  2368. My->IsTimerOn = FALSE;
  2369. if (My->OnTimerLineNumber > 0)
  2370. {
  2371. /* ON TIMER( My->OnTimerCount ) GOSUB My->OnTimerLineNumber */
  2372. LineType *x;
  2373. for (x = My->StartMarker->next; x != My->EndMarker; x = x->next)
  2374. {
  2375. if (x->number == My->OnTimerLineNumber)
  2376. {
  2377. /* FOUND */
  2378. /* save current stack level */
  2379. assert (My->StackHead != NULL);
  2380. My->StackHead->line = r;
  2381. /* increment exec stack */
  2382. if (bwb_incexec ())
  2383. {
  2384. /* set the new position to x and return x */
  2385. x->position = 0;
  2386. assert (My->StackHead != NULL);
  2387. My->StackHead->line = x;
  2388. My->StackHead->ExecCode = EXEC_GOSUB;
  2389. }
  2390. else
  2391. {
  2392. /* ERROR */
  2393. assert (My->StackHead != NULL);
  2394. My->StackHead->line = My->EndMarker;
  2395. }
  2396. return;
  2397. }
  2398. }
  2399. /* NOT FOUND */
  2400. }
  2401. }
  2402. }
  2403. }
  2404. }
  2405. /* check for end of line: if so, advance to next line and return */
  2406. if (r == l)
  2407. {
  2408. /* advance to the next line */
  2409. l->next->position = 0;
  2410. r = l->next;
  2411. }
  2412. else if (line_is_eol (r))
  2413. {
  2414. /* we could be at the end-of-the-line, added for RETURN */
  2415. /* advance to the next line */
  2416. r->next->position = 0;
  2417. r = r->next;
  2418. }
  2419. /* else reset with the value in r */
  2420. assert (My->StackHead != NULL);
  2421. My->StackHead->line = r;
  2422. }
  2423. /***************************************************************
  2424. FUNCTION: is_ln()
  2425. DESCRIPTION: This function determines whether a program
  2426. line (in buffer) begins with a line number.
  2427. ***************************************************************/
  2428. static int
  2429. is_ln (char *buffer)
  2430. {
  2431. int position;
  2432. assert (buffer != NULL);
  2433. position = 0;
  2434. buff_skip_spaces (buffer, &position); /* keep this */
  2435. if (bwb_isdigit (buffer[position]))
  2436. {
  2437. return TRUE;
  2438. }
  2439. return FALSE;
  2440. }
  2441. /***************************************************************
  2442. FUNCTION: is_numconst()
  2443. DESCRIPTION: This function reads the string in <buffer>
  2444. and returns TRUE if it is a numerical
  2445. constant and FALSE if it is not. At
  2446. this point, only decimal (base 10)
  2447. constants are detected.
  2448. ***************************************************************/
  2449. static int
  2450. is_numconst (char *buffer)
  2451. {
  2452. char *p;
  2453. assert (buffer != NULL);
  2454. /* Return FALSE for empty buffer */
  2455. if (buffer[0] == NulChar)
  2456. {
  2457. return FALSE;
  2458. }
  2459. /* else check digits */
  2460. p = buffer;
  2461. while (*p != NulChar)
  2462. {
  2463. switch (*p)
  2464. {
  2465. case '0':
  2466. case '1':
  2467. case '2':
  2468. case '3':
  2469. case '4':
  2470. case '5':
  2471. case '6':
  2472. case '7':
  2473. case '8':
  2474. case '9':
  2475. break;
  2476. default:
  2477. return FALSE;
  2478. }
  2479. p++;
  2480. }
  2481. /* only numerical characters detected */
  2482. return TRUE;
  2483. }
  2484. /* SWITCH */
  2485. LineType *
  2486. bwb_vector( LineType *l )
  2487. {
  2488. LineType *r;
  2489. assert (l != NULL);
  2490. switch( l->cmdnum )
  2491. {
  2492. case C_DEF8LBL:
  2493. r = bwb_DEF8LBL( l );
  2494. break;
  2495. case C_APPEND:
  2496. r = bwb_APPEND( l );
  2497. break;
  2498. case C_AS:
  2499. r = bwb_AS( l );
  2500. break;
  2501. case C_AUTO:
  2502. r = bwb_AUTO( l );
  2503. break;
  2504. case C_BACKSPACE:
  2505. r = bwb_BACKSPACE( l );
  2506. break;
  2507. case C_BREAK:
  2508. r = bwb_BREAK( l );
  2509. break;
  2510. case C_BUILD:
  2511. r = bwb_BUILD( l );
  2512. break;
  2513. case C_BYE:
  2514. r = bwb_BYE( l );
  2515. break;
  2516. case C_CALL:
  2517. r = bwb_CALL( l );
  2518. break;
  2519. case C_CASE:
  2520. r = bwb_CASE( l );
  2521. break;
  2522. case C_CASE_ELSE:
  2523. r = bwb_CASE_ELSE( l );
  2524. break;
  2525. case C_CHAIN:
  2526. r = bwb_CHAIN( l );
  2527. break;
  2528. case C_CHANGE:
  2529. r = bwb_CHANGE( l );
  2530. break;
  2531. case C_CLEAR:
  2532. r = bwb_CLEAR( l );
  2533. break;
  2534. case C_CLOAD:
  2535. r = bwb_CLOAD( l );
  2536. break;
  2537. case C_CLOAD8:
  2538. r = bwb_CLOAD8( l );
  2539. break;
  2540. case C_CLOSE:
  2541. r = bwb_CLOSE( l );
  2542. break;
  2543. case C_CLR:
  2544. r = bwb_CLR( l );
  2545. break;
  2546. case C_CMDS:
  2547. r = bwb_CMDS( l );
  2548. break;
  2549. case C_COMMON:
  2550. r = bwb_COMMON( l );
  2551. break;
  2552. case C_CONSOLE:
  2553. r = bwb_CONSOLE( l );
  2554. break;
  2555. case C_CONST:
  2556. r = bwb_CONST( l );
  2557. break;
  2558. case C_CONT:
  2559. r = bwb_CONT( l );
  2560. break;
  2561. case C_CONTINUE:
  2562. r = bwb_CONTINUE( l );
  2563. break;
  2564. case C_COPY:
  2565. r = bwb_COPY( l );
  2566. break;
  2567. case C_CREATE:
  2568. r = bwb_CREATE( l );
  2569. break;
  2570. case C_CSAVE:
  2571. r = bwb_CSAVE( l );
  2572. break;
  2573. case C_CSAVE8:
  2574. r = bwb_CSAVE8( l );
  2575. break;
  2576. case C_DATA:
  2577. r = bwb_DATA( l );
  2578. break;
  2579. case C_DEC:
  2580. r = bwb_DEC( l );
  2581. break;
  2582. case C_DEF:
  2583. r = bwb_DEF( l );
  2584. break;
  2585. case C_DEFBYT:
  2586. r = bwb_DEFBYT( l );
  2587. break;
  2588. case C_DEFCUR:
  2589. r = bwb_DEFCUR( l );
  2590. break;
  2591. case C_DEFDBL:
  2592. r = bwb_DEFDBL( l );
  2593. break;
  2594. case C_DEFINT:
  2595. r = bwb_DEFINT( l );
  2596. break;
  2597. case C_DEFLNG:
  2598. r = bwb_DEFLNG( l );
  2599. break;
  2600. case C_DEFSNG:
  2601. r = bwb_DEFSNG( l );
  2602. break;
  2603. case C_DEFSTR:
  2604. r = bwb_DEFSTR( l );
  2605. break;
  2606. case C_DELETE:
  2607. r = bwb_DELETE( l );
  2608. break;
  2609. case C_DELIMIT:
  2610. r = bwb_DELIMIT( l );
  2611. break;
  2612. case C_DIM:
  2613. r = bwb_DIM( l );
  2614. break;
  2615. case C_DISPLAY:
  2616. r = bwb_DISPLAY( l );
  2617. break;
  2618. case C_DO:
  2619. r = bwb_DO( l );
  2620. break;
  2621. case C_DOS:
  2622. r = bwb_DOS( l );
  2623. break;
  2624. case C_DSP:
  2625. r = bwb_DSP( l );
  2626. break;
  2627. case C_EDIT:
  2628. r = bwb_EDIT( l );
  2629. break;
  2630. case C_ELSE:
  2631. r = bwb_ELSE( l );
  2632. break;
  2633. case C_ELSEIF:
  2634. r = bwb_ELSEIF( l );
  2635. break;
  2636. case C_END:
  2637. r = bwb_END( l );
  2638. break;
  2639. case C_END_FUNCTION:
  2640. r = bwb_END_FUNCTION( l );
  2641. break;
  2642. case C_END_IF:
  2643. r = bwb_END_IF( l );
  2644. break;
  2645. case C_END_SELECT:
  2646. r = bwb_END_SELECT( l );
  2647. break;
  2648. case C_END_SUB:
  2649. r = bwb_END_SUB( l );
  2650. break;
  2651. case C_ERASE:
  2652. r = bwb_ERASE( l );
  2653. break;
  2654. case C_EXCHANGE:
  2655. r = bwb_EXCHANGE( l );
  2656. break;
  2657. case C_EXIT:
  2658. r = bwb_EXIT( l );
  2659. break;
  2660. case C_EXIT_DO:
  2661. r = bwb_EXIT_DO( l );
  2662. break;
  2663. case C_EXIT_FOR:
  2664. r = bwb_EXIT_FOR( l );
  2665. break;
  2666. case C_EXIT_FUNCTION:
  2667. r = bwb_EXIT_FUNCTION( l );
  2668. break;
  2669. case C_EXIT_REPEAT:
  2670. r = bwb_EXIT_REPEAT( l );
  2671. break;
  2672. case C_EXIT_SUB:
  2673. r = bwb_EXIT_SUB( l );
  2674. break;
  2675. case C_EXIT_WHILE:
  2676. r = bwb_EXIT_WHILE( l );
  2677. break;
  2678. case C_FEND:
  2679. r = bwb_FEND( l );
  2680. break;
  2681. case C_FIELD:
  2682. r = bwb_FIELD( l );
  2683. break;
  2684. case C_FILE:
  2685. r = bwb_FILE( l );
  2686. break;
  2687. case C_FILES:
  2688. r = bwb_FILES( l );
  2689. break;
  2690. case C_FLEX:
  2691. r = bwb_FLEX( l );
  2692. break;
  2693. case C_FNCS:
  2694. r = bwb_FNCS( l );
  2695. break;
  2696. case C_FNEND:
  2697. r = bwb_FNEND( l );
  2698. break;
  2699. case C_FOR:
  2700. r = bwb_FOR( l );
  2701. break;
  2702. case C_FUNCTION:
  2703. r = bwb_FUNCTION( l );
  2704. break;
  2705. case C_GET:
  2706. r = bwb_GET( l );
  2707. break;
  2708. case C_GO:
  2709. r = bwb_GO( l );
  2710. break;
  2711. case C_GO_SUB:
  2712. r = bwb_GO_SUB( l );
  2713. break;
  2714. case C_GO_TO:
  2715. r = bwb_GO_TO( l );
  2716. break;
  2717. case C_GOODBYE:
  2718. r = bwb_GOODBYE( l );
  2719. break;
  2720. case C_GOSUB:
  2721. r = bwb_GOSUB( l );
  2722. break;
  2723. case C_GOTO:
  2724. r = bwb_GOTO( l );
  2725. break;
  2726. case C_HELP:
  2727. r = bwb_HELP( l );
  2728. break;
  2729. case C_IF:
  2730. r = bwb_IF( l );
  2731. break;
  2732. case C_IF_END:
  2733. r = bwb_IF_END( l );
  2734. break;
  2735. case C_IF_MORE:
  2736. r = bwb_IF_MORE( l );
  2737. break;
  2738. case C_IF8THEN:
  2739. r = bwb_IF8THEN( l );
  2740. break;
  2741. case C_IMAGE:
  2742. r = bwb_IMAGE( l );
  2743. break;
  2744. case C_INC:
  2745. r = bwb_INC( l );
  2746. break;
  2747. case C_INPUT:
  2748. r = bwb_INPUT( l );
  2749. break;
  2750. case C_INPUT_LINE:
  2751. r = bwb_INPUT_LINE( l );
  2752. break;
  2753. case C_LET:
  2754. r = bwb_LET( l );
  2755. break;
  2756. case C_LINE:
  2757. r = bwb_LINE( l );
  2758. break;
  2759. case C_LINE_INPUT:
  2760. r = bwb_LINE_INPUT( l );
  2761. break;
  2762. case C_LIST:
  2763. r = bwb_LIST( l );
  2764. break;
  2765. case C_LISTNH:
  2766. r = bwb_LISTNH( l );
  2767. break;
  2768. case C_LLIST:
  2769. r = bwb_LLIST( l );
  2770. break;
  2771. case C_LOAD:
  2772. r = bwb_LOAD( l );
  2773. break;
  2774. case C_LOCAL:
  2775. r = bwb_LOCAL( l );
  2776. break;
  2777. case C_LOOP:
  2778. r = bwb_LOOP( l );
  2779. break;
  2780. case C_LPRINT:
  2781. r = bwb_LPRINT( l );
  2782. break;
  2783. case C_LPRINTER:
  2784. r = bwb_LPRINTER( l );
  2785. break;
  2786. case C_LPT:
  2787. r = bwb_LPT( l );
  2788. break;
  2789. case C_LSET:
  2790. r = bwb_LSET( l );
  2791. break;
  2792. case C_MAINTAINER:
  2793. r = bwb_MAINTAINER( l );
  2794. break;
  2795. case C_MAINTAINER_CMDS:
  2796. r = bwb_MAINTAINER_CMDS( l );
  2797. break;
  2798. case C_MAINTAINER_CMDS_HTML:
  2799. r = bwb_MAINTAINER_CMDS_HTML( l );
  2800. break;
  2801. case C_MAINTAINER_CMDS_ID:
  2802. r = bwb_MAINTAINER_CMDS_ID( l );
  2803. break;
  2804. case C_MAINTAINER_CMDS_MANUAL:
  2805. r = bwb_MAINTAINER_CMDS_MANUAL( l );
  2806. break;
  2807. case C_MAINTAINER_CMDS_SWITCH:
  2808. r = bwb_MAINTAINER_CMDS_SWITCH( l );
  2809. break;
  2810. case C_MAINTAINER_CMDS_TABLE:
  2811. r = bwb_MAINTAINER_CMDS_TABLE( l );
  2812. break;
  2813. case C_MAINTAINER_DEBUG:
  2814. r = bwb_MAINTAINER_DEBUG( l );
  2815. break;
  2816. case C_MAINTAINER_DEBUG_OFF:
  2817. r = bwb_MAINTAINER_DEBUG_OFF( l );
  2818. break;
  2819. case C_MAINTAINER_DEBUG_ON:
  2820. r = bwb_MAINTAINER_DEBUG_ON( l );
  2821. break;
  2822. case C_MAINTAINER_FNCS:
  2823. r = bwb_MAINTAINER_FNCS( l );
  2824. break;
  2825. case C_MAINTAINER_FNCS_HTML:
  2826. r = bwb_MAINTAINER_FNCS_HTML( l );
  2827. break;
  2828. case C_MAINTAINER_FNCS_ID:
  2829. r = bwb_MAINTAINER_FNCS_ID( l );
  2830. break;
  2831. case C_MAINTAINER_FNCS_MANUAL:
  2832. r = bwb_MAINTAINER_FNCS_MANUAL( l );
  2833. break;
  2834. case C_MAINTAINER_FNCS_SWITCH:
  2835. r = bwb_MAINTAINER_FNCS_SWITCH( l );
  2836. break;
  2837. case C_MAINTAINER_FNCS_TABLE:
  2838. r = bwb_MAINTAINER_FNCS_TABLE( l );
  2839. break;
  2840. case C_MAINTAINER_MANUAL:
  2841. r = bwb_MAINTAINER_MANUAL( l );
  2842. break;
  2843. case C_MAINTAINER_STACK:
  2844. r = bwb_MAINTAINER_STACK( l );
  2845. break;
  2846. case C_MARGIN:
  2847. r = bwb_MARGIN( l );
  2848. break;
  2849. case C_MAT:
  2850. r = bwb_MAT( l );
  2851. break;
  2852. case C_MAT_GET:
  2853. r = bwb_MAT_GET( l );
  2854. break;
  2855. case C_MAT_INPUT:
  2856. r = bwb_MAT_INPUT( l );
  2857. break;
  2858. case C_MAT_PRINT:
  2859. r = bwb_MAT_PRINT( l );
  2860. break;
  2861. case C_MAT_PUT:
  2862. r = bwb_MAT_PUT( l );
  2863. break;
  2864. case C_MAT_READ:
  2865. r = bwb_MAT_READ( l );
  2866. break;
  2867. case C_MAT_WRITE:
  2868. r = bwb_MAT_WRITE( l );
  2869. break;
  2870. case C_MERGE:
  2871. r = bwb_MERGE( l );
  2872. break;
  2873. case C_MID4:
  2874. r = bwb_MID4( l );
  2875. break;
  2876. case C_MON:
  2877. r = bwb_MON( l );
  2878. break;
  2879. case C_NAME:
  2880. r = bwb_NAME( l );
  2881. break;
  2882. case C_NEW:
  2883. r = bwb_NEW( l );
  2884. break;
  2885. case C_NEXT:
  2886. r = bwb_NEXT( l );
  2887. break;
  2888. case C_OF:
  2889. r = bwb_OF( l );
  2890. break;
  2891. case C_OLD:
  2892. r = bwb_OLD( l );
  2893. break;
  2894. case C_ON:
  2895. r = bwb_ON( l );
  2896. break;
  2897. case C_ON_ERROR:
  2898. r = bwb_ON_ERROR( l );
  2899. break;
  2900. case C_ON_ERROR_GOSUB:
  2901. r = bwb_ON_ERROR_GOSUB( l );
  2902. break;
  2903. case C_ON_ERROR_GOTO:
  2904. r = bwb_ON_ERROR_GOTO( l );
  2905. break;
  2906. case C_ON_ERROR_RESUME:
  2907. r = bwb_ON_ERROR_RESUME( l );
  2908. break;
  2909. case C_ON_ERROR_RESUME_NEXT:
  2910. r = bwb_ON_ERROR_RESUME_NEXT( l );
  2911. break;
  2912. case C_ON_ERROR_RETURN:
  2913. r = bwb_ON_ERROR_RETURN( l );
  2914. break;
  2915. case C_ON_ERROR_RETURN_NEXT:
  2916. r = bwb_ON_ERROR_RETURN_NEXT( l );
  2917. break;
  2918. case C_ON_TIMER:
  2919. r = bwb_ON_TIMER( l );
  2920. break;
  2921. case C_OPEN:
  2922. r = bwb_OPEN( l );
  2923. break;
  2924. case C_OPTION:
  2925. r = bwb_OPTION( l );
  2926. break;
  2927. case C_OPTION_ANGLE:
  2928. r = bwb_OPTION_ANGLE( l );
  2929. break;
  2930. case C_OPTION_ANGLE_DEGREES:
  2931. r = bwb_OPTION_ANGLE_DEGREES( l );
  2932. break;
  2933. case C_OPTION_ANGLE_GRADIANS:
  2934. r = bwb_OPTION_ANGLE_GRADIANS( l );
  2935. break;
  2936. case C_OPTION_ANGLE_RADIANS:
  2937. r = bwb_OPTION_ANGLE_RADIANS( l );
  2938. break;
  2939. case C_OPTION_ARITHMETIC:
  2940. r = bwb_OPTION_ARITHMETIC( l );
  2941. break;
  2942. case C_OPTION_ARITHMETIC_DECIMAL:
  2943. r = bwb_OPTION_ARITHMETIC_DECIMAL( l );
  2944. break;
  2945. case C_OPTION_ARITHMETIC_FIXED:
  2946. r = bwb_OPTION_ARITHMETIC_FIXED( l );
  2947. break;
  2948. case C_OPTION_ARITHMETIC_NATIVE:
  2949. r = bwb_OPTION_ARITHMETIC_NATIVE( l );
  2950. break;
  2951. case C_OPTION_BASE:
  2952. r = bwb_OPTION_BASE( l );
  2953. break;
  2954. case C_OPTION_BUGS:
  2955. r = bwb_OPTION_BUGS( l );
  2956. break;
  2957. case C_OPTION_BUGS_BOOLEAN:
  2958. r = bwb_OPTION_BUGS_BOOLEAN( l );
  2959. break;
  2960. case C_OPTION_BUGS_OFF:
  2961. r = bwb_OPTION_BUGS_OFF( l );
  2962. break;
  2963. case C_OPTION_BUGS_ON:
  2964. r = bwb_OPTION_BUGS_ON( l );
  2965. break;
  2966. case C_OPTION_COMPARE:
  2967. r = bwb_OPTION_COMPARE( l );
  2968. break;
  2969. case C_OPTION_COMPARE_BINARY:
  2970. r = bwb_OPTION_COMPARE_BINARY( l );
  2971. break;
  2972. case C_OPTION_COMPARE_DATABASE:
  2973. r = bwb_OPTION_COMPARE_DATABASE( l );
  2974. break;
  2975. case C_OPTION_COMPARE_TEXT:
  2976. r = bwb_OPTION_COMPARE_TEXT( l );
  2977. break;
  2978. case C_OPTION_COVERAGE:
  2979. r = bwb_OPTION_COVERAGE( l );
  2980. break;
  2981. case C_OPTION_COVERAGE_OFF:
  2982. r = bwb_OPTION_COVERAGE_OFF( l );
  2983. break;
  2984. case C_OPTION_COVERAGE_ON:
  2985. r = bwb_OPTION_COVERAGE_ON( l );
  2986. break;
  2987. case C_OPTION_DATE:
  2988. r = bwb_OPTION_DATE( l );
  2989. break;
  2990. case C_OPTION_DIGITS:
  2991. r = bwb_OPTION_DIGITS( l );
  2992. break;
  2993. case C_OPTION_DISABLE:
  2994. r = bwb_OPTION_DISABLE( l );
  2995. break;
  2996. case C_OPTION_DISABLE_COMMAND:
  2997. r = bwb_OPTION_DISABLE_COMMAND( l );
  2998. break;
  2999. case C_OPTION_DISABLE_FUNCTION:
  3000. r = bwb_OPTION_DISABLE_FUNCTION( l );
  3001. break;
  3002. case C_OPTION_DISABLE_OPERATOR:
  3003. r = bwb_OPTION_DISABLE_OPERATOR( l );
  3004. break;
  3005. case C_OPTION_EDIT:
  3006. r = bwb_OPTION_EDIT( l );
  3007. break;
  3008. case C_OPTION_ENABLE:
  3009. r = bwb_OPTION_ENABLE( l );
  3010. break;
  3011. case C_OPTION_ENABLE_COMMAND:
  3012. r = bwb_OPTION_ENABLE_COMMAND( l );
  3013. break;
  3014. case C_OPTION_ENABLE_FUNCTION:
  3015. r = bwb_OPTION_ENABLE_FUNCTION( l );
  3016. break;
  3017. case C_OPTION_ENABLE_OPERATOR:
  3018. r = bwb_OPTION_ENABLE_OPERATOR( l );
  3019. break;
  3020. case C_OPTION_ERROR:
  3021. r = bwb_OPTION_ERROR( l );
  3022. break;
  3023. case C_OPTION_ERROR_GOSUB:
  3024. r = bwb_OPTION_ERROR_GOSUB( l );
  3025. break;
  3026. case C_OPTION_ERROR_GOTO:
  3027. r = bwb_OPTION_ERROR_GOTO( l );
  3028. break;
  3029. case C_OPTION_EXPLICIT:
  3030. r = bwb_OPTION_EXPLICIT( l );
  3031. break;
  3032. case C_OPTION_EXTENSION:
  3033. r = bwb_OPTION_EXTENSION( l );
  3034. break;
  3035. case C_OPTION_FILES:
  3036. r = bwb_OPTION_FILES( l );
  3037. break;
  3038. case C_OPTION_IMPLICIT:
  3039. r = bwb_OPTION_IMPLICIT( l );
  3040. break;
  3041. case C_OPTION_INDENT:
  3042. r = bwb_OPTION_INDENT( l );
  3043. break;
  3044. case C_OPTION_LABELS:
  3045. r = bwb_OPTION_LABELS( l );
  3046. break;
  3047. case C_OPTION_LABELS_OFF:
  3048. r = bwb_OPTION_LABELS_OFF( l );
  3049. break;
  3050. case C_OPTION_LABELS_ON:
  3051. r = bwb_OPTION_LABELS_ON( l );
  3052. break;
  3053. case C_OPTION_PROMPT:
  3054. r = bwb_OPTION_PROMPT( l );
  3055. break;
  3056. case C_OPTION_PUNCT:
  3057. r = bwb_OPTION_PUNCT( l );
  3058. break;
  3059. case C_OPTION_PUNCT_AT:
  3060. r = bwb_OPTION_PUNCT_AT( l );
  3061. break;
  3062. case C_OPTION_PUNCT_BYTE:
  3063. r = bwb_OPTION_PUNCT_BYTE( l );
  3064. break;
  3065. case C_OPTION_PUNCT_COMMENT:
  3066. r = bwb_OPTION_PUNCT_COMMENT( l );
  3067. break;
  3068. case C_OPTION_PUNCT_CURRENCY:
  3069. r = bwb_OPTION_PUNCT_CURRENCY( l );
  3070. break;
  3071. case C_OPTION_PUNCT_DOUBLE:
  3072. r = bwb_OPTION_PUNCT_DOUBLE( l );
  3073. break;
  3074. case C_OPTION_PUNCT_FILENUM:
  3075. r = bwb_OPTION_PUNCT_FILENUM( l );
  3076. break;
  3077. case C_OPTION_PUNCT_IMAGE:
  3078. r = bwb_OPTION_PUNCT_IMAGE( l );
  3079. break;
  3080. case C_OPTION_PUNCT_INPUT:
  3081. r = bwb_OPTION_PUNCT_INPUT( l );
  3082. break;
  3083. case C_OPTION_PUNCT_INTEGER:
  3084. r = bwb_OPTION_PUNCT_INTEGER( l );
  3085. break;
  3086. case C_OPTION_PUNCT_LONG:
  3087. r = bwb_OPTION_PUNCT_LONG( l );
  3088. break;
  3089. case C_OPTION_PUNCT_LPAREN:
  3090. r = bwb_OPTION_PUNCT_LPAREN( l );
  3091. break;
  3092. case C_OPTION_PUNCT_PRINT:
  3093. r = bwb_OPTION_PUNCT_PRINT( l );
  3094. break;
  3095. case C_OPTION_PUNCT_QUOTE:
  3096. r = bwb_OPTION_PUNCT_QUOTE( l );
  3097. break;
  3098. case C_OPTION_PUNCT_RPAREN:
  3099. r = bwb_OPTION_PUNCT_RPAREN( l );
  3100. break;
  3101. case C_OPTION_PUNCT_SINGLE:
  3102. r = bwb_OPTION_PUNCT_SINGLE( l );
  3103. break;
  3104. case C_OPTION_PUNCT_STATEMENT:
  3105. r = bwb_OPTION_PUNCT_STATEMENT( l );
  3106. break;
  3107. case C_OPTION_PUNCT_STRING:
  3108. r = bwb_OPTION_PUNCT_STRING( l );
  3109. break;
  3110. case C_OPTION_RECLEN:
  3111. r = bwb_OPTION_RECLEN( l );
  3112. break;
  3113. case C_OPTION_RENUM:
  3114. r = bwb_OPTION_RENUM( l );
  3115. break;
  3116. case C_OPTION_ROUND:
  3117. r = bwb_OPTION_ROUND( l );
  3118. break;
  3119. case C_OPTION_ROUND_BANK:
  3120. r = bwb_OPTION_ROUND_BANK( l );
  3121. break;
  3122. case C_OPTION_ROUND_MATH:
  3123. r = bwb_OPTION_ROUND_MATH( l );
  3124. break;
  3125. case C_OPTION_ROUND_TRUNCATE:
  3126. r = bwb_OPTION_ROUND_TRUNCATE( l );
  3127. break;
  3128. case C_OPTION_SCALE:
  3129. r = bwb_OPTION_SCALE( l );
  3130. break;
  3131. case C_OPTION_SLEEP:
  3132. r = bwb_OPTION_SLEEP( l );
  3133. break;
  3134. case C_OPTION_STDERR:
  3135. r = bwb_OPTION_STDERR( l );
  3136. break;
  3137. case C_OPTION_STDIN:
  3138. r = bwb_OPTION_STDIN( l );
  3139. break;
  3140. case C_OPTION_STDOUT:
  3141. r = bwb_OPTION_STDOUT( l );
  3142. break;
  3143. case C_OPTION_STRICT:
  3144. r = bwb_OPTION_STRICT( l );
  3145. break;
  3146. case C_OPTION_STRICT_OFF:
  3147. r = bwb_OPTION_STRICT_OFF( l );
  3148. break;
  3149. case C_OPTION_STRICT_ON:
  3150. r = bwb_OPTION_STRICT_ON( l );
  3151. break;
  3152. case C_OPTION_TERMINAL:
  3153. r = bwb_OPTION_TERMINAL( l );
  3154. break;
  3155. case C_OPTION_TERMINAL_ADM:
  3156. r = bwb_OPTION_TERMINAL_ADM( l );
  3157. break;
  3158. case C_OPTION_TERMINAL_ANSI:
  3159. r = bwb_OPTION_TERMINAL_ANSI( l );
  3160. break;
  3161. case C_OPTION_TERMINAL_NONE:
  3162. r = bwb_OPTION_TERMINAL_NONE( l );
  3163. break;
  3164. case C_OPTION_TIME:
  3165. r = bwb_OPTION_TIME( l );
  3166. break;
  3167. case C_OPTION_TRACE:
  3168. r = bwb_OPTION_TRACE( l );
  3169. break;
  3170. case C_OPTION_TRACE_OFF:
  3171. r = bwb_OPTION_TRACE_OFF( l );
  3172. break;
  3173. case C_OPTION_TRACE_ON:
  3174. r = bwb_OPTION_TRACE_ON( l );
  3175. break;
  3176. case C_OPTION_USING:
  3177. r = bwb_OPTION_USING( l );
  3178. break;
  3179. case C_OPTION_USING_ALL:
  3180. r = bwb_OPTION_USING_ALL( l );
  3181. break;
  3182. case C_OPTION_USING_COMMA:
  3183. r = bwb_OPTION_USING_COMMA( l );
  3184. break;
  3185. case C_OPTION_USING_DIGIT:
  3186. r = bwb_OPTION_USING_DIGIT( l );
  3187. break;
  3188. case C_OPTION_USING_DOLLAR:
  3189. r = bwb_OPTION_USING_DOLLAR( l );
  3190. break;
  3191. case C_OPTION_USING_EXRAD:
  3192. r = bwb_OPTION_USING_EXRAD( l );
  3193. break;
  3194. case C_OPTION_USING_FILLER:
  3195. r = bwb_OPTION_USING_FILLER( l );
  3196. break;
  3197. case C_OPTION_USING_FIRST:
  3198. r = bwb_OPTION_USING_FIRST( l );
  3199. break;
  3200. case C_OPTION_USING_LENGTH:
  3201. r = bwb_OPTION_USING_LENGTH( l );
  3202. break;
  3203. case C_OPTION_USING_LITERAL:
  3204. r = bwb_OPTION_USING_LITERAL( l );
  3205. break;
  3206. case C_OPTION_USING_MINUS:
  3207. r = bwb_OPTION_USING_MINUS( l );
  3208. break;
  3209. case C_OPTION_USING_PERIOD:
  3210. r = bwb_OPTION_USING_PERIOD( l );
  3211. break;
  3212. case C_OPTION_USING_PLUS:
  3213. r = bwb_OPTION_USING_PLUS( l );
  3214. break;
  3215. case C_OPTION_VERSION:
  3216. r = bwb_OPTION_VERSION( l );
  3217. break;
  3218. case C_OPTION_ZONE:
  3219. r = bwb_OPTION_ZONE( l );
  3220. break;
  3221. case C_PAUSE:
  3222. r = bwb_PAUSE( l );
  3223. break;
  3224. case C_PDEL:
  3225. r = bwb_PDEL( l );
  3226. break;
  3227. case C_POP:
  3228. r = bwb_POP( l );
  3229. break;
  3230. case C_PRINT:
  3231. r = bwb_PRINT( l );
  3232. break;
  3233. case C_PTP:
  3234. r = bwb_PTP( l );
  3235. break;
  3236. case C_PTR:
  3237. r = bwb_PTR( l );
  3238. break;
  3239. case C_PUT:
  3240. r = bwb_PUT( l );
  3241. break;
  3242. case C_QUIT:
  3243. r = bwb_QUIT( l );
  3244. break;
  3245. case C_READ:
  3246. r = bwb_READ( l );
  3247. break;
  3248. case C_RECALL:
  3249. r = bwb_RECALL( l );
  3250. break;
  3251. case C_REM:
  3252. r = bwb_REM( l );
  3253. break;
  3254. case C_RENAME:
  3255. r = bwb_RENAME( l );
  3256. break;
  3257. case C_RENUM:
  3258. r = bwb_RENUM( l );
  3259. break;
  3260. case C_RENUMBER:
  3261. r = bwb_RENUMBER( l );
  3262. break;
  3263. case C_REPEAT:
  3264. r = bwb_REPEAT( l );
  3265. break;
  3266. case C_REPLACE:
  3267. r = bwb_REPLACE( l );
  3268. break;
  3269. case C_RESET:
  3270. r = bwb_RESET( l );
  3271. break;
  3272. case C_RESTORE:
  3273. r = bwb_RESTORE( l );
  3274. break;
  3275. case C_RESUME:
  3276. r = bwb_RESUME( l );
  3277. break;
  3278. case C_RETURN:
  3279. r = bwb_RETURN( l );
  3280. break;
  3281. case C_RSET:
  3282. r = bwb_RSET( l );
  3283. break;
  3284. case C_RUN:
  3285. r = bwb_RUN( l );
  3286. break;
  3287. case C_RUNNH:
  3288. r = bwb_RUNNH( l );
  3289. break;
  3290. case C_SAVE:
  3291. r = bwb_SAVE( l );
  3292. break;
  3293. case C_SCRATCH:
  3294. r = bwb_SCRATCH( l );
  3295. break;
  3296. case C_SELECT:
  3297. r = bwb_SELECT( l );
  3298. break;
  3299. case C_SELECT_CASE:
  3300. r = bwb_SELECT_CASE( l );
  3301. break;
  3302. case C_STEP:
  3303. r = bwb_STEP( l );
  3304. break;
  3305. case C_STOP:
  3306. r = bwb_STOP( l );
  3307. break;
  3308. case C_STORE:
  3309. r = bwb_STORE( l );
  3310. break;
  3311. case C_SUB:
  3312. r = bwb_SUB( l );
  3313. break;
  3314. case C_SUB_END:
  3315. r = bwb_SUB_END( l );
  3316. break;
  3317. case C_SUB_EXIT:
  3318. r = bwb_SUB_EXIT( l );
  3319. break;
  3320. case C_SUBEND:
  3321. r = bwb_SUBEND( l );
  3322. break;
  3323. case C_SUBEXIT:
  3324. r = bwb_SUBEXIT( l );
  3325. break;
  3326. case C_SWAP:
  3327. r = bwb_SWAP( l );
  3328. break;
  3329. case C_SYSTEM:
  3330. r = bwb_SYSTEM( l );
  3331. break;
  3332. case C_TEXT:
  3333. r = bwb_TEXT( l );
  3334. break;
  3335. case C_THEN:
  3336. r = bwb_THEN( l );
  3337. break;
  3338. case C_TIMER:
  3339. r = bwb_TIMER( l );
  3340. break;
  3341. case C_TIMER_OFF:
  3342. r = bwb_TIMER_OFF( l );
  3343. break;
  3344. case C_TIMER_ON:
  3345. r = bwb_TIMER_ON( l );
  3346. break;
  3347. case C_TIMER_STOP:
  3348. r = bwb_TIMER_STOP( l );
  3349. break;
  3350. case C_TLOAD:
  3351. r = bwb_TLOAD( l );
  3352. break;
  3353. case C_TO:
  3354. r = bwb_TO( l );
  3355. break;
  3356. case C_TRACE:
  3357. r = bwb_TRACE( l );
  3358. break;
  3359. case C_TRACE_OFF:
  3360. r = bwb_TRACE_OFF( l );
  3361. break;
  3362. case C_TRACE_ON:
  3363. r = bwb_TRACE_ON( l );
  3364. break;
  3365. case C_TSAVE:
  3366. r = bwb_TSAVE( l );
  3367. break;
  3368. case C_TTY:
  3369. r = bwb_TTY( l );
  3370. break;
  3371. case C_TTY_IN:
  3372. r = bwb_TTY_IN( l );
  3373. break;
  3374. case C_TTY_OUT:
  3375. r = bwb_TTY_OUT( l );
  3376. break;
  3377. case C_UNTIL:
  3378. r = bwb_UNTIL( l );
  3379. break;
  3380. case C_USE:
  3381. r = bwb_USE( l );
  3382. break;
  3383. case C_VARS:
  3384. r = bwb_VARS( l );
  3385. break;
  3386. case C_WEND:
  3387. r = bwb_WEND( l );
  3388. break;
  3389. case C_WHILE:
  3390. r = bwb_WHILE( l );
  3391. break;
  3392. case C_WRITE:
  3393. r = bwb_WRITE( l );
  3394. break;
  3395. default:
  3396. WARN_INTERNAL_ERROR;
  3397. r = l;
  3398. break;
  3399. }
  3400. return r;
  3401. }
  3402. /* EOF */