textfiles/apple/DOCUMENTATION/aplwrks.util.2

297 lines
15 KiB
Groff
Raw Normal View History

2021-04-15 11:31:59 -07:00
APPLEWORKS UTILITY TECH NOTE CECIL FRETWELL 6-MAY-87 PAGE 1
AN APPLEWORKS UTILITY
by
Cecil Fretwell
2605 Highview Ave.
Waterloo, Iowa 50702
(319) 236-0961
6-May-87
--------------------
TECHNICAL DISCUSSION
--------------------
Several technical aspects can be learned by studying the logic of this
program. Lines 240 to 300 install a special ampersand function which
allows one to delete an array after it has been dimensioned and used
to the extent of its useful life. As the discussion to follow will
show, the entries in a subdirectory are collected in an appropriate
array, sorted, and then displayed or printed. By deleting an array
after it has been used, valuable variable storage and its associated
strings are recovered. Also, using this technique allows one to
redimension an array in a program. The power of this technique will
become more evident as this discussion progresses.
The logic of the ampersand function is reasonably simple. In the
listing given below, Lines 37 to 42 insure no syntax errors, verify
the specified array exists, and sets up pointers to the array name.
Lines 43 to 65 set up the process to remove the specified array from
the array variable table. Once these are set up, the routine exits
through the monitor routine MOVE at $FE2C with the end result of
having the array removed.
1 ***********************************
2 * AMPERSAND FUNCTION TO DELETE AN *
3 * ARRAY VARIABLE. MODIFIED CODE *
4 * OBTAINED FROM CALL A.P.P.L.E. *
5 * ALL ABOUT APPLESOFT. *
6 * SYNTAX IS *
7 * & FRE XX$ *
8 ***********************************
9
10 *****************************
11 * PREPARED USING MERLIN PRO *
12 *****************************
13
14 ORG $2F0
15
16 A1L = $3C ;BOTTOM OF MOVE POINTER
17 A2L = $3E ;TOP OF MOVE POINTER
18 A4L = $42 ;DESTINATION POINTER
19 STREND = $6D ;END OF VAR POINTER
20 LOWTR = $9B ;ARRAY ADDRESS POINTER
21 CHRGET = $B1 ;GET NEXT TOKEN
APPLEWORKS UTILITY TECH NOTE CECIL FRETWELL 6-MAY-87 PAGE 2
22 CHRGOT = $B7 ;GET CURRENT TOKEN
23 AMPERV = $3F5 ;AMPERSAND VECTOR
24 SYNERR = $DEC9 ;REPORT SYNTAX ERROR
25 GETARYPT = $F7D9 ;GET ARRAY POINTER
26 MOVE = $FE2C ;MOVE SUBROUTINE
27
02F0: A2 02 28 INIT LDX #2 ;SET UP '&' VECTOR
02F2: BD FD 02 29 :1 LDA AMPJ,X
02F5: 9D F5 03 30 STA AMPERV,X
02F8: CA 31 DEX
02F9: 10 F7 32 BPL :1
02FB: 18 33 CLC
02FC: 60 34 RTS
02FD: 4C 00 03 35 AMPJ JMP FUNCS ;'&' JMP INSTRUCTION
36
0300: 20 B7 00 37 FUNCS JSR CHRGOT ;GET CURRENT TOKEN
0303: C9 D6 38 CMP #$D6 ;FRE?
0305: F0 03 39 BEQ :1 ;IF YES, BRANCH
0307: 4C C9 DE 40 JMP SYNERR ;ELSE SYNTAX ERROR
030A: 20 B1 00 41 :1 JSR CHRGET ;GET NEXT TOKEN
030D: 20 D9 F7 42 JSR GETARYPT ;FIND THE ARRAY
0310: A0 02 43 LDY #2 ;SET UP BOTTOM OF MOVE,
0312: 18 44 CLC ;TOP OF MOVE, AND THE
0313: A5 9B 45 LDA LOWTR ;DEST ADDRESS FOR
0315: 85 42 46 STA A4L ;USE BY MONITOR MOVE
0317: 71 9B 47 ADC (LOWTR),Y ;ROUTINE
0319: 85 3C 48 STA A1L
031B: A5 9C 49 LDA LOWTR+1
031D: 85 43 50 STA A4L+1
031F: C8 51 INY
0320: 71 9B 52 ADC (LOWTR),Y
0322: 85 3D 53 STA A1L+1
0324: 38 54 SEC
0325: A5 6D 55 LDA STREND ;ALSO CORRECT THE END
0327: 85 3E 56 STA A2L ;OF VARIABLES POINTER
0329: 88 57 DEY
032A: F1 9B 58 SBC (LOWTR),Y
032C: 85 6D 59 STA STREND
032E: A5 6E 60 LDA STREND+1
0330: 85 3F 61 STA A2L+1
0332: C8 62 INY
0333: F1 9B 63 SBC (LOWTR),Y
0335: 85 6E 64 STA STREND+1
0337: A0 00 65 LDY #0
0339: 4C 2C FE 66 JMP MOVE ;GO MOVE AND RETURN
Lines 310 to 580 represent the code to provide the main menu control.
Once a function is performed, control always returns to Line 360.
Lines 590 to 4120 provide the logic to display a catalog or print a
catalog. Using a simple flag in PF$, the same code can be used for
both functions. The logic starts with the necessary code to prompt
for a volume or subdirectory name and initialize the display or print
process. This is performed in Lines 590 to 810.
APPLEWORKS UTILITY TECH NOTE CECIL FRETWELL 6-MAY-87 PAGE 3
The logic in Lines 840 and 850 causes the DIM statement in Line 860 to
reserve exactly enough space for the entries in the first root
directory or sub directory. Line 840 uses HIMEM to locate the 1K
buffer established for the OPENed directory file. Based on technical
knowledge of file handling techniques used by BASIC.SYSTEM, the logic
of Line 850 then picks up the number of entries as stored in the first
block describing the entires in the directory.
The actual display or print of the desired catalog starts in Line 820.
Notice the OPEN with the TDIR parameter in Line 820. Under ProDOS, a
directory file may be opened and read just like a sequential file.
What is returned by each INPUT statement is the same as that displayed
by a CATALOG command with things like file name, file type, etc.
returned in a fixed format. With this in mind, Line 870 reads the
volume or subdirectory name, ignores the following blank line, and the
CATALOG header line.
Lines 880 to 940 input and collect each line in the CATALOG display.
This logic uses the BLOCKS FREE... line as an end of file marker
instead of using ONERR processing to trap a true end of file.
After a line for a file is read, the input is processed by the
subroutine in Lines 1540 to 1780. This subroutine returns a string
whose contents are as follows:
Position Contents
-------- --------
1 File status. "*" = locked. " " = unlocked
2-16 File name
17-31 File type, e.g., SYSTEM PROGRAM
32-41 Modification date dd-mmm-yy
42-49 Right justified file length in terms of K
50-... Left justified file length in terms of K
This string is then added to the array for the volume or subdirectory
entries.
Lines 990 to 1100 sort the array in ascending order by file name
and/or directory name. This code is a modification of the code
presented by Garry G. Kiziak in "The Compact Sorter", NIBBLE Vol4/No.
1. It is a very fast sort routine worthy repeating here in its more
general form.
10 Z = 1
20 Z = 3 * Z + 1 : IF Z < NUM THEN 20
30 Z = (Z - 1)/3 : IF Z < 1 THEN RETURN
40 FOR I = Z + L TO H : J = I - Z
50 K = J + Z : IF A = (MID$(NA$(J),M,N)>
MID$(NA$(K),M,N)) THEN TEMP$ = NA$(J):
NA$(J) = NA$(K) : NA$(K) = TEMP$ :
J = J - Z : IF J >= L THEN 50
60 NEXT I : GOTO 30
In this subroutine,
APPLEWORKS UTILITY TECH NOTE CECIL FRETWELL 6-MAY-87 PAGE 4
NA$ = the array to be sorted.
L = the starting subscript for the sort.
H = the ending subscript for the sort.
M = the column at which the sort begins.
N = the number of columns to be sorted.
A = the value 1 if an ascending sort is
required, or the value 0 if a descending
sort is required.
To quote Garry, "this routine is supposed to be a modified SHELL
METZNER sort. It might be called the SHELL SHUTTLE sort since it is
also a modified version of the SHUTTLE INTERCHANGE sort". Based on my
extensive use of the algorithm, I have found it to be very fast.
Garry also presents a machine language form which really makes a sort
in BASIC fly.
With the array sorted, Lines 1840 to 1950 display the contents of the
array. Each line of the display starts at the left margin. When the
array is completely displayed, Lines 1960 to 2170 display the final
line showing space free, space used, and total space on the volume.
Control is then passed back to the main menu logic starting at Line
360.
Going back to the display of the array process, if Line 1940 finds a
directory entry in the array, control passes to Lines 2230 to 2680.
Basically, this logic reads the entries for the subdirectory, sorts
them, and displays them.
First note Lines 2230 and 2240. The program could have been designed
to dimension the subdirectory arrays once at the beginning of the
program. This has a couple of problems. First, there is the problem
of how big to make the arrays. Subdirectories are not limited to 51
entries, therefore, too small a dimension might make the program bomb
with a subscript out of range error. Too large a dimension might make
the program bomb with an out of memory error. To minimize this
problem, Line 2230 results in a D1 which is the number of directory
blocks in the subdirectory. Each block can hold a maximum of 13
entries, therefore, Line 2240 dimensions an array with a proper size
to accommodate the subdirectory entries.
The second problem involves garbage collection. Even though I force
garbage collection at appropriate points in the logic, after an array
is used, its strings still exist in string storage. When the array is
used again, new strings are built and, based on experience, without
deleting the array after it has been used, the garbage collection
logic is invoked more often.
To minimize problems with potential out of memory conditions and
garbage collection, the array is deleted after it has been used.
With this in mind, let's continue with the discussion of processing a
subdirectory under the root of the volume. Lines 2290 to 2380 read
the subdirectory entries into an array in a manner exactly as
described for the root entries. In Line 2410, if there are no entries
APPLEWORKS UTILITY TECH NOTE CECIL FRETWELL 6-MAY-87 PAGE 5
in the subdirectory, control is passed to Line 2660 in which the D1$
array is deleted then control is passed to Line 1950 to continue
processing of the root entries.
If the subdirectory is not empty, Lines 2420 to 2540 sort the array
using the sort algorithm described earlier. Lines 2550 to 2650
display the entries in the subdirectory with each line indented over
three spaces. The final result of the display or print provides a
layout in which subdirectories can be quickly located.
Once the subdirectory has been completely processed, Line 2660 deletes
the array, garbage collection is forced, and control is passed to Line
1950 to continue processing of the root entries.
A subdirectory under the root can also contain subdirectories. If
Line 2640 detects a subdirectory, control is passed to the logic in
Lines 2780 to 3220. This logic is an exact duplicate of the logic in
Lines 2230 to 2680 with D1 replaced by D2, R$ replaced with D1$, and
L1 replaced by L2. Each displayed or printed line is indented over
five spaces from the left margin. When this subdirectory is
completely processed, Line 3200 deletes the array, garbage collection
is forced, and control is passed to Line 2650 to continue processing
in the first level subdirectory.
A subdirectory under a subdirectory can also contain subdirectories.
If Line 3180 detects a subdirectory, control is passed to the logic in
Lines 3320 to 3750. Again, logic is duplicated with D2 replaced by
D3, D1$ replaced by D2$, and L2 replaced by L3.
The logic described here assumes only three levels of subdirectories
under the root. Modifying the logic to include another level is
relatively easy. Add a Line 3715 to look for a subdirectory entry
using say Line 3180 as a model. Duplicate Lines 3320 to 3750 starting
after the end of the program at Line 4870. Now change each D2 to D3,
each D3 to D4, each D3$ to D4$, and each L3 to L4. Add a couple of
spaces to the copied Line 3640 and delete a couple of periods from the
copied Line 3690. Finally replace the GOTO 3190 in the copied Line
3750 to GOTO 3720.
Lines 4180 to 4370 handle the LOCK A FILE logic. Lines 4430 to 4620
handle the UNLOCK A FILE logic. Lines 4680 to 4870 handle the START
UP APPLEWORKS logic. The logic of these three functions is reasonably
straightforward and require no technical discussion.
This program should be a very useful addition to any library - it
certainly has been to mine. It has been tested by several non
technical types like my wife who rarely work outside the world of
Appleworks.