02.03.08
Reading Old GW-Basic Programs
I found a disk image I’d made of an old hard drive of mine today (circa 1995) and had some fun browsing through my files. Back then, I was programming in a combination of QBASIC and GW-BASIC. It’s easy to read old QBASIC programs, since QB saved code as human-readable text.
Not so, GW-BASIC. To save space, it stored code in a compact, binary format. This seems like an unnecessary optimization now, but back in 1984 it made a lot of sense. GW-BASIC was an interactive environment, and it stored all your code in memory. Memory was a scarce resource at the time, so every byte counted. Hence the binary format.
I wanted to read my old GW-BASIC programs, so I dug around and found this discussion of the GW-BASIC binary file format. It’s incredibly detailed, which let me whip up a decoder in Python over two solid hours of hacking. Without further ado, here it is:
For a sample decoding, see below the fold.
Here’s a 20-questions style program I wrote on August 15, 1995:
10 CLS 20 DIM G$(15),RP(15),RD(15) 30 PRINT "In this game I will make up a three digit code. The code will be between 100 and 999. You have 15 guesses. After each guess, I will tell you how many digits are correct and how many are in the right position. If you enter an invalid guess, "; 35 PRINT "or a duplicate answer, I will let you try again. " 40 PRINT 50 PRINT "Press any key when ready. . . " 60 GOSUB 1000 70 CLS 80 GOSUB 2000 90 IF CODE < 100 OR CODE >999 THEN GOTO 80 100 CODE$=RIGHT$(STR$(CODE),3) 110 D$=CODE$ 120 FLAG=0 130 GOSUB 1500 140 IF FLAG=1 THEN GOTO 80 150 FOR I=1 TO 15 160 CLS 170 IF I=1 THEN GOTO 230 180 FOR J=1 TO I-1 190 PRINT "Guess #";J;": ";G$(J);". results: "; 200 PRINT "digits: ";RD(J);"positions: ";RP(J) 210 NEXT J 220 REM 230 PRINT 240 PRINT "enter guess #";I; 250 INPUT G 260 IF G<100 OR G>999 THEN 240 270 G$(I)=STR$(G) 280 IF LEN(G$(I))=0 THEN GOTO 240 290 G$(I)=RIGHT$(G$(I),3) 300 D$=G$(I) 310 FLAG = 0 320 GOSUB 1500 330 IF FLAG=1 THEN GOTO 240 340 FLAG=0 350 GOSUB 1400 360 IF FLAG=1 THEN 240 370 GOSUB 1100 380 IF RP(I)<>3 THEN GOTO 410 390 PRINT "Good job!! You guessed the code in";I;"try's." 400 END 410 NEXT I 420 PRINT "Your guesses are up!" 430 PRINT "The code was";CODE$ 440 END 1000 R$=INPUT$(1) 1010 RETURN 1100 FOR K=1 TO 3 1110 FOR L=1 TO 3 1120 G$=MID$(G$(I),K,1) 1130 C$=MID$(CODE$,L,1) 1140 IF G$<>C$ THEN GOTO 1170 1150 IF K<>L THEN RD(I)=RD(I)+1 1160 IF K=L THEN RP(I)=RP(I)+1 1170 NEXT L 1180 NEXT K 1190 RETURN 1400 IF I=1 THEN RETURN 1410 FOR K=1 TO I-1 1420 IF G$(I)=G$(K) THEN FLAG=1 : RETURN 1430 NEXT K 1460 RETURN 1500 REM 1510 FOR K=1 TO 3 1520 FOR L=K+1 TO 3 1530 IF MID$(D$,K,1)=MID$(D$,L,1) THEN FLAG=1: RETURN 1540 NEXT L 1550 NEXT K 1560 RETURN 2000 OPEN "r", 1, "b:amunt.ran", 2: FIELD 1, 2 AS T$ 2010 IF LOF(1)=0 THEN CODE = INT(100+RND*999): T$=MKI$(0): GOTO 2050 2020 GET 1,1 2030 FOR I=1 TO CVI(T$): CODE=RND:NEXT 2040 CODE = INT(100+RND*999) 2050 LSET T$=MKI$(CVI(T$)+1): PUT 1,1 2060 CLOSE #1: RETURN
Oh, for the days of unstructured programming and rampant use of the “GOTO” statement. The convention was to number your lines 10, 20, 30, … so that you could go back and add extra lines between your originals. Hence line 35 above. I must have been really ambitious jumping to line 1000!
aqeel said,
April 12, 2010 at 12:01 am
please give this version
CVI Program said,
May 27, 2011 at 6:03 am
Hello,
I just wanted to take a minute to tell you that you have a great site!
Keep up the good work…..