;**************************************************************** ; * ; A UTILITY PROGRAM TO FACILITATE COPYING FILES * ; BETWEEN USER AREAS * ; * ;**************************************************************** ; TITLE 'BUFFERED INTER-USER COPY ROUTINE FOR CP/M-86' ; ; Copyright (C) 1981,1982,1984 by ; ; Angus Bliss Bill Bolton ; P.O. Box 293, Software Tools RCPM ; Hamilton, P.O. Box 357, ; NSW, 2303, Kenmore, ; AUSTRALIA QLD, 4069, ; AUSTRALIA ; ; This program is made available for public distribution ; for NON-COMMERCIAL use only. All commercial rights ; retained by the authors. ; ; ------------------------------------------------------ ; ; This program is built on the Intel small memory model ; and uses the operating system 96 byte stack. It ; should be GENCMD with the following command line ; ; GENCMD PUT DATA[M860] ; ; ------------------------------------------------------ ; ; VERSION LIST, most recent version first ; --------------------------------------- ; ; 1.8 Added code to close source file for ; Concurrent DOS operation - Bill Bolton, 30/Oct/84 ; ; 1.7 Translated to CP/M-86, buffer size fixed ; at 32K (generally no lack of memory in ; 16 bit systems) - Bill Bolton 07/Aug/84 ; ; 1.6 Fixed problem with zero length files writing ; a file as large as buffer. Fixed problem of ; large files being truncated to 32K in ; some multifile transfers. Tidied up for ; publication - Angus Bliss 29/Apr/82 ; ; 1.5 Initial release version. Large file transfer ; bug fixed and other minor internal changes ; mode - Bill Bolton 3/Feb/82 ; ; 1.4 Overwrite options added, user abort added, ; filename show added and lots more comments ; added - Bill Bolton 2/Feb/82 ; ; 1.3 Transfer to $$$ file first then rename after ; succesful close (like PIP) added - Bill Bolton ; 1/Feb/82 ; ; 1.2 Wildcard file transfer added. - Bill Bolton ; 31/Jan/82 ; ; 1.1 Converted to 8080 code for greater portability ; (now that the Godbout 8085/8088 card has given ; 8080 code a new lease of life) and presentation- ; tidied up. - Bill Bolton 30/Jan/82 ; ; 1.0 Original code in Xitan Z80 source. - Angus Bliss ; Aug/82 ; VERSION EQU 18 ;VERSION NUMBER ; CNTRLC EQU 3 ;CP/M 'PANIC' CHARACTER ACR EQU 0DH ALF EQU 0AH ; WBOOT EQU 0 ;CP/M WARM BOOT ENTRY BDOS EQU 0005H ;CP/M BDOS ENTRY POINT FCB EQU 05CH ;CP/M FILE CONTROL BLOCK FCB0 EQU 06CH TBUF EQU 080H ;CP/M COMMAND LINE BUFFER ; CI EQU 1 ;BDOS CONSOLE IN CO EQU 2 ;BDOS CONSOLE OUT DIRECT EQU 6 ;BDOS DIRECT CONSOLE B_PRINT EQU 9 ;BDOS CONSOLE MESSAGE VERS EQU 12 ;BDOS RETURN VERSION NUMBER B_OPEN EQU 15 ;BDOS OPEN FILE B_CLOSE EQU 16 ;BDOS CLOSE FILE SRCH_1ST EQU 17 ;BDOS SEARCH FOR FILE SRCH_NXT EQU 18 ;BDOS SEARCH FOR NEXT (AMBIG) FILE DELET EQU 19 ;BDOS DELETE FILE B_READ EQU 20 ;BDOS SEQUENTIAL READ B_WRITE EQU 21 ;BDOS SEQUENTIAL WRITE MAKE EQU 22 ;BDOS CREATE NEW FILE REN EQU 23 ;BDOS RENAME FILE DMA EQU 26 ;BDOS SET NEW DMA ATTRIB EQU 30 ;BDOS SET FILE ATTRIBUTES USER EQU 32 ;BDOS SET/GET USER ; BUFSIZ EQU 255 ;Disk buffer in sectors (32K) M EQU Byte Ptr 0[BX] ; CSEG ORG 0 ; START: MOV DX,(Offset MSG1) MOV CL,B_PRINT CALL BDOSE ;ANNOUNCE OURSELF ; MOV CL,VERS ;CHECK VERSION ; INT 224 ;USES BX REGISTER ; MOV AL,BL ; CMP AL,2 ; JNB L_1 ; JMP ERROR3 ;WRONG CP/M VERSION ;L_1: MOV AL,Byte Ptr .TBUF ;PARAMETER COUNT CMP AL,0 ;NO PARAMETER JNZ START_1 JMP ERROR1 ; START_1: MOV BX,FCB-1 ;TAKE A COPY OF FCB MOV DX,(Offset FCB2)-1 ;_ TBUF MOV CX,33 ;LENGTH OF A FILENAME LDIR1: INC BX ;ADJUST POINTERS INC DX MOV AL,M ;GET A BYTE MOV SI,DX ;PUT A BYTE MOV [SI],AL DEC CX ;ADJUST COUNT MOV AL,CH OR AL,CL ;ZERO YET JNZ LDIR1 ;NO MOV BX,TBUF ;YES MOV CH,0 MOV CL,M ;GET COUNT INC BX ;STEP OVER ANY SOURCE DEC CL INC BX ; DRIVE IDENTIFIER ON DEC CL INC BX ; FILE NAME DEC CL MOV AL,':' ;DRIVE DELIMITER CCIR1: INC BX CMP AL,M ;MATCH JZ GO_ON1 DEC CL JZ NOT_FOUND1 ;YES JMPS CCIR1 ; GO_ON1: DEC BX ;ADJUST PTR MOV AL,M CMP AL,'G'+1 JNB NOT_FOUND1 CMP AL,'A' JB NOT_FOUND1 AND AL,7 ;MAKE 0 TO 7 MOV Byte Ptr DEST_DRV,AL MOV Byte Ptr FCB2,AL NOT_FOUND1: MOV BX,FCB MOV CL,11 ;GET LENGTH OF FILE NAME MOV AL,'?' ;WILDCARD CCIR2: INC BX ;LOOP TO SEARCH FOR WILDCARD CMP AL,M JZ GO_ON2 DEC CL JZ NOT_FOUND2 JMPS CCIR2 ; GO_ON2: MOV AL,0FFH MOV Byte Ptr WILD,AL ;SET MULTIFILE FLAG NOT_FOUND2: MOV BX,TBUF ;YES MOV CH,0 MOV CL,M ;GET COUNT MOV AL,'-' ;OPTION SPECIFIER CCIR_3: INC BX ;LOOP TO SEARCH FOR OPTIONS CMP AL,M PUSH BX JNZ CCIR_4 CALL OPTION CCIR_4: POP BX DEC CL JNZ CCIR_3 JMPS NOT_FOUND3 ; OPTION: LAHF ;FOUND THE FLAG XCHG AL,AH PUSH AX OPT_1: INC BX ;NOW LOOK FOR AN OPTION MOV AL,M CMP AL,'W' JZ OVER_WRITE CMP AL,'N' JZ NO_QUERY POP AX XCHG AL,AH SAHF RET ; OVER_WRITE: MOV AL,0FFH MOV Byte Ptr O_W,AL JMPS OPT_1 ;LOOK FOR ANOTHER ONE ; NO_QUERY: MOV AL,0FFH MOV Byte Ptr N_Q,AL JMPS OPT_1 ;LOOK FOR ANOTHER ONE ; NOT_FOUND3: MOV BX,6DH ;FROM USER CALL NSCAN ;GET NUMBER JNB NF_4 JMP ERROR2 ;INVALID USER NF_4: MOV Byte Ptr FUSER,AL ;FROM USER MOV BX,75H ;TO USER CALL NSCAN JNB NF_5 JMP ERROR2 NF_5: MOV Byte Ptr TUSER,AL ;TO USER MOV DL,0FFH MOV CL,USER ;GET CURRENT USER CALL BDOSE MOV Byte Ptr CUSER,AL ;SAVE IT MOV AL,Byte Ptr FUSER ;FROM USER MOV DL,AL ;PUT IN E MOV CL,USER CALL BDOSE ;SET THE USER MOV BX,FCB MOV AL,Byte Ptr WILD OR AL,AL ;SINGLE FILE ONLY ? JZ COPY_FCB ;YES MOV DX,FCB MOV CL,SRCH_1ST CALL BDOSE CMP AL,0FFH ;FOUND? JNZ DIR_MATCH JMP ERROR4 ;NO ; DIR_MATCH: ADD AL,AL ;MULTIPLY BY 5 ADD AL,AL ADD AL,AL ADD AL,AL ADD AL,AL MOV BX,TBUF ;POINT TO DIRECTORY BUFFER MOV DL,AL MOV DH,0 ADD BX,DX ;BX <--- POINTER TO MATCHED FILE COPY_FCB: PUSH BX MOV CL,12 MOV DX,(Offset FCB1) MOV AL,Byte Ptr .FCB MOV M,AL ;STUFF SRC DRIVE IDENT INTO FCB C_FCB_1: MOV AL,M ;COPY FCB TO FCB1 (READ FCB) MOV SI,DX MOV [SI],AL INC BX INC DX DEC CL JNZ C_FCB_1 POP BX C_FCB_2: MOV CL,11 MOV DX,(Offset FCB2) MOV AL,Byte Ptr DEST_DRV MOV SI,DX ;STUFF DEST DRIVE IDENT INTO FCB MOV [SI],AL INC BX INC DX C_FCB_3: MOV AL,M ;COPY FCB TO FCB1 (WRITE FCB) AND AL,7FH ;RESET ANY FILE ATTRIBUTES MOV SI,DX MOV [SI],AL LAHF INC BX SAHF LAHF INC DX SAHF DEC CL JNZ C_FCB_3 READ_FILE: MOV BX,(Offset FCB1) CALL SHOW MOV DX,(Offset FCB1) ;CP/M DEFAULT MOV CL,B_OPEN CALL BDOSE ;OPEN OUR SOURCE CMP AL,255 JNZ RD_FILE_1 JMP ERROR4 ;OPEN FAILURE ; RD_FILE_1: XOR AL,AL ;INITIALISE REGISTER MOV Byte Ptr ACOUNT,AL ;SECTOR COUNT MOV AL,BUFSIZ MOV CH,AL ;SECTOR COUNT ; READ: MOV DX,(Offset BUFSTART) ;CH HAS SECTOR CNT READ1: MOV CL,DMA CALL BDOSE ;SET DMA ADDRESS PUSH DX ;SAVE DMA ADDR. MOV DX,(Offset FCB1) MOV CL,B_READ CALL BDOSE ;READ A SECTOR POP DX ;RESTORE DMA CMP AL,1 JZ FINISH CMP AL,0 JZ READ2 JMP ERROR5 ;READ ERROR ; READ2: MOV AL,DL ;BUMP POINTER ADD AL,80H MOV DL,AL MOV AL,0 ADC AL,DH MOV DH,AL ;BY 128 BYTES MOV AL,Byte Ptr ACOUNT INC AL MOV Byte Ptr ACOUNT,AL ;SECTORS READ DEC CH ;ADJUST COUNT JNZ READ1 ;NO CALL WRITE ;FULL, SO EMPTY IT XOR AL,AL ;RESET REGISTERS MOV Byte Ptr ACOUNT,AL ;SECTOR COUNT MOV AL,BUFSIZ MOV CH,AL ;SECTOR COUNT JMPS READ ; FINISH: MOV DX,(Offset FCB1) MOV CL,B_CLOSE ;CLOSE SOURCE CALL BDOSE MOV AL,0FFH MOV Byte Ptr EOF,AL ;FINISHED THIS FILE MOV AL,BUFSIZ SUB AL,CH MOV CH,AL CALL WRITE MOV DX,(Offset FCB2) MOV CL,B_CLOSE ;CLOSE DESTINATION CALL BDOSE CMP AL,255 JNZ FINI_1 JMP ERROR9 ;CLOSE FAILURE ; FINI_1: CALL RENAME ;RENAME $$$ TO TYP MOV AL,Byte Ptr WILD OR AL,AL ;MORE FILES? JNZ FINI_2 JMP DONE ; FINI_2: MOV BX,(Offset BUFSTART) MOV Word Ptr BUFPT,BX ;RESET BUFFER POINTER XOR AL,AL MOV Byte Ptr OPEN,AL ;RESET FILE OPEN FLAG MOV Byte Ptr EOF,AL ;WON'T BE EOF ON NEXT FILE MOV BX,(Offset FCB1) ;POINT TO INTERNAL FCBS MOV CL,64 ;LENGTH OF 2 * FCB XOR AL,AL FCB_FILL1: MOV M,AL ;RESET MEMORY LAHF ;ADJUST POINTER INC BX SAHF DEC CL ;DONE ? JNZ FCB_FILL1 ;NO MOV AL,Byte Ptr FUSER MOV DL,AL ;SAVE DIRECTORY POINTER TIL LATER MOV CL,USER CALL BDOSE ;RESET TO SOURCE USER MOV DX,TBUF ;RESET DMA MOV CL,DMA CALL BDOSE MOV DX,FCB MOV CL,SRCH_1ST ;START SEARCH FOR NEXT CALL BDOSE ; WILDCARD MATCH (TEDIOUS) MOV AL,Byte Ptr F_COUNT ;NO FILES DONE SO FAR INC AL ;JUST DONE ANOTHER ONE MOV Byte Ptr F_COUNT,AL ;KEEP FOR NEXT TIME MOV Byte Ptr D_COUNT,AL ;INITIALISE LOOP COUNTER SEARCH_LOOP: MOV DX,0 MOV CL,SRCH_NXT ;SEARCH FOR NEXT WILDCARD MATCH CALL BDOSE MOV Byte Ptr DIR_POINT,AL CMP AL,0FFH ;NO MORE MATCH ? JNZ SRC_LP_1 JMP DONE ;YES SRC_LP_1: MOV AL,Byte Ptr D_COUNT ;NO, GET LOOP COUNT DEC AL ;ONE SEARCH DONE MOV Byte Ptr D_COUNT,AL JNZ SEARCH_LOOP ;SEARCH AGAIN MOV CL,DIRECT MOV DL,0FFH CALL BDOSE CMP AL,CNTRLC ;USER WANTS ABORT ? JNZ SRC_LP_2 JMP U_ABORT ;YES ; SRC_LP_2: MOV AL,Byte Ptr DIR_POINT ;NO, A = POINTER INTO DIR SECTOR JMP DIR_MATCH ;FOUND THE ONE WE NEEDED ; WRITE: MOV AL,Byte Ptr TUSER MOV DL,AL MOV CL,USER CALL BDOSE ;SET DESTINATION USER MOV AL,Byte Ptr OPEN CMP AL,0 ;FILE ALREADY OPEN ? JZ WRITE_M JMP WRITE2 ;YES ; WRITE_M: NOT AL ;NO MOV Byte Ptr OPEN,AL ;INDICATE FILE OPEN MOV DX,(Offset FCB2) MOV CL,B_OPEN CALL BDOSE ;ATTEMPT OPEN CMP AL,255 JZ WRITE0 ;NOT PRESENT MOV AL,Byte Ptr FCB2+9 ;PRESENT, CHECK R/O AND AL,80H ;ISOLATE BIT RCL AL,1 ;PUT IN CARRY JNB NOT_RO ;NOT R/O MOV AL,Byte Ptr O_W OR AL,AL ;OVER WRITE R/O FILE ? JNZ REMOVE_RO JMP ERR6A ;IS R/O ; REMOVE_RO: MOV DX,(Offset FCB2) MOV CL,B_CLOSE CALL BDOSE ;CLOSE FILE TO CHANGE ATTRIBUTES MOV BX,(Offset FCB2)+12 ;FCB2 HAS GROUP 'GARBAGE' XOR AL,AL ; FROM OPEN CALL WHICH MOV CL,21 ; NEEDS TO BE CLEANED OUT CALL FILL_BLOCK ; FOR ATTRIBUTE CALL MOV BX,(Offset FCB2) MOV CL,12 R_RO: MOV AL,M ;RESET ATTRIBUTES IN FILE NAME AND AL,7FH MOV M,AL LAHF INC BX SAHF DEC CL JNZ R_RO MOV DX,(Offset FCB2) MOV CL,ATTRIB CALL BDOSE CMP AL,0FFH ;THIS SHOULD NEVER HAPPEN JNZ OPEN_RW JMP ERROR11 ; BUT JUST IN CASE ; OPEN_RW: MOV DX,(Offset FCB2) MOV CL,B_OPEN CALL BDOSE ;OPEN, we already know it exists NOT_RO: MOV AL,Byte Ptr N_Q OR AL,AL ;NO FILE EXISTS QUERY? JNZ WRITE0 ;YES CALL ERROR6 ;CHECK BEFORE DELETE CMP AL,'Y' JZ WRITE1 ;CONTINUE CMP AL,'y' JZ WRITE1 ;CONTINUE JMP ABORT ;ANSWER NOT 'Y' OR 'y' WRITE1: CALL CRLF WRITE0: MOV BX,(Offset FCB2)+9 ;POINT TO SECONDARY FILENAME MOV DX,(Offset F_TYPE) MOV CL,3 ;LENGTH OF SECONDARY FILENAME MOV CH,'$' ;TEMPORARY FILE TYPE MARKER FILL_TYPE1: MOV AL,M ;GET SECONDARY FILE NAME MOV SI,DX ;SAVE IT FOR LATER MOV [SI],AL MOV M,CH ;STUFF IN TEMP MARKERS INC BX INC DX DEC CL JNZ FILL_TYPE1 MOV BX,(Offset FCB2)+12 ;ZERO FILL REST OF FCB MOV CL,24 XOR AL,AL CALL FILL_BLOCK MOV DX,(Offset FCB2) MOV CL,MAKE CALL BDOSE ;CREATE DESTINATION FILE CMP AL,255 JNZ WRITE2 JMP ERROR7 ;DIRECTORY FULL ; WRITE2: MOV AL,Byte Ptr ACOUNT OR AL,AL ;ZERO LENGTH FILE? JZ ZEXIT ;YES, DONT WRITE TO DESTINATION MOV CH,AL ;ACTUAL SECTOR COUNT PUSH BX MOV BX,(Offset BUFSTART) MOV Word Ptr BUFPT,BX ;SAVE BUFFER POINTER POP BX WRITE3: PUSH BX MOV BX,Word Ptr BUFPT ;GET BUFFER POINTER XCHG BX,DX ;DE <---- BUFFER POINTER POP BX PUSH DX MOV AL,DL ADD AL,80H MOV DL,AL MOV AL,0 ADC AL,DH ;16 BIT ADD OF 1 SECTOR MOV DH,AL PUSH BX XCHG BX,DX MOV Word Ptr BUFPT,BX ;SAVE NEW BUFFER POINTER POP BX POP DX MOV CL,DMA CALL BDOSE ;CHANGE DMA ADDRESS MOV DX,(Offset FCB2) MOV CL,B_WRITE CALL BDOSE ;WRITE A SECTOR CMP AL,0 JZ WRITE4 JMP ERROR8 ;WRITE ERROR ; WRITE4: DEC CH ;DONE YET? JNZ WRITE3 ;NO ZEXIT: ;(COME IN HERE IF ZERO LENGTH FILE) MOV AL,Byte Ptr EOF CMP AL,0 JZ ZEXIT_1 RET ;END ; ZEXIT_1: MOV AL,Byte Ptr FUSER MOV DL,AL MOV CL,USER ;SET SOURCE USER CALL BDOSE RET ; FILL_BLOCK: MOV M,AL ;GENERAL BLOCK FILLER LAHF ; WITH A CONSTANT INC BX SAHF DEC CL JNZ FILL_BLOCK RET ; ; RENAME: MOV BX,(Offset FCB2)+9 ;START POINT MOV CL,27 ;LENGTH TO FILL XOR AL,AL ;ZERO A CALL FILL_BLOCK MOV BX,(Offset F_TYPE) ;POINT TO FILE TYPE MOV DX,(Offset FCB2)+9 ;SECONDARY FILE NAME MOV CL,3 ;LENGTH TO MOVE REN_LOOP1: MOV AL,M ;STUFF FILE TYPE BACK INTO FCB MOV SI,DX MOV [SI],AL LAHF INC BX SAHF LAHF INC DX SAHF DEC CL JNZ REN_LOOP1 MOV DX,(Offset FCB2) MOV CL,DELET CALL BDOSE ;KILL ORIGINAL DESTINATION FILE MOV BX,(Offset FCB2)+9 MOV CL,27 XOR AL,AL CALL FILL_BLOCK ;ZERO FILL WRITE FCB YET AGAIN MOV BX,(Offset FCB2) MOV DX,(Offset FCB2)+16 MOV CL,9 REN_LOOP2: MOV AL,M ;COPY WRITE FCB TO MAKE THE MOV SI,DX ; SPECIAL RENAME FORMAT FCB MOV [SI],AL LAHF INC BX SAHF LAHF INC DX SAHF DEC CL JNZ REN_LOOP2 MOV AL,'$' ;HL = POINTER TO FCB2 +9 MOV CL,3 REN_LOOP3: MOV M,AL ;STUFF TEMP FILE MARKERS IN LAHF ; THE 'FROM' PART OF FCB INC BX SAHF DEC CL JNZ REN_LOOP3 MOV BX,(Offset F_TYPE) ;DE = FCB2+9+16 MOV CL,3 REN_LOOP4: MOV AL,M ;STUFF FILE TYPE IN THE MOV SI,DX ; 'TO' PART OF FCB MOV [SI],AL LAHF INC BX SAHF LAHF INC DX SAHF DEC CL JNZ REN_LOOP4 MOV DX,(Offset FCB2) MOV CL,REN ;DO THE RENAME CALL BDOSE CMP AL,0FFH ;AGAIN, THIS SHOULD NEVER HAPPEN JZ ERROR10 ; BUT....... RET ; ;ERROR AND MESSAGE HANDLING ; ERROR1: MOV DX,(Offset MSG3) CALL PRINT MOV DX,(Offset MSG2) CALL PRINT JMP ABORT ; ERROR2: MOV DX,(Offset MSG4) CALL PRINT MOV DX,(Offset MSG2) CALL PRINT JMP ABORT ; ERROR3: MOV DX,(Offset MSG5) CALL PRINT JMPS ABORT ; ERROR4: MOV DX,(Offset MSG6) CALL PRINT JMPS ABORT ; ERROR5: MOV DX,(Offset MSG7) CALL PRINT JMPS ABORT ; ERROR6: MOV DX,(Offset MSG8) MOV CL,B_PRINT CALL BDOSE ;PROMPT QUESTION MOV CL,CI CALL BDOSE RET ;RETURN WITH INPUT ; ERR6A: MOV DX,(Offset MSG8A) CALL PRINT JMPS ABORT ; ERROR7: MOV DX,(Offset MSG9) CALL PRINT MOV DX,(Offset MSG10) CALL PRINT JMPS ABORT ; ERROR8: MOV DX,(Offset MSG11) CALL PRINT JMPS ABORT ; ERROR9: MOV DX,(Offset MSG12) CALL PRINT JMPS ABORT ; ERROR10: MOV DX,(Offset MSG16) CALL PRINT JMPS ABORT ; ERROR11: MOV DX,(Offset MSG17) CALL PRINT JMPS ABORT ; ; ;GENERAL PURPOSE SUBROUTINES ; PRINT: PUSH DX CALL CRLF POP DX MOV CL,B_PRINT CALL BDOSE ;PRINT MESSAGE RET ; U_ABORT: MOV DX,(Offset MSG18) CALL PRINT JMPS EOJ ; ABORT: MOV DX,(Offset MSG13) CALL PRINT JMPS EOJ ; CRLF: MOV DL,ACR MOV CL,CO CALL BDOSE MOV DL,ALF MOV CL,CO CALL BDOSE RET ; DONE: CALL CRLF ;NORMAL EOJ MSG MOV DX,(Offset MSG14) MOV CL,B_PRINT CALL BDOSE ; EOJ: MOV AL,Byte Ptr CUSER ;RESET USER MOV DL,AL MOV CL,USER CALL BDOSE MOV CX,0 MOV DX,0 INT 224 ; SHOW: CALL CRLF MOV DX,(Offset MSG15) MOV CL,B_PRINT CALL BDOSE MOV DH,9 SHOW1: ;DISPLAY FILENAME IN READ FCB LAHF INC BX SAHF DEC DH JNZ SHOW2 MOV DL,'.' ;PRINT THE SEPARATOR MOV CL,CO CALL BDOSE SHOW2: MOV AL,M CMP AL,0 JNZ SHOW3 RET ; SHOW3: CMP AL,' ' ;SKIP BLANKS JZ SHOW1 MOV DL,AL MOV CL,CO CALL BDOSE JMPS SHOW1 ; ; BDOSE: PUSH CX ;BDOS ENTRY PUSH DX PUSH BX INT 224 POP BX POP DX POP CX RET ; NSCAN: MOV DX,0 ;CLEAR WORK MOV AL,M ;GET CHAR CMP AL,'9'+1 ;IS IT A DIGIT JNB NSCAN2 ;> 9 CMP AL,'0' JB NSCAN2 ;< 0 NSCAN0: SUB AL,'0' ;REMOVE ASCII BIAS PUSH BX ;SAVE PTR XCHG BX,DX ;GET WORK IN BX PUSH BX POP DX SHL BX,1 SHL BX,1 ADD BX,DX SHL BX,1 ;BX = BX * 10 MOV DH,0 MOV DL,AL ;NEW DIGIT ADD BX,DX ;ADD IT IN XCHG BX,DX ;PUT WORK BACK POP BX ;RESTORE PTR INC BX ;AND STEP IT MOV AL,M CMP AL,'9'+1 JNB NSCAN1 CMP AL,'0' JB NSCAN1 JMPS NSCAN0 ;LOOP ; NSCAN1: MOV AL,DL ;GET NUMBER CMP AL,16 ;<= 15 JNB NSCAN2 OR AL,AL ;CLEAR CARRY JMPS NSCAN3 ; NSCAN2: STC ;SET CARRY NSCAN3: RET ;EXIT HERE ; DSEG ORG 100H ; MSG1 DB 'PUT, CP/M-86 Version ',VERSION/10 + '0','.' DB VERSION MOD 10 + '0' DB ', by Angus Bliss and Bill Bolton',ACR,ALF,'$' ; MSG2 DB 'Usage:',ACR,ALF DB ' A>put [d:]filename f.t [d:] [-NW] ' DB ACR,ALF DB 'Where:',ACR,ALF DB ' filename - is any valid CP/M file ' DB 'specifier',ACR,ALF DB ' f - is source user area',ACR,ALF DB ' t - is destination user area' DB ACR,ALF DB ' d: - is optional drive specifier' DB ACR,ALF DB ' - - is an option flag',ACR,ALF DB ' N - is no query to overwrite ' DB 'existing file',ACR,ALF DB ' W - is force overwrite of R/O ' DB 'file',ACR,ALF,ALF DB ' Will prompt if destination ' DB 'file is already present',ACR,ALF,'$' ; MSG3 DB 'No parameters given',ACR,ALF,'$' ; MSG4 DB 'Invalid user number(s)',ACR,ALF,'$' ; MSG5 DB 'Sorry - you need CP/M 2.x',ACR,ALF,'$' ; MSG6 DB 'Open fail on source file.',ACR,ALF,'$' ; MSG7 DB 'Read failure on source file.',ACR,ALF,'$' ; MSG8 DB ' Destination file is present.',ACR,ALF DB ' Continue (y) or Abort (n)?$' ; MSG8A DB 'Destination is present and R/O.$' ; MSG9 DB 'Open failure on destination file.$' ; MSG10 DB 'Destination directory probably full.$' ; MSG11 DB 'Write error on destination.$' ; MSG12 DB 'Close fail on destination.$' ; MSG13 DB 'ABORT - returning to CP/M.',ACR,ALF,'$' ; MSG14 DB '**** Normal end-of-job ****',ACR,ALF,'$' ; MSG15 DB ' Putting file : $' ; MSG16 DB 'Rename error on destination.$' ; MSG17 DB 'Rename error on R/O file.$' ; MSG18 DB 'ABORT, Control C typed at console - ' DB 'returning to CP/M',ACR,ALF,'$' ; CUSER DB 0 ;INITIATING USER FUSER DB 0 ;FILE FROM USER TUSER DB 0 ;FILE TO USER SIZEB DW 0 ;BUFFER IN BYTES BUFPT DW 0 ;DMA POINTER ACOUNT DB 0 ;ACTUAL SECTOR COUNT OPEN DB 0 ;FILE OPEN SWITCH EOF DB 0 ;END OF SOURCE SWITCH WILD DB 0 ;WILDCARD SWITCH O_W DB 0 ;OVER WRITE SWITCH N_Q DB 0 ;NO QUERY SWITCH DEST_DRV DB 0 ;DESTINATION DRIVE F_COUNT DB 0 ;FILES TRANSFERED COUNTER D_COUNT DB 0 ;FILES TO SEARCH COUNTER DIR_POINT DB 0 ;TEMP STORAGE FOR SEARCH NEXT ; F_TYPE DB ' ' ;SECONDARY FILE TYPE ; ; FOR RENAME AFTER WRITE ; FCB1 DB 0,0,0,0,0,0,0,0,0 ;SOURCE FCB DB 0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0 ; FCB2 DB 0,0,0,0,0,0,0,0,0 ;Destination FCB DB 0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0 ; BUFSTART RB (BUFSIZ + 1) * 128 ;Disk buffer ; BUFEND EQU $ ;Generate symbol for SID ; END