LBSOS KRNLI/O ERRORFILE 'SOS.KERNEL' NOT FOUNDINVALID KERNEL FILExةw,@  4  J  ȱ⩤i8#) ) 8LeARTICLE3vR' ')ARTICLE.3 ,UR /DATA.PARTS.PROG E RMINPUTEXAMPLE 5OR!-LIST.PARTS 4<R! +NUMBERFILE1 >R;)*NUMBERFILEAjKŸ/ DISKNAME.DATM#k7k7MENU.MKAER  Gk8k8III.BSB.03IC.01u' ARTICLE3R<ARTICLE4OR<ARTICLE5R<*MENU.MAKER K;+READCRT.INV!t%SEG.T m#im#iЛ#Lȱ  6L憦  Lsmm l y` @8(Je稽 ʈR;,*PARTS.PROG 7d R;9 PRINT.DATA C8R!TESTNUMBER KR! TESTNUMBER1 LR!& ONEMR- TWONR-  T H E T H I R D B A S I C Taylor Pohlman Exploring Business BASIC, Part Three Lots has happened to the Apple III since my last article, and I appreci9 PRINT" 9 to Quit":PRINT 50 PRINT:INPUT"Your selection: ";a$ 60 IF a$="" THEN 1000 70 a=ABS(VAL(a$)) 80 ON a GOSUB 100,400 90 IF a=9 THEN 1000:ELSE 5 100 PRINT:INPUT"Name of new parts file: ";a$ 110 IF a$="" THEN RETURN 120 Citement, here's the new version of the program: 5 HOME 7 PRINT 10 PRINT"Parts File Create and Modify Program" 20 PRINT:PRINT"Type:" 30 PRINT" 1 to Create a parts file":PRINT 40 PRINT" 2 to Use an existing parts file":PRINT 4 making your own changes. In addition, I have generalized some of the functions that the program performs into subroutines, so that we can make changes later without wholesale rewriting. The new Parts Program Well, now that you're breathless with excample, we could only perform two functions, creating files and adding records. Most parts companies would want to look up parts, delete parts, get lists of parts, etc. This month's version gets closer to that ideal, without denying you some of the fun oftion was the part number, a description of the part, the location where the part was stored, and the quantity on hand. Unfortunately, the program was just designed to make some clever points about files, not to really be useful to parts companies. For exe type, it's going to be necessary to create a more general version of last month's program. Last month's example program allowed us to create a file which contained four pieces of information about a hypothetical parts distribution company. This informaod which wastes very little space in storing records on the disk, even if they have widely different record numbers. To go into further depth on this subject, and to compare the TEXT file type we were working with last time to the more mysterious DATA fillows file records to be numbered from 0 to 32767 and read directly without having to read all records from the beginning of the file. The example I gave at the end of last month's article also demonstrated that SOS uses a special storage and indexing meth last article concluded with an example program that showed how the SOS file system could be used to store and rapidly find records in a file. We did that by using the random file access method that SOS and Business Basic have built in. That technique alck with relatively simple indexing techniques for now, but next month we'll also cover some advanced indexing and file access methods to give you an idea of some of the ways that the popular "Data Base" programs retrieve data so rapidly. Looking Back The last time. After reading this article and working with the examples, you should have a good knowledge of the differences between the TEXT and DATA file types as well as more information about string handling functions and techniques. We are going to sti  !"#$%&'()*+,-./0123ate all your comments about the articles in this series. We'll have a chance to pick up on some of your suggestions next month, along with more news about the Apple III. For now we'll continue our exploration of the Business Basic file system as promisedREATE a$, TEXT,64 130 PRINT"Parts file ";a$;" created." 140 RETURN 400 HOME 405 PRINT:INPUT"Name of existing parts file: ";a$ 410 IF a$="" THEN RETURN 420 OPEN#1,a$ 425 file$=a$ 430 HOME 435 PRINT:PRINT"Modify Parts File ";CHR$(34);file$;CHR$(34):PRINT 437 PRINT"Type:" 440 PRINT" 1 to add to your parts file":PRINT 445 PRINT" 2 to delete a part from your parts file":PRINT 450 PRINT" 3 to find a part in your parts file":PRINT 460 PRINT" 9 to quit the ming as we went along! Let's take a quick look at the changes in this version of the program, as well as its major features. First, as to structure, the program looks something like this: 5-90 Initialization and first menu 100-140 Create a ne2005 errorcode=0 2010 rec$=partnum$+"/"+desc$+"/"+location$+"/"+quantity$+"/" 2015 ON ERR GOTO 2040 2020 PRINT#1,rec;rec$ 2030 OFF ERR:RETURN 2040 errorcode= ERR:OFF ERR:RETURN Well, nobody said that this series wouldn't get more interestuantity$=MID$(rec$,pointer,length) 1890 errorcode=0:RETURN 1899 REM 1900 REM delete a record with record number = "rec" 1901 REM 1905 PRINT#1,rec;"" 1910 RETURN 1999 REM 2000 REM add a record with record number = "rec" 2001 REM nter=pointer+length+1:length= FN scan(pointer) 1857 Desc$=MID$(rec$,pointer,length) 1860 pointer=pointer+length+1:length= FN scan(pointer) 1870 Location$=MID$(rec$,pointer,length) 1875 pointer=pointer+length+1:length= FN scan(pointer) 1885 QREM 1805 errorcode=1 1810 ON EOF#1 RETURN 1820 DEF FN scan(start)=INSTR(rec$,"/",start)-start 1830 INPUT#1,rec;rec$ 1835 IF rec$="" THEN RETURN 1840 pointer=1:length= FN scan(pointer) 1850 partnum$=MID$(rec$,pointer,length) 1855 poiTO 800 899 REM 900 REM delay subroutine 901 REM 995 FOR i=1 TO 1000:NEXT i:RETURN 996 REM 1000 PRINT:PRINT"End of parts file program." 1010 CLOSE 1020 END 1799 REM 1800 REM retrieve a record with record number = "rec" 1801 850 PRINT:PRINT"Part number: ";partnum$ 855 PRINT:PRINT"Description: ";desc$ 860 PRINT:PRINT"Location: ";location$ 865 PRINT:PRINT"Quantity on hand: ";quantity$ 870 PRINT 890 PRINT:INPUT"Press RETURN to continue: ";a$:GO0 HOME:PRINT 805 INPUT"Part number to find: ";a$ 810 IF a$="" THEN RETURN 815 a=VAL(a$) 820 IF a<1 OR a>32767 OR INT(a)<>a THEN 800 825 rec=a 830 GOSUB 1800 840 IF errorcode=1 THEN PRINT:PRINT"No such part number":GOSUB 995:GOTO 800 e ";partnum$;"/";desc$;"/";location$;"/";quantity$;"? "; 745 INPUT"";a$:a$=MID$(a$,1,1) 750 IF a$<>"y" AND a$<>"Y" THEN PRINT"Not deleted":GOSUB 995:GOTO 700 755 GOSUB 1900 760 PRINT:PRINT CHR$(7);CHR$(7);"Record deleted":GOSUB 995:GOTO 700 80PRINT:INPUT"Part number to Delete: ";a$ 710 IF a$="" THEN RETURN 715 a=VAL(a$) 720 IF a<1 OR a>32767 THEN 700 725 rec=a 730 GOSUB 1800 735 IF errorcode=1 THEN PRINT:PRINT CHR$(7);"No such part number":GOSUB 995:GOTO 700 740 PRINT"Delet(a$,1,1):IF a$<>"y" AND a$<>"Y" THEN 505 660 GOSUB 2000 665 IF errorcode=0 THEN PRINT:PRINT"Record added.":GOSUB 995:GOTO 500 670 PRINT:INVERSE:PRINT"Record not added, ERROR= ";:NORMAL:PRINT errorcode:G OSUB 995:GOTO 505 700 HOME 705 ) 590 location$=a$ 600 PRINT:INPUT"Quantity on hand: ";a$ 610 a=0:a=VAL(a$):IF INT(a)<>a OR a>99999 THEN 600 620 quantity$=a$ 630 PRINT:PRINT"Record is: ";partnum$;"/";desc$;"/";location$;"/";quantity$; 640 INPUT" Ok? ";a$ 650 a$=MID$L(a$) 530 IF a<1 OR a>32767 OR INT(a)<>a THEN 500 535 rec=a 540 partnum$=a$ 545 PRINT:INPUT"Description: ";a$ 550 IF LEN(a$)>35 THEN a$=MID$(a$,1,35) 560 desc$=a$ 570 PRINT:INPUT"Location: ";a$ 580 IF LEN(a$)>15 THEN a$=MID$(a$,1,15odify mode":PRINT 465 PRINT:INPUT"Your selection: ";a$ 467 a=ABS(VAL(a$)) 470 IF a=9 OR a$="" THEN RETURN 475 ON a GOSUB 500,700,800 480 GOTO 430 500 HOME 505 PRINT:INPUT"Part number to add: ";a$ 510 IF a$="" THEN RETURN 520 a=VAw parts file 400-480 Open an existing file and set up second menu 500-670 Add a record 700-760 Delete a record 800-890 Find and display a record 900-995 Subroutine to create a delay 1000-1020 Terminate the program and close files 1800-1890 Subroutine to find a record and load data values 1900-1910 Subroutine to physically delete a record 2000-2040 Subroutine to add a record with given data values Note that for simplicity we have assumed a fixed file record structure. That is, y well become much more interesting. The add routine is also simple, consisting (at line 2010) of packing the various field values together using the String Concatenation Operator (the world's longest way to refer to "+"). There is one thing of interest,t by changing the routine at 1800 rather than making changes throughout the program. The delete routine at line 1900 is really simple, just consisting of printing a "null" record over a previously existing record. As we change the file structure, this ma are assigned to the proper variable, they can be used in the calling routines (at lines 730 and 830) to display the values as desired. Later on we are going to change the structure of this file considerably, and it will be handy to be able to handle thaappropriate variable. Study this section carefully to be sure you see how this works. My technique to understand routines like this is to make a diagram of the data and work through the statements while "playing computer". Now that the individual fieldslds. This is done by setting the variable "pointer" to the beginning of the field and then setting length to the number of characters in the field using the "scan" function defined previously. The MID$ function then is used to make the assignment to the for this function (POS is one example I know of). Line 1830 inputs the record according to the record number "rec". After checking for a "null" string (line 1835), lines 1840 through 1885 are responsible for breaking up the record into its separate fiealue from the position gives the total length of the field. More about INSTR can be found in the Business Basic manual. Give that section a look, because INSTR is one of the most useful functions you'll find. Some other Basics may use a different name t we used the "/" character to delimit the fields within the string record we stored in the file. The INSTR function returns the character position of the string being searched for, starting with the position given by "start". Subtracting the starting vads past the current end of file. Line 1820 sets up a function definition that comes in pretty handy. The function "scan" uses the Basic INSTR function to determine how many characters there are to the next occurrence of the "/" character. Remember thaWe will communicate any problems encountered in a subroutine by using the "errorcode" variable, with 0 indicating no error found. The ON EOF statement in line 1810 will return with "errorcode" set to 1 in the event that the INPUT statement in line 1830 rerogram and to also check out a few new features that make Business Basic really handy, let's look at the subroutines in the program. First, examine the record retrieval routine at line 1800, which is used by the "Find" section and the "Delete" section. sting items. Obviously, the more such generalizations we put in the program, the larger and more complex it will be. Our purpose is to learn something about files first, and then to write the world's greatest database program. To help understand the p real "data base" program would have all this information stored in tables for more flexibility. For example, there is no practical way, short of rewriting parts of the program, to add an extra data item to the records, or to change the meaning of the exiwe have "hard coded" into the program the fact that the data items in each record are Part number, Description, Location, and Quantity on hand. We have also coded into the program some restrictions as to the length of each item (lines 550,560 and 610). A however. Note that the ON ERR statement is used to trap any errors which may occur in writing to the file. We again use "errorcode" to communicate that an error has occurred, and are careful to turn error trapping off before returning to the main routine. It would have been possible and even desirable to use the ON ERR statement to check for all errors in the program, but the routine required to make the program that "bulletproof" would have made this program unnecessarily long. That's probably a good on. Try this with values like 500 and 4.25. Everything should go normally. Now try a value like 3.033 and .031. Still ok. Now try 3.031 and .031. The result should print out appearing exactly the same, yet the comparison in line 60 fails. If you wismpare: ";z,z1 80 GOTO 20 Note that by printing the value to the file with the random access method in line 40, we are able to read it back directly in line 50. This lets us check to see if any value change has occurred as a result of the file operati text file than they were in memory. A short example will illustrate: 10 OPEN#1,"numberfile" 20 INPUT"type two numbers: ";x,y 30 z=x*y 40 PRINT#1,1;z 50 INPUT#1,1;z1 60 IF z=z1 THEN PRINT"they compare":GOTO 20 70 PRINT"they don't coces than can be displayed, then the number is rounded before printing. By contrast, this does not occur with integers. Since rounding occurs during printing, and text files are storage of the printed format, values of real numbers may be different in theh the space that this notation takes up that causes the trouble, but the fact that the printed representation of a "real" may not correspond exactly to the value stored in memory. If the representation of a number is not exact or requires more decimal plary small. In those circumstances, Basic will display the number in "scientific notation". This means that the output format of a "real" can vary from something simple like "3.45" to something like "-1.36723E-06". Interestingly enough, it is not so mucin Business Basic as 32 bit floating point quantities requiring four bytes of internal storage. Normally they are displayed with six digits of precision, and the format itself may vary greatly, especially if the magnitude of the number is very large or ve even more acute for the "long integer" data type, which can be up to nineteen digits long, but only requires 8 bytes of internal storage. There's another problem with using text files which only shows up when using "real" numbers. Reals are represented a file. Furthermore, it is not possible to tell beforehand just how much space a given set of numeric variables will take, without checking each one beforehand. This can cause some design problems for programmers. As you can imagine, these problems areds with the "%" character) occupies two bytes of storage in memory. However, representing the value in string format can take up to six bytes (-32000 for example). Add a RETURN character to delimit it and you have up to seven bytes to store an integer infile, it will automatically be converted to a string value, just as is done when printing numbers to the screen. This sounds pretty nice, but it can cause some inconvenience and some real problems. For example, you know that an integer variable (which enain data, Business Basic uses the term "DATA files" in a special way. You may remember that a TEXT file consists of strings of characters with the "carriage return" character as the terminator between strings. If you print a numeric variable into a text ss or elegance of coding style. As you add records, then find and delete them, try to imagine ways you could improve the way the program works, or how it asks for information. Business Basic "DATA" files While it is certainly true that most files contsubject for a future article. Well, now that we've been through the major features of the program, I suggest that you enter the program and start fooling around. As I mentioned last time, this program was never meant to be the ultimate in user friendlineh you can insert a statement at line 75 to print out the difference. It will be small, but obviously significant. For the real reason why the product of this pair of numbers fails to work, I commend you to your local math professor or textbook on numerical analysis. Suffice it to say that certain real numbers cannot be stored exactly as binary numbers nor can certain binary numbers be displayed exactly in a finite number of digits. As soon as these situations occur, the quantities stored in the text filss of splitting them out of the string record. I must confess, however, that I really wanted to discuss the INSTR function, and that previous technique seemed the most logical way to show its features. Oh, well, its always more fun to find an easier way!820 READ#1,rec;partnum%,desc$,location$,quantity 1825 IF partnum%<0 THEN RETURN 1830 partnum$=num$(partnum%) 1840 quantity$=num$(quantity) That's it! Since all the items are stored separately, there is no need to go through the procentry section of the program. Next comes the changes to the subroutine which reads a record back. Now things are really very simple. We can replace all the lines between 1820 and 1885 with these: 1815 read#1,rec:IF TYP(1) = 5 THEN RETURN 1 packing all the strings together as we did in the old line 2010, we simply converted the string values to the appropriate numeric ones. If we had designed the program to use data files from the beginning, we would probably have handled that in the data eThe new statements look like this: 2010 partnum%= VAL(partnum$):quantity= VAL(quantity$) 2020 WRITE#1,rec;partnum%,desc$,location$,quantity There, that was easy. Note that WRITE was substituted for PRINT since this is a DATA file, and instead ofata. Description and location are string quantities, and quantity on hand will fit nicely into a "real" value, since it is a maximum of 5 digits (line 610 checks for that). The first subroutine to change is the one at line 2000 which writes a record. ubroutines, the other changes are minimal as well. The idea is to store each item we used before (part number, description, etc.) as a separate data item in the file. Since the part number is always a 4 digit number, we can use an integer to store that dginning of the article. First, we'll need to change the file type specification on the CREATE statement at line 120. The new line will look like this: 120 CREATE a$, DATA,64 Since the program was fairly modular, with the file access done in sany information about it beforehand. Much more information about DATA files can be found in your manual, and I suggest you spend some time reviewing it. In the meantime, lets look at a what using DATA files will do to the parts program I listed at the bestrings in any order and still read them back correctly. The information about the type of a particular data item is retrieved, astoundingly enough, by the TYPe function. This allows a simple program to read the contents of any DATA file, without having might happen to the information. In addition, Business Basic adds an identifier to the front of each item of data you store in a DATA file, to indicate what kind of data it is. This is called the data Type, and allows you to intermix integers, reals and character, the text file input statement will terminate wherever the RETURN occurs, thereby losing the rest of the characters in the string. The key is that with DATA file format, you can store any numeric or string quantity without worrying about what from time to time to store numbers in a file in the exact form which they have in memory. Can you think of a circumstance where you might want to do that with a string? Right! Among others, if you have a string which contains (or could contain) a RETURNe will not exactly match what was calculated in memory. Play around with this program further. There are nearly infinite numbers of combinations which will also fail the test, but appear to be equal. You've just seen two reasons why there is a need Two more things are of interest here. Note that we have checked in line 1815 for TYPe 5 which indicates end of file. This takes care of checking for empty records. In line 1825 we introduce a new concept. Previously, when we wanted to delete a record we simply printed a null string over the existing information. There are times when it is useful to only "flag" that a record is deleted, not actually wipe the information out. This allows deleted information be retrieved in the event of mistakes. Peri689:;<1000:5$d:"Name of new parts file: ";a$ na$="" xa$,,64!"Parts file ";a$;" created."):"Name of existing parts file: ";a$ a$="" #1,a$ file$=a$/:"Modify Parts File ";34);file$;34): "Type:")b + "Parts File Create and Modify Program":"Type:"&" 1 to Create a parts file":-(" 2 to Use an existing parts file":1" 9 to Quit":2:"Your selection: ";a$<a$=""1000Fa=a$))Pa100,400Za=9M #1,".console"a$a$ (#1;a$ 2#1;a$<a$ F#1;a$P#2:#2"End of file after ";rec-1" records.": "Name of Parts file: ";a$ #1,a$("Name of list file: ";2a$ <#2,a$ Fž#11000Prec=132767Z#1,rec:1)=5200)d#1;partnum%,desc$,location$,quantitynpartnum%<0200)x#2;partnum%,desc$,location$,quantityrec0it should be fun to go through some tips on how to make your printouts look like professional reports. Until then, have fun practicing the "facts of life" (programming facts, of course). mple record number scheme that has been used so far. That should complete the effort to make you a "file expert". In addition, Business Basic has an incredible output formatting capability, and now that you have learned the techniques for storing data, ext time we'll cover some new but related topics which will require completely rewriting this month's program (just a JOKE!). We will actually talk about different kinds of ways to store and retrieve records on disk which give more flexibility than the siular your program design, the more painless is the making of inevitable changes. I know that isn't your favorite fact of life, but there is nothing worse than to stare at several thousand lines of BASIC knowing that it has to be completely rewritten. Nst about do it. In addition to giving you several things to try out before next time, the above changes illustrate an important programming "fact of life" (you've been waiting for this article to get juicy, right?). This fact of life is that the more modlete" routine now will look like this: 1905 partnum%=-partnum% 1907 WRITE#1,rec;partnum%,desc$,location$,quantity That will write the record out with a negative part number, which will flag it as "logically" deleted. Well, that should juodically another routine can be used which goes through the file and physically deletes the "flagged" records. Here, and below in the actual delete routine, we use making the part number negative to indicate that it is no longer an active record. The "de" 1 to add to your parts file":5" 2 to delete a part from your parts file":1" 3 to find a part in your parts file":'" 9 to quit the modify mode"::"Your selection: ";a$a=a$))a=9a$=""a500,700,800 ,=?"\"+desc$+"\"+location$+"\"+quantity$+"\" œ2040#1,rec;rec$:errorcode=::ointer+length+1:length=scan(pointer)$]Quantity$=rec$,pointer,length)berrorcode=0:k0l delete a record with record number = "rec"mq#1,rec;""v- add a record with record number = "rec"errorcode=0;rec$=partnum$+$0pointer=1:length=scan(pointer)#:partnum$=rec$,pointer,length)3?pointer=pointer+length+1:length=scan(pointer) ADesc$=rec$,pointer,length)3Dpointer=pointer+length+1:length=scan(pointer)$NLocation$=rec$,pointer,length)3Spointer=p delay subroutinei=11000:i:#:"End of parts file program."2 retrieve a record with record number = "rec"  errorcode=1 ž#1*scan(start)=rec$,"\",start)-start&#1,rec;rec$+rec$=""ec=a >18004Herrorcode=1:"No such part number":995:800$R:"Part number: ";partnum$!W:"Description: ";desc$%\:"Location: ";location$%a:"Quantity on hand: ";quantity$f+z:"Press RETURN to continue: ";a$:800c$;"\";location$;"\";quantity$;"? ";"";a$:a$=a$,1,1)/a$<>"y"a$<>"Y""Not deleted":995:700 1900+:7);7);"Record deleted":995:700 :%"Part number to find: ";a$ *a$="" /a=a$)4a<1a>32767a)<>a800 9r500<::"Record not added, ERROR= ";::errorcode:995:505#:"Part number to Delete: ";a$ a$="" a=a$)a<1a>32767700 rec=a 18009errorcode=1:7);"No such part number":995:700C"Delete ";partnum$;"\";desX:"Quantity on hand: ";a$&ba=0:a=a$):a)<>aa>99999600lquantity$=a$Dv:"Record is: ";partnum$;"\";desc$;"\";location$;"\";quantity$;" Ok? ";a$'a$=a$,1,1):a$<>"y"a$<>"Y"505 2000.errorcode=0:"Record added.":995:430 :"Part number to add: ";a$ a$="" a=a$)a<1a>32767a)<>a500 rec=apartnum$=a$!:"Description: ";a$&a$)>35a$=a$,1,35) 0desc$=a$::"Location: ";a$Da$)>15a$=a$,1,15)Nlocation$=a$$X:"Quantity on hand: ";a$&ba=0:a=a$):a)<>aa>99999600lquantity$=a$Dv:"Record is: ";partnum$;"\";desc$;"\";location$;"\";quantity$;" Ok? ";a$'a$=a$,1,1):a$<>"y"a$<>"Y"505 2000.errorcode=0:"Record added.":900430 :"Part number to add: ";a$ a$="" a=a$)a<1a>32767a)<>a500 rec=apartnum$=a$!:"Description: ";a$&a$)>35a$=a$,1,35) 0desc$=a$::"Location: ";a$Da$)>15a$=a$,1,15)Nlocation$=a" 1 to add to your parts file":5" 2 to delete a part from your parts file":1" 3 to find a part in your parts file":'" 9 to quit the modify mode"::"Your selection: ";a$a=a$))a=9a$=""a500,700,8DFGHIJ1000:5$d:"Name of new parts file: ";a$ na$=""xa$,,64 !"Parts file ";a$;" created."):"Name of existing parts file: ";a$ a$="" #1,a$ file$=a$/:"Modify Parts File ";34);file$;34): "Type:") + "Parts File Create and Modify Program":"Type:"&" 1 to Create a parts file":-(" 2 to Use an existing parts file":1" 9 to Quit":2:"Your selection: ";a$<a$=""1000Fa=a$))Pa100,400Za=9:"End of file after ";rec-1" records."6 "Name of Parts file: ";a$ #1,a$("Name of list file: ";2a$ <#2,a$ Fž#11000Prec=132767Z#1,rec:1)=5200)d#1;partnum%,desc$,location$,quantitynpartnum%<0200)x#2;partnum%,desc$,location$,quantityrec,.094023 03 @B95:500<::"Record not added, ERROR= ";::errorcode:995:505#:"Part number to Delete: ";a$ a$="" a=a$)a<1a>32767700 rec=a 18009errorcode=1:7);"No such part number":995:700C"Delete ";partnum$;"\";desc$;"\";location$;"\";quantity$;"? ";"";a$:a$=a$,1,1)/a$<>"y"a$<>"Y""Not deleted":995:700 1900+:7);7);"Record deleted":995:700 :%"Part number to find: ";a$ *a$="" /a=a$)4a<1a>32767a)<>a800 ARTICLE4vR' ')ARTICLE.4\7jR O,CHANGES.PROG YRQ OLISTROUTINE$RQO-NEW.PROG.DATA Q RQ(OPARTS.LIST <RQ" O.SORT.PROG.DATA OLUME NAME (/DISKNAME) OR DEVICE NAME (.Dx)"P12);::"80C";a$;:Zb$="CHANGING DISKS"$d=23:=0::"80C";b$;::12).n=12:=20:"MAKE A NEW MENU FOR DISK: ";N$xN$)<2110=N$ :210 I=1L(A$(I),A$))200B$(/ WAP /// SIG MENU.MAKER PROGRAM (v. 6.1) =".D1"210: Coldstart (320: Warmstart &*X=11000: TEXT SLOW-DOWN LOOP ,X.1 CHANGE DISK SUBROUTINE23œ202:2200<RFa$=" YOU MAY SELECT YOUR DISK BY VThe Third Basic by Taylor Pohlman  #1,"numberfile1""type two numbers: ";x,y z=x*y (#1,1;z 2#1,1;z1<z=z1"they compare":20 F"they don't compare: ";z,z1K"5#.6#,3x,5#.6#";z,z1 Lz-z1P20 #1,"numberfile""type two numbers: ";x,y z=x*y (#1,1;z 2#1,1;z1<z=z1"they compare":20 F"they don't compare: ";z,z1P20rec"errorcode=0.partnum%=partnum$):quantity=quantity$) œ2040-#1,rec;partnum%,desc$,location$,quantity:errorcode=::!partnum%<0.&partnum$=partnum%):quantity$=quantity)berrorcode=0:k0l delete a record with record number = "rec"mqpartnum%=-partnum%-s#1,rec;partnum%,desc$,location$,quantityv- add a record with record number = "800 delay subroutinei=11000:i:#:"End of parts file program."2 retrieve a record with record number = "rec"  errorcode=1 ž#1#1,rec:1)=5-#1,rec;partnum%,desc$,location$,quantity9rec=a >18004Herrorcode=1:"No such part number":995:800$R:"Part number: ";partnum$!W:"Description: ";desc$%\:"Location: ";location$%a:"Quantity on hand: ";quantity$f+z:"Press RETURN to continue: ";a$: RQ)O'SORTSUB(RQ+O !flist%(1000):maxrecord%=1000+ "Parts File Create and Modify Program":"Type:"&" 1 to Create a parts file":-(" 2 to Use an existing parts file":1" 9 to Quit":2:"Your selection: ";a$<a$=""1000Faile full":.partnum%=partnum$):quantity=quantity$) œ2040-#1,rec;partnum%,desc$,location$,quantity/flist%(0)=flist%(0)+1:flist%(flist%(0))=rec:errorcode=:: ž#12570 #1,20000) 1)<>2flist%(0)=0:#1;flist%(0):ode=0:k0l delete a record with record number = "rec"mqpartnum%=-partnum%-s#1,rec;partnum%,desc$,location$,quantityv- add a record with record number = "rec"errorcode=0<flist%(0)=maxrecord%errorcode=-1:"Parts fess RETURN to continue: ";2 retrieve a record with record number = "rec"  errorcode=1 ž#1#1,rec:1)=5-#1,rec;partnum%,desc$,location$,quantity!partnum%<0.&partnum$=partnum%):quantity$=quantity)berrorcs for parts file: ";file$`,jflist%(0)=0"No parts on file":995:8o"Part number","Description","Location","Quantity":ti=1flist%(0)~rec=flist%(i) 18004errorcode=0partnum%,desc$,location$,quantityi1:"End of list, procation: ";location$%a:"Quantity on hand: ";quantity$f+z:"Press RETURN to continue: ";a$:800 delay subroutinei=11000:i:#:"End of parts file program." 2600L5V:"List of current partleted":995:700 :%"Part number to find: ";a$ *a$="" /a=a$)4a<1a>9999a)<>a800 9rec=a >18004Herrorcode=1:"No such part number":995:800$R:"Part number: ";partnum$!W:"Description: ";desc$%\:"L999700 rec=a 18009errorcode=1:7);"No such part number":995:700C"Delete ";partnum$;"/";desc$;"/";location$;"/";quantity$;"? ";"";a$:a$=a$,1,1)/a$<>"y"a$<>"Y""Not deleted":995:700 1900+:7);7);"Record deuantity$;" Ok? ";a$'a$=a$,1,1):a$<>"y"a$<>"Y"505 2000.errorcode=0:"Record added.":995:500<::"Record not added, ERROR= ";::errorcode:995:505#:"Part number to Delete: ";a$ a$="" a=a$)a<1a>9n: ";a$&a$)>35a$=a$,1,35) 0desc$=a$::"Location: ";a$Da$)>15a$=a$,1,15)Nlocation$=a$X:"Quantity on hand: ";a$&ba=0:a=a$):a)<>aa>99999600lquantity$=a$Dv:"Record is: ";partnum$;"/";desc$;"/";location$;"/";qto quit the modify mode"::"Your selection: ";a$a=a$))a=9a$=""2600:a500,700,800,1100430 :"Part number to add: ";a$ a$="" a=a$)a<1a>9999a)<>a500 rec=apartnum$=a$!:"Descriptioify Parts File ";34);file$;34): "Type:")" 1 to add to your parts file":5" 2 to delete a part from your parts file":1" 3 to find a part in your parts file":4" 4 to list the parts in your parts file":'" 9 PRSTUVW=a$))Pa100,400Za=91000:5$d:"Name of new parts file: ";a$ na$=""xa$,,64 !"Parts file ";a$;" created."995):"Name of existing parts file: ";a$ a$="" #1,a$ file$=a$ 2500/:"Mod #1;flist%(0) flist%(0)=0 i=1flist%(0) #1;flist%(i) i % flist%(0)=0:#1,20000;flist%(0):&( file$=""::#1,20000;flist%(0)2 flist%(0)=07 i=1flist%(0)< #1;flist%(i)A iF !flist%(1000):maxrecord%=1000 25004" 4 to list the parts in your parts file":a500,700,800,1100a<1a>9999a)<>a500a<1a>99997004a<1a>9999a)<>a800 2600L5V:"List of current parts for parts filrds of specific parts by part number. The program: 5 HOME 7 PRINT 10 PRINT"Parts File Create and Modify Program" 20 PRINT:PRINT"Type:" 30 PRINT" 1 to Create a parts file":PRINT 40 PRINT" 2 to Use an existing parts file":PRINT -- Remember that this program was designed to allow the entry and retrieval of information about parts, such as might be maintained by a distributor or retail store. So far the program allows creation of parts files, and adding, deleting and finding recot will about finish us in the data management area, leaving future issues to explore formatting, business arithmetic and matrix arithmetic. Once more, dear friends, into the breach... The Program as it Currently Stands --------------------------------abase program to use the data file format. For at least one more time, I'll list the program as it currently stands and then plunge into this month's enhancements, which cover the breathlessly exciting topics of list management, indexing and sorting. Thamation I promised last time before getting into the new goodies. As you may remember (and are otherwise encouraged to discover), I concluded the last article by making some points about the use of Data files in Business Basic and modified our simple dat[]^_`abcdefghijklmnopqrstuvwxyz{|}~'s have probably received some very good news in the last few weeks. Yes, Virginia, there is a new version of Business Basic with some fantastic new features! But first, a word from our sponsor... Seriously, I would like to conclude presenting the infor T H E T H I R D B A S I C Taylor Pohlman Exploring Business Basic - Part Four Those of you who have Apple ///st%(i) i % flist%(0)=0:#1,20000;flist%(0):( #1,20000;flist%(0)2 flist%(0)=07 i=1flist%(0)< #1;flist%(i)A iF ontinue: ";<flist%(0)=maxrecord%errorcode=-1:"Parts file full":/flist%(0)=flist%(0)+1:flist%(flist%(0))=rec ž#12570 #1,20000) 1)<>2flist%(0)=0:#1;flist%(0): #1;flist%(0) flist%(0)=0 i=1flist%(0) #1;fliXZe: ";file$`,jflist%(0)=0"No parts on file":995:8o"Part number","Description","Location","Quantity":ti=1flist%(0)~rec=flist%(i) 18004errorcode=0partnum%,desc$,location$,quantityi1:"End of list, press RETURN to c49 PRINT" 9 to Quit":PRINT 50 PRINT:INPUT"Your selection: ";a$ 60 IF a$="" THEN 1000 70 a=ABS(VAL(a$)) 80 ON a GOSUB 100,400 90 IF a=9 THEN 1000:ELSE 5 100 PRINT:INPUT"Name of new parts file: ";a$ 110 IF a$="" THEN RETURN 120 CREATE a$, DATA,64 130 PRINT"Parts file ";a$;" created." 140 RETURN 400 HOME 405 PRINT:INPUT"Name of existing parts file: ";a$ 410 IF a$="" THEN RETURN 420 OPEN#1,a$ 425 file$=a$ 430 HOME 435 PRINT:PRINT"Modify Parts File ";CHund with this program, you may have discovered something very interesting. Retrieving individual records on parts is simple and quick, as long as you remember the part number you want. Try coming back to the program after a few days or weeks (as I have) REM 2005 errorcode=0 2010 partnum%=VAL(partnum$):quantity=VAL(quantity$) 2015 ON ERR GOTO 2040 2020 WRITE#1,rec;partnum%,desc$,location$,quantity 2030 OFF ERR:RETURN 2040 errorcode= ERR:OFF ERR:RETURN Impressive, right? In playing aro=0:RETURN 1899 REM 1900 REM delete a record with record number = "rec" 1901 REM 1905 partnum%=-partnum% 1907 WRITE#1,rec;partnum%,desc$,location$,quantity 1910 RETURN 1999 REM 2000 REM add a record with record number = "rec" 2001 1 REM 1805 errorcode=1 1810 ON EOF#1 RETURN 1815 READ#1,rec:IF TYP(1)=5 THEN RETURN 1820 READ#1,rec;partnum%,desc$,location$,quantity 1825 IF partnum%<0 THEN RETURN 1830 partnum$=STR$(partnum%):quantity$=STR$(quantity) 1890 errorcode$:GOTO 800 899 REM 900 REM delay subroutine 901 REM 995 FOR i=1 TO 1000:NEXT i:RETURN 996 REM 1000 PRINT:PRINT"End of parts file program." 1010 CLOSE 1020 END 1799 REM 1800 REM retrieve a record with record number = "rec" 180800 850 PRINT:PRINT"Part number: ";partnum$ 855 PRINT:PRINT"Description: ";desc$ 860 PRINT:PRINT"Location: ";location$ 865 PRINT:PRINT"Quantity on hand: ";quantity$ 870 PRINT 890 PRINT:INPUT"Press RETURN to continue: ";a 800 HOME:PRINT 805 INPUT"Part number to find: ";a$ 810 IF a$="" THEN RETURN 815 a=VAL(a$) 820 IF a<1 OR a>32767 OR INT(a)<>a THEN 800 825 rec=a 830 GOSUB 1800 840 IF errorcode=1 THEN PRINT:PRINT"No such part number":GOSUB 995:GOTO elete ";partnum$;"/";desc$;"/";location$;"/";quantity$;"? "; 745 INPUT"";a$:a$=MID$(a$,1,1) 750 IF a$<>"y" AND a$<>"Y" THEN PRINT"Not deleted":GOSUB 995:GOTO 700 755 GOSUB 1900 760 PRINT:PRINT CHR$(7);CHR$(7);"Record deleted":GOSUB 995:GOTO 7005 PRINT:INPUT"Part number to Delete: ";a$ 710 IF a$="" THEN RETURN 715 a=VAL(a$) 720 IF a<1 OR a>32767 THEN 700 725 rec=a 730 GOSUB 1800 735 IF errorcode=1 THEN PRINT:PRINT CHR$(7);"No such part number":GOSUB 995:GOTO 700 740 PRINT"DMID$(a$,1,1):IF a$<>"y" AND a$<>"Y" THEN 505 660 GOSUB 2000 665 IF errorcode=0 THEN PRINT:PRINT"Record added.":GOSUB 995:GOTO 500 670 PRINT:INVERSE:PRINT"Record not added, ERROR= ";:NORMAL:PRINT errorcode: GOSUB 995:GOTO 505 700 HOME 701,15) 590 location$=a$ 600 PRINT:INPUT"Quantity on hand: ";a$ 610 a=0:a=VAL(a$):IF INT(a)<>a OR a>99999 THEN 600 620 quantity$=a$ 630 PRINT:PRINT"Record is: ";partnum$;"/";desc$;"/";location$;"/";quantity$; 640 INPUT" Ok? ";a$ 650 a$=a=VAL(a$) 530 IF a<1 OR a>32767 OR INT(a)<>a THEN 500 535 rec=a 540 partnum$=a$ 545 PRINT:INPUT"Description: ";a$ 550 IF LEN(a$)>35 THEN a$=MID$(a$,1,35) 560 desc$=a$ 570 PRINT:INPUT"Location: ";a$ 580 IF LEN(a$)>15 THEN a$=MID$(a$,he modify mode":PRINT 465 PRINT:INPUT"Your selection: ";a$ 467 a=ABS(VAL(a$)) 470 IF a=9 OR a$="" THEN RETURN 475 ON a GOSUB 500,700,800 480 GOTO 430 500 HOME 505 PRINT:INPUT"Part number to add: ";a$ 510 IF a$="" THEN RETURN 520 R$(34);file$;CHR$(34):PRINT 437 PRINT"Type:" 440 PRINT" 1 to add to your parts file":PRINT 445 PRINT" 2 to delete a part from your parts file":PRINT 450 PRINT" 3 to find a part in your parts file":PRINT 460 PRINT" 9 to quit tand attempt to remember the part numbers that were previously entered. The immediate response is that a list of all the active (not deleted) part numbers is needed. The program below will accomplish this task. 10 PRINT"Name of Parts file: "; 20 INPUT a$ 30 OPEN#1,a$ 40 PRINT"Name of list file: "; 50 INPUT a$ 60 OPEN#2,a$ 70 ON EOF#1 GOTO 1000 75 PRINT"Part number","Description","Location","Quantity":PRINT 80 FOR rec=1 TO 9999 90 READ#1,rec:IF TYP(1)=5 THEN 200 100 Rs Basic begin with element 0, a handy place to store the number of items. The next thing required is a place to store the information permanently so that it can be used by the main program and others (such as the little list program above). This could bent 3: second item record number element (number of items + 1):last item record number Since all the record numbers are less than 10000, we can easily use an Integer array to store them and the count. Also convenient is the fact that all arrays in BusinesThe file can contain up to 9999 parts, so it will be convenient to keep track of how many records there are in our list. To do that, the following kind of list will be used: element 1: number of items in the list element 2: first item record number elemethis case, the list will consist of the part numbers stored in the file. Since the part number is also the record number, our task of retrieving the part number information is simply one of looking up all the record numbers in the list. One other note. rs to organized ways to maintain data and the information about the data. In this case, we need a structure called a "List". Sounds obvious, right? Lots of things in computer science are needlessly obfuscated (lots of things in English can be too!) In become important. With the extra memory, we can keep extra data structures around to simplify the task of finding out what data is on the disk and where it is. The term "data structure" is a much revered one in computer science circles, and simply refery record. However, we still want the fast lookup of an individual record which the random record access technique provides. Here's where all those comments I made earlier in the series about how neat it is to have lots of user memory in Business Basicrked disk. This is easy to understand, since 1700 records must be searched before the final one is found. Just imagine that I had used 9000 as the last record instead! Clearly there must be a better way to find out what is in the file than searching eve anvil top shelf 1 End of file Try entering these part numbers yourself and run the sample program. You will notice that the first records print out fairly quickly, but the last one appears only after much whirring of the poor, overwootice the sample printout below: Part number Description Location Quantity 35 shovel bin 3 2 200 hammer bin 1 10 300 wrench bin 5 6 2000 f data is present, it is read into the variables and the part number is checked. A negative value means that the part number has been deleted. If the data passes all tests, it is printed out. Running the program reveals several interesting things. Necords are actually in the file, a FOR NEXT loop is used to scan all the valid record numbers. Line 90 reads the particular record into memory and checks to see if it contains valid data. Recall that TYP(1)=5 means that there is no data in the record. Iom any parts file and to output to any file as well. This is similar to some programs from previous articles, and allows to output to go to the screen (by replying ".console") or to a printer, etc. Additionally, since we have no idea which part number rEAD#1;partnum%,desc$,location$,quantity 110 IF partnum%<0 THEN 200 120 PRINT#2;partnum%,desc$,location$,quantity 200 NEXT rec 1000 PRINT#2:PRINT#2"End of file" 1010 CLOSE 1020 END Notice that this program has been set up to read fr done with a separate file on the disk, but it is much safer and more convenient to store the information in the main data file itself. Among other things, it is much easier to keep track of where the information is if it is all physically together. With that in mind, I'll pick record 20000 to park the list. This is clearly out of the way of our regular data, and, because very little extra space is taken up, it doesn't hurt anything. So much for the philosophy. The following additional program lines ves updating the list count and storing the new part number in the next available list position. Since adds are done in the subroutine at line 2000, the changes are simple: 2006 IF flist%(0)=maxrecord% THEN errorcode=-1:PRINT"Parts file full":RETURN ord 20000. The changes are as follows: 530 IF a<1 OR a>9999 OR INT(a)<>a THEN 500 720 IF a<1 OR a>9999 THEN 700 820 IF a<1 OR a>9999 OR INT(a)<>a THEN 800 The next change is to add to the list each time a record is added to the file. This invola perfect program (or a perfect programmer). These changes just recognize the fact that our part numbers were supposed to be four digit numbers, yet we allowed any part number up to 32767. That was fine before we decided to put the part number list at rec the errorcode variable to check for that. Note that we could have opened a secondary file here to redirect the list to another device if desired. The next changes just clean up some sloppy programming from before. See there? There is no such thing as After first checking to see if the list was empty, the heading is printed and the list array is scanned. We can use the subroutine at 1800 to retrieve the record and set up the variables. That subroutine also checks for deleted records and line 1170 usesantity":PRINT 1140 FOR i=1 TO flist%(0) 1150 rec=flist%(i) 1160 GOSUB 1800 1170 IF errorcode=0 THEN PRINT partnum$,desc$,location$,quantity$ 1180 NEXT i 1190 PRINT:INPUT"End of list, press RETURN to continue: ";a$ 1200 RETURN ray and print the list to the screen: 1100 HOME 1110 PRINT:PRINT"List of current parts for parts file: ";file$ 1120 PRINT 1130 IF flist%(0)=0 THEN PRINT"No parts on file":GOSUB 995:RETURN 1135 PRINT"Part number","Description","Location","Quprogram is set up makes that simple to accomplish. The following changes add the new option: 452 PRINT" 4 to list the parts in your parts file":PRINT 475 ON a GOSUB 500,700,800,1100 The List option requires a new subroutine to read the list arhen a FOR NEXT loop loads the remaining data. Note that this is much more efficient than reading or writing all 1000 values each time. Next we need to add the "List" option to our menu of things we can do with existing files. Fortunately, the way the ile and statement 2570 will set up the list count in flist%(0) and write that into the file. If record 20000 exists, a check is made to be sure the data is of the correct type (and initialized if not). If everything is ok, the list count is read in and t 2570 flist%(0)=0:WRITE#1,20000;flist%(0):RETURN First an ON EOF statement is used in connection with the READ statement in line 2505 to take care of the case where the file is newly created. In that circumstance record 20000 will be past the end of f500 ON EOF#1 GOTO 2570 2505 READ#1,20000 2510 IF TYP(1)<>2 THEN flist%(0)=0:WRITE#1;flist%(0):RETURN 2515 READ#1;flist%(0) 2520 IF flist%(0)=0 THEN RETURN 2530 FOR i=1 TO flist%(0) 2540 READ#1;flist%(i) 2550 NEXT i 2560 RETURNeasily been 9999 as long as the DIM statement and the maxrecord% variable agree. Next, we need to retrieve the list when the file is initially referenced by the program. To allow us to change this easily, a subroutine will be used: 427 GOSUB 2500 2will accomplish the task: First, set up the array for the list: 4 DIM flist%(1000):maxrecord%=1000 The variable "maxrecord%" will serve as a check not to exceed 1000 part numbers. Since Business Basic permits very large arrays, this could just as 2025 flist%(0)=flist%(0)+1:flist%(flist%(0))=rec First, line 2006 checks to be sure that the list count will not be exceeded by adding this record. If everything is ok, line 2025 updates the list count and uses it as the index to store the new part number (record number). The last task is to write out the updated list as a part of ending the program. This must also be done when switching to a new file. The changes are as follows: 470 IF a=9 or a$="" THEN GOSUB 2600:RETURN 1005 GOSUB 2600 Tortorder<>2 THEN GOTO 1100 1107 GOSUB 1300 1140 FOR i=1 TO slist%(0) 1150 rec=slist%(i) The changes from 1102 to 1107 set up the choice and GOSUB to 1300 to perform the actual sort. Lines 1140 and 1150 change the list index to a new array "sls change the list routine to provide some sort options: 1102 PRINT"Type:" 1103 PRINT" 1 for chronological order" 1104 PRINT" 2 for part number order":PRINT 1105 INPUT"Your selection: ";a$ 1106 sortorder=VAL(a$):IF sortorder<>1 AND scs. In fact, there is enough implied in the paragraph above to be the meat for several articles. We'll look at a simple example and then I suggest you slide over to your local library for a book on database techniques for the real details. First, let', it may occur to you that several of these sorted indexes could be stored simultaneously in the file. Similar kinds of "multi-key indexing" are used in sophisticated database management systems. Wow! That's a lot of definitions of esoteric computer topi destroy the chronological order, and that might be a useful way to list the data as well. This implies that we should create some additional arrays to hold sorted versions of the flist% array. These arrays are sometimes called "sorted indexes". In factr. That's because the values in flist% are used as "indexes" into the larger file itself. It is the value assigned to the variable "rec" in line 1150 that determines which record is read and listed. Unfortunately, sorting the information in flist% would "chronological" order. Ordering the list in any other way is generally referred to as a "sorted" order. Clearly, if the array "flist%" was arranged in numeric order, we could use the subroutine at 1100 to list the contents of the file out in that orded. The previous example of a separate list program always listed the parts in part number order, since it scanned the file sequentially from the beginning. Ordering of lists according to the sequence in which they were entered into the file is calledmade all these fun changes, try running the program on a new file. Try adding the following part numbers in this order: 5,35,200,100,50. Now when you use the list option, you will notice that the part numbers appear in the order in which they were entere This is an extremely useful and widely used structure. One example in front of you at the moment is the Business Basic string variable. See your Basic manual for details of how the length of a string is stored. INDEXING AND SORTING Now that we've y the data is arranged in the file. Furthermore, this permits us to do some really interesting things later. The type of data structure used here is commonly referred to as a "variable length list". Here "variable" is used in the sense of "changeable". s no open file to which to write. All that above seems like a tremendous number of program changes, I know, but the results are well worth it. You can now find out what's in the file at any time, and the listing speed is essentially independent of the wa(0) 2620 WRITE#1;flist%(i) 2625 NEXT i 2630 RETURN Notice that we use the fact that file$ is assigned the name of the file after opening to determine if the modify section of the program was used. If the string is empty ("null") then there ihe subroutine at 2600 does just the reverse of the one at 2500, that is, writes the list back into the file starting at record 20000: 2600 IF file$="" THEN RETURN:ELSE:WRITE#1,20000;flist%(0) 2610 IF flist%(0)=0 THEN RETURN 2615 FOR i=1 TO flist%ist%" which has the same structure as flist%. This allows changing the order without changing the actual contents of flist%. This also means a change to line 4: 4 DIM flist%(1000),slist%(1000):maxrecord%=1000 Isn't having all that memory nice? Next, lets cook up a subroutine which will sort the flist% array and create a slist% array with the contents in ascending order: 1300 IF flist%(0)=0 THEN RETURN 1305 slist%(0)=flist%(0) 1310 FOR i=1 TO flist%(0) 1315 slist%(i)=flist%(i) 1320 bove contains enough challenges to last you as long as you want. Just remember that Business Basic has enough power and capability to allow you to be as sophisticated as you wish in managing file data. Good luck! THE NEW GOODIES Version 1.1 of Busineslues allowed. Real database programs maintain this information in the file as well, permitting the user to define many different databases with the same program. You might think about how our program would be modified to do that as well. The paragraph adifferent elements, you could store all their "addresses" there (or maybe just the address to the addresses!). Another thing hardcoded into this program is the record format, including not only the number of elements, but their names, type and range of vaat is "hard coded" at record 20000, but for a lot of reasons, it might need to be changed later. Writing it into the file and reading it back at open time would make the program much more flexible. Also, if you decided later to keep multiple indexes for Then listing from slist% would produce a list in description order. This is referred to as a "pointer" sort. Another interesting change would be to use record 0 of the data file as a place to store the record number where flist% begins. Right now thsubroutine so that the slist% array was used to read in records to build a string array from the values of "description$". When you sort the string array, you could swap the slist% elements in correspondence to the way you swap the string array elements. Apple III owners have fewer problems in that area, the classic techniques have to be looked at differently. It might also occur to you that it is possible to sort on items other than the part number. A good experiment for you might be to change the sort , there are far better sort techniques. Later in this series I will try to do an article on different sort techniques. Most microcomputer references on sorting tend to try to minimize memory utilization, which usually hurts performance. Since you lucky n to being ugly, this version performs significantly slower than the version using SWAP, since SWAP is done internally by Basic in assembly language. Try putting this routine into your program. For small lists it will perform very well. For larger listsby assigning one variable to a temporary variable, as in the following example: 1345 IF slist%(position)>slist%(position+1) THEN temp%=slist%(position): slist%(position)=slist%(position+1):slist%(position+1)=temp%: madeaswap%=1 In additio new statement named SWAP which comes in very handy in sorting situations, among others. It will exchange the values of any two variables of the same type. This includes, as this example points out, elements of arrays. Normally this exchange is handled ist%. If chronological order is desired, we're finished. If not, the contents of slist%, but not the list count, slist%(0), must be sorted in order. For simplicity, we use a version of the classic "bubble" sort, with a new wrinkle. Business Basic has aposition), slist%(position+1):madeaswap%=1 1350 NEXT position 1355 IF madeaswap%=0 THEN RETURN 1360 NEXT pass 1365 RETURN Several things are of note here. First, if there is anything in the flist% array, it is copied to sl NEXT i 1325 IF sortorder=1 THEN RETURN 1330 length%=slist%(0) 1332 IF length%=1 THEN RETURN 1335 FOR pass=1 TO length%:madeaswap%=0 1340 FOR position=1 TO length%-pass 1345 IF slist%(position)>slist%(position+1) THEN SWAP slist%(s Basic is now released and it is neat! Obviously, it clears up some nasty little problems from the first version, and the manual is now a completely revised (and two volume) reference guide that you will really enjoy. But that's only the beginning. Several new capabilities have been added in response to user requests and some pretty good thinking on the part of the Apple engineering staff. They are summarized below, but I suggest that you slide over to your local dealer to get the real scoop. The P.S.rator. After setting up the character definition in an array, one Perform statement passes it to the Operating System as the new character set. The Business Basic disk contains several sample character sets, and you can have fun inventing your own. Thisto directly get device status, and use the SOS SETCONTROL mechanism. More details on this super-powerful module are in the documentation. The last goodie is an invokable which allows you to DOWNLOAD character sets directly to the RAM-based character genead or write up to 64K bytes in one statement to any file on the system (including text and data files, .console, etc.). Numeric arrays can be stored about 20 times faster than with regular FOR NEXT loops! In addition, REQUEST allows the Basic programmer , and less desire, to renumber a program while it is running). The next biggie is the REQUEST module. Remember all those wonderful things I keep saying about SOS? REQUEST allows a Basic program to make calls to the Operating System directly. You can rerams in memory. This means you can save important subroutines and have them automatically added to the program you are currently working on. Because it is an Invokable module, it won't take up any memory unless you want it (obviously there is little needaving no place to put it, take heart. RENUMBER will renumber your program in memory and save it on disk automatically, or renumber a program stored on the disk and place it in memory for you. In addition, it supports merging of programs on disk with proge! For the development programmer, the most significant module is probably RENUMBER/MERGE. There's too much available in this one to go into detail but for those of you who have been frustrated by wanting to add that "one extra line" into a program and hIII, you can keep lots of these routines around, or if you need the space for data, you can invoke just the ones you need at a particular time. The new release of Business Basic contains some really powerful Invokables. Hang on to .console, here they come language to be extended almost infinitely. Since the Invokable routines are accessed by name, and available from Immediate as well as Deferred execution modes, its really like adding commands to the language. With all the memory available in the Apple k Data files, Text files, and character devices. I can't begin to tell you all the possibilities this presents, but it should keep you busy for a while. NEW INVOKABLE MODULES As we've discussed before, the design of the Basic Invoke mechanism allows threwing up those pretty indented listings with long lines! This works with any output file you specify. An enhancement has been made to the GET statement as well. You are now allowed to use GET# to get a single character from any file. This includes diss to work as in the old version. The neat feature is that when the printed output reaches the OUTREC value, Basic automatically inserts a carriage return and spaces over to line the next part up with the indentation level of the previous line. No more scs (default is 3) and OUTREC sets the record length Basic uses to format listings. Ever have a long line in a Basic program which got overprinted on your 80 column printer? OUTREC is initially set to 80, but can have any value to 255. Zero causes listing is pretty good too. Its free to all current purchasers of Basic, no matter how long ago you bought your old version! New language additions There are two new reserved words, INDENT and OUTREC. INDENT sets the level of indentation for the FOR NEXT loop also allows you to create animation, by properly defining special characters, ala the DOS Toolkit ANIMATRIX program. I'm sure some clever programmers will design a really nice program to use this invokable for character set design. Closing thoughts Whew! Glancing up at the prompt line of my Applewriter III display, I see that I'm up to 26590 characters in this article! Your tired eyes and my tired fingers both need a rest. Next time we'll have a mixed bag of things to enjoy, including some commenta<1a>9999700 rec=a 18009errorcode=1:7);"No such part number":995:700C"Delete ";partnum$;"/";desc$;"/";location$;"/";quantity$;"? ";"";a$:a$=a$,1,1)/a$<>"y"a$<>"Y""Not deleted":995:700 1900+:7);cation$;"/";quantity$;" Ok? ";a$'a$=a$,1,1):a$<>"y"a$<>"Y"505 2000.errorcode=0:"Record added.":995:500<::"Record not added, ERROR= ";::errorcode:995:505#:"Part number to Delete: ";a$ a$="" a=a$):"Description: ";a$&a$)>35a$=a$,1,35) 0desc$=a$::"Location: ";a$Da$)>15a$=a$,1,15)Nlocation$=a$X:"Quantity on hand: ";a$&ba=0:a=a$):a)<>aa>99999600lquantity$=a$Dv:"Record is: ";partnum$;"/";desc$;"/";lo'" 9 to quit the modify mode"::"Your selection: ";a$a=a$))a=9a$=""2600:a500,700,800,1100430 :"Part number to add: ";a$ a$="" a=a$)a<1a>9999a)<>a500 rec=apartnum$=a$!/:"Modify Parts File ";34);file$;34): "Type:")" 1 to add to your parts file":5" 2 to delete a part from your parts file":1" 3 to find a part in your parts file":4" 4 to list the parts in your parts file":""1000Fa=a$))Pa100,400Za=91000:5$d:"Name of new parts file: ";a$ na$=""xa$,,64 !"Parts file ";a$;" created."995):"Name of existing parts file: ";a$ a$="" #1,a$ file$=a$ 2500.flist%(1000),slist%(1000):maxrecord%=1000+ "Parts File Create and Modify Program":"Type:"&" 1 to Create a parts file":-(" 2 to Use an existing parts file":1" 9 to Quit":2:"Your selection: ";a$<a$=#2:#2"End of file after ";rec-1" records.": "Name of Parts file: ";a$ #1,a$("Name of list file: ";2a$ <#2,a$ Fž#11000Prec=132767Z#1,rec:1)=5200)d#1;partnum%,desc$,location$,quantitynpartnum%<0200)x#2;partnum%,desc$,location$,quantityrec0happy holiday season! P.S. As you probably noticed in the paragraph above, there's more than Basic that's changed about the new Apple III! s on the powerful formatting capabilities of Business Basic, and I'll reveal a secret that I hope you all get in on. That secret is the answer to the question "how many bytes of memory are available for programs in a 256K Apple III?". Until then, have a 7);"Record deleted":995:700 :%"Part number to find: ";a$ *a$="" /a=a$)4a<1a>9999a)<>a800 9rec=a >18004Herrorcode=1:"No such part number":995:800$R:"Part number: ";partnum$!W:"Description: ";desc$%\:"Location: ";location$%a:"Quantity on hand: ";quantity$f+z:"Press RETURN to continue: ";a$:800 delay subroutinei=11000:i:#:"End of parts file program." 2600L N"Type:"%OI=1:I=2I>2=-1:I=I-2:IBOTM<30THPOS=44I=IBOTM/2)*2:=+IBOTM/2)-1:0=+IBOTM/2-.5):I=IBOTM:I/2=I/2)I=I-1 œ2120B=B$(I),16)," ")-1 B$(I),"BASIC 0")850B$(I),"TEXT 0")890 81+LCA):::: RebootN=THPOS:B$(I);XA<8A>11540bA-7640,660,690,720l:=THPOS:B$(I);v:520: 500THPOS=4:I/2=I/2)I=I-1I=IBOTM THPOS=44:I/2<>I/2)I=I+1I13000Zha$="{,|,~,}; selects; to new disk; J/2)=4:=+1:ۙ=44B$(J);:J=J+1I:1,180,22:2,280,21:2,2380,23:8A$(1000),B$(1000),C%(511),C$(20),name$(20):=10:=0UCA=128:LCA=UCA+32CT=15 IF PREFIX$= PREFIX$+MID$(B$(I),1Nuantity)berrorcode=0:k0l delete a record with record number = "rec"mqpartnum%=-partnum%-s#1,rec;partnum%,desc$,location$,quantityv- add a record with record number = "rec"errorcode=0<flist%(0)=maxrecord%erro=1 FpositionKmadeaswap%=0 PpassU2 retrieve a record with record number = "rec"  errorcode=1 ž#1#1,rec:1)=5-#1,rec;partnum%,desc$,location$,quantity!partnum%<0.&partnum$=partnum%):quantity$=qi=1flist%(0)#slist%(i)=flist%(i)(i-sortorder=12length%=slist%(0)4length%=1!7pass=1length%:madeaswap%=0<position=1length%-pass[Aslist%(position)>slist%(position+1)slist%(position),slist%(position+1):madeaswap%o"Part number","Description","Location","Quantity":ti=1slist%(0)~rec=slist%(i) 18005errorcode=0partnum$,desc$,location$,quantity$i3:"End of list, press RETURN to continue: ";a$flist%(0)=0slist%(0)=flist%(0)" 1 for chronological order"%P" 2 for part number order":Q"choose: ";a$6Rsortorder=a$):sortorder<>1sortorder<>21100 S13005V:"List of current parts for parts file: ";file$`,jflist%(0)=0"No parts on file":995:8B$(I),"CAT 0")1140*B$(I),"FONT 0")18504B$(I),"FOTO 0")1930>B$(I),"PASTXT 0")2070H540R\A$="RUNNING "+B$(I),16,B)f"79C";A$;:=0pB$(I),16,B) z::SEG=1".D1/SEG.T"t=+B$(I),16,B) yCT=CT+1~240:=24:=0:"@ ..... "DATE.TIME.LINE" ....JM=Ҡ,4,2))BTM1630,1640,1650,1660,1670,1680,1690,1700,1710,1720,1730,1740^M$="JANUARY":1750hM$="FEBRUARY":1750rM$="MARCH":1750|M$="APRIL":1750M$="MAY":1750M$=length%:madeaswap%=0 1340 FOR position=1 TO length%-pass 1345 IF slist%(position)>slist%(position+1) THEN SWAP slist%(position),s list%(position+1):madeaswap%=1 1350 NEXT position 1355 IF madeaswap%=0 THEN RETURN 1360 1300 IF flist%(0)=0 THEN RETURN 1305 slist%(0)=flist%(0) 1310 FOR i=1 TO flist%(0) 1315 slist%(i)=flist%(i) 1320 NEXT i 1325 IF sortorder=1 THEN RETURN 1330 length%=slist%(0) 1332 IF length%=1 THEN RETURN 1335 FOR pass=1 TO 0:#1;flist%(0): #1;flist%(0) flist%(0)=0 i=1flist%(0) #1;flist%(i) i % flist%(0)=0:#1,20000;flist%(0):&( file$=""::#1,20000;flist%(0)2 flist%(0)=07 i=1flist%(0)< #1;flist%(i)A iF rcode=-1:"Parts file full":.partnum%=partnum$):quantity=quantity$) œ2040-#1,rec;partnum%,desc$,location$,quantity/flist%(0)=flist%(0)+1:flist%(flist%(0))=rec:errorcode=:: ž#12570 #1,20000) 1)<>2flist%(0)=79C";"PRESS ANY KEY TO HALT LISTING"::202 1020#2,B$(I),16,B)ž#242:::1160Z=1#2;A$:"78A";A$Z=Z+1:Z>1842:::Z=1980*:=23:=0::"79C";"CONTINUE...?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"10 MENU.MAKER TEXT MODULESEG=0"MENU.MAKER"890&*X=11000: TEXT SLOW-DOWN LOOP ,X.1,180,22:2,280,21:2,2380,23:z:A$="LISTING "+B$(I),16,B)$=01:=0::"80C";A$;::12)>=23:=0::"12405l=ơ):: Routine to back up one directory level.a$=С,l-1) s=a$)a$=a$,s-1)a$,1)="/"5060:s=s-1 5030=a$240( MENU.MAKER 6.10 * Thanks to C.M.Davidson for his help!NOT FOUND.)"X=11000:X:::210Z a$="{,|,~,}; selects; back 1 level; G$:::320H: Error Routine 202:U=11:"79C";"BAD PATH ERROR (NO DISK IN DISK DRIVE OR DESIRED FILE ,2))=0"12";џ,6);:ٟ;$П,2))=>12" PM-":" AM-" 1830WW=1530 =26:=21 1600 &:WW=1:0 :SEG=1;".D1/S EG.F" SEG=1".D1/SEG.G"diskname$=3802  CATCH PASCAL TEXT FILES "JUNE":1750M$="JULY":1750M$="AUGUST":1750M$="SEPTEMBER":1750M$="OCTOBER":1750M$="NOVEMBER":1750M$="DECEMBER":1750826);"-";M$;" ";Ѡ,2));", ";"19";Р,2);" ";/П,2))=>13П,2))-12;џ,6);:1780$ NEXT pass 1365 RETURN 65 RETURN a<1a>9999700 rec=a 18009errorcode=1:7);"No such part number":995:700C"Delete ";partnum$;"/";desc$;"/";location$;"/";quantity$;"? ";"";a$:a$=a$,1,1)/a$<>"y"a$<>"Y""Not deleted":995:700 1900+:7);cation$;"/";quantity$;" Ok? ";a$'a$=a$,1,1):a$<>"y"a$<>"Y"505 2000.errorcode=0:"Record added.":995:500<::"Record not added, ERROR= ";::errorcode:995:505#:"Part number to Delete: ";a$ a$="" a=a$):"Description: ";a$&a$)>35a$=a$,1,35) 0desc$=a$::"Location: ";a$Da$)>15a$=a$,1,15)Nlocation$=a$X:"Quantity on hand: ";a$&ba=0:a=a$):a)<>aa>99999600lquantity$=a$Dv:"Record is: ";partnum$;"/";desc$;"/";lo'" 9 to quit the modify mode"::"Your selection: ";a$a=a$))a=9a$=""2600:a500,700,800,1100430 :"Part number to add: ";a$ a$="" a=a$)a<1a>9999a)<>a500 rec=apartnum$=a$!/:"Modify Parts File ";34);file$;34): "Type:")" 1 to add to your parts file":5" 2 to delete a part from your parts file":1" 3 to find a part in your parts file":4" 4 to list the parts in your parts file":""1000Fa=a$))Pa100,400Za=91000:5$d:"Name of new parts file: ";a$ na$=""xa$,,64 !"Parts file ";a$;" created."995):"Name of existing parts file: ";a$ a$="" #1,a$ file$=a$ 2500.flist%(1000),slist%(1000):maxrecord%=1000+ "Parts File Create and Modify Program":"Type:"&" 1 to Create a parts file":-(" 2 to Use an existing parts file":1" 9 to Quit":2:"Your selection: ";a$<a$=R o&NEW.CREATE.JUNK VR o'-OUTPUT.CREATER o(*PARTS.PROG Rk ARTICLE5vR' ')ARTICLE.54eR -% )DUMP.DATAR o*(DUMP.OUT R o DUMP.USING.GET R oFORMAT.DUMP R oHEX.CONVERT O slist%(0) 1150 rec=slist%(i) 1102 PRINT"Type:" 1103 PRINT" 1 for chronological order" 1104 PRINT" 2 for part number order":PRINT 1105 INPUT"choose: ";a$ 1106 sortorder=VAL(a$):IF sortorder<>1 AND sortorder<>2 THEN GOTO 1100 1107 GOSUB 1300 1140 FOR i=1 T7);"Record deleted":995:700 :%"Part number to find: ";a$ *a$="" /a=a$)4a<1a>9999a)<>a800 9rec=a >18004Herrorcode=1:"No such part number":995:800$R:"Part number: ";partnum$!W:"Description: ";desc$%\:"Location: ";location$%a:"Quantity on hand: ";quantity$f+z:"Press RETURN to continue: ";a$:800 delay subroutinei=11000:i:#:"End of parts file program." 2600L N"Type:"%O5805 EFCEB7872 5.22635E+09 926532264949760 2278 BEDDF1343 1.56348E+09 741812408557568 3814 AABED9057 2.27867E+09 768212125296640 3412 CDAFE3698 9.62256E+09 630485650254848 5723 AEFFE7065 6.37234E+09 991827728389120 6486 DCBCF5008 9.53929E+09 684570741485568 2092 CEEBE4542 7.72055E+09 930904428626944 7107 CDCAD1031 6.87212E+09 971614244086784 9206 DDADE8239 6.94853E+08 839965717072896 3038 ADBAC4450 6.09472E+09 397952126404096 =1)*1e10:#1;val:#2;val,1i&=1)*1E15) 2#1;i& 4#2;i&7i<FT#1,"junkfile",30&"NUMBER OF RECORDS TO CREATE: ";N#2,"output.create" I=1N i%=1)*10000 #1,i;i% #2;i%, A$="" J=15A$=A$+65+6*1)))#J )K=14*A$=A$+48+10*1)))+K -#2;a$, /#1;a$"0val0:#1;flist%(0): #1;flist%(0) flist%(0)=0 i=1flist%(0) #1;flist%(i) i % flist%(0)=0:#1,20000;flist%(0):&( file$=""::#1,20000;flist%(0)2 flist%(0)=07 i=1flist%(0)< #1;flist%(i)A iF rcode=-1:"Parts file full":.partnum%=partnum$):quantity=quantity$) œ2040-#1,rec;partnum%,desc$,location$,quantity/flist%(0)=flist%(0)+1:flist%(flist%(0))=rec:errorcode=:: ž#12570 #1,20000) 1)<>2flist%(0)=uantity)berrorcode=0:k0l delete a record with record number = "rec"mqpartnum%=-partnum%-s#1,rec;partnum%,desc$,location$,quantityv- add a record with record number = "rec"errorcode=0<flist%(0)=maxrecord%erro=1 FpositionKmadeaswap%=0 PpassU2 retrieve a record with record number = "rec"  errorcode=1 ž#1#1,rec:1)=5-#1,rec;partnum%,desc$,location$,quantity!partnum%<0.&partnum$=partnum%):quantity$=qi=1flist%(0)#slist%(i)=flist%(i)(i-sortorder=12length%=slist%(0)4length%=1!7pass=1length%:madeaswap%=0<position=1length%-pass[Aslist%(position)>slist%(position+1)slist%(position),slist%(position+1):madeaswap%o"Part number","Description","Location","Quantity":ti=1slist%(0)~rec=slist%(i) 18005errorcode=0partnum$,desc$,location$,quantity$i3:"End of list, press RETURN to continue: ";a$flist%(0)=0slist%(0)=flist%(0)" 1 for chronological order"%P" 2 for part number order":Q"choose: ";a$6Rsortorder=a$):sortorder<>1sortorder<>21100 S13005V:"List of current parts for parts file: ";file$`,jflist%(0)=0"No parts on file":995:8sixteen&=16 "hex value: ";a$a$=""100 cum&=0 mult&=1i=a$)1-1#val&=a$,i,1)))(digit&=mult&*val&-cum&=cum&+digit&2mult&=mult&*sixteen&7i <cum&A10dnterpreters use this technique. One of the consequences of this method is that the program statements cannot be listed out without the Basic LIST command converting these "tokens" back to their English equivalents. In converting the tokens, Basic always Reserved Words, into a special internal one byte code called a Token. English majors will appreciate the appropriateness of that term. Not only does this code save space, but it simplifies error checking and execution of the program. Almost all Basic irors) until you actually run the program. Basic does perform some tasks as each statement is entered, however, a process generally referred to as "tokenizing". Simply, this means that Basic scans each statement and converts each Keyword, sometimes calledcaps. Actually, it would be easy to say that I lack the strength or will to operate the alpha lock key, but the real reason has to do with the way Basic itself works. You are probably aware that Business Basic defers its "syntax checking" (looking for eries started in September, but the most interesting ones concern programming style and philosophy. The most intriguing concerned why I always use lower case variable names in my programs, especially since the Basic keywords (PRINT, etc.) all seem to be in time we'll explore a mixed bag of items, and defer our discussion of the Print Using capabilities of Business Basic until next time. Our Mixed Bag The first bagged item for this month is the mailbag. Several questions have come my way since this sermes the workspace available in any other personal computer Basic. (Aren't you glad you've got an Apple ///? Don't you wish everybody did?) We were discussing some sorting techniques for our database last time which can make good use of that space. Thisst time I promised the answer to "How many bytes of memory are available in a 256K Apple ///?" Well, as you know, the 256K Apple /// has been announced and is beginning to be available. The answer can now be revealed: 191,484 bytes! That's over three ti these articles on Applewriter ///, which I really enjoy. I could go on describing the new software for the rest of this column, but since this is supposed to be about Basic, I'll temporarily restrain my enthusiasm. One thing before we start, though. Laart five Last time I dropped several broad hints about new software and hardware happenings on the Apple ///. Hopefully by now you have had a chance to go down to your dealer and check some of these things out. As you might have guessed, I've been doing T H E T H I R D B A S I C by Taylor Pohlman Exploring Business Basic - Pprints out the Upper case version of the keywords. I type in all Basic statements in lower case, both variables and keywords, so that when I list out the program, I can see what Basic interpreted as keywords. If I misspell PRINT, Basic will not recognize it as a keyword, and the fact that it remains lower case makes such errors easy to spot in a listing. In addition, Business Basic requires spaces between keywords and variable names, to allow variables to contain keywords themselves. Ever try to use a vy SOS file one character at a time, without respect to what kind of file it is. This can be very handy to read all characters from the communications port (via the .RS232 driver) or read other character streams from special devices. One of its most interding the keyboard one character at a time, including all special control characters and delimiters. This means you can bypass Control-C and Carriage Return, read commas, etc. Business Basic 1.1 extends GET to allow GET#n. This means that you can read an list last month of new goodies in Business Basic 1.1, I completely overlooked one which seems minor but has important consequences. The change is an extension to the standard GET statement. Normally, as in Applesoft and some other Basics, GET allows reareserved word EOF in the example above was a major clue toward understanding the problem. The technique of entering everything in lower case has saved me countless hours of debugging my errors. I recommend it strongly to you. Bag Item Number Two In my can be interpreted, LET can be used to clear it up. Our new version of the EOF statement: typing: 10 on eof#1 let xval=20 will result in: 10 ON EOF#1 LET xval=20 and everything will work fine. Note that the fact that Basic failed to upshift the dialects have long since allow the LET keyword to be optional, and most people have quit using it altogether. An example of the use of LET is: 10 LET x=45 which is usually written simply: 10 x=45 If there is any ambiguity in the way a statement For some reason Basic treats the whole thing as one variable. The solution involves dredging up a bit of Basic folklore. Remember in your first class in Basic when they told you that all assignment statements started with the keyword LET? Most Basic enerally used GOTO or GOSUB statements to take action. Consider the following: Typing: 10 on eof#1 goto 20 will result in: 10 ON EOF#1 GOTO 20 as you would expect. But: Typing: 10 on eof#1 xval=20 will result in: 10 ON EOF#1xval=20technique helped me spot. As you may know, we have used the ON EOF# statement quite a bit to take action if a program tries to read past the end of file. According to the manual, the part following EOF#n can be any executable statement. So far we have glem: Typing: 10 xval=aval*fnumber will result in: 10 xval=aval* FN umber and you will immediately know that something is wrong (assuming that you really wanted to use "fnumber" as a variable name). There is another little quirk in Basic that this N x GOTO 20,40,50 See how much easier it is to catch the error visually? Like every rule, there are exceptions. Any variable which starts with the letters "FN" will be assumed to be a function name. Again, typing all lower case will help spot the probarify: Typing: 10 prunt x*53 will result in: 10 pruntx*53 whereas: 10 print x*53 will result in: 10 PRINT x*53 Typing: 10 on xgoto 20,40,50 will result in: 10 ON xgoto20,40,50 whereas: 10 on x goto 20,40,50 will result in: 10 OO 10" instead of "FOR i=1 TO 10". The first case will produce an error, since Basic will assume you are trying to assign the value of 1 to the variable "fori" and for some reason put the phrase "TO 10" onto the end of the statement. Some examples will clariable like ORANGE in Applesoft, only to discover that OR is a reserved word and therefore your variable must be renamed to something like RNGE? Typing in lower case will allow you to spot those times that you forgot to space and ended up with "fori=1 Testing uses, however, is the fact that it can be used on disk files as well. Remember that one file is just like another in the SOS environment, so if we open a text file on disk, GET# will allow us to read one character at a time from it. This means that there is now an easy way to read text files which contain more than 255 characters without a RETURN character. Normally this would cause a string overflow error if attempted with the Basic INPUT statement. Even more interesting is the fact that we canne$" string to accumulate the characters read from the file for later printing. After each line of print we will re-initialize the string. Since we will be printing 32 characters at a time from the file, line 45 uses the HEX$ function to set up the labelsy to see that "eof.occurred" is easier to interpret than "eofoccurred", and this is especially true for more complex variable names (remember that Business Basic permits 64 character names!). Lines 35 and 40 initialize variables. We will be using the "lin the screen. Line 30 sets up our end-of-file condition, using the LET statement to get around the problem we described earlier, and shows one other handy thing of note. Notice that we can imbed periods in variable names to improve readability. It's easTHEN 40 95 CLOSE 120 END Scanning down the program, note that in addition to opening the file to be dumped, we now open a second file to which the output is written. This gives more flexibility, and still allows using ".console" to see the output o7 THEN val=val-128 60 IF val<32 THEN line$=line$+" .":ELSE:line$=line$+" "+CHR$(val) 65 outhex$=HEX$(ASC(a$)) 70 PRINT#2;MID$(outhex$,3,2); 75 NEXT i 80 PRINT#2:PRINT#2;" ";line$ 85 bytes=bytes+32 90 IF eof.occurred=0 ,a$ 20 INPUT"File for output: ";a$ 25 OPEN#2,a$ 30 ON EOF#1 LET eof.occurred=1:GOTO 80 35 bytes=0:eof.occurred=0 40 line$="" 45 PRINT#2;HEX$(bytes);"-";HEX$(bytes+31);" "; 50 FOR i=1 TO 32 55 GET#1;a$ 57 val=ASC(a$):IF val>12cter set only defines 128. Clearly we need a safe and consistent way to display any byte readable from a file. So, like most small, simple programs, this last one is about to get complex: 5 INPUT"File to dump: ";a$ 10 IF a$="" THEN 95 15 OPEN#1 is in the example program. The console uses lots of different control sequences to perform functions, including setting windows and changing from black and white to color text modes. Also, a byte can contain 256 different characters, and the ASCII chara need to be made to avoid overflowing the 255 character limit. This program has one serious deficiency, however. Printing arbitrary characters from a file (especially a Data file) can have weird consequences when the output device is the console, as itloading the variable "cr$" with a RETURN (decimal 13) and then testing for it before printing. If you want to reconstruct strings from the file, you could use a string variable to accumulate characters, stopping when a RETURN is encountered. A test wouldrarily long strings is the file I'm creating now, using Applewriter ///. RETURN characters are inserted only at the end of paragraphs which, if you notice my style, tend to run on indefinitely. Note that in this program I look for RETURN characters by 30 GET#1;a$ 40 IF a$=cr$ THEN PRINT 50 PRINT a$; 70 GOTO 30 100 CLOSE 110 END This simple example will dump any text file to the screen, no matter how long the intervals between carriage returns. A good example of a text file with arbitta file in its binary form. GET# allows reading this binary information, one byte at a time. One example is worth a thousand explanations: 5 INPUT"File to dump: ";a$ 10 IF a$="" THEN 100 15 OPEN#1,a$ 20 ON EOF#1 GOTO 100 25 cr$=CHR$(13) also open and read from the Basic Data file! Remember that I described the Data file as having special "tags", called "Type bytes", to allow Basic to determine what data type was stored next in the file. Remember also that numeric data is stored in a Da for each line. A note about "HEX" is appropriate here. HEX stands for hexadecimal, or base 16 arithmetic. It is used extensively in computers for its convenience, since any hex digit can be represented by 4 binary bits, and a byte can be exactly represented by 2 hex digits. This convenience makes it preferred over decimal and octal notation, and of course it is much more compact than binary. What usually throws people is that to properly represent with a single digit all values between 0 and 15, hex u at bytes 00 through 1F (0 to 31 decimal), and the top line is the hex representation of the characters, two digits per character. The first character in the file is "2E" hex, which happens to be a period. Notice that that is the character printed below 206368616E636520746F20676F20646F776E20746F20796F75722064 a d a c h a n c e t o g o d o w n t o y o u r d Messy, huh! Let's look at this more closely and see if it makes sense. First, the first line tells us that we are looking70706C65202F r d w a r e h a p p e n i n g s o n t h e A p p l e / 00C0-00DF 2F2F2E2020486F706566756C6C79206279206E6F7720796F7520686176652068 / / . H o p e f u l l y b y n o w y o u h a v e h 00E0-00FF 61642061 d r o p p e d s e v e r a l b r o a d 0080-009F 2068696E74732061626F7574206E657720736F66747761726520616E64206861 h i n t s a b o u t n e w s o f t w a r e a n d h a 00A0-00BF 7264776172652068617070656E696E6773206F6E2074686520410040-005F 6E6720427573696E657373204261736963202D205061727420666976650D0D4C n g B u s i n e s s B a s i c - P a r t f i v e . . L 0060-007F 6173742074696D6520492064726F70706564207365766572616C2062726F6164 a s t t i m e I 52204420204220412053204920430D . c j . T H E T H I R D B A S I C . 0020-003F 0D6279205461796C6F7220506F686C6D616E0D0D0D2E6C6A0D4578706C6F7269 . b y T a y l o r P o h l m a n . . . . l j . E x p l o r i e count, check for EOF condition, and repeat the sequence. The easiest way to check this little jewel is to run it against the file for this article. If we did that, the output would look something like this: 0000-001F 2E636A0D54204820452020542048204920x$" in line 65, and printed to the output file in line 70. Note that we want only the rightmost two hex digits, so the MID$ function is used. After the loop prints out the 32 values, lines 80-90 print the ASCII equivalents stored in "line$", bump the bytis unprintable. Otherwise, the character representation is stored. Note that the characters are right justified in each two byte cell, because they will be printed below the hex values. Next, the hex value of the original character is assigned to "outhe it is in the 128 to 255 range. If so, 128 is subtracted to bring the value within the normal ASCII range. Line 60 checks to see if the resulting character is a "control" character, and if so, it is represented as a period in "line$", signifying that it 7). The back of your Basic manual contains an ASCII code chart, which will be helpful in following along with the decoding. Line 57 in the program sets the variable "val" to the ASCII value of the byte just read, and then an IF statement checks to see if of hex digits. Getting back to our program, the loop from line 50 to line 75 is the main one where we dump 32 bytes at a time in hex format, while providing character representations for those within the displayable range (hex 20 to 7F, decimal 32 to 12on computers usually covers the subject thoroughly, and readers of Rodger Wagner's column in this journal have been inundated with help on "hex". Suffice it to say that the HEX$ function will convert any reasonable numeric quantity into a four byte stringses the digits 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F respectively. "F" thus is equivalent to 15, and "1F" is 31 (the 1 is in the "sixteens" place). There will be no attempt to explain hex further. If you are not familiar with the notation, any beginning text on the next line. The next two characters in the file are "63" and "6A" which correspond to the ASCII characters "c" and "j". This is understandable, since Applewriter /// uses the print format command ".cj" for center-justify, which is what I wanted done with the title. The next character is "0D" which translates to decimal 13, or a RETURN character. Note that a period is substituted for this character on the print line, since RETURN is in the "control" character range. And so on, and so on. Practice the exact contents of the file. Now the fun begins. The first thing to notice is that almost the entire first line is composed of zeros. Remember that our dump program starts at the beginning of the file, but the program we used to create this file bience was for the faint of heart! By the way, the term generally used for this type of listing of file contents is "formatted dump". "Formatted" because we have organized the information in the printout, and "dump" because it is a non-selective output of5A30818000169EF7321C6000000120EE621094141424544 A C 4 4 5 0 . ! 5 # . . . . i o s ! F . . . . . f ! . A A B E D 00A0-00BF 3930353714A007D1D0180002BAAF52D728000000 9 0 5 7 . . Q P . . . : / R W ( . . . Well, nobody said computer sc944 . C D C A D 1 0 3 1 . ! L N . . . . s - . ` $ . . . . # v ! . D 0060-007F 4441444538323339149E25AA7B180002FBF1C2308C000000120BDE2109414442 D A D E 8 2 3 9 . . % * { . . . { q B 0 . . . . . . ^ ! . A D B 0080-009F 41433434353014A13 . . . . . . . . . . . . . . . . . 0020-003F 2C210943454542453435343214A16617221800034EA713C9C4000000121BC321 , ! . C E E B E 4 5 4 2 . ! f . " . . . N ' . I D . . . . . C ! 0040-005F 0943444341443130333114A14CCE1D18000373AD91E0A40000001223F62100 Now for the fun. When you run your dump program against the file that this program creates, the output should look something like this: 0000-001F 0000000000000000000000000000000000000000000000000000000000001208 . . . . . . . . . . . . . . .4 7107 CDCAD1031 6.87212E+09 971614244086784 9206 DDADE8239 6.94853E+08 839965717072896 3038 ADBAC4450 6.09472E+09 397952126404096 3814 AABED9057 2.27867E+09 76821212529664l come in handy later in sorting exercises. For now, type this in and run it to create a small file, say 5 records. Although each run will differ, the output should look something like this: 2092 CEEBE4542 7.72055E+09 93090442862694h record. The interesting things of note are the two small loops which build the string value. They are set up in such a way to insure that the first five characters are upper case alpha, and the next four are decimal digits. As I said, this routine wilWRITE#1;val:PRINT val, 49 i&=CONV&(RND(1)*1E15) 50 WRITE#1;i&:PRINT i& 55 NEXT i 60 CLOSE 70 END This program will create a random access data file of arbitrary length containing an integer, a string, a real and a long integer in eac00 13 WRITE#1,i;i%:PRINT i%, 15 a$="" 20 FOR j=1 TO 5 30 a$=a$+CHR$(65+INT(6*RND(1))) 35 NEXT j 41 FOR k=1 TO 4 42 a$=a$+CHR$(48+INT(10*RND(1))) 43 NEXT k 45 WRITE#1;a$:PRINT a$, 48 val=RND(1)*1E10: do the trick. Later on in a future article when we get serious about sorting techniques, we'll need such a program, so I'll introduce it now: 5 OPEN#1,"junkfile",30 6 INPUT"Number of records to create: ";n 10 FOR i=1 TO n 12 i%=RND(1)*100et data out, things like the "type" bytes, and string length bytes are normally inaccessable. To see how our dump program would work on a Data file, we need a way to generate an interesting file at which to look. The following program is simple, and will on a few text files of your own and get a feel for reading the notation. Where this really gets interesting is in reading files whose exact format is normally pretty obscure. Data files are an excellent example, since, although the READ# statement can gegan at record number one. Therefore, since the record size was 30 bytes, we would expect to find an empty record of 30 bytes at the beginning. That is exactly what the dump shows. This means that the hex "12" in byte 31 of the file must be at the beginning of record one. Now something that was mentioned earlier about "type" bytes in Data files becomes important. Remember that the general format of a Data file is the following: !==============!=========================! ! Type byte ! optionally check for the high-order bit and negate the final result, but the program then loses its general nature. Anyway, it's free. Well, that got us completely off track. Going back for a second to the formatted dump, we are now at position "3A" het since the long integer arithmetic is very fast, performance of the program is quite reasonable. One note, this program knows nothing about sign bits, so it will fail in converting negative integers expressed as hex constants. A fix for this would be to 1 STEP-1 35 val&=CONV&(TEN(MID$(a$,i,1))) 40 digit&=mult&*val& 45 cum&=cum&+digit& 50 mult&=mult&*sixteen& 55 NEXT i 60 PRINT cum& 65 GOTO 10 100 END The program simply "brute force"s the problem, one digit at a time, bu decimal and print it out rather quickly, using the long integer data type and Business Basic's conversion functions. Forthwith, it is: 5 sixteen&=16 10 INPUT"hex value: ";a$ 15 IF a$="" THEN 100 20 cum&=0 25 mult&=1 30 FOR i=LEN(a$) TOvalue should yield the decimal value originally printed out: 930904428626944. As a little added bonus in this article, let me offer a program which will demonstrate the truth in the statement above. This program will convert any reasonable hex value intope" byte in position "31" (decimal 49) has the value of hex "18". Long integers are stored as eight byte quantities, therefore the next 16 hex digits should represent the number. Since that hex value is "00034EA713C9C400", it follows that coverting this eader. That phrase "left to the numerically inclined reader" is this author's equivalent to the famous line found in all math texts "it can easily be shown that..." and is just as big a cop-out. The last value in the record is a long integer, and the "tyit internal format in Business Basic, so we would expect that the next four bytes would contain the binary value. Proving that this value (hex "A1661722") is equal to 7.72055E+09 is considerably more complex, and will be left to the numerically inclined rlue in the record was a "real". Since the next byte after the string should be the "type" byte for reals, we can conclude that the hex "14" found in position "2C" (44 decimal) is the floating point "type" byte. Floating point numbers are stored in a 32 bch, since the string is 9 characters long, should be equal to 9. That's hex code "09", one of those lucky hex numbers which is the same as its decimal equivalent. After that our format line shows that indeed, the string value is "CEEBE4542". The next vas to expect. The next value in the file was a string, which contained "CEEBE4542". Referring again to our format for strings in Data files, we would expect the next file byte to be the "type" byte. That's the hex code "21". Next is the length byte, whi2" must be the "type byte" for integer data. Following our format, that means the next 2 bytes (hex codes "08" and "2C") must be the binary integer value. Evaluating the hex value "082C" yields decimal value 2092, which is exactly what our printout led u Data bytes (0 to 255) ! !==============!===============!=========================! for strings. With this information, we should be able to decode the information in this dump. Since the first value in the record was an integer, the hex code "1 Data bytes (2,4 or 8) ! !==============!=========================! for numeric values (integer, real and long integer), and the following: !==============!===============!=========================! ! Type byte ! Length byte ! x (58 decimal), which is really position 28 decimal in this record. The remaining two bytes of the record (remember that we declared the record to be 30 bytes long) should be empty, and sure enough, show up here as zeros. This gets us to position "3C", the beginning of the next record, and there is the integer "type" byte "12" signaling that we can start the whole process again. I leave that to you if you want to try your hand at decoding. I can summarize some of what we have learned in the following ta P o h l m a n . . . . l j . E x p l o r i 0040-005F 6E6720427573696E657373204261736963202D205061727420666976650D0D4C n g B u s i n e s s B a s i c - P a r t f i v e . . L 0060-007F 6173742074696D6520492064726F70706564207365766572616C0000-001F 2E636A0D5420482045202054204820492052204420204220412053204920430D . c j . T H E T H I R D B A S I C . 0020-003F 0D6279205461796C6F7220506F686C6D616E0D0D0D2E6C6A0D4578706C6F7269 . b y T a y l o r ~"File to dump: ";a$ a$=""100 #1,a$ ž#1100 cr$=13) #1;a$(a$=cr$2a$;F30dn than with regular FOR NEXT loops! In addition, REQUEST allows the Basic programmer to directly get device status, and use the SOS SETCONTROL mechanism. More details on this super-powerful module are in the documentation. we have left the era of "Voodoo Economics" (an unpopular phrase in Washington these days) and entered a new era of "Voodoo Basic". Oh well, maybe if I wore garlic while typing... files, .console, etc.). Numeric arrays can be stored about 20 times fasterthese days we'll get to graphics as well, and discuss how to use BGRAF and DOWNLOAD to create some really interesting stuff. Until then, just one last note. I looked back over this article and decided that the word "hex" was mentioned so many times thatvides some significant capability to the person interested in data analysis and sophisticated file indexing. I also promise to get to my thesis on PRINT USING, especially since Business Basic allows some tricks not available in most other Basics. One of writing of numeric arrays to disk should tune in next time when we show how to get at least twenty times the performance improvement over using FOR NEXT loops to accomplish the same task. That, combined with the huge memory space available for arrays, proly intended to explore one more topic which had previously generated questions, but this tome is now growing overlong. The topic I had in mind was the use of the REQUEST invokable module. Those of you who are writing programs which do lots of reading andtion is to effectively process console input without those characters being first processed by Basic. I just thought the examples above would give us a chance to explore several interesting topics at once. Final Thoughts (Bottom of the Bag) I had ful 14 20 Long Integer 3 18 24 String 4 21 33 Don't forget that the GET# statement can be used in lots of other interesting ways and that its primary funcble: Data type name TYP() function value Internal file code hex decimal Integer 2 12 18 Real 1 2062726F6164 a s t t i m e I d r o p p e d s e v e r a l b r o a d 0080-009F 2068696E74732061626F7574206E657720736F66747761726520616E64206861 h i n t s a b o u t n e w s o f t w a r e a n d h a 00A0-00BF 726477616E20616E79206F74686572207065 k s p a c e a v a i l a b l e i n a n y o t h e r p e 0380-039F 72736F6E616C20636F6D70757465722042617369632E2020284172656E277420 r s o n a l c o m p u t e r B a s i c . ( A r e n ' t 03w b e r e v e a l e d : 1 9 7 , 0 0 0 b y t e s ! 0340-035F 20546861742773206F7665722074687265652074696D65732074686520776F72 T h a t ' s o v e r t h r e e t i m e s t h e w o r 0360-037F 6B737061636520617661696C61626C652069i n n i n g t 0300-031F 6F20626520617661696C61626C652E202054686520616E737765722063616E20 o b e a v a i l a b l e . T h e a n s w e r c a n 0320-033F 6E6F772062652072657665616C65643A203139372C3030302020627974657321 n o 6865203235364B204170706C65202F2F2F206861732062 u k n o w , t h e 2 5 6 K A p p l e / / / h a s b 02E0-02FF 65656E20616E6E6F756E63656420616E6420697320626567696E6E696E672074 e e n a n n o u n c e d a n d i s b e g 6E b y t e s o f m e m o r y a r e a v a i l a b l e i n 02A0-02BF 2061203235364B204170706C65202F2F2F3F22202057656C6C2C20617320796F a 2 5 6 K A p p l e / / / ? " W e l l , a s y o 02C0-02DF 75206B6E6F772C2074h . L a s t t i m e I p 0260-027F 726F6D697365642074686520616E7377657220746F2022486F77206D616E7920 r o m i s e d t h e a n s w e r t o " H o w m a n y 0280-029F 6279746573206F66206D656D6F72792061726520617661696C61626C6520697920656E746875736961736D2E20204F6E65207468696E67206265666F726520 y e n t h u s i a s m . O n e t h i n g b e f o r e 0240-025F 77652073746172742C2074686F7567682E20204C6173742074696D6520492070 w e s t a r t , t h o u g 652061626F7574204261 t h i s i s s u p p o s e d t o b e a b o u t B a 0200-021F 7369632C2049276C6C2074656D706F726172696C7920726573747261696E206D s i c , I ' l l t e m p o r a r i l y r e s t r a i n m 0220-023F n g t h e n e w s o f t w a r e f o r t h 01C0-01DF 652072657374206F66207468697320636F6C756D6E2C206275742073696E6365 e r e s t o f t h i s c o l u m n , b u t s i n c e 01E0-01FF 207468697320697320737570706F73656420746F2062c h I 0180-019F 207265616C6C7920656E6A6F792E20204920636F756C6420676F206F6E206465 r e a l l y e n j o y . I c o u l d g o o n d e 01A0-01BF 7363726962696E6720746865206E657720736F66747761726520666F72207468 s c r i b i 656E20646F696E672074686573652061727469 s s e d , I ' v e b e e n d o i n g t h e s e a r t i 0160-017F 636C6573206F6E204170706C65777269746572202F2F2F2C2077686963682049 c l e s o n A p p l e w r i t e r / / / , w h i e a l e r a n d c h e c k s o m e o f t h e s e t h 0120-013F 696E6773206F75742E2020417320796F75206D69676874206861766520677565 i n g s o u t . A s y o u m i g h t h a v e g u e 0140-015F 737365642C2049277665206265o w y o u h a v e h 00E0-00FF 61642061206368616E636520746F20676F20646F776E20746F20796F75722064 a d a c h a n c e t o g o d o w n t o y o u r d 0100-011F 65616C657220616E6420636865636B20736F6D65206F66207468657365207468 72652068617070656E696E6773206F6E20746865204170706C65202F r d w a r e h a p p e n i n g s o n t h e A p p l e / 00C0-00DF 2F2F2E2020486F706566756C6C79206279206E6F7720796F7520686176652068 / / . H o p e f u l l y b y n A0-03BF 796F7520676C616420796F7527766520676F7420616E204170706C65202F2F2F y o u g l a d y o u ' v e g o t a n A p p l e / / / 03C0-03DF 3F2020446F6E277420796F752077697368206576657279626F6479206469643F ? D o n ' t y o u w i s h e v e r y b o d y d i d ? 03E0-03FF 292020576520776572652064697363757373696E6720736F6D6520736F727469 ) W e w e r e d i s c u s s i n g s o m e s o r t i 0400-041F 6E6720746563686E697175657320666F72206F7572206461746162. [ ! . A E F F E 7 0 6 5 00E0-00FF 14A13DE919180003860FE36DD4000000121956210944434243463530303814A2 . = . . . . . . m . . . . . V ! . D C B C F 5 0 0 8 . 0100-011F 0E25811800026E9D0BDEB00000001216AD210945464345423738373214A11BC1 14A007D1D0180002BAAF52D728000000120D54210943444146453336 9 0 5 7 . . . . . R ( . . . . . T ! . C D A F E 3 6 00C0-00DF 393814A20F63241800023D6C61382C00000012165B2109414546464537303635 9 8 . . c $ . . . = l a 8 , . . . . DE2109414442 D A D E 8 2 3 9 . . % { . . . 0 . . . . . . ! . A D B 0080-009F 41433434353014A135A30818000169EF7321C6000000120EE621094141424544 A C 4 4 5 0 . 5 . . . . i s ! . . . . . ! . A A B E D 00A0-00BF 393035374 2 . f . " . . . N . . . . . . ! 0040-005F 0943444341443130333114A14CCE1D18000373AD91E0A40000001223F6210944 . C D C A D 1 0 3 1 . L . . . . s . . . . . # ! . D 0060-007F 4441444538323339149E25AA7B180002FBF1C2308C000000120B0000-001F 0000000000000000000000000000000000000000000000000000000000001208 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 0020-003F 2C210943454542453435343214A16617221800034EA713C9C4000000121BC321 , ! . C E E B E 4 5 line$=line$+" ."::line$=line$+" "+a$Aa$=a$))F#2;a$,3,2);KiP#2:#2;" ";line$Ubytes=bytes+32Zeof.occurred=040_xi"File to dump: ";a$ a$=""95 #1,a$"File for output: ";a$ #2,a$ž#1eof.occurred=1:80#bytes=0:eof.occurred=0 (line$=""%-#2;bytes);"-";bytes+31);" "; 2i=132 7#1;a$#9val=a$):val>127val=val-1282<val<3274746564206F75747075742E20200D0D0D4F l l y n i c e f o r m a t t e d o u t p u t . . . . O 0500-051F 7572204D69786564204261670D0D u r M i x e d B a g . . t h e P r i n t U s i n g c a p a b i l i t i e s o f 04C0-04DF 20427573696E657373204261736963207768696368207065726D697420726561 B u s i n e s s B a s i c w h i c h p e r m i t r e a 04E0-04FF 6C6C79206E69636520666F726D61 o f i t e m s , a 0480-049F 6E64207468656E2067657420696E746F20612064697363757373696F6E206F66 n d t h e n g e t i n t o a d i s c u s s i o n o f 04A0-04BF 20746865205072696E74205573696E67206361706162696C6974696573206F66 6861742073706163652E2020546869732074696D65207765276C6C o f t h a t s p a c e . T h i s t i m e w e ' l l 0460-047F 206578706C6F72652061206D6978656420626167206F66206974656D732C2061 e x p l o r e a m i x e d b a g 617365206C n g t e c h n i q u e s f o r o u r d a t a b a s e l 0420-043F 6173742074696D652077686963682063616E206D616B6520676F6F6420757365 a s t t i m e w h i c h c a n m a k e g o o d u s e 0440-045F 206F662074 . % . . . . n . . . . . . . ! . E F C E B 7 8 7 2 . . 0120-013F E31800034AAD1A86780000001208E62109424544444631333433149F3A61A418 . . . J . . x . . . . . ! . B E D D F 1 3 4 3 . . : a . 0140-015F 0002A2ACA91A20000000 . . . . . . 0 =Q:WW=0A=:A=21A=9oldprefix$=A=31110A=27:=".D1":980A=13630=THPOS:B$(I);A<8A>11400A-7500,520,550,580:=THPOS:B$(I);:380: 500THPOS=4:I/2=I/2)I=I-1I=IBOTM THPEAD PASCAL TEXT FILES."04=10:"78C";"ANY KEY RETURNS TO THE MENU."!>G$:::".D1/MENU.MAKER",320R",220(204::"79A";""; 2D=1:F=1 <#4;a$ FD=D+1 P#5;a$ZD=60#5;12)dD=60D=1nF=F+1::d$;::Y=1100:Y x13402  CATCH PASCAL TEXT FILES 202 :F*=08:"78C";"SORRY BUT MENU.MAKER CAN'T R".D1/MENU.MAKER",220 d$="" A$="PRINTING "+B$(I),16,B)=01:=0::"80C";A$;:#3,B$(I),16,B)Z=1#3;b$:"78A";b$Z=Z+1:Z=18:1290 1260 #4,B$(I),16,B)#5,".PRINTER"+ž#4#5;12):::".D1/MENU.MAKE30C$="N"C$="n"1160;:=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING": $1020.202 8::Z=1B::=23:=0::"79C";"WOULD YOU LIKE A PRINTED COPY?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"1170*C$="N"C$="n"READC READC  #.-2hhhhHH`$.CONSOLE24320/JGApple 1.1R READC OS=44:I/2<>I/2)I=I+1&I2=-1:I=I-2:NIBOTM<30XTHPOS=44I=IBOTM/2)*2:=+IBOTM/2)-1:0b=+IBOTM/2-.5):I=IBOTM:I/2=I/2)I=I-1lvB=B$(I),16)," ")-1B$(I),"BASIC 0")700B$(I),"TEXT 0")740B$(I),"CAT 0")960B$(I),"FONT 0")1660B$(I),"FOTO 0")1730400A$="RUNNING "+B$(I),16,B)"79C";A$;:=0B$(I),16,B):A$="LISTING "+BWBUFLEN !UFLEN SOSWRITE$SWRITERWBUF BUF RETADDR ieB>INITCHK UITCHK MOVETO MOVETO  WBUFLEN _UFLEN SOSWRITEbSWRITE00:X::RELEASE:#530%& Menu.Maker v. 4.55.1 (side two)00:X::RELEASE:#530%& Menu.Maker v. 4.55.1 (side two)d.inv"C$=B$(I),16,B)array$="C%"name$=34)+C$+34)getfont(@name$,@array$)loadfont(@array$)30#5,".GRAFIX"".D1/BGRAF.INV"D$=B$(I),16,B)name$=34)+D$+34) GLOAD.D$16);1) GRAFIXONX=120);", ";"19";Р,2);" ";/П,2))=>13П,2))-12;џ,6);:1580$"П,2))=0"12";џ,6);:ٟ;$,П,2))=>12" PM-":" AM-" 61630@WW=1390J=26:=21:1400 T1400 ^:WW=1:h |: CHANGE THE FONT".D1/downloa="FEBRUARY":1550M$="MARCH":1550M$="APRIL":1550M$="MAY":1550M$="JUNE":1550M$="JULY":1550M$="AUGUST":1550M$="SEPTEMBER":1550M$="OCTOBER":1550M$="NOVEMBER":1550M$="DECEMBER":1550826);"-";M$;" ";Ѡ,2)8=11010<9F=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING":P2,280,2 Z1310dn"x ..... "DATE.TIME.LINE" ....M=Ҡ,4,2))BM1430,1440,1450,1460,1470,1480,1490,1500,1510,1520,1530,1540M$="JANUARY":1550M$SH$ SLOW FLASH :120#w=w+.5*(w=0):I=1(w*1000):: Halt Subroutine::=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING.": 1300(=23:=0::"79C";"CONTINUE...?":'(<>89<>121<>78<>11013202=70#4,B$(I),16,B)#5,".PRINTER" $ž#4120 .#4;a$ 8#5;a$ B1070LV:=24:=0::-`#8,".D1/FLASHNAME.DAT":#9;FLASH$:#8%jFLASH=110: FLASHER SUBROUTINEtSLOW=110~FLASH/2=FLASH/2):۴ =11:=07 FLA:=".d1":=12:=0:120=+B$(I),16,B)1408A$(1000),B$(1000),C%(511),C$(20),name$(20):=10:=0 :120;::=23:=0::"79C";"WOULD YOU LIKE A HARD COPY?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"1010C$="N"C$="n"12C$<>"y"C$<>"N"C$<>"n"850\C$="N"C$="n"1000;f:=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING": p840z2,280,21K:=23:=0::"79C";"TO PRINT OR RETURN TO MENU, HIT THE SPACE BAR":C$:C$<>" "930:ۺ1000 $(I),16,B)$=01:=0::"80C";A$;::12)E=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING"::2,280,21 840#2,B$(I),16,B) ž#2910*#2;A$:A$:12304810 >:120*H:=23:=0::"79C";"CONTINUE...?":0RC$:C$<>"Y"RWBUF ZRNJFCALCABS BRETADDR SOSDSTATSDSTATGSCB  MOVEREL MOVEREL INITCHK ITCHK WBUFLEN UFLEN SOSWRITESWRITERWBUF  RETADDR c _ < 8 INITCHK O ITCHK WBUFLEN Y UFLEN SOSWRITE\ SWRITERWBUF T L H D @ DOTAT DOTAT mand. The following simple program will illustrate, on the same subdirectory we just looked at: 1 INPUT"Directory to dump: ";a$ 10 OPEN#1,a$ 15 ON EOF#1 GOTO 60 20 INPUT#1;a$ 30 PRINT LEN(a$)":"a$ 50 GOTO 20 60 CLOSE 70 END The oGApple 1.1R READC YLOC  SDSTATGSCB  INITCHK  ITCHK XLOC XLOC RETADDR     SOSDSTAT SDSTATGSCB   INITCHK  ITCHK YLOC  ASADR SOSSMARK SSMARKRETADDR  z v INITCHK  ITCHK XYCOLOR XYCOLOR RWBUF  F SOSREAD  SREAD RETADDR  SOSDSTATGPGSREQD GSREQDSOSCLOSE SCLOSEGRAFIXMO AFIXMOGLOAD GLOAD RBUFLEN  N RWBUF    SOSREAD  EAD GBASADR GBASADR ( ASADR SOSDSTAT~ SDSTATGSCB  INITCHK { ITCHK CREFNUM  EFNUM RBUFADR  ADR SREFNUM  EFNUM RREFNUM  M WBUFADR   ADR GSAVE GSAVE WREFNUM F  M GPGSREQD5 GSREQDSOSCLOSE> SCLOSEWBUFLEN 8  LEN SOSWRITE; SWRITERWBUF C F INITCHK  ITCHK BMOVCHK  OVCHK INITFLG  ITFLG RWBUF  F SOSDSTAT" SDSTATGSCB % CB INITCHK  ITCHK CREFNUM  EFNUM  T P SOSDSTATj SDSTATGSCB LINEREL LINEREL INITCHK g ITCHK WBUFLEN  UFLEN SOSWRITE SWRITERWBUF } d ` \ X RELEASE RELEASE  RETADDR % ! INITCHK  ITCHK LINETO LINETO WBUFLEN  UFLEN SOSWRITE SWRITERWBUF     CALCABS x q ABS RETADDR CALCABS  ABS RETADDR  SOSDSTAT SDSTATGSCB INITCHK  ITCHK DOTREL DOTREL WBUFLEN  UFLEN SOSWRITE SWRITERWBUF nly thing unusual here is that we arranged to print the length of each string that is read, to check for any special formatting. The output looks like this: 68: MYSUB (12/29/81) V0 68: