Reputation: 55
I have a task to calculate how many characters are in a .txt
file whose name the user enters and edit characters if needed. I am new at Assembly x86 so I need some help with file reading and symbols reading in a file.
As my code below shows I use int 21,3d
to open the file and int 21,3f
to read the file. But I don't understand how to read symbols from file correctly, because if I have 100 random symbols in my txt file, how to read one by one and count them all?
My code:
.data
fname_input db 255,?,255 dup("$")
buff db 255,?,255 dup("$")
endl db 13,10,"$"
handle dw ?
.code
start:
mov dx, @data
mov ds, dx
mov ah, 0Ah
mov dx, offset fname_input ;input put in to buffer
int 21h
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
mov ax, 4c00h ;exit
int 21h
end start
Upvotes: 1
Views: 330
Reputation: 39341
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
offset fname_input
. That's where you defined the input structure for the DOS.BufferedInput function 0Ah.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.
Upvotes: 1