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.