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
/
CPM
/
ZCPR33
/
S-Z
/
SPP10.LBR
/
SPP10.AZM
/
SPP10.ASM
Wrap
Assembly Source File
|
2000-06-30
|
77KB
|
3,503 lines
; SUPER PURGE PROGRAM
; SPP
; 2 AUG 88
;
; Gene Nolan
;
;
; This program is being distributed ready
; to use on a CP/M v2.2 computer with two
; disk drives , no Z80DOS, and no ZCPR/ZCMD in use.
;
; SPP gives you the full power of SD/SDZD in specifying files to be erased.
; With one command you can erase EVERY FILE ON EVERY DRIVE/USER, so be
; carefull. If you are running Z80DOS, you can also use dates to specify
; which files to be considered for erasure.
;
; NOTE: If WHEEL is TRUE and not set, this program WILL NOT EXECUTE,
; but merely display 'SPP ?' and return to CPM.
;
; Current versions of SPP automatically adjust for any block size and di-
; rectory length under CP/M 2.2, 3.0 or MP/M. They can also handle any
; number of disk drives or skip those not available. Current features:
;
; 1) Searching individual or multiple drives and/or user areas
; 2) Unconditional or optional disk system reset before execution
; begins
; 3) Summary line output giving drive and user information, num-
; ber of files erased, how much space they consumed and free
; space remaining on the disk(s)
; 4) Selecting or suppressing "system" and R/O files
; 5) Accepting ambiguous filenames with or without a drive name
; 6) Optional help menu with '?' or '//' if ZCPR33 option TRUE
; 7) Summary line output optionally contains name of ZCPR3 named
; directory, if selected
; 8) ZCPR3 named directory may be used in command line instead
; of DU: if selected
; 9) Choose files based upon attributes 1-4
; 10) Z33 ENViorment support of wheel, maxdrv, maxusr location
; 11) Summary totals supplied as to number of files/total k erased
;
;-----------------------------------------------------------------------
;
; ASEG ; Needed for M80 and RMAC, ignore error
;
ORG 0100H
;
JMP START
;
NO EQU 0
YES EQU NOT NO ; (Some assemblers don't like 0FFh)
;
; Define version number
;
MAIN EQU 1 ; Main block number
VER EQU 00 ; Current version
MONTH EQU 08 ; Month
DAY EQU 02 ; Day
YEAR EQU 88 ; Year
;
;-----------------------------------------------------------------------
; options
;
MAXDRV EQU NO ; *Yes if MAXD byte is supported
MAXUR EQU NO ; *Yes if MAXU byte is supported
WHEEL EQU NO ; *Yes if using ZCPR wheel byte
; If using equate ZCPR33 set to YES, then the following 3 will be
; taken from the ENV descriptor automaticaly if the corresponding
; MAXDRV, MAXUR, or WHEEL equate is set YES
MXDRV EQU 3DH ; *Set to max drive address if MAXDRV=Yes
MXUSR EQU 3FH ; *Set to max user address if MAXUR=Yes
WHLOC EQU 3EH ; *Set to wheel location if WHEEL=Yes
MXZUSR EQU 15 ; Maximum user # allowed with WHEEL set
EDATE EQU NO ; No, use USA date format for version mess.
PRBRDR EQU NO ; Yes = print quasi-borders for libraries
WMBOOT EQU NO ; If warmboot is needed on exit
DB 'Z3ENV' ; For ZCPR3 Environment ID
DB 1 ; Class 1, External
Z3ENV: DW 0 ; Environment Address. If using ZCPR33
; This can be left as is.
;-------------------------------
;
; Drive/User area lookup table:
; ----------------------------
; Change the following table as appropriate for your version of CP/M.
; You can limit the maximum user area without wheel byte independently
; for any drive available. Use 0FFh for drives that are not available.
;
; CP/M v2.2 has 16 user areas, 0-15
; CP/M v3.0 has 32 user areas, 0-31
;
; NOTE: Use your editor to move the "HIDRV" line below the correct
; number of drives for your system. This not only saves time when the
; highest drive has been reached, but will display a drive/user error
; message which otherwise will not be shown.
;
LODRV EQU $ ; Mark beginning of drive/user table
DB 15 ; Maximum user area for drive A
DB 15 ; " " " " " B
HIDRV EQU $ ; Mark end of drive/user table
DB 0FFH ; " " " " " C
DB 0FFH ; " " " " " D
DB 0FFH ; " " " " " E
DB 0FFH ; " " " " " F
DB 0FFH ; " " " " " G
DB 0FFH ; " " " " " H
DB 0FFH ; " " " " " I
DB 0FFH ; " " " " " J
DB 0FFH ; " " " " " K
DB 0FFH ; " " " " " L
DB 0FFH ; " " " " " M
DB 0FFH ; " " " " " N
DB 0FFH ; " " " " " O
DB 0FFH ; " " " " " P
;
;
;-------------------------------
;
; Showing tagged attributes
; -------------------------
; Displaying files with tagged attributes ($R/O, $SYS, $ARC etc.) in an
; in an unique manner so they are easy to find, if present.
;
; Example:
; FILENAME.SyS - $SYS attribute set
; FILENAME.doC - $SYS and $R/O both set
; FILENAME.com - $SYS, $R/O and $ARC all set
;
; The following equates will permit SPP to display the files with tagged
; attributes in lower case letters (a-z) as in example above.
;
USELC EQU YES ; Allow lower case letters (a-z)
USELCW EQU YES ; *Allow lower case without wheel byte?
;
;-----------------------------------------------------------------------
;
; Reverse video options
; ---------------------
; The following equate will permit SPP to display the files with tagged
; attributes in either reverse video or bright/dim modes. This will al-
; low any character tagged to be visible, as opposed to the USELD method.
; Up to 7 bytes for enter and exit video modes are provided. These can
; be easily patched with DDT, etc.
;
REVID EQU NO ; Yes = inverse or bright/dim display
;
; The following equate will highlight/underline the summary line
;
ULINE EQU NO ; Yes = highlight/underline summary
;
;
; Reverse video control bytes
; ---------------------------
; If byte at RVON is 0, simple lower case will be used to display file
; attributes.
;
IF REVID
RVON: DB 0,0,0,0,0,0,0 ; Up to 7 characters for ENTER REVERSE
DB 0 ; String Terminator MUST BE 0
;
RVOFF: DB 0,0,0,0,0,0,0 ; Up to 7 characters for EXIT REVERSE
DB 0 ; String Terminator MUST BE 0
ENDIF ; REVID
;
; If byte at ULON is 0, no highlighting/underlining will be used in the
; banner line.
;
IF ULINE
ULON: DB 0,0,0,0,0,0,0 ; Up to 7 characters for ENTER ULINE
DB 0 ; String Terminator, MUST BE 0
;
ULOFF: DB 0,0,0,0,0,0,0 ; Up to 7 characters for EXIT ULINE
DB 0 ; String Terminator MUST BE 0
ENDIF ; ULINE
;
;-------------------------------
;
; If using Z80DOS and you want date stamping support, set the following
; to YES.
;
Z80DOS EQU NO
;
;-------------------------------
;
; If want to be able to specify files to be displayed based upon attribute
; 1 thru 4 , set the following to yes
;
FATTRIB EQU YES
;
;-------------------------------
;
; Z3CPR options
; -------------
; for ZCPR33 users - leave all set to NO if not using ZCPR3
;
ZCPR33 EQU NO ; Allow named dir's and ENV support
ZCPR3 EQU NO ; Allow named directory in command line
NDIRS EQU NO ; To display directory names
ZRDOS EQU NO ; Set to YES if using ZRDOS
Z3DRV EQU 44 ; Offset from ENV location to find drive max
Z3USR EQU 45 ; Offset from ENV location to find user max
Z3WHL EQU 41 ; Offset from ENV location to find wheel address
Z3NDR EQU 21 ; Offset from ENV location to find NDIR address
;
; end of options
;-----------------------------------------------------------------------
;
; Reference items
; ---------------
RECORD EQU 36
FRN EQU 33
FCR EQU 32
READRN EQU 33
HDRSIZ EQU 27
ARCMAR EQU 26
TMPLT0 EQU $ ; Start of initialization template
DB 'A' ; All-users option flag
DB 'D' ; Multi-disk option flag
DB 'H' ; Show areas from current to highest
DB 'N' ; No page-pause option flag
DB 'O' ; To show $SYS files only
DB 'Q' ; To show only non-$ARC files
DB 'R' ; Optional reset of disk system
DB 'S' ; Include $SYS files
DB 'T' ; Primary sort by file type
DB 'V' ; Show SD version
DB 'L' ; Include $R/O files
IF Z80DOS
DB '=' ; Look for exact match of date given
DB '+' ; Look for files of date GE date given
DB '-' ; Look for files of date LT date given
DB '!' ; Match with creation date
DB '%' ; Match with alteration date
DB '@' ; Match with access date
DB 'Z' ; Do not show dates
ENDIF ;Z80DOS
IF FATTRIB ; Allow spec of file attributes 1-4?
DB '1' ; Only files with attrib 1
DB '2' ; Only files woth attrib 2
DB '3' ; Only files with attrib 3
DB '4' ; Only files with attrib 4
ENDIF ;FATTRIB
;
; End of option lookup table
;
DW OUTBUF ; Next location in output buffer
DB 128 ; # of bytes left in output buffer
DB 0,'DISK DIR' ; Output Filename.typ
;
TMPLT1 EQU $ ; End of initialization data template
VERNAME:DB 13,10,'SPP',MAIN+'0'
DB VER/10+'0',VER MOD 10+'0',' -- '
IF NOT EDATE
DB MONTH/10+'0',MONTH MOD 10+'0','/'
ENDIF ; NOT EDATE
DB DAY/10+'0',DAY MOD 10+'0','/'
IF EDATE
DB MONTH/10+'0',MONTH MOD 10+'0','/'
ENDIF ; EDATE
DB YEAR/10+'0',YEAR MOD 10+'0'
IF Z80DOS
DB ', Z80DOS'
ENDIF
IF ZCPR3 ;
DB ', ZCPR3 Version'
ENDIF ; ZCPR3
IF ZCPR33 ;
DB ', ZCPR33 Version'
ENDIF ; ZCPR33
DB 0
;
;-----------------------------------------------------------------------
; Program starts here
;-----------------------------------------------------------------------
;
START: LXI H,0
DAD SP ; HL=old stack
SHLD STACK ; Save it
LXI SP,STACK ; Get new stack
IF ZCPR33
LHLD Z3ENV ; Get ENV address
PUSH H
LXI D,Z3DRV ; Point to max drv byte
DAD D
SHLD Z3DRVL ; Save location away
POP H
PUSH H
LXI D,Z3USR ; Point to maxuser byte
DAD D
SHLD Z3USRL ; Save location away
POP H
PUSH H
LXI D,Z3WHL ; Point to address pointer of wheel
DAD D
MOV E,M ; Get address of wheel byte
INX H
MOV D,M
XCHG
SHLD Z3WHLL ; Save it away
POP H
ENDIF ; ZCPR33
IF NDIRS
LHLD Z3ENV ; Get Environment Address
LXI D,Z3NDR ; Point to named directory space
DAD D
MOV E,M
INX H
MOV D,M ; DE Now contains NDR Address
INX H
MOV A,M
ADI 1
STA NUMDIR ; Maximum number of entries plus 1
XCHG
SHLD NAMADR ; Keep Address for later
ENDIF ; NDIRS
IF WHEEL
XRA A ; Start at line 0
STA LINCNT
INR A
STA NOPFLG ; And assume verify in case of error or
; help wanted
IF ZCPR33
LHLD Z3WHLL ; Get Z33 wheel location
MOV A,M ; Get the wheel
ENDIF ; ZCPR33
IF NOT ZCPR33
LDA WHLOC ; Get the wheel
ENDIF ; NOT ZCPR33
ORA A
JNZ WHLOK ; NZ=wheel set, continue
LXI D,WHLERR
CALL PUTS
JMP EXIT3
WHLOK:
ENDIF ; WHEEL
;
; See if help is wanted
;
LXI H,FCB+1 ; Filename
MOV A,M ; 1st Character
IF NOT ZCPR33
CPI '?' ; Is it "?"
JNZ INIT ; No, Continue
INX H ; Yes, Next Char
MOV A,M ; 2nd Character
CPI ' ' ; Is it " "
JNZ INIT ; If not, did not want help guide
LDA FCB+9 ; Check for any extent
CPI ' '
JZ HELPME ; If none, wanted help
ENDIF ; NOT ZCPR33
IF ZCPR33
CPI '?' ; Is it "?"
JNZ CHKSLH ; No, Continue
INX H ; Yes, Next Char
MOV A,M ; 2nd Character
CPI ' ' ; Is it " "
JNZ INIT ; If not, did not want help guide
LDA FCB+9 ; Check for any extent
CPI ' '
JZ HELPME ; If none, wanted help
JMP INIT
CHKSLH: CPI '/' ; Is it a slash?
JNZ INIT
INX H
MOV A,M ; two slashes gets help
CPI '/'
JZ HELPME
ENDIF ; ZCPR33
;
; Zero out the entire initialization data area
;
INIT: LXI H,DATA0 ; Point to start of initialized data area
PUSH H ; Save for non-zero filling later
MVI C,DATA1-DATA0 ; Data area length
XRA A ; Clear the "A" register
ZFILL: MOV M,A ; Null the address
INX H ; Pointer+1
DCR C ; One less to go
JNZ ZFILL
;
; Now copy non-zero initialization data from the template area
;
POP H ; Load A(DATA0)
LXI D,TMPLT0 ; Load A(TMPLT0)
MVI C,TMPLT1-TMPLT0 ; Template area length
NZFILL: LDAX D ; Load template byte
MOV M,A ; Move to data area
INX D ; Next location to store data
INX H ; Next location to get data
DCR C ; One less to go
JNZ NZFILL
LXI H,0 ; Clear HL
IF ZRDOS
MVI C,ZRDVER ; Get ZRDOS version
CALL BDOS
MOV A,L ; ZRDOS Version #
STA ZRDFLG ; Save it
ENDIF ; ZRDOS
MVI C,CPMVER ; Get CP/M version
CALL BDOS
MOV A,L ; CP/M Version number
STA VERFLG ; Save it
STA SOHFLG ; Prevents initial unwanted CRLF
CPI 20H ; Set carry if CP/M 1.4
PUSH PSW ; Save for BYE test
MVI E,0FFH ; Load current user number if CP/M 2
MVI C,STUSER ; Fall through with A=0 if not
CNC CPM ; Only if CP/M 2.0 or ZRDOS
STA OLDUSR ; Initial user number
STA NEWUSR ; New user = Initial user
STA BASUSR ; Directories
POP PSW ; Recover Version Flag
IF ZCPR3 OR ZCPR33
LDA FCB+13 ; Point to command line buffer (CLB)
STA NEWUSR
ENDIF ; ZCPR3
IF NOT ZCPR3 AND NOT ZCPR33
LXI H,TBUF+1 ; Point to command line buffer (CLB)
MOV A,M ; CLB Character
CPI '[' ; CP/M 3.0 style delimiter
JZ CLOK ; (may follow command in CP/M 3.0)
INX H ; CLB pointer +1
ORA A ; Terminator?
JNZ CLOK ; No, continue
MOV M,A ; Yes, set 2nd terminator
CLOK: LXI D,FCB ; A(file control block)
CALL FNAME ; Process filename.typ
MOV A,B ; Disk specification
CPI 0FFH ; Current?
JZ CLUS ; Yes
STAX D ; No, set disk specification
CLUS: MOV A,C ; User specification
CPI 0FFH ; Current?
JZ CLNON ; Yes
STA NEWUSR ; No, set user specification
STA BASUSR
ENDIF ; NOT ZCPR3 AND NOT ZCPR33
CLNON: MVI C,CURDSK
CALL CPM ; Load current disk number
STA OLDDSK ; Save for reset if needed
INR A ; Adjust
STA OUTFCB ; Save directory file drive
LXI H,FCB ; A(file control block)
MOV A,M ; Load directory search drive
ORA A ; Any specified?
JNZ START1 ; Yes, skip next routine
LDA OLDDSK ; Otherwise, get default disk
INR A ; Adjust
JMP START2
START1: PUSH PSW ; Save status
MVI A,1
STA DRVFLG ; Set DRVFLG = 1
POP PSW ; Load status
START2: MOV M,A ; Absolute drive code in directory FCB
;
; If at least one option is allowed, scan command line for the option
; field delimiter. The option field delimiter is considered valid only
; if it is preceded by at least 1 space (otherwise may be part of the
; directory filename). Any unrecognized options/illegal user numbers
; will be flagged.(We scan the command line buffer rather than the 2nd
; default FCB because all 8 options + 2 digit user number will not fit
; in the 2nd FCB name field).
;
LXI H,TBUF ; CLB pointer
MOV B,M ; CLB length
;
; Search for valid command line delimiter, if not found, assume no
; options. Show help menu if single "?" entered.
;
SCNDOL: INX H ; CLB PTR+1
DCR B ; CLB LEN-1
JM DOPTN ; Exit if command line buffer empty
MOV A,M ; CLB Character
CPI '[' ; CPM+ style delimiter?
JZ OPTDLM ; Yes
CPI '$' ; CPM2 style delimiter?
JZ SPB4 ; Yes
CPI '/' ; ZCPR style delimiter?
JNZ SCNDOL ; No
SPB4: DCX H ; '$' found, space must precede
MOV A,M ; Previous character
INX H
CPI ' '
JNZ SCNDOL ; No space, ignore '$'
;
; Valid delimiter found. Scan the rest of the buffer for options.
; Errors past this point cause an abort.
;
OPTDLM: XCHG ; DE = CLB pointer (swap pointers)
SCNOPT: INX D ; CLB PRT+1
DCR B ; CLB LEN-1
JM DOPTN ; If option field exhausted, exit
SCNAGN: LDAX D ; Load option character
CPI ' ' ; Is it " "?
IF Z80DOS
JZ LOKDAT ; Space, go look for date info
ENDIF ;Z80DOS
IF NOT Z80DOS
JZ SCNOPT ; Yes, Ignore it
ENDIF ;NOT Z80DOS
CPI ']' ; CPM+ style terminator?
JZ SCNOPT ; Options may follow terminator
LXI H,OTBL-1 ; OTBL pointer
MVI C,OEND-OTBL+1 ; OTLB length
NOMACH: INX H ; OTLB pointer+1
DCR C ; OTLB length-1
JZ CLERR ; Error if option table end
CMP M ; Compare with table entry
JNZ NOMACH ; If no match, check next
MVI M,0 ; Else, activate the option
JMP SCNOPT ; Continue scan
;.....
;
; Playback the command line up to the character that stopped the scan
; and exit
;
CLERR: XRA A ; Clear "A" register
INX D ; Tag end of CLB
STAX D ; With terminator
CALL CRLF ; New line
LXI D,ERRMS2 ; 'Error'
CALL PUTS
LXI D,ERRTAG ; '->'
CALL PUTS
LXI H,TBUF+1 ; Playback CLB to error point
CLELP: MOV A,M ; Character
ORA A ; Zero?
JZ CLEX ; Yes, exit
CALL PUTCHR ; No, output to console
INX H ; CLB pointer+1
JMP CLELP ; Continue
CLEX: MVI A,'?' ; Tag line with a '?' field
CALL PUTCHR
CALL CRLF ; New Line
;;;;; JMP 0000H ; And reset CCP, all finished
JMP EXIT2
IF Z80DOS
LOKDAT: INX D
LDAX D ; Check to see if * was entered meaning
CPI '*' ; use current system time
JNZ LOKDAT1 ; NZ=no
PUSH D ; Save pointer to input line
LXI D,ASCII ; Tell Z80DOS to put time here
MVI C,105
CALL 5 ; Go get the time
LXI D,ASCII
LDAX D ; Get LSB of JDAY
MOV L,A
INX D
LDAX D ; Get MSB of JDAY
MOV H,A
POP D ; Get input pointer back
INX D ; Point ot next
LDAX D
CPI '-' ; Does operator want a subtraction?
JNZ LOKDAT2 ; NZ=no
PUSH H
INX D
CALL EVAL10 ; Yes go get number
MOV E,A
XRA A
MOV D,A
MOV A,L
SBB E
MOV L,A
MOV A,H
SBB D
MOV H,A
JMP LOKDAT2 ; And continue
LOKDAT1:
call eval10 ; convert month to binary
ORA A ; month can't be 0
JZ BADDATE
CPI 13 ; can't be >12
JNC BADDATE
STA MONTHS ; store month
LDAX D ; End of input line?
ORA A
JZ BADDATE ; Z=yes, a no-no
INX D ; Skip /
call eval10 ; convert
ORA A ; day can't be 0
JZ BADDATE
CPI 32 ; or >31
JNC BADDATE
STA DAYS1 ; store day
LDAX D ; End of input line?
ORA A
JZ BADDATE ; Z=yes, a no-no
INX D ; Skip /
call eval10
STA YEARS1 ; store year
LXI H,YEARS1 ; pt at date
call bin2jul ; get jul date in hl
LOKDAT2:
SHLD DATCHK
JMP DOPTN
EVAL10:
XRA A
MOV B,A ; B holds current number input
EVAL1: LDAX D ; Get input
CPI '/' ; / is seperator
JZ DEVAL10 ; Z= done
ORA A
JZ DEVAL10 ; Z= at end of line
SUI '0' ; Verify ascii 0-9
JC BADDATE
CPI 10
JNC BADDATE
INX D
MOV C,A ; Old*10+new
MOV A,B
ADD A
ADD A
ADD B
ADD A
ADD C
MOV B,A ; B has current
JMP EVAL1
DEVAL10:
MOV A,B
RET
BADDATE:
PUSH D
LXI D,BDTMES
CALL PUTS
POP D
JMP CLERR
BDTMES:
DB 13,10,13,10
DB ' *** Illegal Date Entered, form MM/DD/YY or MM/D/YY or M/DD/YY'
DB 13,10,13,10,0
;
; Binary to Julian Date routine.
;
; >> hl -> yr,mo,da in bin
; << hl = Julian date
;
; Convert to 8080 code from the original
; BCD2JUL
; by Bridger Mitchel and Howard Goldstein - 4/16/88
;
BIN2JUL:
PUSH PSW
PUSH B
PUSH D
MOV A,M ; A=yr
INX H
MOV C,M ;c = mo
INX H
PUSH H ;save ptr to day
PUSH PSW ;save year
;
; set hl= initial julian value of 77/12/31
;
LXI H,0
SUI 78
JZ B2JUL3
JNC B2JUL0
ADI 100 ;<78, assume next century
B2JUL0: MOV B,A ;b = # yrs > 78
MVI A,1 ;init modulo 4 counter
LXI D,365 ;days/yr
B2JUL1: DAD D ;calc julian val. of (yr/01/01 - 1)
INR A
ANI 3 ;every 4 yrs,
JNZ B2JUL2
INX H ;..add 1 for leap year
B2JUL2: DCR B
JNZ B2JUL1
;
; hl now = # days in years before current year
;
B2JUL3: POP PSW
ANI 3 ;if current yr == leap year
JNZ B2JUL5
MOV A,C
CPI 3 ;..and mo >= march
JC B2JUL5
INX H ;..add the extra day (Feb 29)
;
B2JUL5: MOV B,C ; b = month = # months +1 to sum
LXI D,DPERMO ;point at table
JMP B2JUL7
;
B2JUL6: CALL ADDHL ;add # days in this month
INX D ;bump tbl ptr
B2JUL7: DCR B
JNZ B2JUL6
;
POP D ;ptr to day
CALL ADDHL
POP D
POP B
POP PSW
RET
ADDHL: LDAX D ;add day of current month
;
ADDA2HL:
ADD L
MOV L,A
RNC
INR H
RET
;
; table of days per month (non-leap year)
;
DPERMO: DB 31 ;jan
DB 28 ;feb
DB 31 ;mar
DB 30 ;apr
DB 31 ;may
DB 30 ;jun
DB 31 ;jul
DB 31 ;aug
DB 30 ;sep
DB 31 ;oct
DB 30 ;nov
DB 31 ;dec
ENDIF ;Z80DOS
;.....
;
; Options input or not specified, and associated flags set.
;
; If D-option, swap error vectors, then start at drive A if no
; drive specified on command line.
;
DOPTN: LDA DOPFLG ; If multi-disk flag set,
ORA A ; Need to set error traps
JNZ AOPTN ; If not, go check A-option
CALL SWAPEM ; Swap BDOS error vector tables
LDA DRVFLG ; Directory drive specified?
ORA A
JNZ AOPTN ; No, don't reset
MVI A,1 ; Yes, Set FCB to A:
STA FCB
;
; Start user at 0 if A-option selected without U-option
;
AOPTN: LDA AOPFLG ; Check All-users option
ORA A
JNZ COPTN ; Jump if not
LDA HOPFLG ; Asking to show all from current?
ORA A
JZ COPTN ; If yes, do not reset "A" to zero
XRA A ; No, Start at user 0
STA NEWUSR
STA BASUSR
COPTN:
MVI A,'k'
COPTN1: STA FSIZEC ; Indicator char after size
;
; The following optionally resets the disk system. The reset must
; be done OUTSIDE of the multiple drive loop if the $F option is
; enabled because CP/M 1.4 will clobber the DMA buffer on reset.
;
LDA ROPFLG ; Reset Disk?
ORA A
JNZ NOOPT
;
; Disk reset if R option entered on command line
;
MVI C,RESET
CALL CPM
;
; Validate drive code and user area numbers from the drive table
;
NOOPT: LXI D,DRUMSG ; Get drive/user error message
PUSH D
LDA FCB ; Get directory drive code
DCR A ; Normalize to range of 0-31
CPI HIDRV-LODRV ; Compare with max drives on-line
JNC ERXIT ; Drive error exit if out of range
IF MAXDRV ; Look for MXDRV
IF ZCPR33
LHLD Z3DRVL ; Point to ENV as loaded
ENDIF ;ZCPR33
IF NOT ZCPR33
LXI H,MXDRV ; A(MXDRV) to HL
ENDIF ;NOT ZCPR33
MOV L,M ; (MXDRV) to L
ENDIF ; MAXDRV
IF MAXDRV
IF NOT ZCPR33
INX H ; +1
ENDIF ; NOT ZCPR33
CMP L ; Check it
JNC ERXIT ; Oops if not bigger
ENDIF ; MAXDRV
;
; Skips any drives marked 0FFh, some computers do not have contiguous
; drives, such as Heath H89, etc.
;
MOV E,A ; Drive code = table index
MVI D,0
LXI H,LODRV ; DUTBL Pointer
DAD D ; DUTBL Pointer+INDEX
MOV A,M ; User Number
ORA A ; Set Status
JM NDSK ; If negative, ignore drive
IF WHEEL
IF ZCPR33
PUSH H
LHLD Z3WHLL ; Point to enviorment
MOV A,M ; Get it
POP H
ENDIF ;ZCPR33
IF NOT ZCPR33
LDA WHLOC ; Get wheel byte
ENDIF ;NOT ZCPR33
ORA A ; Check it
JZ USRCK ; If reset, restrict user
MVI A,MXZUSR ; If set, max user = MXZUSR
JMP USRCK1
ENDIF ; WHEEL
USRCK: LXI H,LODRV ; DUTBL PTR
DAD D ; DUTLB PTR+INDEX
MOV A,M ; Load max user for this drive
IF MAXUR ; Use low memory values if smaller
MOV H,A ; Current value of MAXUSR
IF ZCPR33
PUSH H
LHLD Z3USRL ; Point to ENV
MOV A,M ; Get user
POP H
ENDIF ;ZCPR33
IF NOT ZCPR33
LDA MXUSR ; Alternate value
ENDIF ;NOT ZCPR33
ENDIF ; MAXUR
IF ( MAXUR AND NOT ZCPR3 ) AND NOT ZCPR33
SBI 1 ; MAXUSR is really maximum user+1
ENDIF ; MAXUR AND NOT ZCPR3 AND NOT ZCPR33
IF MAXUR
CMP H ; Compare the two
JNC USRCK1 ; OK if MAXU <= table value
STA MAXUSR ; Else replace it
ENDIF ; MAXUR
USRCK1: MOV B,A ; Save max user for later testing
ANI 1FH ; Insure in range 0-31
STA MAXUSR ; Save it for later
LXI H,NEWUSR ; Point to directory user area
CMP M ; Compare with the maximum
JC ERXIT ; User number illegal, error exit
POP D ; Destroy error message pointer
MOV A,B ; Check to see if this drive
ORA A ; Has been mapped out
JM NDSK ; Yes, skip this drive
LXI H,FCB+1 ; No, point to name
MOV A,M ; Any name specified?
CPI '$' ; Delimiter?
JZ WCD ; Yes, All files
CPI '/' ; Unix/ZCPR3 delimiter?
JZ WCD ; Yes, All files
CPI '[' ; CP/M+ delimiter?
JZ WCD
CPI ' ' ; No, Filename specified
JNZ GOTFCB
;
; No FCB - make FCB all '?'
;
WCD: MVI B,11 ; Filename+typ length
QLOOP: MVI M,'?' ; Store "?" in FCB
INX H ; FCB pointer+1
DCR B ; FCB length-1
JNZ QLOOP ; Continue
GOTFCB: MVI A,'?' ; Force wild extent
STA FCB+12
CALL SETSRC ; Set DMA for BDOS media change check
LXI H,FCB ; Point to FCB drive code for directory
MOV E,M ; Load drive code from FCB
DCR E ; Normalize drive code for select
MVI C,SELDSK ; Select directory drive to retrieve
CALL CPM ; The proper allocation vector
CALL CKVER ; Check version
JC V14 ; Pre-2.x...get parameters the 1.4 way
MVI C,DSKPAR ; If 2.2 or MP/M...request DPB
CALL BDOS
INX H
INX H
MOV A,M ; Load block shift
STA BLKSHF ; Block Shift
INX H ; Bump to block mask
MOV A,M ; Load block mask
STA BLKMSK ; Block Mask
INX H
INX H
MOV E,M ; Get maximum block #
INX H
MOV D,M
XCHG
SHLD BLKMAX ; Maximum Block #
XCHG
INX H
MOV E,M ; Load directory size
INX H
MOV D,M
XCHG
JMP FREE
V14: LHLD BDOS+1 ; Get parameters 1.4 style
MVI L,3BH ; Point to directory size
MOV E,M ; Get it
MVI D,0 ; Force high order to 0
PUSH D ; Save for later
INX H ; Point to block shift
MOV A,M ; Fetch
STA BLKSHF ; Save
INX H ; Point to block mask
MOV A,M ; Fetch it
STA BLKMSK ; And save it
INX H
MOV E,M ; Get maximum block #
MVI D,0
XCHG
SHLD BLKMAX ; Save it
POP H ; Restore directory size
JMP FREE20 ; Calculate free space from alloc vector
;
; Calculate number of K free on selected drive now so the FREE figure
; will not reflect either creation or additions to the DISK.DIR file.
; Note: This routine will not always function correctly as coded. To
; insure the proper calculation when the $F option is specified and
; cataloging multiple disks on a single drive, you should do a CTL-C
; AFTER the disk to be cataloged has been readied.
;
FREE: SHLD DIRMAX ; Save max number of directory entries
LDA VERFLG ; Check version number
CPI 30H ; CP/M 3.0?
JC FREE20 ; No, Use old method
LDA FCB ; Load drive number
DCR A ; Normalize
MOV E,A ; Use compute free space BDOS call
MVI C,46 ; Calculate free space
CALL CPM
MVI C,3 ; Answer is a 24-bit integer
FRE3L1: LXI H,TBUF+2 ; Answer in 1st 3 bytes of TBUF
MVI B,3 ; Convert from records to k
ORA A ; By dividing by 8
FRE3L2: MOV A,M ; LS byte record count
RAR ; /2
MOV M,A ; Replace
DCX H ; Next byte record count
DCR B ;
JNZ FRE3L2 ; Loop for 3 bytes
DCR C
JNZ FRE3L1 ; Shift 3 times
LHLD TBUF ; Now get result in k
JMP SAVFRE ; Save Free Space
FREE20: MVI C,DSKALL ; Allocation vector address
CALL BDOS
XCHG
LHLD BLKMAX ; Max Block Number
INX H
LXI B,0 ; Init block count = 0
GSPBYT: PUSH D ; Save allocation address
LDAX D
MVI E,8 ; Set to process 8 blocks
GSPLUP: RAL ; Test bit
JC NOTFRE
INX B
NOTFRE: MOV D,A ; Save bits
DCX H ; Count down blocks
MOV A,L
ORA H
JZ ENDALC ; Quit if out of blocks
MOV A,D ; Restore bits
DCR E ; Count down 8 bits
JNZ GSPLUP ; Do another bit
POP D ; Bump to next byte of allocation vector
INX D
JMP GSPBYT ; Process it
ENDALC: POP D ; Clear stack of allocation vector pointer
MOV L,C ; Copy blocks to HL
MOV H,B
LDA BLKSHF ; Load block shift factor
SUI 3 ; Convert from records to k
JZ SAVFRE ; Skip shifts if 1k blocks return free in HL
FREKLP: DAD H ; Multiply blocks by k/block
DCR A
JNZ FREKLP
;
SAVFRE: SHLD FREEBY ; Save free space for output later
XCHG
LHLD TOTFRE
DAD D
SHLD TOTFRE
;
; Reenter here on subsequent passes while in the all-users mode
;
SETTBL: LHLD DIRMAX ; Load directory maximum size
INX H ; Directory size is DIRMAX+1
DAD H ; Double directory size
LXI D,ORDER ; Too get order table size
DAD D ; Allocate order table
SHLD TBLOC ; Name tbl begins where order tbl ends
SHLD NEXTT
XCHG
LHLD BDOS+1 ; Insure we have room to continue
MOV A,E
SUB L
MOV A,D
SBB H
JNC OUTMEM
CALL CKVER ; Set carry if pre-CP/M 2
LDA NEWUSR ; Load directory user area
MOV E,A
MVI C,STUSER ; Get the user function
CNC CPM ; Set new user number if CP/M 2
;
; Look up the FCB in the directory
;
MVI A,'?' ; Check for wild FCB extent
LXI H,FCB+12
MOV M,A ; Match all extents
INX H
MOV M,A ; Match all S1 bytes
INX H
MOV M,A ; Match all S2 bytes
LXI H,0
SHLD COUNT ; Initialize match counter
SHLD TOTFIL ; " total file counter
SHLD TOTSIZ ; " total size counter
CALL SETSRC ; Set DMA for directory search
MVI C,SRCHF ; Load 'search first' function
JMP LOOK ; Go search for 1st match
;
; Read more directory entries
;
MORDIR: MVI C,SRCHN ; Search next function
LOOK: LXI D,FCB ; A(file control block)
CALL CPM ; Read directory entry
INR A ; End (0FFH)?
JZ SPRINT ; Yes, sort & print what we have
;
; Point to directory entry
;
DCR A ; Undo previous INR A
ANI 3 ; Make modulus 4
ADD A ; Multiply
ADD A ; By 32 because
ADD A ; Each directory
ADD A ; Entry is 32
ADD A ; Bytes long
LXI H,TBUF+1 ; Point to buffer (skip to FN/FT)
ADD L ; Point to entry
IF FATTRIB
MOV L,A ; HL now point to file name
LDA ONEFLG ; Looking for only attribute 1?
ORA A
JNZ NOTONE ; NZ=no
MOV A,M
ORA A
JP MORDIR ; P=not attr 1
NOTONE: INX H
LDA TWOFLG ; Only attribute 2?
ORA A
JNZ NOTTWO ; NZ=no
MOV A,M
ORA A
JP MORDIR ; P=not attr 2
NOTTWO: INX H
LDA THRFLG ; Only attrib 3?
ORA A
JNZ NOTTHR ; NZ=no
MOV A,M
ORA A
JP MORDIR ; P= not attr 3
NOTTHR: INX H
LDA FORFLG ; Only attr 4?
ORA A
JNZ NOTFOR ; NZ=no
MOV A,M
ORA A
JP MORDIR ; P= not attr 4
NOTFOR: MOV A,L
ADI 5 ; POINT TO R/O BYTE
ENDIF ; FATTRIB
IF NOT FATTRIB
ADI 8 ; Point to R/O BYTE
ENDIF ; NOT FATTRIB
MOV L,A
LDA LOPFLG ; Should we allow R/O files?
ORA A
JZ QSYS ; Z=yes
MOV A,M ; Check for R/O
ORA A
JM MORDIR ; M=yes, ignore this file
QSYS: INX H
LDA QOPFLG ; Find only non-$ARC files?
ORA A
JNZ OSYS ; No, check for only $SYS files
INX H ; Yes, get the archive byte
MOV A,M
DCX H
ORA A ; Check bit 7 for $ARC file
JM MORDIR ; If set, ignore this filename
OSYS: LDA OOPFLG ; Find only $SYS files?
ORA A
JNZ CKSYS
MOV A,M ; Yes, get system byte
ORA A ; Check bit 7 for $SYS file
JP MORDIR ; If not set, ignore this filename
JMP SYSFOK ; Else check for a match
CKSYS: LDA SOPFLG ; Did user request $SYS files?
ORA A
JZ SYSFOK ; If yes, exit
MOV A,M ; Get system byte back
ORA A ; Check bit 7 for $SYS file
JM MORDIR ; Skip that file
SYSFOK: MOV A,L ; Go back now
SUI 10 ; Back to user number (allocation flag)
MOV L,A ; HL points to entry now
LDA NEWUSR ; Get current user
CMP M
JNZ MORDIR ; Ignore if different
INX H
IF Z80DOS
PUSH B ;
PUSH D ;
PUSH H ;
MVI C,54 ; Get time stamp from last search
CALL BDOS ;
LXI D,6 ; Point to last access field
LDA DGOPFL
ORA A
JZ ACCESS ; Z=what is wanted
LXI D,2 ; Point to last alteration field
LDA DAOPFL
ORA A
JZ ACCESS ; Z=what is wanted
LXI D,0 ; Point to creation field
LDA DNOPFL
ORA A
JZ ACCESS ; Z=what is wanted
LXI D,2 ; Didn't say, so give him alteration date
ACCESS: DAD D ; Point to right field in returned database
MOV E,M ; Get the date in Julian
INX H
MOV D,M
XCHG
SHLD DATMOD
;
POP H
POP D
POP B
ENDIF ;Z80DOS
;
; Move entry to table
;
XCHG ; Entry to DE
LHLD NEXTT ; Next table entry to HL
MVI B,11 ; Entry length (name, type, extent)
TMOVE: LDAX D ; Get entry character
IF NOT (USELC OR REVID)
ANI 7FH ; Remove attributes
ENDIF ; NOT (USELC OR REVID)
MOV M,A ; Store in table
INX D
INX H
DCR B ; More?
JNZ TMOVE
INX D ; DE->> S1
INX D ; DE->> S2
LDAX D ; Get S2 byte, oflo=int(extents/32)
PUSH H ; Save HL
MOV L,A ; Set up 16-bit multiply
MVI H,0
MVI B,5
CALL SHLL ; HL is now # of oflo extents
DCX D ; DE->> S1
DCX D ; DE->> extent
LDAX D ; Get extent
ADD L
MOV L,A
MOV A,H
ACI 0
MOV H,A ; HL has total extents
MVI B,7
CALL SHLL ; HL has total records less last ext
INX D ; DE->> S1
INX D ; DE->> S2
INX D ; Point to sector count
LDAX D ; Get it
ADD L
MOV L,A
MOV A,H
ACI 0
MOV H,A ; HL has total records
XTHL ; Do some fancy shuffling
XCHG
XTHL
XCHG
MOV M,D
INX H
MOV M,E
POP D ; All back to normal
INX H
IF Z80DOS
LDA DATMOD ; Get LSB of last modified date
MOV M,A ;
INX H ;
LDA DATMOD+1 ; Get MSB of last modified date
MOV M,A ;
INX H ;
ENDIF ;Z80DOS
SHLD NEXTT ; Save updated table address
XCHG
LHLD COUNT ; Bump the # of matches made
INX H
SHLD COUNT
IF Z80DOS
LXI H,15 ; Size of entry include date
ENDIF ;Z80DOS
IF NOT Z80DOS
LXI H,13 ; Size of next entry
ENDIF ;NOT Z80DOS
DAD D
XCHG ; Future NEXTT is in DE
LHLD BDOS+1 ; Pick up TPA end
MOV A,E
SUB L ; Compare NEXTT-TPA end
MOV A,D
SBB H
JC MORDIR ; If TPA end > NEXTT, loop back for more
OUTMEM: CALL ERXIT ; Exit if directory too large
DB 'Memory',0
;
; Shift HL left by B bits
;
SHLL: DAD H
DCR B
RZ
JMP SHLL
;
; Sort and print
;
SPRINT: CALL SETFOP ; Return to file output DMA & user #
LHLD COUNT ; Get file name count
MOV A,L
ORA H ; Any found?
JZ PRTOTL ; Exit if no files found
PUSH H ; Save file count
STA SUPSPC ; Enable leading zero suppression
;
; Initialize the order table
;
LHLD TBLOC ; Get start of name table
XCHG ; Into DE
LXI H,ORDER ; Point to order table
IF Z80DOS
LXI B,15 ; Entry length including date
ENDIF ;Z80DOS
IF NOT Z80DOS
LXI B,13 ; Entry length
ENDIF ;NOT Z80DOS
BLDORD: MOV M,E ; Save low order address
INX H
MOV M,D ; Save high order address
INX H
XCHG ; Table address to HL
DAD B ; Point to next entry
XCHG
XTHL ; Save table address, load loop counter
DCX H ; Count down loop
MOV A,L
ORA H ; More?
XTHL ; Load table address, save loop counter
JNZ BLDORD ; Yes, go do another one
POP H ; Clean loop counter off stack
LHLD COUNT ; Get count
SHLD SCOUNT ; Save as # to sort
DCX H ; Only 1 entry?
MOV A,L
ORA H
JZ DONE ; Yes, so skip sort
;
; This sort routine is adapted from SOFTWARE TOOLS
;
LHLD SCOUNT ; Number of entries
L1: ORA A ; Clear carry
MOV A,H ; GAP=GAP/2
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
ORA H ; Is it zero?
JZ DONE ; Then none left
MOV A,L ; Make gap odd
ORI 1
MOV L,A
SHLD GAP
INX H ; I=GAP+1
L2: SHLD I
XCHG
LHLD GAP
MOV A,E ; J=I-GAP
SUB L
MOV L,A
MOV A,D
SBB H
MOV H,A
L3: SHLD J
XCHG
LHLD GAP ; JG=J+GAP
DAD D
SHLD JG
CALL COMPARE ; Compare (J) and (JG)
JP L4 ; If A(J)<=A(JG)
LHLD J
XCHG
LHLD JG
CALL SWAP ; Exchange a(J) and a(JG)
LHLD J ; J=J-GAP
XCHG
LHLD GAP
MOV A,E
SUB L
MOV L,A
MOV A,D
SBB H
MOV H,A
JM L4 ; If J>0 go to l3
ORA L ; Check for zero
JZ L4
JMP L3
L4: LHLD SCOUNT ; For later
XCHG
LHLD I ; I=I+1
INX H
MOV A,E ; If I<=n go to l2
SUB L
MOV A,D
SBB H
JP L2
LHLD GAP
JMP L1
;
; Sort is all done - print entries
;
DONE:
NOOUT: LDA FIRSTT ; First time through?
ORA A
JNZ NOVOPT ; No, we've been here before
MVI A,0FFH ; Yes,
STA FIRSTT ; Set first time flag
LDA VOPFLG ; Version display flag
ORA A ; Set?
JNZ NOVOPT ; No, skip version print
LXI D,VERNAME ; Yes, print version
CALL PUTS ; Print the string
CALL CRLF
NOVOPT: LHLD COUNT
LXI H,ORDER ; Initialize order table pointer
SHLD NEXTT
LHLD COUNT ; Code computes end of name table
CALL MULT13 ; (or start of second table
XCHG ; Where files to be stored after
LHLD TBLOC ; Redundant extents removed)
DAD D
SHLD NEWPTR ; Save it twice
SHLD XPOINT ; For later
;
; Output the directory files we've matched
;
ENTRY: LHLD COUNT ; Files matched count
DCX H ; Count-1
SHLD COUNT
MOV A,H ; Is this the last file?
ORA L
JZ OKPRNT ; Yes, last file so skip compare
;
; Compare each entry to make sure that it isn't part of a multiple
; extent file. Go only when we have the last extent of the file.
;
PUSH B ; Save number of columns
LHLD NEXTT
MVI A,11
CALL COMPR ; Does this entry match next one?
POP B ; Restore number of columns
JNZ OKPRNT ; No, print it
NOKPRN: INX H
INX H ; Skip, highest extent last in list
SHLD NEXTT
JMP ENTRY ; Loop back for next lowest extent
;
; OKPRINT moves unique filenames and sizes in "k" to a second table
; above the first for use later.
;
OKPRNT:
;
IF Z80DOS
PUSH H
PUSH D
PUSH B
LHLD NEXTT ; Get order table pointer
MOV E,M ; Get low order address
INX H
MOV D,M ; Get high order address
LXI H,13
DAD D
; XCHG
MOV E,M
INX H
MOV D,M
LHLD DATCHK ; Get the date we are looking for
MOV A,H
ORA L
JZ GDTMTC ; Z=not looking
MOV A,H
CMP D ; Check if given date >,=,< the files date
JZ CHDLOW ; High EQ, check low
JC DATLT ; C=LT
JMP DATGE ; Given date GT file date
CHDLOW: MOV A,L ; Check low byte of date vs. file date
CMP E
DATGE: MVI A,0 ; Assume EQ
JC DATLT ; C= given LT files date
JZ DATFLG ; Z= they are EQ
MVI A,2 ; Given GT files date
JMP DATFLG
DATLT: MVI A,1 ; Given was less than files
DATFLG: STA DTMTCH
LDA DEOPFL ; What kind of date match?
ORA A
JZ DTEXAC ; Z=exact
LDA DPOPFL
ORA A
JZ DTABVE ; Z=GE
LDA DMOPFL ; LT wanted?
ORA A
JNZ DTEXAC ; NZ=no, didn't tell us so do anything but gave
; us a date so assume want exact match
LDA DTMTCH
CPI 2
JZ GDTMTC ; Date was below and they wanted below
NDTMTC:
POP B
POP D
POP H
PUSH H
LHLD COUNT
MOV A,L
ORA H
POP H
JZ PRTOTL
JMP NOKPRN
DTEXAC: LDA DTMTCH ; They wanted exact, was it?
ORA A
JZ GDTMTC ; Z=yes
JMP NDTMTC
DTABVE: LDA DTMTCH ; They wanted GE
CPI 1
JZ GDTMTC ; Z=G
ORA A
JNZ NDTMTC ; Must be 2, so not equal
GDTMTC: POP B
POP D
POP H
ENDIF ; Z80DOS
LHLD NEXTT ; Get order table pointer
MOV E,M ; Get low order address
INX H
MOV D,M ; Get high order address
INX H
SHLD NEXTT ; Save updated table pointer
XCHG ; Table entry to HL
PUSH H ; Save address of byte to be moved
LHLD NEWPTR ; Address in new table to put byte
PUSH H ; Save address
IF Z80DOS
LXI D,15 ; Update address including date
ENDIF ;Z80DOS
IF NOT Z80DOS
LXI D,13 ; Update address
ENDIF ;NOT Z80DOS
DAD D
SHLD NEWPTR ; Save for later (end of table)
POP H ; Set current move to address
XCHG ; Swap pointers
POP H ; Set current move from address
MVI B,11 ; Filename.typ length
CALL MOVE ; Move it
IF Z80DOS
PUSH H
ENDIF ;Z80DOS
PUSH D
OKPR2:
CALL SIZEFL
LHLD TOTSIZ ; DE = rounded size in K
DAD D ; Add to total used
SHLD TOTSIZ
LHLD TOTFIL ; Increment filecount
INX H
SHLD TOTFIL
XCHG
OKPR3:
POP D ; A(size to go)
MOV A,H ; Move size to table two
STAX D
INX D
MOV A,L
STAX D
IF Z80DOS
POP H ; Currently pointing to file size
INX H ; Skip size
INX H
INX D
MOV A,M ; Get LSB of date
STAX D ; Save it away
INX D
INX H
MOV A,M ; Ditto for MSB of date
STAX D
ENDIF ;Z80DOS
;
; One File Moved - Test to see if we have to move another
;
LHLD COUNT ; Current file counter
MOV A,H
ORA L
JZ PRTOTL ; Zero, output summary
JMP ENTRY
;.....
;
; Compute the size of the file/library and update our summary datum.
; This has been changed into a subroutine so that both the file size
; computation and a library size (when printing out library members)
; can be computed in K.
;
SIZEFL: MOV D,M
INX H
MOV E,M ; Size in DE (records)
XCHG
SHLD FILERC ; Save record count
XCHG
LDA BLKMSK
PUSH PSW
ADD E
MOV E,A
MOV A,D
ACI 0
MOV D,A
POP PSW
CMA
ANA E
MOV E,A
MVI B,3
SHRR: MOV A,D
ORA A
RAR
MOV D,A
MOV A,E
RAR
MOV E,A
DCR B
JNZ SHRR
RET
;
; Print HL in decimal with leading zero suppression
;
DECPRT: XRA A ; Clear leading zero flag
STA LZFLG
LXI D,-10000
LDA SUPSPC
PUSH PSW
XRA A
STA SUPSPC
CALL DIGIT
POP PSW
STA SUPSPC
LXI D,-1000 ; Print 1000's digit
CALL DIGIT
LXI D,-100 ; Etc.
CALL DIGIT
LXI D,-10
CALL DIGIT
MVI A,'0' ; Get 1's digit
ADD L
JMP PUTCHR
DIGIT: MVI B,'0' ; Start off with ASCII 0
DIGLP: PUSH H ; Save current remainder
DAD D ; Subtract
JNC DIGEX ; Quit on overflow
POP PSW ; Throw away remainder
INR B ; Bump digit
JMP DIGLP ; Loop back
DIGEX: POP H ; Restore pointer
MOV A,B
CPI '0' ; Zero digit?
JNZ DIGNZ ; No, type it
LDA LZFLG ; Leading zero?
ORA A
MVI A,'0'
JNZ PUTCHR ; Print digit
LDA SUPSPC ; Get space suppression flag
ORA A ; See if printing file totals
RZ ; Yes, don't give leading spaces
JMP SPACE ; Leading zero..print space
;
DIGNZ: STA LZFLG ; Leading zero flag set
JMP PUTCHR ; Print leading zero & digit
;.....
;
;-----------------------------------------------------------------------
;
;Multiply contents of HL register by 13
;
MULT13: MOV D,H
MOV E,L
DAD H
DAD D
DAD H
DAD H
DAD D
IF Z80DOS
DAD D ; Actually by 15
DAD D ;
ENDIF ;Z80DOS
RET
;.....
;
; Main subroutine to output a filename to be erased
;
VENTRY:
;.....
;
PFILE1:
PUSH H
MVI B,8 ; Print filename and type
CALL PUTSB
MVI A,'.'
CALL PUTCHR
MVI B,3
CALL PUTSB
IF Z80DOS
LDA NODFLG
ORA A
JZ NOD3
CALL DISDAT ; Display the date
NOD3:
ENDIF ;Z80DOS
MOV D,M ; Get it into DE
INX H
MOV E,M
XCHG ; HL <-> DE
SHLD TFSIZE
CALL DECPRT ; Print it out
LDA FSIZEC ; Follow with 'k'
CALL PUTCHR
POP B ; B point to data base with file name
PUSH H
LXI H,OUTFCB ; Build an FCB with file name to erase
LDA FCB ; Get drive number
MOV M,A
INX H ; Point to name field of FCB
MVI E,0CH ; Copy 12 chars from data base to FCB
MOVFCB:
LDAX B
MOV M,A
INX H
INX B
DCR E
JNZ MOVFCB
LDA NOPFLG ; Are we in NO VERIFY?
ORA A
JNZ ERA0 ; NZ= no
CALL CKABRT ; Yes, check for abort
MVI A,'Y' ; Force a YES answer to erase?
JMP ERA1
ERA0: LXI D,ERAMES ; Ask operator if should erase
CALL PUTS
MVI C,RDCON
CALL BDOS
ERA1: ANI 5FH ; Convert to upper case
PUSH PSW
CPI 3 ; CTRL-C?
JZ ERAABO ; Z=yes, abort
CPI 11 ; CTRL-K
JZ ERAABO ; Z=yes, abort
CPI 'Y' ; Y(es)?
JNZ NOERAS ; NZ=no, don't erase this one
LDA NEWUSR ; Set user are currently working on
MOV E,A ; And set it
MVI C,32
CALL 5
LDA OUTFCB+9 ; Change potential R/O to R/W
ANI 7FH
STA OUTFCB+9
LXI D,OUTFCB
MVI C,1EH
CALL 5 ; And set file attributes
LXI D,OUTFCB
MVI C,13H
CALL 5 ; And go erase the file
INR A
JNZ OKERA ; NZ= no error
LXI D,ERAMSE ; Tell operator had a problem
CALL PUTS
JMP NOERAS
OKERA:
LHLD TFSIZE ; size of this file in 'K'
XCHG
LHLD TOTSZ1 ; Add i total so far
DAD D
SHLD TOTSZ1 ; And save it away
LHLD TOTFL1
INX H
SHLD TOTFL1 ; Up count of files done
LXI D,ERAMS1 ; Say we did it fine
CALL PUTS
NOERAS:
POP PSW
CALL CRLF
POP H
LHLD TOTFIL ; Load number of files left
DCX H ; # files-1
SHLD TOTFIL ; Resave it
RET ; This return
ERAABO:
LXI D,CKMS1 ; Say ABORTED
CALL PUTS
JMP EX0 ; And done
;.....
;
; End of routines
;-----------------------------------------------------------------------
;
; Show total space and files used
;
PRTOTL:
PRTOT1: XRA A ; Get a zero to
STA SUPSPC ; Suppress leading spaces in totals
LHLD TOTFIL ; How many files matched?
MOV A,H
ORA L
JZ NXTUSR ; Skip summary if none found
PUSH H ; Save TOTFIL
STA FNDFLG ; Set file found flag
LDA SOHFLG
ORA A
JZ PRTOT2
XRA A
STA SOHFLG
JMP PRTOT3
PRTOT2: ; CALL CRLF
PRTOT3: LXI D,TOTMS1 ; Print "13,10,' Drive'"
CALL PUTS
LDA FCB
ADI 'A'-1
CALL PUTCHR ; Output the drive code
CALL CKVER
JC NOUSER
CALL PUTUSR ; Output user number
IF NDIRS
MVI A,' '
CALL PUTCHR
CALL NAMDIR
ENDIF ; NDIRS
LDA USRNR
CPI 10
IF ULINE
LXI D,ULON ; Turn on underline
CALL COUTS ; If not null
ENDIF ; ULINE
NOUSER:
POP H ; Recall TOTFIL
IF ULINE
LXI D,ULOFF ; Turn off underline
CALL COUTS ; If not null
ENDIF ; ULINE
CALL CRLF
;
; Summary line printed, now print detail files, first compute total
; printout lines.
;
NPRNT:
MVI A,1
STA SUPSPC ; Allow spaces preceding file sizes
;
; Fill a record with FF at the end of table 2
;
LHLD NEWPTR ; Now points to end of table 2
MVI B,128
MVI A,0FFH
NPRNT2: MOV M,A
INX H
DCR B
JNZ NPRNT2
;
; Increment the number of files for use later in VENTRY. This insures
; that a column delimiter will be printed after the last filename, if
; the file appears in other than the last column of the display.
;
; IF NOT Z80DOS
; LXI H,TOTFIL
; INR M
; ENDIF ;NOT Z80DOS
;
; Print first filename
;
NPRNT3: LHLD XPOINT ; XPOINT = to start of second table
CALL VENTRY ; At entry. Below, it is incremented
; For additional lines of printout
NLINE: LHLD XPOINT ; Increment XPOINT to next file
IF Z80DOS
LXI D,15
ENDIF ;Z80DOS
IF NOT Z80DOS
LXI D,13
ENDIF ;NOT Z80DOS
DAD D
SHLD XPOINT
LHLD TOTFIL ; Out of files?
MOV A,H
ORA L
JZ NXTUSR ; Yes, Check for libraries
JMP NPRNT3
;
; Directory for one user area completed. If all users option is select-
; ed, then go do another directory on the next user number until we ex-
; ceed the maximum user # for the selected drive.
;
NXTUSR: LDA AOPFLG ; All user flag
ORA A ; Set?
JZ NXTUSU ; Set if zero, show all user areas
LDA HOPFLG ; "H" flag to show remaining areas
ORA A
JNZ GOCLZ ; Non-zero, not set, exit
NXTUSU: CALL CKVER ; Running CP/M 2?
JC GOCLZ ; No, Skip user increment
CALL CKABRT ; Yes, Check for user abort
LDA MAXUSR ; No abort - get maximum user #
LXI H,NEWUSR ; Increment directory user number
INR M
CMP M ; Next user # exceed maximum?
JNC SETTBL ; No, more user areas to go
LDA BASUSR ; Reset base user number for
MOV M,A ; The next directory search
;
; We've finished all of our outputting. Flush the remainder of the out-
; put buffer and close the file before going to exit routine.
;
GOCLZ:
NXTDSK: LXI H,FNDFLG ; Load file found flag
MOV A,M
MVI M,0 ; Clear found flag for next drive
ORA A
JNZ NDSK ; Continue if at least 1 file found
LXI D,NOFMS1 ; Print 1st part of no files message
CALL PUTS ; Print it
LXI D,NOFLM
CALL PUTS ; Print message
LDA FCB
ADI 'A'-1
CALL PUTCHR ; Output the drive
CALL CKVER
JC NOUSR1
CALL PUTUSR ; Output the user number
NOUSR1: CALL CRLF
NDSK: LDA DOPFLG ; Multi-disk selected?
ORA A
JNZ NPRT ; No, skip next check
CALL CKABRT ; Check for user abort
MVI A,HIDRV-LODRV ; Load max drive code to search
LXI H,FCB ; Increment directory FCB drive code
INR M
CMP M ; Does next disk exceed maximum?
JC NPRT
IF MAXDRV
IF ZCPR33
PUSH H
LHLD Z3DRVL ; Point to ENV
MOV A,M ; Get it
POP H
ENDIF ;ZCPR33
IF NOT ZCPR33
LDA MXDRV ; Look at another value limit
INR A
ENDIF ;NOT ZCPR33
CMP M ; Is it lower?
JC NPRT ; Bail out if too low
JMP NOOPT ; Search next disk
ENDIF ; MAXDRV
JNC NOOPT ; Search next disk if maxdr not true
;
; If no printer, fall through to EXIT
;
NPRT:
JMP EXIT ; All done - exit to CCP
;.....
;
; Output the user number of the directory in decimal
;
PUTUSR: LDA NEWUSR
CPI 10 ; User no. < 10?
JC DUX ; Yes, skip 10's digit
STA USRNR
PUSH B ; No, process 10's digit
MVI C,'0'-1
DUY: INR C ; Get tens digit
SUI 10
JNC DUY ; Loop until we've gone too far
ADI 10
MOV B,A ; Save units digit
MOV A,C ; Print tens digit
CALL PUTCHR
MOV A,B ; Recall units digit
POP B
DUX: ADI '0' ; Make it ASCII
JMP PUTCHR
;.....
;
; Force new line on output and check for page pause
;
CRLF: MVI A,13 ; Send CR
CALL PUTCHR
MVI A,10 ; Send LF
JMP PUTCHR
;.....
SPACE: MVI A,' '
;
; Output character in A to console, and optionally to printer
; and/or the output file. Detects user abort request.
;
PUTCHR: PUSH B
PUSH D
PUSH H
PUSH PSW ; Save the character to output
CALL HITYPE ; Send it to console
POP PSW ; Restore the output character
ANI 7FH ; Strip parity bit on character
;
; Test for erase mode no verify
;
MOV B,A ; Save stripped character to B
CPI 10 ; At end of line?
JNZ NOTEOL
PUSH PSW
LDA NOPFLG
ORA A
JNZ PAUSON
LDA LINCNT ; Load line count
INR A ; Bump it
STA LINCNT
MVI L,23 ; Allows use of [more] to finish display
CMP L ; End of the screen?
JC PAUSON
LXI D,EOSMSG ; Else, display pause message
MVI C,PRINT ; Without checking for line feeds
CALL BDOS
CALL GETCH ; Wait for character
CPI 'C'-40H ; Abort on CTL-C
JZ EXIT1
CPI 'K'-40H ; Or CTL-K
JZ EXIT1
CPI 'X'-40H ; Or CTL-X
JZ EXIT1
CPI ' ' ; See if printing character
JC NOTEOS ; Exit if not
ANI 5FH ; Change to upper-case
CPI 'C' ; Can abort with c, C
JZ EXIT1
CPI 'K' ; Can abort with k, K
JZ EXIT1
CPI 'X' ; Can abort with x, X
JZ EXIT1
NOTEOS: XRA A ; Reset line count
STA LINCNT
LXI D,MORERA ; Overwrite the [more] display
MVI C,PRINT
CALL BDOS
PAUSON: POP PSW
CZ CKABRT ; Check for user abort request
NOTEOL: POP H ; Exit from PUTCHR
POP D
POP B
RET
;.....
;
; Fetch character from console (without echo)
;
GETCH: LHLD 0000H+1 ; Warm Boot Address
MVI L,9 ; Direct Console
CALL GOHL ; Get Character
ANI 7FH ; Strip off any parity
RET
;.....
;
; Output character, with low-case or reverse-video highlighting if high
; bit set and conditionals enabled.
;
HITYPE: DS 0
IF USELC OR REVID
ORA A ; Check for attributes not set
JP CONOUT ; No attribute..ignore this one
ANI 7FH ; Attribute set, delete now
ENDIF ; USELC OR REVID
IF NOT USELCW AND WHEEL
MOV E,A ; Save the character for later
IF ZCPR33
PUSH H
LHLD Z3WHLL ; Point to enviorment
MOV A,M ; Get it
POP H
ENDIF ;ZCPR33
IF NOT ZCPR33
LDA WHLOC ; Get wheel byte
ENDIF ;NOT ZCPR33
ORA A ; Don't use lower case or REVID
MOV A,E ; Get back the character to display
JZ CONOUT
ENDIF ; NOT USELCW AND WHEEL
IF REVID
PUSH PSW ; Save character
LXI D,RVON ; Turn on reverse video
CALL COUTS ; If not null
POP PSW ; Restore character
ENDIF ; REVID
IF USELC
CPI 'A' ; Change only from A-Z
JC TYPEC
CPI 'Z'+1
JNC TYPEC ; Punctuation can change so leave it
ORI 20H ; If attribute, make lower case
ENDIF ; USELC
IF USELC OR REVID
TYPEC: CALL CONOUT ; Send the processed character
ENDIF ; USELC OR REVID
IF REVID
LXI D,RVOFF ; Turn off reverse video
CALL COUTS ; If not null
ENDIF ; REVID
IF USELC OR REVID
RET
ENDIF ; USELC OR REVID
;.....
;
; Output character in A to console
;
CONOUT: MOV E,A ; Get character for BDOS entry
MVI C,WRCON
JMP BDOS ; Console Output
;.....
;
; Output (raw) null-terminated string at (DE) to console.
;
COUTS: LDAX D ; Get byte of string
ORA A ; Null?
RZ ; Return if so
PUSH D
CALL CONOUT
POP D
INX D ; Next byte
JMP COUTS
;.....
;
; Output bytes at HL of length B to console/printer/file
;
PUTSB: MOV A,M
CALL PUTCHR
INX H
DCR B
JNZ PUTSB
RET
;.....
;
; Output null-terminated string to console/printer/file
;
PUTS: LDAX D ; Load character from DE string
ANI 7FH ; Strip off parity
ORA A ; Is a 0?
RZ ; Yes, Terminate
CALL PUTCHR ; Display character
INX D ; Next string position
JMP PUTS ; Continue
;
; Check for a CTL-C or CTL-S entered from the keyboard. Jump to EXIT if
; CTL-C, pause on CTL-S.
;
CKABRT: PUSH H
PUSH D
PUSH B
MVI C,CONST
CALL BDOS
ORA A
JZ CKAB3 ; No character, exit
MVI C,RDCON
CALL BDOS
ANI 5FH
CPI 'S'-40H
JZ CKAB0
CPI 'S'
JNZ CKAB1
CALL CKAB4
CKAB0: MVI C,RDCON
CALL BDOS
ANI 5FH
CKAB1: CPI 'C'-40H ; CTL-C?
JZ CKAB2 ; Yes, quit
CPI 'K'-40H
JZ CKAB2
CPI 'X'-40H
JZ CKAB2
CPI ' ' ; Any other CTL-character, abort
JC CKAB3
CALL CKAB4 ; Clear the character from screen
CPI 'C'
JZ CKAB2
CPI 'K'
JZ CKAB2
CPI 'X'
JNZ CKAB3
CKAB2: LXI D,CKMS1
CALL PUTS
POP B
POP D
POP H
JMP EX0 ; All done
CKAB3: POP B
POP D
POP H
RET
CKAB4: PUSH PSW
LXI D,CKMS2
CALL PUTS
POP PSW
RET
;.....
;
; Call here to call address in HL
;
GOHL: PCHL
;
; Enter BDOS, save all extended registers
;
CPM: PUSH B ; Save Registers
PUSH D
PUSH H
IF ZRDOS
LDA ZRDFLG ; ZRDOS running?
ORA A
JNZ ZRD ; ZRDOS error trap and DOSs call
ENDIF ; ZRDOS
CALL BDOS
MOV B,A ; Save return code
LDA VERFLG ; Is this 3.0?
CPI 30H
MOV A,B
JC CPM20 ; No, exit normally
CPI 0FFH ; Yes, was return code FF?
JNZ CPM20 ; No, exit normally
MOV A,H ; Yes, check for error code
ORA A
JNZ DSKERR ; Exit if physical error
MOV A,B ; Else, continue normally
CPM20: POP H
POP D
POP B
RET
;.....
;
; ZRDOS Error Trap and System Call exits to CPM20
;
IF ZRDOS
ZRD: CALL SETTRAP ; Set the warm boot trap
CALL BDOS ; Do what we're told
CALL RESTRAP ; Reset the trap
JMP CPM20 ; Error free exit
;.....
;
; Set Warm Boot Trap in ZRDOS
;
SETTRAP:PUSH H
PUSH D
PUSH B
MVI C,SETWBT ; Set warm boot trap to come here
LXI D,WBTRAP
CALL BDOS
POP B
POP D
POP H
RET
;.....
;
; WBTRAP is where the ZRDOS returns control on warm boot (error)
;
WBTRAP: LXI H,DSKERR ; Return here after trap reset
PUSH H ; Save DSKERR on stack
;
; Reset Warm Boot Trap in ZRDOS
;
RESTRAP:PUSH H
PUSH D
PUSH B
PUSH PSW
MVI C,RESWBT ; Reset warm boot trap
CALL BDOS
POP PSW
POP B
POP D
POP H
RET
ENDIF ; ZRDOS
;.....
;
; For file output mode, return to old user area and set DMA for the file
; output buffer.
;
SETFOP: CALL CKVER ; Clear carry if CP/M 2 or later
LDA OLDUSR ; Get user number at startup
MOV E,A
MVI C,STUSER
CNC CPM ; Reset old user number if CP/M 2
LXI D,OUTBUF ; Move DMA from search buffer into
JMP SET2 ; Output buffer
RET
;.....
;
; Move disk buffer DMA to default buffer for directory search operations
; and BDOS media change routines (required for pre-CP/M 2 systems while
; in file output mode with active buffer).
;
SETSRC: LXI D,TBUF ; Default DMA Address
SET2: MVI C,STDMA ; Set DMA Address
JMP CPM
;.....
;
; Print amount of free space remaining on selected drive
;
PRTFRE: LXI D,TOTMS7 ; Print " Free: '
CALL PUTS
LHLD FREEBY
CALL DECPRT ; Print k free
LXI D,TOTMS8 ; Print "k "
CALL PUTS
RET
;.....
;
; Show string on the console
;
SHOW: LDAX D ; Get character from DE string
ANI 7FH ; Strip off parity
ORA A ; Is it a 0?
RZ ; Yes, terminate
PUSH B ; Save registers
PUSH D
PUSH H
CALL CONOUT ; Show character on console
POP H ; Load registers
POP D
POP B
INX D ; Next string position
JMP SHOW ; Continue
;.....
;
; Compare routine for last extent of file search
;
COMPR: PUSH H ; Save table address
MOV E,M ; Load low order
INX H
MOV D,M ; Load high order
INX H
MOV C,M
INX H
MOV B,M
;
; BC, DE now point to entries to be compared
;
XCHG
MOV E,A ; Get count
CMPLP: LDAX B
XRA M ; Copy bit 7 of M
ANI 7FH ; Into bit 7 of A
XRA M
CMP M ; Then compare
INX H
INX B
JNZ NOTEQL ; Quit on mismatch
DCR E ; Or end of count
JNZ CMPLP
;
NOTEQL: POP H
RET ; Condition code tells all
;.....
;
; Swap entries in the order table
;
SWAP: LXI B,ORDER-2 ; Table base
DAD H ; *2
DAD B ; + base
XCHG
DAD H ; *2
DAD B ; + base
MOV C,M
LDAX D
XCHG
MOV M,C
STAX D
INX H
INX D
MOV C,M
LDAX D
XCHG
MOV M,C
STAX D
RET
;.....
;
; New compare routine for sorting
;
COMPARE:LXI B,ORDER-2
DAD H
DAD B
XCHG
DAD H
DAD B
XCHG
MOV C,M
INX H
MOV B,M
XCHG
MOV E,C
MOV D,B
MOV C,M
INX H
MOV H,M
MOV L,C
MVI B,13 ; Count for normal sort
LDA TOPFLG ; Check for sort by type
ORA A
JNZ CMPLPE ; Jump if normal sort
PUSH H ; Save name pointers for later
PUSH D
LXI B,8 ; Point to file types
DAD B
XCHG
DAD B
XCHG
MVI B,3 ; Count for type compare
CALL CMPLPE
POP D ; Retrieve name pointers
POP H ;
RNZ
MVI B,8 ; Count for name compare
CALL CMPLPE
RNZ
INX D ; Point to extent
INX D
INX D
INX H
INX H
INX H
MVI B,2 ; Count for extent compare
CMPLPE: LDAX D ;
XRA M ; Copy bit 7 of M
ANI 7FH ; Into bit 7 of A
XRA M ;
CMP M ; Then compare
INX D
INX H
RNZ
DCR B
JNZ CMPLPE
RET
;.....
;
; Error exit
;
ERXIT:
CALL CRLF ; Space down
POP D ; Load message string pointer
CALL PUTS ; Print message
LXI D,ERRMS1 ; " Error"
CALL PUTS ; Print message
CALL CRLF ; Space down
;
; Exit - all done, restore stack
;
EXIT: LDA DOPFLG ; Multi-disk selected?
ORA A
JNZ EX0 ; No, skip next
CALL CKABRT ; Check for user abort
MVI A,HIDRV-LODRV ; Maximum drive code to search
LXI H,FCB ; Increment directory FCB drive code
INR M
CMP M ; Does next disk exceed maximum?
JC EX0
IF MAXDRV
IF ZCPR33
PUSH H
LHLD Z3DRVL ; Point to ENV
MOV A,M ; Get it
POP H
ENDIF ;ZCPR33
IF NOT ZCPR33
LDA MXDRV ; Look at another value limit
INR A
ENDIF ;NOT ZCPR33
CMP M ; Is it lower?
JC EX0 ; Bail out if too low
JMP NOOPT ; Search next disk
ENDIF ; MAXDRV
JNC NOOPT ; Search next disk if MAXDR not true
EX0:
CALL CRLF
MVI C,CONST ; Check console status
CALL CPM
ORA A ; Character waiting?
MVI C,RDCON
CNZ CPM ; Gobble up character
IF ZRDOS
LDA ZRDFLG ; ZRDOS running?
ORA A
JNZ EXIT2 ; Yes
ENDIF ; ZRDOS
LDA VERFLG ; Version flag
CPI 30H ; CP/M 3.0?
JC EXIT1 ; No
MVI C,2DH ; Yes,
MVI E,0 ; Reset error mode to default
CALL CPM
JMP EXIT2 ; Quit
EXIT1: LDA DOPFLG ; If they were swapped
ORA A
CZ SWAPEM
EXIT2 EQU $
LDA AOPFLG ; Doing all users
MOV C,A
LDA DOPFLG ; Or disk?
ANA C
MOV C,A
LDA HOPFLG ; Or higher users?
ANA C
JNZ TOTDONE ; If no, skip totals
LXI D,ALLTOT ; First part of message
CALL PUTS
LHLD TOTFL1 ; Total files found
CALL DECPRT
LXI D,TOTMS4
CALL PUTS
LHLD TOTSZ1 ; Total 'k' found
CALL DECPRT
LXI D,TOTMS8
CALL PUTS
LXI D,TOTMS7
CALL PUTS
LHLD TOTFRE
XCHG
LHLD TOTSZ1
DAD D
CALL DECPRT
LXI D,ALLTO1
CALL PUTS
TOTDONE:
IF WMBOOT
JMP 0000H
ENDIF ; WMBOOT
LDA OLDDSK ; Restore original drive
MOV E,A
MVI C,14
CALL CPM
LDA OLDUSR ; Restore original user area
MOV E,A
MVI C,32
CALL CPM
EXIT3: LHLD STACK ; Get old stack pointer
SPHL ; Move back to old stack
RET ; And return to CCP
;.....
;
IF NDIRS
NAMDIR: MVI A,0
STA CURDIR ; Initial check count
NAMDR1: LHLD NAMADR ; Named directory buffer address
NAMDR2: LDA FCB ; Get current Drive
CMP M ; Does NDR entry match current drive?
JNZ NXTDIR ; No, check next
LDA NEWUSR ; Get current user
INX H
CMP M ; Does NDR entry match current user?
JNZ NXTDIR ; No, check next
MVI A,'[' ; Frame the name in brackets
CALL PUTCHR
MVI C,8 ; Number of Characters in entry
DIRCHR: INX H ; Match, Point to Directory Name
MOV A,M ; Get Character
CPI 20H ; End of entry?
JNZ DIRCH1 ; No
DIRCH0: PUSH PSW
MVI A,']' ; Print closing bracket
CALL PUTCHR
POP PSW
JMP DIRCH2
DIRCH1: CALL PUTCHR
DCR C
JNZ DIRCHR ; Output Eight characters
JMP DIRCH0
RET ; Done
DIRCH2: MOV A,C
ORA A
RZ
MVI A,20H ; Fill with spaces for neatness sake
CALL PUTCHR
DCR C
JNZ DIRCH2
RET
NXTDIR: LDA CURDIR
ADI 1 ; Increment Directory pointer
STA CURDIR
LXI H,NUMDIR
CMP M ; Exceeded Max Entry?
JZ NODIR ; Yes, there is no entry for this DU
LHLD NAMADR ; Get base NDR address
MVI D,0
MVI E,18 ; Increment to next entry
NXTD: DAD D
DCR A ; Decrement count
JNZ NXTD ; Until current Offset reached
JMP NAMDR2 ; And check the entry for a match
NODIR: MVI C,10 ; No match, output ten spaces
NODIR1: MVI A,20H
CALL PUTCHR
DCR C
JNZ NODIR1
RET
ENDIF ; NDIRS
;.....
;
; Trap BDOS select and sector error vectors to our own intercept routine
; so we can catch a reference to an illegal drive.
;
SWAPEM: DS 0
IF ZRDOS
LDA ZRDFLG ; See if ZRDOS running
ORA A
RNZ ; Yes, quit this
ENDIF ; ZRDOS
LDA VERFLG ; Version flag
CPI 30H ; Error mode call available?
JC SWAP20 ; No, use BDOS error vectors
MVI C,2DH ; Yes, use error mode call
MVI E,0FFH ;
CALL CPM ; Set "return code only" mode
RET
SWAP20: LHLD BDOS+1 ; Load pointer to base of BDOS
INX H ; Swap new pointer if running a
MOV E,M ; Program below the CCP
INX H
MOV D,M
XCHG ; HL points to the proper vector
MVI L,9 ; Point to record error vector
LXI D,VECTBL ; Exchange with our vector table
MVI A,4 ; 4 bytes to swap
SWAPLP: MOV B,M ; Load byte from HL
XCHG
MOV C,M ; Load byte from DE
MOV M,B ; Save byte from HL
XCHG
MOV M,C ; Save byte from DE
INX H ; Increment exchange pointers
INX D
DCR A ; Counter-1
JNZ SWAPLP ; Continue swapping
RET
;.....
;
; Check CP/M version number. Return carry flag set if pre-CP/M 2. If
; CP/M 2 or later or MP/M (any version), return carry clear.
;
CKVER: LDA VERFLG ; Version Flag
CPI 20H ; CP/M 2.0?
RET
;.....
;
; Return point from intercepted BDOS select and bad record errors.
;
DSKERR: LXI SP,STACK ; Get out of BDOS' stack
JMP EXIT ; And exit back to CCP
;.....
;
;-----------------------------------------------------------------------
; Start of FNAME routine
;
; Main module
; on entry, DE points to FCB to be filled, HL points to first
; byte of target string, RFCB is 36 bytes long
; on exit, B=disk number (1 for A, etc.) and C=user number
; HL points to terminating character
; A=0 and Z set if error in disk or user numbers
; A=0FFH and NZ if ok
;
MAXDISK EQU 16 ; Maximum number of disks
MAXUSER EQU 31 ; Maximum user number
FNAME: PUSH D ; Save DE
MVI A,0FFH ; Set default disk and user
STA DISKNO
STA USERNO
MVI B,36 ; Initialize FCB
PUSH D ; Save pointer
XRA A ; A=0
FNINI: STAX D ; Store zero
INX D ; Point to next
DCR B ; Count down
JNZ FNINI
POP D ; Get pointer back
PUSH H ; Save pointer
;
; Scan for colon, comma, or space in string
;
COLON: MOV A,M ; Scan for colon or space
INX H ; Point to next
CPI ':' ; Colon found?
JZ COLON1
CPI ',' ; Comma found?
JZ GETF1
CPI ' '+1 ; Delimiter?
JC GETF1
JMP COLON ; Continue if not EOL
;
COLON1: POP H ; Clear stack
MOV A,M ; Save possible drive specification
CALL CAPS ; Capitalize
CPI 'A' ; Digit if less than "A"
JC USERCK ; Process user number
SUI 'A' ; Change from ASCII to binary
CPI MAXDISK ; Within bounds?
JC SVDISK
;
ERREXIT:XRA A ; Error indicator
POP D ; Restore DE
RET
;.....
;
; Log in specified disk
;
SVDISK: INR A ; Adjust to 1 for "A"
STA DISKNO ; Save flag
INX H ; Point to next character
;
; Check for user
;
USERCK: MOV A,M ; Get possible user #
CPI ':' ; No user number
JZ GETFILE
CPI '?' ; All user numbers?
JNZ USERC1
STA USERNO ; Set value
INX H ; Point to after
MOV A,M ; Must be colon
CPI ':'
JZ GETFILE
JMP ERREXIT ; Fatal error if not colon after ?
USERC1: XRA A ; Zero user number
MOV B,A ; B = A for user number
USRLOOP:MOV A,M ; Get digit
INX H ; Point to next
CPI ':' ; Done?
JZ USRDN
SUI '0' ; Convert to binary
JC ERREXIT ; User number error?
CPI 10
JNC ERREXIT
MOV C,A ; Next digit in C
MOV A,B ; Old number in A
ADD A ; *2
ADD A ; *4
ADD B ; *5
ADD A ; *10
ADD C ; *10+new digit
MOV B,A ; Result in B
JMP USRLOOP
USRDN: MOV A,B ; Get newer user number
CPI MAXUSER+1 ; Within range?
JNC ERREXIT
STA USERNO ; Save in flag
JMP GETFILE
;
; Extract file name
;
GETF1: POP H ; Get pointer to byte
;
GETFILE:MOV A,M ; Pointing to colon?
CPI ':'
JNZ GFILE1
INX H ; Skip over colon
GFILE1: MOV A,M ; Get next character
CPI ',' ; Delimiter?
JZ GFQUES
CPI ' '+1 ; Not a delimiter?
JNC GFILE2
GFQUES: INX D ; Fill with ???
MVI B,11 ; 11 bytes
MVI A,'?'
GFFILL: STAX D ; Put?
INX D ; Point to next
DCR B ; Count down
JNZ GFFILL
FNDONE: LDA DISKNO ; Get disk number
MOV B,A ; In 'B'
LDA USERNO ; Get user number
MOV C,A ; In 'C'
POP D ; Restore registers
MVI A,0FFH ; No error
ORA A ; Set flags
RET
;
; Get file name fields
;
GFILE2: MVI B,8 ; At most, 8 byte filename
CALL SCANF ; Scan and fill
MVI B,3 ; At most, 3 byte filetype
MOV A,M ; Get delimiter
CPI '.' ; Filename ending in "."?
JNZ GFILE3
INX H ; Point to character after "."
CALL SCANF ; Scan and fill
JMP FNDONE ; Done, return to "args"
GFILE3: CALL SCANF4 ; Fill with spaces
JMP FNDONE
;
; Scanner routine
;
SCANF: CALL DELCK ; Check for delimiter
JZ SCANF4 ; Fill with spaces if found
INX D ; Next byte in filename
CPI '*' ; Question mark fill ?
JNZ SCANF1
MVI A,'?' ; Place "?"
STAX D
JMP SCANF2
SCANF1: STAX D ; Place character
INX H ; Next position
SCANF2: DCR B ; Count down
JNZ SCANF ; Continue loop
SCANF3: CALL DELCK ; Skip to delimiter
RZ
INX H ; Point to next
JMP SCANF3
SCANF4: INX D ; Next filename or filetype
MVI A,' ' ; Fill with spaces
STAX D
DCR B ; Count down
JNZ SCANF4
RET
;.....
;
; Check character pointed to by HL for a delimiter,
; return with Zero flag set if the character is a delimiter
;
DELCK: MOV A,M ; Get the character
CALL CAPS ; Capitalize
ORA A ; 0=delimiter
RZ
CPI ' '+1 ; Space character+1
JC DELCK1 ; Space character or less
CPI '='
RZ
CPI 5FH ; Underscore
RZ
CPI '.'
RZ
CPI ':'
RZ
CPI ';'
RZ
CPI ','
RZ
CPI '<'
RZ
CPI '>'
RET
;
DELCK1: CMP M ; Compare with self for OK
RET
;.....
;
CAPS: CPI 'a'
RC
CPI 'z'+1
RNC
SUI 20H
RET
;.....
; End of FNAME routine
;
;.....
;
; Move characters from "HL" to "DE" length in "B"
;
MOVE: MOV A,M ; Get a character
STAX D ; Store it
INX H ; To next "from"
INX D ; To next "to"
DCR B ; More?
JNZ MOVE ; Yes, loop
RET ; No, return
;-----------------------------------------------------------------------
; help routine
;
; Help menu if ? is typed, using a fancy ZCMD or ZCPR system
;
;
; Help menu if ? is typed, NOT using any fancy ZCMD or ZCPR system
;
HELPME: LXI D,OPTMSG ; Point at message
CALL SHOW
JMP EXIT3 ; And exit
;
OPTMSG: DB 13,10,13,10
DB ' Available Options (start with a $ or / or'
DB ' [ character):',13,10
DB 13,10
DB ' A - all user areas D - all drives',13,10
DB ' H - current area to highest L - include $R/O files'
DB 13,10
DB ' O - $SYS files only Q - non $ARChived only'
DB 13,10
DB ' R - reset disk system S - include $SYS files'
DB 13,10
DB ' T - order files by EXT type V - show version'
DB 13,10
IF Z80DOS
DB ' Z - do not show dates',13,10
ENDIF ; Z80DOS
IF FATTRIB
DB ' 1 - files with attrib 1 2 - files with attrib 2'
DB 13,10
DB ' 3 - files with attrib 3 4 - files with attrib 4'
DB 13,10
ENDIF ;FATTRIB
IF Z80DOS
DB ' = - Exact date match + - GE date match',13,10
DB ' - - LT date match ! - Use creation date for'
DB ' match',13,10
DB ' % - Use alteration date match @ - Use access date for'
DB ' match',13,10
DB ' A date input with no =+-!%@ will use =% default,'
DB ' * as date is current date'
DB 13,10,13,10
DB ' Ex - to purge all drv/users of .BAK, no verify,'
DB ' GE date match on access date:',13,10,13,10
DB ' B0>SD *.BAK $AND+@ 7/1/88',13,10,13,10,0
ENDIF ;Z80DOS
IF NOT Z80DOS
DB 13,10,' Example - to purge all drv/users of .BAK,'
DB ' no verify:',13,10,13,10
DB ' B0>SD *.BAK $AND <ret>'
DB 13,10,13,10,13,10,13,10,13,10
DB 0
ENDIF ;NOT Z80ODS
IF Z80DOS
DISDAT: PUSH B
PUSH H ; Save pointer to size field
PUSH D
INX H ; and skip over size
INX H ;
MOV E,M ; Get JD in DE
INX H ;
MOV D,M ;
XCHG ; to HL
CALL DATEHL ;
PUSH H ; Month and Year in L,H
PUSH PSW ; Day in A
CALL SPACE
CALL SPACE
POP PSW
JNZ DAYOK ; NZ = was a day there
POP H
CALL NODATE
JMP DNOTOK
DAYOK: PUSH PSW
MOV A,L ; Month out
CALL BCDOUT
MVI A,'/'
CALL PUTCHR
POP PSW
CALL BCDOUT ; Day out
MVI A,'/'
CALL PUTCHR
POP H
MOV A,H ; Year out
CALL BCDOUT
DNOTOK: CALL SPACE
CALL SPACE
POP D
POP H
POP B
RET
NODATE:
LXI D,NODATM
CALL PUTS
RET
NODATM:
DB '-- -- --',0
BCDOUT:
PUSH B ; Save
MOV B,A ; A holds BCD digits
RAR
RAR
RAR
RAR
CALL BCDOT1 ; Output high order
MOV A,B
CALL BCDOT1 ; And low order
POP B
RET
BCDOT1: ANI 0FH
ADI '0'
CALL PUTCHR
RET
;
; DATEHL converts the value in HL to BCD year, month, day
; for use with Z80DOS time stamps.
;
;
; Inputs: HL contains hex days since December 31, 1977
;
; Outputs: H contains BCD 20th century year
; L contains BCD month
; A contains BCD day
;
; Zero flag set (Z) and A=0 if invalid date (zero) detected,
; Zero flag reset (NZ) and A=0ffh otherwise.
; Converted to 8080 from DATEHL by Carson Wilson who Adapted from B5C-CPM3.INS
DATEHL:
MOV A,H
ORA L ; Test blank date (zero)
RZ ; Return Z and A=0 if so
SHLD DAYS ; Save initial value
MVI B,78 ; Set years counter
LOOP:
CALL CKLEAP
LXI D,-365 ; Set up for subtract
JNZ NOLPY ; Skip if no leap year
DCX D ; Set for leap year
NOLPY:
DAD D ; Subtract
JNC YDONE ; Continue if years done
MOV A,H
ORA L
JZ YDONE
SHLD DAYS ; Else save days count
INR B ; Increment years count
JMP LOOP ; And do again
;
; The years are now finished, the years count is in 'B' (HL is invalid)
;
YDONE:
MOV A,B
CALL BINBCD
STA YEARS ; save BCD year
;
CALL CKLEAP
MVI A,0E4H ; -28
JNZ FEBNO ; February not 29 days
MVI A,0E3H ; Leap year -29
FEBNO:
STA FEB ; Set february
LHLD DAYS ; Get days count
LXI D,MTABLE ; Point to months table
MVI B,0FFH ; Set up 'B' for subtract
MVI A,0 ; Set a for # of months
MLOOP:
PUSH PSW
LDAX D ; Get month
MOV C,A ; Put in 'C' for subtract
POP PSW
SHLD DAYS ; save days count
DAD B ; Subtract
INX D ; Increment months counter
INR A
JC MLOOP ; Loop for next month
;
; The months are finished, days count is on stack. First, calculate
; month.
;
MDONE:
MOV B,A ; Save months
LHLD DAYS
MOV A,H
ORA L
JNZ NZD
DCX D
DCX D
LDAX D
CMA
INR A
MOV L,A
DCR B
NZD:
MOV A,L ; Retrieve binary day of month
CALL BINBCD ; Convert to BCD
PUSH PSW ; Save day in A
;
MOV A,B ; Retrieve the binary month
CALL BINBCD ; Convert binary month to BCD
MOV L,A ; Return month in L
;
LDA YEARS
MOV H,A ; Return year in H
;
POP PSW ; Restore day
ORA A ; Set NZ flag
RET
;
; Support Routines:
;
;
; Check for leap years.
;
CKLEAP:
MOV A,B
ANI 0FCH
CMP B
RET
;
; Convert A to BCD & store back in A
;
BINBCD:
ORA A
RZ
PUSH B
MOV B,A
XRA A
BINBCD1:
ADI 1
DAA
DCR B
JNZ BINBCD1
POP B
RET
;
; Buffers:
;
;
; Months table
;
MTABLE:
DB 0E1H ;January -31
FEB:
db 0E4H ;February -28
db 0E1H,0E2H,0E1H,0E2H ;Mar-Jun -31,-30,-31,-30
db 0E1H,0E1H,0E2H ;Jul-Sep -31,-31,-30
db 0E1H,0E2H,0E1H ;Oct-Dec -31,-30,-31
ENDIF ;Z80DOS
;
; Messages and Error statements
;
CKMS1: DB 13,10,'++ ABORTED ++',0
CKMS2: DB 8,' ',8,0
DRUMSG: DB 'Drive/User',0
ERRMS1: DB ' '
ERRMS2: DB 'Error',0
ERRTAG: DB ' ->',0
NOFLM: DB '>> No file(s) on ',0
NOFMS1: DB 13,10,0
NOFMS2: DB ' ',0
NOFMS3: DB ': ',0
SOHFLG: DB 0
TOTMS1: DB 13,10,'Drive ',0
TOTMS4: DB '/',0
TOTMS5: DB 'k ',0
TOTMS6: DB ' Files: ',0
TOTMS7: DB ' Free: ',0
TOTMS8: DB 'k ',0
ALLTOT: DB 13,10,' Total files erased: ',0
ALLTO1: DB 'k',13,10,0
ERAMES: DB ' Erase (Y/N)? ',0
ERAMS1: DB ' Erased',0
ERAMSE: DB ' ERROR, COULD NOT ERASE!!!',0
WHLERR: DB 13,10,' SPP ?',13,10,0
EOSMSG: DB '[more] ','$'
MORERA: DB 13,' ',13,'$'
;
; Permanently initialized data area
;
VECTBL: DW DSKERR ; BDOS record error intercept vector
DW DSKERR ; BDOS select error intercept vector
;
; End of code that must be stored on disk in the .COM file
;
; Data area reinitialized by code when SD is run or rerun
;
DATA0 EQU $ ; Start of area to initialize
OTBL EQU $ ; Mark start of option table
AOPFLG: DS 1
DOPFLG: DS 1
HOPFLG: DS 1
NOPFLG: DS 1
OOPFLG: DS 1
QOPFLG: DS 1
ROPFLG: DS 1
SOPFLG: DS 1
TOPFLG: DS 1
VOPFLG: DS 1
LOPFLG: DS 1
IF Z80DOS ;
DEOPFL: DS 1
DPOPFL: DS 1
DMOPFL: DS 1
DNOPFL: DS 1
DAOPFL: DS 1
DGOPFL: DS 1
NODFLG: DS 1
ENDIF ;Z80DOS
IF FATTRIB
ONEFLG: DS 1
TWOFLG: DS 1
THRFLG: DS 1
FORFLG: DS 1
ENDIF
OEND EQU $ ; End of option table
;
; End of option lookup table
;
BUFPNT: DS 2 ; Next location in output buffer
BUFCNT: DS 1 ; Number of bytes left in output buffer
OUTFCB: DS 1+8+3 ; User number, filename, and filetype
;
; Beginning of area reinitialized to zero each time SD.COM is run
;
DS 21 ; Rest of DISK.DIR FCB
DISKNO: DS 1 ; Disk number
USERNO: DS 1 ; User number
DRVFLG: DS 1 ; D option check for prior drive specificaton
FNDFLG: DS 1 ; Files Matched Flag
FIRSTT: DS 1 ; First time flag for version number
;
; Uninitialized data area
;
BASUSR: DS 1 ; Copy of original directory user #
BLKMAX: DS 2 ; Highest block # on drive
BLKMSK: DS 1 ; Records/block - 1
BLKSHF: DS 1 ; Number shifts to mult by sec/blk
COUNT: DS 2 ; Entry count
DIRMAX: DS 2 ; Highest file # in directory
FILERC: DS 2 ; File size in records
FREEBY: DS 2 ; Number of k left on dir. drive
FSIZEC: DS 1 ; File size character ('k' or 'r')
GAP: DS 2 ; Sort routine storage
I: DS 2 ; Sort routine storage
J: DS 2 ; Sort routine storage
JG: DS 2 ; Sort routine storage
LZFLG: DS 1 ; 0 when printing leading zeros
MAXUSR: DS 1 ; Max user # for drive
NEWUSR: DS 1 ; User # selected by "$U" option
NEXTT: DS 2 ; Next table entry
OLDDSK: DS 1 ; Currently logged-in drive
OLDUSR: DS 1 ; User number upon invocation
SCOUNT: DS 2 ; # to sort
SUPSPC: DS 1 ; Leading space flag
TBLOC: DS 2 ; Start of name table
TOTFIL: DS 2 ; Total number of files
TOTSIZ: DS 2 ; Total size of all files
TOTFL1: DS 2 ; Total files of all D/U
TOTSZ1: DS 2 ; Total size of all D/U
TFSIZE: DS 2 ; Size of file currently erased
TOTFRE: DS 2
USRNR: DS 1 ; User number
VERFLG: DS 1 ; CP/M version number (0=pre-CP/M 2)
ZRDFLG: DS 1 ; ZRDOS version number
IF Z80DOS ;
DATCHK: DS 2 ; Holds date to look for
DTMTCH: DS 1 ; Holds <,>=,>
DATMOD: DS 2 ; Holds date found for file
DAYS: ds 2 ; temporary buffers
YEARS: ds 1 ;
YEARS1: DS 1
MONTHS: DS 1
DAYS1: DS 1
ASCII: DS 5 ; holds date from system
ENDIF ;Z80DOS
DATA1 EQU $ ; End of area to initialize
LINCNT: DS 1
IF ZCPR33
Z3DRVL: DS 2 ; Points to Z33 max drv location
Z3USRL: DS 2 ; Points to Z33 max user location
Z3WHLL: DS 2 ; Points to Z33 wheel location
ENDIF ;ZCPR33
IF NDIRS
NAMADR: DS 2 ; Named Directory Buffer Address
NUMDIR: DS 1 ; Number of entries
CURDIR: DS 1 ; NDR Check counter
ENDIF ; NDIRS
NEWPTR: DS 2 ; Start of second table
XPOINT: DS 2
OUTBUF: DS 128 ; Output file buffer
;
; BDOS equates
;
BDOS EQU 0005H ; Entry Point for BDOS calls
FCB EQU 005CH ; Default FCB Address
TBUF EQU 0080H ; Default DMA Address
RDCON EQU 1 ; Console input
WRCON EQU 2 ; Console output
LIST EQU 5 ; List output
PRINT EQU 9 ; Print string
CONST EQU 11 ; Get console status
CPMVER EQU 12 ; Return CP/M version
RESET EQU 13 ; Reset disk system
SELDSK EQU 14 ; Select disk
OPEN EQU 15 ; Open file
CLOSE EQU 16 ; Close file
SRCHF EQU 17 ; Search for first
SRCHN EQU 18 ; Search for next
READ EQU 20 ; Read sequential
WRITE EQU 21 ; Write sequential
MAKE EQU 22 ; Make file
CURDSK EQU 25 ; Return current disk
STDMA EQU 26 ; Set DMA Address
DSKALL EQU 27 ; Get address of allocation vector
DSKPAR EQU 31 ; Get address of disk parameters
STUSER EQU 32 ; Set/get user number
IF ZRDOS
ZRDVER EQU 48 ; Return version (ZRDOS)
SETWBT EQU 50 ; Set warm boot trap (ZRDOS)
RESWBT EQU 52 ; Reset warm boot trap (ZRDOS)
ENDIF ; ZRDOS
DS 60 ; Stack area
STACK: DS 2 ; Old stack pointer
ORDER EQU $ ; Order table starts here
END