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.
 
 
 
 
 
 

4087 lines
82 KiB

  1. /***************************************************************f
  2. bwb_int.c Line Interpretation Routines
  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. /*---------------------------------------------------------------*/
  31. #include "bwbasic.h"
  32. static int buff_read_keyword (char *buffer, int *position, char *keyword);
  33. static int bwb_chartype (int C);
  34. static int char_is_varfirst (char C);
  35. static char char_is_varhead (char C);
  36. static int char_is_varnext (char C);
  37. static int char_is_vartail (char C);
  38. static int GetKeyword (LineType * l, char *Keyword);
  39. static void internal_DEF8SUB (LineType * l);
  40. static int is_cmd (char *name);
  41. static int is_let (char *buffer);
  42. static int line_read_keyword (LineType * line, char *keyword);
  43. extern void
  44. buff_skip_spaces (char *buffer, int *position)
  45. {
  46. /*
  47. skip spaces in 'buffer'.
  48. 'position' is always updated.
  49. */
  50. int p;
  51. assert (buffer != NULL);
  52. assert (position != NULL);
  53. p = *position;
  54. while (buffer[p] == ' ')
  55. {
  56. p++;
  57. }
  58. *position = p;
  59. }
  60. extern void
  61. line_skip_spaces (LineType * line)
  62. {
  63. assert (line != NULL);
  64. buff_skip_spaces (line->buffer, &(line->position)); /* keep this */
  65. }
  66. extern void
  67. buff_skip_eol (char *buffer, int *position)
  68. {
  69. /*
  70. skip to the NUL (NulChar) in 'buffer'.
  71. always updates 'position'.
  72. */
  73. int p;
  74. assert (buffer != NULL);
  75. assert (position != NULL);
  76. p = *position;
  77. while (buffer[p])
  78. {
  79. p++;
  80. }
  81. *position = p;
  82. }
  83. extern void
  84. line_skip_eol (LineType * line)
  85. {
  86. assert (line != NULL);
  87. buff_skip_eol (line->buffer, &(line->position));
  88. }
  89. extern int
  90. buff_is_eol (char *buffer, int *position)
  91. {
  92. /*
  93. determines whether 'position' is effectively at the NUL (NulChar) in 'buffer'.
  94. if successful then 'position' is updated and returns TRUE
  95. otherwise returns FALSE.
  96. */
  97. int p;
  98. assert (buffer != NULL);
  99. assert (position != NULL);
  100. p = *position;
  101. buff_skip_spaces (buffer, &p); /* keep this */
  102. if (buffer[p] == NulChar)
  103. {
  104. *position = p;
  105. return TRUE;
  106. }
  107. return FALSE;
  108. }
  109. extern int
  110. line_is_eol (LineType * line)
  111. {
  112. assert (line != NULL);
  113. return buff_is_eol (line->buffer, &(line->position));
  114. }
  115. extern int
  116. buff_peek_char (char *buffer, int *position, char find)
  117. {
  118. /*
  119. determine whether the next non-space character in 'buffer' is 'find'.
  120. if successful then returns TRUE
  121. otherwise returns FALSE.
  122. 'position' is unchanged.
  123. */
  124. assert (buffer != NULL);
  125. assert (position != NULL);
  126. if (find != NulChar && find != ' ')
  127. {
  128. int p;
  129. p = *position;
  130. buff_skip_spaces (buffer, &p); /* keep this */
  131. if (buffer[p] == find)
  132. {
  133. return TRUE;
  134. }
  135. }
  136. return FALSE;
  137. }
  138. #if FALSE /* keep this ... */
  139. extern int
  140. line_peek_char (LineType * line, char find)
  141. {
  142. assert (line != NULL);
  143. return buff_peek_char (line->buffer, &(line->position), find);
  144. }
  145. #endif
  146. extern int
  147. buff_peek_EqualChar (char *buffer, int *position)
  148. {
  149. /*
  150. determine whether the next non-space character in 'buffer' is 'find'.
  151. if successful then returns TRUE
  152. otherwise returns FALSE.
  153. 'position' is unchanged.
  154. */
  155. assert (buffer != NULL);
  156. assert (position != NULL);
  157. return buff_peek_char (buffer, position, '=');
  158. }
  159. extern int
  160. line_peek_EqualChar (LineType * line)
  161. {
  162. assert (line != NULL);
  163. return buff_peek_EqualChar (line->buffer, &(line->position));
  164. }
  165. extern int
  166. buff_peek_QuoteChar (char *buffer, int *position)
  167. {
  168. /*
  169. determine whether the next non-space character in 'buffer' is 'find'.
  170. if successful then returns TRUE
  171. otherwise returns FALSE.
  172. 'position' is unchanged.
  173. */
  174. assert (buffer != NULL);
  175. assert (position != NULL);
  176. return buff_peek_char (buffer, position,
  177. My->CurrentVersion->OptionQuoteChar);
  178. }
  179. extern int
  180. line_peek_QuoteChar (LineType * line)
  181. {
  182. assert (line != NULL);
  183. return buff_peek_QuoteChar (line->buffer, &(line->position));
  184. }
  185. extern int
  186. buff_peek_LparenChar (char *buffer, int *position)
  187. {
  188. /*
  189. determine whether the next non-space character in 'buffer' is 'find'.
  190. if successful then returns TRUE
  191. otherwise returns FALSE.
  192. 'position' is unchanged.
  193. */
  194. assert (buffer != NULL);
  195. assert (position != NULL);
  196. return buff_peek_char (buffer, position,
  197. My->CurrentVersion->OptionLparenChar);
  198. }
  199. extern int
  200. line_peek_LparenChar (LineType * line)
  201. {
  202. assert (line != NULL);
  203. return buff_peek_LparenChar (line->buffer, &(line->position));
  204. }
  205. extern int
  206. buff_skip_char (char *buffer, int *position, char find)
  207. {
  208. /*
  209. skip the next non-space character in 'buffer' if it is 'find'.
  210. 'find' is NOT an alphabetic (A-Z,a-z) character.
  211. if successful then 'position' is updated past 'find' and returns TRUE
  212. otherwise 'position' is unchanged and returns FALSE.
  213. */
  214. assert (buffer != NULL);
  215. assert (position != NULL);
  216. if (find)
  217. {
  218. int p;
  219. p = *position;
  220. buff_skip_spaces (buffer, &p); /* keep this */
  221. if (buffer[p] == find)
  222. {
  223. p++;
  224. *position = p;
  225. return TRUE;
  226. }
  227. }
  228. return FALSE;
  229. }
  230. extern int
  231. line_skip_char (LineType * line, char find)
  232. {
  233. assert (line != NULL);
  234. return buff_skip_char (line->buffer, &(line->position), find);
  235. }
  236. extern int
  237. buff_skip_FilenumChar (char *buffer, int *position)
  238. {
  239. /*
  240. skip the next non-space character in 'buffer' if it is 'find'.
  241. if successful then 'position' is updated past 'find' and returns TRUE
  242. otherwise 'position' is unchanged and returns FALSE.
  243. */
  244. assert (buffer != NULL);
  245. assert (position != NULL);
  246. return buff_skip_char (buffer, position,
  247. My->CurrentVersion->OptionFilenumChar);
  248. }
  249. extern int
  250. line_skip_FilenumChar (LineType * line)
  251. {
  252. assert (line != NULL);
  253. return buff_skip_FilenumChar (line->buffer, &(line->position));
  254. }
  255. extern int
  256. buff_skip_AtChar (char *buffer, int *position)
  257. {
  258. /*
  259. skip the next non-space character in 'buffer' if it is 'find'.
  260. if successful then 'position' is updated past 'find' and returns TRUE
  261. otherwise 'position' is unchanged and returns FALSE.
  262. */
  263. assert (buffer != NULL);
  264. assert (position != NULL);
  265. return buff_skip_char (buffer, position,
  266. My->CurrentVersion->OptionAtChar);
  267. }
  268. extern int
  269. line_skip_AtChar (LineType * line)
  270. {
  271. assert (line != NULL);
  272. return buff_skip_AtChar (line->buffer, &(line->position));
  273. }
  274. extern int
  275. buff_skip_LparenChar (char *buffer, int *position)
  276. {
  277. /*
  278. skip the next non-space character in 'buffer' if it is 'find'.
  279. if successful then 'position' is updated past 'find' and returns TRUE
  280. otherwise 'position' is unchanged and returns FALSE.
  281. */
  282. assert (buffer != NULL);
  283. assert (position != NULL);
  284. return buff_skip_char (buffer, position,
  285. My->CurrentVersion->OptionLparenChar);
  286. }
  287. extern int
  288. line_skip_LparenChar (LineType * line)
  289. {
  290. assert (line != NULL);
  291. return buff_skip_LparenChar (line->buffer, &(line->position));
  292. }
  293. extern int
  294. buff_skip_RparenChar (char *buffer, int *position)
  295. {
  296. /*
  297. skip the next non-space character in 'buffer' if it is 'find'.
  298. if successful then 'position' is updated past 'find' and returns TRUE
  299. otherwise 'position' is unchanged and returns FALSE.
  300. */
  301. assert (buffer != NULL);
  302. assert (position != NULL);
  303. return buff_skip_char (buffer, position,
  304. My->CurrentVersion->OptionRparenChar);
  305. }
  306. extern int
  307. line_skip_RparenChar (LineType * line)
  308. {
  309. assert (line != NULL);
  310. return buff_skip_RparenChar (line->buffer, &(line->position));
  311. }
  312. extern int
  313. buff_skip_CommaChar (char *buffer, int *position)
  314. {
  315. /*
  316. skip the next non-space character in 'buffer' if it is 'find'.
  317. if successful then 'position' is updated past 'find' and returns TRUE
  318. otherwise 'position' is unchanged and returns FALSE.
  319. */
  320. assert (buffer != NULL);
  321. assert (position != NULL);
  322. return buff_skip_char (buffer, position, ',');
  323. }
  324. extern int
  325. line_skip_CommaChar (LineType * line)
  326. {
  327. assert (line != NULL);
  328. return buff_skip_CommaChar (line->buffer, &(line->position));
  329. }
  330. extern int
  331. buff_skip_SemicolonChar (char *buffer, int *position)
  332. {
  333. /*
  334. skip the next non-space character in 'buffer' if it is 'find'.
  335. if successful then 'position' is updated past 'find' and returns TRUE
  336. otherwise 'position' is unchanged and returns FALSE.
  337. */
  338. assert (buffer != NULL);
  339. assert (position != NULL);
  340. return buff_skip_char (buffer, position, ';');
  341. }
  342. extern int
  343. line_skip_SemicolonChar (LineType * line)
  344. {
  345. assert (line != NULL);
  346. return buff_skip_SemicolonChar (line->buffer, &(line->position));
  347. }
  348. extern int
  349. buff_skip_EqualChar (char *buffer, int *position)
  350. {
  351. /*
  352. skip the next non-space character in 'buffer' if it is 'find'.
  353. if successful then 'position' is updated past 'find' and returns TRUE
  354. otherwise 'position' is unchanged and returns FALSE.
  355. */
  356. assert (buffer != NULL);
  357. assert (position != NULL);
  358. return buff_skip_char (buffer, position, '=');
  359. }
  360. extern int
  361. line_skip_EqualChar (LineType * line)
  362. {
  363. assert (line != NULL);
  364. return buff_skip_EqualChar (line->buffer, &(line->position));
  365. }
  366. extern int
  367. buff_skip_StarChar (char *buffer, int *position)
  368. {
  369. /*
  370. skip the next non-space character in 'buffer' if it is 'find'.
  371. if successful then 'position' is updated past 'find' and returns TRUE
  372. otherwise 'position' is unchanged and returns FALSE.
  373. */
  374. assert (buffer != NULL);
  375. assert (position != NULL);
  376. return buff_skip_char (buffer, position, '*');
  377. }
  378. extern int
  379. line_skip_StarChar (LineType * line)
  380. {
  381. assert (line != NULL);
  382. return buff_skip_StarChar (line->buffer, &(line->position));
  383. }
  384. extern int
  385. buff_skip_PlusChar (char *buffer, int *position)
  386. {
  387. /*
  388. skip the next non-space character in 'buffer' if it is 'find'.
  389. if successful then 'position' is updated past 'find' and returns TRUE
  390. otherwise 'position' is unchanged and returns FALSE.
  391. */
  392. assert (buffer != NULL);
  393. assert (position != NULL);
  394. return buff_skip_char (buffer, position, '+');
  395. }
  396. extern int
  397. line_skip_PlusChar (LineType * line)
  398. {
  399. assert (line != NULL);
  400. return buff_skip_PlusChar (line->buffer, &(line->position));
  401. }
  402. extern int
  403. buff_skip_MinusChar (char *buffer, int *position)
  404. {
  405. /*
  406. skip the next non-space character in 'buffer' if it is 'find'.
  407. if successful then 'position' is updated past 'find' and returns TRUE
  408. otherwise 'position' is unchanged and returns FALSE.
  409. */
  410. assert (buffer != NULL);
  411. assert (position != NULL);
  412. return buff_skip_char (buffer, position, '-');
  413. }
  414. extern int
  415. line_skip_MinusChar (LineType * line)
  416. {
  417. assert (line != NULL);
  418. return buff_skip_MinusChar (line->buffer, &(line->position));
  419. }
  420. extern char
  421. buff_skip_seperator (char *buffer, int *position)
  422. {
  423. /*
  424. skip the next non-space character in 'buffer' if it is a seperator (comma, semicolon, or colon).
  425. if successful then 'position' is updated past the character and returns the character skipped
  426. otherwise 'position' is unchanged and returns NulChar.
  427. */
  428. int p;
  429. char C;
  430. assert (buffer != NULL);
  431. assert (position != NULL);
  432. p = *position;
  433. buff_skip_spaces (buffer, &p); /* keep this */
  434. C = buffer[p];
  435. switch (C)
  436. {
  437. case ',': /* COMMA */
  438. case ';': /* SEMICOLON */
  439. case ':': /* COLON */
  440. p++;
  441. buff_skip_spaces (buffer, &p); /* keep this */
  442. *position = p;
  443. return C;
  444. }
  445. return NulChar;
  446. }
  447. extern char
  448. line_skip_seperator (LineType * line)
  449. {
  450. assert (line != NULL);
  451. return buff_skip_seperator (line->buffer, &(line->position));
  452. }
  453. static int
  454. char_is_varfirst (char C)
  455. {
  456. /*
  457. determine whether the character is allowed to be the first character of a BASIC variable name.
  458. if successful then returns TRUE
  459. otherwise returns FALSE.
  460. */
  461. if (C == NulChar || C == ' ')
  462. {
  463. return FALSE; /* never allowed */
  464. }
  465. if (bwb_isalpha (C))
  466. {
  467. return TRUE; /* always allowed */
  468. }
  469. /* dialect specific */
  470. switch (C)
  471. {
  472. case '@':
  473. case '#':
  474. case '$':
  475. if (My->CurrentVersion->OptionVersionValue & (S70 | I70 | I73))
  476. {
  477. /* alphabet extenders */
  478. return TRUE;
  479. }
  480. break;
  481. }
  482. /* NOT FOUND */
  483. return FALSE;
  484. }
  485. static int
  486. char_is_varnext (char C)
  487. {
  488. /*
  489. determine whether the character is allowed to be the second character of a BASIC variable name.
  490. if successful then returns TRUE
  491. otherwise returns FALSE.
  492. */
  493. if (C == NulChar || C == ' ')
  494. {
  495. return FALSE; /* never allowed */
  496. }
  497. if (bwb_isalnum (C))
  498. {
  499. return TRUE; /* always allowed */
  500. }
  501. /* dialect specific */
  502. switch (C)
  503. {
  504. case '.':
  505. case '_':
  506. if (My->CurrentVersion->OptionFlags & (OPTION_BUGS_ON)) /* varname: period and underscore are allowed */
  507. {
  508. return TRUE;
  509. }
  510. break;
  511. case '@':
  512. case '#':
  513. case '$':
  514. if (My->CurrentVersion->OptionVersionValue & (S70 | I70 | I73)) /* alphabet extenders */
  515. {
  516. return TRUE;
  517. }
  518. break;
  519. }
  520. /* NOT FOUND */
  521. return FALSE;
  522. }
  523. extern char
  524. TypeCode_to_Char (char TypeCode)
  525. {
  526. /*
  527. Convert the internal TypeCode value into the dialect-specifc tail character.
  528. if successful then returns the dialect-specifc tail character
  529. otherwise returns NulChar.
  530. */
  531. switch (TypeCode)
  532. {
  533. case ByteTypeCode:
  534. return My->CurrentVersion->OptionByteChar;
  535. case IntegerTypeCode:
  536. return My->CurrentVersion->OptionIntegerChar;
  537. case LongTypeCode:
  538. return My->CurrentVersion->OptionLongChar;
  539. case CurrencyTypeCode:
  540. return My->CurrentVersion->OptionCurrencyChar;
  541. case SingleTypeCode:
  542. return My->CurrentVersion->OptionSingleChar;
  543. case DoubleTypeCode:
  544. return My->CurrentVersion->OptionDoubleChar;
  545. case StringTypeCode:
  546. return My->CurrentVersion->OptionStringChar;
  547. }
  548. /* NOT FOUND */
  549. return NulChar;
  550. }
  551. extern char
  552. Char_to_TypeCode (char C)
  553. {
  554. /*
  555. Convert the dialect-specifc tail character into the internal TypeCode value.
  556. if successful then returns the internal TypeCode value
  557. otherwise returns NulChar.
  558. */
  559. if (C == NulChar || C == ' ')
  560. {
  561. return NulChar; /* never allowed */
  562. }
  563. /* dialect specific */
  564. if (C == My->CurrentVersion->OptionByteChar)
  565. {
  566. return ByteTypeCode;
  567. }
  568. if (C == My->CurrentVersion->OptionIntegerChar)
  569. {
  570. return IntegerTypeCode;
  571. }
  572. if (C == My->CurrentVersion->OptionLongChar)
  573. {
  574. return LongTypeCode;
  575. }
  576. if (C == My->CurrentVersion->OptionCurrencyChar)
  577. {
  578. return CurrencyTypeCode;
  579. }
  580. if (C == My->CurrentVersion->OptionSingleChar)
  581. {
  582. return SingleTypeCode;
  583. }
  584. if (C == My->CurrentVersion->OptionDoubleChar)
  585. {
  586. return DoubleTypeCode;
  587. }
  588. if (C == My->CurrentVersion->OptionStringChar)
  589. {
  590. return StringTypeCode;
  591. }
  592. /* NOT FOUND */
  593. return NulChar;
  594. }
  595. extern char
  596. var_nametype (char *name)
  597. {
  598. /*
  599. determine the internal TypeCode associated with the vaariable name.
  600. if successful then returns the internal TypeCode value
  601. otherwise returns NulChar.
  602. */
  603. assert (name != NULL);
  604. if (name == NULL)
  605. {
  606. WARN_INTERNAL_ERROR;
  607. return NulChar;
  608. }
  609. /* look only at the last charactr of the variable name */
  610. if (*name)
  611. {
  612. while (*name)
  613. {
  614. name++;
  615. }
  616. name--;
  617. }
  618. return Char_to_TypeCode (*name);
  619. }
  620. static char
  621. char_is_varhead (char C)
  622. {
  623. /*
  624. determine whether the character is allowed at the head of a variable name.
  625. if successful then returns TRUE
  626. otherwise retuns FALSE.
  627. */
  628. if (C == NulChar || C == ' ')
  629. {
  630. return NulChar;
  631. } /* never allowed */
  632. if (char_is_varfirst (C))
  633. {
  634. return C;
  635. }
  636. if (char_is_varnext (C))
  637. {
  638. return C;
  639. }
  640. return NulChar;
  641. }
  642. static int
  643. char_is_vartail (char C)
  644. {
  645. /*
  646. determine whether the character is allowed at the tail of a variable name.
  647. if successful then returns TRUE
  648. otherwise retuns FALSE.
  649. */
  650. if (C == NulChar || C == ' ')
  651. {
  652. return FALSE; /* never allowed */
  653. }
  654. if (char_is_varnext (C))
  655. {
  656. return TRUE;
  657. }
  658. if (Char_to_TypeCode (C))
  659. {
  660. return TRUE;
  661. }
  662. return FALSE;
  663. }
  664. #if FALSE /* kepp this ... */
  665. extern int
  666. buff_peek_word (char *buffer, int *position, char *find)
  667. {
  668. /*
  669. determine whether the next non-space word in 'buffer' is 'find';
  670. the word 'find' is not allowed to be a sub-string of a bigger word.
  671. if successful then returns TRUE
  672. otherwise returns FALSE.
  673. 'position' is unchanged.
  674. */
  675. int p;
  676. int n;
  677. assert (buffer != NULL);
  678. assert (position != NULL);
  679. assert (find != NULL);
  680. p = *position;
  681. buff_skip_spaces (buffer, &p); /* keep this */
  682. if (buff_is_eol (buffer, &p))
  683. {
  684. return FALSE;
  685. }
  686. n = bwb_strlen (find);
  687. if (bwb_strnicmp (&(buffer[p]), find, n) == 0)
  688. {
  689. if (p > 0)
  690. {
  691. if (char_is_varhead (buffer[p - 1]))
  692. {
  693. /* _TO */
  694. return FALSE;
  695. }
  696. }
  697. if (char_is_vartail (buffer[p + n]))
  698. {
  699. /* TO_ */
  700. return FALSE;
  701. }
  702. return TRUE;
  703. }
  704. return FALSE;
  705. }
  706. #endif
  707. #if FALSE /* keep this ... */
  708. extern int
  709. line_peek_word (LineType * line, char *find)
  710. {
  711. assert (line != NULL);
  712. assert (find != NULL);
  713. return buff_peek_word (line->buffer, &(line->position), find);
  714. }
  715. #endif
  716. extern int
  717. buff_skip_word (char *buffer, int *position, char *find)
  718. {
  719. /*
  720. skip the next non-space word in 'buffer' if it is 'find';
  721. the word 'find' is not a sub-string of a bigger word.
  722. if successful then 'position' is updated past 'find' and returns TRUE
  723. otherwise 'position' is unchanged and returns FALSE.
  724. */
  725. int p;
  726. int n;
  727. assert (buffer != NULL);
  728. assert (position != NULL);
  729. assert (find != NULL);
  730. p = *position;
  731. buff_skip_spaces (buffer, &p); /* keep this */
  732. if (buff_is_eol (buffer, &p))
  733. {
  734. return FALSE;
  735. }
  736. n = bwb_strlen (find);
  737. if (bwb_strnicmp (&(buffer[p]), find, n) == 0)
  738. {
  739. if (p > 0)
  740. {
  741. if (char_is_varhead (buffer[p - 1]))
  742. {
  743. /* _TO */
  744. return FALSE;
  745. }
  746. }
  747. if (char_is_vartail (buffer[p + n]))
  748. {
  749. /* TO_ */
  750. return FALSE;
  751. }
  752. p += n;
  753. *position = p;
  754. return TRUE;
  755. }
  756. return FALSE;
  757. }
  758. extern int
  759. line_skip_word (LineType * line, char *find)
  760. {
  761. assert (line != NULL);
  762. assert (find != NULL);
  763. return buff_skip_word (line->buffer, &(line->position), find);
  764. }
  765. extern int
  766. buff_read_varname (char *buffer, int *position, char *varname)
  767. {
  768. /*
  769. read the next non-space word in 'buffer' that conforms to a BASIC variable name into 'varname'.
  770. if successful then 'position' is updated past 'varname' and returns TRUE
  771. otherwise 'position' is unchanged ('varname' is truncated) and returns FALSE.
  772. 'varname' shall be declared "char varname[NameLengthMax + 1]".
  773. */
  774. int p;
  775. assert (buffer != NULL);
  776. assert (position != NULL);
  777. assert (varname != NULL);
  778. p = *position;
  779. buff_skip_spaces (buffer, &p); /* keep this */
  780. if (char_is_varfirst (buffer[p]))
  781. {
  782. int i;
  783. i = 0;
  784. if (i > NameLengthMax)
  785. {
  786. i = NameLengthMax;
  787. }
  788. varname[i] = buffer[p];
  789. p++;
  790. i++;
  791. while (char_is_varnext (buffer[p]))
  792. {
  793. if (i > NameLengthMax)
  794. {
  795. i = NameLengthMax;
  796. }
  797. varname[i] = buffer[p];
  798. p++;
  799. i++;
  800. }
  801. if (Char_to_TypeCode (buffer[p]))
  802. {
  803. if (i > NameLengthMax)
  804. {
  805. i = NameLengthMax;
  806. }
  807. varname[i] = buffer[p];
  808. p++;
  809. i++;
  810. }
  811. varname[i] = NulChar;
  812. *position = p;
  813. return TRUE;
  814. }
  815. varname[0] = NulChar;
  816. return FALSE;
  817. }
  818. extern int
  819. line_read_varname (LineType * line, char *varname)
  820. {
  821. assert (line != NULL);
  822. assert (varname != NULL);
  823. return buff_read_varname (line->buffer, &(line->position), varname);
  824. }
  825. extern int
  826. buff_read_label (char *buffer, int *position, char *label)
  827. {
  828. /*
  829. read the next non-space word in 'buffer' that conforms to a BASIC label name into 'label'.
  830. if successful then 'position' is updated past 'label' and returns TRUE
  831. otherwise 'position' is unchanged and returns FALSE.
  832. 'label' shall be declared "char label[NameLengthMax + 1]".
  833. */
  834. int p;
  835. assert (buffer != NULL);
  836. assert (position != NULL);
  837. assert (label != NULL);
  838. p = *position;
  839. buff_skip_spaces (buffer, &p); /* keep this */
  840. if (char_is_varfirst (buffer[p]))
  841. {
  842. int i;
  843. i = 0;
  844. if (i > NameLengthMax)
  845. {
  846. i = NameLengthMax;
  847. }
  848. label[i] = buffer[p];
  849. p++;
  850. i++;
  851. while (char_is_varnext (buffer[p]))
  852. {
  853. if (i > NameLengthMax)
  854. {
  855. i = NameLengthMax;
  856. }
  857. label[i] = buffer[p];
  858. p++;
  859. i++;
  860. }
  861. label[i] = NulChar;
  862. *position = p;
  863. return TRUE;
  864. }
  865. return FALSE;
  866. }
  867. extern int
  868. line_read_label (LineType * line, char *label)
  869. {
  870. assert (line != NULL);
  871. assert (label != NULL);
  872. return buff_read_label (line->buffer, &(line->position), label);
  873. }
  874. static int
  875. buff_read_keyword (char *buffer, int *position, char *keyword)
  876. {
  877. /*
  878. read the next non-space word in 'buffer' that conforms to a BASIC keyword into 'keyword'.
  879. if successful then 'position' is updated past 'keyword' and returns TRUE
  880. otherwise 'position' is unchanged and returns FALSE.
  881. 'label' shall be declared "char keyword[NameLengthMax + 1]".
  882. */
  883. int p;
  884. assert (buffer != NULL);
  885. assert (position != NULL);
  886. assert (keyword != NULL);
  887. p = *position;
  888. buff_skip_spaces (buffer, &p); /* keep this */
  889. if (char_is_varfirst (buffer[p]))
  890. {
  891. int i;
  892. i = 0;
  893. if (i > NameLengthMax)
  894. {
  895. i = NameLengthMax;
  896. }
  897. keyword[i] = buffer[p];
  898. p++;
  899. i++;
  900. while (char_is_varnext (buffer[p]))
  901. {
  902. if (i > NameLengthMax)
  903. {
  904. i = NameLengthMax;
  905. }
  906. keyword[i] = buffer[p];
  907. p++;
  908. i++;
  909. }
  910. if (Char_to_TypeCode (buffer[p]) == StringTypeCode)
  911. {
  912. if (i > NameLengthMax)
  913. {
  914. i = NameLengthMax;
  915. }
  916. keyword[i] = buffer[p];
  917. p++;
  918. i++;
  919. }
  920. keyword[i] = NulChar;
  921. *position = p;
  922. return TRUE;
  923. }
  924. keyword[0] = NulChar;
  925. return FALSE;
  926. }
  927. static int
  928. line_read_keyword (LineType * line, char *keyword)
  929. {
  930. assert (line != NULL);
  931. assert (keyword != NULL);
  932. return buff_read_keyword (line->buffer, &(line->position), keyword);
  933. }
  934. extern VariableType *
  935. buff_read_scalar (char *buffer, int *position)
  936. {
  937. /*
  938. read the next non-space word in 'buffer' that conforms to a BASIC variable name,
  939. including both scalar variables and subscripted array variables.
  940. if successful then 'position' is updated
  941. past 'varname' for scalar variables
  942. (past right parenthesis for subscripted array variables).
  943. and returns a pointer to the variable.
  944. otherwise 'position' is unchanged and returns NULL.
  945. */
  946. int p;
  947. VariableType *v;
  948. char varname[NameLengthMax + 1];
  949. assert (buffer != NULL);
  950. assert (position != NULL);
  951. p = *position;
  952. /* Read a variable name */
  953. buff_skip_spaces (buffer, &p); /* keep this */
  954. if (buff_read_varname (buffer, &p, varname) == FALSE)
  955. {
  956. WARN_VARIABLE_NOT_DECLARED;
  957. return NULL;
  958. }
  959. if (buff_peek_LparenChar (buffer, &p))
  960. {
  961. /* MUST be a an array */
  962. int n;
  963. int n_params; /* number of parameters */
  964. int pp[MAX_DIMS];
  965. /* get parameters because the variable is dimensioned */
  966. if (buff_read_array_dimensions (buffer, &p, &n_params, pp) == FALSE)
  967. {
  968. WARN_SUBSCRIPT_OUT_OF_RANGE;
  969. return NULL;
  970. }
  971. /* get the array variable */
  972. if ((v = var_find (varname, n_params, TRUE)) == NULL)
  973. {
  974. WARN_VARIABLE_NOT_DECLARED;
  975. return NULL;
  976. }
  977. for (n = 0; n < v->dimensions; n++)
  978. {
  979. v->VINDEX[n] = pp[n];
  980. }
  981. }
  982. else
  983. {
  984. /* simple scalar variable */
  985. if ((v = var_find (varname, 0, TRUE)) == NULL)
  986. {
  987. WARN_VARIABLE_NOT_DECLARED;
  988. return NULL;
  989. }
  990. }
  991. *position = p;
  992. return v;
  993. }
  994. extern VariableType *
  995. line_read_scalar (LineType * line)
  996. {
  997. assert (line != NULL);
  998. return buff_read_scalar (line->buffer, &(line->position));
  999. }
  1000. extern VariableType *
  1001. buff_read_matrix (char *buffer, int *position)
  1002. {
  1003. /*
  1004. read the next non-space word in 'buffer' that conforms to a BASIC matrix name,
  1005. including both simple matrix variables and redimensioned matrix variables.
  1006. if successful then 'position' is updated
  1007. past 'varname' for matrix variables
  1008. (past right parenthesis for redimensioned matrix variables).
  1009. and returns a pointer to the variable.
  1010. otherwise 'position' is unchanged and returns NULL.
  1011. */
  1012. int p;
  1013. VariableType *v;
  1014. char varname[NameLengthMax + 1];
  1015. assert (buffer != NULL);
  1016. assert (position != NULL);
  1017. p = *position;
  1018. /* Read a variable name */
  1019. buff_skip_spaces (buffer, &p); /* keep this */
  1020. if (buff_read_varname (buffer, &p, varname) == FALSE)
  1021. {
  1022. WARN_SYNTAX_ERROR;
  1023. return NULL;
  1024. }
  1025. v = mat_find (varname);
  1026. if (v == NULL)
  1027. {
  1028. WARN_VARIABLE_NOT_DECLARED;
  1029. return NULL;
  1030. }
  1031. if (buff_peek_LparenChar (buffer, &p))
  1032. {
  1033. /* get requested matrix size, which is <= original matrix size */
  1034. size_t array_units;
  1035. int n;
  1036. int dimensions;
  1037. int LBOUND[MAX_DIMS];
  1038. int UBOUND[MAX_DIMS];
  1039. if (buff_read_array_redim (buffer, &p, &dimensions, LBOUND, UBOUND) ==
  1040. FALSE)
  1041. {
  1042. WARN_SYNTAX_ERROR;
  1043. return NULL;
  1044. }
  1045. /* update array dimensions */
  1046. array_units = 1;
  1047. for (n = 0; n < dimensions; n++)
  1048. {
  1049. if (UBOUND[n] < LBOUND[n])
  1050. {
  1051. WARN_SUBSCRIPT_OUT_OF_RANGE;
  1052. return FALSE;
  1053. }
  1054. array_units *= UBOUND[n] - LBOUND[n] + 1;
  1055. }
  1056. if (array_units > v->array_units)
  1057. {
  1058. WARN_SUBSCRIPT_OUT_OF_RANGE;
  1059. return FALSE;
  1060. }
  1061. v->dimensions = dimensions;
  1062. for (n = 0; n < dimensions; n++)
  1063. {
  1064. v->LBOUND[n] = LBOUND[n];
  1065. v->UBOUND[n] = UBOUND[n];
  1066. }
  1067. }
  1068. *position = p;
  1069. return v;
  1070. }
  1071. extern VariableType *
  1072. line_read_matrix (LineType * line)
  1073. {
  1074. assert (line != NULL);
  1075. return buff_read_matrix (line->buffer, &(line->position));
  1076. }
  1077. extern int
  1078. buff_read_line_number (char *buffer, int *position, int *linenum)
  1079. {
  1080. /*
  1081. read the next non-space word in 'buffer' that conforms to a BASIC line number.
  1082. if successful then 'position' is updated past 'linenum' and returns TRUE
  1083. otherwise 'position' is unchanged and returns FALSE.
  1084. */
  1085. int p;
  1086. assert (buffer != NULL);
  1087. assert (position != NULL);
  1088. assert (linenum != NULL);
  1089. p = *position;
  1090. buff_skip_spaces (buffer, &p); /* keep this */
  1091. if (bwb_isdigit (buffer[p]))
  1092. {
  1093. int i;
  1094. int n;
  1095. char label[NameLengthMax + 1];
  1096. i = 0;
  1097. while (bwb_isdigit (buffer[p]))
  1098. {
  1099. if (i > NameLengthMax)
  1100. {
  1101. i = NameLengthMax;
  1102. }
  1103. label[i] = buffer[p];
  1104. p++;
  1105. i++;
  1106. }
  1107. label[i] = NulChar;
  1108. n = atoi (label);
  1109. *linenum = n;
  1110. *position = p;
  1111. return TRUE;
  1112. }
  1113. return FALSE;
  1114. }
  1115. extern int
  1116. line_read_line_number (LineType * line, int *linenum)
  1117. {
  1118. assert (line != NULL);
  1119. assert (linenum != NULL);
  1120. return buff_read_line_number (line->buffer, &(line->position), linenum);
  1121. }
  1122. extern int
  1123. buff_read_line_sequence (char *buffer, int *position, int *head, int *tail)
  1124. {
  1125. /*
  1126. read the next non-space words in 'buffer' that conforms to a BASIC line number sequnence.
  1127. if successful then 'position' is updated past the line number sequence and returns TRUE
  1128. otherwise 'position' is unchanged and returns FALSE.
  1129. */
  1130. /*
  1131. ### head == tail
  1132. ### - head to BMAX
  1133. ### - ### head to tail
  1134. - ### BMIN to tail
  1135. */
  1136. int p; /* position */
  1137. int h; /* head */
  1138. int t; /* tail */
  1139. char c; /* line range seperator for BREAK, DELETE and LIST */
  1140. assert (buffer != NULL);
  1141. assert (position != NULL);
  1142. assert (head != NULL);
  1143. assert (tail != NULL);
  1144. p = *position;
  1145. buff_skip_spaces (buffer, &p); /* keep this */
  1146. c = '-';
  1147. if (My->CurrentVersion->OptionVersionValue & (D70 | H80))
  1148. {
  1149. c = ',';
  1150. }
  1151. if (buff_skip_char (buffer, &p, c) /* line sequence seperator */ )
  1152. {
  1153. /* - ... */
  1154. if (buff_read_line_number (buffer, &p, &t))
  1155. {
  1156. /* - ### */
  1157. *head = MINLIN;
  1158. *tail = t;
  1159. *position = p;
  1160. return TRUE;
  1161. }
  1162. }
  1163. else
  1164. if (buff_read_line_number (buffer, &p, &h) /* line sequence seperator */ )
  1165. {
  1166. /* ### ... */
  1167. if (buff_skip_char (buffer, &p, c))
  1168. {
  1169. /* ### - ... */
  1170. if (buff_read_line_number (buffer, &p, &t))
  1171. {
  1172. /* ### - ### */
  1173. *head = h;
  1174. *tail = t;
  1175. *position = p;
  1176. return TRUE;
  1177. }
  1178. else
  1179. {
  1180. /* ### - */
  1181. *head = h;
  1182. *tail = MAXLIN;
  1183. *position = p;
  1184. return TRUE;
  1185. }
  1186. }
  1187. else
  1188. {
  1189. /* ### */
  1190. *head = h;
  1191. *tail = h;
  1192. *position = p;
  1193. return TRUE;
  1194. }
  1195. }
  1196. return FALSE;
  1197. }
  1198. extern int
  1199. line_read_line_sequence (LineType * line, int *head, int *tail)
  1200. {
  1201. assert (line != NULL);
  1202. assert (head != NULL);
  1203. assert (tail != NULL);
  1204. return buff_read_line_sequence (line->buffer, &(line->position), head,
  1205. tail);
  1206. }
  1207. extern int
  1208. buff_read_integer_expression (char *buffer, int *position, int *Value)
  1209. {
  1210. /*
  1211. read the next non-space words in 'buffer' that conforms to a BASIC integer expression into 'Value'.
  1212. if successful then 'position' is updated past 'Value' and returns TRUE
  1213. otherwise 'position' is unchanged and returns FALSE.
  1214. 'Value' shall be declared "int Value".
  1215. */
  1216. DoubleType X;
  1217. int p;
  1218. assert (buffer != NULL);
  1219. assert (position != NULL);
  1220. assert (Value != NULL);
  1221. p = *position;
  1222. buff_skip_spaces (buffer, &p); /* keep this */
  1223. if (buff_read_numeric_expression (buffer, &p, &X))
  1224. {
  1225. /* we want the rounded value */
  1226. X = bwb_rint (X);
  1227. if (INT_MIN <= X && X <= INT_MAX)
  1228. {
  1229. /* OK */
  1230. *Value = (int) bwb_rint (X);
  1231. *position = p;
  1232. return TRUE;
  1233. }
  1234. }
  1235. /* ERROR */
  1236. return FALSE;
  1237. }
  1238. extern int
  1239. line_read_integer_expression (LineType * line, int *Value)
  1240. {
  1241. assert (line != NULL);
  1242. assert (Value != NULL);
  1243. return buff_read_integer_expression (line->buffer, &(line->position),
  1244. Value);
  1245. }
  1246. extern int
  1247. buff_read_numeric_expression (char *buffer, int *position, DoubleType * Value)
  1248. {
  1249. /*
  1250. read the next non-space words in 'buffer' that conforms to a BASIC numeric expression into 'Value'.
  1251. if successful then 'position' is updated past 'Value' and returns TRUE
  1252. otherwise 'position' is unchanged and returns FALSE.
  1253. 'Value' shall be declared "DoubleType Value".
  1254. */
  1255. int p;
  1256. VariantType x;
  1257. VariantType *X;
  1258. assert (buffer != NULL);
  1259. assert (position != NULL);
  1260. assert (Value != NULL);
  1261. X = &x;
  1262. p = *position;
  1263. CLEAR_VARIANT (X);
  1264. buff_skip_spaces (buffer, &p); /* keep this */
  1265. if (buff_read_expression (buffer, &p, X) == FALSE) /* buff_read_numeric_expression */
  1266. {
  1267. return FALSE;
  1268. }
  1269. if (X->VariantTypeCode != StringTypeCode)
  1270. {
  1271. /* OK */
  1272. *Value = X->Number;
  1273. *position = p;
  1274. return TRUE;
  1275. }
  1276. RELEASE_VARIANT (X);
  1277. return FALSE;
  1278. }
  1279. extern int
  1280. line_read_numeric_expression (LineType * line, DoubleType * Value)
  1281. {
  1282. assert (line != NULL);
  1283. assert (Value != NULL);
  1284. return buff_read_numeric_expression (line->buffer, &(line->position),
  1285. Value);
  1286. }
  1287. extern int
  1288. buff_read_string_expression (char *buffer, int *position, char **Value)
  1289. {
  1290. /*
  1291. read the next non-space words in 'buffer' that conforms to a BASIC string expression into 'Value'.
  1292. if successful then 'position' is updated past 'Value' and returns TRUE
  1293. otherwise 'position' is unchanged and returns FALSE.
  1294. 'Value' shall be declared "char * Value = NULL".
  1295. */
  1296. int p;
  1297. VariantType x;
  1298. VariantType *X;
  1299. assert (buffer != NULL);
  1300. assert (position != NULL);
  1301. assert (Value != NULL);
  1302. X = &x;
  1303. p = *position;
  1304. CLEAR_VARIANT (X);
  1305. buff_skip_spaces (buffer, &p); /* keep this */
  1306. if (buff_read_expression (buffer, &p, X) == FALSE) /* buff_read_string_expression */
  1307. {
  1308. return FALSE;
  1309. }
  1310. if (X->VariantTypeCode == StringTypeCode)
  1311. {
  1312. /* OK */
  1313. X->Buffer[X->Length] = NulChar;
  1314. *Value = X->Buffer;
  1315. *position = p;
  1316. return TRUE;
  1317. /* the caller is responsible to free() the returned pointer */
  1318. }
  1319. return FALSE;
  1320. }
  1321. extern int
  1322. line_read_string_expression (LineType * line, char **Value)
  1323. {
  1324. assert (line != NULL);
  1325. assert (Value != NULL);
  1326. return buff_read_string_expression (line->buffer, &(line->position), Value);
  1327. }
  1328. extern int
  1329. buff_read_index_item (char *buffer, int *position, int Index, int *Value)
  1330. {
  1331. /*
  1332. read the next non-space words in 'buffer' that conforms to a BASIC integer expression list into 'Value',
  1333. selecting the item matching 'Index'. The first 'Index' value is one;
  1334. if successful then 'position' is updated past 'Value' and returns TRUE
  1335. otherwise 'position' is unchanged and returns FALSE.
  1336. 'Value' shall be declared "int Value".
  1337. */
  1338. int p;
  1339. int i;
  1340. assert (buffer != NULL);
  1341. assert (position != NULL);
  1342. assert (Value != NULL);
  1343. p = *position;
  1344. buff_skip_spaces (buffer, &p); /* keep this */
  1345. if (buff_is_eol (buffer, &p))
  1346. {
  1347. return FALSE;
  1348. }
  1349. if (Index < 1)
  1350. {
  1351. return FALSE;
  1352. }
  1353. /* Index >= 1 */
  1354. i = 0;
  1355. do
  1356. {
  1357. int v;
  1358. if (buff_read_integer_expression (buffer, &p, &v))
  1359. {
  1360. i++;
  1361. if (i == Index)
  1362. {
  1363. *Value = v;
  1364. *position = p;
  1365. return TRUE;
  1366. }
  1367. }
  1368. else
  1369. {
  1370. return FALSE;
  1371. }
  1372. }
  1373. while (buff_skip_seperator (buffer, &p));
  1374. return FALSE;
  1375. }
  1376. extern int
  1377. line_read_index_item (LineType * line, int Index, int *Value)
  1378. {
  1379. assert (line != NULL);
  1380. assert (Value != NULL);
  1381. return buff_read_index_item (line->buffer, &(line->position), Index, Value);
  1382. }
  1383. extern int
  1384. buff_read_letter_sequence (char *buffer, int *position, char *head,
  1385. char *tail)
  1386. {
  1387. /*
  1388. read the next non-space alphabetic character in 'buffer' into 'start';
  1389. if seperated by a hyphen ('-') then read the next non-space alphabetic character into 'end'.
  1390. if successful then 'position' is updated past 'start' (or 'end') and returns TRUE
  1391. otherwise 'position' is unchanged and returns FALSE.
  1392. */
  1393. int p;
  1394. char h;
  1395. char t;
  1396. assert (buffer != NULL);
  1397. assert (position != NULL);
  1398. assert (head != NULL);
  1399. assert (tail != NULL);
  1400. p = *position;
  1401. buff_skip_spaces (buffer, &p); /* keep this */
  1402. if (bwb_isalpha (buffer[p]) == FALSE)
  1403. {
  1404. /* character at this position must be a letter */
  1405. return FALSE;
  1406. }
  1407. h = buffer[p];
  1408. p++;
  1409. /* check for hyphen, indicating sequence of more than one letter */
  1410. if (buff_skip_MinusChar (buffer, &p))
  1411. {
  1412. buff_skip_spaces (buffer, &p); /* keep this */
  1413. if (bwb_isalpha (buffer[p]) == FALSE)
  1414. {
  1415. /* character at this position must be a letter */
  1416. return FALSE;
  1417. }
  1418. t = buffer[p];
  1419. p++;
  1420. }
  1421. else
  1422. {
  1423. t = h;
  1424. }
  1425. *head = h;
  1426. *tail = t;
  1427. *position = p;
  1428. return TRUE;
  1429. }
  1430. extern int
  1431. line_read_letter_sequence (LineType * line, char *head, char *tail)
  1432. {
  1433. assert (line != NULL);
  1434. assert (head != NULL);
  1435. assert (tail != NULL);
  1436. return buff_read_letter_sequence (line->buffer, &(line->position), head,
  1437. tail);
  1438. }
  1439. extern int
  1440. buff_read_array_dimensions (char *buffer, int *position, int *n_params,
  1441. int params[ /* MAX_DIMS */ ])
  1442. {
  1443. /*
  1444. read the next non-space words in 'buffer' that conform to BASIC array index values;
  1445. if successful then 'position' is updated past the right parenthesis and returns TRUE
  1446. otherwise 'position' is unchanged and returns FALSE.
  1447. */
  1448. int p;
  1449. int n;
  1450. assert (buffer != NULL);
  1451. assert (position != NULL);
  1452. assert (n_params != NULL);
  1453. assert (params != NULL);
  1454. p = *position;
  1455. n = 0;
  1456. buff_skip_spaces (buffer, &p); /* keep this */
  1457. if (buff_skip_LparenChar (buffer, &p))
  1458. {
  1459. /* matrix */
  1460. do
  1461. {
  1462. int Value;
  1463. if (n >= MAX_DIMS)
  1464. {
  1465. /* ERROR */
  1466. return FALSE;
  1467. }
  1468. /* OK */
  1469. if (buff_read_integer_expression (buffer, &p, &Value) == FALSE)
  1470. {
  1471. /* ERROR */
  1472. return FALSE;
  1473. }
  1474. /* OK */
  1475. params[n] = Value;
  1476. n++;
  1477. }
  1478. while (buff_skip_seperator (buffer, &p));
  1479. if (buff_skip_RparenChar (buffer, &p) == FALSE)
  1480. {
  1481. /* ERROR */
  1482. return FALSE;
  1483. }
  1484. }
  1485. else
  1486. {
  1487. /* scalar */
  1488. n = 0;
  1489. }
  1490. *n_params = n;
  1491. *position = p;
  1492. return TRUE;
  1493. }
  1494. #if FALSE /* keep this ... */
  1495. extern int
  1496. line_read_array_dimensions (LineType * line, int *n_params,
  1497. int params[ /* MAX_DIMS */ ])
  1498. {
  1499. assert (line != NULL);
  1500. assert (n_params != NULL);
  1501. assert (params != NULL);
  1502. return buff_read_array_dimensions (line->buffer, &(line->position),
  1503. n_params, params);
  1504. }
  1505. #endif
  1506. extern int
  1507. buff_read_array_redim (char *buffer, int *position, int *dimensions,
  1508. int LBOUND[ /* MAX_DIMS */ ],
  1509. int UBOUND[ /* MAX_DIMS */ ])
  1510. {
  1511. /*
  1512. read the next non-space words in 'buffer' that conform to BASIC array index values;
  1513. if successful then 'position' is updated past the right parenthesis and returns TRUE
  1514. otherwise 'position' is unchanged and returns FALSE.
  1515. */
  1516. int p;
  1517. int n;
  1518. assert (buffer != NULL);
  1519. assert (position != NULL);
  1520. assert (dimensions != NULL);
  1521. assert (LBOUND != NULL);
  1522. assert (UBOUND != NULL);
  1523. p = *position;
  1524. n = 0;
  1525. buff_skip_spaces (buffer, &p); /* keep this */
  1526. if (buff_skip_LparenChar (buffer, &p))
  1527. {
  1528. /* matrix */
  1529. do
  1530. {
  1531. int Value;
  1532. if (n >= MAX_DIMS)
  1533. {
  1534. /* ERROR */
  1535. return FALSE;
  1536. }
  1537. /* OK */
  1538. if (buff_read_integer_expression (buffer, &p, &Value) == FALSE)
  1539. {
  1540. /* ERROR */
  1541. return FALSE;
  1542. }
  1543. /* OK */
  1544. if (buff_skip_word (buffer, &p, "TO") == TRUE)
  1545. {
  1546. LBOUND[n] = Value; /* explicit lower bound */
  1547. if (buff_read_integer_expression (buffer, &p, &Value) == FALSE)
  1548. {
  1549. /* ERROR */
  1550. return FALSE;
  1551. }
  1552. /* OK */
  1553. UBOUND[n] = Value; /* explicit upper bound */
  1554. }
  1555. else
  1556. {
  1557. LBOUND[n] = My->CurrentVersion->OptionBaseInteger; /* implicit lower bound */
  1558. UBOUND[n] = Value; /* explicit upper bound */
  1559. }
  1560. n++;
  1561. }
  1562. while (buff_skip_seperator (buffer, &p));
  1563. if (buff_skip_RparenChar (buffer, &p) == FALSE)
  1564. {
  1565. /* ERROR */
  1566. return FALSE;
  1567. }
  1568. }
  1569. else
  1570. {
  1571. /* scalar */
  1572. n = 0;
  1573. }
  1574. *dimensions = n;
  1575. *position = p;
  1576. return TRUE;
  1577. }
  1578. extern int
  1579. line_read_array_redim (LineType * line, int *dimensions,
  1580. int LBOUND[ /* MAX_DIMS */ ],
  1581. int UBOUND[ /* MAX_DIMS */ ])
  1582. {
  1583. assert (line != NULL);
  1584. assert (dimensions != NULL);
  1585. assert (LBOUND != NULL);
  1586. assert (UBOUND != NULL);
  1587. return buff_read_array_redim (line->buffer, &(line->position), dimensions,
  1588. LBOUND, UBOUND);
  1589. }
  1590. extern int
  1591. buff_peek_array_dimensions (char *buffer, int *position, int *n_params)
  1592. {
  1593. /*
  1594. peek the next non-space words in 'buffer' that conform to BASIC array index values;
  1595. if successful then 'n_params' is updated and returns TRUE
  1596. otherwise 'n_params' is unchanged and returns FALSE.
  1597. 'position' is always unchanged.
  1598. */
  1599. int p;
  1600. int ParenLevel;
  1601. int NumDimensions;
  1602. assert (buffer != NULL);
  1603. assert (position != NULL);
  1604. assert (n_params != NULL);
  1605. ParenLevel = 0;
  1606. NumDimensions = 1;
  1607. p = *position;
  1608. buff_skip_spaces (buffer, &p); /* keep this */
  1609. while (buffer[p])
  1610. {
  1611. /* check the current character */
  1612. buff_skip_spaces (buffer, &p); /* keep this */
  1613. if (buff_skip_LparenChar (buffer, &p))
  1614. {
  1615. ParenLevel++;
  1616. }
  1617. else if (buff_skip_RparenChar (buffer, &p))
  1618. {
  1619. ParenLevel--;
  1620. if (ParenLevel < 0)
  1621. {
  1622. return FALSE;
  1623. }
  1624. if (ParenLevel == 0)
  1625. {
  1626. *n_params = NumDimensions;
  1627. return TRUE;
  1628. }
  1629. }
  1630. else if (buff_skip_seperator (buffer, &p))
  1631. {
  1632. if (ParenLevel == 1)
  1633. {
  1634. NumDimensions++;
  1635. }
  1636. }
  1637. else if (buffer[p] == My->CurrentVersion->OptionQuoteChar)
  1638. {
  1639. /* embedded string constant */
  1640. p++;
  1641. while ((buffer[p] != My->CurrentVersion->OptionQuoteChar)
  1642. && (buffer[p] != NulChar))
  1643. {
  1644. p++;
  1645. }
  1646. if (buffer[p] == My->CurrentVersion->OptionQuoteChar)
  1647. {
  1648. p++;
  1649. }
  1650. }
  1651. else
  1652. {
  1653. /* normal character */
  1654. p++;
  1655. }
  1656. }
  1657. return FALSE;
  1658. }
  1659. #if FALSE /* keep this ... */
  1660. extern int
  1661. line_peek_array_dimensions (LineType * line, int *n_params)
  1662. {
  1663. assert (line != NULL);
  1664. assert (n_params != NULL);
  1665. return buff_peek_array_dimensions (line->buffer, &(line->position),
  1666. n_params);
  1667. }
  1668. #endif
  1669. extern char
  1670. buff_read_type_declaration (char *buffer, int *position)
  1671. {
  1672. /*
  1673. skip the next non-space words in 'buffer' if it is a BASIC type declaration.
  1674. if successful then 'position' is updated past the BASIC type declaration and returns the TypeCode
  1675. otherwise 'position' is unchanged and returns NulChar.
  1676. */
  1677. int p;
  1678. char TypeCode;
  1679. assert (buffer != NULL);
  1680. assert (position != NULL);
  1681. p = *position;
  1682. TypeCode = NulChar;
  1683. buff_skip_spaces (buffer, &p); /* keep this */
  1684. if (buff_is_eol (buffer, &p))
  1685. {
  1686. return TypeCode;
  1687. }
  1688. if (buff_skip_word (buffer, &p, "AS") == TRUE)
  1689. {
  1690. /* AS ... */
  1691. if (buff_skip_word (buffer, &p, "BYTE"))
  1692. {
  1693. /* AS BYTE */
  1694. TypeCode = ByteTypeCode;
  1695. }
  1696. else if (buff_skip_word (buffer, &p, "INTEGER"))
  1697. {
  1698. /* AS INTEGER */
  1699. TypeCode = IntegerTypeCode;
  1700. }
  1701. else if (buff_skip_word (buffer, &p, "LONG"))
  1702. {
  1703. /* AS LONG */
  1704. TypeCode = LongTypeCode;
  1705. }
  1706. else if (buff_skip_word (buffer, &p, "CURRENCY"))
  1707. {
  1708. /* AS CURRENCY */
  1709. TypeCode = CurrencyTypeCode;
  1710. }
  1711. else if (buff_skip_word (buffer, &p, "SINGLE"))
  1712. {
  1713. /* AS SINGLE */
  1714. TypeCode = SingleTypeCode;
  1715. }
  1716. else if (buff_skip_word (buffer, &p, "DOUBLE"))
  1717. {
  1718. /* AS DOUBLE */
  1719. TypeCode = DoubleTypeCode;
  1720. }
  1721. else if (buff_skip_word (buffer, &p, "STRING"))
  1722. {
  1723. /* AS STRING */
  1724. TypeCode = StringTypeCode;
  1725. }
  1726. else
  1727. {
  1728. /* invalid type */
  1729. }
  1730. }
  1731. if (TypeCode)
  1732. {
  1733. /* success */
  1734. *position = p;
  1735. }
  1736. return TypeCode;
  1737. }
  1738. extern char
  1739. line_read_type_declaration (LineType * line)
  1740. {
  1741. assert (line != NULL);
  1742. return buff_read_type_declaration (line->buffer, &(line->position));
  1743. }
  1744. /***************************************************************
  1745. FUNCTION: line_start()
  1746. DESCRIPTION: This function reads a line buffer in
  1747. <buffer> beginning at the position
  1748. <pos> and attempts to determine (a)
  1749. the position of the line number in the
  1750. buffer (returned in <lnpos>), (b) the
  1751. line number at this position (returned
  1752. in <lnum>), (c) the position of the
  1753. BASIC command in the buffer (returned
  1754. in <cmdpos>), (d) the position of this
  1755. BASIC command in the command table
  1756. (returned in <cmdnum>), and (e) the
  1757. position of the beginning of the rest
  1758. of the line (returned in <Startpos>).
  1759. Although <Startpos> must be returned
  1760. as a positive integer, the other
  1761. searches may fail, in which case FALSE
  1762. will be returned in their positions.
  1763. <pos> is not incremented.
  1764. ***************************************************************/
  1765. static void
  1766. internal_DEF8SUB (LineType * l)
  1767. {
  1768. /*
  1769. **
  1770. ** User is executing a function as though it were a command, such as 100 COS X.
  1771. ** This applies to both intrinsic functions and user defined functions and subroutines.
  1772. ** No special parsing is required, just insert "CALL" before the name and
  1773. ** add parentheses around the parameters:
  1774. ** 100 fna 1,2,3 -->> 100 CALL fna(1,2,3)
  1775. **
  1776. */
  1777. const char *A = "CALL ";
  1778. int a;
  1779. int n;
  1780. char *buffer;
  1781. assert (l != NULL);
  1782. a = bwb_strlen (A);
  1783. n = bwb_strlen (l->buffer) + a /* "CALL " */ + 1 /* '(' */ + 1 /* ')' */ ;
  1784. buffer = calloc (n + 1 /* NulChar */ , sizeof (char));
  1785. if (buffer == NULL)
  1786. {
  1787. WARN_OUT_OF_MEMORY;
  1788. return;
  1789. }
  1790. bwb_strcpy (buffer, A);
  1791. /* buffer == "CALL " */
  1792. l->position = 0;
  1793. if (line_read_varname (l, &(buffer[a])) == FALSE)
  1794. {
  1795. WARN_SYNTAX_ERROR;
  1796. return;
  1797. }
  1798. /* buffer == "CALL name" */
  1799. line_skip_spaces (l);
  1800. if (line_is_eol (l))
  1801. {
  1802. /* buffer == "CALL name" */
  1803. }
  1804. else
  1805. {
  1806. /* buffer == "CALL name" */
  1807. bwb_strcat (buffer, "(");
  1808. /* buffer == "CALL name(" */
  1809. bwb_strcat (buffer, &(l->buffer[l->position]));
  1810. /* buffer == "CALL name(...parameters..." */
  1811. bwb_strcat (buffer, ")");
  1812. /* buffer == "CALL name(...parameters...)" */
  1813. }
  1814. /*
  1815. printf("%s\n", buffer );
  1816. */
  1817. free (l->buffer);
  1818. l->buffer = buffer;
  1819. l->position = a;
  1820. l->Startpos = a;
  1821. l->cmdnum = C_CALL;
  1822. }
  1823. extern void
  1824. line_start (LineType * l)
  1825. {
  1826. char tbuf[NameLengthMax + 1];
  1827. assert (l != NULL);
  1828. /* set initial values */
  1829. l->cmdnum = 0; /* NOT FOUND */
  1830. l->Startpos = 0;
  1831. l->position = 0;
  1832. line_skip_spaces (l); /* keep this */
  1833. /* handle special cases */
  1834. if (line_is_eol (l))
  1835. {
  1836. /* the NUL (0) char must be handled first */
  1837. l->cmdnum = C_REM;
  1838. return;
  1839. }
  1840. if (line_skip_char (l, My->CurrentVersion->OptionCommentChar))
  1841. {
  1842. line_skip_eol (l);
  1843. l->Startpos = l->position;
  1844. l->cmdnum = C_REM;
  1845. return;
  1846. }
  1847. if (line_skip_char (l, My->CurrentVersion->OptionPrintChar))
  1848. {
  1849. line_skip_spaces (l); /* keep this */
  1850. l->Startpos = l->position;
  1851. l->cmdnum = C_PRINT;
  1852. return;
  1853. }
  1854. if (line_skip_char (l, My->CurrentVersion->OptionInputChar))
  1855. {
  1856. line_skip_spaces (l); /* keep this */
  1857. l->Startpos = l->position;
  1858. l->cmdnum = C_INPUT;
  1859. return;
  1860. }
  1861. if (line_skip_char (l, My->CurrentVersion->OptionImageChar))
  1862. {
  1863. line_skip_spaces (l); /* keep this */
  1864. l->Startpos = l->position;
  1865. l->cmdnum = C_IMAGE;
  1866. return;
  1867. }
  1868. if (bwb_strnicmp (&l->buffer[l->position], "REM", 3) == 0)
  1869. {
  1870. line_skip_eol (l);
  1871. l->Startpos = l->position;
  1872. l->cmdnum = C_REM;
  1873. return;
  1874. }
  1875. /* not a SPECIAL */
  1876. /* get the first keyword */
  1877. if (line_read_keyword (l, tbuf) == FALSE)
  1878. {
  1879. /* ERROR */
  1880. return;
  1881. }
  1882. line_skip_spaces (l); /* keep this */
  1883. /*
  1884. **
  1885. ** check for COMMAND
  1886. **
  1887. */
  1888. l->cmdnum = is_cmd (tbuf);
  1889. if (l->cmdnum)
  1890. {
  1891. /*
  1892. **
  1893. ** NOTE: This is NOT a full parser, this exists only to
  1894. ** handle STRUCTURED commands. It is true that we also handle
  1895. ** some other easy cases, but remember that this only exists
  1896. ** to support STRUCTURED commands. Whether any other commands
  1897. ** get processed here is simply because it was easy to do so.
  1898. **
  1899. */
  1900. int cmdnum;
  1901. char *xbuf;
  1902. int xlen;
  1903. cmdnum = 0;
  1904. xbuf = My->ConsoleInput;
  1905. xlen = MAX_LINE_LENGTH;
  1906. bwb_strcpy (xbuf, tbuf);
  1907. do
  1908. {
  1909. cmdnum = 0;
  1910. l->Startpos = l->position;
  1911. if (line_read_keyword (l, tbuf))
  1912. {
  1913. int n;
  1914. n = bwb_strlen (xbuf) + 1 /* SpaceChar */ + bwb_strlen (tbuf);
  1915. if (n < xlen)
  1916. {
  1917. /* not too long */
  1918. bwb_strcat (xbuf, " ");
  1919. bwb_strcat (xbuf, tbuf);
  1920. cmdnum = is_cmd (xbuf);
  1921. if (cmdnum)
  1922. {
  1923. /* longer command is valid */
  1924. line_skip_spaces (l); /* keep this */
  1925. l->Startpos = l->position;
  1926. l->cmdnum = cmdnum;
  1927. }
  1928. }
  1929. }
  1930. }
  1931. while (cmdnum);
  1932. /*
  1933. **
  1934. ** process special cases here
  1935. **
  1936. */
  1937. l->position = l->Startpos;
  1938. switch (l->cmdnum)
  1939. {
  1940. case C_CLOAD:
  1941. {
  1942. if (line_skip_StarChar (l))
  1943. {
  1944. /*
  1945. **
  1946. ** CLOAD*
  1947. **
  1948. */
  1949. line_skip_spaces (l); /* keep this */
  1950. l->Startpos = l->position;
  1951. l->cmdnum = C_CLOAD8;
  1952. }
  1953. }
  1954. break;
  1955. case C_CSAVE:
  1956. {
  1957. if (line_skip_StarChar (l))
  1958. {
  1959. /*
  1960. **
  1961. ** CSAVE*
  1962. **
  1963. */
  1964. line_skip_spaces (l); /* keep this */
  1965. l->Startpos = l->position;
  1966. l->cmdnum = C_CSAVE8;
  1967. }
  1968. }
  1969. break;
  1970. case C_DEF:
  1971. if (bwb_strchr (l->buffer, '=') == NULL)
  1972. {
  1973. /*
  1974. **
  1975. ** multi-line DEF ... FNEND
  1976. **
  1977. */
  1978. l->cmdnum = C_FUNCTION;
  1979. }
  1980. /*
  1981. **
  1982. ** we look up declared USER functions as we load
  1983. **
  1984. */
  1985. UserFunction_add (l);
  1986. break;
  1987. case C_FEND:
  1988. /*
  1989. **
  1990. ** this makes bwb_scan() simpler
  1991. **
  1992. */
  1993. l->cmdnum = C_END_FUNCTION;
  1994. break;
  1995. case C_FNEND:
  1996. /*
  1997. **
  1998. ** this makes bwb_scan() simpler
  1999. **
  2000. */
  2001. l->cmdnum = C_END_FUNCTION;
  2002. break;
  2003. case C_FUNCTION:
  2004. /*
  2005. **
  2006. ** we look up declared USER functions as we load
  2007. **
  2008. */
  2009. UserFunction_add (l);
  2010. break;
  2011. case C_IF:
  2012. /*
  2013. **
  2014. ** CLASSIC vs STRUCTURED
  2015. **
  2016. */
  2017. if (IsLastKeyword (l, " THEN"))
  2018. {
  2019. /*
  2020. **
  2021. ** STRUCTURED
  2022. **
  2023. */
  2024. l->cmdnum = C_IF8THEN;
  2025. }
  2026. break;
  2027. case C_OPEN:
  2028. /*
  2029. **
  2030. ** CLASSIC vs STRUCTURED
  2031. **
  2032. */
  2033. if (My->CurrentVersion->OptionVersionValue & (S70 | I70 | I73 | D71))
  2034. {
  2035. /*
  2036. **
  2037. ** STRUCTURED
  2038. **
  2039. */
  2040. /* OPEN filenum, filename$, INPUT | OUTPUT */
  2041. }
  2042. else if (GetKeyword (l, " AS "))
  2043. {
  2044. /*
  2045. **
  2046. ** STRUCTURED
  2047. **
  2048. */
  2049. /* OPEN ... AS ... */
  2050. }
  2051. else
  2052. {
  2053. /*
  2054. **
  2055. ** CLASSIC
  2056. **
  2057. */
  2058. /*
  2059. l->cmdnum = C_DEF8SUB;
  2060. l->Startpos = 0;
  2061. */
  2062. internal_DEF8SUB (l);
  2063. }
  2064. break;
  2065. case C_SUB:
  2066. /*
  2067. **
  2068. ** we look up declared USER functions as we load
  2069. **
  2070. */
  2071. UserFunction_add (l);
  2072. break;
  2073. case C_SUBEND:
  2074. case C_SUB_END:
  2075. /*
  2076. **
  2077. ** this makes bwb_scan() simpler
  2078. **
  2079. */
  2080. l->cmdnum = C_END_SUB;
  2081. break;
  2082. case C_SUBEXIT:
  2083. case C_SUB_EXIT:
  2084. /*
  2085. **
  2086. ** this makes bwb_scan() simpler
  2087. **
  2088. */
  2089. l->cmdnum = C_EXIT_SUB;
  2090. break;
  2091. case C_DEF8LBL:
  2092. /*
  2093. **
  2094. ** we look up declared USER functions as we load
  2095. **
  2096. */
  2097. UserFunction_add (l);
  2098. break;
  2099. }
  2100. return;
  2101. }
  2102. /* not a COMMAND */
  2103. /*
  2104. **
  2105. ** check for implied LET
  2106. **
  2107. */
  2108. if (is_let (l->buffer))
  2109. {
  2110. /*
  2111. **
  2112. ** this is an implied LET, such as:
  2113. ** 100 A = 123
  2114. **
  2115. */
  2116. l->Startpos = 0;
  2117. l->cmdnum = C_LET;
  2118. return;
  2119. }
  2120. /* not an implied LET */
  2121. /*
  2122. **
  2123. ** check for FUNCTION called as a SUBROUTINE
  2124. **
  2125. */
  2126. if (UserFunction_name (tbuf) || IntrinsicFunction_name (tbuf))
  2127. {
  2128. /*
  2129. **
  2130. ** check for a bogus assignment to a FUNCTION called as a SUBROUTINE, such as:
  2131. ** 100 COS = X
  2132. **
  2133. */
  2134. if (line_peek_EqualChar (l))
  2135. {
  2136. /* SYNTAX ERROR */
  2137. l->cmdnum = 0;
  2138. return;
  2139. }
  2140. /*
  2141. **
  2142. ** FUNCTION called as a SUBROUTINE, such as:
  2143. ** 100 OUT X, Y
  2144. **
  2145. */
  2146. /*
  2147. l->Startpos = 0;
  2148. l->cmdnum = C_DEF8SUB;
  2149. */
  2150. internal_DEF8SUB (l);
  2151. return;
  2152. }
  2153. /* not a FUNCTION */
  2154. /*
  2155. **
  2156. ** check for LABEL
  2157. **
  2158. */
  2159. if (My->CurrentVersion->OptionFlags & OPTION_LABELS_ON) /* labels are enabled */
  2160. if (My->CurrentVersion->OptionStatementChar) /* a Statement seperator exists */
  2161. if (line_skip_char (l, My->CurrentVersion->OptionStatementChar)) /* this is a label */
  2162. if (line_is_eol (l)) /* we finish the line */
  2163. {
  2164. /*
  2165. **
  2166. ** LABEL, such as:
  2167. ** 100 MyLabel:
  2168. **
  2169. */
  2170. l->Startpos = l->position;
  2171. l->cmdnum = C_DEF8LBL;
  2172. return;
  2173. }
  2174. /* not a LABEL */
  2175. /* SYNTAX ERROR */
  2176. l->cmdnum = 0;
  2177. return;
  2178. }
  2179. /***************************************************************
  2180. FUNCTION: is_cmd()
  2181. DESCRIPTION: This function determines whether the
  2182. string in 'buffer' is a BASIC command
  2183. statement, returning 'id' or 0.
  2184. ***************************************************************/
  2185. static int
  2186. is_cmd (char *name)
  2187. {
  2188. int i;
  2189. assert (name != NULL);
  2190. #if THE_PRICE_IS_RIGHT
  2191. /* start with the closest command, without going over */
  2192. i = VarTypeIndex (name[0]);
  2193. if (i < 0)
  2194. {
  2195. /* non-alpha, all commands start with an alpha character */
  2196. /* NOT FOUND */
  2197. return 0;
  2198. }
  2199. i = My->CommandStart[i]; /* first command starting with this letter */
  2200. if (i < 0)
  2201. {
  2202. /* no command starts with that letter */
  2203. /* NOT FOUND */
  2204. return 0;
  2205. }
  2206. #else /* THE_PRICE_IS_RIGHT */
  2207. i = 0;
  2208. #endif /* THE_PRICE_IS_RIGHT */
  2209. for (; i < NUM_COMMANDS; i++)
  2210. {
  2211. if (My->CurrentVersion->OptionVersionValue & IntrinsicCommandTable[i].
  2212. OptionVersionBitmask)
  2213. {
  2214. int result;
  2215. result = bwb_stricmp (IntrinsicCommandTable[i].name, name);
  2216. if (result == 0)
  2217. {
  2218. /* FOUND */
  2219. return IntrinsicCommandTable[i].CommandID;
  2220. }
  2221. if (result > 0 /* found > searched */ )
  2222. {
  2223. /* NOT FOUND */
  2224. return 0;
  2225. }
  2226. /* result < 0 : found < searched */
  2227. }
  2228. }
  2229. /* NOT FOUND */
  2230. return 0;
  2231. }
  2232. static int
  2233. is_let (char *buffer)
  2234. {
  2235. /*
  2236. **
  2237. ** returns TRUE if 'buffer' contains an implied LET statement,
  2238. ** which is detected by an unquoted '='
  2239. **
  2240. */
  2241. int n;
  2242. assert (buffer != NULL);
  2243. /* Go through the expression and search for an unquoted assignment operator. */
  2244. for (n = 0; buffer[n]; n++)
  2245. {
  2246. if (buffer[n] == '=')
  2247. {
  2248. return TRUE;
  2249. }
  2250. if (buffer[n] == My->CurrentVersion->OptionQuoteChar)
  2251. {
  2252. /* string constant */
  2253. n++;
  2254. while (buffer[n] != My->CurrentVersion->OptionQuoteChar)
  2255. {
  2256. n++;
  2257. if (buffer[n] == NulChar)
  2258. {
  2259. WARN_SYNTAX_ERROR;
  2260. return FALSE;
  2261. }
  2262. }
  2263. n++;
  2264. }
  2265. }
  2266. /* No command name was found */
  2267. return FALSE;
  2268. }
  2269. extern int
  2270. bwb_freeline (LineType * l)
  2271. {
  2272. /*
  2273. **
  2274. ** free memory associated with a program line
  2275. **
  2276. */
  2277. if (l != NULL)
  2278. {
  2279. /* free arguments if there are any */
  2280. if (l->buffer != NULL)
  2281. {
  2282. free (l->buffer);
  2283. l->buffer = NULL;
  2284. }
  2285. free (l);
  2286. /* l = NULL; */
  2287. My->IsScanRequired = TRUE; /* program needs to be scanned again */
  2288. }
  2289. return TRUE;
  2290. }
  2291. static int
  2292. GetKeyword (LineType * l, char *Keyword)
  2293. {
  2294. /*
  2295. *
  2296. * Returns TRUE if Keyword is found unquoted
  2297. *
  2298. */
  2299. char *S;
  2300. char *C;
  2301. int n;
  2302. assert (l != NULL);
  2303. assert (Keyword != NULL);
  2304. S = l->buffer;
  2305. S += l->position;
  2306. C = S;
  2307. n = bwb_strlen (Keyword);
  2308. while (*C)
  2309. {
  2310. if (bwb_strnicmp (C, Keyword, n) == 0)
  2311. {
  2312. /* FOUND */
  2313. return TRUE;
  2314. }
  2315. else if (*C == My->CurrentVersion->OptionQuoteChar)
  2316. {
  2317. /* skip string constant */
  2318. C++;
  2319. while (*C != NulChar && *C != My->CurrentVersion->OptionQuoteChar)
  2320. {
  2321. C++;
  2322. }
  2323. if (*C == My->CurrentVersion->OptionQuoteChar)
  2324. {
  2325. C++;
  2326. }
  2327. }
  2328. else
  2329. {
  2330. /* skip normal character */
  2331. C++;
  2332. }
  2333. }
  2334. /* NOT FOUND */
  2335. return FALSE;
  2336. }
  2337. extern int
  2338. IsLastKeyword (LineType * l, char *Keyword)
  2339. {
  2340. /* find the end of the line */
  2341. /* backup thru spaces */
  2342. int n;
  2343. char *S;
  2344. char *C;
  2345. assert (l != NULL);
  2346. assert (Keyword != NULL);
  2347. S = l->buffer;
  2348. S += l->position;
  2349. C = S;
  2350. n = bwb_strlen (Keyword);
  2351. S += n;
  2352. /*
  2353. ** IF x THEN 0
  2354. ** IF x THEN
  2355. */
  2356. while (*C)
  2357. {
  2358. /* skip string constants */
  2359. if (*C == My->CurrentVersion->OptionQuoteChar)
  2360. {
  2361. /* skip leading quote */
  2362. C++;
  2363. while (*C != NulChar && *C != My->CurrentVersion->OptionQuoteChar)
  2364. {
  2365. C++;
  2366. }
  2367. /* skip trailing quote */
  2368. if (*C == My->CurrentVersion->OptionQuoteChar)
  2369. {
  2370. C++;
  2371. }
  2372. }
  2373. else
  2374. {
  2375. C++;
  2376. }
  2377. }
  2378. if (C > S)
  2379. {
  2380. C--;
  2381. while (C > S && *C == ' ')
  2382. {
  2383. C--;
  2384. }
  2385. C++;
  2386. if (C > S)
  2387. {
  2388. C -= n;
  2389. if (bwb_strnicmp (C, Keyword, n) == 0)
  2390. {
  2391. /* FOUND */
  2392. return TRUE;
  2393. }
  2394. }
  2395. }
  2396. /* NOT FOUND */
  2397. return FALSE;
  2398. }
  2399. /* bitmask values returned by bwb_chartype() */
  2400. #define CHAR_IS_CNTRL 0x01
  2401. #define CHAR_IS_SPACE 0x02
  2402. #define CHAR_IS_PRINT 0x04
  2403. #define CHAR_IS_PUNCT 0x08
  2404. #define CHAR_IS_DIGIT 0x10
  2405. #define CHAR_IS_XDIGIT 0x20
  2406. #define CHAR_IS_UPPER 0x40
  2407. #define CHAR_IS_LOWER 0x80
  2408. #define CHAR_IS_ALPHA (CHAR_IS_UPPER | CHAR_IS_LOWER)
  2409. #define CHAR_IS_ALNUM (CHAR_IS_ALPHA | CHAR_IS_DIGIT)
  2410. #define CHAR_IS_GRAPH (CHAR_IS_ALNUM | CHAR_IS_PUNCT)
  2411. static int
  2412. bwb_chartype (int C)
  2413. {
  2414. /* returns the the character type bitmask */
  2415. switch (C)
  2416. {
  2417. case EOF:
  2418. return 0; /* Special Case */
  2419. case '\t':
  2420. case '\n':
  2421. case '\v':
  2422. case '\f':
  2423. case '\r':
  2424. return CHAR_IS_CNTRL | CHAR_IS_SPACE;
  2425. case ' ':
  2426. return CHAR_IS_PRINT | CHAR_IS_SPACE;
  2427. case '!':
  2428. case '"':
  2429. case '#':
  2430. case '$':
  2431. case '%':
  2432. case '&':
  2433. case '\'':
  2434. case '(':
  2435. case ')':
  2436. case '*':
  2437. case '+':
  2438. case ',':
  2439. case '-':
  2440. case '.':
  2441. case '/':
  2442. return CHAR_IS_PRINT | CHAR_IS_PUNCT;
  2443. case '0':
  2444. case '1':
  2445. case '2':
  2446. case '3':
  2447. case '4':
  2448. case '5':
  2449. case '6':
  2450. case '7':
  2451. case '8':
  2452. case '9':
  2453. return CHAR_IS_PRINT | CHAR_IS_DIGIT | CHAR_IS_XDIGIT;
  2454. case ':':
  2455. case ';':
  2456. case '<':
  2457. case '=':
  2458. case '>':
  2459. case '?':
  2460. case '@':
  2461. return CHAR_IS_PRINT | CHAR_IS_PUNCT;
  2462. case 'A':
  2463. case 'B':
  2464. case 'C':
  2465. case 'D':
  2466. case 'E':
  2467. case 'F':
  2468. return CHAR_IS_PRINT | CHAR_IS_UPPER | CHAR_IS_XDIGIT;
  2469. case 'G':
  2470. case 'H':
  2471. case 'I':
  2472. case 'J':
  2473. case 'K':
  2474. case 'L':
  2475. case 'M':
  2476. case 'N':
  2477. case 'O':
  2478. case 'P':
  2479. case 'Q':
  2480. case 'R':
  2481. case 'S':
  2482. case 'T':
  2483. case 'U':
  2484. case 'V':
  2485. case 'W':
  2486. case 'X':
  2487. case 'Y':
  2488. case 'Z':
  2489. return CHAR_IS_PRINT | CHAR_IS_UPPER;
  2490. case '[':
  2491. case '\\':
  2492. case ']':
  2493. case '^':
  2494. case '_':
  2495. case '`':
  2496. return CHAR_IS_PRINT | CHAR_IS_PUNCT;
  2497. case 'a':
  2498. case 'b':
  2499. case 'c':
  2500. case 'd':
  2501. case 'e':
  2502. case 'f':
  2503. return CHAR_IS_PRINT | CHAR_IS_LOWER | CHAR_IS_XDIGIT;
  2504. case 'g':
  2505. case 'h':
  2506. case 'i':
  2507. case 'j':
  2508. case 'k':
  2509. case 'l':
  2510. case 'm':
  2511. case 'n':
  2512. case 'o':
  2513. case 'p':
  2514. case 'q':
  2515. case 'r':
  2516. case 's':
  2517. case 't':
  2518. case 'u':
  2519. case 'v':
  2520. case 'w':
  2521. case 'x':
  2522. case 'y':
  2523. case 'z':
  2524. return CHAR_IS_PRINT | CHAR_IS_LOWER;
  2525. case '{':
  2526. case '|':
  2527. case '}':
  2528. case '~':
  2529. return CHAR_IS_PRINT | CHAR_IS_PUNCT;
  2530. }
  2531. return CHAR_IS_CNTRL;
  2532. }
  2533. extern int
  2534. bwb_isalnum (int C)
  2535. {
  2536. /*
  2537. 4.3.1.1 The isalnum function
  2538. Synopsis
  2539. #include <ctype.h>
  2540. int isalnum(int c);
  2541. Description
  2542. The isalnum function tests for any character for which isalpha or
  2543. isdigit is true.
  2544. */
  2545. if (bwb_chartype (C) & CHAR_IS_ALNUM)
  2546. {
  2547. return TRUE;
  2548. }
  2549. return FALSE;
  2550. }
  2551. int
  2552. bwb_isalpha (int C)
  2553. {
  2554. /*
  2555. 4.3.1.2 The isalpha function
  2556. Synopsis
  2557. #include <ctype.h>
  2558. int isalpha(int c);
  2559. Description
  2560. The isalpha function tests for any character for which isupper or
  2561. islower is true, or any of an implementation-defined set of characters
  2562. for which none of iscntrl , isdigit , ispunct , or isspace is true.
  2563. In the C locale, isalpha returns true only for the characters for
  2564. which isupper or islower is true.
  2565. */
  2566. if (bwb_chartype (C) & CHAR_IS_ALPHA)
  2567. {
  2568. return TRUE;
  2569. }
  2570. return FALSE;
  2571. }
  2572. #if FALSE /* keep this ... */
  2573. extern int
  2574. bwb_iscntrl (int C)
  2575. {
  2576. /*
  2577. 4.3.1.3 The iscntrl function
  2578. Synopsis
  2579. #include <ctype.h>
  2580. int iscntrl(int c);
  2581. Description
  2582. The iscntrl function tests for any control character.
  2583. */
  2584. if (bwb_chartype (C) & CHAR_IS_CNTRL)
  2585. {
  2586. return TRUE;
  2587. }
  2588. return FALSE;
  2589. }
  2590. #endif
  2591. extern int
  2592. bwb_isdigit (int C)
  2593. {
  2594. /*
  2595. 4.3.1.4 The isdigit function
  2596. Synopsis
  2597. #include <ctype.h>
  2598. int isdigit(int c);
  2599. Description
  2600. The isdigit function tests for any decimal-digit character (as
  2601. defined in $2.2.1).
  2602. */
  2603. if (bwb_chartype (C) & CHAR_IS_DIGIT)
  2604. {
  2605. return TRUE;
  2606. }
  2607. return FALSE;
  2608. }
  2609. extern int
  2610. bwb_isgraph (int C)
  2611. {
  2612. /*
  2613. 4.3.1.5 The isgraph function
  2614. Synopsis
  2615. #include <ctype.h>
  2616. int isgraph(int c);
  2617. Description
  2618. The isgraph function tests for any printing character except space (' ').
  2619. */
  2620. if (bwb_chartype (C) & CHAR_IS_GRAPH)
  2621. {
  2622. return TRUE;
  2623. }
  2624. return FALSE;
  2625. }
  2626. #if FALSE /* keep this ... */
  2627. extern int
  2628. bwb_islower (int C)
  2629. {
  2630. /*
  2631. 4.3.1.6 The islower function
  2632. Synopsis
  2633. #include <ctype.h>
  2634. int islower(int c);
  2635. Description
  2636. The islower function tests for any lower-case letter or any of an
  2637. implementation-defined set of characters for which none of iscntrl ,
  2638. isdigit , ispunct , or isspace is true. In the C locale, islower
  2639. returns true only for the characters defined as lower-case letters (as
  2640. defined in $2.2.1).
  2641. */
  2642. if (bwb_chartype (C) & CHAR_IS_LOWER)
  2643. {
  2644. return TRUE;
  2645. }
  2646. return FALSE;
  2647. }
  2648. #endif
  2649. extern int
  2650. bwb_isprint (int C)
  2651. {
  2652. /*
  2653. 4.3.1.7 The isprint function
  2654. Synopsis
  2655. #include <ctype.h>
  2656. int isprint(int c);
  2657. Description
  2658. The isprint function tests for any printing character including
  2659. space (' ').
  2660. */
  2661. if (bwb_chartype (C) & CHAR_IS_PRINT)
  2662. {
  2663. return TRUE;
  2664. }
  2665. return FALSE;
  2666. }
  2667. extern int
  2668. bwb_ispunct (int C)
  2669. {
  2670. /*
  2671. 4.3.1.8 The ispunct function
  2672. Synopsis
  2673. #include <ctype.h>
  2674. int ispunct(int c);
  2675. Description
  2676. The ispunct function tests for any printing character except space
  2677. (' ') or a character for which isalnum is true.
  2678. */
  2679. if (bwb_chartype (C) & CHAR_IS_PUNCT)
  2680. {
  2681. return TRUE;
  2682. }
  2683. return FALSE;
  2684. }
  2685. #if FALSE /* keep this ... */
  2686. extern int
  2687. bwb_isspace (int C)
  2688. {
  2689. /*
  2690. 4.3.1.9 The isspace function
  2691. Synopsis
  2692. #include <ctype.h>
  2693. int isspace(int c);
  2694. Description
  2695. The isspace function tests for the standard white-space characters
  2696. or for any of an implementation-defined set of characters for which
  2697. isalnum is false. The standard white-space characters are the
  2698. following: space (' '), form feed ('\f'), new-line ('\n'), carriage
  2699. return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). In the
  2700. C locale, isspace returns true only for the standard white-space
  2701. characters.
  2702. */
  2703. if (bwb_chartype (C) & CHAR_IS_SPACE)
  2704. {
  2705. return TRUE;
  2706. }
  2707. return FALSE;
  2708. }
  2709. #endif
  2710. #if FALSE /* keep this ... */
  2711. extern int
  2712. bwb_isupper (int C)
  2713. {
  2714. /*
  2715. 4.3.1.10 The isupper function
  2716. Synopsis
  2717. #include <ctype.h>
  2718. int isupper(int c);
  2719. Description
  2720. The isupper function tests for any upper-case letter or any of an
  2721. implementation-defined set of characters for which none of iscntrl ,
  2722. isdigit , ispunct , or isspace is true. In the C locale, isupper
  2723. returns true only for the characters defined as upper-case letters (as
  2724. defined in $2.2.1).
  2725. */
  2726. if (bwb_chartype (C) & CHAR_IS_UPPER)
  2727. {
  2728. return TRUE;
  2729. }
  2730. return FALSE;
  2731. }
  2732. #endif
  2733. extern int
  2734. bwb_isxdigit (int C)
  2735. {
  2736. /*
  2737. 4.3.1.11 The isxdigit function
  2738. Synopsis
  2739. #include <ctype.h>
  2740. int isxdigit(int c);
  2741. Description
  2742. The isxdigit function tests for any hexadecimal-digit character (as
  2743. defined in $3.1.3.2).
  2744. */
  2745. if (bwb_chartype (C) & CHAR_IS_XDIGIT)
  2746. {
  2747. return TRUE;
  2748. }
  2749. return FALSE;
  2750. }
  2751. extern int
  2752. bwb_tolower (int C)
  2753. {
  2754. /*
  2755. 4.3.2.1 The tolower function
  2756. Synopsis
  2757. #include <ctype.h>
  2758. int tolower(int c);
  2759. Description
  2760. The tolower function converts an upper-case letter to the
  2761. corresponding lower-case letter.
  2762. Returns
  2763. If the argument is an upper-case letter, the tolower function
  2764. returns the corresponding lower-case letter if there is one; otherwise
  2765. the argument is returned unchanged. In the C locale, tolower maps
  2766. only the characters for which isupper is true to the corresponding
  2767. characters for which islower is true.
  2768. */
  2769. switch (C)
  2770. {
  2771. case 'A':
  2772. return 'a';
  2773. case 'B':
  2774. return 'b';
  2775. case 'C':
  2776. return 'c';
  2777. case 'D':
  2778. return 'd';
  2779. case 'E':
  2780. return 'e';
  2781. case 'F':
  2782. return 'f';
  2783. case 'G':
  2784. return 'g';
  2785. case 'H':
  2786. return 'h';
  2787. case 'I':
  2788. return 'i';
  2789. case 'J':
  2790. return 'j';
  2791. case 'K':
  2792. return 'k';
  2793. case 'L':
  2794. return 'l';
  2795. case 'M':
  2796. return 'm';
  2797. case 'N':
  2798. return 'n';
  2799. case 'O':
  2800. return 'o';
  2801. case 'P':
  2802. return 'p';
  2803. case 'Q':
  2804. return 'q';
  2805. case 'R':
  2806. return 'r';
  2807. case 'S':
  2808. return 's';
  2809. case 'T':
  2810. return 't';
  2811. case 'U':
  2812. return 'u';
  2813. case 'V':
  2814. return 'v';
  2815. case 'W':
  2816. return 'w';
  2817. case 'X':
  2818. return 'x';
  2819. case 'Y':
  2820. return 'y';
  2821. case 'Z':
  2822. return 'z';
  2823. }
  2824. return C;
  2825. }
  2826. extern int
  2827. bwb_toupper (int C)
  2828. {
  2829. /*
  2830. 4.3.2.2 The toupper function
  2831. Synopsis
  2832. #include <ctype.h>
  2833. int toupper(int c);
  2834. Description
  2835. The toupper function converts a lower-case letter to the corresponding upper-case letter.
  2836. Returns
  2837. If the argument is a lower-case letter, the toupper function
  2838. returns the corresponding upper-case letter if there is one; otherwise
  2839. the argument is returned unchanged. In the C locale, toupper maps
  2840. only the characters for which islower is true to the corresponding
  2841. characters for which isupper is true.
  2842. */
  2843. switch (C)
  2844. {
  2845. case 'a':
  2846. return 'A';
  2847. case 'b':
  2848. return 'B';
  2849. case 'c':
  2850. return 'C';
  2851. case 'd':
  2852. return 'D';
  2853. case 'e':
  2854. return 'E';
  2855. case 'f':
  2856. return 'F';
  2857. case 'g':
  2858. return 'G';
  2859. case 'h':
  2860. return 'H';
  2861. case 'i':
  2862. return 'I';
  2863. case 'j':
  2864. return 'J';
  2865. case 'k':
  2866. return 'K';
  2867. case 'l':
  2868. return 'L';
  2869. case 'm':
  2870. return 'M';
  2871. case 'n':
  2872. return 'N';
  2873. case 'o':
  2874. return 'O';
  2875. case 'p':
  2876. return 'P';
  2877. case 'q':
  2878. return 'Q';
  2879. case 'r':
  2880. return 'R';
  2881. case 's':
  2882. return 'S';
  2883. case 't':
  2884. return 'T';
  2885. case 'u':
  2886. return 'U';
  2887. case 'v':
  2888. return 'V';
  2889. case 'w':
  2890. return 'W';
  2891. case 'x':
  2892. return 'X';
  2893. case 'y':
  2894. return 'Y';
  2895. case 'z':
  2896. return 'Z';
  2897. }
  2898. return C;
  2899. }
  2900. extern void *
  2901. bwb_memcpy (void *s1, const void *s2, size_t n)
  2902. {
  2903. /*
  2904. 4.11.2.1 The memcpy function
  2905. Synopsis
  2906. #include <string.h>
  2907. void *memcpy(void *s1, const void *s2, size_t n);
  2908. Description
  2909. The memcpy function copies n characters from the object pointed to
  2910. by s2 into the object pointed to by s1 . If copying takes place
  2911. between objects that overlap, the behavior is undefined.
  2912. Returns
  2913. The memcpy function returns the value of s1 .
  2914. */
  2915. if (n > 0)
  2916. {
  2917. char *Target;
  2918. char *Source;
  2919. int p;
  2920. assert (s1 != NULL);
  2921. assert (s2 != NULL);
  2922. Target = (char *) s1;
  2923. Source = (char *) s2;
  2924. p = 0;
  2925. while (p < n)
  2926. {
  2927. Target[p] = Source[p];
  2928. p++;
  2929. }
  2930. }
  2931. return s1;
  2932. }
  2933. #if FALSE /* keep this ... */
  2934. extern void *
  2935. bwb_memmove (void *s1, const void *s2, size_t n)
  2936. {
  2937. /*
  2938. 4.11.2.2 The memmove function
  2939. Synopsis
  2940. #include <string.h>
  2941. void *memmove(void *s1, const void *s2, size_t n);
  2942. Description
  2943. The memmove function copies n characters from the object pointed to
  2944. by s2 into the object pointed to by s1 . Copying takes place as if
  2945. the n characters from the object pointed to by s2 are first copied
  2946. into a temporary array of n characters that does not overlap the
  2947. objects pointed to by s1 and s2 , and then the n characters from the
  2948. temporary array are copied into the object pointed to by s1 .
  2949. Returns
  2950. The memmove function returns the value of s1 .
  2951. */
  2952. if (n > 0)
  2953. {
  2954. char *Target;
  2955. char *Source;
  2956. char *Temp;
  2957. assert (s1 != NULL);
  2958. assert (s2 != NULL);
  2959. Target = (char *) s1;
  2960. Source = (char *) s2;
  2961. Temp = (char *) malloc (n);
  2962. if (Temp != NULL)
  2963. {
  2964. int p;
  2965. p = 0;
  2966. while (p < n)
  2967. {
  2968. Temp[p] = Source[p];
  2969. p++;
  2970. }
  2971. p = 0;
  2972. while (p < n)
  2973. {
  2974. Target[p] = Temp[p];
  2975. p++;
  2976. }
  2977. free (Temp);
  2978. Temp = NULL;
  2979. }
  2980. }
  2981. return s1;
  2982. }
  2983. #endif
  2984. extern char *
  2985. bwb_strcpy (char *s1, const char *s2)
  2986. {
  2987. /*
  2988. 4.11.2.3 The strcpy function
  2989. Synopsis
  2990. #include <string.h>
  2991. char *strcpy(char *s1, const char *s2);
  2992. Description
  2993. The strcpy function copies the string pointed to by s2 (including
  2994. the terminating null character) into the array pointed to by s1 . If
  2995. copying takes place between objects that overlap, the behavior is
  2996. undefined.
  2997. Returns
  2998. The strcpy function returns the value of s1 .
  2999. */
  3000. char C;
  3001. int p;
  3002. assert (s1 != NULL);
  3003. assert (s2 != NULL);
  3004. p = 0;
  3005. do
  3006. {
  3007. C = s2[p];
  3008. s1[p] = C;
  3009. p++;
  3010. }
  3011. while (C);
  3012. return s1;
  3013. }
  3014. extern char *
  3015. bwb_strncpy (char *s1, const char *s2, size_t n)
  3016. {
  3017. /*
  3018. 4.11.2.4 The strncpy function
  3019. Synopsis
  3020. #include <string.h>
  3021. char *strncpy(char *s1, const char *s2, size_t n);
  3022. Description
  3023. The strncpy function copies not more than n characters (characters
  3024. that follow a null character are not copied) from the array pointed to
  3025. by s2 to the array pointed to by s1 ./120/ If copying takes place
  3026. between objects that overlap, the behavior is undefined.
  3027. If the array pointed to by s2 is a string that is shorter than n
  3028. characters, null characters are appended to the copy in the array
  3029. pointed to by s1 , until n characters in all have been written.
  3030. Returns
  3031. The strncpy function returns the value of s1 .
  3032. */
  3033. if (n > 0)
  3034. {
  3035. char C;
  3036. int p;
  3037. assert (s1 != NULL);
  3038. assert (s2 != NULL);
  3039. p = 0;
  3040. do
  3041. {
  3042. C = s2[p];
  3043. s1[p] = C;
  3044. p++;
  3045. }
  3046. while (C != NulChar && p < n);
  3047. while (p < n)
  3048. {
  3049. s1[p] = NulChar;
  3050. p++;
  3051. }
  3052. }
  3053. return s1;
  3054. }
  3055. extern char *
  3056. bwb_strcat (char *s1, const char *s2)
  3057. {
  3058. /*
  3059. 4.11.3.1 The strcat function
  3060. Synopsis
  3061. #include <string.h>
  3062. char *strcat(char *s1, const char *s2);
  3063. Description
  3064. The strcat function appends a copy of the string pointed to by s2
  3065. (including the terminating null character) to the end of the string
  3066. pointed to by s1 . The initial character of s2 overwrites the null
  3067. character at the end of s1 . If copying takes place between objects
  3068. that overlap, the behavior is undefined.
  3069. Returns
  3070. The strcat function returns the value of s1 .
  3071. */
  3072. char *Temp;
  3073. assert (s1 != NULL);
  3074. assert (s2 != NULL);
  3075. Temp = bwb_strchr (s1, NulChar);
  3076. bwb_strcpy (Temp, s2);
  3077. return s1;
  3078. }
  3079. #if FALSE /* keep this ... */
  3080. extern char *
  3081. bwb_strncat (char *s1, const char *s2, size_t n)
  3082. {
  3083. /*
  3084. 4.11.3.2 The strncat function
  3085. Synopsis
  3086. #include <string.h>
  3087. char *strncat(char *s1, const char *s2, size_t n);
  3088. Description
  3089. The strncat function appends not more than n characters (a null
  3090. character and characters that follow it are not appended) from the
  3091. array pointed to by s2 to the end of the string pointed to by s1 .
  3092. The initial character of s2 overwrites the null character at the end
  3093. of s1 . A terminating null character is always appended to the
  3094. result./121/ If copying takes place between objects that overlap, the
  3095. behavior is undefined.
  3096. Returns
  3097. The strncat function returns the value of s1 .
  3098. */
  3099. char *Temp;
  3100. assert (s1 != NULL);
  3101. assert (s2 != NULL);
  3102. Temp = bwb_strchr (s1, NulChar);
  3103. bwb_strncpy (Temp, s2, n);
  3104. return s1;
  3105. }
  3106. #endif
  3107. extern int
  3108. bwb_memcmp (const void *s1, const void *s2, size_t n)
  3109. {
  3110. /*
  3111. 4.11.4.1 The memcmp function
  3112. Synopsis
  3113. #include <string.h>
  3114. int memcmp(const void *s1, const void *s2, size_t n);
  3115. Description
  3116. The memcmp function compares the first n characters of the object
  3117. pointed to by s1 to the first n characters of the object pointed to by
  3118. s2 ./122/
  3119. Returns
  3120. The memcmp function returns an integer greater than, equal to, or
  3121. less than zero, according as the object pointed to by s1 is greater
  3122. than, equal to, or less than the object pointed to by s2 .
  3123. */
  3124. if (n > 0)
  3125. {
  3126. int p;
  3127. char *L;
  3128. char *R;
  3129. assert (s1 != NULL);
  3130. assert (s2 != NULL);
  3131. p = 0;
  3132. L = (char *) s1;
  3133. R = (char *) s2;
  3134. while (p < n)
  3135. {
  3136. if (L[p] > R[p])
  3137. {
  3138. return 1;
  3139. }
  3140. if (L[p] < R[p])
  3141. {
  3142. return -1;
  3143. }
  3144. /* L[ p ] == R[ p ] */
  3145. p++;
  3146. }
  3147. }
  3148. return 0;
  3149. }
  3150. extern int
  3151. bwb_strcmp (const char *s1, const char *s2)
  3152. {
  3153. /*
  3154. 4.11.4.2 The strcmp function
  3155. Synopsis
  3156. #include <string.h>
  3157. int strcmp(const char *s1, const char *s2);
  3158. Description
  3159. The strcmp function compares the string pointed to by s1 to the
  3160. string pointed to by s2 .
  3161. Returns
  3162. The strcmp function returns an integer greater than, equal to, or
  3163. less than zero, according as the string pointed to by s1 is greater
  3164. than, equal to, or less than the string pointed to by s2 .
  3165. */
  3166. char C;
  3167. int p;
  3168. assert (s1 != NULL);
  3169. assert (s2 != NULL);
  3170. p = 0;
  3171. do
  3172. {
  3173. if (s1[p] > s2[p])
  3174. {
  3175. return 1;
  3176. }
  3177. if (s1[p] < s2[p])
  3178. {
  3179. return -1;
  3180. }
  3181. /* s1[ p ] == s2[ p ] */
  3182. C = s1[p];
  3183. p++;
  3184. }
  3185. while (C);
  3186. return 0;
  3187. }
  3188. #if FALSE /* keep this ... */
  3189. extern int
  3190. bwb_strncmp (const char *s1, const char *s2, size_t n)
  3191. {
  3192. /*
  3193. 4.11.4.4 The strncmp function
  3194. Synopsis
  3195. #include <string.h>
  3196. int strncmp(const char *s1, const char *s2, size_t n);
  3197. Description
  3198. The strncmp function compares not more than n characters
  3199. (characters that follow a null character are not compared) from the
  3200. array pointed to by s1 to the array pointed to by s2 .
  3201. Returns
  3202. The strncmp function returns an integer greater than, equal to, or
  3203. less than zero, according as the possibly null-terminated array
  3204. pointed to by s1 is greater than, equal to, or less than the possibly
  3205. null-terminated array pointed to by s2 .
  3206. */
  3207. if (n > 0)
  3208. {
  3209. char C;
  3210. int p;
  3211. assert (s1 != NULL);
  3212. assert (s2 != NULL);
  3213. p = 0;
  3214. do
  3215. {
  3216. if (s1[p] > s2[p])
  3217. {
  3218. return 1;
  3219. }
  3220. if (s1[p] < s2[p])
  3221. {
  3222. return -1;
  3223. }
  3224. /* s1[ p ] == s2[ p ] */
  3225. C = s1[p];
  3226. p++;
  3227. }
  3228. while (C != NulChar && p < n);
  3229. }
  3230. return 0;
  3231. }
  3232. #endif
  3233. #if FALSE /* keep this ... */
  3234. extern void *
  3235. bwb_memchr (const void *s, int c, size_t n)
  3236. {
  3237. /*
  3238. 4.11.5.1 The memchr function
  3239. Synopsis
  3240. #include <string.h>
  3241. void *memchr(const void *s, int c, size_t n);
  3242. Description
  3243. The memchr function locates the first occurrence of c (converted to
  3244. an unsigned char ) in the initial n characters (each interpreted as
  3245. unsigned char ) of the object pointed to by s .
  3246. Returns
  3247. The memchr function returns a pointer to the located character, or
  3248. a null pointer if the character does not occur in the object.
  3249. */
  3250. if (n > 0)
  3251. {
  3252. int p;
  3253. unsigned char *Check;
  3254. unsigned char Find;
  3255. assert (s != NULL);
  3256. p = 0;
  3257. Check = (unsigned char *) s;
  3258. Find = (unsigned char) c;
  3259. do
  3260. {
  3261. if (Check[p] == Find)
  3262. {
  3263. return (void *) &(Check[p]);
  3264. }
  3265. p++;
  3266. }
  3267. while (p < n);
  3268. }
  3269. return NULL;
  3270. }
  3271. #endif
  3272. extern char *
  3273. bwb_strchr (const char *s, int c)
  3274. {
  3275. /*
  3276. 4.11.5.2 The strchr function
  3277. Synopsis
  3278. #include <string.h>
  3279. char *strchr(const char *s, int c);
  3280. Description
  3281. The strchr function locates the first occurrence of c (converted to
  3282. a char ) in the string pointed to by s . The terminating null
  3283. character is considered to be part of the string.
  3284. Returns
  3285. The strchr function returns a pointer to the located character, or
  3286. a null pointer if the character does not occur in the string.
  3287. */
  3288. int p;
  3289. char Find;
  3290. char C;
  3291. assert (s != NULL);
  3292. p = 0;
  3293. Find = (char) c;
  3294. do
  3295. {
  3296. C = s[p];
  3297. if (C == Find)
  3298. {
  3299. return (char *) &(s[p]);
  3300. }
  3301. p++;
  3302. }
  3303. while (C);
  3304. return NULL;
  3305. }
  3306. extern char *
  3307. bwb_strrchr (const char *s, int c)
  3308. {
  3309. /*
  3310. 4.11.5.5 The strrchr function
  3311. Synopsis
  3312. #include <string.h>
  3313. char *strrchr(const char *s, int c);
  3314. Description
  3315. The strrchr function locates the last occurrence of c (converted to
  3316. a char ) in the string pointed to by s . The terminating null
  3317. character is considered to be part of the string.
  3318. Returns
  3319. The strrchr function returns a pointer to the character, or a null
  3320. pointer if c does not occur in the string.
  3321. */
  3322. int p;
  3323. char Find;
  3324. char *Found;
  3325. char C;
  3326. assert (s != NULL);
  3327. p = 0;
  3328. Find = (char) c;
  3329. Found = NULL;
  3330. do
  3331. {
  3332. C = s[p];
  3333. if (C == Find)
  3334. {
  3335. Found = (char *) &(s[p]);
  3336. }
  3337. p++;
  3338. }
  3339. while (C);
  3340. return Found;
  3341. }
  3342. extern void *
  3343. bwb_memset (void *s, int c, size_t n)
  3344. {
  3345. /*
  3346. 4.11.6.1 The memset function
  3347. Synopsis
  3348. #include <string.h>
  3349. void *memset(void *s, int c, size_t n);
  3350. Description
  3351. The memset function copies the value of c (converted to an unsigned
  3352. char ) into each of the first n characters of the object pointed to by
  3353. s .
  3354. Returns
  3355. The memset function returns the value of s .
  3356. */
  3357. if (n > 0)
  3358. {
  3359. int p;
  3360. unsigned char *Target;
  3361. unsigned char Value;
  3362. assert (s != NULL);
  3363. p = 0;
  3364. Target = (unsigned char *) s;
  3365. Value = (unsigned char) c;
  3366. do
  3367. {
  3368. Target[p] = Value;
  3369. p++;
  3370. }
  3371. while (p < n);
  3372. }
  3373. return s;
  3374. }
  3375. extern size_t
  3376. bwb_strlen (const char *s)
  3377. {
  3378. /*
  3379. 4.11.6.3 The strlen function
  3380. Synopsis
  3381. #include <string.h>
  3382. size_t strlen(const char *s);
  3383. Description
  3384. The strlen function computes the length of the string pointed to by s .
  3385. Returns
  3386. The strlen function returns the number of characters that precede
  3387. the terminating null character.
  3388. */
  3389. size_t p;
  3390. assert (s != NULL);
  3391. p = 0;
  3392. while (s[p])
  3393. {
  3394. p++;
  3395. }
  3396. return p;
  3397. }
  3398. extern char *
  3399. bwb_strdup (char *s)
  3400. {
  3401. size_t n;
  3402. char *r;
  3403. assert (s != NULL);
  3404. /* r = NULL; */
  3405. n = bwb_strlen (s);
  3406. r = calloc (n + 1 /* NulChar */ , sizeof (char));
  3407. if (r != NULL)
  3408. {
  3409. bwb_strcpy (r, s);
  3410. }
  3411. return r;
  3412. }
  3413. extern char *
  3414. bwb_strdup2 (char *s, char *t)
  3415. {
  3416. size_t n;
  3417. char *r;
  3418. assert (s != NULL);
  3419. assert (t != NULL);
  3420. /* r = NULL; */
  3421. n = bwb_strlen (s) + bwb_strlen (t);
  3422. r = calloc (n + 1 /* NulChar */ , sizeof (char));
  3423. if (r != NULL)
  3424. {
  3425. bwb_strcpy (r, s);
  3426. bwb_strcat (r, t);
  3427. }
  3428. return r;
  3429. }
  3430. #if HAVE_UNIX_GCC
  3431. /* these are intrinsic C functions in my environment using -ansi */
  3432. #else /* ! HAVE_UNIX_GCC */
  3433. extern unsigned int
  3434. sleep (unsigned int X)
  3435. {
  3436. /* do nothing */
  3437. return X;
  3438. }
  3439. #endif /* ! HAVE_UNIX_GCC */
  3440. extern double
  3441. bwb_rint (double x)
  3442. {
  3443. /* BASIC dialects have different rounding rules */
  3444. double Result;
  3445. if (x < 0)
  3446. {
  3447. return -bwb_rint (-x);
  3448. }
  3449. /* x >= 0 */
  3450. switch (My->OptionRoundType)
  3451. {
  3452. case C_OPTION_ROUND_BANK:
  3453. /* normal financial rounding */
  3454. Result = floor (x + 0.5);
  3455. if (x - floor (x) == 0.5)
  3456. {
  3457. /* midway */
  3458. double Half;
  3459. Half = Result / 2.0;
  3460. if (Half != floor (Half))
  3461. {
  3462. /* odd -> even */
  3463. Result--;
  3464. }
  3465. }
  3466. break;
  3467. case C_OPTION_ROUND_MATH:
  3468. /* normal mathematical rounding */
  3469. Result = floor (x + 0.5);
  3470. break;
  3471. case C_OPTION_ROUND_TRUNCATE:
  3472. /* simple truncation */
  3473. Result = floor (x);
  3474. break;
  3475. }
  3476. return Result;
  3477. }
  3478. extern int
  3479. bwb_stricmp (const char *s1, const char *s2)
  3480. {
  3481. const unsigned char *p1;
  3482. const unsigned char *p2;
  3483. assert (s1 != NULL);
  3484. assert (s2 != NULL);
  3485. p1 = (const unsigned char *) s1;
  3486. p2 = (const unsigned char *) s2;
  3487. while (*p1)
  3488. {
  3489. char c1;
  3490. char c2;
  3491. c1 = bwb_toupper (*p1);
  3492. c2 = bwb_toupper (*p2);
  3493. if (c1 < c2)
  3494. {
  3495. return -1;
  3496. }
  3497. if (c1 > c2)
  3498. {
  3499. return 1;
  3500. }
  3501. p1++;
  3502. p2++;
  3503. }
  3504. if (*p2 == NulChar)
  3505. {
  3506. return 0;
  3507. }
  3508. return -1;
  3509. }
  3510. extern int
  3511. bwb_strnicmp (const char *s1, const char *s2, size_t n)
  3512. {
  3513. const unsigned char *p1;
  3514. const unsigned char *p2;
  3515. size_t x = 0;
  3516. assert (s1 != NULL);
  3517. assert (s2 != NULL);
  3518. p1 = (const unsigned char *) s1;
  3519. p2 = (const unsigned char *) s2;
  3520. while (x < n)
  3521. {
  3522. char c1;
  3523. char c2;
  3524. c1 = bwb_toupper (p1[x]);
  3525. c2 = bwb_toupper (p2[x]);
  3526. if (c1 < c2)
  3527. {
  3528. return -1;
  3529. }
  3530. if (c1 > c2)
  3531. {
  3532. return 1;
  3533. }
  3534. if (c1 == NulChar)
  3535. {
  3536. return 0;
  3537. }
  3538. x++;
  3539. }
  3540. return 0;
  3541. }
  3542. /* EOF */