BAC segment para public 'code' assume cs:BAC, ds:BAC, es:BAC, ss:NOTHING org 100h ; .COM format BEGIN: jmp CODE_START ; Jump around data declarations DECLARE: ; Messages, Storage Areas, Equates COPYRIGHT db 'BACopy (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 SOURCE_HANDLE dw 0 TARGET_HANDLE dw 0 SOURCE_DTA db 44 dup(0) TARGET_DTA db 44 dup(0) VALID_IN db 'abcdefghijklmnopqrstuvwxyz,;=',9 VALID_OUT db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',4 dup(32) VALID_NUM equ $ - VALID_OUT + 1 BLKSIZE dw 0 LAST_BLOCK db 0 EVENT_FLAG db 0 ERR_HEAD db 10,13,'BACopy Error - $' NO_PARMS db 'Correct Syntax is:',13,10,10 db 'BACopy [d:][source_path]source_filename[.ext] [d:][target_path]$' FILE_NOT_FOUND db 'File Not Found$' SOURCE_ERROR db 'Opening Source File$' CREATE_ERROR db 'Creating Target File$' TARGET_FULL db '!!',10,10,13,'Target Disk is Full',13,10,10 db 'Insert New Disk and Press [Enter]',7,'$' ERR_TAIL db 10,10,13,' . . . Aborting',10,13,13,'$' CONFIRM_MSG_1 db ' . . $' CONFIRM_MSG_2 db 'BACopied to . . $' END_LINE db 10,13,'$' NOTHING_TO_DO db 13,10,'No Files Needed to be BACopied',13,10,'$' ; CODE_START: ; Parse command line into source & target parameters mov dx,offset COPYRIGHT ; Display copyright notice mov ah,9h int 21h 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 parameters present NO_PARMS_PASSED: ; Exit with an error if there mov dx,offset NO_PARMS ; are no parameters passed jmp ERROR_EXIT FIX_UP: ; Fix SOURCE_FILE and TARGET_PATH mov si,offset SOURCE_FILE ; For Search calls lodsb ; Get Number of bytes xor ah,ah ; Zero high byte of AX mov di,si ; Move SI to DI for scan add di,ax ; Start scan at end of parameter dec di ; Adjust 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 to 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 high byte of AX 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 disk 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 stosb ; not TARGET_FIXED: mov TARGET_END,di ; Move DI to TARGET_END pointer jmp BUFFER_SIZE NO_TARGET: ; Set up to allow target path default mov TARGET_END,offset TARGET_PATH + 1 ; to current path BUFFER_SIZE: ; Compute size of file buffer mov ax,0fdffh ; Leave plenty of room in segment mov dx,offset FILE_BUFFER ; for stack & set DX to end of code sub ax,dx ; Subtract mov BLKSIZE,ax ; Save result in BLKSIZE FIND_FILE: ; Find first source file xor ax,ax ; Request to use SOURCE_DTA mov ah,1ah ; to house FCB for SOURCE_FILE mov dx,offset SOURCE_DTA int 21h ; Call PC-DOS mov dx,offset SOURCE_FILE + 1 ; DX points to SOURCE_FILE mov ah,4eh ; Request function 4EH (find 1st 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 LAST_BLOCK,0 ; Initalize last block read flag mov si,offset SOURCE_DTA+30 ; SI points to source file name in DTA mov di,SOURCE_END ; DI points to end of source path push si ; Save pointer to source file name mov cx,13 ; DTA will have 13 bytes rep movsb ; Move name bytes to SOURCE_FILE mov di,TARGET_END ; DI points to end of target path pop si ; Recover pointer to source file name mov cx,13 ; DTA will have 13 bytes rep movsb ; Move file name bytes to TARGET_PATH FIND_TARGET: ; Find matching target file mov ah,1ah ; Request to use TARGET_DTA xor al,al ; to house FCB for TARGET_PATH mov dx,offset TARGET_DTA int 21h ; Call PC-DOS mov ah,4eh ; Request find 1st file for target mov dx,offset TARGET_PATH+1 mov cx,0 ; Set CX to zero for normal files only int 21h ; Call PC-DOS jc OPEN_SOURCE ; If not found, bypass date & time check CHECK_TIME_DATE: ; Check time & date stamps in DTAs mov si,offset SOURCE_DTA+24 ; Load source file date stamp to AX lodsw mov dx,ax ; Save in DX mov si,offset TARGET_DTA+24 ; Load target file date stamp to AX lodsw cmp dx,ax ; If Source file newer, jump ja OPEN_SOURCE ; to OPEN_SOURCE jne DONT_COPY ; If Source file older, don't copy it mov si,offset SOURCE_DTA+22 ; Otherwise, lodsw ; load source time stamp to AX mov dx,ax ; Save in DX mov si,offset TARGET_DTA+22 ; Load target time stamp to AX lodsw cmp dx,ax ; If Source file newer, jump ja OPEN_SOURCE ; to OPEN_SOURCE jmp DONT_COPY DONT_COPY: ; Otherwise, call CLOSE_ALL ; Close all files jmp NEXT_FILE ; Check for next file OPEN_SOURCE: mov ah,3dh ; Request Open Source File mov dx,offset SOURCE_FILE+1 ; DX points to source file path name mov al,0 ; with read permission only int 21h ; Call PC-DOS mov SOURCE_HANDLE,ax ; Save handle in memory jnc CREATE_TARGET ; If no carry, open was good mov dx,offset SOURCE_ERROR ; Otherwise, exit with error mov SOURCE_HANDLE,0 ; Make sure CLOSE_ALL ignores handle jmp ERROR_EXIT CREATE_TARGET: xor ax,ax mov ah,3ch ; Request create & open a file mov dx,offset TARGET_PATH+1 ; named the target file xor cx,cx ; with normal attribute int 21h ; Call PC-DOS mov TARGET_HANDLE,ax ; Save target handle jnc PROCEED_TO_COPY ; If no carry, create / open is ok mov dx,offset CREATE_ERROR ; Otherwise, exit with an error mov TARGET_HANDLE,0 ; Make sure CLOSE_ALL ignores target jmp ERROR_EXIT PROCEED_TO_COPY: ; The heart of the matter mov si,offset SOURCE_FILE+1 ; Point to source file START1: lodsb ; Load each byte to AL cmp al,0 ; If ASCII 0, end of field je DOTS mov dl,al ; Copy byte to DL for funciton 2H mov ah,2h ; Request function 2H int 21h ; Call PC-DOS jmp START1 ; Get next character DOTS: mov ah,9h ; Confirm start of task mov dx,offset CONFIRM_MSG_1 int 21h KEEP_COPYING: mov ah,3fh ; Request read block of data mov cx,BLKSIZE ; BLKSIZE bytes long mov bx,SOURCE_HANDLE ; from source file mov dx,offset FILE_BUFFER ; into buffer int 21h ; Call PC-DOS cmp ax,0 ; If AX is 0, no bytes were je FINISH ; read, and we're done mov cx,ax ; Move AX to CX for write call (below) cmp cx,BLKSIZE ; Check number of bytes read against je MORE_TO_COME ; request. If equal, we got them all, mov LAST_BLOCK,1 ; otherwise, it's the last block of file MORE_TO_COME: ; push cx ; Save requested write count on stack mov ah,40h ; Request write block of data mov bx,TARGET_HANDLE ; to target file mov dx,offset FILE_BUFFER ; from file buffer int 21h ; Call PC-DOS pop cx ; Recover requested write count cmp ax,cx ; If CX equals AX, je WRITE_OK ; write was successful, DISK_FULL: call CLOSE_ALL ; Otherwise disk is full -- close files mov ah,41h ; Request erase file mov dx,offset TARGET_PATH+1 ; for incomplete target. int 21h ; Call PC-DOS mov dx,offset TARGET_FULL mov ah,9h int 21h READ_KEYBOARD: ; Prompt requested [Enter] key mov ah,8h ; Make sure [Ctrl]-[Break] is detected int 21h ; Call PC-DOS for key cmp al,13 ; Check for [Enter] jne READ_KEYBOARD ; (no extended codes are 13) mov cx,2 END_FULL: mov dx,offset END_LINE ; Send a new line to screen mov ah,9h int 21h loop END_FULL jmp FOUND_FILE ; Re-start from FOUND_FILE: WRITE_OK: cmp LAST_BLOCK,1 ; If this is the last block, je FINISH ; we're done jmp KEEP_COPYING ; Otherwise, keep going. FINISH: ; Force target time & date stamps mov ah,57h ; to equal source, close files mov al,0 ; Request get time and date stamos mov bx,SOURCE_HANDLE ; for source file int 21h ; DX & CX contain data mov ah,57h ; Request set date and time mov al,1 ; to force target file to mov bx,TARGET_HANDLE ; source stamp int 21h ; Call PC-DOS call CLOSE_ALL ; Go close all files mov dx,offset CONFIRM_MSG_2 ; Confirm completion of task mov ah,9h ; Request function 9H int 21h ; Call PC-DOS mov si,offset TARGET_PATH+1 ; Point to source file START2: lodsb ; Load each byte to AL cmp al,0 ; If ASCII 0, end of field je CR_LF mov dl,al ; Copy byte to DL for funciton 2H mov ah,2h ; Request function 2H int 21h ; Call PC-DOS jmp START2 ; Get next character CR_LF: mov dx,offset END_LINE ; Terminate display line mov ah,9h ; Request function 9H int 21h mov EVENT_FLAG,1 ; Set flag to indicate file was copied NEXT_FILE: ; Go Look for next file xor ax,ax mov ah,1ah ; Request to use SOURCE_DTA mov dx,offset SOURCE_DTA ; to house FCB for SOURCE_FILE int 21h ; Call PC-DOS mov ah,4fh ; Request find next source file mov cx,0 ; Normal files only int 21h ; Call PC-DOS 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: cmp EVENT_FLAG,1 ; Did anything happen? je EXIT ; Yes, just exit mov dx,offset NOTHING_TO_DO ; No, tell user that nothing happened mov ah,9h int 21h EXIT: int 20h ; Exit to PC-DOS ERROR_EXIT: ; Print Error Message and Exit push dx ; Save error message pointer on stack mov ah,9 ; Display error header mov dx,offset ERR_HEAD int 21h mov ah,9 ; Display error message pop dx int 21h mov ah,9 ; Display error tail mov dx,offset ERR_TAIL call CLOSE_ALL int 21h int 20h ; Exit to PC-DOS CLOSE_ALL proc cmp SOURCE_HANDLE,0 ; Check for valid SOURCE_HANDLE je CLOSE_TARGET ; None, then go close target mov ah,3eh ; Request close file mov bx,SOURCE_HANDLE ; for source handle int 21h ; Call PC-DOS mov SOURCE_HANDLE,0 ; Refresh handle CLOSE_TARGET: cmp TARGET_HANDLE,0 ; Check for valid TARGET_HANDLE je CLOSE_RETURN ; None, then return mov bx,TARGET_HANDLE ; Request close file mov ah,3eh ; for target handle int 21h ; Call PC-DOS mov TARGET_HANDLE,0 ; Refresh handle CLOSE_RETURN: ret CLOSE_ALL endp FILE_BUFFER label word BAC ends end BEGIN