SETUP.SYSTEM – A Proposed Startup File Standard

Call-A.P.P.L.E. Magazine – November 1987 – PP14-23

This article describes a program which lets you easily install customizing routines, such as a RAMdisk and clock card drivers, on bootup into ProDOS, It mimics, under ProDOS 8, the SYSTEM.SETUP feature of ProDOS 16. It is emphatically placed in the public domain: I urge software publishers to take it and include it where appropriate with their own programs. I only ask that you take the program unmodified. It would be unfortunate if variants of the program spread around, each subtly incompatible with the others.

One feature which makes ProDOS 16 a more powerful operating system than ProDOS 8 is its flexible and complicated startup sequence. This includes the ability to boot up into either ProDOS 8 or ProDOS 16 based applications, as well as automatically installing, on bootup, patches in RAM to the Apple IIGS toolbox. ProDOS 16 accomplishes this by loading and executing all files found in the /SYSTEM/SYSTEM.SETUP subdirectory. These files must include TOOLSETUP, but may include other files for installing desk accessories, diagnostic and debugging routines, or anything else you can think of.

SYSTEM.SETUP is a nice idea. It allows you to specify what happens at boot up simply by placing the correct files in a particular subdirectory. Unfortunately, ProDOS 8 does not support SYSTEM.SETUP. If it did, it would be much easier to install IIe RAM disk drivers, clock card drivers, and IIGS Classic Desk Accessories on ProDOS 8 disks.

Suppose you have a large memory card in your IIe, and you want a RAM disk driver for it to be installed automatically every time you boot. Here are two ways you could do it:

  1. If the RAM disk driver is a system program, you could place it first on the disk so that it’s automatically called on boot up. When the system program quits, you then type in the name of the next system program to run, such as “BASIC.SYSTEM”.
  2. If the RAM disk driver is a binary file, you can place BASIC.SYSTEM first, and have a BASIC program called STARTUP which BRUNs the RAM disk driver. This is fine, as long as you plan to boot up into BASIC.

If you have both a large memory card and a clock card, you may need to install drivers for both of them. Now things become more difcult for you, particularly if your memory card came with a SYStem file program to install the RAM disk, and your clock card came with a BINary file clock driver. SETUP.SYSTEM (note: not SYSTEM.SETUP) automates the bootup sequence for you. To use it, assemble it and make it the first SYStem program on your disk whose name ends in “.SYSTEM”. This ensures that it will be run on boot up. Then create a subdirectory called “SETUPS”, containing the files which you want to be executed on boot up. That’s all there is to it.

Many existing programs already work with SETUP.SYSTEM. I have used it with the RAM disk drivers for both Applied Engineering’s and Checkmate Technologies’ IIe memory cards, and with Diversi-Cache and Diversi-Hack (1165 classic desk accessories by Bill Basham).

When run, SETUP.SYSTEM will search for the SETUPS subdirectory in the volume directory of the last disk accessed. It then loads and executes, in turn, each SYStem or BINary file in the SETUPS subdirectory. These files I refer to as “setup files.” When all setup files have been called, SETUP.SYSTEM then looks for the second system file in the main volume directory whose name ends in “.SYSTEM”, and runs that. This second “.SYSTEM” program is your main application. It can be BASIC.SYSTEM, your assembler, word processor, AppleWorks, or any other ProDOS application.

SETUP.SYSTEM was especially written to be compatible with already existing RAM disk drivers, clock drivers, and Apple IIGS Classic Desk Accessories under ProDOS 8. The rules for compatibility are simple. Setup files must be either BINary files or SYStem programs in the SETUPS subdirectory. This is in contrast to ProDOS 16’s SYSTEM.SETUP, which uses new ProDOS 16 file types exclusively. You may place other file types in the SETUPS subdirectory, such as text files, but SETUP.SYSTEM will ignore them. BINary setup files may load anywhere in either memory range $200-$3EF or $800-$BEFF. They should exit with an RTS. You may also place SYStem programs in the SETUPS subdirectory. These SYStem programs. as usual, must load at S2000, and must not exceed $B8FF when loaded. SYStem setup programs should exit with a ProDOS QUIT call. Most SYStem programs do this, although there are exceptions. A few exit by looking for the next SYStem program to run by name, or look for and run the second “.SYSTEM” file on the disk. Programs which do this are incompatible with SETUP.SYSTEM. Among the few system programs which are incompatible for this reason is the original version of the ProDOS FILER.

Once the setup program is in memory, it may use any memory except for pages $BD and $BE, which is where SETUP.SYSTEM lives in hibernation, and the ProDOS global page at $BF00. Because of this memory restriction, some existing SYStem programs may not be used as setup files. You should not, for instance, place BASIC.SYSTEM in the SETUPS subdirectory. BASIC.SYSTEM relocated itself to $9A00-$BEFF, overwriting SETUP.SYSTEM. If you do so, and then type “BYE” from BASIC, your Apple will explode into a reball, destroying all life other than insects within a half mile radius. Really.

A third reason why system programs may not work in the SETUPS subdirectory is that they may require subsidiary files ó which must also be placed in the SETUPS subdirectory. If these subsidiary files are BINary or SYStem files, SETUP.SYSTEM will eventually try to call them on their own. This problem happened to me when I moved the Apple IIGS System Utilities into my SETUPS directory. (Why? So I could copy some files onto my RAM disk on bootup.) The problem was solved by changing the file type of the three BINary files which the System Utilities needed. I gave them file type codes of $03. which is a defunct Apple III Pascal Text file code. The point was, SETUP.SYSTEM cared what the le types were and the System Utilities didn’t. I should point out that placing random system programs in your SETUPS subdirectory can be dangerous. By trial and error, I found that the GS System Utilities left the crucial pages $BD and $BE undamaged.

If you plan to write new setup programs, I recommend that you make them BINary files rather than SYStem programs. SETUP.SYSTEM temporarily redirects the ProDOS quit vector at $BF03 into itself before calling any SYStem programs in the SETUPS subdirectory. Therefore, when the setup program executes a ProDOS Quit call, control is returned to my code. This is not kosher programming, and may not work with future revisions of ProDOS. I added the feature solely so that many already existing SYStem programs could be used with SETUP.SYSTEM.

Typing it in

Although the program below was assembled using the Merlin Pro assembler, I tried to avoid as many Merlin-specific psuedo ops as possible and present a generic assembly listing. In order to assemble it on other assemblers, some minor changes will be necessary: The psuedo-op “ASC” in Merlin creates either high or low ASCII characters, depending on whether the string is surrounded by a single quote (low ASCII) or a double quote (high ASCII), I used both varieties. Users of EDASM, APW, or ORCA/M should add the MSB psuedo-op where needed. The last byte of the program is a checksum byte. It is the exclusive-OR of all the previous bytes in the program. If you assemble the program using Merlin, be sure to check that the byte you get is the same as the one in the listing. If it isnët, you made a typo.

If you are not using Merlin, replace the last line with

DFB $E8

and run the following program to check that the code is correct:

10 PRINT CHR$(4) "BLOAD SETUP.SYSTEM,A$2000,TSYS"
20 FOR X=8192 TO 8703
30 SUM=SUM+PEEM(X)
40 NEXT
50 IF SUM=64732 THEN PRINT "OK":END
60 PRINT "ERROR"

Program Logic

SETUP.SYSTEM is not a model of good programming practice. In order to get all the functionality I wanted into 512 bytes, I had to resort to self-modifying code. If the program went one byte over, to 513 bytes, the storage space on disk would mushroom from one block to three.

Among the first tasks of SETUP.SYSTEM is to relocate itself from it’s load address of $2000 to it’s running address of $BD00. SETUP.SYSTEM must move itself out of the way so that it can load other system programs without overwriting itself. Lines 48 through 54 in the program listing accomplish this. Next, the program (lines 61 through 72) tries to determine the name of the disk from which SETUP.SYSTEM was run. This name is saved so that the program can set the ProDOS prefix to the volume directory at a later time. The quit vector in the ProDOS global page is then saved (lines 73-76) so that it can be restored on exit.

Control returns to line 78 at the label MainLoop, before and after executing each of the setup files. The reset vector and the quit vector are both redirected to point to MainLoop, to increase the chances of SETUP.SYSTEM regaining control after calling setup programs. The system bitmap is then cleared so that we can load the setup file (lines 87-95), and the machine is then put into as normal a state as possible (lines 96-103).

Lines 106 through 127 make sure that the original volume is in the disk drive, and sets the ProDOS prefix to that volume. If the disk isn’t around, a warning message is displayed, and the user is given a chance to insert the correct disk.

Line 129 calls a subroutine called NextFile, which reads the SETUPS subdirectory until it finds the name of the next BINary or SYStem program. It leaves that name in a known place. If it finds no more SYStem or BINary files it exits with the carry set. This will happen when all of the setup files have been loaded and executed ó that case will be dealt with later.

If NextFile found the name of a setup file, we proceed to line 132. Here the prefix is set to the SETUPS snbdirectory, and the setup file is loaded into memory by calling the subroutine ReadFile, which starts at line 240. If there was no error when loading it, the setup file in memory is called. One way or another, control retums to MainLoop, either through the ProDOS Quit call, the user pressing RESET, or the setup file exiting with an RTS.

Once all the setup files have been loaded, we go to line 139 and restore the original ProDOS quit vector. Lines 145 through 149 then modify the NextFile routine so that it works rather differently. Where before NextFile looked for either BINary or SYStem files, now it will look for only SYStem ones. NextFile used to look in the SETUPS subdirectory. It now looks in the volume directory. NextFile will now be used to find the name of the system program to exit to.

NextFile is called repeatedly, returning the names of all SYStem programs in the volume directory (line 150). Lines 152-159 make sure that the filename ends in “.SYSTEM”. If it passes this test, we then check that it is not the first “.SYSTEM” file on the disk (lines 160-162). The first “.SYSTEM” file on the disk is presumably “SETUP.SYSTEM”, and we don’t want to run that, or we’d go into an endless loop. The system file is loaded, and called (line 163) with the same subroutine, ReadFile, which was used to load and call setup files. The difference is that this time we never come back, since the ProDOS quit vector has been restored to its original value.

Program Listing

                1    *
                2    * SETUP.SYSTEM by Sean Nolan
                3    *
                4    * A Proposed Startup File Standard
                5    *
                6    * Published in Call-APPLE, November, 1987
                7    * This program is in the public domain.
                8    *
                9    * This program mimics the ProDOS 16
                10   * SYSTEM.SETUP convention. It can be used
                11   * to install RAM disk drivers, clock
                12   * drivers, and IIGS Classic Desk
                13   * Accessories on bootup under ProDOS 8.
                14   *
                15   * This program loads and calls all BINary
                16   * and SYStem files in a subdirectory named
                17   * SETUPS. It then looks for the second
                18   * system program in the volume directory
                19   * whose name ends in ".SYSTEM", and runs
                20   * that.
                21   *
                22   *
                23            TYP   $FF        ;save as a system file
                24            ORG   $BD00      ;load at $2000, but run at $BD00
                25   ******************* equates
                26   CH       =     $24        
                27   IN2      =     $280       
                28   FILETYPE =     IN2+16     
                29   AUXCODE  =     IN2+31     
                30   RESET    =     $3F2       
                31   IOBUFFER =     $B900      
                32   PRODOS   =     $BF00      
                33   QUITVECT =     $BF03      
                34   DEVNUM   =     $BF30      
                35   BITMAP   =     $BF58      
                36   INIT     =     $FB2F      
                37   VTABZ    =     $FC24      
                38   HOME     =     $FC58      
                39   RDKEY    =     $FD0C      
                40   SETVID   =     $FE93      
                41   SETKBD   =     $FE89      
                42   SETNORM  =     $FE84      
                43   ******************* boot code
                44   VOLNAME  =     *          ;The first 17 bytes are overwritten with the
                45                             ;name of the volume from which this was run.
BD00: A2 01     46            LDX   #1         ;mark page $BD as free in the system bitmap
BD02: 8E 6F BF  47            STX   BITMAP+23  ;so we can put Online result in our code.
BD05: CA        48            DEX              ;relocate this program to $BD00-BEFF
BD06: BD 00 20  49   LOOP1    LDA   $2000,X    
BD09: 9D 00 BD  50            STA   $BD00,X    
BD0C: BD 00 21  51            LDA   $2100,X    
BD0F: 9D 00 BE  52            STA   $BE00,X    
BD12: E8        53            INX              
BD13: D0 F1     54            BNE   LOOP1      
BD15: CA        55            DEX              
BD16: 9A        56            TXS              ;init stack pointer
BD17: 4C 21 BD  57            JMP   ENTER      ;jump to relocated code
BD1A: 06        58   DIRNAME  DFB   6          ;DirName and VolName must be in the same page
BD1B: D3 C5 D4  59            ASC   "SETUPS"
BD1E: D5 D0 D3 
                60   ******* Get name of boot volume
BD21: AD 30 BF  61   ENTER    LDA   DEVNUM     ;get name of last volume accessed
BD24: 8D BF BE  62            STA   ONLINEN    
BD27: 20 00 BF  63            JSR   PRODOS     
BD2A: C5        64            DFB   $C5        ;ONLINE
BD2B: BE BE     65            DA    ONLINEP    
BD2D: AD 01 BD  66            LDA   VOLNAME+1  ;insert a slash nefore the name
BD30: 29 0F     67            AND   #$0F       
BD32: AA        68            TAX              
BD33: E8        69            INX              
BD34: 8E 00 BD  70            STX   VOLNAME    
BD37: A9 2F     71            LDA   #$2F       ;/
BD39: 8D 01 BD  72            STA   VOLNAME+1  
BD3C: AD 04 BF  73            LDA   QUITVECT+1 ;save original quit vector
BD3F: 8D D2 BD  74            STA   QUITMOD1+1 
BD42: AD 05 BF  75            LDA   QUITVECT+2 
BD45: 8D D7 BD  76            STA   QUITMOD2+1 
                77   ******* Clean up before & after calling files
BD48: A2 02     78   MAINLOOP LDX   #2         ;point Reset vector and ProDOS
BD4A: BD CB BD  79   LOOP3    LDA   JUMP+1,X   ;Quit vectors to MainLoop
BD4D: 9D F2 03  80            STA   RESET,X    
BD50: BD CA BD  81            LDA   JUMP,X     
BD53: 9D 03 BF  82            STA   QUITVECT,X 
BD56: CA        83            DEX              
BD57: 10 F1     84            BPL   LOOP3      
BD59: 9A        85            TXS              ;fix stack pointer (X=$FF)
BD5A: 20 85 BE  86            JSR   CLOSE      ;close all open files
BD5D: A2 17     87            LDX   #23        ;clear system bit map
BD5F: A9 00     88            LDA   #0         
BD61: 9D 58 BF  89   LOOP2    STA   BITMAP,X   
BD64: CA        90            DEX              
BD65: 10 FA     91            BPL   LOOP2      
BD67: A9 CF     92            LDA   #$CF       ;mark pages 0,1,4-7 as used
BD69: 8D 58 BF  93            STA   BITMAP     
BD6C: A9 07     94            LDA   #%111      ;mark pages $BD-$BF as used
BD6E: 8D 6F BF  95            STA   BITMAP+23  
BD71: AD 82 C0  96            LDA   $C082      ;Language card off
BD74: 8D 0C C0  97            STA   $C00C      ;40-column
BD77: 8D 0E C0  98            STA   $C00E      ;normal character set
BD7A: 8D 00 C0  99            STA   $C000      ;80STORE off
BD7D: 20 84 FE  100           JSR   SETNORM    ;normal
BD80: 20 2F FB  101           JSR   INIT       ;display text page 1
BD83: 20 93 FE  102           JSR   SETVID     ;PR#0
BD86: 20 89 FE  103           JSR   SETKBD     ;IN#0
                104  *Make sure boot volume is around
                105  *AND set prefix to the boot volume
BD89: 20 58 FC  106  VOLMOUNT JSR   HOME       
BD8C: 20 00 BF  107           JSR   PRODOS     ;set prefix to volume
BD8F: C6        108           DFB   $C6        ;SET PREFIX
BD90: C5 BE     109           DA    PFX2P      
BD92: 90 28     110           BCC   VOLOK      
BD94: A2 0D     111           LDX   #13        
BD96: BD F1 BE  112  LOOP6    LDA   VOLTEXT-1,X ;print message "insert volume"
BD99: 9D AC 05  113           STA   $5A8+4,X   
BD9C: CA        114           DEX              
BD9D: D0 F7     115           BNE   LOOP6      
BD9F: BD 01 BD  116  LOOP7    LDA   VOLNAME+1,X ;print volume name
BDA2: 09 80     117           ORA   #$80       
BDA4: 9D BB 05  118           STA   $5A8+19,X  
BDA7: E8        119           INX              
BDA8: EC 00 BD  120           CPX   VOLNAME    
BDAB: 90 F2     121           BCC   LOOP7      
BDAD: A9 23     122           LDA   #35        ;go to CH=35, CV=11
BDAF: 85 24     123           STA   CH         
BDB1: A9 0B     124           LDA   #11        
BDB3: 20 24 FC  125           JSR   VTABZ      
BDB6: 20 0C FD  126           JSR   RDKEY      ;wait for keypress
BDB9: 4C 89 BD  127           JMP   VOLMOUNT   
                128  ******* Get name of next file at IN2
BDBC: 20 15 BE  129  VOLOK    JSR   NEXTFILE   ;get name of next file at IN2
BDBF: B0 0D     130           BCS   EXITLOOP   ;if error, we're done with setup files
                131  ******* Load and call setup file
BDC1: 20 00 BF  132           JSR   PRODOS     ;set prefix to SETUPS
BDC4: C6        133           DFB   $C6        ;SET PREFIX
BDC5: C2 BE     134           DA    PFX1P      
BDC7: 20 8E BE  135           JSR   READFILE   ;read in file whose name is at IN@
                136                            ;and call it if there was no error.
BDCA: 4C 48 BD  137  JUMP     JMP   MAINLOOP   ;3 bytes here copied into ProDOS quit vector
BDCD: 18        138           DFB   #$BD!$A5   ;3 bytes here are copied into reset vector
BDCE: EE F4 03  139  EXITLOOP INC   RESET+2    ;scramble reset vector
BDD1: A9 00     140  QUITMOD1 LDA   #0         ;restore original quit vector
BDD3: 8D 04 BF  141           STA   QUITVECT+1 
BDD6: A9 00     142  QUITMOD2 LDA   #0         
BDD8: 8D 05 BF  143           STA   QUITVECT+2 
                144  ******* Look for second system program on disk
BDDB: A9 00     145           LDA   #0         ;modify NextFile routine so that it searches
BDDD: 8D 3E BE  146           STA   NUMBER+1   ;the volume directory for system files only.
BDE0: 8D 82 BE  147           STA   CHEKTYPE+1 
BDE3: A9 00     148           LDA   #<VOLNAME  ;NamePtr+1 does not bneed to be changed
BDE5: 8D D2 BE  149           STA   NAMEPTR    ;since VolName and DirName are in the same page
BDE8: 20 15 BE  150  NEXTSYS  JSR   NEXTFILE   
BDEB: B0 1B     151           BCS   QUIT       
BDED: AE 80 02  152           LDX   IN2        ;see if file ends with ".SYSTEM"
BDF0: A0 06     153           LDY   #6         
BDF2: BD 80 02  154  LOOP4    LDA   IN2,X      ;I expect pathname at IN2 in low ASCII
BDF5: D9 0E BE  155           CMP   SYSTEXT,Y  
BDF8: D0 EE     156           BNE   NEXTSYS    
BDFA: CA        157           DEX              
BDFB: 88        158           DEY              
BDFC: 10 F4     159           BPL   LOOP4      
BDFE: EE 02 BE  160           INC   MOD+1      
BE01: A9 FF     161  MOD      LDA   #$FF       ;the first .SYSTEM program we find is this
BE03: F0 E3     162           BEQ   NEXTSYS    ;one, so skip it and look for next one.
BE05: 20 8E BE  163           JSR   READFILE   ;if successful, never come back
BE08: 20 00 BF  164  QUIT     JSR   PRODOS     
BE0B: 65        165           DFB   $65        ;QUIT
BE0C: C8 BE     166           DA    QUITP      
BE0E: 2E 53 59  167  SYSTEXT  ASC   ë.SYSTEM'
BE11: 53 54 45 4D 
                168  * Get name of next system file or binary file
                169  *
                170  * This routine is set up to look for both SYSTEM and
                171  * BINary files in the SETUPs subdirectory. It is later
                172  * modified to search for SYSTEM files only in the
                173  * volume directory. The locations which are changed
                174  * are ChekType+1, Number+1, and NamePtr (in the Open
                175  * parametr list)
                176  *
                177  * Returns carry if not found, clear if found.
BE15: 20 00 BF  178  NEXTFILE JSR   PRODOS     
BE18: C8        179           DFB   $C8        ;OPEN
BE19: D1 BE     180           DA    OPENP      
BE1B: B0 68     181           BCS   CLOSE      
BE1D: AD D6 BE  182           LDA   OPENN      
BE20: 8D D8 BE  183           STA   MARKN      
BE23: 8D DD BE  184           STA   READN      
BE26: 20 00 BF  185           JSR   PRODOS     ;Read in first 39 bytes of directory to
BE29: CA        186           DFB   $CA        ;IN2. This gets the number of entries per
BE2A: DC BE     187           DA    READP      ;block and number of bytes per entry.
BE2C: B0 57     188           BCS   CLOSE      
BE2E: AD A3 02  189           LDA   IN2+35     ;save number of bytes per directory entry
BE31: 8D 54 BE  190           STA   ENTSIZE+1  
BE34: AD A4 02  191           LDA   IN2+36     ;save number of entries per directory block
BE37: 8D 44 BE  192           STA   ENTRIES+1  
BE3A: EE 3E BE  193  NEXTENT  INC   NUMBER+1   
BE3D: A9 00     194  NUMBER   LDA   #0         ;self-modified operand
                195  * Retrieve catalog entry #A
BE3F: A2 FE     196           LDX   #$FE       ;build page index in X
BE41: E8        197  LOOP5    INX              
BE42: E8        198           INX              
BE43: C9 0D     199  ENTRIES  CMP   #13        
BE45: 90 05     200           BCC   OK         
BE47: ED 44 BE  201           SBC   ENTRIES+1  
BE4A: B0 F5     202           BCS   LOOP5      ;always
BE4C: A8        203  OK       TAY              
BE4D: A9 04     204           LDA   #4         ;1st entry per directory block starts 4 bytes in
BE4F: 88        205  LOOP10   DEY              
BE50: 30 08     206           BMI   OK2        
BE52: 18        207           CLC              
BE53: 69 27     208  ENTSIZE  ADC   #39        ;add size of directory entry
BE55: 90 F8     209           BCC   LOOP10     
BE57: E8        210           INX              
BE58: D0 F5     211           BNE   LOOP10     ;always
BE5A: 8D D9 BE  212  OK2      STA   MARK       ;save mark in file
BE5D: 8E DA BE  213           STX   MARK+1     
BE60: 20 00 BF  214           JSR   PRODOS     ;set the mark
BE63: CE        215           DFB   $CE        ;SET_MARK
BE64: D7 BE     216           DA    MARKP      
BE66: B0 1D     217           BCS   CLOSE      
BE68: 20 00 BF  218           JSR   PRODOS     ;read in directory info
BE6B: CA        219           DFB   $CA        ;READ
BE6C: DC BE     220           DA    READP      
BE6E: B0 15     221           BCS   CLOSE      
BE70: AD 80 02  222           LDA   IN2        ;make sure that file is not deleted
BE73: F0 C5     223           BEQ   NEXTENT    
BE75: 29 0F     224           AND   #$0F       
BE77: 8D 80 02  225           STA   IN2        
BE7A: AD 90 02  226           LDA   FILETYPE   ;make sure file type is correct
BE7D: 49 FF     227           EOR   #$FF       ;we look for system programs...
BE7F: F0 04     228           BEQ   CLOSE      
BE81: 49 F9     229  CHEKTYPE EOR   #6!$FF     ;...and binary ones.
BE83: D0 B5     230           BNE   NEXTENT    
BE85: 08        231  CLOSE    PHP              ;close all files - do not change carry
BE86: 20 00 BF  232           JSR   PRODOS     
BE89: CC        233           DFB   $CC        ;CLOSE
BE8A: CF BE     234           DA    CLOSEP     
BE8C: 28        235           PLP              
BE8D: 60        236  ANRTS    RTS              
                237  * Read file and call it.
                238  * Name should be found at IN2
                239  * Prefix must be set.
BE8E: AE 90 02  240  READFILE LDX   FILETYPE   ;if a system program, set to read to $2000
BE91: A9 20     241           LDA   #$20       
BE93: E8        242           INX              
BE94: F0 06     243           BEQ   SETDEST    
BE96: AE 9F 02  244           LDX   AUXCODE    ;else, set to read in file at address
BE99: AD A0 02  245           LDA   AUXCODE+1  ;found in auxcode
BE9C: 8E EC BE  246  SETDEST  STX   READ2D     
BE9F: 8D ED BE  247           STA   READ2D+1   
BEA2: 20 00 BF  248           JSR   PRODOS     ;Open file
BEA5: C8        249           DFB   $C8        ;OPEN
BEA6: E4 BE     250           DA    OPEN2P     
BEA8: B0 DB     251           BCS   CLOSE      
BEAA: AD E9 BE  252           LDA   OPEN2N     
BEAD: 8D EB BE  253           STA   READ2N     
BEB0: 20 00 BF  254           JSR   PRODOS     ;Read file into memory
BEB3: CA        255           DFB   $CA        ;READ
BEB4: EA BE     256           DA    READ2P     
BEB6: 20 85 BE  257           JSR   CLOSE      
BEB9: B0 D2     258           BCS   ANRTS      
BEBB: 6C EC BE  259           JMP   (READ2D)   ;call the file just loaded
                260  ******* ProDOS MLI parameter lists
BEBE: 02        261  ONLINEP  DFB   2          ;Online parameter list
BEBF: 00        262  ONLINEN  DS    1          
BEC0: 01 BD     263           DA    VOLNAME+1  
                264  *
BEC2: 01        265  PFX1P    DFB   1          ;to set prefix to SETUP
BEC3: 1A BD     266           DA    DIRNAME    
                267  *
BEC5: 01        268  PFX2P    DFB   1          ;to set prefix to volume directory
BEC6: 00 BD     269           DA    VOLNAME    
                270  *
BEC8: 04 00 00  271  QUITP    DFB   4,0,0,0,0,0,0 
BECB: 00 00 00 00 
                272  *
BECF: 01 00     273  CLOSEP   DFB   1,0        ;close all files
                274  *
BED1: 03        275  OPENP    DFB   3          ;open directory
BED2: 1A BD     276  NAMEPTR  DA    DIRNAME    ;pathname pointer
BED4: 00 B9     277           DA    IOBUFFER   
BED6: 00        278  OPENN    DS    1          ;reference number
                279  *
BED7: 02        280  MARKP    DFB   2          ;set mark in directory
BED8: 00        281  MARKN    DS    1          
BED9: 00 00 00  282  MARK     DS    3          
                283  *
BEDC: 04        284  READP    DFB   4          ;read directory
BEDD: 00        285  READN    DS    1          
BEDE: 80 02     286           DA    IN2        ;target address
BEE0: 27 00     287           DA    39         ;length
BEE2: 00 00     288           DS    2          
                289  *
BEE4: 03        290  OPEN2P   DFB   3          ;open setup or system file
BEE5: 80 02     291           DA    IN2        
BEE7: 00 B9     292           DA    IOBUFFER   
BEE9: 00        293  OPEN2N   DS    1          
                294  *
BEEA: 04        295  READ2P   DFB   4          ;read setup or system file
BEEB: 00        296  READ2N   DS    1          
BEEC: 00 00     297  READ2D   DS    2          ;destination of file is self-mod here
BEEE: 00 B1     298           DA    $B900-$800 ;ask for largest possible that will fit
BEF0: 00 00     299           DS    2          
                300  *
BEF2: C9 CE D3  301  VOLTEXT  ASC   "INSERT VOLUME" 
BEF5: C5 D2 D4 A0 
BEF9: D6 CF CC D5 
BEFD: CD C5 
BEFF: E8        302           CHK              ;checksum - eor for all previous bytes
 
--End assembly, 512 bytes, Errors: 0

You can download the disk with this program on it at:
https://www.callapple.org/soft/ap2/anthology/CA8711_Example_ProDOS.dsk