Files
RomWBW/Source/Images/d_bp/u15/DIR.MAC
2020-01-03 20:42:06 -08:00

1465 lines
32 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;
; Program: DIR
; Author: Richard Conn
; Version: 1.0
; Date: 23 Mar 84
;
VERS EQU 11 ; Changed manner of calculating disk size
; Using all0 and all1 instead of drm
; Added modified dirqs and fsize jww
; Trial to list files vertically jww
;
;VERS EQU 10 ; Release
;
MONTH EQU 1
DAY EQU 2
YEAR EQU 85
;
Z3ENV SET 0F400H ; Set zcpr3 environment descriptor address
;
; Equates
;
YES EQU 0FFH
NO EQU 0
;
VIDEO EQU YES ; Enhanced video?
VOPT EQU YES ; Print signon and vers no
VERT EQU YES ; List files vertically (default)
;
FCB EQU 5CH
FCB2 EQU 6CH
CTRLC EQU 03H
CR EQU 0DH
LF EQU 0AH
;
; VLIB, Z3LIB and SYSLIB References
;
EXT Z3VINIT,TINIT,STNDOUT,STNDEND,BDOS
EXT CODEND,RETUD,PFN1,DFREE,DUTDIR,DPARAMS
EXT CRLF,COUT,PAFDC,PHLDC,PHLFDC,Z3LOG,FILLB,GETCRT,CIN
;
; Environment Definition
;
IF Z3ENV NE 0
;
; External ZCPR3 Environment Descriptor
;
JMP START
DB 'Z3ENV' ; This is a zcpr3 utility
DB 1 ; External environment descriptor
Z3EADR:
DW Z3ENV
START:
LHLD Z3EADR ; Pt to zcpr3 environment
;
ELSE
;
; Internal ZCPR3 Environment Descriptor
;
MACLIB Z3BASE.LIB
MACLIB SYSENV.LIB
Z3EADR:
JMP START
SYSENV
START:
LXI H,Z3EADR ; Pt to zcpr3 environment
ENDIF
;
; Start of Program -- Initialize ZCPR3 Environment
;
CALL Z3VINIT ; Initialize the zcpr3 env
CALL TINIT ; Initialize the terminal
;
; Make FCB Wild if No Entry
;
LXI H,FCB+1 ; Pt to first char
MOV A,M ; Get it
CPI ' ' ; Check for space
MVI B,11 ; Prepare to set 11 bytes
MVI A,'?' ; To "?"
CZ FILLB ; Do it if space
;
; Check for Help
;
LXI D,FCB+1 ; Pt to first char of fcb
LDAX D ; Get first char of fcb
CPI '/'
JNZ DOIT
CALL PRINT
DB 'DIR Vers '
DB (VERS/10)+'0','.',(VERS MOD 10)+'0',CR,LF
DB ' Syntax: DIR dir:afn o',CR,LF
DB ' Options: A=All, S=Sys, H=Horiz, V=Vert, '
DB 'T=File Type/Name Sor','t'+80H
RET
;
; Perform Directory Function
;
DOIT:
DCX D ; Pt to fcb
CALL Z3LOG ; Log into dir
XRA A ; Clear disk selection byte
STAX D
;
; Process Options in FCB2
;
LXI H,FCB2+1 ; Pt to options
MVI B,8 ; Allow for up to 8 options
MVI C,10000000B ; Assume just normal files
OPTLOOP:
MOV A,M ; Get next char
INX H ; Advance
DCR B ; Count down
JZ SETDATA ; Done - set data
CPI ' '
JZ OPTLOOP
CPI 'H' ; Select horizontal listing
JZ SETHORIZ
CPI 'V' ; Select vertical listing
JZ SETVERT
CPI 'T' ; File type?
JZ SETTYPE
CPI 'S' ; System?
JZ SETSYS
CPI 'A' ; System and normal?
JNZ OPTLOOP
;
; Select Both System and Normal Files
;
MVI A,11000000B ; Normal and system files
JMP SETSYS1
;
; Select Horizontal listing
;
SETHORIZ:
MVI A,YES
STA HORIZ
JMP OPTLOOP
;
; Select Vertical listing
;
SETVERT:
MVI A,NO
STA HORIZ
JMP OPTLOOP
;
HORIZ: DB NOT VERT ; Horizontal listing flag
;
; Select File Type/Name Alphabetization
;
SETTYPE:
MOV A,C ; Get flag
ORI 00100000B
MOV C,A
JMP OPTLOOP
;
; Select Just System Files
;
SETSYS:
MVI A,01000000B ; System
SETSYS1:
PUSH PSW
MOV A,C
ANI 00111111B ; Mask out
MOV C,A
POP PSW
ORA C
MOV C,A
JMP OPTLOOP
;
; Set Selection Byte in A
;
SETDATA:
CALL DPARAMS ; Init parameters
CALL CODEND ; Pt to free area
MOV A,C ; Selection in a
;
; Load and Sort Directory
;
CALL DIRQS ; Quick load
SHLD DIRBEG ; Beginning of directory area
JNZ DISPLAY
CALL PRINT
DB ' Ovf','l'+80H
RET
;
; Display Directory
;
DISPLAY:
PUSH H ; Save ptr to first entry
;
; Init:
; Total of All File Sizes
; Number of Files Displayed
; Line Counter
; Entry Counter
;
IF VOPT ; Signon and version
PUSH B
IF VIDEO
CALL STNDOUT
ENDIF
MVI C,22 ; Print 22 spaces
DIS0: MVI A,' '
CALL COUT
DCR C
JNZ DIS0
CALL PRINT
DB 'DIRectory Version '
DB VERS/10+'0','.',VERS MOD 10+'0'
DB ' ',MONTH/10+'0',MONTH MOD 10+'0','/'
DB DAY/10+'0',DAY MOD 10+'0','/'
DB YEAR/10+'0',YEAR MOD 10+'0'
DB CR,LF+80H
IF VIDEO
CALL STNDEND
ENDIF
POP B
ENDIF ; Vopt
;
LXI H,0 ; Set total size count
SHLD TOTCOUNT
LXI H,FCOUNT ; Save file count
MOV M,C
INX H
MOV M,B ; File count saved from bc
PUSH B ; Save file count
MOV H,B
MOV L,C ; Move it to hl
LXI D,4
CALL DIVIDE ; Divide by four columns
JZ DIS1
INX B ; Round up if remainder from division
DIS1: MOV H,B
MOV L,C ; Quotient to hl
CALL X16
SHLD LINES
POP H ; Get file count
PUSH H ; And put it back
DCX H ; File count -1 points to last file
CALL X16 ; Multiply by 16 chars/line
XCHG ; Directory size to de
LHLD DIRBEG
DAD D
SHLD DIREND
POP B ; Get file count
POP H ; Pt to first entry
XRA A
STA LCOUNT ; Init line count
STA COUNT ; Init entry count
MOV A,B ; Check for done
ORA C
JZ PRREMAIN ; Print remaining space on disk and exit
CALL PRINT
DB ' '+80H ; Print first leading space
;
; Loop to Display File Entries
;
DISPLOOP:
;
; Print Separator if Within a Line
;
LDA COUNT ; See if new entry on line
ANI 3
JZ DISPL1
;
; Print Separator if Entry is Within a List
;
IF VIDEO
CALL STNDOUT
ENDIF
CALL PRINT ; Print separator
DB '|',' '+80H
IF VIDEO
CALL STNDEND
ENDIF
;
; Print Next Entry
;
DISPL1:
PUSH H ; Save key regs
PUSH B ; Hl pts to next entry, bc = count
;
; Print File Name
;
INX H ; Pt to file name
XCHG
CALL PFN1 ; Print file name
XCHG
DCX H ; Pt to first byte of file entry
;
; Print File Size and Increment Total of All File Sizes
;
PUSH H ; Save ptr to first byte of file entry
CALL FSIZE ; Compute file size (to de)
LHLD TOTCOUNT ; Increment total count
DAD D
SHLD TOTCOUNT
XCHG
CALL PHLDC ; Print file size
POP H ; Get ptr to first byte of file entry
;
; Check R/O Byte
;
MVI B,' ' ; Assume r/w
LXI D,9 ; Pt to r/o
DAD D
MOV A,M ; Get r/o byte
ANI 80H ; Look at it
JZ ROOUT
MVI B,'r' ; Set r/o
ROOUT:
MOV A,B ; Get char
CALL COUT
;
; Increment Entry Count and Issue New Line if Limit Reached
;
LDA COUNT ; Increment entry count
INR A
STA COUNT
LDA HORIZ ; Check horiz/vert listing
ORA A
JZ DISPL2 ; Vertical listing
LDA COUNT
ANI 3 ; New line?
CZ NEWLIN
JMP DISPL2
;
; New Line - Increment Line Count and Issue Page Break if Limit Reached
;
NEWLIN: CALL PRNL
LDA LCOUNT ; Count down lines
INR A
STA LCOUNT
CALL GETCRT ; Get crt data
INX H ; Pt to text line count
INX H
DCR A ; Back up again
CMP M ; Compare
RNZ
XRA A ; Reset line count
STA LCOUNT
IF VIDEO
CALL STNDOUT
ENDIF
CALL PRINT
DB ' Pause -',' '+80H
IF VIDEO
CALL STNDEND
ENDIF
CALL CIN
CALL PRNL ; Print new line with leading space
CPI CTRLC ; Abort?
RNZ
POP PSW ; Clear the rest of the stack
POP PSW
POP PSW
RET ; To zcpr3
;
; Advance to Next Entry
;
DISPL2:
POP B ; Restore count and ptr to current entry
POP H
LDA HORIZ ; Check horiz/vert listing
ORA A
JNZ DISP2 ; Horizontal
XCHG ; Pointer to de
LHLD LINES
DAD D ; Point to next entry
XCHG ; New pointer to de
LHLD DIREND
CALL SUBDE ; Check if new ptr is within the directory
XCHG ; New pointer to hl
JNC DISP3 ; New pointer is ok
LHLD DIRBEG ; Otherwise start new line
LXI D,16 ; Next line
DAD D
SHLD DIRBEG ; Save it
XRA A
STA COUNT ; Clear column count
PUSH H
PUSH B
CALL NEWLIN
POP B
POP H
JMP DISP3
DISP2: LXI D,16 ; Skip to next entry
DAD D
DISP3: DCX B ; Count down
MOV A,B ; Done?
ORA C
JNZ DISPLOOP
LDA COUNT ; See if new line required
ANI 3
CNZ CRLF ; New line if any entries on line
;
; Print Remaining Space on Disk and Exit
;
PRREMAIN:
;
; Print DU
;
IF VIDEO
CALL STNDOUT
ENDIF
MVI B,8 ; Space over 8 spaces
MVI A,' '
SPACER:
CALL COUT
DCR B
JNZ SPACER
CALL RETUD ; Get du in bc
MOV A,B ; Print disk letter
ADI 'A' ; Convert to ascii
CALL COUT
MOV A,C ; Print user number
CALL PAFDC ; Print floating
CALL PRINT ; Print separator
DB ':'+80H
CALL DUTDIR ; See if matching dir
JZ PRREM1
;
; Print DIR if any
;
MVI B,8 ; 8 chars max
PRREM0:
MOV A,M ; Get char
INX H ; Pt to next
CPI ' ' ; Space?
CNZ COUT ; Echo char
DCR B ; Count down
JNZ PRREM0
;
; Print File Count
;
PRREM1:
LHLD FCOUNT ; Print number of files
CALL PRINT
DB ' --',' '+80H
CALL PHLFDC
;
; Print Total of All File Sizes
;
LHLD TOTCOUNT ; Print total count
CALL PRINT
DB ' files using',' '+80H
CALL PHLFDC ; Print as floating
;
; Print Amount of Free Space Remaining
;
CALL DFREE ; Compute amount of free space
XCHG ; In hl
CALL PRINT
DB 'k ','('+80H
CALL PHLFDC
CALL PRINT
DB 'k remain of',' '+80H
CALL DSIZE
CALL PHLFDC
CALL PRINT
DB 'k total',')'+80H
IF VIDEO
CALL STNDEND
ENDIF
RET
;
; Print New Line with Leading Space
;
PRNL:
CALL PRINT
DB CR,LF,' '+80H ; New line with leading space
RET
;
; Print Routine (String at Return Address) which is terminated by MSB
;
PRINT:
XTHL ; Pt to string and save hl
PUSH PSW
PRINT1:
MOV A,M ; Get next char
ANI 7FH ; Mask msb
CALL COUT
MOV A,M ; Get next char
INX H ; Pt to next
ANI 80H ; Check msb
JZ PRINT1
POP PSW ; Get a
XTHL ; Restore return address and hl
RET
;
; DSIZE returns the size of the current disk in HL (k)
;
DSIZE: PUSH D
PUSH B
;
MVI C,31 ; Return dpb address in hl
CALL BDOS
INX H
INX H ; Point to bls
MOV A,M ; Bls in a
STA BLS
INX H
INX H
INX H ; Point to dsm
MOV E,M
INX H
MOV D,M ; Dsm in de
INX D ; Rel 1
PUSH D ; Save dsm on stack
INX H ; Point to drm
INX H
INX H ; Point to all0
MOV D,M
INX H ; Point to all1
MOV E,M
XCHG ; Allocation vector in hl
LXI D,-1 ; Clear a counter
DS0: INX D
CALL SHLHL
JC DS0
CALL SUBDE ; Get complement of count
POP D ; Get dsm from stack
DAD D ; Hl = groups available
LDA BLS ; Block shift factor
SUI 3 ; From bls in a
JZ DSX
DSIZ0: DAD H
DCR A
JNZ DSIZ0
DSX:
POP B
POP D
RET
;
; DIVIDE divides HL by DE returning quotient in BC and remainder in HL
; Zero flag is set if no remainder
;
DIVIDE: LXI B,0 ; Clear quotient
DIV0: CALL SUBDE ; Subtract de from hl
JC DIV1 ; Overflow
INX B ; Increment quotient
JMP DIV0 ; Again..
DIV1: DAD D ; Restore remainder in hl
MOV A,H ; Check for remainder
ORA L ; Equal zero
RET
;
; SUBDE subtracts DE from HL returning carry set if de > hl
;
SUBDE: MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A
RET
;
; X16 simply shifts HL left four times
;
X16: DAD H
DAD H
DAD H
DAD H
RET
;
; SHLHL shifts HL left into carry
;
SHLHL: ORA A ; Reset carry
MOV A,L
RAL
MOV L,A
MOV A,H
RAL
MOV H,A
RET
;
; SYSLIB Module Name: SDIRQS
; Author: Richard Conn
; Part of SYSLIB3 SDIR Series
; SYSLIB Version Number: 3.0
; Module Version Number: 1.4
; Module Entry Points:
; DIRQS
; Module External References:
; None
;
;*
;* EQUATES
;*
CPM EQU 0
BUFF EQU 80H ; Dma buffer
ESIZE EQU 16 ; 16 bytes/entry
;*
;* GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITHOUT SIZING INFORMATION
;* THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES
;* WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL. ON EXIT,
;* BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER.
;* THE DIRECTORY BUFFER GENERATED BY DIRQ CONTAINS ENTRIES WHICH MAY NOT
;* BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE. THE
;* DIRQS ROUTINE IS DESIGNED FOR THIS PURPOSE. THE BASIC TRADEOFF BETWEEN
;* THE TWO ROUTINES IS THE DIRQ RUNS FASTER THAN DIRQS, AND THIS IS NOTICABLE
;* IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED.
;*
;* THE DIRQ/DIRQS ROUTINES ARE INTENDED TO BE USED IN APPLICATIONS WHERE
;* THE ONLY THING DESIRED IS A DIRECTORY LOAD OF THE CURRENT DIRECTORY
;* (DISK AND USER). DIRF/DIRFS PROVIDE MORE FLEXIBILITY AT A GREATER COST
;* IN TERMS OF SIZE.
;*
;* INPUT PARAMETERS:
;* HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG:
;* Bit 7 - Select Non-Sys, Bit 6 - Select Sys
;* Bit 5 - Sort by File Name and Type (0) or other (1)
;* Bits 4-0 - Unused
;* OUTPUT PARAMETERS:
;* HL PTS TO FIRST FILE IN BUFFER
;* BC = NUMBER OF FILES
;* A=0 and Z Flag Set if TPA Overflow
;* DE UNCHANGED
;*
DIRQS:
PUSH D ; Save ptr to fcb
STA SELFLG ; Save select flag for selection and alphabetization
SHLD HOLD ; Set ptr to hold buffer
LXI B,36 ; Allow 36 bytes
DAD B ; Hl now points to temp fcb
SHLD TFCB ; Set ptr to temp fcb
DAD D ; Hl now pts to scratch area
PUSH D ; Save ptr to fcb
CALL DBUFFER ; Get ptrs
POP D ; Get ptr to fcb
PUSH H ; Save ptr to buffer
CALL DIRLOAD ; Load directory (fast load)
POP H ; Get ptr to buffer
POP D ; Get ptr to fcb
RZ ; Abort if tpa overflow
PUSH PSW ; Save flag to indicate no tpa overflow
CALL DIRALPHA ; Alphabetize
POP PSW ; Get psw (tpa overflow flag)
RET
;*
;* THIS ROUTINE ACCEPTS A BASE ADDRESS FOR THE DYNAMIC BUFFERS
;* REQUIRED, DETERMINES HOW MUCH SPACE IS REQUIRED FOR THE BUFFERS,
;* AND SETS THE ORDER PTR TO PT TO THE FIRST AND DIRBUF TO PT TO
;* THE SECOND (ORDER SPACE = DIRMAX*2 AND DIRBUF = DIRMAX * ESIZE)
;* ON INPUT, HL PTS TO AVAILABLE BASE
;* ON OUTPUT, HL PTS TO DIRBUF
;* A=0 AND ZERO FLAG SET IF CCP OVERRUN
;*
DBUFFER:
SHLD ORDER ; Pt to order table
CALL DPARAMS0 ; Get parameters
LHLD DIRMAX ; Number of entries in dir
XCHG ; In de
LHLD ORDER ; Add to order base
DAD D ; *1
CALL MEMCHK ; Check for within range
DAD D ; Hl pts to dirbuf
CALL MEMCHK ; Check for within range
SHLD DIRBUF ; Set ptr and hl pts to directory buffer
XRA A ; Ok
DCR A ; Set flags (nz)
RET
MEMCHK:
PUSH H ; Save regs
PUSH D
XCHG ; Next address in de
LHLD BDOS+1 ; Get address of bdos
MOV A,D ; Check for page overrun
CMP H
JNC MEMORUN ; Overrun if d>=h
POP D
POP H
RET
MEMORUN:
POP D ; Restore
POP H
POP PSW ; Clear stack
XRA A ; Return 0
RET
;*
;* THIS ROUTINE EXTRACTS DISK PARAMETER INFORMATON FROM THE DPB AND
;* STORES THIS INFORMATION IN:
;* BLKSHF <-- BLOCK SHIFT FACTOR (1 BYTE)
;* BLKMSK <-- BLOCK MASK (1 BYTE)
;* EXTENT <-- EXTENT MASK (1 BYTE) [NOT ANY MORE]
;* BLKMAX <-- MAX NUMBER OF BLOCKS ON DISK (2 BYTES)
;* DIRMAX <-- MAX NUMBER OF DIRECTORY ENTRIES (2 BYTES)
;*
DPARAMS0:
;*
;* VERSION 2.x OR MP/M
;*
MVI C,31 ; 2.x or mp/m...request dpb
CALL BDOS
INX H
INX H
MOV A,M ; Get block shift
STA BLKSHF ; Block shift factor
INX H ; Get block mask
MOV A,M
STA BLKMSK ; Block mask
INX H
INX H
MOV E,M ; Get max block number
INX H
MOV D,M
XCHG
INX H ; Add 1 for max number of blocks
SHLD BLKMAX ; Maximum number of blocks
XCHG
INX H
MOV E,M ; Get directory size
INX H
MOV D,M
XCHG
INX H ; Add 1 for number of entries
SHLD DIRMAX ; Maximum number of directory entries
RET
;*
;* BUILD DIRECTORY TABLE AT DIRBUF
;* THIS IS THE OPTIMAL DIRECTORY LOAD ROUTINE; IT ONLY LOADS UNIQUE
;* FILE NAMES FROM DISK, BUT THE INFORMATION IS NOT SUFFICIENT
;* TO COMPUTE THE FILE SIZES
;* ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX)
;* DE PTS TO FCB (ONLY 12 BYTES NEEDED)
;* ON OUTPUT, BC IS NUM OF FILES
;* A=0 AND ZERO FLAG SET IF TPA OVERFLOW
;*
DIRLOAD:
SHLD DSTART ; Set start of buffer area
INX D ; Pt to file name
LHLD TFCB ; Pt to tfcb
MVI M,0 ; Select current disk
INX H ; Pt to file name in tfcb
MVI B,11 ; 11 chars
DLLOOP:
LDAX D ; Copy
MOV M,A
INX H ; Pt to next
INX D
DCR B ; Count down
JNZ DLLOOP
MVI M,'?' ; Select all extents
INX H ; Pt to next char
MVI M,0
INX H
MVI M,'?' ; And all modules
INX H
MVI B,21 ; 23 chars
XRA A ; Zero rest of tfcb
DLLOOP1:
MOV M,A ; Store zero
INX H ; Pt to next
DCR B ; Count down
JNZ DLLOOP1
;*
;* THIS SECTION OF CODE INITIALIZES THE COUNTERS USED
;*
LXI H,0 ; Hl=0
SHLD FCOUNT0 ; Total files on disk = 0
;*
;* NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER
;*
MVI C,17 ; Search for file
JMP DIRLP1
DIRLP:
CALL PENTRY ; Place entry in dir
JZ DIROVFL ; Memory overflow error
MVI C,18 ; Search for next match
DIRLP1:
LHLD TFCB ; Pt to fcb
XCHG
CALL BDOS
CPI 255 ; Done?
JNZ DIRLP
;*
;* NOW WE ARE DONE WITH THE LOAD -- SET UP RETURN VALUES
;*
DIRDN:
XRA A ; Load ok
DCR A ; Set flags (nz)
DIRDNX:
LHLD FCOUNT0 ; Get total number of files
MOV B,H ; In bc
MOV C,L
RET
;*
;* MEMORY OVERFLOW ERROR
;*
DIROVFL:
XRA A ; Load error
JMP DIRDNX
;*
;* PENTRY --
;* PLACE ENTRY IN DIRECTORY BUFFER IF NOT AN ERASED ENTRY
;*
;* ON INPUT, A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB
;* FCOUNT0=NUMBER OF FILES IN DIR SO FAR
;* ON OUTPUT, FCOUNT0=NUMBER OF FILES IN DIR SO FAR
;* A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR
;*
PENTRY:
RRC ; Multiply by 32 for offset computation
RRC
RRC
ANI 60H ; A=byte offset
LXI D,BUFF ; Pt to buffer entry
MOV L,A ; Let hl=offset
MVI H,0
DAD D ; Hl=ptr to fcb
;*
;* HL=ADR OF FCB IN BUFF
;*
CALL ATTEST ; Test attributes
JZ PEDONE ; Skip if attribute not desired
;*
;* SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME
;* NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX
;* AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT
;* FOUND, RETURN WITH ZERO FLAG RESET (NZ)
;*
CALL DUPENTRY ; Check for duplicate and select ex
JZ PEDONE ; Skip if duplicate
;*
;* COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER
;*
XCHG ; Save ptr in de
LHLD DIRBUF ; Pt to next entry location
XCHG ; Hl pts to fcb, de pts to next entry location
MVI B,ESIZE ; Number of bytes/entry
CALL SDMOVE ; Copy fcb into memory buffer
XCHG ; Hl pts to next entry
SHLD DIRBUF ; Set ptr
XCHG ; Ptr to next entry in de
LHLD BDOS+1 ; Base address of bdos in hl
MOV A,H ; Get base page of bdos
SUI 9 ; Compute 1 page in front of base page of ccp
CMP D ; Is ptr to next entry beyond this?
RZ
;* INCREMENT TOTAL NUMBER OF FILES
LHLD FCOUNT0 ; Total files = total files + 1
INX H
SHLD FCOUNT0
;* DONE WITH PENTRY AND NO ERROR
PEDONE:
XRA A ; No error
DCR A ; Set flags (nz)
RET
;*
;* CHECK ATTRIBUTES OF FILE ENTRY PTED TO BY HL AGAINST SELFLG
;* IF SYSTEM FILE AND SYSTEM ATTRIBUTE SET, RETURN NZ
;* IF NORMAL FILE AND NORMAL ATTRIBUTE SET, RETURN NZ
;*
ATTEST:
PUSH H ; Save ptr
LXI B,10 ; Pt to system attribute
DAD B
MOV A,M ; Get system attribute
POP H ; Restore ptr
ANI 80H ; Check for sys
LDA SELFLG ; Get selection flag
JZ ATDIR
ANI 01000000B ; Check system attribute
RET
ATDIR:
ANI 10000000B ; Check normal attribute
RET
;*
;* SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME
;* NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX
;* AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT
;* FOUND, RETURN WITH ZERO FLAG RESET (NZ)
;* ON INPUT, HL PTS TO ENTRY TO SCAN FOR, FCOUNT0 = NUMBER OF ENTRIES SO FAR,
;* AND (DSTART) = STARTING ADDRESS OF DIRECTORY LOADED
;* ON OUTPUT, A=0 AND ZERO FLAG SET IF DUPLICATE ENTRY FOUND; A=0FFH AND NZ
;* IF NO DUP ENTRY FOUND
;* ONLY HL NOT AFFECTED
;*
DUPENTRY:
PUSH H ; Save ptr to entry to scan for
XCHG ; Ptr in de
LHLD FCOUNT0 ; Check count
MOV A,H ; No entries?
ORA L
JZ NODUP ; No duplicate entry return
MOV B,H ; Bc=number of entries
MOV C,L
LHLD DSTART ; Hl pts to first entry
DUPELOOP:
PUSH B ; Save count
PUSH H ; Save ptrs
PUSH D
INX H ; Pt to fn
INX D
MVI B,11 ; Compare fn and ft
CALL COMP
JNZ NODUPL ; Continue looking for another entry
; DUPLICATE ENTRIES HAVE BEEN IDENTIFIED AT THIS POINT
MOV C,M ; Extent in low order
INX H
INX H
MOV B,M ; Module in high order
PUSH B ; Save entry size a moment
XCHG ; Point hl to target
MOV E,M ; Extent in low order
INX H
INX H
MOV D,M ; Module in high order
POP H ; Dir in hl, target in de
XCHG
CALL SUBDE ; Subtract dir size from target size
POP D ; Get ptrs
POP H
JC DUPSMALL ; Target is smaller
; NEW TARGET IS LARGER THAN STORED ENTRY
XCHG ; Hl pts to target, de pts to dir entry
MVI B,ESIZE ; Number of bytes to move
CALL SDMOVE ; Move it
; NEW TARGET IS SMALLER THAN STORED ENTRY
DUPSMALL:
POP B ; Clear count from stack
XRA A ; Indicate dup found
POP H ; Restore ptr to entry to scan for
RET
; NO DUPLICATE FOUND; ADVANCE TO NEXT ENTRY
NODUPL:
POP D ; Restore ptrs
POP H
LXI B,ESIZE ; Hl pts to current entry in buffer, so add esize to it
DAD B
POP B ; Get count
DCX B ; Count down
MOV A,B ; Check for done
ORA C
JNZ DUPELOOP
; NO DUPLICATE FOUND
NODUP:
XRA A ; Indicate dup not found
DCR A ; Set flags (nz)
POP H ; Restore ptr to entry to scan for
RET
;*
;* DIRALPHA -- ALPHABETIZES DIRECTORY PTED TO BY HL; BC CONTAINS
;* THE NUMBER OF FILES IN THE DIRECTORY AND A = SORT FLAG
;* (0=SORT BY FILE NAME/TYPE, <>0 = SORT BY FILE TYPE/NAME)
;*
DIRALPHA:
MOV A,B ; Any files?
ORA C
RZ
PUSH H ; Save regs
PUSH D
PUSH B
SHLD DIRBUF ; Save ptr to directory
PUSH H ; Save hl
MOV H,B ; Hl=bc=file count
MOV L,C
SHLD N ; Set "N"
POP H
;*
;* SHELL SORT --
;* THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS"
;* BY KERNIGAN AND PLAUGHER, PAGE 106. COPYRIGHT, 1976, ADDISON-WESLEY.
;* ON ENTRY, BC=NUMBER OF ENTRIES
;*
SORT:
XCHG ; Pointer to directory in de
LHLD ORDER ; Pt to order table
;*
;* SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT
;* ENTRY IN DIRECTORY, BC = NUMBER OF ELEMENTS REMAINING
;*
SORT1:
MOV M,E ; Store low-order address
INX H ; Pt to next order byte
MOV M,D ; Store high-order address
INX H ; Pt to next order entry
PUSH H ; Save ptr
LXI H,ESIZE ; Hl=number of bytes/entry
DAD D ; Pt to next dir1 entry
XCHG ; De pts to next entry
POP H ; Get ptr to order table
DCX B ; Count down
MOV A,B ; Done?
ORA C
JNZ SORT1
;*
;* THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P
;*
;*
;* SHELL SORT FROM "SOFTWARE TOOLS" BY KERNINGHAN AND PLAUGER
;*
LHLD N ; Number of items to sort
SHLD GAP ; Set initial gap to n for first division by 2
;* FOR (GAP = N/2; GAP > 0; GAP = GAP/2)
SRTL0:
ORA A ; Clear carry
LHLD GAP ; Get previous gap
MOV A,H ; Rotate right to divide by 2
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
;* TEST FOR ZERO
ORA H
JZ SDONE ; Done with sort if gap = 0
SHLD GAP ; Set value of gap
SHLD I ; Set i=gap for following loop
;* FOR (I = GAP + 1; I <= N; I = I + 1)
SRTL1:
LHLD I ; Add 1 to i
INX H
SHLD I
;* TEST FOR I <= N
XCHG ; I is in de
LHLD N ; Get n
MOV A,L ; Compare by subtraction
SUB E
MOV A,H
SBB D ; Carry set means i > n
JC SRTL0 ; Don't do for loop if i > n
LHLD I ; Set j = i initially for first subtraction of gap
SHLD J
;* FOR (J = I - GAP; J > 0; J = J - GAP)
SRTL2:
LHLD GAP ; Get gap
XCHG ; In de
LHLD J ; Get j
MOV A,L ; Compute j - gap
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A
SHLD J ; J = j - gap
JC SRTL1 ; If carry from subtractions, j < 0 and abort
MOV A,H ; J=0?
ORA L
JZ SRTL1 ; If zero, j=0 and abort
;* SET JG = J + GAP
XCHG ; J in de
LHLD GAP ; Get gap
DAD D ; J + gap
SHLD JG ; Jg = j + gap
;* IF (V(J) <= V(JG))
CALL ICOMPARE ; J in de, jg in hl
;* ... THEN BREAK
JC SRTL1
;* ... ELSE EXCHANGE
LHLD J ; Swap j, jg
XCHG
LHLD JG
CALL ISWAP ; J in de, jg in hl
;* END OF INNER-MOST FOR LOOP
JMP SRTL2
;*
;* SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE
;*
SDONE:
LHLD N ; Number of entries
MOV B,H ; In bc
MOV C,L
LHLD ORDER ; Ptr to ordered pointer table
SHLD PTPTR ; Set ptr ptr
LHLD DIRBUF ; Ptr to unordered directory
SHLD PTDIR ; Set ptr dir buffer
;* FIND PTR TO NEXT DIR1 ENTRY
SRTDN:
LHLD PTPTR ; Pt to remaining pointers
XCHG ; In de
LHLD PTDIR ; Hl pts to next dir entry
PUSH B ; Save count of remaining entries
;* FIND PTR TABLE ENTRY
SRTDN1:
LDAX D ; Get current pointer table entry value
INX D ; Pt to high-order pointer byte
CMP L ; Compare against dir1 address low
JNZ SRTDN2 ; Not found yet
LDAX D ; Low-order bytes match -- get high-order pointer byte
CMP H ; Compare against dir1 address high
JZ SRTDN3 ; Match found
SRTDN2:
INX D ; Pt to next ptr table entry
DCX B ; Count down
MOV A,C ; End of table?
ORA B
JNZ SRTDN1 ; Continue if not
;* FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT
FERR$PTR:
MVI E,7 ; Ring bell
MVI C,2 ; Output
CALL BDOS
JMP CPM
;* FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED DIR1 ENTRY
;* MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED DIR1 ENTRY)
;* POINT TO SAME LOCATION (PTR TO NEXT DIR1 ENTRY TO BE ORDERED)
SRTDN3:
LHLD PTPTR ; Get ptr to next ordered entry
DCX D ; De pts to low-order pointer address
MOV A,M ; Make ptr to next unordered dir1 pt to buffer for
STAX D ; Dir1 entry to be moved to next unordered dir1 pos
INX H ; Pt to next ptr address
INX D
MOV A,M ; Make high point similarly
STAX D
;* COPY NEXT UNORDERED DIR1 ENTRY TO HOLD BUFFER
MVI B,ESIZE ; B=number of bytes/entry
LHLD HOLD ; Pt to hold buffer
XCHG
LHLD PTDIR ; Pt to entry
PUSH B ; Save b=number of bytes/entry
CALL SDMOVE
POP B
;* COPY TO-BE-ORDERED DIR1 ENTRY TO NEXT ORDERED DIR1 POSITION
LHLD PTPTR ; Point to its pointer
MOV E,M ; Get low-address pointer
INX H
MOV D,M ; Get high-address pointer
LHLD PTDIR ; Destination address for next ordered dir1 entry
XCHG ; Hl pts to entry to be moved, de pts to dest
PUSH B ; Save b=number of bytes/entry
CALL SDMOVE
POP B
XCHG ; Hl pts to next unordered dir1 entry
SHLD PTDIR ; Set pointer for next loop
;* COPY ENTRY IN HOLD BUFFER TO LOC PREVIOUSLY HELD BY LATEST ORDERED ENTRY
LHLD PTPTR ; Get ptr to ptr to the destination
MOV E,M ; Get low-address pointer
INX H
MOV D,M ; High-address pointer
LHLD HOLD ; Hl pts to hold buffer, de pts to entry dest
CALL SDMOVE ; B=number of bytes/entry
;* POINT TO NEXT ENTRY IN POINTER TABLE
LHLD PTPTR ; Pointer to current entry
INX H ; Skip over it
INX H
SHLD PTPTR
;* COUNT DOWN
POP B ; Get counter
DCX B ; Count down
MOV A,C ; Done?
ORA B
JNZ SRTDN
POP B ; Restore regs
POP D
POP H
RET ; Done
;*
;* SWAP (Exchange) the pointers in the ORDER table whose indexes are in
;* HL and DE
;*
ISWAP:
PUSH H ; Save hl
LHLD ORDER ; Address of order table - 2
MOV B,H ; In bc
MOV C,L
POP H
DCX H ; Adjust index to 0...n-1 from 1...n
DAD H ; Hl pts to offset address indicated by index
; Of original hl (1, 2, ...)
DAD B ; Hl now pts to pointer involved
XCHG ; De now pts to pointer indexed by hl
DCX H ; Adjust index to 0...n-1 from 1...n
DAD H ; Hl pts to offset address indicated by index
; Of original de (1, 2, ...)
DAD B ; Hl now pts to pointer involved
MOV C,M ; Exchange pointers -- get old (de)
LDAX D ; -- get old (hl)
XCHG ; Switch
MOV M,C ; Put new (hl)
STAX D ; Put new (de)
INX H ; Pt to next byte of pointer
INX D
MOV C,M ; Get old (hl)
LDAX D ; Get old (de)
XCHG ; Switch
MOV M,C ; Put new (de)
STAX D ; Put new (hl)
RET
;*
;* ICOMPARE compares the entry pointed to by the pointer pointed to by HL
;* with that pointed to by DE (1st level indirect addressing); on entry,
;* HL and DE contain the numbers of the elements to compare (1, 2, ...);
;* on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)),
;* and Non-Zero and No-Carry means ((DE)) > ((HL))
;*
ICOMPARE:
PUSH H ; Save hl
LHLD ORDER ; Address of order - 2
MOV B,H ; In bc
MOV C,L
POP H
DCX H ; Adjust index to 0...n-1 from 1...n
DAD H ; Double the element number to point to the ptr
DAD B ; Add to this the base address of the ptr table
XCHG ; Result in de
DCX H ; Adjust index to 0...n-1 from 1...n
DAD H ; Do the same with the original de
DAD B
XCHG
;*
;* HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH
;* DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH
;* FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL
;* TO THE 4TH POINTER
;*
MOV C,M ; Bc is made to point to the object indexed to
INX H ; By the original hl
MOV B,M
XCHG
MOV E,M ; De is made to point to the object indexed to
INX H ; By the original de
MOV D,M
MOV H,B ; Set hl = object pted to indirectly by bc
MOV L,C
;*
;* COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE;
;* NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE<HL
;* RET W/ZERO SET MEANS DE=HL
;*
CMP$ENTRY:
LDA SELFLG ; Group by file type?
ANI 00100000B
JZ CMP$FN$FT
;*
;* COMPARE BY FILE TYPE AND FILE NAME (IN THAT ORDER)
;*
PUSH H
PUSH D
LXI B,9 ; Pt to ft (8 bytes + 1 byte for user number)
DAD B
XCHG
DAD B
XCHG ; De, hl now pt to their ft's
MVI B,3 ; 3 bytes
CALL COMP ; Compare ft's
POP D
POP H
RNZ ; Continue if complete match
MVI B,8 ; 8 bytes
JMP CMP$FT1
;*
;* COMPARE BY FILE NAME AND FILE TYPE (IN THAT ORDER)
;*
CMP$FN$FT:
MVI B,11 ; 11 bytes for fn and ft
CMP$FT1:
PUSH H
PUSH D
INX H ; Pt to fn
INX D
CALL COMP ; Do comparison
POP D
POP H
RET
;*
;* COMP COMPARES DE W/HL FOR B BYTES; RET W/CARRY IF DE<HL
;* MSB IS DISREGARDED
;*
COMP:
MOV A,M ; Get (hl)
ANI 7FH ; Mask msb
MOV C,A ; In c
LDAX D ; Compare
ANI 7FH ; Mask msb
CMP C
RNZ
INX H ; Pt to next
INX D
DCR B ; Count down
JNZ COMP
RET
;*
;* COPY FROM HL TO DE FOR B BYTES
;*
SDMOVE:
MOV A,M ; Copy
STAX D
INX H ; Pt to next
INX D
DCR B ; Count down
JNZ SDMOVE
RET
;*
;* BUFFERS
;*
HOLD:
DS 2 ; Exchange hold buffer for fcb's
PTPTR:
DS 2 ; Pointer pointer
PTDIR:
DS 2 ; Directory pointer
I:
DS 2 ; Indexes for sort
J:
DS 2
JG:
DS 2
N:
DS 2 ; Number of elements to sort
GAP:
DS 2 ; Binary gap size
TFCB:
DS 2 ; Address of temporary fcb
DSTART:
DS 2 ; Pointer to first directory entry
FCOUNT0:
DS 2 ; Total number of files/number of selected files
BLKSHF:
DB 0 ; Block shift factor
BLKMSK:
DB 0 ; Block mask
BLKMAX:
DW 0 ; Max number of blocks
DIRMAX:
DW 0 ; Max number of directory entries
SELFLG:
DB 0 ; File attribute flag
ORDER:
DW 0 ; Pointer to order table
DIRBUF:
DW 0 ; Pointer to directory
; END
;
; Buffers
;
COUNT: DS 1 ; Counter used in display
FCOUNT: DS 2 ; Number of files displayed
LCOUNT: DS 1 ; Line counter
TOTCOUNT: DS 2 ; Total of sizes of all files
BLS: DS 1 ; Block shift factor
LINES: DS 2 ; Lines to be displayed
DIRBEG: DS 2 ; Beginning of directory area
DIREND: DS 2 ; End of directory area
; END
;
; SYSLIB Module Name: SDIR04
; Author: Richard Conn
; Part of SYSLIB3 SDIR Series
; SYSLIB Version Number: 3.0
; Module Version Number: 1.4
; Module Entry Points:
; FSIZE
; Module External References:
;
;
; INCLUDE SDIRHDR.LIB
;*
;* COMPUTE SIZE OF FILE WHOSE LAST EXTENT IS POINTED TO BY HL
;* FILE SIZE IS RETURNED IN DE IN K
;* NOTE THAT THE ROUTINE DPARAMS MUST HAVE BEEN CALLED BEFORE THIS ROUTINE
;* IS USED
;*
FSIZE:
PUSH B ; Save regs
PUSH H
PUSH PSW
LXI D,12 ; Point to extent
DAD D
MOV E,M ; Get extent #
MVI D,0
INX H ; S1
INX H ; S2 is the module number (512 k)
MOV A,M ; Get module #
ORA A ; Reset carry
RAL
RAL
RAL
RAL
RAL ; * 32 extents
ORA E
MOV E,A ; Add to e
JNC FS0 ; Check high order bit
INR D ; If carry
FS0: INX H ; Hl pts to record count field
MOV A,M ; Get record count of last extent
XCHG
DAD H ; Number of extents times 16k
DAD H
DAD H
DAD H
XCHG ; Total size of previous extents in de
LXI H,BLKMSK
ADD M ; Round last extent to block size
RRC
RRC ; Convert from records to k
RRC
ANI 1FH
MOV L,A ; Add size of last extent to total of previous
; extents
MVI H,0 ; Hl=size of last extent, de=total of previous
; extents
DAD D ; Hl=total file size in blocks
LDA BLKMSK ; Get records/blk-1
RRC
RRC ; Convert to k/blk
RRC
ANI 1FH
CMA ; Use to finish rounding
ANA L
MOV L,A ; Hl now equals the size of the file in k
; increments
XCHG ; De=file size in k
POP PSW ; Restore regs
POP H
POP B
RET
END