How to open a txt file [EMU8086/Assembly]

8.8k Views Asked by At

I've written a simple program, in which one I press

  1. the program makes a text file
  2. it shows a sentence about the program
  3. the program gets finished.

These three buttons work perfectly fine, now I what I want is this: when I press "4" the program reads that text file (that I made before by pressing "1"). Now I've also written the code that opens the text file and it works normal as an stand alone. Here it is:

org 100h ; .com memory layout
mov dx, offset file ; address of file to dx
mov al,0 ; open file (read-only)
mov ah,3dh
int 21h ; call the interupt
jc terminate ; if error occurs, terminate program
mov bx,ax ; put handler to file in bx
mov cx,1 ; read one character at a time
print:
lea dx, BUF
mov ah,3fh ; read from the opened file (its handler in bx)
int 21h
CMP AX, 0 ; how many bytes transfered?
JZ terminate 
mov al, BUF 
mov ah,0eh ; print character (teletype).
int 10h
jmp print ; repeat if not end of file.
terminate:
mov ah, 0 ; wait for any key...
int 16h
ret
file db "c:\finaltest.txt", 0
BUF db ?
END

But when I import these codes into my main program, it can't open the file. Here's the full program, I want the program to read that text file when I press "4", but instead the program just gets reloaded:

.model small
.stack 100h

.data
msg1    db      10, 13, 10, 13, "Please select an item:",0Dh,0Ah,0Dh,0Ah,09h
        db      "1- Create File",0Dh,0Ah,09h
        db      "2- About",0Dh,0Ah,09h      
        db      "3- Exit",0Dh,0Ah,09h     
        db      "4- Open File",0dh,0ah,09h
        db      "Enter item number: " 
        db      '$'   

About   db      10, 13, 10, 13, "Blank Text About the Program$"

handle  dw  ?
file1   db  "c:\finaltest.txt", 0
text    db  "Contains Message",0
text_size equ $ - text

.code
main proc 
    mov   ax,@data
    mov   ds,ax

ShowMenu:       
    lea     dx, msg1  
    mov     ah, 09h 
    int     21h     

getnum:        
    mov     ah, 1 
    int     21h        

    cmp     al, '1' 
    jl      ShowMenu   
    cmp     al, '3'
    jg      ShowMenu 

    cmp     al, "1"
    je      CreateFile
    cmp     al, "2"
    je      ShowAbout
    cmp     al, "3"
    jmp     Quit          
    cmp     al, "4"
    jmp     OpenFile


Quit: 
   mov   ah,4ch
   int   21h   

Showabout:       
    lea     dx, About  
    mov     ah, 09h 
    int     21h    
    jmp     ShowMenu

CreateFile:
jmp new
text_size = $ - offset text
new:
mov ah, 3ch
mov dx, offset file1
int 21h
mov handle, ax
mov ah, 40h
mov bx, handle
mov dx, offset text
mov cx, text_size
int 21h
int 21h           
ret

OpenFile:    
jmp print
mov dx, offset file
mov al,0 
mov ah,3dh
int 21h
jc terminate 
mov bx,ax 
mov cx,1 
print:
lea dx, BUF
mov ah,3fh
int 21h
CMP AX, 0
JZ terminate 
mov al, BUF 
mov ah,0eh 
int 10h
jmp print 
terminate:
mov ah, 0 
int 16h
ret
file db "c:\finaltest.txt", 0
BUF db ?
END            

    jmp     ShowMenu                
main endp
end main
2

There are 2 best solutions below

0
On

Looking at your code, I see multiple issues:

  1. OpenFile does not open the file; there's a weird jmp print that skips the first part of the function.
  2. Neither CreateFile nor OpenFile closes the file after writing/reading. I'm not sure about an emulated environment, but in production, you'd be creating an empty file.
  3. Duplicate int 21h at the end of CreateFile; a copy/paste error?
  4. Use of ret without any call, as already pointed out by Michael.
  5. file and BUF are in .code segment, should be in .data (though this may not be a problem in the emulator you are using).

Solutions:

  1. Remove the jmp print that's at the start of OpenFile.
  2. Close the file (for code, see below), both after writing and after reading the file.
  3. Remove the duplicate int 21h.
  4. The easiest way out is to replace each ret by jmp ShowMenu.
  5. Specify .data above the definition of file and BUF.

After that, you may need to do more debugging to get everything to work.

Code sample to close a file:

mov  ah, 3Eh
mov  bx, handle
int  21h
0
On

My answer to this old question is written solely for the benefit of the 1k or so users that view this Q/A every year.

About the external code

Now I've also written the code that opens the text file and it works normal as an stand alone.

The new code was developed as a DOS .COM file (see the org 100h). You cannot just copy it into your .EXE program without proper modifications!

  • In your .COM program the DS segment register was already equal to the CS segment register. Therefore having both the filename and the storage buffer in the code segment did not pose a problem. This is no longer true in your final .EXE program. Place these data items in the .data section.
  • Your .COM program could easily terminate with a mere ret instruction (provided the stack was kept balanced), but once you incorporated the code in your final .EXE, this ret made no sense anymore!
  • Assembling the .COM program could end at the END directive, but it has no purpose anymore in the context of your final .EXE program.

The new code has a few issues of its own:

  • DOS uses the 8.3 filename format. Your "c:\finaltest.txt", 0 does not obey the format as there are 9 characters in the name portion.
  • The DOS.ReadFileOrDevice function 3Fh returns the carry flag as an indication of its success. You must inspect this flag. You can not just consider AX <> 0 to represent success. In case of an error, AX will be non-zero...
  • Although DOS does automatically close files that were open at the time of program termination, it is a much better coding practice to close the files explicitly.

About ShowMenu

I want the program to read that text file when I press "4", but instead the program just gets reloaded:

 cmp     al, '1' 
 jl      ShowMenu   
 cmp     al, '3'
 jg      ShowMenu 

Here, you are limiting the allowed selection to just 1, 2, and 3. Any other key will show the menu again.

 cmp     al, "1"
 je      CreateFile
 cmp     al, "2"
 je      ShowAbout
 cmp     al, "3"
 jmp     Quit          
 cmp     al, "4"
 jmp     OpenFile
Quit: 

Because of the unconditional jump jmp Quit, you are not responding to the result of comparing AL to the ASCII "3", moreover the check for ASCII "4" is now unreachable.

About CreateFile

CreateFile:
 jmp new
 text_size = $ - offset text
new:

A construct that calculates the length of a text message belongs directly below the corresponding message. It looks insane to want to jump over it! It would be much cleaner if you just removed it.

 mov ah, 3ch
 mov dx, offset file1
 int 21h
 mov handle, ax

The DOS.CreateFile function 3Ch expects to receive the desired fileattribute in the CX register. For a normal file use xor cx, cx.
And DOS will inform you about any problems that could occur, through the carry flag and the AX register. Don't neglect this possibility. At the very least have something like jc Abort before saving the handle and continuing the program.

 mov ah, 40h
 mov bx, handle
 mov dx, offset text
 mov cx, text_size
 int 21h

Again a case of neglecting the possibility of an error occuring.

 int 21h           

It is very probable that repeating this int 21h is going to terminate the program immediately. At the conclusion of the DOS.WriteFile function 40h, the AH register would have been set to 0, and that happens to be the function number for one of the program termination functions in DOS. What would make sense here is specifying mov ah, 3Eh so that the file gets closed with DOS.

 ret

Because you reached the CreateFile procedure through a conditional jump je CreateFile, you can not use ret to continue the program. Either use jmp ShowMenu (much preferred), or learn something new and write mov ax, offset ShowMenu push ax ret.

About OpenFile

OpenFile:    
 jmp print
 mov dx, offset file
 mov al,0 
 mov ah,3dh
 int 21h
 jc terminate 
 mov bx,ax 
 mov cx,1 
print:

Even if the program execution should arrive at OpenFile (see 'About ShowMenu'), there's no hope to effectively open a file given that you are skipping the necessary instructions!

 lea dx, BUF
 ...

You can load the address with the mov dx, offset BUF instruction. A few extra keys to press but the reward is a 3-byte instruction instead of the 4 bytes that lea produces.

The other problems in OpenFile were already discussed in the top paragraph of this answer.