RENDIR segment para public 'code' assume cs:RENDIR, ds:RENDIR, es:RENDIR, ss:NOTHING org 100h ; .COM format BEGIN: jmp CODE_START ; Jump around data declarations DECLARE: ; Equates and Storage allocation for messages & data areas COPYRIGHT db 'RENDIR (C) 1986, Ziff-Davis Publishing Co.' db 13,10,'$' PATH_FILE_LEN equ 77 ;Length = 1, Path = 63, FileName = 12, 0 = 1 SOURCE_NAME db PATH_FILE_LEN dup (0) TARGET_NAME db PATH_FILE_LEN dup (0) TARGET_END dw $ - 1 VALID_IN db '/abcdefghijklmnopqrstuvwxyz,;=',9 VALID_OUT db '\ABCDEFGHIJKLMNOPQRSTUVWXYZ',4 dup(32) VALID_NUM equ $ - VALID_OUT + 1 ERR_HEAD db 10,13,'RENDIR Error - $' BAD_VERSION db 'Must be PC-DOS 3.0 or Higher$' NO_PARMS db 'Correct Syntax is:',13,10,10 db 'RENDIR [D:][Source_Path]Source_Name[.Ext] ' db 'Target_Name[.Ext]$' NO_TARGET db 'No Target Name Specified$' BAD_TARGET db 'Invalid "\" or ":" in Target Name$' DIR_NOT_FOUND db 'Source Directory Not Found$' NOT_DIRECTORY db 'Source File Not a Directory$' PATH_NOT_FOUND db 'Source or Target Path Not Found$' ACCESS_DENIED db 'Access to Target Denied or Target Exists$' 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_MSG1 db 10,13,'Directory "$' GOOD_MSG2 db '" . . renamed to . . "$' GOOD_MSG3 db '"$' END_LINE db 10,13,'$' CODE_START: ; Processing logic starts here mov dx,offset COPYRIGHT ; Display copyright notice mov ah,9h ; Request display string int 21h ; Call PC-DOS mov ah,30h ; Request PC-DOS version int 21h ; Call PC-DOS cmp al,3 ; Must be 3.0 or higher jae VERSION_OK ; If it is, keep going mov dx,offset BAD_VERSION ; Otherwise, exit with error jmp ERROR_EXIT VERSION_OK: ; Parse command line into source name and target name mov si,80h ; PSP parameter byte count pointer mov cl,[si] ; Move byte count to CL xor ch,ch ; Zero CH jcxz PARMS_NO_GOOD ; 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_NAME ; 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_NAME[0],0 ; If there are no bytes in the je PARMS_NO_GOOD ; SOURCE_NAME, no parameters present cmp TARGET_NAME[0],0 ; Same for TARGET_NAME ja CHECK_PARMS PARMS_NO_GOOD: ; Exit with an error if there mov dx,offset NO_PARMS ; are no or incorrect parameters passed jmp ERROR_EXIT CHECK_PARMS: ; Check for '\' or ':' in target name mov di,TARGET_END ; Point DI to end of parameter area mov si,offset TARGET_NAME ; Point SI to number of bytes area lodsb ; Load number of bytes to AL xor ah,ah ; Zero AH mov cx,ax ; Move to CX for loop push cx ; Save CX on stack add si,cx ; Adjust SI to end of target name dec si ; std ; Set direction flag to reverse MOVE_TARGET: ; Move target to end of area while lodsb ; checking for '\' cmp al,'\' je BAD_TARGET_FOUND ; If found, target is bad cmp al,':' je BAD_TARGET_FOUND stosb ; Store byte to end of area loop MOVE_TARGET ; Keep looking add di,1 ; Adjust DI push di ; Save DI on stack jmp FIND_SOURCE_DIR ; Go process source name BAD_TARGET_FOUND: ; Exit with error if target mov dx,offset BAD_TARGET ; contains a '\' jmp ERROR_EXIT FIND_SOURCE_DIR: ; Look for end of path name in source mov si,offset SOURCE_NAME ; Point SI to number of bytes lodsb ; Load number of bytes to AL xor ah,ah ; Zero AH mov di,si ; Move SI to DI for scan mov cx,ax ; Move AX to CX for scan repeat add di,cx ; Adjust DI to end of source name dec di ; mov al,'\' ; Scan for '\' repnz scasb cld ; Set direction flag to forward jnz NO_DIR ; Directory is in current directory dec cx ; Adjust CX mov di,offset TARGET_NAME + 1 ; Point DI to target name mov si,offset SOURCE_NAME + 1 ; Point SI to source name rep movsb ; Move path name to target name jmp MOVE_NAME ; DI points to position for target name NO_DIR: ; No path, point to beginning of name cmp SOURCE_NAME[2],':' ; Check for disk drive specification jne NO_DISK mov di,offset TARGET_NAME + 1 ; Point DI to target name mov si,offset SOURCE_NAME + 1 ; Point SI to source name mov cx,2 ; Move the two bytes into target name rep movsb ; that contain disk drive specification jmp MOVE_NAME NO_DISK: mov di,offset TARGET_NAME + 1 MOVE_NAME: ; Move target name to correct position pop si ; Restore saved DI in SI pop cx ; Restore CX rep movsb mov al,0 ; Finish ASCIIZ string with a binary 0 stosb FIND_DIRECTORY: ; Does source directory exist? mov dx,offset SOURCE_NAME+1 ; DX points to SOURCE_NAME mov ah,4eh ; Request find file mov cx,10h ; Set attribute for directories int 21h ; Call PC-DOS jnc FOUND_FILE ; If no error, a file was found jmp NO_DIRECTORY FOUND_FILE: mov si,95h ; Position of attribute byte in DTA lodsb ; Load attribute byte to AL and al,10h ; Check to see if it's a directory jnz RENAME_DIRECTORY ; If not zero, it's a directory mov dx,offset NOT_DIRECTORY jmp ERROR_EXIT NO_DIRECTORY: ; Exit with error if no directory mov dx,offset DIR_NOT_FOUND ; If file not found, exit jmp ERROR_EXIT ; program with error message RENAME_DIRECTORY: mov dx,offset SOURCE_NAME + 1 ; DX points to old file name mov di,offset TARGET_NAME + 1 ; DI points to new file name mov ah,56h ; Request rename file int 21h ; Call PC-DOS jnc GOOD_RENDIR ; 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 dx,offset ACCESS_DENIED jmp ERROR_EXIT 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_RENDIR: ; Exit with message mov ah,9h ; Request display string mov dx,offset GOOD_MSG1 ; Display GOOD_MSG1 int 21h ; Call PC-DOS mov cx,2 ; 2 fields - source & target file mov bx,offset SOURCE_NAME + 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 funciton 2H mov ah,2h ; Request display one byte 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 mov ah,9h ; Request display string mov dx,offset GOOD_MSG2 ; Display GOOD_MSG2 int 21h ; Call PC-DOS jmp NEXT ; Go process next field CR_LF: mov ah,9h ; Request display string mov dx,offset GOOD_MSG3 ; Display GOOD_MSG3 int 21h ; Call PC-DOS mov dx,offset END_LINE ; Terminate display line mov ah,9h ; Request display string int 21h ; Call PC-DOS NEXT: add bx,PATH_FILE_LEN ; Move BX to point to next field loop START1 ; Loop for second field jmp EXIT ; Exit RENDIR ERROR_EXIT: ; Print Error Message and Exit push dx ; Save error message pointer on stack mov ah,9h ; Request display string mov dx,offset ERR_HEAD ; Display error header int 21h ; Call PC-DOS pop dx ; Display error message int 21h ; Call PC-DOS mov dx,offset ERR_TAIL ; Display error tail int 21h ; Call PC-DOS EXIT: int 20h ; Exit to PC-DOS RENDIR ends end BEGIN