0

I want to read the characters one by one and have it stop when reaching the '|' character. I'm using dosbox and 8086.

    MOV AX, @DATA
    MOV DS, AX
    lea si, buffer
    ; Open the file for reading
    MOV AH, 3Dh         ; Open existing file
    mov al,0
    LEA DX, FileName    ; Load address of file name
    XOR CX, CX          ; Access mode (CX = 0, read-only)
    INT 21h
    MOV fhandle, AX          ; Store file handle


Read_Loop:
    ; Read data from the file
    MOV AH, 3Fh         ; Read from file
    MOV CX, 1           ; Read 1 byte at a time
    LEA DX, Buffer[si+2]      ; Load address of data buffer
    mov bx,fhandle
    INT 21h
    
    ;call NEW_LINE
    ;mov dl,[Buffer]
    ;mov ah,02h 
    ;int 21h
    
    mov cl,'3'
    cmp cl,Buffer[si+2]
    je File_End
    inc si
    jmp Read_Loop
    
    
File_End:

    ;mov ah,09h
    ;lea dx, data2
    ;int 21h
    
    ; Close the file
    MOV AH, 3Eh         ; Close file
    MOV BX, fhandle          ; Use the file handle
    INT 21h

    MOV AH, 4Ch         ; Exit program
    INT 21h
Sep Roland
  • 33,889
  • 7
  • 43
  • 76

1 Answers1

1

You are on the right track with using the DOS.ReadFile function 3Fh, but you seem to confuse it with how the DOS.BufferedInput function 0Ah works!

lea si, buffer
LEA DX, Buffer[si+2] ; Load address of data buffer

Because your lea si, buffer instruction already loads the SI register with the address of the data buffer, the LEA DX, Buffer[si+2] ; Load address of data buffer instruction that follows will be doubling the address since you add Buffer a second time. And seeing the +2 I suspect you are confused with that other DOS function. In all, the pointer passed in DS:DX will make no sense!

mov cl,'3'
cmp cl,Buffer[si+2]

If your intent is to stop when you reach the '|' character, then why do you compare with the '3' character?

XOR CX, CX          ; Access mode (CX = 0, read-only)

The DOS.OpenFile function 3Dh does not depend on CX at all! You can specify the read-only status in the 3 lowest bits of the AL register.


I want to read the characters one by one and have it stop when reaching the '|' character.

Next is your minimal example to accomplish this task. You must always consider the possibility that an operation (and especially a file operation) could fail. You need to inspect the carry flag that DOS provides as well as other info like the number of characters actually read.

  mov dx, OFFSET FileName  ; Load address of file name
  mov ax, 3D00h            ; DOS.OpenFile for reading
  int 21h                  ; -> AX CF
  jc  Abort
  mov bx, ax               ; CONST Store file handle
  mov cx, 1                ; CONST Read 1 byte at a time
  mov si, OFFSET Buffer

Read_Loop:
  mov dx, si
  mov ah, 3Fh              ; DOS.ReadFile
  int 21h                  ; -> AX CF
  jc  Close
  cmp ax, cx
  jne Close
  mov al, [si]
  inc si
  cmp al, '|'
  jne Read_Loop

Close:
  mov ah, 3Eh              ; DOS.CloseFile
  int 21h

  ... Do something useful with the string

Abort:
  mov ax, 4C00h            ; DOS.Terminate
  int 21h

You don't want to overflow your data buffer

Even if the DOS operation works fine, it could still happen that the file from which you read does not contain that terminating '|' character, or that the number of bytes up to the '|' character is superior to the length of your data buffer. For these cases you need to decide whether you would consider such, an error or that you can truncate the result. In the below rewrite I show the latter (here assuming a buffer of some 30 bytes):

  mov dx, OFFSET FileName  ; Load address of file name
  mov ax, 3D00h            ; DOS.OpenFile for reading
  int 21h                  ; -> AX CF
  jc  Abort
  mov bx, ax               ; CONST Store file handle
  mov cx, 1                ; CONST Read 1 byte at a time
  mov si, OFFSET Buffer

Read_Loop:
  mov dx, si
  mov ah, 3Fh              ; DOS.ReadFile
  int 21h                  ; -> AX CF
  jc  Close
  cmp ax, cx
  jne Close
  mov al, [si]
  inc si
  cmp al, '|'
  je  Close
  cmp si, OFFSET Buffer + 30 - 1
  jb  Read_Loop
  mov BYTE PTR [si], '|'   ; (*)

Close:
  mov ah, 3Eh              ; DOS.CloseFile
  int 21h

  ... Do something useful with the string

Abort:
  mov ax, 4C00h            ; DOS.Terminate
  int 21h

(*) Exists so that any further processing only has to deal with '|'-terminated strings.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76