ATARI PROGRAM LIBRARY
Ron and Lynn Marcuse
Freehold, NJ
One of the most difficult aspects of owning a home/personal computer is maintaining an accurate catalog of programs and data files. We first attacked this problem through the use of a home-grown data base which handled the program library in addition to other data. But, alas, it became too time consuming to manually update the data base as new programs were added or changes made. The logical extension to this concept was to automate the cataloging process. To accomplish this, one must compare the index of the disk to the program library file, adding or deleting records on the file as the comparison warrants. The ease of OPENing the ATARI'S DOS directory from BASIC greatly facilitated the programming, but more on this later.
Besides the automatic cataloging function, other required features were:
- Listing the directory from the program.
- Cataloging Non-DOS disks.
- Inquiry, Browse and formatted Print output of catalog records.
- Maintaining other data not supplied by the disk directory (source, description, type, and date).
- Sorting the file on any field (in machine language, for speed).
- An auto-locate function to RUN any program.
- Variable search criteria to locate any program.
- Creating an internal label to automatically identify a disk. All of these goals were achieved in the program which, incidentally, requires at least 24K RAM, one disk drive (810 or 815) and DOS II.
Table 1. List of variables. | ||
NAME | SIZE | DESCRIPTION |
AP$ | 21 | "ATARI PROGRAM LIBRARY" |
REC$ | 62 | Program Library Record |
VOL$ | 4 | Disk (or other) Volume Number |
DSN$ | 12 | Data Set Name (Filespec) |
DES$ | 22 | Description |
TYP$ | 7 | Type (Game, Data, etc.) |
SRC$ | 7 | Source |
DAT$ | 6 | Date (Entry, Version, etc.) |
SEC$ | 3 | Number of Sectors |
X$ | var | Input String (Main Prog and Sort) |
IN$ | 20 | Temporary String Storage |
PL$, PC$ | Filespecs (D : PROGLIB.DB & D : DISK.CAT) | |
SV$ | 20 | Search Value |
SS, SE | Search (and Sort) Start, End Positions | |
SK | Search Key | |
B | Transaction Type | |
R | Return Line Number from TRAPped Error | |
ST | IOCB STATUS Value | |
I, J, L, N | Counting for Loops, Lines, etc. | |
NP | Number of Files in Directory | |
IO | Input/Output Type | |
SEC, BYT | Sector, Byte values for NOTE, POINT | |
P | Output Type (1 = Inqy, 2 = Browse, 3 = Print) | |
EOF | Record Counter |
Table 2. Key conversion (Epson MX-80 printer). | |||
SYMBOL | ASCII VAL (Dec) | KEY SEQUENCE (ATARI) | DESCRIPTION |
[A] | 0 | CON; ,(comma) | Null; End of Tab Set Seq |
[B] | 9 | CON; I | Horizontal Tab |
[C] | 14 | CON; N | Print Double Width Characters |
[D] | 27,68 | ESC; ESC; D | Set Tab (followed by Tab Positions and NULL Char) |
[E] | 253 | ESC; CON; 2 | Console Bell |
[F] | 125 | ESC; CON; CLR | Clear Screen |
[G] | 29 | ESC; CON; = | Move Cursor Down |
[H] | 10 | CON; J | Line Feed |
Note: The string of X's in line 3090 are the printer tabs. Type the ASCII characters for these decimal values: 6, 20, 39, 53, 62, 70 (i.e. 6 is CON ;F) |
Program 1.
10 DIM AP$(21), PC$(10) : AP$ = "" 12 REM ** RON MARCUSE, FREEHOLD NJ ** 30 OPEN #2, 4, 0, "K:" : POKE B2, 0 : ? "[E]" 50 DIM REC$(62), VOL$(4), DSN$(12), DES$(22), TYP$(7), SRC$(7), DAT$(6), SEC$(3) 60 DIM X$(500), IN$(20), SV$(20), PL$(12) : PC$ = "D : DISK.CAT" : PL$ = "D : PROGLIB.DB" 100 GRAPHICS 0 : POKE 16, 64 : POKE 53774, 64:? :? , AP$:? ,"[6] CATALOG OPTIONS " 110 ? "[G] 1 AUTO CATALOG 5 UPDATE RECORD" 120 ? " 2 LIST DIRECTORY 6 SORT LIBRARY" 130 ? " 3 ADD DISK (NON DOS) 7 RUN PROGRAM" 140 ? " 4 INQUIRY/LIST 8 END SESSION" 160 GOSUB 6900 : TRAP 160 : B = VAL(CHR$(A)) : TRAP 40000 : IF B < 1 OR B > 8 THEN 160 170 B = B + 1 : IF B > 3 THEN 500 180 ? : IF B = 3 THEN 300 190 ? "" : GOSUB 6910 200 TRAP 240 : OPEN #3, 4, 0, PC$ : TRAP 40000 : INPUT #3, IN$ 210 IF LEN(IN$) < 14 OR IN$(1, 10) <> PC$ THEN ? " ERROR- ";PC$ : GOTO 250 220 B = 1 : VOL$ = IN$(11, 14) : GOTO 290 240 CLOSE #3 : R = 200 : STATUS #3, ST : IF ST <> 170 THEN 9000 250 ? "(DNNN) =>" ; : INPUT VOL$ : IF LEN(VOL$) = 0 THEN 100 260 R = 260 : TRAP 9000 : OPEN #3, 8, 0, PC$:? #3; PC$; VOL$ 290 CLOSE #3 : XIO 35, #3, 0, 0, PC$ 300 R = 300 : TRAP 9000 : OPEN #3, 6, 0, "D: *.*" : L = 0 310 TRAP 400 : INPUT #3, IN$ : TRAP 40000 320 IF LEN(IN$) < 17 THEN 400 330 IF B = 3 THEN ? , IN$ : L = L + 15 : GOTO 310 340 FOR I = 3 TO 10 : IF IN$ (I, I) <> " " THEN NEXT I 350 DSN$(1, 8) = IN$(3, 10) : DSN$(9, 9) = " " : DSN$(I - 1) = IN$(11, 13) 360 IF DSN$(I - 1) <> " " THEN DSN$(I - 2, I - 2) = "." 370 IF DSN$ = "DOS.SYS" OR DSN$ = "DUP.SYS" OR DSN$ = "MEM.SAV" OR DSN$ = "DISK.CAT" THEN 310 380 X$(L + 1, L + 12) = " " : X$(L + 1, L + 12) = DSN$ 390 X$(L + 13, L + 15) = IN$(15, 17) : L = L + 15 : GOTO 310 400 CLOSE #3 : NP = L/15 410 ? : ? "FILES FOUND = " ; NP ; ", FREE SPACE = " ; IN$(1, 3) 420 IF B < 3 THEN ? "DISK IS # " ; VOL$ : ?"" 430 GOSUB 6910 : IF NP = 0 THEN 100 500 ON B GOTO 1000, 1200, 100, 2000, 3000, 4000, 5000, 5500, 900 900 GRAPHICS 0 : END 950 GOSUB 6250 : GOTO 100 960 POP : GOTO 100 990 FOR I = 1 TO 300 : NEXT I : RETURN 1000 REM ** RE-CATALOG 1010 IO = 12 : GOSUB 6200 : SV$ = VOL$ : SK = 1 : SS = 1 : SE = 4 : EOF = 0 : L = 0 1020 GOSUB 7000 : IF SK = 9 THEN 1190 1030 FOR N = 1 TO NP : IF X$(N * 15 - 14, N * 15 - 3) = DSN$ THEN 1100 1040 NEXT N : REC$ (62) = "D" : ? "" ; DSN$ ; "DELETED ON" ; VOL$ : GOTO 1110 1100 REC$(59, 61) = X$(N * 15 - 2, N * 15) : X$(N * 15, N * 15) = "*" : L = L + 1 1110 POINT #3, SEC, BYT : ? #3 ; REC$ : GOTO 1020 1190 GOSUB 6250 : IF L = NP THEN 100 1200 REM ** AUTO CATALOG 1210 IO = 9 : GOSUB 6200 1220 FOR N = 1 TO NP : IF B = 1 AND X$(N * 15, N * 15) = "*" THEN 1240 1230 DSN$ = X$(N * 15 - 14, N * 15 - 3) : SEC$ = X$(N * 15 - 2, N * 15) : GOSUB 6800 1240 NEXT N : GOTO 950 2000 REM ** MANUAL ADD 2010 IO = 9 : GOSUB 6200 : GOSUB 6800 : GOTO 950 3000 ? "[F][6]" ; AP$; " - INQY/LIST" : N = 8 : GOSUB 6500 : ? 3020 ? " OUTPUT : ", " 1. INQUIRY"? , " 2. BROWSE" : ? , "3. LISTING" 3040 GOSUB 6900 : TRAP 3040 : P = VAL(CHR$(A)) : TRAP 40000 : IF P < 1 OR P > 3 THEN 3040 3050 L = 0 : IO = 4 : GOSUB 6200 : EOF = 0 : IF P < 3 THEN 3100 3090 R = 3090 : TRAP 9020 : OPEN #4, 8, 0, "P :" : TRAP 40000 : ? #4 ; "[D]XXXXXX[A]" 3100 GOSUB 7000 : L = L + 1 : IF SK > 8 THEN 3300 3110 ON P GOTO 3120, 3160, 3200 3120 GOSUB 7600 : ? 3130 L = 0 : ? " (E = END) OR" ; : GOSUB 6910 : IF CHR$(A) = "E" THEN 950 3140 GOTO 3100 3160 IF L = l THEN ? "[F][G]VOL FILE ID DESCRIP" : ? 3170 ? VOL$; " " ; DSN$ ; DES$ : IF L = 19 THEN 3130 3180 GOTO 3100 3200 IF L > 1 THEN 3220 3205 ? #4 ; "[B][C] ATARI PROGRAM LIBRARY[H]" 3210 ? #4 ; "DISK#[B]PR06/FILE ID[B] DESCRIPTIO[B]TYPE[B]SOURCE[B]DATE SECTORS[H]" 3220 ? #4 ; VOL$ ; "[B]" ; DSN$ ; "[B]" ; DES$ ; [B]" ; TYP$ ; "[B]" ; SRC$ ; "[B]" ; DAT$ ; "[B]" ; SEC$ 3230 IF L > 55 THEN L = 0 : ? #4 ; CHR$(12) 3240 GOTO 3100 3300 IF P = 3 THEN CLOSE #4 3310 IF P = 2 THEN GOSUB 6910 3320 GOTO 950 4000 ? "[F][G] " ; AP$ ;" - RECORD UPDATE" : N = 8 : GOSUB 6500 4010 IO = 12 : GOSUB 6200 : EOF = 0 4020 GOSUB 7000 : IF SK > 8 THEN 950 4030 GOSUB 7600 : ? : ? " TYPE FIELD # TO UPDATE, D TO DELETE" 4050 GOSUB 6910 : IF CHR$(A) = (D) THEN REC$(62) = "D" 4060 TRAP 4300 : C = VAL(CHR$(A)) : TRAP 40000 : IF C < 1 OR C > 7 THEN 4300 4100 RESTORE 9910 : FOR I = 1 TO C : READ IN$ : NEXT I : ? 4110 ? "ENTER NEN" : GOSUB 6040 + C : GOTO 4030 4300 GOSUB 6100 : POINT #3, SEC, BYT : ? #3 ; REC$ : GOTO 4020 5000 ? "[F][6] " ; AP$ ; " - SORT/COMPRESS" : N = 7 : GOSUB 6500 5010 ? " TYPE Y TO SORT ON FIELD # ";SK : GOSUB 6910 5020 IF CHR$(A)<>"Y" THEN 100 5040 POKE 207, SS-1 : POKE 208, SE-1 5050 ? " LOADING SORT PROGRAM" : RUN "D:PROGSORT" 5500 REM RUN PROG 5510 ? : ? " = =>"; : INPUT SV$ : I0 = 4 : IF LEN(SV$) = 0 THEN 100 5520 GOSUB 6200 : EOF = 0 : SS = 5 : SE = 4 + LEN(SV$):SK = 2 : GOSUB 7000 : IF SK = 9 THEN 950 5530 ? : ? " " ; VOL$;" TO RUN ";DSN$ 5540 ? : ? " TYPE ‘Y’ TO RUN" : GOSUB 6910 : IF CHR$(A)<>"Y" THEN 950 5550 IN$(3) = DSN$ : IN$(1,2) = "D : " 5560 ? : ? " LOADING ";IN$ : TRAP 5570 : RUN IN$ : TRAP 40000 5570 ? : ? " ";IN$;" NOT ON DISK" : GOSUB 990 : GOTO 950 6000 ? "[F][6] TO ADD ";DSN$;", ENTER : " 6010 RESTORE 9910 : FOR I = 1 TO 7 : READ IN$ 6020 IF B<3 AND (I = 1 OR I = 2 OR I = 7) THEN 6040 6030 ? : GOSUB 6040 + I 6040 NEXT I : RETURN 6041 ? "|----| ";IN$ : INPUT VOL$ : RETURN 6042 ? "|------------| ";IN$ : INPUT DSN$ : RETURN 6043 ? "|----------------------| ";IN$ : INPUT DES$ : RETURN 6044 ? "|-------| ";IN$ : INPUT TYP$ : RETURN 6045 ? "|-------| ";IN$ : INPUT SRC$ : RETURN 6046 ? "|------| ";IN$ : INPUT DAT$ : RETURN 6047 ? "|---| ";IN$ : INPUT SEC$ : RETURN 6100 FOR I = 1 TO 61 : REC$(I, I) = " " : NEXT I 6110 REC$(l,4) = VOL$ : REC$(5,16) = DSN$ : REC$(17,38) = DES$ : REC$(39,45) = TYP$ 6120 REC$(46,52) = SRC$ : REC$(53,58) = DAT$ : REC$(59,61) = SEC$ : RETURN 6200 R = 6200 : TRAP 9000 : IF 10<>4 THEN XI0 36, #3, 0, 0, PL$ 6210 OPEN #3,I0, 0, PL$ : TRAP 40000 : RETURN 6250 R = 6250 : TRAP 9000 : CLOSE #3 6260 IF I0<>4 THEN XI0 35, #3, 0, 0, PL$ 6270 TRAP 40000 : RETURN 6500 ? "[G] KEY : " : RESTORE 9910 6510 FOR I = 1 TO N : READ IN$ : ? ,I;" ";IN$ : NEXT I : ? ,"E END" : GOSUB 6900 6540 TRAP 960 : SK = VAL(CHR$(A)) : TRAP 40000 : IF SK<1 OR SK>N THEN 960 6550 IF SK = 8 THEN 6590 6560 RESTORE : FOR I = 1 TO SK : READ SS, SE : NEXT I : IF B = 7 THEN 6590 6570 ? " ENTER VALUE"; : INPUT SV$ : IF LEN(SV$)<1 THEN 960 6580 IF SS + LEN(SV$)-l> SE THEN 6570 6585 SE = SS + LEN(SV$)-1 6590 RETURN 6800 GOSUB 6000 : GOSUB 6100 : REC$(62) = "*" : GOSUB 7600 6810 ? "[G] TYPE ‘Y’ IF OK " : GOSUB 6910 : IF CHRt$(A)<>"Y" THEN 6800 6820 ? #3; REC$ : RETURN 6900 ? : ? " ==>"; : GET #2, A : ? CHR$(A) : RETURN 6910 ? " PRESS ANY KEY TO CONTINUE"; : GET #2, A : ? CHR$(A) : RETURN 7000 IF B = l OR B = 6 THEN NOTE #3, SEC, BYT 7010 TRAP 7060 : INPUT #3, REC$ : TRAP 40000 : IF REC$(62) = "D" THEN 7000 7020 IF SK = 8 THEN 7040 7030 IF SV$<>REC$(SS, SE) THEN 7000 7040 EOF = EOF + l : VOL$ = REC$(1,4) : DSN$ = REC$(5,16) : DES$ = REC$(17,38) : TYP$ = REC$(39,45) 7050 SRC$ = REC$(46,52) : DAT$ = REC$(53,58) : SEC$ = REC$(59,61) : RETURN 7060 SK = 9 : ? : ? " RECORDS FOUND = ";EOF : GOSUB 990 : RETURN 7600 ? "[F][G]" : RESTORE 9910 : FOR I = 1 TO 7 7610 READ IN$ : ? " ";I;" ";IN$; : GOSUB 7610 + I : NEXT I : RETURN 7611 ? VOL$ : RETURN 7612 ? DSN$ : RETURN 7613 ? DES$ : RETURN 7614 ? TYP$ : RETURN 7615 ? SRC$ : RETURN 7616 ? DAT$ : RETURN 7617 ? SEC$ : RETURN 9000 STATUS #3,ST : CLOSE #3:? " ERROR ";ST:GOSUB 6910:GOTO R 9020 STATUS #4,ST : CLOSE #4: ? " ERROR ";ST:GOSUB 6910 : GOTO R 9900 DATA 1, 4, 5, 16, 17, 38, 39, 45, 46, 52, 53, 58, 59, 61 9910 DATA ALL RECORDS
You did notice that there is a "II" after "DOS." ATARI has finally released the new version and, to say the least, it is a vast improvement. Not that we were unhappy with its predecessor, but it did tend to hide whenever one walked by with a can of "RAID" or "BLACK FLAG." Yes, there are bugs in DOS I, one of which leads the NOTE and POINT-commands (needed to update any record) somewhere into the twilight zone. This program can be modified to work under DOS I, but the explanation would probably take up the rest of the magazine. If you plan to do any serious file processing, it would be advisable to pick up a copy of DOS II. There are other advantages as well, such as less RAM used through the auto-swap feature (the program and DOS share the same area).
The three listings represent the main program, the sort program and the machine language sort routine. The sort program is executed by a RUN statement, allowing the DIMensioning of the rather large string necessary to sort the file in. It loads the file into X$ and calls the machine language sort through the USR function in line 70. You may POKE the routine into storage using the third BASIC program. You must do a BINARY SAVE (DOS II function "K") with AUTORUN.SYS as the file name, 0600 and 066D (hex) as the starting and ending addresses. A possible alternative to this would be to key the FOR/NEXT loop and DATA statements into the BASIC sort program, with the loop as line 14.
The main program begins with the DIMensioning of strings and OPENing of the keyboard in lines 30-60. The strings and other variables are detailed in the accompanying table. Graphics mode 0 is set and the <BREAK> key is disabled (POKE 16,64:POKE 53774,64) in line 100. This begins the start of the primary option menu as well. An option (from 1 to 8) is selected and held in variable B. Note that B is increased by 1 in line 170, allowing "Autocatalog" to split into two functions depending on whether or not the disk has already been cataloged. A "D:DISK.CAT" file, containing the volume number, is written on each as an internal label. If this file is found on any disk, the volume number is retrieved and a "re-catalog" function is performed. If not found, a new disk is assumed and the volume number is requested in line 250. One important note: there is a liberal use of subroutines in the program and, for expediency, we will get into them later.
The options that do not require a DOS directory (B>3) are shunted to line 500. Those that do are sent through the routine (lines 300-430) that OPENs the disk directory (IO = 6) and stores it as substrings of X$. The file name is translated into the more familiar format FILENAME.EXT in lines 340-360. File names equal to DOS.SYS, DUP.SYS, MEM.SAV or DISK.CAT are dropped at this point (Why catalog them?). Line 500 (ON B GOTO) then transfers program control to the routine that will process the requested option.
The "Re-catalog" function (B = 1, lines 1000-1110), after OPENing the library file for both input and output operation (IO = 12), extracts all records having that volume number. These are then compared to the directory string (X$). Changes and deletions are posted to the file using the NOTE and POINT commands. An asterisk (*) is moved to each directory member that was successfully matched to the library. At the conclusion of this procedure, control is passed to "Auto-catalog."
The "Auto-catalog" function (lines 1200-1240) OPENs the file for output (append, IO = 9) operation. All new entries, as per the X$ directory, are shuffled through the proper subroutines and then added to the file. Option 1 (B = 1 or 2) travels this route, with (1) being "Re-cataloged" first. The significance of the asterisk on matched directory members becomes apparent in the bypass on line 1220. The file is then CLOSEd and we return to the option menu.
Option 2 (B = 3) consists of displaying the DOS directory and then returning to the menu. The remaining options (B>3), not requiring any help from the directory, go straight into their respective procedures. Option 3 (B = 4) handles the manual addition of library records to the file. This could be utilized for Non-DOS disks or even cassette tapes. Line 2010, helped by several subroutines, does all of the processing.
The inquiry and print option (B = 5) is handled in lines 3000-3320. The search strategy (GOSUB 6500) and output mode are selected, the file is OPENed for input (IO = 4) and, if applicable, the print tabs are set. The file is actually read in the subroutine at line 7000, with only the records matching the search key being passed back. An inquiry goes to line 3120, the browse (19 records per screen) to line 3160 and print (55 records per page) to line 3200. For the multiple record options, the variable L is the line counter. When end of file is reached at line 7010, the search key (SK) is set to "9" indicating completion, the file and printer are closed, and we are back at the menu.
The Update option (B = 6, lines 4000-4300) would be used for changing or deleting library records. The search key is selected, file OPENed (IO = 12) and records read like the inquiry, but here only the full record is displayed. At this point (line 4030), typing the field number will cause updating of that field and "D" the deletion of the record. Any other character will write (using POINT) the record.
The sort (B = 7, lines 5000-5050), as stated earlier, is executed through a RUN "D:PROGSORT statement. Before this is done, the sort key is selected and its offset (beginning and ending positions) is POKEd into locations 207 and 208 (decimal) for use by the machine language program. These addresses, as well as those on page 6 (1536-1791) containing the sort program, are safe from the ravaging effects of RUN, LOAD and NEW. The RUN PROGRAM option (B = 8, lines 5500-5570) adds a little touch of class to the library. By inserting the program name when requested, it will tell you which disk to load and will then RUN it. Obviously, it will only function with BASIC programs that have been SAVEd on disk. The final option (B = 9) terminates the system. The BREAK key, disabled in line 100, could have disastrous effects on the file if used to end the program at the wrong time.
A few notes on the subroutines that do most of the work in the program. The routine starting at line 6000 is used for the input of data for both adding and updating records. The labels for the individual fields, being DATA statements, are READ during the FOR/NEXT loop in line 6010. The library record (REC$) is built from the individual fields at line 6100. Lines 6200 and 6250 OPENs and CLOSEs the file. The search and sort keys are built at line 6500, using the same DATA statements as above for the headings. The positions of the fields are contained in another DATA statement. Lines 6900 and 6910 are prompts. The library record is READ and moved into its elements in line 7000-7060. The variables SV$, SS, SE and SK are used in the search process. The full screen display of the record is taken care of by 7600-7617, once again using the heading DATA statements. Finally, the error routines for the disk drive and printer are found at lines 9000 and 9020. The variable R is the return line number.
Program 2.
10 REM ** ATARI PROGRAM LIBRARY SORT ** 11 REM ** R MARCUSE 15 A = FRE(0)-800 20 DIM X$(A),REC$(62),AP$(12):AP$ = "D:PROGL IB.DB":? "LOADING FILE" 30 TRAP 130 : OPEN #3, 4, 0, AP$:N = 0 40 TRAP 60 : INPUT #3,REC$ : TRAP 40000: IF REC$(62) = "D" THEN 40 50 N = N + 1: X$(N$62-61,N$62) = REC$: GOTO 40 60 CLOSE #3:? "RECORDS LOADED = ";N;", BEGIN SORT" 70 IF N>1 THEN A = USR(1536,ADR(X$),N) 80 ? "[E] " 90 XIO 36, #3, 0, 0, AP$ : OPEN #3, 8, 0, AP$ 100 FOR 1 = 1 TO N: REC$ = X$(I*62-61,I*62):? #3;REC$: NEXT I 110 CLOSE #3 : XIO 35, #3, 0, 0, AP$ 120 ? "[E] LOADING PROGLIB": RUN "D: PROGLIB" 130 STATUS #3,ST: CLOSE #3:? " , ERROR ";ST 140 ? " PRESS RETURN TO CONTINUE": INPUT REC$ : GOTO 30
Program 3.
10 REM ** PROGLIB MACHINE LANG SORT ** 11 REM ** R MARCUSE ** 12 REM BINARY SAVE WITH FILESPEC = AUTORUN.SYS 20 FOR I = 0 TO 109: READ A: POKE 1536 + I, A : NEXT I 100 DATA 104, 104, 133, 216, 104, 133, 215, 104, 133, 213, 104, 133, 212, 169, 0, 133, 209, 133 110 DATA 214, 162, 1, 165, 215, 133, 205, 165, 216, 133, 206, 24, 165, 205, 133, 203, 105, 62 120 DATA 133, 205, 165, 206, 133, 204, 105, 0, 133, 206, 164, 207, 177, 205, 209, 203, 144, 11 130 DATA 240, 2, 176, 28, 196, 208, 176, 24, 200, 144, 239, 169, 1, 133, 209, 160, 62, 136, 177 140 DATA 205, 72, 177, 203, 145, 205, 104, 145, 203, 192, 0, 208, 241, 232, 224, 0, 208, 2, 230 150 DATA 214, 228, 212, 208, 188, 165, 213, 197, 214, 208, 182, 165, 209, 201, 0, 208, 160, 96
As there are several unprintable characters in the programs, we have substituted others in their place in the BASIC listings. Take a peek at the conversion table before typing. For a better visual effect, the characters enclosed by a box should be typed in reverse video. The two programs call each other by name, so please save them by the names "D:PROGLIB" and "D:PROGSORT". Some last thoughts: The machine language sort routine will not be in storage unless you put it there by either powering up (AUTORUN.SYS will boot in) or doing a DOS binary load. Create the PROGLIB file by typing (in direct mode):
OPEN #3, 8, 0, "D:PROGLIB.DB": CLOSE #3 : XIO 35,#3, 0, 0, "D:PROGLIB.DB".
Good luck.