Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Newbie help - File I/O

Hi, I'm kind of new to X86.

I was wondering if someone could help me: I need to get my head around using file input and output in X86, using function 3DH and such. I'd really appreciate some code snippets or the like, specifically reading in a text file and printing it's contents on the screen.

Thanks in advance!

Comments

  • perfectlyroundperfectlyround Member Posts: 3
    Thanks for the links! With their help, I have been able to come up with this code:

    [code].model small
    .data
    Filename db 'test.txt'
    FHndl dw ?
    Buffer db 80h dup(?)
    .stack 100h
    .code
    Program:
    mov ah, 3dh ;Open the file
    mov al, 0 ;Open for reading
    lea dx, Filename ;Presume DS points at filename
    int 21h ; segment.
    ; jc BadOpen
    mov FHndl, ax ;Save file handle

    LP: mov ah,3fh ;Read data from the file
    lea dx, Buffer ;Address of data buffer
    mov cx, 1 ;Read one byte
    mov bx, FHndl ;Get file handle value
    int 21h
    ; jc ReadError
    cmp ax, cx ;EOF reached?
    jne EOF
    mov al, Buffer ;Get character read
    call write ;Print it
    jmp LP ;Read next byte

    EOF: mov bx, FHndl
    mov ah, 3eh ;Close file
    int 21h
    ;jc CloseError

    PROC write
    push ax bx cx dx
    mov ah, 2
    mov dl, Buffer ;char to be printed
    int 21h
    pop ax bx cx dx
    ret
    ENDP


    End Program[/code]

    My issue now is actually printing the characters from the txt file to the console/cmd prompt. Am I on the right track here? I'm not sure if my write procedure is entirely accurate. Thanks again.

  • anthrax11anthrax11 Member Posts: 511
    You're on the right track, but you've made some small mistakes, which is
    normal though, because asm is no easy language to learn :)

    I hope you're not stuck to that old Tasm assembler, because it has been
    obsolete for years now. I'd go with [link=http://www.flatassembler.net]Fasm[/link] instead.

    Here's the code with some changes to get it to assemble with Fasm.
    I can't get it to work in WinXP, but WinXP has bad DOS emulation too..
    [code]
    format MZ
    entry codeseg:main ; program entry point
    stack 100h

    segment dataseg
    [color=Green] ; a terminating zero is needed so that the function knows where the string ends[/color]
    Filename db 'test.txt'[color=Red],0[/color]
    FHndl dw ?
    [color=Green]; You're reading just one byte, so the buffer only needs one byte..[/color]
    Buffer db ?

    segment codeseg
    main:
    [color=Red] mov ax, dataseg
    mov ds, ax[/color]

    mov ah, 3dh ;Open the file
    mov al, 0 ;Open for reading
    lea dx, [Filename] [color=Red];Presume DS points at filename[/color]
    int 21h [color=Red]; segment.[/color]
    ; jc BadOpen
    mov [FHndl], ax ;Save file handle

    LP: mov ah,3fh ;Read data from the file
    lea dx, [Buffer] ;Address of data buffer
    mov cx, 1 ;Read one byte
    mov bx, [FHndl] ;Get file handle value
    int 21h
    ; jc ReadError
    cmp ax, cx ;EOF reached?
    jne EOF

    mov al, [Buffer] ;Get character read
    call write ;Print it
    jmp LP ;Read next byte

    EOF: mov bx, [FHndl]
    mov ah, 3eh ;Close file
    int 21h
    ;jc CloseError

    [color=Green]; Don't forget to exit![/color]
    [color=Red]exit:
    mov ax, 4c00h
    int 21h[/color]

    write:
    mov ah, 2
    mov dl, al ;char to be printed
    int 21h
    ret
    [/code]
    I hope this helps!
  • perfectlyroundperfectlyround Member Posts: 3
    Brilliant, anthrax11, you're a godsend! Yes, it's quite a tricky language to understand, but I seem to be getting the hang of it now. You've helped quite a bunch!

    One other quick thing, if it's not too much hassle to explain; I know in Java and the like you're able to format the way something is printed, with printf or whatever. Is there a simple way of doing that in assembly? For example, instead of printing the contents of that file one by one, is it possible to print it's contents (the numbers 1-6, for example), as:

    123
    456

    I'm only able to get things to print one by one, or string by string. That's pretty much the final thing I'd like to get this piece of code to do, I suppose I'll need a procedure to do that!
  • anthrax11anthrax11 Member Posts: 511
    If I understand correctly, you want to read in a specific number of bytes, print them,
    go to the next line and start over. Okay, for this you need to make the buffer longer
    and change cx accordingly before calling the file reading function.
    Next you need a function to which you can pass the number of bytes to be printed.
    There are at least two ways to do this. Either by printing out each character individually
    in a loop or by turning the buffer into a string and printing it out then. I'm bored and have
    no life, so I'll show you both:
    [code]
    ; 1)
    segment dataseg
    Buffer db 16 dup(?)
    NewLine db 13,10,"$"

    ...

    LP: mov ah,3fh ;Read data from the file
    lea dx, [Buffer] ;Address of data buffer
    mov cx, [color=Red]16[/color] ;Fill the buffer
    mov bx, [FHndl] ;Get file handle value
    int 21h
    ; jc ReadError
    cmp ax, 0 ;EOF reached?
    jne EOF

    ; Number of bytes read is in ax
    call write ;Print it
    jmp LP ;Read next byte

    ...

    write:
    mov cx, ax ;Use cx as a counter
    lea bx, [Buffer] ;Address of data buffer
    nextbyte:
    push cx ;Save the registers we use
    push bx
    mov ah, 2
    mov dl, [bx] ;Get byte from buffer
    int 21h
    pop bx
    pop cx
    inc bx
    dec cx
    jnz nextbyte

    ;Print a newline
    mov ah, 9
    lea dx, [NewLine]
    int 21h

    ret[/code]
    [code]; 2)
    ;Need one more byte for the terminating character
    segment dataseg
    Buffer db 16+1 dup(?)

    ...

    write:
    lea bx, [Buffer]
    add bx, ax ;Point to end of data buffer
    mov [bx], byte "$" ;Append terminating dollar sign

    ;Print the string
    mov ah,9
    lea dx, [Buffer]
    int 21h

    ;Print a newline
    mov ah, 9
    lea dx, [NewLine]
    int 21h

    ret
    [/code]

    When it comes to formatted output, then in DOS/asm it's probably best to
    make your own string handling functions. The only string functions DOS provides
    are those for getting characters into video memory, nothing more. In Windows you
    would also have wsprintf, plenty of console functions and other interesting functions
    which are also easy to use in assembly. Of course they are not as simple to use
    as those in Java & others, but they make things a lot easier. If you have the interest, then
    you should definitely look into programming under Windows, that way you can actually
    learn something relevant in today's world. Good luck!
  • Copa7Copa7 Member Posts: 2
    But in MASM the function Call write don't work. Can you give me another option to do that?
  • anthrax11anthrax11 Member Posts: 511
    I think you'll have to post the whole source code that you are trying to assemble, because I can't see why "call write" shouldn't work. Use code tags too, please.

    If possible, avoid the hassle and start using [link=http://www.flatassembler.net]FASM[/link] or [link=http://www.nasm.us/]NASM[/link] instead.
  • Copa7Copa7 Member Posts: 2
    I haved see the problem now... But just print the first byte of file, don't print the others bytes... Can you help me? How I can read and print byte to byte? I need to know how can do that, because I have to print in binary, decimal and hex the bytes too...

    (Sorry about my english, but I'm portuguese xD)
  • anthrax11anthrax11 Member Posts: 511
    You need a function for converting an integer to text with a way to give it the base number (2 for binary, 10 for decimal, 16 for hexadecimal). Here's one:
    [code]
    mov al, [Buffer] ; get byte from the buffer
    xor ah, ah ; set rest of ax to zero
    mov cx, 10 ; set base number for decimal
    call itoa

    ...


    ; print ax as base cx
    itoa:
    xor bx, bx

    div_loop:
    xor dx, dx ; dx = 0

    ; Divide ax:dx by cx,
    ; get quotinent in ax and remainder in dx
    div cx

    ; Convert digit to ASCII
    cmp dl, 10
    jb below10
    add dl, 'a'-10
    jmp continue
    below10:
    add dl, '0'
    continue:

    ; Write ASCII character to buffer
    mov [itoa_buffer+bx], dl
    inc bx

    ; Check if there was anything left to convert
    or ax, ax
    jnz div_loop

    ; Now show the result
    show_loop:
    mov ah, 2
    mov dl, [itoa_buffer+bx-1]
    push bx
    int 21h
    pop bx
    dec bx
    jnz show_loop

    itoa_ret:
    ret


    Buffer db ?
    itoa_buffer db 9 dup(?)
    [/code]
Sign In or Register to comment.