;**********************************************************************
; NOCRLF.ASM
;
; By Mark Thomas, released to the public domain.
;
; This little utility will fix binary files which have been
; corrupted by being accidentally transfered in ASCII mode.
;
; Revision History:
; v0.01 05-09-1993 Written by Mark Thomas and Tali Streit.
;
; v1.00 16-11-1995 Added multiple files support on the command line.
; (Thanks to David Kirschbaum's args.asm).
; Added wildcard support on the command line.
; Added full error checking and reporting.
; Much tidying.
;
;
;**********************************************************************
BFR_SIZE EQU 8192 ; Size of input and output buffers.
_TEXT SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:_TEXT, DS:_TEXT, ES:_TEXT, SS:_TEXT
ORG 0100h
Extrn SetArgv:NEAR
Extrn New:NEAR
Extrn argc:WORD, argv:WORD
Main PROC NEAR
call SetArgv ; Get command line args.
mov ax,offset msgTitle
call PrintString
cmp argc,0 ; No arguments, display usage.
jne HasArgs
mov ax,offset msgUsage
call PrintString
jmp Exit
HasArgs:
mov cx,BFR_SIZE ; Allocate input and output
call New ; buffers.
mov InBuffer,bx
call New
mov OutBuffer,bx
mov cx,256 ; Allocate a buffer for the
call New ; output file name.
mov OutName,bx
; Main Loop.
; Processes each file in the command line argument array.
mov ax,argv
inc ax
inc ax ; Skip argv[0].
mov arg,ax
ProcessFiles:
mov ax,offset msgCRLF
call PrintString
mov bx,arg ; Get next command line
mov ax,[bx] ; argument, all done when
inc bx ; NULL.
inc bx
or ax,ax
jz Exit
mov arg,bx
mov InName,ax
call PrintString ; Print the input filename.
mov dx,InName
call BfrReadInit ; Open the input file.
jnc @OpenOk
mov ax,offset msgFailInput
call PrintSkipMessage
jmp ProcessFiles
@OpenOk:
; Create a temporary file in the same directory as the input
; file.
mov si,InName
mov di,OutName
call GetOutName
mov dx,OutName ; Open the output file.
call BfrWriteInit
jnc @CreateOk
mov ax,offset msgFailOutput
call PrintSkipMessage
jmp @CreateFail
@CreateOk:
; File Conversion Loop.
mov ChangeFlag,0
ReadLoop:
cmp BytesRead,0 ; Continue until read buffer
je FileDone ; is empty.
call BfrRead
jc @IOFail
cmp BytesRead,0 ; If the read emptied the
je NotCRLF ; buffer then done.
cmp ax,0A0Dh ; Check for CR/LF. (BfrRead
jne NotCRLF ; returns next char. in AH).
mov ChangeFlag,1
call BfrRead ; Read the LF character, it
jc @IOFail ; will be written out.
NotCRLF:
call BfrWrite
jnc ReadLoop
@IOFail:
mov ax,offset msgIOFail
call PrintSkipMessage
mov bx,OutHandle
mov ah,03Eh
int 21h ; DOS: Close File.
;; jc @UnlinkError ; Don't care.
mov dx,OutName
mov ah,41h ; DOS: Unlink file.
int 21h
;; jc @UnlinkError ; Don't care.
@CreateFail:
mov bx,InHandle
mov ah,03Eh
int 21h ; DOS: Close File.
;; jc @UnlinkError ; Don't care.
jmp ProcessFiles
FileDone:
call BfrWriteDone ; Flush out the remainder of
jc @IOFail ; output buffer.
call BfrReadDone
cmp ChangeFlag,0 ; Were any changes made?
jne UpdateSource
mov dx,OutName ; No, delete the output file.
mov ah,41h ; DOS: Unlink file.
int 21h
;; jc @UnlinkError ; Don't care.
mov ax,offset msgNoChange
call PrintString
jmp ProcessFiles
UpdateSource:
; Conversion has been successful. Now delete the input file
; and replace it by renaming the temporary file. If the
; rename fails the we abort the program to allow the user
; to recover something.
mov dx,InName
mov ah,41h
int 21h ; DOS: Unlink file.
jc @RenameFail
mov dx,OutName
mov di,InName
mov ah,56h
int 21h ; DOS: Rename file.
jc @RenameFail
mov ax,offset msgOK ; File has been successfully
call PrintString ; processed.
jmp ProcessFiles
@RenameFail:
mov ax,offset msgRenameFail
call PrintString
mov al,-1
Exit:
mov ah,04ch
int 21h ; DOS: Terminate program.
Main ENDP
BfrReadInit PROC NEAR
; DX=Filename, returns CF=1 on error
mov ax,03D02h ; Open for RW.
int 21h ; DOS: Open File.
jc briDone
mov InHandle,ax
mov bx,ax
mov ax,05700h
int 21h ; DOS: Get file date/time
jc briError
mov InFileDate,dx
mov InFileTime,cx
mov ax,InBuffer
mov InIndex,ax
mov BytesRead,1
call BfrRead
jnc briDone
briError:
mov bx,InHandle
mov ah,03Eh ; DOS: Close File.
int 21h
stc
briDone:
ret
BfrReadInit ENDP
BfrRead PROC NEAR
; Returns AL=character, AH next character. CF=1 on error
; AH is undefined if BytesRead==0.
mov si,InIndex
lodsb
dec BytesRead ; *CF clear*
jnz NoRead
push ax
mov cx,BFR_SIZE
mov dx,InBuffer
mov si,dx
mov bx,InHandle
mov ah,03Fh
int 21h ; DOS: Read from File.
jc brDone
mov BytesRead,ax ; *CF clear*
pop ax
NoRead:
mov ah,[si]
brDone:
mov InIndex,si
ret
BfrRead ENDP
BfrReadDone PROC NEAR
mov bx,InHandle
mov ah,03Eh ; DOS: Close File.
int 21h
ret
BfrReadDone ENDP
BfrWriteInit PROC NEAR
; DX=Filename, returns CF=1 on error
mov cx,0
mov ah,03Ch
int 21h ; DOS: Create File.
jc bwiDone
mov OutHandle,ax ; *CF clear*
mov ax,OutBuffer ; Reset the buffer pointer.
mov OutIndex,ax
bwiDone:
ret
BfrWriteInit ENDP
BfrWrite PROC NEAR
; AL=character, returns CF=1 on error
mov di,OutIndex
stosb
mov ax,OutBuffer
add ax,BFR_SIZE
cmp di,ax
jb NoWrite
push bx
push cx
mov bx,OutHandle
mov dx,OutBuffer
mov cx,BFR_SIZE
mov ah,040h
int 21h ; DOS: Write to File
jc bwDone
pop cx
pop bx
mov di,OutBuffer
NoWrite:
mov OutIndex,di
clc
bwDone:
ret
BfrWrite ENDP
BfrWriteDone PROC NEAR
mov bx,OutHandle
mov dx,OutBuffer
mov cx,OutIndex
sub cx,OutBuffer
mov ah,040h
int 21h ; DOS: Write to File.
jc bwdDone
mov dx,InFileDate
mov cx,InFileTime
mov bx,OutHandle
mov ax,05701h
int 21h ; DOS: Set file date/time
bwdDone: ; *CF1*
rcr al,1
push ax
mov bx,OutHandle
mov ah,03Eh
int 21h ; DOS: Close File.
; *CF2*
rcr al,1
pop bx
or al,bl
rcl al,1 ; Net result CF=(CF1 | CF2).
ret
BfrWriteDone ENDP
PrintString PROC NEAR
; AX = ASCIIZ string.
mov si,ax
PrintLoop:
lodsb
or al,al
jz PrintDone
mov dl,al
mov ah,02h
int 21h ; DOS: Print character
jmp PrintLoop
PrintDone:
ret
PrintString ENDP
PrintSkipMessage PROC NEAR
; AX = ASCIIZ string.
push ax
mov ax,offset msgSkipping
call PrintString
pop ax
call PrintString
ret
PrintSkipMessage ENDP
GetOutName PROC NEAR
; SI=InName, DI=OutName
mov bx,di
CopyName:
lodsb ; Copy input name, keeping
stosb ; track of the last backslash
or al,al ; which is where the temp
jz EndName ; file name will be appended.
cmp al,'\'
jne CopyName
mov bx,di
jmp CopyName
EndName:
mov di,bx
mov cx,13
mov si,offset TempFile
rep movsb
ret
GetOutName ENDP
msgFailInput db 'unable to open input file.', 0
msgFailOutput db 'unable to create output file.', 0
msgIOFail db 'I/O error during conversion.', 0
msgNoChange db 09h, 'No change required.', 0
msgRenameFail db 09h, 'Aborting, unable to rename temporary file.', 0
msgSkipping db 09h, 'Skipping, ',0
msgTitle db '[NOCRLF v1.00. By Mark Thomas, NPS Software. 1995]' ; **,CR,LF,0
msgCRLF db 0Dh, 0Ah, 0 ; **
msgOK db 09h, 'OK', 0
msgUsage db 0Dh, 0Ah
db 'Fixes binary files which have been corrupted by being transfered', 0Dh, 0Ah
db 'in ASCII mode.', 0Dh, 0Ah
db 0Dh, 0Ah
db 'Usage: NOCRLF files', 0Dh, 0Ah
db 0Dh, 0Ah
db 0
TempFile db '~NOCRLF~.TMP', 0
EVEN
InFileDate dw ?
InFileTime dw ?
InHandle dw ?
OutHandle dw ?
InBuffer dw ?
InIndex dw ?
BytesRead dw ?
OutBuffer dw ?
OutIndex dw ?
arg dw ?
InName dw ?
OutName dw ?
ChangeFlag db ?
_TEXT ENDS
END Main