297 lines
15 KiB
Groff
297 lines
15 KiB
Groff
|
||
|
||
|
||
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.
|
||
|
||
|