home *** CD-ROM | disk | FTP | other *** search
- ;CU.ASM - A PROGRAM TO MOVE FILES FROM ONE USER NUMBER TO ANOTHER
- ;
- ;CU v2.0 06/23/87 Richard Brewster
- ; R.D. 1 Box 46
- ; Brackney, PA 18812
- ;
- ;CHANGES: 1) Altered command syntax to require a period instead
- ; of a comma between source and destination user (e.g.
- ; 3.0 instead of 3,0). This allows proper operation
- ; under ZCPR, which does not format FCB2 (6CH) correctly
- ; using a comma as the delimiter. The second parameter
- ; which gives the source and dest user numbers now looks
- ; like a filespec, and should work under any CCP.
- ;
- ; 2) Added initialization of variables so that ZCPR
- ; GO [parameters] command can be used.
- ;
- ; 3) Added code to check for an existing file of the
- ; same name in the destination user area. If the file
- ; exists and is R/W, it is automatically deleted. If
- ; it exists and is R/O, the change operation is skipped.
- ; Appropriate messages are displayed.
- ;
- ; 4) Corrected display of the filename attributes of
- ; the source files.
- ;
- ; 5) Modified messages.
- ;
- ; 6) Moved video attributes into first sector for easy
- ; patching with DDT, EDFILE, SUPERZAP, etc.
- ;
- ;---------------------------------------------------------------
- ;
- ;CU original documentation
- ;
- ;From an idea by Aubrey Hutchinson of Pompano Beach, Florida
- ;published in Dr. Dobbs Journal, March 1983.
- ;See: Dr. Dobbs Clinic, page 82.
- ;
- ;Written by: Robert Wilcox
- ; 920 N. Washington
- ; Owosso, MI 48867
- ;Date written: 2 Mar 83
- ;Rewritten : 25 Mar 85 to show filenames as they are changed
- ; and allow for operator to be asked before each
- ; file operation. This revision was patterned
- ; after ERAQ, from which much of the code was
- ; borrowed.
- ;
- ;OPERATION: CU [dr:]FILENAME.TYPE s,d [/N]
- ;
- ;Where dr: is the drive designator (optional),
- ; s is the source user number, and
- ; d is the destination user number.
- ; N means don't ask before changing each file.
- ;
- ;Filename.typ may be ambiguous, same as with the ERA command.
- ;
- ;EXAMPLE:
- ; CU *.ASM 0,3 /N
- ;
- ;This would transfer all files of type ASM from user 0 to user 3
- ;without asking before each transfer.
- ;
- ;CAUTION: If a file already exists in the destination user area,
- ;it is possible with this program to create another one with
- ;the same name. Using the ERA command will then erase BOTH
- ;of them.
- ;
- ;NOTE: R/O files will be R/W after the transfer.
- ;
- ;*********************************************************************
- ;
- ;CP/M LOCATIONS
- BOOT EQU 00000H
- BDOS EQU 00005H
- FCB1 EQU 0005CH
- FCB2 EQU 0006CH
- ;
- ;CP/M FUNCTIONS
- CONIN EQU 1 ; Console in function
- TYPE EQU 2 ; Console type function
- PRINTF EQU 9 ; Print string function
- STATUS EQU 11 ; Console status function
- SEARCHF EQU 17 ; Search for first file
- SEARCHN EQU 18 ; Search for next file
- DELETE EQU 19 ; Delete file function
- CDISK EQU 25 ; Get current disk function
- SETDMA EQU 26 ; Set DMA function
- SETFIL EQU 30 ; Set file attributes
- USERF EQU 32 ; Get/set user
- ;
- ;ASCII EQUATES
- CTRLC EQU 3 ; Control - C
- TAB EQU 9
- CR EQU 13
- LF EQU 10
- ESC EQU 27
- ;
- MAXUSR: EQU 15 ; Highest valid user - can be
- ; made higher to 'hide' files
-
- ORG 100H
- START: JMP GO ;skip over video codes
- ;
- ; VIDEO ATTRIBUTE STRINGS
- ; Strings for video attributes are stored here, each ending with '$'
- ; for BDOS function 9. These can be patched using DDT, EDFILE, or
- ; SUPERZAP, using up to six chars each. The string MUST end with '$'!
- ;
- CLSMSG: DB '$$$$$$$' ; Clear screen
- ONSTR: DB '$$$$$$$' ; Reverse video start tag
- OFFSTR: DB '$$$$$$$' ; Reverse video end tag
- NITSTR: DB '$$$$$$$' ; Initialize scrn for reverse video
- ;
- GO: LXI H,PRTFLG ; dynamic itialization of storage area
- XRA A
- MVI B,17 ; number of bytes in storage area
- DCX H
- DOINIT: INX H
- MOV M,A
- DCR B
- JNZ DOINIT
- LXI H,BUFFER ; Initialize BUFPTR
- SHLD BUFPTR
- ;
- GETRDY: LHLD 1 ; get warm start entry point
- LXI D,-654H
- DAD D ; subtract 654h bytes
- SHLD LOCE5 ; save address for later
- MOV A,M ; check to see that byte there
- CPI 0E5H ; is E5
- JZ GETSET ; jump if it's there,
- LHLD 6 ; otherwise search thru
- FIND: INX H ; memory looking for
- MOV A,H ; the code for MVI M,E5, MVI C,xx
- CPI 0 ; If H=0 we have
- JZ BAD ; gone too far...
- MOV A,M ; Otherwise keep searching
- CPI 36H
- JNZ FIND
- INX H
- SHLD LOCE5
- MOV A,M
- CPI 0E5H
- JNZ FIND
- INX H
- MOV A,M
- CPI 0EH
- JZ GETSET
- JMP FIND
- ;
- BAD: LXI D,BADMSG ; print bad system msg
- CALL PRTSTR ; and return to CCP....
- RET
- ;
- GETSET: CALL INIT ; Initialize terminal if needed
- LDA FCB1+1
- CPI ' '
- JNZ NOWGO ; Jump if something was typed
- CALL CLRSCR ; No file spec'd, print help msg
- CALL REVON ; Reverse video on
- LXI D,PGMNAM ; Show the program name
- CALL PRTSTR
- CALL REVOFF ; Reverse video off
- LXI D,HLPMSG ; Help message
- CALL PRTSTR
- RET ; and return to CCP
-
- NOWGO: LXI H,FCB2+1 ; get source user #
- CALL GETNUM
- JC GOMORE ; if ok...
- BADNUM: LXI D,BADNR ; otherwise print bad number msg
- CALL PRTSTR ; and return to CCP
- JMP ABORT
- GOMORE: STA SOURCE ; save source user #
- MVI E,0FFH ; get current user #
- MVI C,USERF
- CALL BDOS
- STA USRNR ; save it
- LXI H,FCB2+9 ; look at file type for dest user
- MOV A,M
- CPI ' ' ; if nothing there
- JNZ GETDES
- LDA USRNR ; dest = current user
- JMP GOTDES
- GETDES: CALL GETNUM ; get dest user #
- JNC BADNUM ; quit if bad number...
- GOTDES: STA DEST
- MOV E,A ; otherwise dest to E
- LDA SOURCE ; get source # and quit if same as
- CMP E ; dest.
- JZ BADNUM ; otherwise...
- PUSH D
- PUSH PSW
- LDA FCB1 ; get drive designation
- ANA A
- JNZ GOTDRV
- MVI C,CDISK ; get default drive
- CALL BDOS ; returns 0 for drive A
- INR A ; fix it so 1 = drive A...
- GOTDRV: ADI '@' ; convert drive to ASCII
- STA DRIVE ; save it
- LHLD LOCE5 ; point to location of e5h in CCP.
- POP PSW
- POP D
- MOV M,E ; replace the e5h with the dest user #
- MOV E,A ; source to E for bdos call
- MVI C,USERF
- CALL BDOS ; set user to source
- LXI H,80H
- MOV B,M
- MOV A,B
- ORA A
- JZ NOTN ; Skip if no characters typed
- FINDN: INX H ; else check each character
- MOV A,M
- CPI '/' ; Was it "/"?
- JNZ FINDLP
- DCR B
- JZ NOTN
- INX H
- MOV A,M
- CPI 'N'
- JZ YESN
- FINDLP: DCR B
- JNZ FINDN
- JMP NOTN
- YESN: STA NAFLG
- NOTN: LXI D,DBUF
- MVI C,SETDMA
- CALL BDOS
- LXI D,FCB1
- MVI C,SEARCHF
- CALL BDOS
- INR A
- JZ FINIS
- GETFN: DCR A ; Adjust Accum to point to filename
- ADD A ; A=A*32
- ADD A
- ADD A
- ADD A
- ADD A
- LXI H,DBUF ; Point to disk buffer
- MVI D,0 ; Add in
- MOV E,A ; offset for
- DAD D ; this file
- XCHG ; DE points to filename in disk buffer
- LHLD BUFPTR ; Point HL to buffer
- MVI C,32 ; # of bytes to move
- MOVE: LDAX D ; Move filename from disk buffer
- MOV M,A ; to main buffer
- INX H
- INX D
- DCR C
- JNZ MOVE
- SHLD BUFPTR ; Update pointer
- LDA FCOUNT ; Add 1 to file count
- INR A
- STA FCOUNT
- LXI D,FCB1
- MVI C,SEARCHN ; Look for more files
- CALL BDOS
- INR A
- JNZ GETFN ; Get next filename
- LXI H,BUFFER ; All found, point to first one
- SHLD BUFPTR
- ;
- ;SEE IF WE TYPED "/N", IF YES, SAY "^C TO QUIT"
- LDA NAFLG
- CPI 'N'
- JNZ PRTFN
- CALL REVON
- LXI D,CTCMSG ; "^C" message
- CALL PRTSTR
- CALL REVOFF
- ;
- ;PRINT THE FILE SPECS
- PRTFN: CALL CRLF
- MVI A,8 ; Print 8 char's
- PUSH H
- INX H
- CALL TYPEA
- PUSH H
- MVI E,'.' ; Print a period
- CALL PCHAR
- POP H
- MVI A,3 ; Print file type
- CALL TYPEA
- MVI E,' ' ; And a couple of spaces
- CALL PCHAR
- MVI E,' '
- CALL PCHAR
- POP H
- LXI D,9 ; Look at
- DAD D ; the
- MOV A,M ; R/O bit
- RLC
- JNC NOTRO ; Skip if not R/O, else
- MVI A,0FFH ; set R/O flag
- STA ROFLG
- NOTRO: INX H ; Look at SYS bit
- MOV A,M
- RLC
- JNC NOTSYS ; Skip if not SYS, else
- MVI A,0FFH ; set SYS flag
- STA SYSFLG
- NOTSYS: LDA ROFLG
- MOV B,A
- LDA SYSFLG
- ORA B
- JNZ PRTATR ; Jump if file is R/O or SYS
- JMP DOIT
- ;
- PRTATR:
- MVI E,'(' ; Print file attributes
- CALL PCHAR
- LDA ROFLG
- ORA A
- JZ SKPRO ; Skip if not R/O
- LXI D,ROMSG ; "R/O"
- CALL PRTSTR
- SKPRO: LDA ROFLG
- MOV B,A
- LDA SYSFLG
- ANA B
- JZ SKPCOM ; print ',' if both 'R/O' and 'SYS'
- MVI E,','
- CALL PCHAR
- SKPCOM: LDA SYSFLG
- ORA A
- JZ SKPSYS
- LXI D,SYSMSG ; "SYS"
- CALL PRTSTR
- SKPSYS: MVI E,')'
- CALL PCHAR
- DOIT: MVI E,' '
- CALL PCHAR
- MVI E,' '
- CALL PCHAR
- CALL CHANGE
- MVI C,STATUS ; Check if anything typed
- CALL BDOS ; on keyboard
- ANA A
- JZ CONT ; Continue if not, else
- MVI C,CONIN ; get character
- CALL BDOS
- CPI CTRLC ; Abort if it was ^C
- JZ FINIS
- CONT: MVI A,0 ; Reset the flags
- STA ROFLG
- STA SYSFLG
- STA ASKFLG
- LDA FCOUNT ; Count down
- DCR A
- STA FCOUNT
- JZ FINIS ; If no more
- LHLD BUFPTR
- LXI D,32 ; Move to next filename
- DAD D
- SHLD BUFPTR
- JMP PRTFN
- ;
- ;SUBROUTINE ASK RETURNS Z IF OK TO CHANGE
- ASK: LDA NAFLG ; See if must ask to change file
- CPI 'N' ; 'N' = no ask
- RZ ; return if don't have to ask
- LDA ASKFLG ; check if asking to delete existing file
- INR A
- RZ ; if so, we've already asked - it's OK
- LXI D,QUERY ; Move this file?
- CALL PRTSTR
- MVI C,CONIN ; Get response
- CALL BDOS
- ANI 05FH ; Make upper case
- CPI CTRLC ; ^C to quit
- JZ FINIS
- CPI 'Y' ; Y to move the file
- RET
- ;
- CHANGE: LHLD BUFPTR ; Get drive and
- LDA FCB1 ; move it to buffer
- MOV M,A
-
- ;CHECK TO SEE IF A FILE OF THE SAME NAME EXISTS IN THE DEST USER AREA
- RWOK: PUSH H ;FCB
- LDA DEST ;get destination user
- MOV E,A
- MVI C,USERF
- CALL BDOS ;set user to destination
- POP D ;FCB
- PUSH D
- MVI C,SEARCHF ;search for file of same name
- CALL BDOS
- INR A
- JZ CHANG2 ;no file, so OK to change
- ;
- ;WE HAVE FOUND AN EXISTING FILE
- DCR A ;now check for R/O status
- ADD A ;compute index to name
- ADD A
- ADD A
- ADD A
- ADD A
- ADI 9 ;point to R/O bit
- LXI H,DBUF
- MVI D,0
- MOV E,A
- DAD D
- MOV A,M ;get it
- RLC
- JNC DDEST ;if it is R/W, continue
- ;
- CALL REVON
- LXI D,NODELE ;else print message and DO NOT change
- CALL PRTSTR
- CALL REVOFF
- POP H ;clean stack
- RET
- ;
- DDEST: CALL REVON
- LXI D,DELMSG
- CALL PRTSTR
- CALL REVOFF
- CALL ASK
- JZ DELOK
- POP H
- RET
- ;
- DELOK: MVI A,0FFH ;set flag for ASK routine
- STA ASKFLG
- LHLD LOCE5 ;have to put E5 back for real delete
- MVI M,0E5H
- POP D
- PUSH D
- PUSH H
- MVI C,DELETE
- CALL BDOS
- LDA NAFLG
- CPI 'N'
- JNZ HADASK ;if not querying, say that the file
- MVI E,' ' ; has been deleted
- CALL PCHAR
- CALL REVON
- LXI D,KILMSG
- CALL PRTSTR
- CALL REVOFF
- HADASK: POP H ;get back LOCE5
- LDA DEST ;and replace destination user
- MOV M,A
-
- ;CHANGE THE FILE'S USER BY CALLING THE DELETE FUNCTION
- CHANG2: LDA SOURCE ;restore source user
- MOV E,A
- MVI C,USERF
- CALL BDOS
- CALL ASK ; Now query if requested
- JZ CHANG3
- POP H ; Do not change
- RET
- CHANG3: POP H ;FCB
- PUSH H
- LDA ROFLG
- ORA A ; If source file is not R/O
- JZ CHNOW ; skip, else
- LXI D,9 ; set it to R/W
- DAD D
- MOV A,M
- ANI 7FH
- MOV M,A
- POP D
- PUSH D
- MVI C,SETFIL
- CALL BDOS
- CHNOW: POP D ;FCB
- MVI C,DELETE
- CALL BDOS
- LDA CHGCNT
- INR A
- STA CHGCNT
- RET
- ;
- ;PRINT THE NUMBER OF FILES CHANGED AND RETURN TO CCP
- ;(IF ABORTING, PRINT ABORT MSG FIRST)
- FINIS: CPI CTRLC
- CZ ABORT
- CALL CRLF
- CALL CRLF
- CALL REVON
- MVI E,TAB
- CALL PCHAR
- LDA CHGCNT
- MVI H,0
- MOV L,A
- CALL PT3DEC ; Print H/L as 3 decimal digits
- LXI D,REPORT ; "FILES CHANGED "
- CALL PRTSTR
- LDA CHGCNT ; See if any files were changed
- ANA A ; Skip if none changed, otherwise
- JZ FINIS1 ; show 'from here to there' message
- LXI D,FRMMSG ; "FROM "
- CALL PRTSTR
- LDA DRIVE
- MOV E,A
- CALL PCHAR
- XRA A
- STA PRTFLG
- LDA SOURCE
- MVI H,0
- MOV L,A
- CALL PT2DEC
- LXI D,TOMSG ; " TO "
- CALL PRTSTR
- LDA DRIVE
- MOV E,A
- CALL PCHAR
- XRA A
- STA PRTFLG
- LDA DEST
- MVI H,0
- MOV L,A
- CALL PT2DEC
- FINIS1: MVI E,TAB
- CALL PCHAR
- MVI E,TAB
- CALL PCHAR
- CALL REVOFF
- CALL CRLF
- ;RESTORE ORIGINAL USER AND REPLACE E5 ERASE CODE
- LHLD LOCE5
- MVI M,0E5H
- LDA USRNR
- MOV E,A
- MVI C,USERF
- CALL BDOS
- JMP BOOT
- ;
- ABORT: LXI D,ABTMSG ; "PROGRAM ABORTED"
- CALL PRTSTR
- RET
- ;
- ;Print H/L as 3 decimal digits
- PT3DEC: LXI B,-100 ; Divide by 100
- CALL DIVIDE
- MOV A,E ; Result to A
- STA PRTFLG ; Save it for later
- CPI 0 ; Suppress leading 0
- JZ PT2DEC
- CALL PRTDIG
- PT2DEC: LXI B,-10 ; Divide by 10
- CALL DIVIDE
- LDA PRTFLG ; Have we printed a char?
- ANA A
- MOV A,E
- JNZ NOSKIP ; Yes, then don't skip a 0
- CPI 0
- JZ LSTDIG
- NOSKIP: CALL PRTDIG
- LSTDIG: MOV A,L
- CALL PRTDIG
- RET
- ;
- ;GETNUM - GETS NUMBER FROM COMMAND LINE - QUITS AT NON-NUMERIC CHAR.
- ; RETURNS WITH CARRY SET IF VALID USER.
- ;
- GETNUM: MVI E,0 ; clear accumulation
- GNLOOP: MOV A,M ; get the character
- INX H ; point to next one
- CALL CKNR ; conv. to binary & check if valid #
- JC GNDONE ; if not 0-9
- MOV D,A ; save present digit of user #
- MOV A,E ; get prev. accumulation
- CALL X10 ; and mult it X 10
- ADD D ; add in present digit
- MOV E,A ; save the accumulated value
- JMP GNLOOP ; get next char.
- GNDONE: MOV A,E ; retrieve the digit
- CPI MAXUSR+1 ; see if valid - ret w/carry set if ok
- SHLD POINTR ; remember where we left off
- RET
- ;
- ;CKNR - Returns carry set if A is not a valid ASCII digit between 0 and 9
- ; otherwise returns carry=0 and A converted to the binary value of
- ; the digit
- ;
- CKNR: SUI '0'
- RC
- CPI 10
- CMC
- RET
- ;
- X10: ADD A ; A=A*2
- MOV B,A
- ADD A ; A=A*4
- ADD A ; A=A*8
- ADD B ; A=A*10
- RET
- ;
- ;TYPE NUMBER OF CHAR'S IN A REG
- TYPEA: PUSH PSW
- PUSH H
- MOV A,M
- ANI 7FH ;clear parity bit
- MOV E,A
- CALL PCHAR
- POP H
- POP PSW
- INX H
- DCR A
- JNZ TYPEA
- RET
- ;
- ;Divide HL/BC, returns quotient in E, remainder in L
- DIVIDE: MVI E,0FFH
- DVLOOP: INR E
- DAD B
- JC DVLOOP
- MOV A,B
- CMA
- MOV B,A
- MOV A,C
- CMA
- MOV C,A
- INX B
- DAD B
- RET
- ;
- ;PRINT VALUE IN ACCUM AS ASCII DIGIT
- PRTDIG: ADI 030H
- PUSH H
- MOV E,A
- CALL PCHAR
- POP H
- RET
- ;
- ;SEND CARRIAGE RETURN, LINEFEED TO CRT
- CRLF: MVI E,CR
- CALL PCHAR
- MVI E,LF
- PCHAR: PUSH H
- MVI C,TYPE
- CALL BDOS
- POP H
- RET
- ;
- ;CLEAR CRT SCREEN
- CLRSCR: LXI D,CLSMSG
- JMP PRTSTR
- ;
- INIT: LXI D,NITSTR ; Initialize CRT for reverse video
- JMP PRTSTR
- ;
- REVOFF: LXI D,OFFSTR ; Reverse video off
- JMP PRTSTR
- ;
- REVON: LXI D,ONSTR ; Reverse video on
- ;
- PRTSTR: PUSH H
- PUSH D
- MVI C,PRINTF
- CALL BDOS
- POP D
- POP H
- RET
- ;
- ;MESSAGES -
- CTCMSG: DB CR,LF,TAB,'Use ^C to quit',TAB,TAB,CR,LF,'$'
- QUERY: DB ' Change? $'
- ABTMSG: DB CR,LF,TAB,'Program aborted',TAB,TAB,CR,LF,'$'
- REPORT: DB ' file(s) changed $'
- FRMMSG: DB 'from $'
- TOMSG: DB ' to $'
- PGMNAM: DB TAB,TAB,'Change User v2.0 6/23/87',TAB,TAB,'$'
- HLPMSG: DB CR,LF,LF
- DB 'Usage:'
- DB TAB,TAB,'CU [d:]filespec s[.d] [/N]',CR,LF,LF
- DB TAB,'d: = optional drive',CR,LF
- DB TAB,'s = source user number (required)',CR,LF
- DB TAB,'d = optional destination user number',CR,LF
- DB TAB,'filespec may be ambiguous',CR,LF
- DB TAB,'optional /N for no query before each change',CR,LF,LF
- DB TAB,TAB,'CU *.ASM 0.3',CR,LF,LF
- DB TAB,'Changes all .ASM files '
- DB 'from user 0 to user 3.',CR,LF,LF
- DB TAB,TAB,'CU TEXT.FIL 5 /N',CR,LF,LF
- DB TAB,'Changes TEXT.FIL from user 5 to the current',CR,LF
- DB TAB,'user area, without query.',CR,LF,LF
- DB TAB,'Can delete an existing R/W file of the',CR,LF
- DB TAB,'same name in the destination user area.',CR,LF,'$'
- BADMSG: DB CR,LF,'CU cannot run on this system.',CR,LF,'$'
- BADNR: DB CR,LF,TAB,'Bad user number',CR,LF,TAB,'$'
- ROMSG: DB 'R/O$'
- SYSMSG: DB 'SYS$'
- NODELE: DB ' NOT CHANGED - R/O destination file $'
- DELMSG: DB ' EXISTING R/W DESTINATION FILE $'
- KILMSG: DB ' DELETED $'
- ;
- ;STORAGE AREA This area is dynamically initialized.
- ;
- PRTFLG: DB 0 ; Flag for decimal print routine
- DRIVE: DB 'A' ; Drive letter for messages
- SOURCE: DB 0 ; temp storage for source #
- DEST: DB 0 ; temp storage for destination #
- POINTR: DW 0 ; pointer to next character for dest user #
- LOCE5: DW 0 ; location of e5h in CCP
- USRNR: DB 0 ; Current user
- BUFPTR: DW BUFFER ; Buffer pointer storage
- FCOUNT: DB 0 ; File counter storage
- CHGCNT: DB 0 ; Changed file counter storage
- ROFLG: DB 0 ; Read-only flag (FF=R/O)
- SYSFLG: DB 0 ; SYSTEM flag (FF=SYS)
- NAFLG: DB 0 ; No ask flag (0=ask)
- ASKFLG: DB 0 ; FF if query concerns existing file
- DBUF: DS 128 ; Disk buffer
- BUFFER: DB 0 ; File name storage starts here
- ;
- END START