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.
 
 
 
 
 
 

693 lines
20 KiB

  1. /*-------------------------------------------------------------------*/
  2. /* renum.c -- Renumbers a BASIC program in an ASCII file. */
  3. /* Originally written in HP 2000 BASIC by David Lance Robinson, 1977 */
  4. /* Adapted to MS BASIC and translated to C 4/1995 by Jon B. Volkoff */
  5. /* (eidetics@cerf.net) */
  6. /* */
  7. /* Some changes 04-2020 Ken. Re cp or copy and input terminator */
  8. /* when compiling under DOS use -DMSDOS */
  9. /* And fgets under Ubuntu. */
  10. /* */
  11. /* 8-2021 Ken. Saves original program in editfl.bas */
  12. /* Cleans up editfl */
  13. /* Handles both upper and lower case GOTo GOSub IF THEN */
  14. /* ON , PRInt , SHEll and INPut */
  15. /* Trims leading white space on line numbers. */
  16. /* Thanks Chipmaster */
  17. /* */
  18. /* Compile as gcc renum.c -o renum */
  19. /*-------------------------------------------------------------------*/
  20. /* *WARN* This code is still broken. Use at your own risk! Its taken
  21. more effort than writing it from scratch. I'm not putting
  22. any more effort into it. -- ChipMaster */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #define MAX_LINE_LENGTH 255
  27. #define MAX_LINE_COUNT 1500
  28. int instr();
  29. char *midstr1();
  30. char *midstr2();
  31. char *myfget;
  32. void binary_search(void);
  33. void trim(char *s);
  34. char *umids(char *astr, int start, int len);
  35. int f2, l2, n, x;
  36. int sidx[MAX_LINE_COUNT][2];
  37. int myretn;
  38. char rstr[MAX_LINE_LENGTH];
  39. int main(argc, argv)
  40. int argc;
  41. char *argv[];
  42. {
  43. int f, d, s, p, s1, t, l, g;
  44. int c, f1, c1, i, f8, r, l1, l3;
  45. int v1, f6, l6, b, f9, x9, b1, p8, p9, a, d9;
  46. char pstr[MAX_LINE_LENGTH];
  47. char sstr[MAX_LINE_LENGTH];
  48. char f9str[MAX_LINE_LENGTH];
  49. char s9str;
  50. char tempstr[MAX_LINE_LENGTH + 64];
  51. FILE *fdin;
  52. FILE *fdout;
  53. int skip, bp, temp, getout, disp_msg , xken;
  54. f = 1;
  55. printf("Version 08/12/2021 Known issues. See version renum2.c\n");
  56. if (argc > 1) strcpy(pstr, argv[1]);
  57. else
  58. {
  59. printf("Program in file (basic bas file)? ");
  60. myfget=fgets(pstr,MAX_LINE_LENGTH, stdin);
  61. if (strchr(pstr, '\n') != NULL)
  62. {
  63. pstr[strlen(pstr)-1] = '\0'; /* NULL terminate input. Ken */
  64. }
  65. }
  66. if (strlen(pstr) == 0) strcpy(pstr, "0.doc");
  67. if (strcmp(pstr,"editfl.bas") == 0)
  68. {
  69. printf("Can not use editfl.bas as progran in file.\n");
  70. printf("editfl.bas is a backup original of the last run.\n");
  71. printf("Exiting.\n");
  72. exit(1);
  73. }
  74. fdin = fopen(pstr, "rt");
  75. if (fdin == NULL)
  76. {
  77. printf("Unable to open input file. Exiting.\n");
  78. exit(1);
  79. }
  80. strcpy(f9str, pstr);
  81. #if defined(__MVS__) || defined(__CMS__)
  82. strcpy(pstr, "dd:editfl");
  83. #else
  84. strcpy(pstr, "editfl");
  85. #endif
  86. fdout = fopen(pstr, "wt");
  87. /* After editfl is created it is left behind. Ken */
  88. if (fdout == NULL)
  89. {
  90. printf("Unable to open temporary file editfl for output.\n");
  91. printf("Exiting.\n");
  92. exit(1);
  93. }
  94. /* Main program begins here */
  95. s = 0; l2 = 0; d = 0;
  96. f2 = 10000;
  97. printf ("PLEASE WAIT A FEW SECONDS! READING INPUT.\n");
  98. while (fgets(pstr, MAX_LINE_LENGTH, fdin) != NULL)
  99. {
  100. trim(pstr);
  101. p = instr(pstr, " ");
  102. if (p != 0 && p <= 5)
  103. {
  104. n = atoi(midstr2(pstr, 1, p));
  105. if (n != 0)
  106. {
  107. s++;
  108. if( s < MAX_LINE_COUNT )
  109. {
  110. /* OK */
  111. }
  112. else
  113. {
  114. printf("Too many lines. Over %d\n",MAX_LINE_COUNT);
  115. printf("Exiting.\n");
  116. exit(1);
  117. }
  118. sidx[s][0] = n;
  119. s1 = s;
  120. while (s1 >= 2)
  121. {
  122. s1--;
  123. if (sidx[s1][0] < sidx[s1 + 1][0]) break;
  124. if (sidx[s1][0] == sidx[s1 + 1][0])
  125. {
  126. printf("ERROR !!! MORE THAN ONE STATEMENT FOR A ");
  127. printf("STATEMENT NUMBER\n");
  128. printf("Line #%s\n",pstr);
  129. printf("Exiting.\n");
  130. exit(1);
  131. }
  132. t = sidx[s1][0];
  133. sidx[s1][0] = sidx[s1 + 1][0];
  134. sidx[s1 + 1][0] = t;
  135. }
  136. }
  137. }
  138. }
  139. fclose(fdin);
  140. if (s == 0)
  141. {
  142. printf("Programs must start with a number in column 1.\n");
  143. printf("NO PROGRAM IS IN THE FILE!\n");
  144. printf("Exiting.\n");
  145. exit(1);
  146. }
  147. strcpy(pstr, "");
  148. for (l = 1; l <= s; l++)
  149. sidx[l][1] = sidx[l][0];
  150. g = 1;
  151. disp_msg = 1;
  152. /*------------------------------------------------------------------------*/
  153. /* Find out how and what to renumber (using HP BASIC renumber parameters) */
  154. /* MS BASIC renumber is: RENUM (newnum) (,(oldnum) (,increment)) */
  155. /*------------------------------------------------------------------------*/
  156. while(1)
  157. {
  158. if (disp_msg == 1)
  159. {
  160. printf("Enter (-starting number (,interval (,first statement ");
  161. printf("(,last))))\n");
  162. disp_msg = 0;
  163. }
  164. skip = 0;
  165. bp = 0;
  166. printf("RENUMBER-");
  167. myfget=fgets(pstr,MAX_LINE_LENGTH,stdin);
  168. p = strlen(pstr);
  169. if (g == 0)
  170. {
  171. if (strlen(pstr) == 0) break;
  172. if (p == 0) skip = 1;
  173. else
  174. {
  175. t = atoi(midstr2(pstr, 1, 1));
  176. if (t == 0) break;
  177. }
  178. }
  179. if (strlen(pstr) == 0) skip = 1;
  180. if (skip == 0)
  181. {
  182. c = instr(pstr, ",");
  183. temp = 0; if (c != 0) temp = -1;
  184. f1 = atoi(midstr2(pstr, 1, p + temp*(p - c + 1)));
  185. if (f1 == 0) bp = 1;
  186. if (c == 0) skip = 2;
  187. }
  188. if (skip == 0 && bp == 0)
  189. {
  190. c1 = instr(midstr1(pstr, c + 1), ",") + c;
  191. temp = 0; if (c1 != c) temp = -1;
  192. i = atoi(midstr2(pstr, c + 1, p + temp*(p - c1 + 1) - c));
  193. if (i == 0) bp = 1;
  194. if (c1 == c) skip = 3;
  195. }
  196. if (skip == 0 && bp == 0)
  197. {
  198. c = instr(midstr1(pstr, c1 + 1), ",") + c1;
  199. temp = 0; if (c != c1) temp = -1;
  200. f8 = atoi(midstr2(pstr, c1 + 1, p + temp*(p - c + 1) - c1));
  201. if (f8 == 0) bp = 1;
  202. if (c == c1) skip = 4;
  203. }
  204. if (skip == 0 && bp == 0)
  205. {
  206. l = atoi(midstr1(pstr, c + 1));
  207. if (l == 0) bp = 1;
  208. }
  209. if (bp == 0) switch (skip)
  210. {
  211. case 1:
  212. f1 = 10;
  213. i = 10;
  214. f8 = 1;
  215. l = 99999;
  216. break;
  217. case 2:
  218. i = 10;
  219. f8 = 1;
  220. l = 99999;
  221. break;
  222. case 3:
  223. f8 = 1;
  224. l = 99999;
  225. break;
  226. case 4:
  227. l = 99999;
  228. break;
  229. }
  230. if (f1 < 1 || i == 0 || f8 < 1 || l < 1) bp = 1;
  231. if (f1 > 99999 || i > 99999 || f8 > 99999 || l > 99999 || f8 > l)
  232. bp = 1;
  233. c = 0;
  234. for (r = 1; r <= s; r++)
  235. if (sidx[r][0] >= f8 && sidx[r][0] <= l) c = c + 1;
  236. if (c == 0)
  237. {
  238. printf("There is nothing to renumber !!\n");
  239. disp_msg = 1;
  240. }
  241. /*------------------------------------*/
  242. /* Make list of new statement numbers */
  243. /*------------------------------------*/
  244. l1 = f1 + (c - 1)*i;
  245. if (l1 < 1 || l1 > 99999) bp = 1;
  246. x = 0; c = 0;
  247. if (bp == 0 && disp_msg == 0) for (r = 1; r <= s; r++)
  248. {
  249. if (sidx[r][0] < f8 || sidx[r][0] > l)
  250. if (sidx[r][1] >= f1 && sidx[r][1] <= l1)
  251. {
  252. printf("SEQUENCE NUMBER OVERLAP\n");
  253. printf("Exiting.\n");
  254. exit(1);
  255. }
  256. else {}
  257. else
  258. {
  259. if (sidx[r][0] != f1 + c*i)
  260. {
  261. if (x == 0)
  262. {
  263. if (r < f2) f2 = r;
  264. x = 1;
  265. }
  266. if (r > l2) l2 = r;
  267. }
  268. sidx[r][1] = f1 + c*i;
  269. c++;
  270. l3 = r;
  271. }
  272. }
  273. if (bp == 0 && disp_msg == 0) g = 0;
  274. if (bp == 1) printf("BAD PARAMETER\n");
  275. }
  276. /*-------------------*/
  277. /* Start renumbering */
  278. /*-------------------*/
  279. if (l2 == 0)
  280. {
  281. printf("NOTHING RENUMBERED!\n");
  282. exit(1);
  283. }
  284. printf("RENUMBERING\n");
  285. /*
  286. for (r = 1; r <= s; r ++)
  287. printf("%d -> %d\n", sidx[r][0], sidx[r][1]);
  288. */
  289. printf("VERIFY? N or n cancels:");
  290. myfget=fgets(pstr,MAX_LINE_LENGTH,stdin);
  291. v1 = 0;
  292. if (strcmp(midstr2(pstr, 1, 1), "N") == 0) v1 = 1; /* Except n or N. Ken */
  293. if (strcmp(midstr2(pstr, 1, 1), "n") == 0) v1 = 1;
  294. if (v1 == 1) {
  295. printf("Operation cancelledi.\n");
  296. exit(1);
  297. }
  298. fdin = fopen(f9str, "rt");
  299. if (fdin == NULL)
  300. {
  301. printf("Unable to open input file.\n");
  302. exit(1);
  303. }
  304. f6 = sidx[f2][0];
  305. l6 = sidx[l2][0];
  306. while (fgets(pstr, MAX_LINE_LENGTH, fdin) != NULL)
  307. {
  308. trim(pstr);
  309. if (*pstr)
  310. {
  311. b = 0;
  312. if (*pstr>='0' && *pstr<='9')
  313. {
  314. b = instr(pstr, " ");
  315. n = atoi(midstr2(pstr, 1, b));
  316. if (n >= f6 && n <= l6)
  317. {
  318. binary_search();
  319. if (x == 0)
  320. {
  321. strcat(rstr, midstr1(pstr, b));
  322. strcpy(pstr, rstr);
  323. b = instr(pstr, " ");
  324. }
  325. }
  326. b++;
  327. }
  328. /*-------------------------------------------------------------*/
  329. /* There are differences, of course, between processing for HP */
  330. /* BASIC and MS BASIC. */
  331. /* */
  332. /* CONVERT, PRINT USING, and MAT PRINT USING changes are not */
  333. /* applicable in MS BASIC. */
  334. /* */
  335. /* Had to also add capability for multiple statements here. */
  336. /*-------------------------------------------------------------*/
  337. while(1)
  338. {
  339. /* ChipMaste-20210817 skip leading WS to start on a token */
  340. while(pstr[b-1]==' ' || pstr[b-1]=='\t') b++;
  341. xken = 0;
  342. if (strcmp(umids(pstr, b, 3), "REM") == 0 || pstr[b-1]=='\'')
  343. break;
  344. f9 = 0;
  345. skip = 0;
  346. b1 = strlen(pstr);
  347. for (x9 = b-1; x9 < b1; x9++)
  348. {
  349. if (pstr[x9] == '"')
  350. {
  351. f9 = !f9;
  352. }
  353. else if (f9 == 0 && pstr[x9] == ':')
  354. {
  355. b1 = x9; /* NOTE: most of this code runs @ BASIC's 1 base */
  356. }
  357. }
  358. /* GOSub , GOTo , IF , ON , RESet , RETurn , SHEll , PRInt , INPut Ken */
  359. /* 2 3 4 5 6 7 8 9 10 */
  360. t = instr("GOSGOTIF ON RESRETSHEPRIINP", umids(pstr, b, 3));
  361. temp = (t + 5)/3;
  362. if (temp != 1)
  363. {
  364. if (temp == 2 || temp == 3 || temp == 4 ||
  365. temp == 6 || temp == 7 || temp == 8 ||
  366. temp == 9 || temp ==10 )
  367. {
  368. /*---------------------------------------------------------*/
  369. /* Change GOSub, GOTo, IF , REStore, RETurn, SHEll */
  370. /* PRInt , INPut */
  371. /* routine. */
  372. /* Go word by word through the statement. */
  373. /*---------------------------------------------------------*/
  374. getout = 0;
  375. p8 = b;
  376. s9str=' ';
  377. }
  378. else if (temp == 5) /* 5 = ON as in ON ERROR */
  379. {
  380. /*---------------------------------------------------*/
  381. /* Change ON event/expression GOSUB/GOTO routine. */
  382. /* Find starting point appropriate to this statement */
  383. /* type. There are several variations of the ON ... */
  384. /* statments but only the ones with "GOTO" or */
  385. /* "GOSUB" get renumbered. ANd they can have */
  386. /* multiple line numbers. */
  387. /*---------------------------------------------------*/
  388. getout = 1;
  389. x9 = instr(pstr+b-1, " GOTO ");
  390. if(x9) {
  391. x9+=5;
  392. } else {
  393. x9 = instr(pstr+b-1, " GOSUB ");
  394. if(x9) x9+=6;
  395. }
  396. if(x9) {
  397. p8 = x9+b;
  398. getout = 0;
  399. s9str=',';
  400. }
  401. }
  402. /* End of scanning statement */
  403. /* Start looping here */
  404. if (getout == 0) while(1)
  405. {
  406. f9 = 0;
  407. skip = 0;
  408. /* ChipMaster-20210816 skip leading WS */
  409. while(p8<b1 && (pstr[p8-1]==' ' || pstr[p8-1]=='\t'))
  410. p8++;
  411. for (x9 = p8-1; x9 < b1; x9++)
  412. {
  413. /* Is a quote " ? */
  414. if (pstr[x9] == '"')
  415. {
  416. f9 = !f9;
  417. }
  418. else if (f9 == 0 && pstr[x9]==s9str)
  419. {
  420. p9 = x9;
  421. skip = 1;
  422. break;
  423. }
  424. }
  425. if (skip == 0) p9 = b1;
  426. skip = 0;
  427. for (x9 = p8-1; x9 < p9; x9++)
  428. {
  429. /* Is not a digit 0 to 9 ? */
  430. if (pstr[x9] < '0' || pstr[x9] > '9')
  431. {
  432. skip = 1;
  433. break;
  434. }
  435. }
  436. if (skip == 0)
  437. {
  438. /*---------------------*/
  439. /* Found a line number */
  440. /*---------------------*/
  441. n = atoi(midstr2(pstr, p8, p9 - p8 + 1));
  442. if (n != 0)
  443. {
  444. if (n >= f6 && n <= l6)
  445. {
  446. binary_search();
  447. if (x == 0)
  448. {
  449. if (p9 == strlen(pstr))
  450. {
  451. strcpy(tempstr, midstr2(pstr, 1, p8 - 1));
  452. strcat(tempstr, rstr);
  453. strcpy(pstr, tempstr);
  454. }
  455. else
  456. {
  457. strcpy(tempstr, midstr2(pstr, 1, p8 - 1));
  458. strcat(tempstr, rstr);
  459. strcat(tempstr, midstr1(pstr, p9 + 1));
  460. strcpy(pstr, tempstr);
  461. }
  462. /*-----------------------------------*/
  463. /* Adjust indices to account for new */
  464. /* substring length, if any. */
  465. /*-----------------------------------*/
  466. d9 = strlen(rstr) - (p9 - p8 + 1);
  467. p9 = p9 + d9;
  468. b1 = b1 + d9;
  469. }
  470. }
  471. }
  472. }
  473. p8 = p9 + 2;
  474. if (p8 > b1) break;
  475. }
  476. }
  477. /*--------------------------------------------------*/
  478. /* No more words to process in the statement, go to */
  479. /* next statement. */
  480. /*--------------------------------------------------*/
  481. if (b1 == strlen(pstr)) break;
  482. b = b1 + 2;
  483. }
  484. }
  485. fprintf(fdout, "%s\n", pstr);
  486. if (v1 == 0) printf("%s\n", pstr);
  487. }
  488. fclose(fdin);
  489. fclose(fdout);
  490. /* 11-2019 Ken */
  491. #if !defined(__MVS__) && !defined(__CMS__) && !defined(MSDOS)
  492. tempstr[strlen(tempstr)] = '\0';
  493. sprintf(tempstr, "cp %s editfl.bas", f9str);
  494. myretn=system(tempstr);
  495. printf("\nOriginal basic program is stored in editfl.bas\n\n");
  496. sprintf(tempstr, "cp editfl %s", f9str); /* Linux type systems use cp. Ken */
  497. myretn=system(tempstr);
  498. sprintf(tempstr, "rm editfl");
  499. myretn=system(tempstr);
  500. #endif
  501. #if defined(MSDOS)
  502. tempstr[strlen(tempstr)] = '\0';
  503. sprintf(tempstr, "copy %s editfl.bas", f9str); /* MSDOS no cp command. Ken */
  504. myretn=system(tempstr);
  505. printf("\nOriginal basic program is stored in editfl.bas\n\n");
  506. sprintf(tempstr, "copy editfl %s", f9str);
  507. myretn=system(tempstr);
  508. sprintf(tempstr, "del editfl");
  509. myretn=system(tempstr);
  510. #endif
  511. return (0);
  512. }
  513. /* 20210826 ChipMaster - make a case insensitive compare */
  514. int instr(astr, bstr)
  515. char *astr, *bstr;
  516. {
  517. char *p, *compa, *compb, ca, cb;
  518. int q;
  519. for(p=astr; *p; p++) {
  520. for(compa=p, compb=bstr; *compa && *compb; compa++, compb++) {
  521. /* if lcase letter make ucase for comparison */
  522. ca = *compa>='a' && *compa<='z' ? *compa&95 : *compa;
  523. cb = *compb>='a' && *compb<='z' ? *compb&95 : *compb;
  524. if(ca!=cb) break; /* no match */
  525. }
  526. if(!*compb) return p-astr+1; /* ooh! we matched bstr */
  527. if(!*compa) return 0; /* unsearched astr is now shorter than bstr */
  528. }
  529. return 0; /* JIC */
  530. }
  531. char *midstr1(astr, start)
  532. char *astr;
  533. int start;
  534. {
  535. static char tempstr[MAX_LINE_LENGTH];
  536. char *startptr;
  537. strcpy(tempstr, astr);
  538. startptr = &tempstr[start - 1];
  539. return startptr;
  540. }
  541. char *midstr2(astr, start, len)
  542. char *astr;
  543. int start, len;
  544. {
  545. static char tempstr[MAX_LINE_LENGTH];
  546. char *startptr, *endptr;
  547. strcpy(tempstr, astr);
  548. startptr = &tempstr[start - 1];
  549. endptr = ((tempstr) + start + len - 1);
  550. strcpy(endptr, "\0");
  551. return startptr;
  552. }
  553. /* 2021-08-15 ChipMaster: a MID$() to aid with case insensitivity */
  554. char *umids(char *astr, int start, int len) {
  555. static char buf[MAX_LINE_LENGTH];
  556. char *p;
  557. buf[0]=0;
  558. if(start<1 || len<1) return buf; /* JIC */
  559. for(start--; start; start--) if(!*astr++) return buf;
  560. if(len>MAX_LINE_LENGTH-1) len = MAX_LINE_LENGTH-1; /* have to leave room for \0 */
  561. for(p=buf; *astr && len; len--) {
  562. if(*astr>='a' && *astr<='z') *p++=(*astr++ & 95); /* UCASE it */
  563. else *p++=*astr++;
  564. }
  565. *p=0;
  566. return buf;
  567. }
  568. void binary_search(void)
  569. {
  570. int f5, l5;
  571. f5 = f2;
  572. l5 = l2 + 1;
  573. while(1)
  574. {
  575. int m;
  576. m = (f5 + l5)/2;
  577. if (sidx[m][0] == n)
  578. {
  579. rstr[strlen(rstr)] = '\0';
  580. sprintf(rstr, "%d", sidx[m][1]);
  581. x = 0;
  582. return;
  583. }
  584. if (m == f5 || m == l5)
  585. {
  586. x = 1;
  587. return;
  588. }
  589. if (sidx[m][0] < n)
  590. f5 = m;
  591. else
  592. l5 = m;
  593. }
  594. }
  595. /* Chipmaster 8-2021 */
  596. void trim(char *s) {
  597. char *p, *e;
  598. /* First trim EOL WS */
  599. for(p=s, e=0; *p; p++) if(*p>' ') e=p;
  600. if(e) *++e=0;
  601. /* Then trim BOL WS */
  602. for(p=s; *p && *p<=' '; p++) ;
  603. if(p==s) return;
  604. for(; *p; p++) *s++=*p;
  605. *s=0;
  606. }