似乎无法将char读取从文件添加到字符串缓冲区

时间:2014-11-19 21:40:06

标签: string assembly x86 dos x86-16

我正在使用8086并且需要一个子程序来从文本文件中读取当前行,将内容放在字符串缓冲区中,除了换行符。我还要跟踪BX上的线路长度(以字节为单位)。基本上我正在做的是:

while read_new_char_from_file() != (\r or \n or EOF) add it to the buffer, inc bx
then increment bx to account for the linefeed, and return

我运行了一些测试用例并且字节数正确,当字节为\n时,循环停止,正如预期的那样。但是,字节似乎没有添加到我的字符串缓冲区中!子程序:

FGETCFHANDLE读取一个字符到CBUFF(更新句柄)并且工作正常,但是可以找到here}。

FGETS PROC NEAR
    PUSH AX             ; (used by fgetc)
    PUSH CX             ; (used by fgetc)
    XOR BX, BX          ; clears our byte counter
    CLD                 ; positive BF (used by STOSB)
    LEA DI, SBUFFL      ; pointer to the string buffer (used by STOSB)
    FGETS_LOOP:         ; read loop
    CALL FGETC          ; read a new char from the file to CBUFF
    CMP AX, CX          ; partial read (EOF)?
    JNE FGETS_RET       ; return
    CMP CBUFF, 13       ; carriage return?
    JE FGETS_RET_I      ; return, increment byte count and handle to account for \r\n
    CMP CBUFF, 10       ; line feed?
    JE FGETS_RET_U      ; return, increment byte count and handle to account for \n
    MOV AL, CBUFF       ; char to be written to buff
    STOSB               ; store string byte (increments DI)
    INC BX              ; increment the byte counter
    JMP FGETS_LOOP      ; loop    
    FGETS_RET_U:        ; account for \n
    INC BX              ; increment byte counter
    JMP FGETS_RET       ; return
    FGETS_RET_I:        ; account for \r and \n
    ADD BX, 2           ; increment byte count by 2
    CALL FGETC          ; increment fhandle (to skip \n)
    FGETS_RET:          ; return...
    MOV AL, '$'         ; add 'end of string' char to the buffer
    STOSB               ; ...
    POP CX              ; pops
    POP AX              ; ...
    RET                 ; actually return
FGETS ENDP

测试案例的结果:

字符串缓冲区(40个大小并使用' x' s结束于' $'以便能够将其打印到标准输出并查看结果):

SBUFFL DB 40 DUP ('x'),'$'  ; 4000 chars (4000 bytes)

文件内容(以\n结尾的行):

4,5
500,-1000,0,250,-300
4,0,1,2,3
3,4,3,2
5,1,2,3,2,1
2,2,3

在文件开头用SBUFFL调用FGETS后,打印FHANDLE(通过DOS int打印一个正常工作的字符串)的结果:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

表示从文件读取的字节未添加到缓冲区。但是,Turbo Debugger显示字节数(BX)和停止条件(\n)对于第一行的读取是正确的:

enter image description here

评论略有不同,只是代码中的差异是不必要的PUSH/POP DX已删除,结果相同

调试器还会按预期在每次调用时显示STOSB递增DI。我尝试使用LEA DI, [SBUFF + 0],没有区别。不使用CLD也没有任何区别。有点失去了。

1 个答案:

答案 0 :(得分:0)

我怀疑DSES根本没有正确初始化。以下测试用例在这里工作正常(我没有改变你的功能):

.MODEL small
.STACK 1000h

.DATA
    SBUFFL DB 40 DUP ('x'),'$'
    FHANDLE DW ?
    CBUFF DB ?
    sample_txt db 'sample.txt',0
    errtxt db 'Error.', 13, 10, '$'

.CODE
main PROC
    mov ax, @data       ; Initialise DS & ES
    mov ds, ax
    mov es, ax

    mov ax, 3d00h       ; fopen
    lea dx, sample_txt
    int 21h
    jc errexit
    mov [FHANDLE], ax

    Loop:               ; print fgets until "no string"
    call FGETS
    cmp byte ptr [SBUFFL], '$'
    je Endloop
    lea dx, SBUFFL
    mov ah, 09h
    int 21h
    call crlf
    jmp Loop
    Endloop:

    mov ah, 3Eh         ; fclose
    mov bx, [FHANDLE]
    int 21h

    mov ax, 4C00h
    int 21h

    errexit:
    lea dx, errtxt
    mov ah, 09h
    int 21h
    mov ax, 4C01h
    int 21h
main ENDP

crlf PROC               ; print line feed
    push ds
    push '$$'
    push 0A0Dh
    mov ax, ss
    mov ds, ax
    mov dx, sp
    mov ah, 09h
    int 21h
    add sp, 4
    pop ds
    ret
crlf ENDP

FGETC PROC NEAR
    PUSH BX             ; pushs
    PUSH DX
    MOV AH, 03Fh        ; Read from file
    MOV BX, FHANDLE     ; Found at fhandle
    MOV CX, 1           ; Read 1 byte
    LEA DX, CBUFF       ; To cbuff
    INT 21H             ; Do it
    POP DX              ; pops
    POP BX
    RET                 ; return
FGETC ENDP

FGETS PROC NEAR
    PUSH AX             ; (used by fgetc)
    PUSH CX             ; (used by fgetc)
    XOR BX, BX          ; clears our byte counter
    CLD                 ; positive BF (used by STOSB)
    LEA DI, SBUFFL      ; pointer to the string buffer (used by STOSB)

    FGETS_LOOP:         ; read loop
    CALL FGETC          ; read a new char from the file to CBUFF
    CMP AX, CX          ; partial read (EOF)?
    JNE FGETS_RET       ; return

    CMP CBUFF, 13       ; carriage return?
    JE FGETS_RET_I      ; return, increment byte count and handle to account for \r\n
    CMP CBUFF, 10       ; line feed?
    JE FGETS_RET_U      ; return, increment byte count and handle to account for \n
    MOV AL, CBUFF       ; char to be written to buff
    STOSB               ; store string byte (increments DI)
    INC BX              ; increment the byte counter
    JMP FGETS_LOOP      ; loop

    FGETS_RET_U:        ; account for \n
    INC BX              ; increment byte counter
    JMP FGETS_RET       ; return

    FGETS_RET_I:        ; account for \r and \n
    ADD BX, 2           ; increment byte count by 2
    CALL FGETC          ; increment fhandle (to skip \n)

    FGETS_RET:          ; return...
    MOV AL, '$'         ; add 'end of string' char to the buffer
    STOSB               ; ...
    POP CX              ; pops
    POP AX              ; ...
    RET                 ; actually return
FGETS ENDP

END main