I am writing a project in assembly language and I have a problem with read from a file and print on the screen what is written in it.
I took part of the code (which is the read and print part) and I tried to fix it and re write it and i still have a problem.
If someone can help me I'll be more then happy
this is the code :
org 100h
mov ah,0ah
mov dx,offset place
int 21h ; getting the place(directory) of the file
mov si,offset place
inc si
mov dx,[si]
inc dx
mov si,dx
mov [si],0
mov ah,02
mov dl,13
int 21h
mov ah,02
mov dl,10
int 21h
mov ah,0ah
mov dx,offset filename
int 21h ;getting the file name
mov si,offset filename
inc si
mov dx,[si]
inc dx
mov si,dx
mov [si],0
mov ah,02
mov dl,13
int 21h
mov ah,02
mov dl,10
int 21h
call gotoplace ;go to the place of the file
;------------------
call openfile ;open the file
;------------------
mov ah,3fh
mov si,offset filehandle
mov bx,[si] ;move file adress to bx
mov cx,40000 ;numbers of bytes to read
mov dx,offset buff ;pointer to read buffer
int 21h
mov si,offset filesize ;move si pointer to filesize
mov [si],ax ;move to filesize how many bytes read
;------------------
;writing on the screen ->
mov bx,offset buff ;move bx pointer of buffer
mov si,offset filesize
mov cx,[si] ;move cx how many to write
startwrite:
mov ah,2
mov dl,[bx] ;move dl letter in place [bx]
int 21h
inc bx
dec cx
jnz startwrite
proc gotoplace
mov ah,3bh
mov dx,offset place ;move offset place to dx
add dx,2
int 21h
ret
endp gotoplace
proc openfile
mov ah,3d
mov al,2 ;open for read / write
mov dx,offset filename ;move dx offset filename
add dx,2
int 21h
;--------------------------
mov si,offset filehandle ;move offset filehandle(location in the memory) to si
mov [si],ax ;move the file adress to the 'filehandle'(location in the meory'
ret
endp openfile
ret
filehandle dd ?
filename db 40
db 42 dup (0)
place db 40
db 42 dup (0)
buff db 40000 dup (0)
filesize dd ?
And this is the function that read and write :
proc readprint
call gotoplace ;go to the place of the file
;------------------
call openfile ;open the file
;------------------
mov ah,3fh
mov si,offset filehandle
mov bx,[si] ;move file adress to bx
mov cx,40000 ;numbers of bytes to read
mov dx,offset buff ;pointer to read buffer
int 21h
mov si,offset filesize ;move si pointer to filesize
mov [si],ax ;move to filesize how many bytes read
;------------------
mov ah,2
mov bh,0
mov dh,1
mov dl,1
int 10h ;Move the cursor to the start of the page
;writing on the screen ->
mov bx,offset buff ;move bx pointer of buffer
mov si,offset filesize
mov cx,[si] ;move cx how many to write
startwrite:
mov ah,2
mov dl,[bx] ;move dl letter in place [bx]
int 21h
inc bx
dec cx
jnz startwrite
;------------------
ret
endp readprint
These are the problems in your code :
In proc openfile you use the number 3d that should be 3dH.
After capturing "place" and "filename" you insert chr(0) at the end of both strings, but you are doing mov dx,[si], which is an error because the length of the string (pointed by [si]) is one byte, and you are moving two bytes to dx.
The file size type is DD but it should be DW, remember you will use this number in cx to write to screen, that's why it must be DW.
You forgot to finish the program properly.
There is another problem that it's not your fault. EMU8086 has an issue when opening files. EMU8086 runs programs in subdirectory c:\emu8086\mybuild, sometimes EMU8086 doesn't allow to open files outside the subdirectory mybuild. In order to work with files in EMU8086, store them in c:\emu8086\mybuild.
Next is your code. I fixed the problems and commented the code that changes the subdirectory, changes are pointed by arrows <========= :
org 100h
;mov ah,0ah
;mov dx,offset place
;int 21h ; getting the place(directory) of the file
;ADD 0 TO END OF STRING <==================================
;mov si,offset place
;inc si
;mov dl,[si] ;<== LENGTH OF STRING IS BYTE, NOT WORD
;mov dh,0 ;<================== CLEAR DH TO USE DX
;inc dx
;add si,dx ;<========= SI POINTS TO FINAL CHAR + 1
;mov [byte ptr si],0 ;<========= THE NUMBER ZERO HAS NO SIZE
;LINE BREAK.
;;mov ah,02
;mov dl,13
;int 21h
;mov ah,02
;mov dl,10
;int 21h
mov ah,0ah
mov dx,offset filename
int 21h ;getting the file name
;ADD 0 TO END OF STRING <==================================
mov si,offset filename
inc si
mov dl,[si] ;<== LENGTH OF STRING IS BYTE, NOT WORD
mov dh,0 ;<================== CLEAR DH TO USE DX
inc dx
add si,dx ;<========= SI POINTS TO FINAL CHAR + 1
mov [byte ptr si],0 ;<========= THE NUMBER ZERO HAS NO SIZE
;LINE BREAK.
mov ah,02
mov dl,13
int 21h
mov ah,02
mov dl,10
int 21h
;call gotoplace ;go to the place of the file
;------------------
call openfile ;open the file
;------------------
mov ah,3fh
mov si,offset filehandle
mov bx,[si] ;move file adress to bx
mov cx,40000 ;numbers of bytes to read
mov dx,offset buff ;pointer to read buffer
int 21h
mov si,offset filesize ;move si pointer to filesize
mov [si],ax ;move to filesize how many bytes read
;------------------
;writing on the screen ->
mov bx,offset buff ;move bx pointer of buffer
mov si,offset filesize
mov cx,[si] ;move cx how many to write
startwrite:
mov ah,2
mov dl,[bx] ;move dl letter in place [bx]
int 21h
inc bx
dec cx
jnz startwrite
;WAIT UNTIL USER PRESS ANY KEY <===========================
mov ah,7
int 21h
;FINISH PROGRAM <==========================================
mov ax, 4c00h
int 21h
proc gotoplace
mov ah,3bh
mov dx,offset place ;move offset place to dx
add dx,2
int 21h
ret
endp gotoplace
proc openfile
mov ah,3dH
mov al,2 ;open for read / write
mov dx,offset filename ;move dx offset filename
add dx,2
int 21h
;--------------------------
mov si,offset filehandle ;move offset filehandle(location in the memory) to si
mov [si],ax ;move the file adress to the 'filehandle'(location in the meory'
ret
endp openfile
ret
filehandle dd ?
filename db 40
db 42 dup (0)
place db 40
db 42 dup (0)
buff db 40000 dup (0)
filesize dw ? ;<========= IN 8086 WE CANNOT READ MORE THAN 64KB.
Related
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
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.
this is my first post so I'm sorry in advance if I did it wrongly (in any ways).
So what I am facing now is, I have a a file (name.txt) and I want to pass the first line to buffer1 , second line to buffer2 and so on.
Extra Info :
The maximum line of the file is going to be 10.
The maximum length of the string is 27(data)+1(dollar sign)+2(CR LF) or so I think.
I created 5 buffer for this example
The example of the string is "1washingmachine"
name.txt is already created
.
.model small
.stack 64
.data
filename db "name.txt",0
handler dw ?
strPrompt db 10,13,"enter:$"
strInput label byte
max db 28 ;max name is 20 , + 1 for index , 6 for time , 1 for $
act db ?
data db 28 dup ('$')
buffer1 db 30 dup ('$')
buffer2 db 30 dup ('$')
buffer3 db 30 dup ('$')
buffer4 db 30 dup ('$')
buffer5 db 30 dup ('$')
newLine db 10,13
.code
main proc far
;INITIALIZE DATA SEGMENT.
mov ax,#data
mov ds,ax
;CREATE FILE.
mov ah, 3dh
mov al, 2
lea dx, filename
int 21h
;PRESERVE FILE HANDLER RETURNED.
mov handler, ax
;READ STRING
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer1
INT 21H ; AX = bytes read
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer2
INT 21H
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer3
INT 21H
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer4
INT 21H
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer5
INT 21H
mov ah,09h
lea dx,buffer1
int 21h
mov ah,09h
lea dx,buffer2
int 21h
mov ah,09h
lea dx,buffer3
int 21h
mov ah,09h
lea dx,buffer4
int 21h
mov ah,09h
lea dx,buffer5
int 21h
;input string to write in file
mov ah,09h
lea dx,strPrompt
int 21h
mov ah,0ah
lea dx,strInput
int 21h
;WRITE STRING.
mov ah, 40h
mov bx, handler
mov ch,0
mov cl, act ;STRING LENGTH.
inc cx
mov dx, offset data
int 21h
lea dx,newLine
mov bx,handler
mov cx,2
mov ah,40h
int 21h
;CLOSE FILE (OR DATA WILL BE LOST).
mov ah, 3eh
mov bx, handler
int 21h
;FINISH THE PROGRAM.
mov ax,4c00h
int 21h
main endp
end main
Hopefully someone from StackOverflow can help me with this, either guidance or solution will do !
This should be counting every character in file but its working only for smaller files and i need it to work for files containing more than 32768 characters
fn DB strsize DUP ('$');
bsize equ 32768
buff db bsize dup ('$')
read proc
mov ah,3dh ;open
mov al,0 ; read only mode
mov dx,offset fn ; offset of file name
int 21h ; file handle
jc jmpchyba
ret
endp
BITY proc
mov full,00
mov actual,00
jmpback:
call read
mov actual,00
mov bx,ax;offset buff
mov ah,3fh
mov cx,bsize ; count bytes
mov dx,offset buff
int 21h ;
mov actual,ax
mov bx,actual
add full,bx
cmp actual,bsize
je jmpback
vypis kolko
mov ax,full
call convasci;this is working convert from binary to asci
ret
endp
Firstly define full as a dword. Then use this code
mov actual,ax
mov bx,actual
add full,bx
adc full+2,0
Obviously the conversion routine convasci should also be changed to deal with a dword.
The proc read actually opens the file! You should certainly not keep calling it from the BITY proc.
Rename read as open and place call open before the label jmpback:
Open proc
mov ah,3dh ;open
mov al,0 ; read only mode
mov dx,offset fn ; offset of file name
int 21h ; file handle
jc jmpchyba
ret
endp
BITY proc
mov full,0
mov full+2,0
call Open
mov bx,ax ;Handle!!!
jmpback:
mov actual,00
mov ah,3fh
mov cx,bsize ; count bytes
mov dx,offset buff
int 21h ;
mov actual,ax
add full,ax
adc full+2,0
cmp ax,bsize
je jmpback
I am stuck at point where I need to read 3 numbers from created buffer of text file. I've tryed reading every byte, but no luck if the number is bigger than 9.
Steps that I do:
Open text file
Read file's content into created buffer
Put every buffers byte into different register (ax, bx, cx, dx).
The problem is, it reads 1 byte (mov ax, buffer[0]) at a time: if my text file is (10 10 1), it reads 1 then 0 then space symbol(ascii 20) and so on. Should I do cycle that converts and adds every byte to one register while it doesn't detect space symbol? Or is there a possibility to read whole number at one time? Here's the code:
.model small
bufferLen equ 16
.stack 100h
.data
duom db "duom.txt", 0
fident dw 0
buffer db bufferLen dup (?)
.code
start:
mov dx, #data
mov ds, dx
mov bx, 81h
tikrinam: ; not important
mov ax, es:[bx]
inc bx
cmp al, 13
je openf
cmp al, 20h
je tikrinam
cmp ax, "?/"
jne openf
mov ax, es:[bx]
cmp ah, 13
je abouthlp
jmp openf
abouthlp:
mov dx, offset about
mov ah, 09h
int 21h
jmp ending
openf:
mov ah, 3Dh
mov al, 0
mov dx, offset duom
int 21h
mov [fident], ax
readf:
mov ah, 3Fh
mov bx, [fident]
mov cx, bufferLen
mov dx, offset buffer
int 21h
mov al, buffer[0]
mov bl, buffer[1]
mov cl, buffer[2]
I've found the solution if anyone is having same problem:
changeNumbers:
push ax
mov ax, 0
cmp cl, 0
je change
temp1:
mov ch, 0
mov cl, buffer[si]
inc si
cmp cl, 32
je changeNumbers
cmp cl, 0
je changeNumbers
sub cl, 48
mul abc
add ax, cx
jmp temp1
Basically what I did was read every byte and if the number is >9 then add cx to ax and multiply it by 10. Then just push it to stack for further usage. Brain is an amazing thing, I'd say.
I am trying to read a string from a file and print it on the screen, but I always get an error at opening the file. Why is this happening? What is wrong with the code or with the file? PS: the file is in the same folder as the .asm file.
ASSUME cs: code, ds:data
data SEGMENT
inputFile db "D:\AC\input.txt", 0
openingError db 'An error has occured at opening the file!$'
readingError db 'An error has occured at reading the file!$'
s1 db 10 dup(?)
ls db 0
handle dw ?
data ENDS
code SEGMENT
start:
mov ax,data
mov ds,ax
;open the file
mov ah, 3dh
mov al, 0
mov dx, offset inputFile
int 21h
mov handle, ax
jc openError
;read 10 bytes from the file into s1
mov ah, 3fh
mov bx, handle
mov cx, 10
mov dx, offset s1
int 21h
jc readError
openError:
mov ah, 09h
mov dx, offset openingError
int 21h
jmp the_end
readError:
mov ah, 09h
mov dx, offset readingError
int 21h
jmp the_end
;close file
mov ah, 3eh
mov bx, handle
int 21h
;print string on the screen
lea dx, s1
mov ah, 09h
int 21h
the_end:
mov ax,4C00h
int 21h
code ENDS
END start
Did youi forget to actually open the file? Where is the int 21?
mov ah, 3dh
mov al, 0
lea dx, inputFile
int 21h
jc openingError
mov handle, ax