; Find UFD blocks (Even containing a specific file)
;
; Written by Dell Coleman (on October 7, 1991)
;            Alpha Automation Incorporated
;            2000 West Loop South  Suite 700
;            Houston, TX 77027
;            (713) 877-8039
;            copyrighted by the above
;               You are granted license to use this software any way you wish
;               so long as you do NOT sell or charge any fee for it.
;
;               NOTE: The idea of checking for extensions was taken from
;                       UFDFND.M68 written by Steven G. McNaughton &
;                       Rich Eakin of Quaker State Oil Corp.  UFDFND.M68 was
;                       gotten from the AMUS bulletin board for free.
;
;[100] 7 October 1991 - Dell Coleman
;       Program written.
;       Because of the monitor call DEVCHR - AMOS 2.0 or above may be needed.
;
       SYM
       SEARCH  SYS
       SEARCH  SYSSYM
       SEARCH  AAI

       VMAJOR=1
       VMINOR=0
       VEDIT=100.

OFINI
OFDEF   DDB,D.DDB                       ; DDB for reading disk
OFDEF   FILNAM,6                        ; ASCII filename
OFDEF   LSTBAS,4                        ; Last base address
OFDEF   DVCHR,DC.SIZ                    ; Table for DEVCHR to return data
OFDEF   COUNT,2                         ; Count of blocks printed on this line
OFSIZ   IMPSIZ

FNDUFD: PHDR    -1,PV$RPD,PH$REE!PH$REU
       GETIMP  IMPSIZ,A5               ; Get impure area (Exit if no memory)
       BYP                             ; Bypass any blanks in the input line
       LIN                             ; End of line?
       JEQ     HELP                    ; Yes - Tell user how to execute
       CLR     D6                      ; Default extension is null
       FSPEC   DDB(A5)                 ; Get device and optional file name
       INIT    DDB(A5)                 ; Initialize DDB and get buffer
       DEVCHR  DDB(A5),DVCHR(A5)       ; Get device characteristics
       MOV     DC.FLG+DVCHR(A5),D7
       AND     #DC$FSD,D7              ; Is device file structured?
       JEQ     NOFSD                   ; Branch if not
       MOV     DC.FLG+DVCHR(A5),D7
       AND     #DC$MNT,D7              ; Is device mounted?
       JEQ     NOMNT                   ; Branch if not
       TYPE    <Blocks marked with '*' are probably UFD blocks.  >
       TYPECR  <Unmarked blocks may not be.>
       TYPE    <Reading >
       MOV     DC.BLK+DVCHR(A5),D1     ; Number of blocks on disk to D1
       DCVT    0,OT$TRM                ; print it
       TYPE    < blocks with >
       AND     #DC$14D,DC.FLG+DVCHR(A5); Clear all bits except Extended dir
       BEQ     10$                     ; Branch if traditional directories
       TYPE    <extended directories>
       BR      20$
10$:    TYPE    <traditional directories>
20$:    TYPE    < for >
       PFILE   DDB(A5)                 ; Print device (and filename)
       CRLF
       CLRW    COUNT(A5)               ; Clear blocks on this line counter
       MOV     D.BUF+DDB(A5),A4        ; Address of buffer to A4
       MOV     A4,A0                   ; Save buffer address
       MOV     #2,D.REC+DDB(A5)        ; Start at block 4th block on disk
                                       ; 1st block is label
                                       ; 2nd block is 1st block of MFD
                                       ; 3rd block is 1st block of bitmap

LOOP:   CTRLC   ENDIT                   ; Exit on ^C
       ADD     #1,D.REC+DDB(A5)        ; Increment block number
       MOV     D.REC+DDB(A5),D7        ; Move to D7 for compare
       CMP     D7,DC.BLK+DVCHR(A5)     ; Are we at end of disk?
       JEQ     ENDIT                   ; Branch if yes
       READ    DDB(A5)                 ; Read a block from disk
       MOV     #1,LSTBAS(A5)           ; Set last UFD entry was not zeroes
       TST     DC.FLG+DVCHR(A5)        ; Extended directories?
       BEQ     10$                     ; Branch if not
       MOV     A0,A4                   ; Get addr of buffer
       ADD     #D$NAM,A4               ; Add displacement to filename
       MOVW    #^H26,D2                ; Length of a UFD entry
       MOVW    #4,D3                   ; Starting byte in the block
       MOVW    #12.,D4                 ; Number of possible entries in UFD -1
       BR      20$
10$:    MOVW    #12.,D2                 ; Length of a UFD entry
       MOVW    #2,D3                   ; Starting byte in the block
       MOVW    #41.,D4                 ; Number of possible entries in UFD -1
20$:    SAVE    A4,D2-4                 ; Save registers
30$:    BCALL   CHKENT                  ; Is this the entry we want?
       BEQ     40$                     ; Branch if yes
       ADDW    D2,D3                   ; Set for displacement to next entry
       DBF     D4,30$                  ; Decrement counter and loop
       REST    A4,D2-4                 ; Restore registers
       BR      LOOP                    ; Not this block
40$:    REST    A4,D2-4                 ; Restore registers
       INCW    COUNT(A5)               ; Incremment blocks counter
       CMPW    COUNT(A5),#9.           ; Is it time for a CR/LF?
       BMI     45$                     ; Branch if not
       CRLF
       CLRW    COUNT(A5)               ; Clear blocks on this line counter
45$:    MOV     D.REC+DDB(A5),D1        ; Block number to D1 for printing
       OCVT    9.,OT$TRM!OT$ZER        ; Print block number on screen
                                       ; .LOG file if task manager
       MOV     #1,LSTBAS(A5)           ; Set last UFD entry was not zeroes
50$:    BCALL   CHKUFD                  ; Is this a valid UFD entry
       BNE     60$                     ; This is not a good UFD block
       ADDW    D2,D3                   ; Set displacement to next entry
       DBF     D4,50$                  ; Decrement counter and loop
       TYPE    <*>                     ; Indicate this is a UFD block
       JMP     LOOP                    ; Get next block
60$:    TYPE    < >                     ; Indicate this may not be a UFD block
       JMP     LOOP

ENDIT:  CRLF
       EXIT

; Check an entry in this block
CHKENT: MOV     D.FIL+DDB(A5),D7        ; Filename to D7
       BEQ     10$                     ; Branch if no filename specified
       CMP     D7,0(A4)[~D3]           ; Do we have a match?
       BNE     90$                     ; Branch if not
       MOVW    D.EXT+DDB(A5),D7        ; Extension to D7
       CMPW    D7,4(A4)[~D3]           ; Do we have a match?
       RTN

10$:    LEA     A3,EXTTBL               ; Address of extensions table to A3
20$:    MOVW    (A3)+,D7                ; Move an extension to compare to D7
       BEQ     90$                     ; Branch if end of table
       CMPW    D7,4(A4)[~D3]           ; Is this an extension we want?
       BNE     20$                     ; Branch if not
       BCALL   CHKUFD                  ; Is this a valid UFD entry?
       RTN
90$:    MOVB    #-1,D7                  ; Set bad indicator
       RTN

CHKUFD:                                 ; This MAY be a UFD block. Check it
       TST     LSTBAS(A5)              ; Have we encountered a zeroes UFD?
       BNE     20$                     ; Branch if not before in this block
       LEA     A2,0(A0)[~D3]           ; Get addr of start of UFD entry
       MOVW    D2,D7                   ; Size of UFD entry to D7
       SUB     #1,D7                   ; Set for -1 stop
10$:    TSTB    (A2)+                   ; Is this byte 0?
       DBNE    D7,10$                  ; End loop if not 0 or count exhausted
       RTN

20$:    TST     DC.FLG+DVCHR(A5)        ; Extended directories
       BEQ     40$                     ; Branch if not
       MOV     D$BAS(A0)[~D3],LSTBAS(A5) ; Set last bas indicator
       BEQ     CHKUFD                  ; If base is 0, entire entry must be
       CALL    CHKNAM                  ; Is this a valid filename?
       BNE     90$                     ; Branch if not
       MOV     D$BAS(A0)[~D3],D5       ; Get first block number of file
       BCALL   CHKBAS                  ; Is it valid?
       BNE     90$                     ; Branch if not
       MOVW    D$LSZ(A0)[~D3],D6       ; Get bytes in last block
       BCALL   CHKLSZ                  ; Is it valid?
       BNE     90$                     ; Branch if not
       MOV     D$FSZ(A0)[~D3],D7       ; Get file size
       BCALL   CHKFSZ                  ; Is it valid?
       RTN
40$:    TSTW    10.(A4)[~D3]            ; Is base block 0?
       BNE     45$                     ; Branch if not
       CLR     LSTBAS(A5)              ; Set zero UFD indicator
       BR      CHKUFD                  ; Validate zero entry
45$:    CMPW    0(A4)[~D3],#-1          ; Check for deleted entry
       BNE     50$                     ; Branch if not deleted
       MOVW    2(A4)[~D3],0(A4)[~D3]   ; Set last half of name to first half
       CLRW    2(A4)[~D3]              ; Clear last half of name
50$:    BCALL   CHKNAM                  ; Is this a valid filename?
       BNE     90$                     ; Branch if not
       CLR     D5
       MOVW    10.(A4)[~D3],D5         ; Get first block number of file
       BCALL   CHKBAS                  ; Is it valid?
       BNE     90$                     ; Branch if not
       MOVW    8.(A4)[~D3],D6          ; Get bytes in last block
       BCALL   CHKLSZ                  ; Is it valid?
       BNE     90$                     ; Branch if not
       CLR     D7
       MOVW    6(A4)[~D3],D7           ; Get file size
       BCALL   CHKFSZ                  ; Is it valid?
       RTN
90$:    MOVB    #-1,D7                  ; Set not found flag
       RTN

                                       ; Validate first block number
CHKBAS: CMP     D5,#3                   ; First block must be > 2
       BMI     90$                     ; Branch if it is NOT
       CMP     D5,DC.BLK+DVCHR(A5)     ; Must be < number of blocks on disk
       BPL     90$                     ; Branch if is is not
       CLRB    D6                      ; Set good return flag
       RTN
90$:    MOVB    #-1,D7                  ; Set bad indicator
       RTN

                                       ; Validate last block size
CHKLSZ: CMPW    D6,#-1                  ; Is it > -1
       BLE     10$                     ; Branch if not
       CMPW    D6,#512.                ; Is < 512 bytes?
       BGE     10$                     ; Branch if not
       CLRB    D7                      ; Set good return
10$:    RTN

                                       ; Validate file size
CHKFSZ: CMP     D7,DC.BLK+DVCHR(A5)     ; Must be < number of blocks on disk
       BPL     90$                     ; Branch if not
       TSTW    D6                      ; Is this a contiguous file?
       BMI     20$                     ; Branch if it is
10$:    CLRB    D7                      ; Set good return
       RTN
20$:    ADD     D7,D5                   ; Add file size to starting position
       CMP     D5,DC.BLK+DVCHR(A5)     ; Must be < number of blocks on disk
       BLE     10$                     ; Branch if it is
90$:    MOVB    #-1,D7                  ; Set bad indicator
       RTN

                                       ; Validate a file name
CHKNAM: CMPW    0(A4)[~D3],#-1          ; Neither RAD50 word of name can be -1
       BEQ     90$
       CMPW    2(A4)[~D3],#-1
       BEQ     90$
       LEA     A2,FILNAM(A5)           ; Addr of ASCII filename to A2
       LEA     A1,0(A4)[~D3]           ; Addr of RAD50 filename to A1
       UNPACK
       UNPACK
       SUB     #6,A2                   ; Reset A1 to start of filename
       MOVW    #5,D7                   ; Character count -1 to D7
10$:    MOVB    (A2)+,D6                ; Move a character to D6 for compares
       CMPB    D6,#'.                  ; Is it a period?
       BEQ     90$                     ; Branch if yes
       CMPB    D6,#^H20                ; Is it a space?
       BEQ     70$                     ; Branch if yes
       DBF     D7,10$                  ; Decrement counter & loop
20$:    CLRB    D7                      ; Set good indicator
       RTN
70$:    DECW    D7                      ; Decrement counter
       BMI     20$                     ; Branch at end
75$:    CMPB    (A2)+,#^H20             ; Is this byte a space?
       DBNE    D7,75$                  ; Fall through if not or count exhausted
       RTN
90$:    MOVB    #-1,D7                  ; Set bad indicator
       RTN

HELP:   TYPECR  <?To execute this program you should:>
       TYPECR  <FNDUFD DEVn:file.ext>
       TYPECR  <%           file.ext is optional>
       EXIT
       EVEN
NOFSD:  TYPECR  <?Device is not file structured>
       EXIT
       EVEN
NOMNT:  TYPECR  <?Device is not mounted>
       EXIT
       EVEN
; Table of extensions to search for
EXTTBL: WORD    [A  ]   ; A.A
       WORD    [ALC]   ; AlphaCALC
       WORD    [BAK]   ; Old file from several programs
       WORD    [BAS]   ; Basic source file
       WORD    [BSI]   ; Basic Include source file
;       WORD    [BV ]
       WORD    [CAX]   ; AlphaCALC function key table
       WORD    [CBJ]   ; COBOL object file
       WORD    [CBL]   ; COBOL source file
       WORD    [CBX]   ; AlphaCOBOL function key table
       WORD    [CMN]   ; Compiled AlphaMENU
       WORD    [CMD]   ; Command file
       WORD    [CPY]
       WORD    [DAT]   ; Data file (Usually contiguous)
;       WORD    [DBD]
;       WORD    [DBK]
       WORD    [DO ]   ; DO command file
       WORD    [FOR]   ; Fortran source file
       WORD    [HLP]   ; HELP file
       WORD    [HLV]   ; Another type of HELP file
       WORD    [IDA]   ; ISAM data file
       WORD    [IDX]   ; ISAM index file
       WORD    [INC]   ; Fortran include source file
       WORD    [INI]   ; INItialization file
       WORD    [JRL]   ; XED journal file
       WORD    [JRN]   ; SuperVUE journal file
       WORD    [L  ]
       WORD    [LCB]   ; AAI COBOL copy source file
       WORD    [LIB]
       WORD    [LIT]   ; Executable code
;       WORD    [LSP]   ; LISP program file
       WORD    [LST]   ; Listing file
       WORD    [LPT]   ; Computer Details Listing file
       WORD    [M68]   ; Assembly source code
       WORD    [MNU]   ; AlphaMENU source file
       WORD    [MSG]   ; AAI PICS message file
       WORD    [OBJ]   ; Assembler object file
       WORD    [OLD]   ; Old copy of a file
;       WORD    [PAS]   ; Pascal source file
;       WORD    [PCF]   ; Pascal object file
       WORD    [POT]   ; AAI Purchasing line item description
       WORD    [QRY]   ; AlphaMENU query file
;       WORD    [R  ]
;       WORD    [REN]
;       WORD    [RPT]
       WORD    [RUN]   ; Basic object file
;       WORD    [S  ]
       WORD    [SAV]   ; Old copy of a file
       WORD    [SEQ]   ; Data file (Usually sequential)
       WORD    [SBR]   ; Subroutine for Basic
       WORD    [SUB]   ; Fortran subroutine
;       WORD    [SV ]
       WORD    [SYM]   ; Assembler Symbol table file
       WORD    [SYS]   ; System subroutine
       WORD    [T  ]   ; SuperVUE word processing file
       WORD    [TMP]   ; Temporary file
       WORD    [TXT]   ; TXTFMT text file
       WORD    [UNV]   ; Assembler Universal file
       WORD    [VUE]   ; Sequential file with CR/LF
       WORD    [VUX]   ; AlphaVUE function key table
       WORD    [WRT]   ; AlphaWRITE word processing file
       WORD    [WRX]   ; AlphaWRITE function key table
       WORD    [WSV]   ; MULTI configuration file
       WORD    [XBR]   ; Basic+ subroutine file
       WORD    [XUX]   ; AlphaXED function key table
       WORD    0
       END