!pr1
A New Catalog for DOS 3.3...................Robert F. O'Brien
                                              Dublin, Ireland

In AAL March '85 Bob S-C presented re-writes of some loosely coded DOS sections to make space for patches - the Catalog Function Handler is another such loose bit of code, but rather than just free up some bytes I decided to add some useful features which Apple omitted and correct an annoying error at the same time. This new routine adds the following features to the CATALOG command: 

!lm+9
!pp-4
1.  Displays the free space remaining on the disk. 

2.  Allows you to terminate the Catalog during the normal  pause after a screenful of files have been displayed by pressing the <ESC>-key (or other designated key).

3.  Displays the correct number of sectors for each file in the Catalog for even the very large files - where the number of  sectors exceeds 255 (which was the limit of the old  PRINT.DECIMAL subroutine at $AE42 in DOS 3.3).

4.  Optionally displays two filenames on each line of the Catalog - this is an 80-Column card option, also great for double-barrelled CATALOG printouts (for labels etc.).
!pp0
!lm-9

In addition, the new Catalog retains the principal features of the old routine such as displaying the Volume number, the locked file indicator (*) and the file type abbreviation so that the user is not deprived of any essential information.

All the foregoing was achieved without using any additional DOS RAM space or zero-page locations other than that space already used by the Catalog Function Handler itself. Of course, something of the old routine had to be sacrificed in order to add the new features - it was necessary to omit the message "DISK VOLUME " from the beginning of the display.  The 12-byte space where this message resided is now used to house a subroutine to check for locked files.

Even with all these enhancements, there are 17 free bytes left over!  You could use some of them to print out an abbreviated form of the "DISK VOLUME " message, like "V=".

An additional constraint I saddled myself with in doing the re-write was that PRINT.DECIMAL (the DOS subroutine used to convert the hexadecimal numbers in locations $44,45 to decimal and print them) should retain its normal entry point ($AE42) so that the new code would be compatible with other programs which might use it.

For those who wish to get double-barrelled Catalog listings on an 80-column card or on a printer just change the "SEC" at line 2010 to "LSR".  In other words, $AE12:4A will enable the wide printout, and $AE12:38 will put it back to normal.

To install the new patches just BLOAD the two binary files:  NEW CATALOG PART 1, and NEW CATALOG PART 2.  You can put the modified DOS onto any normal disk using Bob Perkins' technique (in AAL Aug 1982 p.24) without disturbing any other files present, or INIT a blank disk and the modified DOS will be incorporated on it.  If you prefer to terminate long Catalog's with the <RETURN> key as you do for listings with the S-C Macro Assemblers just change byte $AE21:8D.

Also, if you are prepared to restrict yourself to 11 character file-names you can have a double-barrelled Catalog on the 40-Column screen by changing byte $ADF7:0B (POKE 44535,11), but I feel it would be of little value overall.

Now for a more detailed look at the program internals.  Due to the requirement to save as many bytes as possible to squeeze in the desired features it was not possible to write the code in as straight-forward a manner as one would like.  Even so, the routine was written with 17 byte to spare - after many re-writes to fit in all the features.

Lines 1020-1240 define various subroutines, variables, and data tables inside the rest of DOS.

Lines 1320-1360 use the same code as the original Catalog routine to initialize the File Manager and read the disk Volume Table Of Contents (VTOC).

In lines 1370-1410 we clear LINE.SKIP.FLAG which is used by SKIP.LINE subroutine to determine whether to tab to a second column or print a carriage return.  Then we call PRINT.DECIMAL.YA to print the volume number.  The volume number itself is passed in the A-register, and a zero high-byte in Y.  Since we stripped out the code for printing "DISK VOLUME ", the volume number will be printed immediately to the right of the CATALOG command, on the same line.  You will see "CATALOG 254  395", or the like, where the first number is the volume number and the second is the count of free sectors.

By making a special entry above the PRINT.DECIMAL subroutine which is used both here and at line 1830 below, we save several bytes.  Of course we have already save a couple dozen bytes by not printing "DISK VOLUME ".

Calculation of the free disk space is made in lines 1420-1530.  We make use of a new feature in the corrected PRINT.DECIMAL routine whereby $44 and $45 are reduced to 0 during the conversion - resulting in a saving of 4 bytes by not having to re-zero $45.  (In the old routine only $44 was reduced to 0.)

In the VTOC 4 bytes are set aside for each track to indicate sector usage although only 2 are needed for a standard Apple disk.  (The extra space allows up to 50 tracks and up to 32 sectors per track to be initialized.)  A bit set=1 means that the corresponding sector on the track is available for use. If a bit is set=0 then the sector is already allocated. So it was simply a matter of counting every bit set from offset byte $38 (track 0) to Byte $C3 (for Trk $22) of the VTOC buffer to get a count of the free space.  If you want to count all the way to the 50th track, in case the program is working with a hard disk like the Sider or Corvus, or a RANA 320K floppy, change lines 1430-1440:

       1430       LDX #$38
       1440       LDA VTOC.BUFFER,X

In line 1550 we have another departure from the original code - 2 bytes were saved by entering the tail end of the SKIP.LINE subroutine in order to set the number of lines to place on the screen before pausing during a Catalog.  This has the added advantage that you can customize your Catalog more easily in that the line count can be adjusted by modifying a single byte ($AE25). 

At lines 1570-1610 we start by clearing the Carry flag so that the first sector of the directory will be read (track $11, sector $0F).  Also we set the index (X) to the first filename entry in the sector.

Lines 1620-1660 examine the track number of the Track/Sector list for the current filename entry.  Should this number be 0 it indicates that we are at the end of the directory, at which point we would terminate the Catalog by exiting the File Manager routine by a jump to $B37F.

Fortunately, there was a JMP $B37F instruction within relative branching distance of the Catalog Function Handler.  We could therefore dispense with the JMP to $B37F in the original code saving a further 3 bytes by branching to FM.EXIT at $AD86 instead.  This is an address in the DELETE Function Handler ($AD2B-AD97) which precedes the Catalog routine in RAM.  There are three ways we can terminate the Catalog, which all result in a branch to FM.EXIT:  here at line 1600 when we find there are no more catalog sectors, at line 1650 when we find there are no more catalog entries, and at line 2090 when the ESC-key is typed during a screen-pause.

At line 1660 if the track number value is negative (bit 7 set) then we have found a deleted file.  Deleted files don't show up on the Catalog, so we call on the subroutine at $B230 which sets the X-Register to the value of the entry point offset for the next entry in the sector, if any.

If on return from this subroutine the Carry flag bit is set (=1) then we have reached the end of the current catalog sector and we branch back to READ.SECTOR at line 1580 to read the next directory sector, if any.  (Each directory sector accommodates 7 entries.)

At line 1680 we call the SKIP.LINE subroutine, which normally merely prints a carriage return.  This routine was called from five different places in the original catalog code, so we have saved a dozen bytes by only calling it from this one place.  (Putting it in-line would save four more!)

At line 1700 we call the new subroutine at the site of the DISK VOLUME message space to check for locked files and print the space or asterisk.  This routine also leaves the file type code in the Y-register.  This code could be placed in-line, rather than making it a subroutine, but then the final two lines could not be used as a short PRINT.SPACE subroutine.

Lines 1710-1790 convert the file type code to a file type character.  The file type code is in bits 6-0, and is either zero (meaning type T), or a single bit.  The hex values 40, 20, 10, 08, 04, 02, and 01 stand for file types B, A, R, S, B, A, and I.  A string at $B4C8 holds "TIABSRAB", so we need to convert the bit position to an index value, and pick up the character out of that string.  The ASL at line 1740 elminates the "lock/unlock" bit.  The loop in line 1750-1770 shifts bits out until the value is zero, counting up in the Y-register.  If the value was already zero, we exit immediately with Y=0, and type is "T".  A type value of 1 gives an index of 1, up through $40 giving an index of 7.

By the way, types 40 and 20 are not Binary and Applesoft.  They are hardly ever used, except in protection schemes.  Types 04 and 02 are Binary and Applesoft.

The original catalog code had a significantly longer loop for converting the file type number to an index.  You might want to compare the two.

The number of sectors in the file is picked up and converted in lines 1800-1830 and the decimal value is printed, surrounded by spaces.  Lines 1840-1900 print out the file name.

Lines 1920-1950 advance to the next filename entry, and branch either to process it or to read in another catalog sector.

Lines 1970-2130 usually print a carriage return.  If you have changed line 2010 to "LSR", to get double column catalogs, the least significant bit of LINE.SKIP.FLAG will determine whether to print a carriage return or not.  When line 2010 is "SEC" we will always get a carriage return.  If a carriage return is printed, we also count the line.  When the line count is complete, we pause and wait for a keystroke.  If that key is an ESC-key, the catalog will terminate.  If not, the line count is re-initialized and we go back for more file names.

Line 2150 simply reserves 17 bytes, shoving the PRINT.DECIMAL routine down so that it still starts at $AE42 like it used to.  These 17 bytes could be used for other code or data, whatever you like.

Lines 2160-2230 store a value to be converted and printed, print a blank, and then fall into the PRINT.DECIMAL subroutine.

The new corrected PRINT.DECIMAL subroutine is actually a little shorter than th buggy original.  It left room for a JMP PRINT.SPACE at the end, which saved calling PRINT.SPACE from several other places.  It also left room for the LINE.SKIP.FLAG variable.

The PRINT.DECIMAL subroutine (lines 2240-2490) effectively divides the number in $44,45 by subtracting in turn the values 100, 10 and 1 from it - a 16-bit subtraction.  The count of the number of subtractions and the low order byte remainder are temporarily stored on the stack to conserve memory usage.  We start with 100 and keep subtracting it and incrementing the subtraction-counter until we get borrow, at which point we print the counter value. 

Now $44,45 will contain the remainder and so we continue using 10 and then 1 until three decimal digits are printed.  This subroutine can accurately convert numbers having values up to 999 decimal.

CHALLENGE.  Even though we have already squeezed out 17 bytes, while adding new features, we did lose the "DISK VOLUME " message.  Can someone out there squeeze enough more out, without losing any features, to slip the message back in?

CAVEAT.  If you decide to put this new CATALOG program on your disks, please be careful.  There are some programs which temporarily patch the catalog routine themselves.  In particular, ES-CAPE and other commercial programs patch the SKIP.LINES subroutine so that the pause is eliminated.  Since SKIP.LINES has been moved and is different, no telling what might happen.
