; FINDIR.MAC-FROM JUNE-JULY AMUS NEWSLETTER-KHALSA COMPUTER-ROBERT FOWLER
; converted to L Bob Rubendunst 9/13/83. One fine program I needed on L.
; donated to AMUS 7/26/84 rpr
;
; Assembly instructions:
;       M68 FINDIR
;       LNKLIT FINDIR
;
       SEARCH  SYS
       SEARCH  SYSSYM
       EXTERN $ODTIM                   ; link to system library routine

; impure variable map
       ASECT
DDBIN:  BLKB    D.DDB
DDBOUT: BLKB    D.DDB
OFLAG:  BLKW    1                       ; output flags
NFLAG:  BLKW    1                       ; for OCVT use
MAXREC: BLKW    1                       ; maximum record on disk
PAKBUF: BLKB    12.                     ; UNPACK workspace
       EVEN
MEMLTH=.
=0

; MACRO to make directed messages easier.
DEFINE  OUTS    ARG
       OUTI
       ASCIZ   /ARG/
       EVEN                            ; make sure it ends evenly!
       ENDM

       PSECT


       GETIMP  MEMLTH,A5               ; get some memory
       CLEAR   @A5,MEMLTH              ;  clear it out
       BYP                             ; SCAN PAST BLANKS & TABS
       LIN                             ; TEST FOR LIN TERMINATOR
       BNE     DSKFI1
       TYPECR  <usage: FINDIR devN:>
       EXIT

DSKFI1:
       MOVW    #OT$TRM,OFLAG(A5)       ; default to screen
       FSPEC   DDBIN(A5)               ; stuff device name in input ddb
       INIT    DDBIN(A5)               ; get a buffer area
       TYPE    <Output file name or CR for screen only: >
       KBD
       BYP
       LIN
       BEQ     10$
       FSPEC   DDBOUT(A5)
       INIT    DDBOUT(A5)
       OPENO   DDBOUT(A5)
       MOVW    #OT$DDB,OFLAG(A5)       ; set output flag word
10$:    MOVW    OFLAG(A5),D7
       ORW     #OT$ZER,D7              ; add zero suppression
       RORW    D7,#8.                  ; swap bytes
       ORW     #40006,D7               ; set digit count & octal flag
       MOVW    D7,NFLAG(A5)            ; save it
       ORB     #D$BYP!D$ERC,D.FLG+DDBIN(A5)    ; do not abort to AMOS on errors.
       READ    DDBIN(A5)               ; set up driver address
       MOV     D.DVR(A5),A6            ; index the driver
       MOV     DD.DSZ(A6),D7
       MOVW    D7,MAXREC(A5)   ; store maximum record #
       TYPESP  <Enter 1st block to scan or CR for whole disk:>
       KBD                             ; get some input
       CTRLC   EOFGO                   ; let user abort
       BYP                             ; scan past blanks

       CLR     D1                      ; preset to 1st block
       LIN                             ; check for null line
       BEQ     SCAN                    ; yes-use default of 0
       GTOCT                           ; no-convert string to octal in D1

SCAN:   MOV     D1,DDBIN+D.REC(A5)      ; save record number
       LEA     A2,DDBOUT(A5)           ; index output DDB
       MOVW    OFLAG(A5),D6
       OUTL    TITL                    ; show title
       LEA     A1,DDBIN+D.DEV(A5)
       LEA     A2,PAKBUF(A5)
       UNPACK                          ; unpack device name
       CLR     D1
       MOVW    DDBIN+D.DRV(A5),D1      ; and unit #
       DCVT    0,OT$MEM                ;  to memory
       MOVB    #':,(A2)+               ;
       CLRB    @A2                     ; add 2 CR & null
       LEA     A2,DDBOUT(A5)           ; index output DDB
       MOVW    OFLAG(A5),D6
       OUTL    PAKBUF(A5)              ; output the whole line
       MOVW    OFLAG(A5),D6
       OUTL    MADE
; perform $ODTIM call
       LEA     A2,DDBOUT(A5)           ; index output DDB
       CLR     D3                      ; use current date & time
       CLR     D4                      ; not used
; bit ruler        5432109876543210
       MOV     #^B1100110011100110,D5  ; control options
       CMPW    OFLAG(A5),#OT$TRM       ; just to terminal ?
       BNE     20$                     ;  no-to file
       BCLR    #15.,D5                 ;  yes -shut down file flag
       SUB     A2,A2                   ;   and clear A2
20$:    CALL    $ODTIM                  ; output date & time
       MOVW    OFLAG(A5),D6
       OUTL    HDR
       MOV     DDBIN+D.REC(A5),D1              ; set initial record

; read all the records on disk, finding UFD entry by checking for entries
; that are NOT UFD entries. The records that are NOT NOT UFD are very likely
; UFDs...
READ:   CTRLC   EOFGO
; clear buffer before read in case this read fails....
       MOV     DDBIN+D.BUF(A5),A6      ; get buffer address
       MOV     DDBIN+D.SIZ(A5),D7      ;  and size
       SUB     #1,D7                   ; adjust for DBF
10$:    CLRB    (A6)+
       DBF     D7,10$                  ; clear out buffer before read
       MOV     D1,DDBIN+D.REC(A5)      ; insert record number
       READ    DDBIN(A5)               ; read the block
       TSTB    DDBIN+D.ERR(A5)         ; check for errors
       BEQ     SETREG                  ; no error
; show disk read errors.
       TYPE    <(Error >
       CLR     D1
       DCVT    0,OT$TRM!OT$TSP
       TYPE    <at record>
       CLR     D1
       MOV     DDBIN+D.REC(A5),D1
       OCVT    5,2!OT$LSP                      ; show the record number
       TYPECR  < )>
       CLRB    DDBIN+D.ERR(A5)         ; clear the error
SETREG: MOV     DDBIN+D.BUF(A5),A3      ; index contents of record
       TSTW    772(A3)                 ; is the end blank ?
       BNE     10$                     ;  not a valid directory.
       MOVW    (A3)+,D7                ; get possible link to next block
       CMPW    D7,MAXREC(A5)           ; is it reasonable ?
       BHI     10$                     ;  no
       TSTW    @A3                     ; are first three letters of dir blank?
       BEQ     10$                     ; no-dir not empty
       CALL    CHECK                   ; check for proper form
       BNE     10$                     ; not proper
       CALL    SHOW                    ; show the first few filenames
10$:    MOV     DDBIN+D.REC(A5),D1      ; get block #
       INC     D1                      ; bump it
       CMPW    D1,MAXREC(A5)           ; compare to disk size.
       JLO     READ                    ;  still legal, keep reading
END2:   TYPECR  <Directory scan complete.>
EOFGO:  CMPW    OFLAG(A5),#OT$DDB
       BNE     10$
       CLOSE   DDBOUT(A5)
10$:    EXIT

; check checks each possible UFD entry for good form.
; At entry, A3 indexs the UFD elements.
; At exit, if all looks well, Z is set.
CHECK:  MOV     #40.,D2                 ; set up count for all DIR entries
4$:     TSTW    @A3                     ; end of DIR entries ?
       BEQ     60$                     ;  yes-test for garbage
       CMPW    @A3,#-1                 ; is it an erased file ?
       BEQ     50$                     ;  yes-exit ok.
       MOV     A3,A1                   ; index RAD50 filename
       LEA     A2,PAKBUF(A5)           ;  and buffer zone
       CLRB    (A2)+                   ; set initial null
       UNPACK
       UNPACK                          ; unpack filename
10$:    CMPB    -(A2),#40               ; trailing space ?
       BEQ     10$                     ;  yes-keep backing up
       TSTB    (A2)+                   ; was the whole thing blank ?
       BEQ     C.BAD                   ;  yes-not a valid entry
       UNPACK                          ; unpack extension
14$:    CMPB    -(A2),#40
       BEQ     14$                     ; strip extension trailing spaces
       CLRB    1(A2)                   ; set null at end
       LEA     A2,PAKBUF(A5)           ; index the filename
; check for legal filename characters, plus $, which is used sometimes.
20$:    ADDW    #1,A2                   ; bump to next character
       LIN                             ; end of filename ?
       BEQ     30$                     ;  ok-check block stuff
       ALF                             ; alphabetic
       BEQ     20$                     ;  ok
       NUM                             ; numeral
       BEQ     20$                     ;  ok
       CMPB    @A2,#'$                 ; allow dollar sign, too.
       BNE     C.BAD                   ;  invalid character
       BR      20$
; check file parameters for proper range.
30$:    CMMW    6(A3),MAXREC(A5)        ; see if too big for disk.
       BHI     C.BAD                   ;  yes-more records than whole disk.
       MOVW    10(A3),D7               ; get active bytes in last block
       CMPW    D7,#-1                  ; test for random file
       BEQ     40$                     ;  yes-that's ok
       CMPW    D7,#512.                ; test for sequential file
       BHI     C.BAD                   ;  that isn't any good
40$:    MOVW    12(A3),D7               ; get link block number
       BEQ     C.BAD                   ;  no link, no file!
       CMPW    D7,MAXREC(A5)           ; is it too big for drive?
       BHI     C.BAD                   ;  yes-impossible
50$:    ADD     #14,A3
       DBF     D2,4$                   ; loop thru all entries
       BR      C.OK                    ; OK if all blocks pass inspection
; check remianing space after null entry for another entry. This does not
; occur on live UFD blocks.
60$:    TST     @A3
       BNE     C.BAD                   ; garbage
       TST     4(A3)
       BNE     C.BAD                   ; garbage
       TST     10(A3)
       BNE     C.BAD                   ; garbage
       ADD     #14,A3
       DBF     D2,60$
C.OK:   LCC     #4                      ; flag ok with Z set
       RTN
C.BAD:  LCC     #0                      ; flag invalid entry with Z clear
       RTN


SHOW:   LEA     A2,DDBOUT(A5)           ; A2 indexs output DDB
       MOVW    OFLAG(A5),D6
       MOV     DDBIN+D.REC(A5),D1              ; get record number
       CLR     D6
       MOVW    NFLAG(A5),D6
       OCVT
       MOVW    OFLAG(A5),D6
       OUTS    < next >
       MOV     DDBIN+D.BUF(A5),A1              ; index the buffer
       CLR     D1
       MOVW    (A1)+,D1                        ; get the link
       MOVW    NFLAG(A5),D6
       OCVT                            ; show link
       MOV     #5-1,D3                 ; show 5 filename
10$:    CALL    SHOFIL                  ; display the filename entry
       ADDW    #6,A1                   ; index next entry
       DBF     D3,10$                  ; loop
       MOVW    OFLAG(A5),D6
       OUTI
       BYTE    215,212,0,0             ; output a CRLF
       RTN

; SHOFIL outputs the filename indexs via UFD pointer A1.
SHOFIL: MOVW    OFLAG(A5),D6
       OUTS    <  >                    ; space out
       CMPW    @A1,#-1                 ; file been erased ?
       BNE     10$                     ;  no
       MOVW    OFLAG(A5),D6            ; yes
       OUTS    <--erased-->            ;  say erased
       ADD     #6,A1                   ; adjust for no UNPACKs
       BR      100$                    ; done
10$:    PUSH    A2
       LEA     A2,PAKBUF(A5)           ; index workspace for UNPACK
       UNPACK
       UNPACK
       MOVB    #'.,(A2)+                       ; add a dot
       UNPACK                          ; and extension
       CLRB    @A2
       POP     A2
       MOVW    OFLAG(A5),D6
       OUTL    PAKBUF(A5)              ; output the filename
100$:   RTN


TITL:   ASCII   /Directory scan of /
       BYTE    0
MADE:   ASCII   / made on /
       BYTE    0
HDR:    BYTE    215,212,215,212
       ASCII   /Record ---Link----  -----------------------File Entries-----------------------/
       BYTE    215,212,0
       EVEN

       END