Corrections to the code.
mov ah, 3fh
mov al, 00 ;only read
mov dx, offset fname_input ; name of the file to open
int 21h
mov ah,3fh
mov bx,[handle]
mov cx,4
mov dx,offset buff
int 21h
- It's maybe a typo, but the DOS.OpenFile function is 3Dh (so not 3fh)
- The filename is not at the address of
offset fname_input. That's where you defined the input structure for the DOS.BufferedInput function 0Ah.
The actual filename starts 2 bytes higher up in memory, and for now is terminated by the code 13. You must change this code to 0 before you can present this to the DOS.OpenFile function.
- You must never omit checking for any errors reported by DOS!
- Your DOS.ReadFile function 3Fh uses the handle variable even before you initialized it!
Way to solve the task
The simplest(1) solution will read the file one byte at a time, until the read function reports it could not fulfil the request. That will happen at file's end.
For every byte you receive, you can increment a counter for establishing the file length, and if you find that the byte needs changing, then you can set the file pointer one position back and write the new character code to the file. Because you not only need read access to the file, you'll have to ask DOS for read/write access when you open the file.
mov si, offset TheBuffer
mov word ptr [si], 0050h ; Set both lengths for DOS.BufferedInput
mov dx, si
mov ah, 0Ah ; DOS.BufferedInput
int 21h
xor bx, bx
mov bl, [si + 1] ; Length of the filename
mov [si + 2 + bx], bh ; Changing carriage return 13 into zero-terminator 0
lea dx, [si + 2] ; ASCIIZ Filename
mov ax, 3D02h ; DOS.OpenFile for read/write
int 21h ; -> AX CF
jc ERROR
mov [handle], ax
MainLoop:
mov dx, offset TheBuffer
mov cx, 1
mov bx, [handle]
mov ah, 3Fh ; DOS.ReadFile
int 21h ; -> AX CF
jc ERROR
cmp ax, cx
jb EOF
...
jmp MainLoop
EOF:
mov bx, [handle]
mov ah, 3Eh ; DOS.CloseFile
int 21h ; -> AX CF
mov ax, 4C00h ; DOS.Terminate
int 21h
TheBuffer db 512 dup (0)
At the ellipsis in the above code snippet, you can do anything you need to do with that one byte that you received.
In order to set the filepointer one position back so you can update the file with the new character that you prepared in TheBuffer, you need to use the DOS.MoveFilepointer function 42h. Use it with a 32-bit offset of -1 in CX:DX.
mov dx, -1
mov cx, -1
mov bx, [handle]
mov ax, 4201h ; DOS.MoveFilepointer from current position
int 21h ; -> DX:AX CF
jc ERROR
mov dx, offset TheBuffer
mov cx, 1
mov bx, [handle]
mov ah, 40h ; DOS.WriteFile
int 21h ; -> AX CF
jc ERROR
(1) A solution that reads more than 1 byte at a time will be more efficient, albeit somewhat more involved. In such case defining a buffer of 512 bytes is best. It nicely matches the disk sector size and the buffers that DOS maintains.