;	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
