[net.micro.6809] Yet Another Directory utility

dml@loral.UUCP (Dave Lewis) (09/10/86)

  Long and long ago, Jim OMura of Toronto (You listening?) lamented the fact
that the OS-9 Dir utility neglected to print the current date in its header.
Some time after that, an 80-column Dir program from S.B. Goldberg appeared in
the Rainbow and I modified it to print the date and posted it here. Some bugs
appeared ("dir e x" didn't always work right) and the thing was FIXED at 80
columns. Then, OS-9 V2 came out, with its 32/80 column dir which STILL didn't
put the date in the header.

  I pitched all the previous stuff and started hacking, and the end result is
presented here for your pleasure. It displays directories in 32, 51 and 80
column formats, prints the date in the header, accepts multiple arguments so
you can print out five or six directories in one run of the program, ALWAYS
finds the right drive when `e' is selected, and the "date last modified" is
arranged in the normal mm/dd/yy format instead of yy/mm/dd.

  One problem: although it automatically selects between 32 and 80 columns on
OS-9 V2, it won't select 51 cols. for FHL's O-Pak. A debugging session reveals
that even when O-Pak is running and the /Term descriptor has been patched to
51 columns, the Get Status SS.SCSZ (screen size) call still returns 32 columns
which it's NOT supposed to do! If someone can find a solution to that problem
the Dir program will work fine. Until then, you can set the WIDESIZE EQUate
to 51 and use "dir w" for 51 columns.

  Another puzzling thing -- under V2, O-Pak's cursor goes away after I set the
time. Where does it go? I put CCIO, CO32, GRFO, HIRES and STDCS in OS9Boot,
and put HIRES and TMODE .1 -upc pag=24 in the Startup file.

*****************************************************************
*
*  Dir -- directory display utility for OS-9 Version 1 or 2.
*  Automatically selects correct display mode for screen width
*  under Version 2. Prints date in header and will display
*  multiple directories.
*
*  Dir [e] [x] [d] [w] [directory] [directory]...
*
*  e -- displays data from file descriptor including size,
*       LSN of file descriptor, attributes, date last modified
*  x -- displays current execution directory
*  d -- displays file size in decimal (default is hex)
*  w -- forces wide-screen mode. Most useful under Version 1
*       which lacks the screen size status call
*
*  If you want to display either the current working directory
*  or the execution directory AND any other directory, you must
*  put a `.' in the command line at the appropriate position. If
*  you want to display both the working and execution
*  directories you must put a `.' for the working directory,
*  then the `x' option, then a `.' for the execution directory.
*
*****************************************************************
*
*  Copyright 1986 by Dave Lewis
*                    4417 Idaho apt. 4
*                    San Diego CA 92116
*
         NAM Dir
         TTL Directory listing utility
*
         IFP1
         USE /D0/DEFS/OS9Defs
         USE /D0/DEFS/RBFDefs
         USE /D0/DEFS/SCFDefs
         ENDC
*
DEFAULT  EQU 32 Default screen width for V.1
WIDESIZE EQU 80 Size for `W' option
BREAKYR  EQU 70 Switch year from 19XX to 20XX
*
         MOD SIZE,NAME,$11,$81,EXEC,STORG
NAME     FCS 'Dir'
         FCB $06 Version byte
*
PATHLIST RMB 2 Current parameter position
EFLAG    RMB 1 Dir `e' flag
XFLAG    RMB 1 Dir `x' flag
NOTFIRST RMB 1 Zero on first directory
SCREENSZ RMB 1 Width of screen in columns
SCRWIDTH RMB 1 Screen width flag
COLWIDTH RMB 1 Width of a column
COLUMNS  RMB 1 Columns used so far
SIZEBASE RMB 1 Numeric base for file size
NUMBASE  RMB 1 Numeric base for output
DIRPATH  RMB 1 Directory path number
ATPATH   RMB 1 /Dn@ path number
SCRATCH  RMB 12 For numeric conversion
FILENAME RMB 29 File name and sector number
FDS.LSN  RMB 3 File descriptor sector #
FILEDATA RMB 32 Stuff from file descriptor
LINEBUF  RMB 120 Output line buffer
         RMB 200 Stack space
         RMB 100 Parameter area
STORG    EQU . Total storage required
*
HEADER1  FCB C$LF
         FCS 'Directory of '
MONTHS   FCB 13,20,28,33,38,41
         FCB 45,49,55,64,71,79
         FCS 'January'
         FCS 'February'
         FCS 'March'
         FCS 'April'
         FCS 'May'
         FCS 'June'
         FCS 'July'
         FCS 'August'
         FCS 'September'
         FCS 'October'
         FCS 'November'
         FCS 'December'
*
HEADER2  FCS 'O'
         FCB $86
         FCS 'wn'
         FCB $42
         FCS 'er  Last modified  Attrib'
         FCB $84
         FCS 'utes  Sect'
         FCB $C3
         FCS 'or  '
         FCB $81
         FCS ' Size '
         FCB $81
         FCC ' Filename'
         FCB C$LF
         FCS '-------------------------------'
         FCB $5E
         FCS '----------------'
         FCB $8D
         FCC '-------------'
         FCB $8D,0
*
DOT      FCC '.'
         FCB C$CR
*
* Find options and do appropriate stuff
*
DECSIZE  LDA #10 Set file size display base
         STA SIZEBASE   to decimal
FINDARGS LDD ,X+ Get next command line char.
         CMPA #C$SPAC Test for space
         BEQ FINDARGS Keep looking if so
         CMPA #'- Test for minus
         BEQ FINDARGS Keep looking if so
         CMPA #C$COMA Test for comma
         BEQ FINDARGS Keep looking if so
         CMPA #'. Test for "." (current dir)
         BEQ FINDARG3 Go open path if so
         CMPA #C$CR Test for end of command line
         BNE FINDARG2 Continue if not
         LEAX <DOT,PCR Point to `.' (current dir)
         CLRB Might exit, ensure no error
         TST NOTFIRST Is this the first directory?
         BNE FA.EXIT If not, exit the process
         RTS
*
FINDARG2 CMPB #'0 First character in a name?
         BLO FINDARG4 If not, must be an argument
FINDARG3 LEAX -1,X Point back to the character
         RTS
*
FINDARG4 ANDA #$5F Convert lower case to upper
         CMPA #'E Is it an `E'?
         BNE NOT.E Continue if not
         STA EFLAG Set the `E' flag
         BRA FINDARGS Look for more arguments
*
NOT.E    CMPA #'X Is it an `X'?
         BNE NOT.X Continue if not
         LDA #EXEC. Set execute bit in `X' flag
         STA XFLAG
         BRA FINDARGS Look for more arguments
*
NOT.X    CMPA #'W Is it a `W'?
         BNE NOT.W Continue if not
         LDB #WIDESIZE Force wide screen
         BSR SETSIZE Reset screen size
         BRA FINDARGS Look for more arguments
*
NOT.W    CMPA #'D Is it a `D'?
         BEQ DECSIZE Set size to decimal if so
*
         LEAX <ERRSTRN,PCR Point to error string
         LDA #2 Standard error path
         LDY #30 Max characters to write
         OS9 I$WRITLN Write error message
FA.EXIT  LBRA MAINEXIT Quit the process
*
ERRSTRN  FCC 'Dir: ERROR -- bad option'
         FCB C$CR
*
SETSIZE  LDA #8 Set up initial value
         STB SCREENSZ Store raw screen size
         CMPB #70 Test for 70+ columns
         BHS SETSIZE2 Set screen values if so
         RORA Shift A right, 1 -> bit 7
         CMPB #50 Test for 50 -> 69 columns
         BHS SETSIZE2 Set screen values if true
         LSRA Shift A right again (now $42)
SETSIZE2 TFR A,B Copy value in A
         ANDA #$F0 Mask off width flag
         ANDB #$F Mask off column width offset
         ADDB #8 Convert to column width
         STD SCRWIDTH Set both variables
         RTS
*
* Initialization routines - set up variables, establish
* screen size, etc.
*
EXEC     STX PATHLIST Save X register
         CLRA Set everything up for default
         CLRB   conditions
         STD EFLAG CLear `e' and `x' flags
         STD NOTFIRST Clear init flag
         LDD #$100A Hex size, all else decimal
         STD SIZEBASE Initialize base variables
         LDD #$126 Stdout, SS.SCSIZ codes
         OS9 I$GETSTT Get screen size
         TFR X,D Put screen width in D
         BCC EXEC.2 Continue if no error
         CMPB #E$UNKSVC Version 1 won't recognize
         BEQ V1DFAULT   the call so default to 32
         COMA Set carry for error
         LBRA MAINEXIT Quit with error
V1DFAULT LDB #DEFAULT Set Version 1 default size
EXEC.2   BSR SETSIZE Set up screen size variables
*
DIRLOOP  LDX PATHLIST Get parameter pointer
         LBSR FINDARGS Process options
*
         PSHS X Save start of path
         LDA #DIR.+READ. Set access mode
         LDB #'. If it points to `.' (current
         CMPB ,X   directory), add in the `x'
         BNE NOTDOT   flag for the execution
         ADDA XFLAG   directory (if set)
NOTDOT   OS9 I$OPEN Open the directory
         LBCS MAINEXIT Quit if error
         STA DIRPATH Store path number
         STX PATHLIST Store current position
*
         LBSR CLEARBUF Clear output line buffer
         LEAX HEADER1,PCR Point to start of header
         LBSR MOVE.PL Move it into buffer
         LDD PATHLIST Get end of pathlist
         SUBD ,S Find length of pathlist
         PULS X Retrieve path pointer
         LBSR MOVE.$B Move it to buffer
*
         LEAY 4,Y Put four spaces after the path
         TST SCRWIDTH Check screen size
         BEQ ONELINE Skip next if 70 col. or more
         LEAY -4,Y Back over the spaces
         LDB #C$LF Put a line feed ahead of
         STB ,Y+   the date/time display
*
ONELINE  LEAX FILEDATA,U Point to a buffer
         OS9 F$TIME Get current date and time
         LBCS MAINEXIT Quit if error
         LDA 1,X Get month
         LEAX MONTHS-1,PCR Point to month name list
         LDA A,X Get offset for current month
         LEAX A,X Index into name list
         LBSR MOVE.PL Move it to line buffer
         LEAY 1,Y Put a space after month name
         LDB FILEDATA+2 Get day
         CLRA Make it a 16-bit number
         LBSR LEFTJUST Print in decimal, left just.
         LDA #C$COMA Put a comma and a space
         STA ,Y++   after the day
         LDB FILEDATA Get year
         CLRA Zero upper half of D
         CMPB #BREAKYR Test for 19xx or 20xx year
         BHI NINETEEN If last two digits of year
         ADDB #100   are higher than break point
NINETEEN ADDD #1900   year is 19xx; if not, 20xx
         LBSR LEFTJUST Write out the year
         LEAY 2,Y Put two spaces after the year
*
         LEAX FILEDATA+3,U Point to hour
         LBSR WRITIME Write current time to buffer
         LDA #C$LF Leave a blank line
         STA ,Y+
         BSR WRITBUFR Write out the buffer contents
         INC NOTFIRST Next directory won't be #1
         CLR COLUMNS Indicate empty buffer
         BSR READNAME Read and discard the `.' and
         BSR READNAME   `..' entries in directory
         TST EFLAG Was `e' option selected?
         LBNE DIREHDR Start Dir `e' display
*
*  Get next file name and count characters
*
DIRCOL.1 BSR READNAME Get next file name
         BCC DIRCOL.2 No error, continue
         TST COLUMNS End of file error, check buf
         BEQ DIRLP.LB Do next directory
         BSR WRITBUFR Write buffer if not empty
DIRLP.LB LBRA DIRLOOP Go do next directory
*
DIRCOL.2 LDB #$FF Start short to test byte 0
FINDLEN  INCB Count one character
         TST B,X Test next char. for end
         BPL FINDLEN Not end, keep counting
         ANDB #$1F Illegal over 32 characters
         INCB Convert int to natural
         ADDB COLUMNS Add name to current column
         CMPB SCREENSZ Compare to screen width
         BLO NONEWLIN Same line if there's room
         BSR WRITBUFR Write out current line
         CLR COLUMNS Indicate empty buffer
         LEAX FILENAME,U Restore pointer to filename
         BRA DIRCOL.2 New line, same filename
*
NONEWLIN INCB Count one beyond filename
         STB COLUMNS Save new line size
         BSR MOVE.PL Move filename into buffer
         CLRA Start at zero
NEXTCOL  ADDA COLWIDTH Point to start of next
         CMPA COLUMNS   display column, leaving at
         BLS NEXTCOL   least two spaces after name
*
         TFR A,B Copy new column number
         INCB Compensate for previous INC
         SUBB COLUMNS Find offset to new position
         STA COLUMNS Store new line length
         CMPA SCREENSZ Compare to screen width
         BHS DIRCOL.1 Don't move Y past end of line
         LEAY B,Y Reposition Y if there's room
         BRA DIRCOL.1 Get next file name
*
READNAME PSHS Y Save buffer pointer
READNM.2 LDY #32 Size of one directory entry
         LEAX FILENAME,U Point to filename buffer
         LDA DIRPATH Get directory path number
         OS9 I$READ Read the next name
         BCS READNM.3 Test for end-of-file error
         TST ,X Not a valid file if the first
         BEQ READNM.2   byte is a null
         PULS Y,PC Pull and return
*
READNM.3 CMPB #E$EOF Test for end of file
         BNE MAINEXIT Quit if another error
         LDA DIRPATH Close directory path
         OS9 I$CLOSE
         BCS MAINEXIT Quit if error
         COMA Set carry flag
         PULS Y,PC Pull and return
*
MAINEXIT OS9 F$EXIT
*
WRITBUFR LDA #C$CR Terminate the line
         STA ,Y+
         LEAX LINEBUF,U Point to line buffer
         LDY #120 Maximum bytes to write
         LDA #1 Standard output path
         OS9 I$WRITLN Write out a line
         BCS MAINEXIT Quit if error
*
CLEARBUF LEAY LINEBUF,U Point to start of line buffer
         LDD #$2077 Space in A, 119 in B
CLRBUF.2 STA B,Y Store it in buffer
         DECB Count off one
         BPL CLRBUF.2 Repeat until all bytes done
         RTS
*
MOVE.PL  LDA ,X+ Get next character
         STA ,Y+ Store in line buffer
         BPL MOVE.PL Repeat if bit 7 not set
         ANDA #$7F Mask off bit 7
         STA -1,Y Fix last character
         RTS
*
MOVE.$B  LDA ,X+ Get next character
         STA ,Y+ Store in line buffer
         DECB Count off one character
         BNE MOVE.$B Repeat if not done
         RTS
*
LEFTJUST PSHS X Save X register
         BSR LEFTJUSX Go write out number
         PULS X,PC Pull and return
*
LEFTJUSX LEAX FILENAME,U Point to 12 free bytes
LEFTJUS2 BSR DIVIDE Convert one digit
         STD -2,S Test D by storing it
         BEQ LEFTJUS3 Done if D is zero
         BSR LEFTJUS2 Convert next digit
LEFTJUS3 LDA ,X+ Get latest digit from scratch
         STA ,Y+ Store it in the write buffer
         RTS
*
WRITIME  BSR LEADZERO Write first part of date
         BSR WRITIME2 Write colon and second part
WRITIME2 LDB #': Load colon
         STB ,Y+ Store in buffer
*
LEADZERO LDD #$3030 Two zeros
         STD ,Y++ Store in buffer
         LDB ,X+ Get next object
ONEBYRTJ CLRA Zero upper half of D
*
RIGHTJUS PSHS Y,X Save X and Y
         LEAX FILENAME,U Point to 12 free bytes
RIGHTJU2 BSR DIVIDE Convert one digit
         PSHS D Save intermediate result
         LDA ,X+ Get converted digit
         STA ,-Y Store in write buffer
         LDD ,S++ Retrieve and test D
         BNE RIGHTJU2 Repeat if not zero
         PULS X,Y,PC Restore registers and return
*
DIVIDE   PSHS D Save the number
         CLRA Zero upper 8 bits
         LDB #9 Initialize shift counter
         STD ,--X Set up counter, divisor LSB
         LDB NUMBASE Get conversion base
         STD ,--X Divisor MSB, quotient LSB
         STA ,-X Initialize quotient MSB
         PULS D Retrieve the number
*
DIVIDE2  CMPD 2,X Compare number to divisor
         BLS DIVIDE3 Start dividing if <= divisor
         INC 4,X Add one to shift counter
         LSL 2,X Shift divisor left one bit
         BCC DIVIDE2 Test again if divisor intact
         ROR 2,X If divisor lost a 1, restore
         DEC 4,X   it and start dividing
*
DIVIDE3  LSL 1,X Shift quotient left one bit,
         ROL ,X   multiplying it by 2
         CMPD 2,X Compare number to divisor
         BLO DIVIDE4 If smaller, do nothing
         SUBD 2,X Subtract divisor from number
         INC 1,X Add one to quotient
DIVIDE4  LSR 2,X Shift divisor right one bit,
         ROR 3,X   dividing it by 2
         DEC 4,X Count off one shift
         BNE DIVIDE3 Repeat until shift count = 0
*
         TFR B,A Move remainder to A
         ADDA #$90 Convert binary number in A
         DAA   to an ASCII character
         ADCA #$40   representing a digit
         DAA
         STA 4,X Put it `under' other stuff
         LDD ,X Retrieve the quotient
         LEAX 4,X Adjust X - now points just
         RTS   above the remainder digit
*
DIREHDR  LEAX HEADER2,PCR Point to subheader
         TST SCRWIDTH Start with a space if screen
         BPL WRITHEAD   is 50 to 69 columns wide
         LEAY 1,Y Leave a space
WRITHEAD LBSR MOVE.PL Write out next header section
         LDB ,X+ Get the format control byte
         BITB SCRWIDTH Test vs. current screen width
         BEQ WRITHD2 Continue if no match
         ANDB #$3F Mask off screen size flags
         LEAX B,X Add displacement to X
WRITHD2  TSTB If displacement was not zero,
         BNE WRITHEAD   continue storing the header
         TST SCRWIDTH If the screen is 32 columns,
         BLE WRITHD3   (not zero or negative)
         LDB #C$LF   insert a line feed
         STB LINEBUF+30   after the Attributes column
WRITHD3  LBSR WRITBUFR Write out the completed line
*
         LEAX FILEDATA,U Point to a buffer
         LDA DIRPATH Get directory path number
         CLRB Code for SS.OPT is 0
         OS9 I$GETSTT Get options from PD
         LBCS MAINEXIT Quit if error
         LDA 1,X Get drive number
         ADDA #'0 Convert to ASCII
         STA 2,X Put in correct position
         LDD #$2F44 Start with "/D"
         STD ,X Store ahead of drive number
         LDD #$400D Append "@" and CR to
         STD 3,x   drive designator
         LDA #READ. Access mode is Read
         OS9 I$OPEN Open the entire disk
         LBCS MAINEXIT Quit if error
         STA ATPATH Save /Dn@ path number
*
*  Write out file data in `e' format
*
DIRE.WRT LBSR READNAME Read next filename
         BCC DIREWR.2 Continue if not end of file
         LDA ATPATH Get /Dn@ path number
         OS9 I$CLOSE Close the disk
         LBCS MAINEXIT Quit if error
         LBRA DIRLOOP Go do next directory
*
DIREWR.2 LEAX FILEDATA,U Point to file data buffer
         PSHS U,Y,X Save registers
         LDX FDS.LSN Get MSW of sector number
         LDA FDS.LSN+2 Get LSB of sector number
         CLRB Convert sectors to bytes
         TFR D,U Put in right register
         LDA ATPATH Get /Dn@ path number
         OS9 I$SEEK Position file pointer
         LBCS MAINEXIT Exit if error
         LEAX <POS.TBL,PCR Point to positioning data
         STX COLWIDTH Don't need these 2 vars
         PULS X Retrieve pointer to data buffer
         LDY #32 Prepare to read 32 bytes
         OS9 I$READ Read it
         LBCS MAINEXIT Exit if error
         PULS Y,U Restore registers
         BSR POSITION Position Y register
         LDB FILEDATA+FD.OWN Get file owner number
         LBSR ONEBYRTJ Print 1 byte right-justified
*
*  Write date and time last modified
*
         BSR POSITION Adjust write pointer
         LEAX FD.DAT,X Point to last-modified date
         LDD ,X Rearrange date last modified
         STB ,X   from year/month/day to
         LDB 2,X   month/day/year
         STA 2,X
         STB 1,X
         LBSR LEADZERO Display month with leading 0
         BSR WRTDATE Display /day/year same way
         LEAY 1,Y Put a space after the date
         LBSR LEADZERO Write out the hour
         LBSR LEADZERO Write out the minute
*
*  Write out file attributes
*
         BSR POSITION Adjust write pointer
         LEAX <ATTRIBS,PCR Point to attribute display
         LDB FILEDATA+FD.ATT Get file attributes
         BRA WRDATA.2 Jump into the loop
*
POS.TBL  FCB $23,3 Owner number
         FCB $12,4 Date/time last modified
         FCB $13,3 File attributes
         FCB $44,8 Sector number
         FCB $67,8 Size of file
         FCB $12,2 Filename
*
ATTRIBS  FCC 'dsewrewr' File attribute codes
         FCB 0 Null to terminate
*
*  Position Y register to write next object
*
POSITION PSHS X,D Save registers
         LDX COLWIDTH Point to current entry
         LDB 1,X Get offset for 70+ columns
         LDA SCRWIDTH Load and test SCRWIDTH flag
         BEQ POSITN.2 Set position if 70 or more
         LDB ,X Get byte for other sizes
         TSTA Check width again
         BPL POSITN.2 Set it if less than 50 col.
         LSRB If 51-69 columns shift offset
         LSRB   value into lower 4 bits
         LSRB   where it can be used
         LSRB
POSITN.2 ANDB #$F Mask off upper four bits
         LEAX 2,X Point to next table entry
         STX COLWIDTH Store updated pointer
         LEAY B,Y Move write pointer
         PULS D,X,PC Pull and return
*
WRTDATE  BSR WRTDATE2 Do it twice
WRTDATE2 LDB #'/ Put a '/' between entries
         STB ,Y+
         LBRA LEADZERO Write out next object
*
WRTATTR  LSLB Shift out the next bit
         BCS ATBITSET Write the letter if it was 1
         LDA #'- Write a dash if it was a 0
ATBITSET STA ,Y+ Write the selected character
WRDATA.2 LDA ,X+ Load the next attribute code
         BNE WRTATTR Repeat if not a null
*
         TST SCRWIDTH Check screen width
         BLE NOT32COL Skip next if 50+ columns
         LDB #C$LF Insert a line feed
         STB ,Y+
NOT32COL BSR POSITION Move Y register into place
         LDA #16 Print sector number in hex
         STA NUMBASE
         LDD FDS.LSN+1 Get sector number
         LBSR RIGHTJUS Write it out, right justified
         LDA SIZEBASE Get base for file size
         STA NUMBASE Store as output base
         BSR POSITION Adjust write pointer
         LDD FILEDATA+FD.SIZ Test MSW of file size
         BNE K.BYTE Display Kbytes if nonzero
         LDD FILEDATA+FD.SIZ+2 Get LSW of file size
         LBSR RIGHTJUS Print out file size
SIZEDONE LDA #10 Restore decimal output base
         STA NUMBASE
         BSR POSITION Adjust write pointer
         LEAX FILENAME,U Point to file name
         LBSR MOVE.PL Move until bit 7 set
         LBSR WRITBUFR Write out the buffer
         LBRA DIRE.WRT Go do next file
*
K.BYTE   LDA #'K Load a K
         STA ,-Y Put it in the buffer
         LEAY -1,Y Leave a space before it
         LDD FILEDATA+FD.SIZ+1  Load center 2 bytes of file size
         LSR FILEDATA+FD.SIZ  Shift out the last
         RORA    two bits representing 1023
         RORB    and shift in two higher
         LSR FILEDATA+FD.SIZ    bits
         RORA
         RORB
         ADDD #1 Add one Kbyte for the unused bits
         LBSR RIGHTJUS Print out number of Kbytes
         LEAY 2,Y Put Y back where it belongs
         BRA SIZEDONE Re-join the main program
*
         EMOD CRC bytes
SIZE     EQU *
         END

-------------------------------
		Dave Lewis    Loral Instrumentation   San Diego

  hp-sdd --\     ihnp4 --\
  sdcrdcf --\      bang --\   kontron -\
  csndvax ---\   calmasd -->-->!crash --\
  celerity --->------->!sdcsvax!sdcc3 --->--->!loral!dml  (uucp)
  dcdwest ---/                 gould9 --/

 Nobody can fix the economy..nobody can be trusted..nobody's perfect..vote
 for nobody!

-------------------------------