home *** CD-ROM | disk | FTP | other *** search
- ;CU.ASM - A PROGRAM TO MOVE FILES FROM ONE USER NUMBER TO ANOTHER
- ;
- ;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.
- ;
- ORG 00100H
- 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
- 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
- LHLD POINTR
- CALL GETNUM ; get dest user #
- JNC BADNUM ; quit if bad number...
- 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 TYPEB
- PUSH H
- MVI E,'.' ; Print a period
- CALL PCHAR
- POP H
- MVI A,3 ; Print file type
- CALL TYPEB
- 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
- MVI E,TAB
- CALL PCHAR
- JMP ASK
- ;
- 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
- ORA A
- JZ SKPCOM ; Don't print ',' if we didn't print 'R/O'
- MVI E,','
- CALL PCHAR
- SKPCOM: LDA SYSFLG
- ORA A
- JZ SKPSYS
- LXI D,SYSMSG ; "SYS"
- CALL PRTSTR
- SKPSYS: MVI E,')'
- CALL PCHAR
- ASK: LDA NAFLG ; See if must ask to change file
- CPI 'N' ; 'N' = no ask
- JZ DOIT
- 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
- DOIT: CZ 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
- 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
- ;
- CHANGE: LHLD BUFPTR ; Get drive and
- LDA FCB1 ; move it to buffer
- MOV M,A
- LDA ROFLG
- ORA A ; If not R/O
- JZ RWOK ; skip next, else
- PUSH H ; Make it
- LXI D,9 ; R/W
- DAD D
- MOV A,M
- ANI 07FH
- MOV M,A
- POP H
- PUSH H
- XCHG
- MVI C,SETFIL
- CALL BDOS
- POP H
- ;CHANGE THE FILE'S USER BY CALLING THE DELETE FUNCTION
- RWOK: XCHG
- 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 REVON
- 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: 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: CALL REVON
- LXI D,ABTMSG ; "PROGRAM ABORTED"
- CALL PRTSTR
- CALL REVOFF
- 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 B REG
- TYPEB: PUSH PSW
- PUSH H
- MOV E,M
- CALL PCHAR
- POP H
- POP PSW
- INX H
- DCR A
- JNZ TYPEB
- 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
- ;
- ;VIDEO ATTRIBUTE STRINGS
- ; Strings for video attributes are stored here, each ending with '$'
- ; Initialized to null strings. Modify as desired for your terminal.
- CLSMSG: DB '$' ; Clear screen
- ONSTR: DB '$' ; Reverse video start tag
- OFFSTR: DB '$' ; Reverse video end tag
- NITSTR: DB '$' ; Initialize scrn for reverse video
- ;
- ;MESSAGES -
- CTCMSG: DB CR,LF,TAB,'Use ^C to quit',TAB,TAB,CR,LF,'$'
- QUERY: DB TAB,'Change this file? $'
- ABTMSG: DB CR,LF,LF,'Program aborted.$'
- REPORT: DB ' files changed $'
- FRMMSG: DB 'from $'
- TOMSG: DB ' to $'
- PGMNAM: DB TAB,'CU - a program to change files from one user to'
- DB ' another.',TAB,'$'
- HLPMSG: DB CR,LF,LF
- DB 'ENTER:',CR,LF,LF
- DB TAB,TAB,'CU [dr:]filename.typ s,d [/N]',CR,LF,LF
- DB TAB,'dr:=drive designator (optional)',CR,LF
- DB TAB,'s=source user number (where it is now)',CR,LF
- DB TAB,'d=destination user number (where you want the file)',CR,LF
- DB TAB,'N means don''t ask before changing each file.',CR,LF
- DB TAB,'filename.typ may be ambiguous, just as in the'
- DB ' ERA command.',CR,LF,LF
- DB 'EXAMPLE:',CR,LF,LF
- DB TAB,TAB,'CU *.ASM 0,3 /N',CR,LF,LF
- DB TAB,'This would transfer all files of type ASM from'
- DB ' user 0 to user 3',CR,LF
- DB TAB,'without asking before changing each file.'
- DB CR,LF,'$'
- BADMSG: DB CR,LF,'System does not match program',CR,LF,'$'
- BADNR: DB CR,LF,'Bad user number entered',CR,LF
- DB 'Enter CU<CR> for help.',CR,LF,'$'
- ;
- ROMSG: DB 'R/O$'
- SYSMSG: DB 'SYS$'
- ;
- ;STORAGE AREA
- ;
- PRTFLG: DB 0 ; Flag for decimal print routine
- DRIVE: DB 'A' ; Default drive
- 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)
- DBUF: DS 128 ; Disk buffer
- BUFFER: DB 0 ; File name storage starts here
- ;
- END GETRDY