Apple II Technical Notes _____________________________________________________________________________ Developer Technical Support ProDOS 8 #17: Recursive ProDOS Catalog Routine Revised by: Dave Lyons, Keith Rollin, & Matt Deatherage November 1989 Written by: Greg Seitz December 1983 This Technical Note presents an assembly language example of a recursive directory reading routine which is AppleShare compatible. Changes since November 1988: The routine now ignores the file_count field in a directory, and it properly increments ThisBlock. More discussion of AppleShare volumes is included. _____________________________________________________________________________ This Note presents a routine in assembly language for recursively cataloging a ProDOS directory. If you apply this technique to the volume directory of a disk, it will display the name of every file stored on the disk. The routine displays the contents of a given directory (the volume directory in this case), displays the contents of each subdirectory as it is encountered. READ_BLOCK is not used, since it does not work with AppleShare servers. READ is used instead, since it works for AppleShare volumes as well as local disks. Instead of using directory pointers to decide which block to read next, we simply read the directory and display filenames as we go, until we reach a subdirectory file. When we reach a subdirectory, the routine saves our place, plunges down one level of the tree structure, and catalogs the subdirectory. You repeat the process if you find a subdirectory at the current level. When you reach the EOF of any directory, the routine closes the current directory and pops back up one level, and when it reaches the EOF of the initial directory, the routine is finished. This routine is generally compatible with AppleShare volumes, but it is impossible to guarantee a complete traversal of all the accessible files on an AppleShare volume: another user on the same volume can add or remove files or directories at any time. If entries are added or removed, some filenames may be displayed twice or missed completely. Be sure that your programs deal with this sort of situation adequately. We assume that AppleShare is in short naming mode (as it is by default under ProDOS 8). If you enable long naming mode, then illegal characters in filenames will not be translated into question marks. In this case, the code would need to be modified to deal with non-ASCII characters. Also, the ChopName routine would need to be aware that a slash (/) character could be contained inside the name of a directory that had been added to the pathname. (As the code stands, such directories fail to open, but their names are still temporarily added to the pathname.) When the catalog routine encounters an error, it displays a brief message and continues. It is important not to abort on an error, since AppleShare volumes generally contain files and folders with names that are inaccessible to ProDOS, as well as folders that are inaccessible to your program's user (error $4E, access error). The code example includes a simple test of the ReadDir routine, which is the actual recursive catalog routine. Note that the simple test relies upon the GETBUFR routine in BASIC.SYSTEM to allocate a buffer; therefore, as presented, the routine requires the presence of BASIC.SYSTEM. The actual ReadDir routine requires nothing outside of the ProDOS 8 MLI. ----- NEXT OBJECT FILE NAME IS CATALOG.0 0800: 0800 2 org $800 0800: 3 ******************************************************* 0800: 4 * 0800: 5 * Recursive ProDOS Catalog Routine 0800: 6 * 0800: 7 * by: Greg Seitz 12/83 0800: 8 * Pete McDonald 1/86 0800: 9 * Keith Rollin 7/88 0800: 10 * Dave Lyons 11/89 0800: 11 * 0800: 12 * This program shows the latest "Apple Approved" 0800: 13 * method for reading a directory under ProDOS 8. 0800: 14 * READ_BLOCK is not used, since it is incompatible 0800: 15 * with AppleShare file servers. 0800: 16 * 0800: 17 * November 1989: The file_count field is no longer 0800: 18 * used (all references to ThisEntry were removed). 0800: 19 * This is because the file count can change on the fly 0800: 20 * on AppleShare volumes. (Note that the old code was 0800: 21 * accidentally decrementing the file count when it 0800: 22 * found an entry for a deleted file, so some files 0800: 23 * could be left off the end of the list.) 0800: 24 * 0800: 25 * Also, ThisBlock now gets incremented when a chunk 0800: 26 * of data is read from a directory. Previously, this 0800: 27 * routine could get stuck in an endless loop when 0800: 28 * a subdirectory was found outside the first block of 0800: 29 * its parent directory. 0800: 30 * 0800: 31 * Limitations: This routine cannot reach any 0800: 32 * subdirectory whose pathname is longer than 64 0800: 33 * characters, and it will not operate correctly if 0800: 34 * any subdirectory is more than 255 blocks long 0800: 35 * (because ThisBlock is only one byte). 0800: 36 * 0800: 37 ******************************************************* 0800: 38 * 0800: 39 * Equates 0800: 40 * 0800: 41 * Zero page locations 0800: 42 * 0800: 0080 43 dirName equ $80 ; pointer to directory name 0800: 0082 44 entPtr equ $82 ; ptr to current entry 0800: 45 * 0800: 46 * ProDOS command numbers 0800: 47 * 0800: BF00 48 MLI equ $BF00 ; MLI entry point 0800: 00C7 49 mliGetPfx equ $C7 ; GET_PREFIX 0800: 00C8 50 mliOpen equ $C8 ; Open a file command 0800: 00CA 51 mliRead equ $CA ; Read a file command 0800: 00CC 52 mliClose equ $CC ; Close a file command 0800: 00CE 53 mliSetMark equ $CE ; SET_MARK command 0800: 004C 54 EndOfFile equ $4C ; EndOfFile error 0800: 55 * 0800: 56 * BASIC.SYSTEM stuff 0800: 57 * 0800: BEF5 58 GetBufr equ $BEF5 ; BASIC.SYSTEM get buffer routine 01 CATALOG ProDOS Catalog Routine 14-OCT-89 16:20 PAGE 3 0800: 59 * 0800: 60 * Offsets into the directory 0800: 61 * 0800: 0000 62 oType equ $0 ; offset to file type byte 0800: 0023 63 oEntLen equ $23 ; length of each dir. entry 0800: 0024 64 oEntBlk equ $24 ; entries in each block 0800: 65 * 0800: 66 * Monitor routines 0800: 67 * 0800: FDED 68 cout equ $FDED ; output a character 0800: FD8E 69 crout equ $FD8E ; output a RETURN 0800: FDDA 70 prbyte equ $FDDA ; print byte in hex 0800: 00A0 71 space equ $A0 ; a space character 0800: 72 * 0800: 73 ******************************************************* 0800: 74 * 0800: 0800 75 Start equ * 0800: 76 * 0800: 77 * Simple routine to test the recursive ReadDir 0800: 78 * routine. It gets an I/O buffer for ReadDir, gets 0800: 79 * the current prefix, sets the depth of recursion 0800: 80 * to zero, and calls ReadDir to process all of the 0800: 81 * entries in the directory. 0800: 82 * 0800:A9 04 83 lda #4 ; get an I/O buffer 0802:20 F5 BE 84 jsr GetBufr 0805:B0 17 081E 85 bcs exit ; didn't get it 0807:8D D7 09 86 sta ioBuf+1 080A: 87 * 080A: 88 * Use the current prefix for the name of the 080A: 89 * directory to display. Note that the string we 080A: 90 * pass to ReadDir has to end with a "/", and that 080A: 91 * the result of GET_PREFIX does. 080A: 92 * 080A:20 00 BF 93 jsr MLI 080D:C7 94 db mliGetPfx 080E:E8 09 95 dw GetPParms 0810:B0 0C 081E 96 bcs exit 0812: 97 * 0812:A9 00 98 lda #0 0814:8D CE 09 99 sta Depth 0817: 100 * 0817:A9 EB 101 lda #nameBuffer 0819:A2 0B 102 ldx #