home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ZSYS
/
SIMTEL20
/
ZCPR3
/
DIR.MAC
< prev
next >
Wrap
Text File
|
2000-06-30
|
33KB
|
1,465 lines
;
; 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