assembly - 缓冲输入如何工作

标签 assembly input dos x86-16

下一个程序中的输入工作正常,但是当我要求显示输出时,DOS
根本不显示任何内容!这怎么可能?

        ORG     256
        mov     dx, msg1
        mov     ah, 09h                 ;DOS.WriteString
        int     21h
        mov     dx, buf
        mov     ah, 0Ah                 ;DOS.BufferedInput
        int     21h
        mov     dx, msg2
        mov     ah, 09h                 ;DOS.WriteString
        int     21h
        mov     dx, buf
        mov     ah, 09h                 ;DOS.WriteString
        int     21h
        mov     ax, 4C00h               ;DOS.TerminateWithExitcode
        int     21h
; --------------------------------------
msg1:   db      'Input : ', '$'
buf:    db      20 dup ('$')
msg2:   db      13, 10, 'Output : ', '$'
; --------------------------------------

最佳答案

查看您如何定义输入缓冲区(buf: db 20 dup ('$')),我明白了
您想偷工减料,并已将输入终止为$
重新显示它。可悲的是,这弄乱了DOS输入所需的设置
功能0Ah,并且您的程序存在潜在的缓冲区严重问题
超限。
此外,使用$终止并不是您可以做的最明智的选择
因为$字符可能已经出现在输入字符中。
我在下面介绍的所有示例程序都将使用零终止
代替。

使用int 21h AH=0Ah输入文本

Buffered STDIN Input函数从键盘获取字符,并且
继续这样做,直到用户按下Enter键。所有
字符和最后的回车符放置在
从调用程序提供的输入缓冲区的第3个字节开始
通过DS:DX中的指针。
字符计数(不包括最后的回车符)存储在
输入缓冲区的第二个字节。
调用程序有责任告诉DOS
存储空间是。因此,您必须将其长度放在
调用此函数之前输入缓冲区。允许输入1
字符,您将存储大小设置为2。允许输入254
您将存储大小设置为255个字符。
如果您不希望从模板中调出任何先前的输入,
那么最好也将第二个字节清零。基本上,模板是
输入缓冲区中预先存在(且有效)的内容是调用程序的
提供。如果预先存在的内容无效,则模板不是
可用。

令人惊讶的是,此功能的编辑功能有限。


转义从当前输入中删除所有字符。
当前输入被放弃,但停留在屏幕上,光标置于
下一行,输入第一次开始的位置。
Backspace从当前输入中删除最后一个字符。
如果输入停留在屏幕上的单个行中,则按预期方式工作。
另一方面,如果输入跨越几行,则此后退间距将
停在屏幕的左边缘。从那时起,
逻辑输入和视觉输入之间存在差异,因为在逻辑上
退格将继续进行,直到到达存储空间的第一个位置!
F6在当前输入中插入文件结尾字符(1Ah)。
屏幕将显示“ ^ Z”。
F7在当前输入中插入一个零字节。
屏幕将显示“ ^ @”。
ctrlEnter转换到下一行(执行
回车和换行),则不会在当前输入中添加任何内容,
不能回去。


还有更多的编辑键可用。它们都让人联想到EDLIN.EXE,
古老的DOS行编辑器,这是一个文本编辑器,前一行
成为您在其上构建下一行的模板。


F1将一个字符从模板复制到新行。
F2 + ...将所有字符从模板复制到新行,直到指定的字符为止。
F3将模板中所有剩余的字符复制到新行。
F4 + ...跳过模板中的字符,向上
到指定的字符。
F5使新行成为新模板。
转义清除当前输入,并使模板保持不变。
删除跳过模板中的一个字符。
插入进入或退出插入模式。
退格键删除新行的最后一个字符,并将光标移回模板中的一个字符。
左与Backspace相同。
右与F1相同。


通过此功能扩展选项卡。标签扩展是替换的过程
ASCII 9除以一系列一个或多个空格(ASCII 32),直到光标到达
列位置是8的倍数。
此选项卡扩展仅在屏幕上发生。存储空间将保存ASCII 9。

此函数执行ctrlC / ctrlBreak
检查。

完成此功能后,光标将位于菜单栏的最左列。
当前行。

示例1,缓冲的STDIN输入。

        ORG     256                     ;Create .COM program
        cld
        mov     si, msg1
        call    WriteStringDOS
        mov     dx, buf
        mov     ah, 0Ah                 ;DOS.BufferedInput
        int     21h
        mov     si, msg2
        call    WriteStringDOS
        mov     si, buf+2
        movzx   bx, [si-1]              ;Get character count
        mov     word [si+bx+1], 10      ;Keep CR, append LF and 0
        call    WriteStringDOS
        mov     ax, 4C00h               ;DOS.TerminateWithExitcode
        int     21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
        pusha
        jmps    .b
.a:     mov     dl, al
        mov     ah, 02h                 ;DOS.DisplayCharacter
        int     21h                     ; -> AL
.b:     lodsb
        test    al, al
        jnz     .a
        popa
        ret
; --------------------------------------
buf:    db      255, 16, "I'm the template", 13, 255-16-1+2 dup (0)
msg1:   db      'Choose color ? ', 0
msg2:   db      10, 'You chose ', 0
; --------------------------------------


使用int 21h AH=3Fh输入文本

与预定义的句柄0(在BX中)一起使用时,此Read From File Or Device
函数从键盘获取字符并继续这样做,直到
用户按Enter。所有字符(不超过127个)和
最后的回车符和附加的换行符放在一个私人
DOS内核中的缓冲区。现在,它将成为新模板。
此后,函数将写入DS:DX提供的缓冲区中
CX参数中请求的字节数。如果CX指定了一个数字
小于此输入生成的字节数,一个或多个
需要其他对该函数的调用才能检索完整的输入。
只要还有剩余字符需要提取,此功能将
不要使用键盘启动另一个输入会话!两者之间甚至如此
不同的程序或同一程序的会话。

上一节中介绍的所有编辑键均可用。

选项卡仅在屏幕上展开,而不在模板中展开。

此函数执行ctrlC / ctrlBreak
检查。

完成此功能后,光标将位于菜单栏的最左列。


如果终止换行符不在返回的字节中,则返回当前行。
如果终止换行符位于返回的字节中,则返回下一行。


示例2a,“从文件或设备读取”,一次读取所有文件。

        ORG     256                     ;Create .COM program
        cld
        mov     si, msg1
        call    WriteStringDOS
        mov     dx, buf
        mov     cx, 127+2               ;Max input is 127 chars + CR + LF
        xor     bx, bx                  ;STDIN=0
        mov     ah, 3Fh                 ;DOS.ReadFileOrDevice
        int     21h                     ; -> AX CF
        jc      Exit
        mov     bx, ax                  ;Bytes count is less than CX
        mov     si, msg2
        call    WriteStringDOS
        mov     si, buf
        mov     [si+bx], bh             ;Keep CR and LF, append 0 (BH=0)
        call    WriteStringDOS
Exit:   mov     ax, 4C00h               ;DOS.TerminateWithExitcode
        int     21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
        pusha
        jmps    .b
.a:     mov     dl, al
        mov     ah, 02h                 ;DOS.DisplayCharacter
        int     21h                     ; -> AL
.b:     lodsb
        test    al, al
        jnz     .a
        popa
        ret
; --------------------------------------
buf:    db      127+2+1 dup (0)
msg1:   db      'Choose color ? ', 0
msg2:   db      'You chose ', 0
; --------------------------------------


示例2b,“从文件或设备读取”,一次拾取一个字节。

        ORG     256                     ;Create .COM program
        cld
        mov     si, msg1
        call    WriteStringDOS
        mov     dx, buf
        mov     cx, 1
        xor     bx, bx                  ;STDIN=0
        mov     ah, 3Fh                 ;DOS.ReadFileOrDevice
        int     21h                     ; -> AX CF
        jc      Exit
        mov     si, msg2
        call    WriteStringDOS
        mov     si, dx                  ;DX=buf, CX=1, BX=0
Next:   mov     ah, 3Fh                 ;DOS.ReadFileOrDevice
        int     21h                     ; -> AX CF
        jc      Exit
        call    WriteStringDOS          ;Display a single byte
        cmp     byte [si], 10
        jne     Next
Exit:   mov     ax, 4C00h               ;DOS.TerminateWithExitcode
        int     21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
        pusha
        jmps    .b
.a:     mov     dl, al
        mov     ah, 02h                 ;DOS.DisplayCharacter
        int     21h                     ; -> AL
.b:     lodsb
        test    al, al
        jnz     .a
        popa
        ret
; --------------------------------------
msg1:   db      'Choose color ? ', 0
msg2:   db      10, 'You chose '
buf:    db      0, 0
; --------------------------------------


使用int 2Fh AX=4810h输入文本

DOSKEY Buffered STDIN Input函数只能被if the DOSKEY.COM TSR was installed调用。它的运行方式与常规Buffered类似
STDIN输入功能0Ah(参见上文),但具有相同的编辑功能
作为DOS命令行的可能性,包括使用所有
DOSKEY特殊键。


Up从历史记录中获取上一个项目。
向下获取历史记录中的下一项。
F7显示历史记录中所有项目的列表。
AltF7清除历史记录。
... F8查找以...开头的项目
F9从历史记录中按编号选择一个项目。
AltF10删除所有宏定义。


在DOS 6.2上,存储空间始终限制为128个字节,从而允许输入
127个字符,并有强制退回的余地。不是
可以预加载模板,因此请始终设置输入的第二个字节
缓冲为零。
在DOS Win95上,如果您安装了
使用诸如doskey /line:255之类的命令来运行DOSKEY.COM TSR。有可能
使用模板预加载存储空间。这带来了Win95版本
非常接近输入功能0Ah可行的方法。

此函数执行ctrlC / ctrlBreak
检查。

完成此功能后,光标将位于菜单栏的最左列。
当前行。如果字符计数为零,则表示用户输入了
尚未扩展的DOSKEY宏的名称。你不
看到未展开的线!需要第二次调用该功能
返回此时间后,光标将位于的最后一个字符之后
展开的文字。
特殊之处在于,当扩展多命令宏($T)时,您只能
获取第一个命令的扩展文本。的其他调用
需要功能以获得其他扩展文本。尽管所有这些都是
在用户内部从COMMAND.COM之类的命令外壳中非常有用
应用程序,这真让人讨厌,您不知道什么时候发生。

由于输入的文本已添加到命令历史记录中,因此不可避免
历史记录中填充了无关的项目。当然不是您想看到的
在DOS提示符下!

示例3,调用DOSKEY.COM。

        ORG     256                     ;Create .COM program
        cld
        mov     ax, 4800h               ;DOSKEY.CheckInstalled
        int     2Fh                     ; -> AL
        test    al, al
        mov     si, err1
        jz      Exit_
Again:  mov     si, msg1
        call    WriteStringDOS
        mov     dx, buf
        mov     ax, 4810h               ;DOSKEY.BufferedInput
        int     2Fh                     ; -> AX
        test    ax, ax
        mov     si, err2
        jnz     Exit_
        cmp     [buf+1], al             ;AL=0
        je      Again                   ;Macro expansion needed
        mov     si, msg2
        call    WriteStringDOS
        mov     si, buf+2
        movzx   bx, [si-1]              ;Get character count (is GT 0)
        mov     word [si+bx+1], 10      ;Keep CR, append LF and 0
Exit_:  call    WriteStringDOS
Exit:   mov     ax, 4C00h               ;DOS.TerminateWithExitcode
        int     21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
        pusha
        jmps    .b
.a:     mov     dl, al
        mov     ah, 02h                 ;DOS.DisplayCharacter
        int     21h                     ; -> AL
.b:     lodsb
        test    al, al
        jnz     .a
        popa
        ret
; --------------------------------------
buf:    db      128, 0, 128+2 dup (0)
msg1:   db      'Choose color ? ', 0
msg2:   db      13, 10, 'You chose ', 0
err1:   db      'N/A', 13, 10, 0
err2:   db      'Failed', 13, 10, 0
; --------------------------------------


使用int 21h AH=08h输入文本


由于堆栈溢出施加的30000字节限制,文本在下面的答案中继续...


理解来源有问题吗?我使用的汇编程序:


将以点(。)开头的标签视为第一级本地标签
将以冒号(:)开头的标签视为第二级本地标签
是单指令多操作数(SIMO),因此push cx si
转换为push cx push si

关于assembly - 缓冲输入如何工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47379024/

相关文章:

python-3.x - 如何在 python 3 中的函数中使用 raw_input 作为参数

java 不会使用 Scanner 和 System.in 分解具有多个 double 和 char 变量的用户输入

command-line - 我如何在大多数目录上执行代码,但带有批处理文件的文件中列出的目录除外?

linux - x86 指令格式 : "ba 0e 00 00 00" . .. "mov $0xe,%edx"

c++ - Visual Studio 2015 C++ 和程序集未构建

python - 限制 Python 中数组/列表中输入值的数量

java - 基于DOS的JVM可用

haskell - main=return()是一个程序吗?

function - 牛顿拉夫森迭代问题

Windows 查找命令结果到文件