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
/
Z3-33
/
Z33MAKE.LBR
/
Z33MAKE.ZZ0
/
Z33MAKE.Z80
Wrap
Text File
|
2000-06-30
|
38KB
|
1,341 lines
; PROGRAM: Z33MAKE.Z80
; based on MAKE26, by various authors
; AUTHOR: Fred Haines
; DATE: November 24, 1987
; PURPOSE: to change the user number of designated files on a designated
; drive to a different user number. Z33MAKE may be assembled to
; load and run in high memory.
; Z33MAKE does not copy files and delete the originals; only the user number
; byte in the disk directory is changed to reflect the new user number.
; The program also has options to set file attributes of read-only, read-
; write, system, directory, and archive. Files can also be erased or unerased.
; The code assumes that the track and sector are set by the BDOS search
; functions and uses a simple BIOS write to update the directory. Before using
; this program, test it on a garbage disk to make sure that it works with your
; system.
; Z33MAKE has been adapted from MAKE v2.6 by the addition of a Z33 type 3
; header which allows it to be assembled to load and run in high memory. The
; history below refers to the versions of MAKE:
; VERSION 1.0 - 07/05/81 R.E.D.
; 1.1 - 07/15/81 R.E.D.
;
; 1.2 - 8/1/82
; ENHANCED FILE NAME DISPLAY.
; KEN LOVETT
; 1.3 - 8/6/83
; FIXED BUG WHICH CAUSED LAST CHAR IN FILE SPEC TO
; BE NON-SIGNIFICANT.
; KEN LOVETT
; 2.0 - 8/7/83
; ADDED OPTIONS TO SET R/O, R/W, SYS, DIR FLAGS. ALSO
; ERASE AND UNERASE FILES.
; KEN LOVETT
;
; 2.1 - 6/20/85
; Added (actually, just enabled - it was always there)
; full 32 (0-31) area capability, extended display routine
; to handle the higher user numbers, added a four-byte kludge
; of a display fix required by late-model Kaypros and merely
; harmless otherwise, other minor display stuff.
; Bruce Morgen
;
; 2.2 - 07/02/85
; Major cleanup of the code (which was highly unstructured and
; thus hard to read). Added check on user number of files so
; that the code will act only on files in the logged in area.
; There is still no checking to make sure that there is not
; already a file in the destination user area of the same name
; as the file that is being moved in.
; Jay Sage
;
; 2.3 - 07/14/85
; In ZCPR3 systems the CCP processes the DU: and named directory
; forms of directory specification. The drive value is returned
; in the usual way in the FCB, and the user number is placed in
; the S1 byte. Version 22Z of MAKE allows the syntax:
;
; MAKE DIR:AFN OPTION
;
; The files to be operated on can be specified using the full
; ZCPR3 format. The option can even take the DIR: form with a
; named directory. The ZCPR3 equate determines whether a
; ZCPR3 version or a standard version will be assembled.
; For some reason, even though there is no change in allocation,
; performing any write to the directory sets the disk to R/O
; status. I have changed the code I originally put it to
; reset the disk system whenever any write has occurred. I had
; not noticed this problem because I use the ZRDOS replacement
; for the BDOS, and it automatically relogs changed disks.
; Jay Sage
;
; 2.4 - 06/15/86
; Added ability to SET or RESET the ARCHIVE bit, and added
; the WHEEL conditional, which makes MAKE disappear
; (echoes: MAKE?) unless the wheel byte is set.
; Michael Conley
;
; 2.5 - (an obsolete version # observed in the Chicago area dated
; 1984 - skipped to avoid confusion.
;
; 2.6 - 07/22/86
; Added "All users" switch for any options not involving a
; user number. A number sign after the selected option
; makes it operate on ALL user areas, not just the current
; one. (e.g., MAKE *.BAK E# -- would erase all .BAK files
; in all user areas.)
; Michael Conley
;
; Z33MAKE 1.0 - 11/24/87
; Added type 3 header for Z33, removed conditionals for
; CPM versions, changed wheel error message, and altered help
; screen to reflect change to Z33 utility and display load
; address if linked to load and run in high memory.
; Fred Haines
;=============================================================================
; P R O G R A M E Q U A T E S
;=============================================================================
FALSE EQU 0
TRUE EQU NOT FALSE
; User Setable Equates
WHEEL EQU TRUE ;true to test wheel byte before running
WHLADR EQU 0FDFFH ;wheel byte location
CIM EQU FALSE ;true if file to be linked for high memory
LDADDR EQU 98 ;set to address at which program is to be
;linked times 1000h, i.e., 98 = 9800h
; Standard Equates
VERSION EQU 10
BDOS EQU 0005H ;BDOS entry address
DMAADDR EQU 0080H ;default CP/M file buffer
FCB EQU 005CH ;default CP/M FCB
TFCB EQU 006CH ;temporary FCB
Z3ENV EQU 0FE00H ;ZCPR3 environment address filled in by Z3INS
CR EQU 0DH ;(z3env not presently needed anyway)
LF EQU 0AH
TAB EQU 09H
BELL EQU 07H
;=============================================================================
; M A I N P R O G R A M C O D E
;-----------------------------------------------------------------------------
; TYPE 3 HEADER
; Code modified as suggested by Charles Irvine to function correctly with
; interrupts enabled. Program will abort with an error message when not
; loaded to the correct address (attempt to run it under CP/M or Z30).
ENTRY:
jr start0 ; Must use relative jump
defb 0 ; Filler
db 'Z3ENV',3 ; Type-3 environment
Z33ENV:
dw z3env ; Filled in by Z33
dw entry ; Intended load address
START0:
ld hl,0 ; Point to warmboot entry
ld a,(hl) ; Save the byte there
di ; Protect against interrupts
ld (hl),0c9h ; Replace warmboot with a return opcode
rst 0 ; Call address 0, pushing RETADDR onto stack
RETADDR:
ld (hl),a ; Restore byte at 0
dec sp ; Get stack pointer to point
dec sp ; ..to the value of RETADDR
pop hl ; Get it into HL and restore stack
ei ; We can allow interrupts again
ld de,retaddr ; This is where we should be
xor a ; Clear carry flag
push hl ; Save address again
sbc hl,de ; Subtract -- we should have 0 now
pop hl ; Restore value of RETADDR
jr z,start ; If addresses matched, begin real code
ld de,notz33msg-retaddr ; Offset to message
add hl,de
ex de,hl ; Switch pointer to message into DE
ld c,9
jp 0005h ; Return via BDOS print string function
NOTZ33MSG:
defb 'Not Z33+$' ; Abort message if not Z33-compatible
;-----------------------------------------------------------------------
START:
;set up local stack pointer
LD HL,0 ;get CP/M stack pointer
ADD HL,SP
LD (OLDSTK),HL ;save it for later return
LD SP,NEWSTK ;set up new local stack
;perform setup tasks
LD A,(WHLADR) ;get wheel byte
OR A ;is it set?
JP Z,EREXIT ;no/don't run
CALL SIGNON ;print signon message
CALL CHKHLP ;see if help requested and go there if so
CALL INIT ;set up data areas
CALL SETDU ;handle current and specified DU areas
CALL GETOPT ;get option from command line (abort if bad)
CALL CHKRO ;abort if destination drive is R/O and option
;..requests change in files
;begin main work of program
CALL SRCHF ;locate first directory entry (abort if none)
LOOP:
CALL SETPTR ;set DMAPTR to point to disk directory FCB
CALL CHKFIL ;check for applicable file
CALL NC,CALLOPT ;if applicable file, process option
NEXTFIL: ;go on to next file
LD HL,DIRCODE ;point to the directory code
INC (HL) ;increase it one
LD A,(HL) ;get new value
CP 04 ;check for four FCB entries completed
JP NZ,LOOP ;if not, go back and continue
;process this group of four files and go on
;to next
LD HL,CHGFLAG ;point to change flag
LD A,(HL) ;get it into A
LD (HL),0 ;reset it
OR A ;set flags from original value
CALL NZ,WRTDE ;if changes were made, write the buffer back
;sequence through files to get new buffer-full of FCB's
SRNXT:
LD DE,AMBFIL ;point to any-match FCB
LD C,12H ;BDOS search-next function
CALL BDOS
CP 0FFH ;see if end of entries
JP Z,QUIT ;quit if no more files
CP 0 ;loop until buffer is updated by BDOS
JP NZ,SRNXT ;jump until dircode is zero
LD (DIRCODE),A ;save the 0 in dircode
JP LOOP ; and loop again
;=============================================================================
; O P T I O N P R O C E S S I N G R O U T I N E S
;-----------------------------------------------------------------------------
; Set the file attribute to SYS. If the file was not already SYS, then the
; CHGFLAG is set to indicate the need later to write the modified sector out
; to disk.
SETSYS:
LD HL,(DMAPTR) ;point to disk directory FCB entry
LD DE,10 ;offset 10 to DIR/SYS byte
ADD HL,DE
LD A,(HL) ;get the SYS/DIR byte
OR A ;test current state of SYS bit
CALL P,SETCHGFL ;if not already SYS, set the change flag
OR 80H ;make sure it is set
LD (HL),A ;write modified byte back out
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; Set the file attribute to DIR. If the file was not already DIR, then the
; CHGFLAG is set to indicate the need later to write the modified sector out
; to disk.
SETDIR:
LD HL,(DMAPTR) ;point to disk directory FCB entry
LD DE,10 ;offset 10 to SYS/DIR byte
ADD HL,DE
LD A,(HL)
OR A ;sign flag shows state of SYS bit
CALL M,SETCHGFL ;if not already DIR, set change flag
AND 7FH ;clear the DIR bit
LD (HL),A ;write modified byte back to buffer
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; Set the file attribute to R/O. If the file was not already R/O, then the
; CHGFLAG is set to indicate the need later to write the modified sector out
; to disk.
SETRO:
LD HL,(DMAPTR) ;point to disk directory FCB entry
LD DE,9 ;offset 9 to R/O-R/W byte
ADD HL,DE
LD A,(HL)
OR A ;test current state of R/O bit
CALL P,SETCHGFL ;if not already R/O, set the change flag
OR 80H ;make sure it is set
LD (HL),A ;write modified byte back out
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; Set the file attribute to R/W. If the file was not already R/W, then the
; CHGFLAG is set to indicate the need later to write the modified sector out
; to disk.
SETRW:
LD HL,(DMAPTR) ;point to disk directory FCB entry
LD DE,9 ;offset 9 to R/O-R/W byte
ADD HL,DE
LD A,(HL)
OR A ;sign flag shows state of R/O-R/W bit
CALL M,SETCHGFL ;if not already R/W, set change flag
AND 7FH ;clear the R/O bit
LD (HL),A ;write modified byte back to buffer
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; Set the file attribute to ARC. If the file was not already ARC, then the
; CHGFLAG is set to indicate the need later to write the modified sector out
; to disk.
SETARC:
LD HL,(DMAPTR) ;point to disk directory FCB entry
LD DE,11 ;offset 10 to ARCHIVE byte
ADD HL,DE
LD A,(HL) ;get the ARCHIVE byte
OR A ;test current state of ARC bit
CALL P,SETCHGFL ;if not already ARC, set the change flag
OR 80H ;make sure it is set
LD (HL),A ;write modified byte back out
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; RESET the ARCHIVE file attribute. If the file was already ARC, then the
; CHGFLAG is set to indicate the need later to write the modified sector out
; to disk.
SETNRC:
LD HL,(DMAPTR) ;point to disk directory FCB entry
LD DE,11 ;offset 10 to ARCHIVE byte
ADD HL,DE
LD A,(HL)
OR A ;sign flag shows state of ARC bit
CALL M,SETCHGFL ;if it was ARC, set change flag
AND 7FH ;clear the ARC bit
LD (HL),A ;write modified byte back to buffer
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; Erase the file by writing E5 as the user number tag. We know that the file
; is not already erased because of the work of subroutine CHKFIL earlier.
; Therefore, we must set the change flag to show the need to write the sector
; back out to disk.
ERASE:
LD HL,(DMAPTR)
LD (HL),0E5H
CALL SETCHGFL ;show need to write sector back to disk
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; Unerase the file by writing the current user number into the tag byte in
; place of the E5. The comments under ERASE apply here, too.
UNERA:
LD A,(DEFUSR) ;get logged in user number
LD HL,(DMAPTR)
LD (HL),A ;put it into disk directory user # tag
CALL SETCHGFL ;show need to write sector back to disk
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; Change the user number of the file.
CHUSER: LD A,(OPTION) ;get user number
LD HL,(DMAPTR) ;point to place to put it
LD (HL),A ;put new user number in directory
CALL SETCHGFL ;show need to write sector back out to disk
CALL REPORT ;report the new file status
RET
;-----------------------------------------------------------------------------
; This code reports the attributes of the files acted on and, if required,
; the erased or unerased status. This code is called directly by the blank
; option and indirectly by all the other option processors after they have
; finished performing their changes on the files.
REPORT: CALL PRTFN ;print the file name
CALL ILPRT ;print spacer and equal sign
DB ' = ',0
CALL PRTOPT ;print the option letter or number
LD C,3 ;put in three more blank spaces
CALL PRTBLK
CALL PRTATTR ;print file attributes
LD A,(OPTION) ;see if files erased
CP 'E'
CALL Z,PRTERA ;if so, print erased message
LD A,(OPTION)
CP 'U' ;see if files unerased
CALL Z,PRTUNE ;if so, print unerased message
RET
;=============================================================================
; P R O G R A M F L O W R O U T I N E S
;-----------------------------------------------------------------------------
; CALLOPT
; This routine uses the value of OPTION to look up the processing routine
; to which to branch.
CALLOPT:
LD HL,JMPTBL ;point to jump table
LD A,(OPTION) ;get user number or option letter
LD B,A ;save it in B
LOOKUP: LD A,(HL) ;get option letter from table
INC HL ;point to jump address
OR A ;end of table?
JP Z,JMPOPT2 ;if so, jump
CP B ;do we match a table entry
JP Z,JMPOPT1 ;if so, go to code to get jump address
INC HL ;else jump over jump address to
INC HL ;..next option character
JP LOOKUP ;and try again
JMPOPT1:
LD A,(HL) ;get low part of jump address into A
INC HL ;point to high part of address
LD H,(HL) ;get it into H
LD L,A ;jump address is in HL
JP (HL) ;jump to it
JMPOPT2:
LD HL,CHUSER ;default to change user routine
JP (HL) ;jump to it
JMPTBL: DB ' '
DW REPORT
DB 'S'
DW SETSYS
DB 'D'
DW SETDIR
DB 'R'
DW SETRO
DB 'W'
DW SETRW
DB 'A'
DW SETARC
DB 'N'
DW SETNRC
DB 'E'
DW ERASE
DB 'U'
DW UNERA
DB 0 ;end of table mark
;-----------------------------------------------------------------------------
; QUIT
; This code sends a CRLF to the console, restores the original CP/M stack,
; and returns to CP/M. If indicated by the reset flag, it resets the disk
; system. The logged DU area when the program was invoked is restored. The
; entry point QUIT2 is used by code (CHKHLP and CHKVER) that have not changed
; the logged in directory.
QUIT: CALL CRLF
;log in the original drive/user
LD A,(DEFDRV) ;get original default drive
CALL LOGDRV ;log it in
LD A,(DEFUSR) ;get original default user
CALL LOGUSR ;log it in
;see if we need to reset the disk system
QUIT1: LD A,(RSTFLAG)
OR A ;if reset flag is clear
JP Z,QUIT2 ;..we can skip disk system reset
;reset the disk system
LD C,0DH
CALL BDOS
;restore the original stack
QUIT2: LD HL,(OLDSTK) ;get original stack pointer
LD SP,HL ;set it up
RET ;back to CP/M
EREXIT:
CALL ILPRT ;no wheel error message
DB ' Wheel is OFF',0
JP QUIT2
;=============================================================================
; F I L E S E L E C T I O N S U B R O U T I N E S
;-----------------------------------------------------------------------------
; CHKFIL
; This subroutine checks to see whether or not the FCB pointed to in the
; DMA buffer is one that should be acted on. If not, the routine returns
; with the zero flag set.
CHKFIL: CALL CHKUN ;check user number and erased status of file
RET C ;return with carry set to skip file
CALL CHKFN ;next check the file name for a match
RET ;return showing status of name match
;-----------------------------------------------------------------------------
; CHKUN
; This subroutine checks the user number status of a file and sets the carry
; flag if the file should be skipped over. If the option is UNERASE and the
; file is not an erased file, it should be skipped. If the option is not
; unerase and the file is an erased file, then likewise it should be skipped.
; Finally, if the file is in a user number other than the logged in user, it
; should also be skipped.
CHKUN: ;test file erased status
LD HL,(DMAPTR) ;point to user number tag of file
LD A,(HL) ;get the tag
CP 0E5H ;carry flag set if not erased
PUSH AF ;save flag
;test program option status
LD A,(OPTION) ;get the option
CP 'U' ;is it unerase?
JP NZ,CHKUN1 ;if not, skip to CHKUN1
;case of unerase option
POP AF ;carry flag set if not erased
RET ;file not erased will be skipped
;case of option other than unerase
CHKUN1: POP AF
CCF ;carry flag set if file erased
RET C ;erased file will be skipped
;now check for user number in source area
LD A,(ALLUSR) ;see if "all users" was requested
CP '#' ;
JP Z,CHKUN2 ;if so, skip over compare...
LD A,(SRCUSR) ;get source user number
CP (HL) ;compare to file tag
RET Z ;if OK, return (carry is clear)
SCF ;else set carry
CHKUN2:
RET ;..and return
;-----------------------------------------------------------------------------
; CHKFN
; This subroutine compares the name of the file in the FCB in the DMA buffer
; with the specification from the command line.
CHKFN: ;set up pointers and character count
LD HL,(DMAPTR) ;get pointer to FCB in DMA buffer
INC HL ;point to first character in the name
LD DE,FCB+1 ;set DE to name in FCB from command line
LD C,0BH ;load count for compare
CP1: LD A,(DE) ;get fcb command line character
CP '?' ;see if anything matches
JP Z,MATCH ;if it is '?', consider it a match
SUB A,(HL) ;get difference (see next instruction)
AND 7FH ;clear attribute bit
JP Z,MATCH ;if zero, characters match
SCF ;else set carry
RET ;..and return
MATCH: INC DE ;point to next characters
INC HL
DEC C ;decrease count of characters
JP NZ,CP1 ;loop until zero
RET ;carry is clear showing names match
;=============================================================================
; D I S K O P E R A T I O N S U B R O U T I N E S
;-----------------------------------------------------------------------------
; SRCHF
; This subroutine uses the fully ambiguous file spec at AMBFIL to locate the
; first directory entry on the disk. The directory code (0-3) is saved. If
; no directory entry is found, then the program gives a message and branches
; to QUIT for a prompt return.
SRCHF: LD DE,AMBFIL ;point to match any filename.typ
LD C,11H ;bdos search first function
CALL BDOS ;do it
LD (DIRCODE),A ;save directory code
CP 0FFH ;see if end of entries
RET NZ ;if something found, return
CALL ILPRT ;else give a message
DB BELL,CR,LF
DB 'No Files On Disk',CR,LF,0
JP QUIT
;-----------------------------------------------------------------------------
; WRTDE
; This routine writes the directory buffer back to the disk. I also sets the
; reset flag so that the disk system will be reset on program termination.
WRTDE: LD HL,RSTFLAG ;point to the flag
LD (HL),0FFH ;set the flag
LD C,1H ;set BIOS write to directory
; C = 0 write to allocated
; C = 1 write to directory
; C = 2 write to unallocated
CALL WRITE ;do the write
OR A ;check for error
RET Z ;if none, return
CALL ILPRT
DB BELL
DB CR,LF
DB 'Bad Sector Write Error',CR,LF,0
JP QUIT
;-----------------------------------------------------------------------------
; WRITE
; This routine is filled in during the operation of the program and performs
; a direct BIOS sector write operation on the currently selected track and
; sector.
WRITE: JP 0000 ;vector to bios write routine
;=============================================================================
; P R I N T I N G R O U T I N E S
;-----------------------------------------------------------------------------
; PRTFN
; This subroutine displays (at the beginning of the next line of the screen)
; the name of the file pointed to in the DMA buffer.
PRTFN: CALL CRLF ;print cr/lf
LD HL,(DMAPTR) ;address of file fcb
INC HL ;skip to file name
LD DE,BLNKCNT ;point to blanks counter
EX DE,HL ;exchange pointers
LD (HL),0 ;preset blank count to zero
LD C,8 ;length of file name
CALL PRTSTR ;print the name first
LD A,'.' ;print the period
CALL CHAROUT
LD C,3 ;now print the file type
CALL PRTSTR
LD C,(HL) ;get number of blanks needed for fill
CALL PRTBLK ;print the blanks
RET
;-----------------------------------------------------------------------------
; PRTOPT
; This subroutine prints out the option as a letter or as a number as
; appropriate.
PRTOPT: LD A,(OPTION) ;get the option value
CP 20H ;if it's a user number, carry will be set
JP NC,CHAROUT ;if not number, just print the character
LD B,'0'-1 ;preset for two-digit calculation later
CP 10 ;see if single digit
JP NC,TWODIG ;if not, print two digits
ADD '0' ;else convert to ASCII
JP CHAROUT ;and print it
TWODIG: INC B ;count tens digit in B
SUB 10 ;keep subtracting 10 until carry is set
JP NC,TWODIG
ADD 10 ;get remainder (units digit) back
LD C,A ;save it in C
LD A,B ;print tens digit
CALL CHAROUT
LD A,C ;print units digit
ADD '0'
JP CHAROUT
;-----------------------------------------------------------------------------
; PRTATTR
; This subroutine prints the attribute status (SYS or DIR and R/O or R/W)
; of the file currently being worked on.
PRTATTR:
LD HL,(DMAPTR) ;point to file FCB
LD DE,9 ;offset to R/O-R/W byte
ADD HL,DE
PUSH HL ;save pointer for reuse below
LD A,(HL)
RLA ;move R/O bit into carry
PUSH AF ;save flags
CALL C,PRTRO ;if carry, print read-only
POP AF ;get flags back to test again
CALL NC,PRTRW ;if not carry, print read-write
POP HL ;get pointer back
INC HL ;point to SYS/DIR byte
PUSH HL ;save pointer for reuse below
LD A,(HL)
RLA ;move SYS/DIR bit into carry
PUSH AF ;save flags
CALL C,PRTSYS ;if carry, print SYS
POP AF ;get them back
CALL NC,PRTDIR ;if not carry, print DIR
POP HL
INC HL
LD A,(HL)
RLA ;move ARCHIVE bit into carry
PUSH AF ;save flags
CALL C,PRTARC ;if carry, print ARC
POP AF ;get them back
CALL NC,PRTNRC ;if not carry, print Non-ARC
RET
;-----------------------------------------------------------------------------
; MESSAGE PRINTING ROUTINES
PRTRO: CALL ILPRT ;file is read-only
DB ' R/O',0
RET
PRTRW: CALL ILPRT ;file is read-write
DB ' R/W',0
RET
PRTSYS: CALL ILPRT ;file has SYS attribute
DB ' SYS',0
RET
PRTDIR: CALL ILPRT ;file has DIR attribute
DB ' DIR',0
RET
PRTARC: CALL ILPRT ;file has ARC attribute
DB ' ARCHIVE',0
RET
PRTNRC: CALL ILPRT ;file has NO ARC attribute
DB ' Non-ARC',0
RET
PRTERA: CALL ILPRT ;file erased
DB ' *** ERASED ***',0
RET
PRTUNE: CALL ILPRT ;file unerased
DB ' *** UNERASED ***',0
RET
;-----------------------------------------------------------------------------
; HELP
; This code displays the built in help screen and then jumps to QUIT to
; return to CP/M.
HELP: CALL ILPRT
DB 'Syntax: ',CR,LF
DB ' MAKE [dir:]filename.typ o[#]',CR,LF
DB 'Options: ',CR,LF
DB ' DIR: move files to named directory DIR',CR,LF
DB ' nn move files to user nn (0-31)',CR,LF
DB ' S make files System',CR,LF
DB ' D make files Directory',CR,LF
DB ' R make files Read/Only',CR,LF
DB ' W make files Read/Write',CR,LF
DB ' A make files Archive',CR,LF
DB ' N make files Non-Archive',CR,LF
DB ' E erase specified files',CR,LF
DB ' U unerase specified files',CR,LF
DB ' # all user areas',CR,LF,0
JP QUIT2
;=============================================================================
; G E N E R A L - P U R P O S E S U B R O U T I N E S
;-----------------------------------------------------------------------------
; CRTOUT
; This subroutine sends the character in register A to the console. Registers
; BC, DE, and HL are preserved.
CHAROUT:
PUSH HL ;save registers
PUSH DE
PUSH BC
LD E,A ;get character into E
LD C,06 ;BDOS direct console I/O
CALL BDOS
POP BC ;restore registers
POP DE
POP HL
RET
;-----------------------------------------------------------------------------
; CRLF
; This routine sends a carriage return and linefeed to the console.
CRLF: CALL ILPRT
DB CR,LF,0
RET
;-----------------------------------------------------------------------------
; FILL
; This subroutine fills memory starting at HL for a length B with the byte
; in A.
FILL:
LD (HL),A
INC HL
DEC B
JP NZ,FILL
RET
;-----------------------------------------------------------------------------
; ILPRT
; This subroutine prints the string that follows its call. The string must
; be terminated with a null (0).
ILPRT: POP HL ;get address following call into HL
ILPRT1: LD A,(HL) ;get character from message
INC HL ;point to next character
OR A ;test for null indicating end of message
JP Z,ILPRT2 ;if end, fix up return address
LD E,A ;have BDOS send character it to console
LD C,2
PUSH HL ;save pointer to string
CALL BDOS
POP HL ;restore pointer
JP ILPRT1 ;process it
ILPRT2: PUSH HL ;set up return address to just past message
RET
;-----------------------------------------------------------------------------
; PRTSTR
; This subroutine prints a string of characters pointed to by DE. The number
; of characters is in the C register. Blanks are not printed; instead, the
; blanks counter pointed to by HL is incremented.
PRTSTR: LD A,(DE) ;get character
CP ' ' ;see if it is a blank
CALL Z,UPCOUNT ;if so, up the count
CALL NZ,CHAROUT ;if not, output the character
INC DE
DEC C ;check count
JP NZ,PRTSTR
RET
UPCOUNT:
PUSH AF ;save flags
INC (HL) ;increase the blank counter
POP AF ;restore flags
RET
;-----------------------------------------------------------------------------
; PRTBLK
; This subroutine prints blank spaces given by the count in C. The routine
; will work even for a count of zero.
PRTBLK: INC C ;turn 0 into 1
PRTBL1: DEC C ;check count
RET Z ;return if count exhausted
LD A,' ' ;set character to print
CALL CHAROUT
JP PRTBL1
;=============================================================================
; S E T U P S U B R O U T I N E S
;-----------------------------------------------------------------------------
; SIGNON
; This subroutine displays the program signon message.
SIGNON: CALL ILPRT
DB 'Z33MAKE Version '
DB VERSION / 10 + '0'
DB '.'
DB VERSION MOD 10 + '0'
IF CIM
DB ' (loaded at '
DB LDADDR / 10 + '0'
DB LDADDR MOD 10 + '0'
DB '00h)'
ENDIF ; CIM
DB CR,LF,0
RET
;-----------------------------------------------------------------------------
; CHKHLP
; This subroutine checks to see if the user has invoked the program in a
; way to request the built-in help screen. The help screen is shown if the
; command has no tail or if the tail begins with a slash.
CHKHLP: LD A,(FCB+1) ;get first character of first parameter
CP ' ' ;no name?
JP Z,HELP ;if so, go to HELP
CP '/' ;parameter starts with slash?
JP Z,HELP ;if so, go to HELP
RET ;return with flag set appropriately
;-----------------------------------------------------------------------------
; INIT
; This subroutine initializes the data areas in the program so that GO
; command will re-run the program correctly.
INIT: XOR A ;zero the accumulator
LD (CHGFLAG),A ;preset control flags
LD (RSTFLAG),A
LD (DIRCODE),A
LD HL,AMBFIL2
LD B,16
CALL FILL ;clear the fcb
LD A,'?'
LD B,16
LD HL,AMBFIL
CALL FILL
LD HL,(0001) ;get warmboot address (base of bios + 3)
LD DE,27H ;offset for jump to bios write
ADD HL,DE ;compute address for write routine
LD (WRITE + 1),HL ;load our vector with this address
RET
;-----------------------------------------------------------------------------
; SETDU
; This subroutine gets and saves the values of the currently logged in drive
; and user area and the drive and user specified (if any) on the command line
; for the files to be operated on.
SETDU: ;get currently logged in user number
LD C,20H ;BDOS get/set user number function
LD E,0FFH ;get user flag
CALL BDOS
LD (DEFUSR),A
LD (SRCUSR),A ;save for now as source user also
;get the currently logged in drive
LD C,19H ;bdos get drive number function
CALL BDOS ;get drive number
LD (DEFDRV),A
INC A ;change range 1-16 and
LD (SRCDRV),A ;..save for now as source drive also
;now log in the drive and user in file spec
LD A,(FCB) ;get drive spec from FCB
OR A ;see if default specified
JP Z,SETDU1
LD (SRCDRV),A ;save source drive
SUB 1 ;get in range 0-15
CALL LOGDRV ;log in the drive
XOR A ;and change FCB to show default drive
LD (FCB),A
SETDU1:
LD A,(FCB+13) ;get user number from S1 byte
LD (SRCUSR),A ;save as source user area
CALL LOGUSR ;log in the user number
RET
;-----------------------------------------------------------------------------
; These two routines log in the drive or user number given in the A register.
; No registers are preserved.
LOGDRV: LD E,A
LD C,0EH
CALL BDOS
RET
LOGUSR: LD E,A
LD C,20H
CALL BDOS
RET
;-----------------------------------------------------------------------------
; GETOPT
; Process option specified on the command line. If there is an error, the
; routine jumps to HELP which in turn jumps to QUIT. If a named directory
; is specified for the destination on the command line, then its user number
; is obtained from address TFCB+13. The drive is checked to make sure that
; the destination is on the same drive.
GETOPT:
;check for destination specified using named directory
LD A,(TFCB) ;check for drive number
OR A ;if zero, no DIR: or DU: given
JP Z,GETOPT1
;check for correct drive spec
LD HL,SRCDRV ;point to source drive value
CP (HL)
JP NZ,BADDRV ;if not the same, jump to bad drive message
;get the user number
LD A,(TFCB + 13)
LD (OPTION),A ;store user number as option
JP CHKNUM ;check for valid user number
BADDRV: CALL ILPRT ;destination and source drives not same
DB BELL
DB CR,LF,LF
DB 'Source and Destination Drives',CR,LF
DB 'Must be the Same'
DB CR,LF
DB 0
JP QUIT
GETOPT1:
LD HL,TFCB ;point to parsed second parameter
LD A,(HL) ;make sure it wasn't of form 'D:'
OR A ;drive byte should be zero
JP NZ,BADOPT
INC HL ;now look at data entered
LD A,(HL) ;get the first character
CALL GETNUM ;try to read it as a number
JP C,LETTER ;if not, must be a letter or bad
LD B,A ;save digit in B
LD (OPTION),A ;..and as interim option
INC HL ;try next character
LD A,(HL)
CP ' ' ;if it is a blank
JP Z,CHKNUM ;..go to test user number value
CALL GETNUM ;see if second character is a number
JP C,BADOPT ;if not, we have a bad option spec
LD C,A ;save second digit
LD A,B ;get first digit back
ADD A,A ;double it three times to make 8x
ADD A,A
ADD A,A
ADD A,B ;now add original in twice to make 10x
ADD A,B
ADD A,C ;finally, add in second digit
LD (OPTION),A ;..and save the final result
;check for valid user number (in range and not same
;as logged in user number)
CHKNUM: LD A,(OPTION) ;make sure we have the user number
CP 32 ;test for valid user number range
JP NC,BADNUM
LD HL,SRCUSR ;see if same as source user
CP (HL)
JP Z,SAMENUM ;if so, give message
RET
LETTER: ;check for valid letter option
PUSH AF ;save option letter
INC HL ;check whether option followed by '#'
LD A,(HL)
CP '#'
JP NZ,LETTER0 ;not "all users" switch, don't save it
LD (ALLUSR),A
LETTER0:
POP AF ;get option character back
LD HL,OPTLIST ;point to list of valid options
LD C,(HL) ;get number of options in list
LETTER1: ;loop through them checking
INC HL
CP (HL) ;compare to list entry
JP Z,GOODOPT ;if it matches, we have a good option
DEC C ;else, count down
JP NZ,LETTER1 ;..and try again
JP HELP ;we get here if option is not valid
GOODOPT: ;we have a good option letter
LD (OPTION),A
RET
BADOPT: ;we have a bad option specifier
CALL ILPRT
DB BELL,CR,LF
DB TAB,'**** BAD OPTION SPECIFIER ****',CR,LF,0
JP HELP
BADNUM: ;we have an illegal user number
CALL ILPRT
DB BELL,CR,LF
DB TAB,'**** ILLEGAL USER NUMBER ****',CR,LF,0
JP HELP
SAMENUM: ;give message about already in that user area
CALL ILPRT
DB BELL,CR,LF
DB 'destination user number is the',CR,LF
DB 'same as the source user number'
DB CR,LF,0
JP QUIT
;subroutine to check for number character
;returns with carry set if not a number
GETNUM: CP '0' ;see if less than '0'
RET C ;if so, set carry flag as signal
CP '9'+1 ;see if more than '9'
CCF ;reverse sense of carry flag
RET C ;if >9, return with carry set
SUB '0' ;convert to number value
RET ;carry is clear
;list of valid options
OPTLIST:
DB ENDLIST-OPTLIST ;number of options in list
DB ' SDRWANEU' ;valid options
ENDLIST:
;-----------------------------------------------------------------------------
; CHKRO
; This routine checks to see if the destination drive is read-only. If it
; is, an appropriate error message is displayed and the program aborts with
; a jump to QUIT. If the option is display only (option = space char), then
; this test is skipped.
CHKRO: LD A,(OPTION) ;see if display option is in effect
CP ' '
RET Z ;if so, skip rest of test
LD C,1DH ;get R/O vector from BDOS
CALL BDOS
;calculate number of left-shifts needed
LD A,(SRCDRV) ;get the target drive number
CPL ;complement it (makes 255-SRCDRV)
ADD 17 ;makes A = 16 - SRCDRV (value 1-16)
;shift word in HL to put bit of R/O vector for
;specified drive into high bit position
CHKRO1: DEC A ;test for done
JP Z,CHKRO2 ;if so, jump
ADD HL,HL ;shift HL to left
JP CHKRO1 ;and loop
CHKRO2: ADD HL,HL ;move high bit into carry flag
RET NC ;if not R/O, return
CALL ILPRT ;else print R/O error message
DB BELL,CR,LF
DB 'Drive is set to R/O',CR,LF,0
JP QUIT ;abort program
;=============================================================================
; M I S C E L L A N E O U S R O U T I N E S
;-----------------------------------------------------------------------------
; SETPTR
; This subroutine uses the value of the directory code to calculate a pointer
; to the FCB in the DMA buffer. This is done by multiplying the directory code
; by 32 and adding it to the DMA address (DMAADDR). The result is saved in
; DMAPTR.
SETPTR:
LD A,(DIRCODE) ;get the directory code
ADD A,A ;offset by 32 bytes per entry
ADD A,A
ADD A,A
ADD A,A
ADD A,A
LD E,A ;move value into DE
LD D,0
LD HL,DMAADDR ;get buffer address
ADD HL,DE ;compute offset into buffer
LD (DMAPTR),HL ;save the address into the buffer
RET
;-----------------------------------------------------------------------------
; SETCHGFL
; This subroutine sets the change-flag to show that the directory sector
; has been modified and needs to be written out to disk.
SETCHGFL:
PUSH AF
LD A,0FFH ;set the sector change flag
LD (CHGFLAG),A
POP AF
RET
;=============================================================================
; D A T A A R E A
;-----------------------------------------------------------------------------
OLDSTK: ;place to keep old stack pointer
DS 2
BLNKCNT: ;count of blank characters in file name
DS 1
CHGFLAG: ;flag for change requiring write
DS 1
RSTFLAG: ;flag for need to reset disk system
DS 1
AMBFIL: ;working fcb
DS 16
AMBFIL2: ;space for rest of FCB
DS 19
OPTION: ;storage for new user number or option
DS 1
ALLUSR: ;storage for "all users" switch
DS 1
DIRCODE: ;storage for directory code (0-3)
DS 1
DMAPTR: ;address of FCB in DMA buffer
DS 2
DEFDRV: ;current default drive
DS 1
SRCDRV: ;source drive
DS 1
DEFUSR: ;current default user number
DS 1
SRCUSR: ;source user area from file spec
DS 1
DS 60 ;room for local stack
NEWSTK:
END