RED segment para public 'code'
	assume cs:red, ds:red, es:red, ss:nothing
	org 100h		;.com format
begin:	
	jmp	code_start	; jump around data declarations
declare:	; messages, storage areas, equates
	copyright	db	'REDirect (C) 1985, Dickinson Associates Inc.'
			db	13,10,'$'
	path_file_len	equ	77  ;length=1, path=63, filename=12, 0=1
	source_file	db	path_file_len dup (0)
	target_path	db	path_file_len dup (0)
	source_end	dw	0
	target_end	dw	0
	pc_dos_ver	db	0
	valid_in	db	'abcdefghijklmnopqrstuvwxyz,;=',9
	valid_out	db	'ABCDEFGHIJKLMNOPQRSTUVWXYZ',4 DUP(32)
	valid_num	equ	$ - valid_out + 1
	err_flag	db	0
	err_head	db	10,13,'REDirect Error - $'
	bad_version	db	'Incorrect PC-DOS Version$'
	no_parms	db	'Correct Syntax is:',13,10,10
	db	'RED [d:][source_path]source_filename[.ext] [d:][target_path]$'
	file_not_found	db	'File not Found$'
	path_not_found	db	'Target Path not Found$'
	pc_dos_2_patch	db	13,10,'or $'
	drives_conflict	db	'Source and Target Disk Drives Conflict$'
	undefined_err	db	'Undefined Error: PC-DOS Function 56H$'
	err_tail	db	10,10,13,' . . . Aborting',10,13,13,'$'
	good_msg	db	' . . REDirected to . . $'
	bad_msg1	db	' . . Not REDirected . . $'
	bad_msg2	db	' . . already exists$'
	end_line	db	10,13,'$'
code_start:	;parse command line into source and target parameters
	mov	dx,offset copyright	;display copyright notice
	mov	ah,9h
	int	21h
	mov	ah,30h			; get pc-dos version
	int	21h
	mov	pc_dos_ver,al
	mov	si,80h			;psp parameter byte count pointer
	mov	cl,[si]			;move byte count to cl
	xor	ch,ch			;zero ch
	jcxz	no_parms_passed		;if cx is zero, there are no parameters
	mov	dx,cx			;save byte count in dx
	inc	si			;point to parameter area
	mov	di,si			;copy si to di for cleanup routine
	cld				;set direction flag to forward
clean_parms:	;change valid delimiters to blanks, lower to upper case
	lodsb				;load each character to al
	push	di			;save di on stack
	mov	di,offset valid_in	;point to table of valid inputs
	push	cx			;save cx on stack
	mov	cx,valid_num		;set CX TO NUMBER OF INPUTS TO LOOK FOR
repne	scasb				;see if any are in al
	jcxz	clean_end		;if not, change nothing
	mov	bx,valid_num		;set up bx to point to valid output
	sub	bx,cx			;this will leave bx one off
	mov	al,valid_out [bx-1]	;load the valid output to al
clean_end:
	pop	cx			;restore cx
	pop	di			;restore di
	stosb				;store modified al back to psp
loop	clean_parms			;loop until cx is zero
	mov	cx,dx			;restore number of bytes in psp to cx
	mov	dx,2			;set dx to look for up to 2 parameters
	mov	bx,offset source_file	;set bx to address of 1st parameter
	mov	al,' '			;set up to scan for first non-blank
	mov	di,81h			;set di to pc-dos parameter pointer
find_parms:	;start looking for parameters, load to program storage
repe	scasb				;scan while blanks
	mov	si,di			;set si to second non-blank byte
	dec	si			;adjust it to first non-blank byte
	inc	cx			;adjust cx to compensate
	jcxz	parms_loaded		;if cx is zero, no parameters left
	mov	di,bx			;set di to parameter hold area
	mov	ax,cx			;store cx to first byte of hold area
	stosb				;di is adjusted to second byte here
store:	lodsb				;load each byte to al
	cmp	al,' '			;is it a blank?
	jz	end_store		;yes, end of this parameter
	stosb				;no, store the byte to hold area
end_store:	
	loopnz	store			;keep looking
	sub	[bx],cx			;store number of bytes in each
	jcxz	parms_loaded		;if cx is zero, no more parameters
	dec	byte ptr	[bx]	;parameter to first byte of hold area
	mov	di,si			;set up to scan for next non-blank
	dec	di			;adjust di to point to the blank
	inc	cx			;adjust cx to compensate
	dec	dx			;decrement dx counter
	cmp	dx,0			;is dx zero?
	jz	parms_loaded		;yes all expected parameters loaded
	add	bx,path_file_len	;no, point to next part of hold area
	jmp	find_parms		;go back and look for more
parms_loaded:				;all parameters are loaded
	cmp	source_file[0],0	;if there are no bytes in the
	ja	fix_up			;source_file, no paramters present
no_parms_passed:			;exit with an error if there are
	mov	dx,offset no_parms	;no parameters passed
	jmp	error_exit
fix_up:					;fix source_file and target_path
	mov	si,offset source_file	;for search and rename calls
	lodsb				;get number of bytes
	xor	ah,ah			;zero	ah
	mov	di,si			;mov si to di for scan
	add	di,ax			;start scan at end of parameter
	dec	di			;
	mov	cx,ax			;set cx to number of bytes
	mov	al,'\'			;scan for the last '\'
	std				;set direction flag to reverse
repnz	scasb				;scan while not '\'
	jnz	no_source_dir		;if zero flag not set, '\' not found
	add	di,2			;add 2 to di to point to file name
	jmp	source_fixed		;position
no_source_dir:				;no source directory was specified
	add	di,1			;adjust di
	cmp	source_file[2],':'	;check for specified disk drive
	jne	source_fixed		;none present, we're done
	mov	di,offset source_file[3];yes, set di to point of first byte
source_fixed:				;after ':'
	mov	source_end,di		;move di to source_end pointer
	cld				;set direction flag to forward
	mov	si,offset target_path	;set up to look for '\' present
	lodsb				;get number of bytes
	cmp	al,0			;if it's zero, no target specified
	je	no_target
	xor	ah,ah			;zero ah
	add	si,ax			;add it to si to point to end
	dec	si			;decrement si to adjust
	lodsb				;look at last byte
	mov	di,si			;copy si to di
	cmp	al,'\'			;is last byte a '\'?
	je	target_fixed		;yes, everything's fine
	cmp	target_path[0],2	;if target_path is 2 bytes long and
	jne	store_slash		;is a drive specification,
	cmp	target_path[2],':'	;let it default to the current
	je	target_fixed		;directory
store_slash:				;place a '\' at the end of
	mov	al,'\'			;target_path if user did not
	stosb
target_fixed:
	mov	target_end,di		;move di to target_end pointer
	jmp	find_file
no_target:				;set up to allow target path default
	mov	target_end,offset target_path + 1	;to current path
find_file:
	mov	dx,offset source_file + 1	;dx points to source file
	mov	ah,4Eh			;request function 4Eh (find first file)
	mov	cx,0			;set cx to zero for normal files only
	int	21h			;call pc-dos
	jnc	found_file		;if no error, first file found
	mov	dx,offset file_not_found	;if no files found, exit
	jmp	error_exit			;program with error message
found_file:
	mov	di,source_end		;di points to end of source path
	mov	si,9Eh			;si points to default DTA in psp
	mov	cx,13			;dta will have 13 bytes
rep	movsb				;move bytes to source_file
	mov	di,target_end		;di points to end of target path
	mov	si,9Eh			;si points to default DTA in psp
	mov	cx,13			;DTA will have 13 bytes
rep	movsb				;move bytes to target_path
	mov	dx,offset source_file + 1	;dx points to old file name
	mov	di,offset target_path + 1	;di points to new file name
	mov	ah,56h			;request function 56h (rename file)
	int	21h			;call pc-dos
	jnc	good_red		;if no error, call was successful
	cmp	ax,3			;check for error 3 (path not found)
	jne	err_5
	mov	dx,offset path_not_found
	jmp	error_exit		;exit program with error message
err_5:	cmp	ax,5			;check	for error 5 (file inaccessible)
	jne	err_17
	mov	err_flag,1		;soft error -
	call	red_msg			;issue message with subroutine
	jmp	next_file		;and keep going
err_17:	cmp	ax,17			;check for error 17 (drive conflict)
	jne	undef
	mov	dx,offset drives_conflict
	jmp	error_exit		;exit program with error message
undef:	mov	dx,offset undefined_err	;undefined error from function 56h
	jmp	error_exit		;exit program with error message
good_red:				
	mov	err_flag,0		;set error flag off and
	call	red_msg			;issure message with subroutine
next_file:				;look for next file
	mov	ah,4Fh			;request function 4fh (find next file)
	mov	cx,0
	int	21h
	jnc	found_another		;no error, another file was found
	jmp	end_ok			;error, we're done finding files
found_another:
	jmp	found_file		;go process next file
end_ok:	int	20h			;exit to pc-dos

error_exit:				;print error message and exit
	push	dx			;save error message pointer on stack
	mov	ah,9
	mov	dx,offset err_head
	int	21h
	mov	ah,9
	pop	dx
	int	21h
	mov	ah,9
	mov	dx,offset err_tail
	int	21h
	int	20h			;exit to pc-dos

red_msg	proc	near	;display message for each file
	mov	cx,2			;2 fields - source & target file
	mov	bx,offset source_file + 1	;point to source file
start1:	mov	si,bx			;copy bx to si
start2:	lodsb				;load each byte to al
	cmp	al,0			;if ascii 0 end of field
	je	between
	mov	dl,al			;copy byte to dl for funtion 2h
	mov	ah,2h			;request function 2h
	int	21h			;call pc-dos
	jmp	start2			;get next character
between:cmp	cx,2			;is it first or second field
	jne	cr_lf			;if second, display end of message
	cmp	err_flag,0		;is this a success message?
	jz	ok1			;yes, go to good_msg
	mov	dx, offset bad_msg1	;no, display first part of bad_msg
	mov	ah,9h			;request function 9h
	int	21h			;call pc-dos
	jmp	next			;go process next field
ok1:	mov	dx, offset good_msg	;display good_msg
	mov	ah,9h			;request function 9h
	int	21h			;call pc-dos
	jmp	next			;go process next field
cr_lf:	cmp	err_flag,0		;is this a success message?
	jz	ok2			;yes, go to terminate message
	mov	dx,offset bad_msg2	;no, display second part of bad_msg
	mov	ah,9h			;request function 9h
	int	21h			;call pc-dos
pc_dos_2:				;patch for incorrect error
	cmp	pc_dos_ver,3		;return in pc_dos 2.0 and 2.1
	jae	ok2
	mov	dx,offset pc_dos_2_patch
	mov	ah,9h
	int	21h
	mov	dx,offset path_not_found
	int	21h
ok2:	mov	dx,offset end_line	;terminate display line
	mov	ah,9h			;request function 9h
	int	21h
next:	add	bx,path_file_len		;move bx to point to next field
	loop	start1			;loop for second field
	ret				;or end and return to calling point
red_msg		endp
red	ends
	end	begin
