; TITLE 'MICRO RESOURCES "WASH" Directory Maintence Utility Ver 1.4' ;************************************************************************* ; MICRO RESOURCES "WASH"; THE SUPER DIRECTORY MAINTENANCE UTILITY ;************************************************************************* ; ; ; This program is a super-duper CP/M disk directory maintence ; utility that is designed as an "almost" all inclusive routine ; to make it easy to do disk directory house keeping. The ; inspiration to produce this program came from use of an older ; utility program called "CLEAN" that I came across at a meeting of ; the Valley Computer Club about a year and a half ago. At that ; time "CLEAN" seemed like a dream come true. Unfortunately it ; had several major problems that limited its overall usefullness. ; The disadvantages of CLEAN have all been overcome with the new ; WASH program. Program features are listed below: ; ; a) Alphabetical list oriented file operations ; ; b) Any legal CP/M drive (A: to P:) may be selected ; ; c) Operator interface to the file list is at the console ; in sequential apha order in forward or backup mode. ; ; d) The file list is treated as a circular buffer. Forward ; or backward scanning of the list wraps around the list ; back to the beginning or ending respectively. ; ; e) The current list position file can be viewed at the ; Console, printed on the CP/M List device, or sent ; to the CP/M Punch device. ; ; f) The current list position file may be deleted or renamed. ; If renamed, only the new name must be entered. ; ; g) The current list position file may be copied, with the ; same name, to any other operator selected disk drive. ; The copy utilizes all of available memory as the copy ; buffer for the ultimate in copy speed. ; ; h) The current list can be deleted and the "WASH" operation ; may be begun upon another operator selected disk drive. ; ; i) The program is fully implemented in 8080 assembly language ; for speed, small size, and portability to any CP/M 2.2 ; or 1.4 system. No assumption is made upon the maximum ; number of directory files other than available memory ; space for the list. (A directory with 1024 directory ; file names takes 12 K bytes of storage. Assuming the ; copy buffer minimum size requirement of 128 bytes, then ; WASH should easily run in the minimum CP/M 2.2 20K ; System with no problems at all.) ALL directory and ; disk I/O is handled through calls to the BDOS. This ; will guarentee WASH compatibility with any CP/M system ; implementation. This makes the program disk media ; independent (all you have to do is get WASH.COM onto ; your diskette or hard disk in the first place. ; ; Complete documentation on the operation of WASH is given in the ; accompaning documentation file "WASH.DOC". For the most part the ; program is self documenting and contains extensive error message ; reporting. ; ; ; This Program was Written by: ; ; Michael J. Karas ; MICRO RESOURCES ; 2468 Hansen Court ; Simi Valley, California 93065 ; (805) 527-7299 ; September 20, 1981 ; ; NOTE: The WASH program, its source code, documentation file, ; and object code, has been released to the PUBLIC DOMAIN ; by Michael J. Karas. This program may be modified to suit ; your personal requirements or those of your friends. In ; any case no COMMERCIAL or MONEY MAKING ventures with ; regard to SOFTWARE SALES or MODIFICATION and the subsequent ; SALE of the WASH program in WHOLE or any PART is permitted ; by the author. Further modification and public domain ; distribution of the WASH program must include: ; a) This NOTE, ; b) The name "WASH" must be retained, ; c) The original authorship notice ; from above, and ; d) The MICRO RESOURCES Name in the Sign-on ; Menu. ; ; MICRO RESOURCES reserves the right to modify this program at any ; time for any purpose. The Intent of the above NOTE is intended ; for the public domain distribution of the WASH program and ; MICRO RESOURCES reserves the right to utilize the WASH program ; for any application whatsoever including but not limited to ; commercial distribution and modification for custom applications ; with or without the "WASH" name. ; ; ; ; Modification History: ; ; If you modify, enhance, or correct bugs in this program, please ; include a short statement of the modifications done and include ; your name and the date. The modification history log should be ; kept intact with this source code in "most recent first" order. ; Changes to program structure will generally require a change in ; the program version. The version number is documented in the ; signon message and the distribution program name as "WASH-10.ASM" ; in the specific case of the initial release 1.0. ; ; Date: Oct 13, 1981 Version Number: 1.4 Bob Zimmerman ; Changed Delete (D) command to ^D to make deleting files ; a two-handed operation ; ; 9-26-81 V 1.2 Chuck Forsberg ; ; Changed BDOS write record call to detect ANY non zero return as ; error in accordance with CP/M 2.2 documentaion. This fix should ; minimize file diversion to the proverbial bit bucket. ; Other BDOS calls checked for the same error. ; ; ; Date: Sept. 25, 1981 Version Number: 1.3 Name: Ted Shapin ; ; Added BASE for standard or modified CP/M systems. Added BUFR ; equate for same purpose and to make code clearer. Shortened long ; labels to be unique in first six chars. Fixed code to compute ; buffer address correctly for BUFR other than at 80H. Reprint ; help menu on any unknown command. Changed abort to stay at same ; position in list (good for abort while viewing file). ; CP/M 1.4 always returns 0FFH when ; deleting a file, therefore after a file was deleted always ; printed "Not found". I added a switch to bypass this code. ; ; Date: Sept. 24, 1981 Version Number: 1.1 Name: Keith B. Petersen ; ; Fixed problem with incorrect drive select when default disk used ; and running in other than user 0. Added code to turn up two new ; lines to console when entering VIEW mode. ; ; Date: Sept. 20, 1981 Version Number: 1.0 Name: Michael J. Karas ; ; Initial release to the public domain via the CP/M NET remote ; software access program operated by Kelly Smith, 3055 Waco Ave, ; Simi Valley, CA 93063. (805) 527-9321/ PMMI modem. ; ;****************************************************************************** ; ; ; ; ;DEFINE TRUE AND FALSE ASSEMBLY PARAMETERS ; FALSE EQU 0 ;DEFINE FALSE TRUE EQU NOT FALSE ;DEFINE TRUE ; BASE EQU 0H ; 0 FOR STD, 4200H FOR MODIFIED CP/M BUFR EQU 80H+BASE ; DEFAULT CP/M BUFFER CPM14 EQU FALSE ; TRUE IF RUNNING 1.4 ; ; ;CP/M BDOS INTERFACE EQUATES ; WBOOT EQU 0+BASE ;WARM BOOT ENTRY ADRS KEYIN EQU 1 ;CONSOLE INPUT FUNCTION WRCON EQU 2 ;WRITE CHARACTER TO CONSOLE WRLST EQU 5 ;WRITE CHARACTER TO LIST DEVICE WRPUN EQU 4 ;WRITE CHARACTER TO PUNCH DEVICE LOGDRIV EQU 0004H+BASE ;LOCATION OF CURRENTLY LOGGED DRIVE BDOS EQU 0005H+BASE ;THE BDOS I/O VECTOR PRINT EQU 9 ;PRINT STRING (DE) UNTIL '$' GETBUF EQU 10 ;READ INPUT STRING GETST EQU 11 ;GET CONSOLE STATUS OPEN EQU 15 ;OPEN FILE CLOSE EQU 16 ;CLOSE FILE SRCHF EQU 17 ;SEARCH DIR FOR FIRST OCCUR. SRCHN EQU 18 ;SEARCH DIR FOR NEXT OCCUR. DELETE EQU 19 ;ERASE FILE READR EQU 20 ;READ RECORD WRITER EQU 21 ;WRITE RECORD MAKE EQU 22 ;MAKE FILE RENAM EQU 23 ;RENAME FILE STDMA EQU 26 ;SET DMA ADDRESS FCB EQU 5CH+BASE ;DEFAULT FILE CONTROL BLOCK FCBEXT EQU FCB+12 ;EXTENT BYTE IN FCB FCBRNO EQU FCB+32 ;RECORD NUMBER IN FCB ; ; ;ASCII CHARACTER DEFINITIONS ; BS EQU 008H ;ASCII BACK SPACE CHARACTER LF EQU 00AH ;ASCII LINE FEED CHARACTER CR EQU 00DH ;ASCII CARRIAGE RETURN CHARACTER ESC EQU 01BH ;ASCII ESCAPE CHARACTER RUBOUT EQU 07FH ;ASCII RUBOUT CHARACTER EOT EQU 004H ;ASCII EOT CHARACTER (^D) ; ;***************************************************************************** ; ; ORG 0100H+BASE ; DI LXI SP,STCKK ;SETUP LOCAL UTILITY STACK ; RESTART: CALL MENU ; ; ;START UP BY ASSEMBLING LIST OF FILE NAMES OF SPECIFIED DISK DRIVE ; LDA FCB+1 ;CHECK IF A COMMAND PARAMETER WAS ENTERED CPI ' ' ;..FILE NAME = SPACES? JNZ NAMEPRES ;NAME NOT SPACE SO PARM WAS ENTERED LDA FCB+9 ;EXTENT NAME ALSO SPACES? CPI ' ' ;..IF SO THEN MUST TREAT AS *.* JNZ NAMEPRES ; ; ;NO COMMAND PARAMETER FOR A FILE NAME SO SET LIKE *.* ; LXI H,ALFN ;POINT AT ALL FILE WILD CARD NAME LXI D,FCB+1 ;PLACE TO PUT IT MVI B,11 ;SIZE TO SET CALL MOVBYT ;SET FIELD TO *.* JMP NAMEPRES ; ALFN: DB '???????????' ;DUMMY ALL FILE SPECIFIED NAME ; ; ;HERE IF NAME PROPERLY POSITIONED IN THE DEFAULT FCB AREA FOR LIST BUILD ; NAMEPRES: MVI C,STDMA ;INITIALIZE DMA ADDRESS TO DEFAULT BUFFER LXI D,BUFR CALL BDOS ; XRA A ;CLEAR APPROPIATE FIELDS OF SEARCH FCB STA FCBEXT ;EXTENT BYTE STA FCBRNO ;AND RECORD NUMBER ; LXI D,FCB ;USE DEFAULT FCB FOR SEARCH MVI C,SRCHF ;SEARCH FOR FIRST OCCURRANCE CALL BDOS CPI 0FFH ;SEE IF FOUND JNZ LOADLIST ;IF SOME FOUND THEN GO BUILE LIST ; CALL PRTMSG ;TELL THEM THAT NONE FOUND DB CR,LF,' ++ Not Found ++',0 JMP EXIT ; ; MENU: CALL PRTMSG ;PRINT SIGNON MESSAGE ; DB CR,LF,' MICRO RESOURCES DIRECTORY "WASH UTILITY" Ver 1.3' DB CR,LF DB CR,LF,' Command Function' DB CR,LF,' ------- ----------------------------' DB CR,LF,' V View file at Console' DB CR,LF,' (any key aborts)' DB CR,LF,' L Print file to List Device' DB CR,LF,' P Send file to Punch Device' DB CR,LF,' C Copy file to another Disk' DB CR,LF,' R Rename file' DB CR,LF,' ^D Delete file' DB CR,LF,' X Exit to CP/M' DB CR,LF,' B Backup one file in List' DB CR,LF,' S Restart on another Drive' DB CR,LF,' sp or cr Forward to next file in List' DB CR,LF,'H or anything else Display this help message' DB CR,LF,CR,LF,CR,LF,0 RET ; ; ;BUILD UP LIST WITH ALL FOUND ENTRIES ; LOADLIST: LXI H,LIST ;INITIALIZE LIST POINTER PARAMETERS SHLD LISTPOS ;START = CURRENT POS OF LIST ; ; ;PUT CURRENTLY FOUND NAME TO LIST ;(A) = OFFSET IN DEFAULT BUFFER OF NAME ; ; NM2LST: ANI 3 ;ZERO BASED TWO BIT INDEX ADD A ;TIMES 32 TO MAKE POSITION INDEX ADD A ADD A ADD A ADD A MOV C,A ;PUT IN BC XRA B ;CLEAR HIGH ORDER LXI H,BUFR ;TO NAME POSITION IN DEFAULT BUFFER DAD B ;(HL) = CURRENT FOUND NAME POINTER LDA FCB ;PUT DISK DRIVE NUMBER INTO NAME PLACE ORA A ;SEE IF DEFAULT DRIVE JNZ NOTDEF ;SKIP SETTING IF NOT DEFAULT LDA LOGDRIV ANI 0FH ;GET RID OF USER NUMBER INR A ;MAKE 1 = A: NOTDEF: MOV M,A ;INTO BUFFER XCHG LHLD LISTPOS ;POINTER TO CURRENT LOAD POINT IN LIST XCHG MVI B,12 ;MOVE DRIVE DESIGNATOR AND NAME TO LIST CALL MOVBYT XCHG ;(DE) WAS LEFT WITH LEXT LOAD POINT ADDRESS SHLD LISTPOS ; ; ;SEARCH FOR NEXT OCCURANCE OF SPECIFIED FILE NAME ; MVI C,SRCHN ;SEARCH NEXT FUNCTION CODE LXI D,FCB ;FILE NAME SPECIFICATION FIELD CALL BDOS CPI 0FFH ;SEE IF ALL THROUGH DIRECTORY YET JNZ NM2LST ;IF NOT GO PUT NAME INTO LIST ; ; ;ALL FILE NAMES NOW IN LIST SO LETS SETUP PARAMETERS ASSOCIATED ;THE LIST SIZE AND COPY BUFFER START POINT. ; LHLD LISTPOS ;NEXT LOAD POINT OF LIST IS START OF BUFFER SHLD LISTEND ;SET LIST END MARKER SHLD BUFSTART LXI D,LIST+12 ;COMPARE LISTEND TAB BASE+12 CALL CDEHL JZ CMDST ;GO TO COMMAND LOOP IF NO SORT ; ; ;SORT LIST OF FILE NAMES IN ALPHA ORDER AS AN OPERATOR NICEITY ;THIS MAY TAKE A LITTLE WHILE AS THIS IS A VERY SIMPLE SORT ROUTINE ; SORT: LXI H,LIST ;INITIALIZE I SORT VARIABLE SHLD LISTI LXI D,12 ;INITIALIZE ALSO THE J VARIABLE DAD D SHLD LISTJ ; SORT1: LHLD LISTJ ;COMPARE NAMES I & J XCHG LHLD LISTI PUSH H ;SAVE POSITION POINTERS FOR MAYBE SWAP PUSH D MVI B,12 ;COMPARE SIZE CALL CMPSTR ;GO COMPARE POP D POP H MVI B,12 CC SWAP ;GO SWAP IF J STRING LARGER THAN I ; LHLD LISTJ ;INCREMENT J POINTER LXI D,12 DAD D SHLD LISTJ XCHG ;SEE IF END OF J LOOP LHLD LISTEND CALL CDEHL JNZ SORT1 ;..NO SO MORE J LOOP ; LHLD LISTI ;BUMP I POINTER LXI D,12 DAD D SHLD LISTI DAD D ;SET START OVER J POINTER SHLD LISTJ XCHG ;SEE IF END OF I LOOP LHLD LISTEND CALL CDEHL JNZ SORT1 ;MUST BE MORE I LOOP TO DO ; ; ;FILE PROCESSING AND DISPLAY LOOP ; CMDST: LXI H,LIST ;SET START POINT OF LISTING SHLD LISTPOS ; ; ;DISPLAY CURRENT FILE POSITION ; LOOP: LHLD LISTPOS ;MOVE FROM LOCATION LXI D,PNAME ;START POINT OF LIST POINT MVI B,1 ;ONE CHARACTER OF DRIVE ID TO MOVE CALL MOVBYT ; LXI D,PNAME+3 ;PLACE TO PUT FILE NAME FOR PRINT MVI B,8 ;8 CHARS IN FILE NAME CALL MOVBYT ;MOVE NAME FIELD ; LXI D,PNAME+12 ;PLACE TO PUT EXTENSION FOR PRINT MVI B,3 ;3 CHARS IN FILE TYPE CALL MOVBYT ;MOVE TYPE NAME ; SHLD LISTPOS ;SAVE NEXT POSITION OF LISTING ; LDA PNAME ;MAKE DRIVE NAME PRINTABLE ADI 'A'-1 ;THIS ONE O.K. SO MAKE DRIVE PRINTABLE STA PNAME ; SAMEPOS: CALL PRTMSG ;PRINT CURRENT READY TO TRANSFER FILE NAME PNAME: DB 'X: XXXXXXXX.XXX : ' ;DUMMY FILE NAME PRINTING FIELD DB 0 ; MVI C,KEYIN ;CONSOLE CHAR IN FUNCTION CALL BDOS ;GET THE CHARACTER CALL UPCASE CPI ' ' ;IF SPACE THEN ON TO NEXT FILE JZ NEXTPOS CPI CR ;IF CARRIAGE RETURN THEN ON TO NEXT FILE JZ NEXTPOS CPI 'B' ;IF BACKUP THEN ADJUST POSITION POINTER -1 FILE JZ BACKUP CPI 'X' ;IF EXIT THEN TO CP/M JZ EXIT CPI 'R' ;IF RENAME THEN GO DO IT JZ RENAME CPI EOT ;TO DELETE A FILE IF "^D" JZ DELFLE CPI 'V' ;IF TO VIEW FILE AT CONSOLE JZ VIEW CPI 'L' ;IF TO PRINT FILE TO LIST DEVICE JZ PRTFIL CPI 'P' ;IF TO SEND FILE TO THE PUNCH DEVICE JZ PUNFIL CPI 'C' ;IF TO COPY FILE TO ANOTHER DISK JZ COPY CPI 'S' ;IF TO START OVER ON ANOTHER DRIVE JZ LOG CMDERR: CALL MENU ;GIVE HELP MESSAGE JMP SAMEPOS ;STAY IN THIS POSITION ; BACKUP: LHLD LISTPOS ;SEE IF AT BEGINNING OF LIST LXI D,LIST+12 CALL CDEHL JNZ BAKUP1 ;SKIP POSITION POINTER RESET IF NOT ;..AT BEGINNING CALL PRTMSG DB CR,LF,CR,LF,' Beginning of List',CR,LF,0 LHLD LISTEND ;SET TO END +1 TO BACKUP TO END LXI D,12 DAD D SHLD LISTPOS ; BAKUP1: CALL PRTMSG ;PRINT BACKUP INDICATOR DB CR,LF,'< ',0 LHLD LISTPOS LXI D,12*2 ;ONE LIST POSITION BACKWARDS SIZE CALL SDEHL ;SUBTRACT SHLD LISTPOS JMP LOOP ;DISPLAY THAT GUY WITHOUT CRLF ; NEXTPOS: CALL PRTMSG ;DO CARRIAGE RETURN LINE FEED DB CR,LF,0 LHLD LISTPOS ;SEE IF AT END OF LOOP YET XCHG LHLD LISTEND CALL CDEHL ;COMPARE JNZ LOOP ;GO ON TO NEXT POSITION TO PRINT ; ; ;AT END OF DIRECTORY. PRINT MESSAGE AND GO BACK TO TOP ; CALL PRTMSG ;PRINT END OF DIRECTORY MESSAGE DB CR,LF,' End of List',CR,LF,CR,LF,0 LXI H,LIST ;SET POSITION POINTER TO BEGINNING SHLD LISTPOS JMP LOOP ;TO REDISPLAY START ENTRY ; ; ;CLEAN COMMAND LOOP EXIT POINT TO CP/M ; EXIT: JMP WBOOT ;BACK TO CP/M ; ; ;ROUTINE TO RENAME THE FILE CURRENTLY DISPLAYED ; RENAME: LHLD LISTPOS ;MOVE NAME FROM LIST TO RENAME FCB LXI D,12 CALL SDEHL ;POINT TO NAME POSITION LXI D,DESTFCB ;PLACE TO MOVE THE NAME MVI B,12 ;AMOUNT TO MOVE CALL MOVBYT ; CALL PRTMSG ;NEW NAME PROMPT DB ' New Name ? ',0 MVI C,GETBUF ;GET COMMAND BUFFER FUNCTION LXI D,CBUFF ;PLACE TO PUT COMMAND LINE CALL BDOS ; ; ;CONVERT TO UPPER CASE ; LXI H,CBUFFL ;GET BUFFER LENGTH MOV B,M ;..TO (B) XRA A ORA B ;IF ZERO LENGTH SKIP RENAME JZ NEXTPOS ; CONV: INX H ;POINT AT A CHAR TO CONVERT MOV A,M CALL UPCASE MOV M,A ;PUT BACK INTO BUFFER DCR B JNZ CONV ; ; ;SCAN INPUT BUFFER TO MOVE A FILE NAME TO THE RENAME POSITION OF ;DESTINATION FCB ; LXI H,DESTFCB+16 MVI M,0 ;BDOS EXPECTS ZERO HERE INX H ; ; ;PREBLANK THE NEW FILE NAME FIELD ; PUSH H ;SAVE START POINTER MVI B,11 ;NUMBER OF SPACES TO BLANK PREFILL: MVI M,' ' ;PUT IN A SPACE CODE INX H DCR B ;CHECK BYTE COUNT TO SEE IF DONE JNZ PREFILL POP H ; XCHG LXI H,CBUFFL ;GET LENGTH TO (C) MOV C,M INX H XCHG ;(DE) = BUFFER POINTER ;..& (HL) = FCB POINTER ; ; ;PURGE SPACES OFF THE BEGINNING OF BUFFER ; DEBLANK: LDAX D ;GET A CHARACTER CPI ' ' JNZ EXTND ;NOT BLANK, WE HAVE SOMETHING INX D ;TO NEXT CHAR DCR C JZ CMDERR ;ALL SPACES SO ERROR JMP DEBLANK ; ; ;EXTEND BUFFER TO BLANKS BEYOND COMMAND LENGTH ; EXTND: PUSH H MOV L,C ;DOUBLE BYTE REMAINING LENGTH MVI H,0 DAD D ;TO BUFFER END +1 MVI M,' ' ;FORCE ILLEGAL CHAR END POP H ; ; ;START FILE NAME SCAN ; SCAN: MVI B,8 ;MAX OF 8 CHAR IN FILE NAME SCAN1: CALL CHKLEGL ;GET AND SEE IF LEGAL CHARACTER JC CMDERR ;CHECK IF ALL OF COMMAND LINE CPI ' ' ;SEE IF END OF PARAMETER FIELD JZ CPYBITS ;GO TO RENAME THE FILE CPI '.' ;AT END OF FILE NAME JZ SCAN2 ;GO TO PROCESS THE FILE TYPE FIELD MOV M,A ;PUT CHAR INTO DESTINATION FCB INX H DCR B ;CHECK NAME CHARACTER COUNT JNZ SCAN1 ; ; ;GOT HERE IF EIGHT CHAR WITHOUT A "." ; SCAN1A: CALL CHKLEGL ;SCAN BUFFER UP TO PERIOD ;OR END JC CPYBITS ;NO EXTENT IF NOT LEGAL CPI ' ' ;END OF PARAMETER FIELD? JZ CPYBITS CPI '.' JZ SCAN2 ;NOW GO DO EXTENT FIELD JMP SCAN1A ;DO TILL END OR PERIOD ; ; ;NOW BUILD THE EXTENT FIELD ; SCAN2: MVI B,3 ;MAX LENGTH OF EXTENT FIELD LXI H,DESTFCB+25 ;DESTINATION RENAME EXTENT START SCAN3: CALL CHKLEGL ;GET AND CHECK CHARACTER JC SCAN4 ;NAME DONE IF ILLEGAL CPI ' ' ;END OF PARAMETER FIELD? JZ SCAN4 CPI '.' ;CHECK IF ANOTHER PERIOD JZ SCAN4 MOV M,A INX H DCR B JNZ SCAN3 ;GET NEXT EXTENT CHARACTER ; SCAN4: MVI B,4 ;FILL EX,S1,S2,RC WITH ZEROS LXI H,DESTFCB+28 ;SET POINTER TO RENAME EXTENT FIELD SCAN5: MVI M,0 INX H DCR B JNZ SCAN5 ; ; ;COPY OLD FILES ATTRIBUTE BITS TO THE NEW FILE NAME TO HAVE THEN BE ;THE SAME AS OLD FILE NAME ; CPYBITS: LXI D,DESTFCB+1 ;FIRST CHAR OF OLD NAME LXI H,DESTFCB+17 ;FIRST CHAR OF NEW NAME MVI C,011 ;NUMBER OF BYTES WITH TAG BITS CBITS1: LDAX D ;FETCH BIT OF OLD NAME CHAR ANI 080H ;STRIP ONLY UPPER BIT OUT MOV B,A ;SAVE BIT INTO (B) MVI A,07FH ;FETCH A MASK FOR CHAR ONLY ANA M ;GET MASKED CHAR TO (A) ORA B ;PUT OLD BIT IN MOV M,A ;SAVE NEW BYTE BACK INX H ;BUMP COPY POINTERS INX D DCR C ;DEC BYTE COPY COUNT JNZ CBITS1 ; ; ;SEE IF THE NEW FILE NAME ALREADY EXISTS. IF SO SAY SO AND THEN GO ;TO THE COMMAND LOOP AGAIN AT SAME POSITION ; LDA DESTFCB ;COPY NEW NAME TO SOURCE FCB STA SORCFCB MVI B,11 LXI H,DESTFCB+17 ;COPY NEW NAME TO LXI D,SORCFCB+1 ;..SOURCE FCB FOR EXISTENCE CHECK CALL MOVBYT MVI B,4 ;ZERO THE OPERATIONAL FIELDS LXI H,SORCFCB+12 RNFILLP: MVI M,0 ;PUT A ZERO IN THERE INX H ;TAKE CARE OF COUNTERS DCR B JNZ RNFILLP ; LXI D,SORCFCB ;SEARCH TO SEE IF THIS FILE EXISTS MVI C,SRCHF ;SEARCH FIRST FUNCTION CALL BDOS CPI 0FFH ;RETURN CODE IF NOT FOUND JZ RNFILE ;TO RENAME COMMAND IF NOT A DUPLICATE NAME ; CALL PRTMSG ;ASK IF TO REPLACE DB CR,LF,' ++ Name Already Exists ++',CR,LF,0 JMP SAMEPOS ;BACK TO LET HIM TRY ALL THAT AGAIN ON ;... THE SAME FILE NAME ; ; ;COPY NEW NAME INTO LIST POSITION IN CASE HE BACKS UP ; RNFILE: LHLD LISTPOS ;GET LIST POSITION POINTER LXI D,11 ;BACK 11 TO LEAVE DRIVE ID THE SAME CALL SDEHL XCHG LXI H,DESTFCB+17 ;POINT AT THE NEW NAME MVI B,11 ;AMOUNT TO MOVE CALL MOVBYT ; ; ;NOW DO THE RENAME BDOS FUNCTION ; RNFIL1: LXI D,DESTFCB ;RENAME FCB LOCATION MVI C,RENAM ;RENAME FUNCTION CODE CALL BDOS ;GO DO IT CPI 0FFH ;SEE IF RENAME ERROR JNZ NEXTPOS ;IF O.K. PROCEDE CALL PRTMSG ;OR ELSE PRINT ERROR MESSAGE DB ' ++ Not Found ++',0 JMP NEXTPOS ;GO TO NEXT LIST POSITION ; ; ;DELETE A FILE NAME AS SPECIFIED IN CURRENT POSITION POINTER ; DELFLE: LHLD LISTPOS ;MOVE NAME FROM LIST TO RENAME FCB LXI D,12 CALL SDEHL ;POINT TO NAME POSITION LXI D,DESTFCB ;PLACE TO MOVE THE NAME MVI B,12 ;AMOUNT TO MOVE CALL MOVBYT ; ; ;DELETE THE FILE NOW ; LXI D,DESTFCB ;POINT AT DELETE FCB MVI C,DELETE ;DELETE FUNCTION CODE CALL BDOS IF NOT CPM14 ;AVOID 1.4 BUG CPI 0FFH JNZ DELFL1 ;FILE DELETED O.K. CALL PRTMSG ;TYPE ERROR MESSAGE DB ' ++ Not Found ++',0 JMP NEXTPOS ENDIF ; DELFL1: CALL PRTMSG ;SAY IT HAS BEEN DELETED DB ' Deleted',0 ; ; ;MOVE LIST UP ONE POSITION TO CLOSE UP THE ERASED POSITION ; LHLD LISTPOS ;FIXUP MOVE UP POINTERS PUSH H LXI D,12 CALL SDEHL SHLD LISTPOS ;RESET CURRENT POSITION FOR MOVE XCHG ;(DE) = TO LOCATION POP H ;(HL) = FROM LOCATION ; MOVUP: XCHG PUSH H ;CHECK IF AT END LHLD LISTEND ;GET OLD END POINTER CALL CDEHL ;CHECK AGAINST CURRENT END LOCATION POP H XCHG JZ MOVDONE ;MUST BE AT END OF LIST MVI B,12 ;ONE NAME SIZE CALL MOVBYT ;MOVE ONE NAME UP JMP MOVUP ;GO CHECK END PARAMETERS ; MOVDONE: XCHG SHLD LISTEND ;SET NEW LIST END IF ALL MOVED LXI D,LIST ;SEE IF LIST IS EMPTY CALL CDEHL ;..IE LISTEND=LISTPOS=LIST JNZ NEXTPOS LHLD LISTPOS CALL CDEHL JNZ NEXTPOS ;NEITHER EQUAL SO NOT EMPTY CALL PRTMSG DB CR,LF,CR,LF,' List Empty',0 JMP EXIT ;BALE OUT IF DONE ; ; ;ENTRY POINT TO SEND CURRENT FILE NAME CONTENTS TO THE CONSOLE ; VIEW: CALL PRTMSG DB CR,LF,CR,LF,0 ;TURN UP TWO NEW LINES MVI A,WRCON ;WRITE CONSOLE OUT FUNCTION JMP OUTCM ;TO COMMON I/O PROCESSING ; ; ;ENTRY POINT TO SEND CURRENT FILE NAME CONTENTS TO THE LIST DEVICE ; PRTFIL: MVI A,WRLST ;WRITE LIST DEVICE OUT FUNCTION JMP OUTCM ;TO COMMON I/O PROCESSING ; ; ;ENTRY POINT TO SEND CURRENT FILE NAME CONTENTS TO THE PUNCH DEVICE ; PUNFIL: MVI A,WRPUN ;WRITE PUNCH DEVICE OUT FUNCTION ; ; ;COMMON OUTPUT CHARACTER I/O PROCESSING ENTRY ; OUTCM: STA OUTOP ;SAVE BDOS FUNCTION ; ; ;FETCH THE FILE NAME TO SEND OUT ; LHLD LISTPOS ;MOVE NAME FROM LIST TO SOURCE FCB LXI D,12 CALL SDEHL ;POINT TO NAME POSITION LXI D,SORCFCB ;PLACE TO MOVE THE NAME MVI B,12 ;AMOUNT TO MOVE CALL MOVBYT ; LXI D,BUFR ;SET TO USE DEFAULT DMA BUFFER MVI C,STDMA ;ADDRESS SET FUNCTION CALL BDOS ; MVI B,4 ;FILL EX,S1,S2,RC WITH ZEROS LXI H,SORCFCB+12 ;SET POINTER TO SOURCE EXTENT FIELD OUTCM1: MVI M,0 INX H DCR B JNZ OUTCM1 ; LXI D,SORCFCB ;OPEN THE FILE FOR READING MVI C,OPEN ;FILE OPEN FUNCTION CODE CALL BDOS CPI 0FFH JNZ OUTCM2 ;SKIP ERROR MESSAGE IF O.K. CALL PRTMSG DB ' ++ File Cannot Be Opened ++',0 JMP NEXTPOS ; OUTCM2: XRA A ;ZERO THE CURRENT RECORD FIELD STA SORCFCB+32 ; OUTCM3: LXI D,SORCFCB ;POINT AT FILE FCB FOR READING MVI C,READR ;FUNCTION SET FOR RECORD READ CALL BDOS ORA A ;CHECK IF READ WAS O.K. JZ OUTCM4 ;READ O.K. SO GO TO SEND OUT JMP NEXTPOS ;EOF SO TO NEXT LIST NAME POSITION ; OUTCM4: LXI H,BUFR ;POINT AT SECTOR JUST READ MVI B,080H ;SET SECTOR CHARACTER COUNTER TO OUTPUT OUTCM5: MOV A,M ;GET A CHARACTER CPI 01AH ;SEE IF LOGICAL END OF FILE JZ NEXTPOS ;BACK TO LIST LOOP IF LOG EOF MOV E,A ;POSITION CHARACTER FOR BDOS PUSH B PUSH H LDA OUTOP ;GET DEVICE CODE FOR OUTPUT MOV C,A CALL BDOS ;SEND THE CHARACTER ; MVI C,GETST ;GET CONSOLE STATUS FUNCTION CALL BDOS ;GO GET THE ABORT STATUS POP H POP B ; ORA A ;IF CHAR THERE, THEN ABORT JNZ BACKUP ; TO SAME LIST POSITION ; INX H ;INC BUFFER POINTER DCR B ;ALL BYTES OF SECTOR SENT YET? JNZ OUTCM5 ;MORE TO DO ; JMP OUTCM3 ;GO GET THE NEXT SECTOR ; ; ;ROUTINE TO COPY A DISK FILE NAMED BY THE CURRENT LIST POSITON TO ;A DIFFERENT DISK DRIVE OF OPERATOR SELECTION. ; COPY: LHLD LISTPOS ;MOVE NAME FROM LIST TO SOURCE FCB LXI D,12 CALL SDEHL ;POINT TO NAME POSITION LXI D,SORCFCB ;PLACE TO MOVE THE NAME MVI B,12 ;AMOUNT TO MOVE CALL MOVBYT ; MVI B,4 ;FILL EX,S1,S2,RC WITH ZEROS LXI H,SORCFCB+12 ;SET POINTER TO SOURCE EXTENT FIELD COPY1: MVI M,0 ;PUT ZERO IN INX H DCR B JNZ COPY1 ; XRA A ;ZERO THE CURRENT RECORD FIELD STA SORCFCB+32 ; MVI B,33 ;COPY SOURCE FCB TO DESTINATION FCB LXI H,SORCFCB ;FROM COPY POINT LXI D,DESTFCB ;TO COPY POINT CALL MOVBYT ;MOVE IT ACROSS ; LXI D,SORCFCB ;OPEN THE FILE FOR READING MVI C,OPEN ;FILE OPEN FUNCTION CODE CALL BDOS CPI 0FFH JNZ COPY2 ;SKIP ERROR MESSAGE IF O.K. CALL PRTMSG DB CR,LF,' ++ Source File Cannot Be Opened ++',0 JMP NEXTPOS ; COPY2: CALL PRTMSG ;PROMPT FOR DRIVE SELECT NAME DB ' Destination Drive ? ',0 MVI C,KEYIN ;GET SELECTION CALL BDOS CALL UPCASE ;CONVERT TO UPPER CASE SUI 'A' ;ZERO BASE FOR RANGE CHECK CPI 'P'-'A'+1 JNC CMDERR ;BACK TO COMMAND LOOP WITH "?" ; INR A ;BASE DRIVE SELECT FOR 1=A: STA DESTFCB ;SET INTO THE DESTINATION FCB ; MOV B,A ;SEE IF HE PICKED SAME DISK AS CURRENT LDA SORCFCB ;GET SOURCE DRIVE ID CMP B JNZ COPY2A ;NO THEY ARE DIFFERENT? CALL PRTMSG DB CR,LF,' ++ Cannot Select Same Disk as Source ++',CR,LF,0 JMP SAMEPOS ;LET HIM TRY AGAIN ; COPY2A: LXI D,DESTFCB ;SEARCH TO SEE IF THIS FILE EXISTED MVI C,SRCHF ;SEARCH FIRST FUNCTION CALL BDOS CPI 0FFH ;RETURN CODE IF NOT FOUND JZ COPY3 ;GO TO MAKE FUNCTION FOR NEW FILE ; CALL PRTMSG ;ASK IF TO REPLACE DB ' Replace ? ',0 MVI C,KEYIN ;GET HIS ANSWER CALL BDOS CALL UPCASE CPI 'Y' ;IF YES THEN DELETE IT AND COPY OVER JNZ NEXTPOS ;IF COPY NOT WANTED THEN ON TO NEXT ; LXI D,DESTFCB ;DELETE FILE THAT ALREADY EXISTS MVI C,DELETE ;ERASE FILE FUNCTION CODE CALL BDOS ; COPY3: LXI D,DESTFCB ;MAKE NEW FILE AND OPEN FOR WRITING MVI C,MAKE ;MAKE FUNCTION CODE CALL BDOS ;GO MAKE IT CPI 0FFH ;CHECK IF THE DIRECTORY WAS FULL JNZ COPY4 CALL PRTMSG DB CR,LF,' ++ Destination Directory Full ++',0 JMP NEXTPOS ;BACK TO LIST PROCESSOR IF ERROR ; COPY4: LXI B,0 ;FIGURE OUT HOW MANY SECTORS LHLD BDOS+1 ;FIT INTO MEMORY BUFFER DCX H XCHG ;(DE) = MAX ADDRESS ALLOWABLE LHLD BUFSTART ;START ADDRESS OF BUFFER COPY5: INX B ;INCREASE SECTOR COUNT BY ONE PUSH D LXI D,080H ;ONE SECTOR SIZE DAD D ;BUFFER ADDRESS + SEC SIZE POP D CALL CDEHL ;COMPARE VALUES TO SEE IF ALL DONE JNC COPY5 ;MORE WILL FIT? ; DCX B ;SET MAX SECTOR COUNT LESS BY ONE MOV A,B ;CHECK IF ANY MEMORY FOR COPY AT ALL ORA C JNZ COPY6 ;THERE IS MEMORY FOR BUFFER CALL PRTMSG DB CR,LF,' ++ No Memory Available for Copy Buffer ++',0 JMP NEXTPOS ; COPY6: MOV L,C MOV H,B ;PUT MAX SECTOR COUNT IN STORAGE SHLD BUFMAX XRA A ;CLEAR EOF FLAG STA EOFLG ; COPY6A: LXI H,0 ;SET CURRENT BUFFER COUNTER TO ZERO SHLD BUFCNT LHLD BUFSTART ;SET BUFFER START POINTER TO BEGIN SHLD BUFPNT ; ; ;FILE SOURCE READING LOOP TO READ ALL MEMORY FULL OR STOP ON EOF ; COPY7: LHLD BUFPNT ;SET DMA ADDRESS TO BUFFER POINTER XCHG MVI C,STDMA CALL BDOS ; LXI D,SORCFCB ;POINT AT FILE FCB FOR READING MVI C,READR ;FUNCTION SET FOR RECORD READ CALL BDOS ORA A ;CHECK IF READ WAS O.K. OF EOF JNZ COPY8 ;END OF FILE SO SET EOF FLAG ; LHLD BUFPNT ;SET BUFFER POINTER UP ONE SECTOR LXI D,080H DAD D SHLD BUFPNT LHLD BUFCNT ;INCREASE BUFFER SECTOR COUNT INX H SHLD BUFCNT XCHG ;CHECK TO SEE IF MEMORY IS FULL LHLD BUFMAX ;MAXIMUM SECTOR COUNT CALL CDEHL ;COMPARE JNZ COPY7 ;IF NOT FULL GO GET NEXT SECTOR JMP COPY9 ;GO HANDLE WRITE OPERATION ; ; ;HERE IF READ OPERATION INDICATES THAT THE FILE IS AT ITS END ON READ ; COPY8: MVI A,0FFH ;SET EOF FLAG STA EOFLG ; ; ;WRITE OUTPUT FILE PROCESSING LOOP TO SEND MEMORY BUFFER TO ;DESTINATION DISK FILE ; COPY9: LHLD BUFSTART ;SET BUFFER POINTER TO START SHLD BUFPNT ; COPY10: LHLD BUFCNT ;SEE IF BUFFER IS EMPTY YET MOV A,H ORA L JZ COPY11 ;BUFFER EMPTY SO CHECK EOF FLAG DCX H ;DEC BUFFER SECTOR COUNT FOR EACH WRITE SHLD BUFCNT ; LHLD BUFPNT ;SET UP DMA ADDRESS PUSH H ;SAVE FOR SIZE BUMP XCHG MVI C,STDMA CALL BDOS POP H LXI D,080H ;INCREASE ADDRESS FOR SECTOR SIZE DAD D SHLD BUFPNT ; LXI D,DESTFCB ;POINT TO OUTPUT FILE FCB MVI C,WRITER ;WRITE RECORD FUNCTION CODE CALL BDOS ;GO WRITE ORA A ;CHECK IF ANY ERROR-CAF JZ COPY10 ;O.K. SO DO NEXT RECORD ; CALL PRTMSG ;TELL OF DISK WRITE ERROR DB CR,LF,' ++ Disk or Directory Full or error on Write ++',0 ;ts JMP NEXTPOS ;BACK TO LIST PROCESSING ; COPY11: LDA EOFLG ;BUFFER ALL WRITTEN SO GO CHECK EOF ORA A JZ COPY6A ;GO TO READ NEXT BUFFER FULL ; LXI D,DESTFCB ;POINT AT FCB FOR FILE CLOSE MVI C,CLOSE ;CLOSE FILE FUNCTION CODE CALL BDOS CPI 0FFH ;CHECK IF CLOSE ERROR JNZ NEXTPOS CALL PRTMSG DB CR,LF,' ++ Destination Close Error ++',0 JMP NEXTPOS ; ; ;ROUTINE TO INQUIRE ABOUT SELECTING OPERATION ON ANOTHER DRIVE ; LOG: CALL PRTMSG ;PROMPT FOR DRIVE SELECT NAME DB ' New Drive ? ',0 MVI C,KEYIN ;GET SELECTION CALL BDOS CALL UPCASE ;CONVERT TO UPPER CASE CPI CR ;IF CARRIAGE RETURN SKIP RE-LOG JZ NEXTPOS ; SUI 'A' ;ZERO BASE FOR RANGE CHECK CPI 'P'-'A'+1 JNC CMDERR ;BACK TO COMMAND LOOP WITH "?" ; INR A ;BASE DRIVE SELECT FOR 1=A: STA FCB ;SET INTO THE START DEFAULT FCB MVI A,' ' ;SET DEFAULT FCB TO LOOK LIKE *.* STA FCB+1 STA FCB+9 JMP RESTART ;GO RESTART WITH MENU PRINT OVER ; ; ; ;*************************************************************************** ; ; UTILITY SUBROUTINES ; ;COMPARE DOUBLE REGISTERS (DE) TO (HL) SIMILAR TO CMP B INSTRUCTION AND SET ;FLAGS ACCORDINGLY. ; CDEHL: MOV A,D ;SEE IF HIGH BYTES SET FLAGS CMP H RNZ ;RETURN IF NOT EQUAL MOV A,E CMP L ;LOW BYTES SET THE FLAGS INSTEAD RET ; ; ;SUBTRACT DOUBLE REGISTERS (DE) FROM (HL) LEAVING RESULT IN (HL) ; SDEHL: MOV A,L ;DO LOW BYTES FIRST SUB E MOV L,A ;SET LOW BYTE OF RESULT BACK MOV A,H ;HIGH BYTES NOW SBB D ;SUBTRACT HIGH AND BORROW MOV H,A ;HIGH BYTE OF RESULT BCK TO (H) RET ; ; ;MOVE SUBROUTINE MOVE (B) BYTES FROM (HL) TO (DE) ; MOVBYT: MOV A,M ;GET (HL) REFERENCED SOURCE BYTE ANI 7FH ;STRIP CP/M 2.x ATTRIBUTES STAX D ;PUT TO (DE) REFERENCED DESTINATION INX H ;FIX POINTERS FOR NEXT SEARCH INX D DCR B ;DEC BYTE COUNT AND SEE IF DONE JNZ MOVBYT RET ; ; ;INLINE PRINT OF MESSAGE TILL A ZERO ; PRTMSG: XTHL ;SAVE HL, GET MSG POINTER ; PRTMLP: MOV A,M ;GET CHARACTER ANI 07FH ;STRIP USER TYPE BITS MOV E,A INX H ;INCREMENT POINTER TO NEXT CHAR ;..OR RETURN ADDRESS JZ PMXIT ;EXIT IF ZERO ; PUSH H ;SAVE MESSAGE POINTER MVI C,WRCON ;CHARACTER OUTPUT FUNCTION CODE CALL BDOS ;OUTPUT IT POP H JMP PRTMLP ;GO CHECK/DO NEXT CHAR ; PMXIT: XTHL ;RESTORE HL, RET ADDR RET ;RET PAST MSG ; ; ;CONVERT CHARACTER IN (A) TO UPPER CASE ; UPCASE: ANI 07FH ;STRIP UPPER BIT CPI 060H ;IS CHAR ONE REQUIRING CONVERT RC ;NO CONVERT NEEDED ANI 05FH ;CONVERT RET ; ; ;CHECK FOR LEGAL FILE NAME CHARACTER ; CHKLEGL: LDAX D ;GET CHARACTER FROM .(DE) INX D ;TO POINT AT NEXT CHARACTER CPI ' ' ;IS IT LESS THAN SPACE RC ;RETURN CARRY IF ERROR CHAR CPI 05FH ;IF GREATER THAN UNDERSCORE ERROR JNC CHKERR ;CARRY SET EXIT CPI '=' JZ CHKERR CPI ':' JZ CHKERR CPI ';' JZ CHKERR CPI '<' JZ CHKERR CPI '>' JZ CHKERR ORA A ;CLEAR CARRY FOR GOOD CHAR RET ; CHKERR: STC ;ERROR EXIT RET ; ; ;ROUTINE TO COMPARE TWO STRINGS LEFT TO RIGHT SIMILAR TO CMP B INSTRUCTION ; ; (B)=STRING LENGTH ; (DE)=STRING A BASE POINTER ; (HL)=STRING B BASE POINTER ; CMPSTR: LDAX D ;GET AN A STRING CHARACTER CMP M ;CHECK AGAINST B STRING CHARACTER RNZ ;NOT EQUAL SETS RETURN FLAGS DCR B ;DECREMENT COMPARE BYTE COUNT RZ ;SET LIKE EQUAL IF ALL COMPARED EQUAL INX H ;BUMP COMPARE POINTERS INX D JMP CMPSTR ;TO DO NEXT CHARACTER ; ; ;ROUTINE TO INTERCHANGE TWO STRINGS FOR SORTING ; ; (B)=STRING LENGTH ; (DE)=STRING A BASE POINTER ; (HL)=STRING B BASE POINTER ; SWAP: MOV C,M ;GET CHAR FROM ONE STRING LDAX D ;AND ONE FROM OTHER STRING MOV M,A ;SECOND INTO FIRST MOV A,C ;FIRST INTO SECOND STAX D INX H ;BUMP SWAP POINTERS INX D DCR B ;SEE IF ALL BYTES SWAPPED YET JNZ SWAP RET ; ; ;************************************************************************* ; ; ; DS 080H ;DEFINE STORAGE FOR AN EXECUTION STACK STCKK: DS 2 ; SORCFCB: DS 33 ;FCB FOR SOURCE FILE ; DESTFCB: DS 33 ;FCB FOR DESTINATION FILE IF COPY ;AND NEW NAME IF RENAME FUNCTION ; MAXLEN EQU 25 ;MAXIMUM BUFFER INPUT LENGTH ; CBUFF: DB MAXLEN ;COMMAND BUFFER LENGTH CBUFFL: DB 0 ;CURRENT INPUT LENGTH CSTRING: DS MAXLEN+3 ;STORAGE FOR INPUT ; LISTPOS: DS 2 ;CURRENT LIST POSITION IN SCAN ; LISTI: DS 2 ;LIST SORT POINTER ; LISTJ: DS 2 ;ANOTHER LIST SORT POINTER ; LISTEND: DS 2 ;CURRENT LIST END POINTER ; BUFSTART: DS 2 ;START POINTER FOR COPY BUFFER ; BUFPNT: DS 2 ;CURRENT POINTER FOR COPY BUFFER ; BUFMAX: DS 2 ;MAXIMUM NUMBER OF BUFFER SECTORS ; BUFCNT: DS 2 ;NUMBER OF SECTORS CURRENTLY IN BUFFER ; OUTOP: DS 1 ;SIMPLE FILE OUTPUT DESTINATION FUNCTION ;EQUAL TO BDOS FLAG ; EOFLG: DS 1 ;FILE COPY LOOP EOF FLAG ; LIST: DS 1 ;BASE OF FILE NAME LIST ; ; ; END ; ; ;+++...END OF FILE