缓冲输入如何工作 [英] How buffered input works
问题描述
下一个程序中的输入正常,但是当我要求显示输出时,DOS 根本不显示任何内容!这怎么可能?
The input in next program works OK, but when I ask to display the output, DOS doesn't display anything at all! How is this possible?
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,并且您的程序存在潜在的缓冲区严重问题
超限.
此外,使用$终止并不是您可以做的最明智的选择
因为$字符可能已经出现在输入字符中.
我在下面介绍的所有示例程序都将使用零终止
代替.
Looking at how you defined your input buffer (buf: db 20 dup ('$')
), I get it
that you want to cut corners and have the input already $-terminated ready for
re-displaying it. Sadly this messes up the required settings for the DOS input
function 0Ah and your program is in serious problems with a potential buffer
overrun.
Moreover using $-termination is not the brightest choice that you can make
since the $ character could already appear amongst the inputted characters.
All the example programs that I present below will use zero-termination
instead.
此缓冲的STDIN输入函数可从键盘获取字符并
继续这样做,直到用户按下 Enter 键.全部
字符和最后的回车符放置在
从调用程序提供的输入缓冲区的第3个字节开始
通过DS:DX
中的指针.
字符计数(不包括最后的回车符)存储在
输入缓冲区的第二个字节.
调用程序的责任是告诉DOS
存储空间是.因此,您必须将其长度放在
输入缓冲区,然后再调用此函数.允许输入1
字符,您将存储大小设置为2.允许输入254
您将存储大小设置为255个字符.
如果您不想从模板中调出任何先前的输入,
那么最好也将第二个字节清零.基本上,模板是
输入缓冲区中预先存在(且有效)的内容是调用程序的
假如.如果预先存在的内容无效,则模板不是
可用的.
This Buffered STDIN Input function gets characters from the keyboard and
continues doing so until the user presses the Enter key. All
characters and the final carriage return are placed in the storage space that
starts at the 3rd byte of the input buffer supplied by the calling program
via the pointer in DS:DX
.
The character count, not including the final carriage return, is stored in the
2nd byte of the input buffer.
It's the responsibility of the calling program to tell DOS how large the
storage space is. Therefore you must put its length in the 1st byte of the
input buffer before calling this function. To allow for an input of 1
character you set the storage size at 2. To allow for an input of 254
characters you set the storage size at 255.
If you don't want to be able to recall from the template any previous input,
then it is best to also zero the 2nd byte. Basically the template is the
pre-existing (and valid) content in the input buffer that the calling program
provided. If pre-existing content is invalid then the template is not
available.
令人惊讶的是,此功能的编辑功能有限.
Surprisingly this function has limited editing facilities.
- 转义从当前输入中删除所有字符.
当前输入被放弃,但停留在屏幕上,光标置于 下一行,即输入第一次开始的位置. - 退格从当前输入中删除最后一个字符.
如果输入停留在屏幕上的单个行中,则按预期方式工作. 另一方面,如果输入跨越几行,则此后退间距将 停在屏幕的左边缘.从那时起,将会有一个严重的 逻辑输入和视觉输入之间存在差异,因为逻辑上 退格将一直进行到存储空间达到第一个位置为止! - F6 在当前输入中插入文件结尾字符(1Ah).
屏幕将显示"^ Z". - F7 在当前输入中插入一个零字节.
屏幕将显示"^ @". - ctrl Enter 过渡到下一行(执行 回车和换行),则不会在当前输入中添加任何内容, 不能回去.
- Escape Removes all characters from the current input.
The current input is abandoned but stays on screen and the cursor is placed on the next row, beneath where the input first started. - Backspace Removes the last character from the current input.
Works as expected if the input stays within a single row on screen. If on the other hand the input spans several rows then this backspacing will stop at the left edge of the screen. From then on there will be a serious discrepancy between the logical input and the visual input because logically backspacing will go on until the 1st position in the storage space is reached! - F6 Inserts an end-of-file character (1Ah) in the current input.
The screen will show "^Z". - F7 Inserts a zero byte in the current input.
The screen will show "^@". - ctrlEnter Transitions to the next row (executing a carriage return and linefeed), nothing is added to the current input, and you can't go back.
还有更多编辑键可用.它们都让人联想到 EDLIN.EXE , 古老的DOS行编辑器,这是一个文本编辑器,前一行 成为您在其上构建下一行的模板.
Many more editing keys are available. They are all reminiscent of EDLIN.EXE, the ancient DOS line editor, which is a text editor where each previous line becomes the template on which you build the next line.
- F1 将一个字符从模板复制到新行.
- F2 + ... 将所有字符从模板复制到新行,直到指定的字符为止.
- F3 将模板中所有剩余的字符复制到新行.
- F4 + ... 跳过模板中的字符,向上 到指定的字符.
- F5 将新行设置为新模板.
- 转义清除当前输入,并使模板保持不变.
- 删除跳过模板中的一个字符.
- 插入进入或退出插入模式.
- Backspace 删除新行的最后一个字符,并将光标移回模板中的一个字符.
- 左与Backspace相同.
- 右与F1相同.
- F1 Copies one character from the template to the new line.
- F2 + ... Copies all characters from the template to the new line, up to the character specified.
- F3 Copies all remaining characters in the template to the new line.
- F4 + ... Skips over the characters in the template, up to the character specified.
- F5 Makes the new line the new template.
- Escape Clears the current input and leaves the template unchanged.
- Delete Skips one character in the template.
- Insert Enters or exits insert mode.
- Backspace Deletes the last character of the new line and places the cursor back one character in the template.
- Left Same as Backspace.
- Right Same as F1.
标签通过此功能扩展.制表符扩展是替换的过程
ASCII 9除以一系列一个或多个空格(ASCII 32),直到光标到达
列位置是8的倍数.
此选项卡扩展仅在屏幕上发生.存储空间将保存ASCII 9.
Tabs are expanded by this function. Tab expansion is the process of replacing
ASCII 9 by a series of one or more spaces (ASCII 32) until the cursor reaches
a column position that is a multiple of 8.
This tab expansion only happens on screen. The storage space will hold ASCII 9.
此函数执行 ctrl C / ctrl 中断 检查.
This function does ctrlC/ctrlBreak checking.
此功能完成后,光标将位于 当前行.
When this function finishes, the cursor will be in the far left column on the current row.
示例1,缓冲的STDIN输入.
Example 1, Buffered STDIN input.
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
中)一起使用时,此从文件读取或设备
函数从键盘获取字符并继续这样做,直到
用户按 Enter .所有字符(不超过127个)和
最后的回车符和附加的换行符放在一个私人
DOS内核中的缓冲区.现在,它将成为新模板.
此后,该函数将写入DS:DX
中提供的缓冲区
CX
参数中请求的字节数.如果CX
指定了一个数字
小于此输入生成的字节数,一个或多个
需要其他对该函数的调用才能检索完整的输入.
只要还有字符需要提取,此功能将
不要使用键盘启动另一个输入会话!两者之间甚至如此
不同的程序或同一程序的会话.
Inputting text using int 21h AH=3Fh
When used with predefined handle 0 (in BX
) this Read From File Or Device
function gets characters from the keyboard and continues doing so until the
user presses Enter. All characters (never more than 127) and the
final carriage return plus an additional linefeed are placed in a private
buffer within the DOS kernel. This now becomes the new template.
Hereafter the function will write in the buffer provided at DS:DX
, the amount
of bytes that were requested in the CX
parameter. If CX
specified a number
that is less than the number of bytes generated by this input, one or more
additional calls to this function are required to retrieve the complete input.
As long as there are characters remaining to be picked up, this function will
not launch another input session using the keyboard! This is even true between
different programs or sessions of the same program.
上一节中描述的所有编辑键均可用.
All the editing keys described in the previous section are available.
选项卡仅在屏幕上展开,而不在模板中展开.
Tabs are expanded on screen only, not in the template.
此函数执行 ctrl C / ctrl 中断 检查.
This function does ctrlC/ctrlBreak checking.
此功能完成后,光标将位于
When this function finishes, the cursor will be in the far left column on the
- 当前行,如果终止换行符不在返回的字节中.
- 如果换行符在返回的字节中,则为下一行.
示例2a,从文件或设备读取",一次提取所有内容.
Example 2a, Read From File Or Device, pick up all at once.
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,从文件或设备读取",一次拾取一个字节.
Example 2b, Read From File Or Device, pick up one byte at a time.
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缓冲的STDIN输入函数只能被调用
Inputting text using int 2Fh AX=4810h
This DOSKEY Buffered STDIN Input function can only be invoked if the DOSKEY.COM TSR was installed. It operates much like the regular Buffered STDIN Input function 0Ah (see above), but has all the same editing possibilities as the DOS command line, including the ability to use all of the DOSKEY special keys.
- 上从历史记录中获取上一个项目.
- Down 从历史记录中获取下一项.
- F7 显示历史记录中所有项目的列表.
- Alt F7 清除历史记录.
- ... F8 查找以... 开头的项目
- F9 从历史记录中按编号选择一个项目.
- Alt F10 删除所有宏定义.
- Up Gets previous item from history.
- Down Gets next item from history.
- F7 Shows a list of all the items in the history.
- AltF7 Clears the history.
- ...F8 Finds item(s) that start with ...
- F9 Selects an item from the history by number.
- AltF10 Removes all macrodefinitions.
在DOS 6.2上,存储空间始终限制为128个字节,从而允许输入
127个字符,并有强制退回的余地.它不是
可以预加载模板,因此请始终设置输入的第二个字节
缓冲为零.
在DOS Win95上,如果安装了Windows XP操作系统,则存储空间可以多达255个字节.
使用类似doskey /line:255
的命令的DOSKEY.COM TSR.有可能
使用模板预加载存储空间.这带来了Win95版本
非常接近输入功能0Ah可行的方法.
On DOS 6.2 the storage space is always limited to 128 bytes, allowing an input
of 127 characters and room for the mandatory carriage return. It's not
possible to pre-load a template, so always set the 2nd byte of the input
buffer to zero.
On DOS Win95 the storage space can be as big as 255 bytes if you installed the
DOSKEY.COM TSR with a command like doskey /line:255
. It's possible to
pre-load the storage space with a template. This brings the Win95 version
very close to what is feasable with input function 0Ah.
此函数执行 ctrl C / ctrl 中断 检查.
This function does ctrlC/ctrlBreak checking.
此功能完成后,光标将位于
当前行.如果字符计数为零,则表示用户输入了
尚未扩展的DOSKEY宏的名称.你不
看看未展开的线!需要第二次调用该功能
并在返回该时间时,光标将位于的最后一个字符的后面
展开的文本.
特殊之处在于,当扩展多命令宏($T
)时,您只能
获取第一个命令的扩展文本.的其他调用
需要功能以获取其他扩展文本.尽管所有这些都是
在用户内部从像COMMAND.COM这样的命令外壳中非常有用
应用程序真的很烦人,您不知道什么时候发生这种情况.
When this function finishes, the cursor will be in the far left column on the
current row. If the character count is zero, it means that the user typed in
the name of a DOSKEY macro that was not yet expanded. You don't
get to see the un-expanded line! A second invocation of the function is needed
and upon returning this time, the cursor will be behind the last character of
the expanded text.
A peculiarity is that when a multi-command macro ($T
) gets expanded, you only
get the expanded text of the 1st command. Additional invocations of the
function are needed to get the other expanded texts. Although all of this is
very useful from within a command shell like COMMAND.COM, from within a user
application it's really annoying that you can't know when this happens.
由于输入的文本已添加到命令历史记录中,因此不可避免的是 历史记录中填充了无关的项目.当然不是您想看到的 在DOS提示符下!
Since the inputted text is added to the command history, it is unavoidable that the history fills up with unrelated items. Certainly not what you want to see at the DOS prompt!
示例3,调用DOSKEY.COM.
Example 3, Invoking 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
输入文本
Inputting text using int 21h AH=08h
由于堆栈溢出强加了30000个字节的限制,因此文本在下面的答案中继续出现...
Because of the 30000 byte limit that Stack Overflow imposes the text continues in the below answer...
是否了解源代码?我使用的汇编器:
Problem understanding the source? The assembler I used:
- 将以点(.)开头的标签视为第一级本地标签
- 将以冒号(:)开头的标签视为第二级本地标签
- 是单指令多操作数(SIMO),所以
push cx si
转换为push cx
push si
.
- considers labels that start with a dot ( . ) as 1st level local labels
- considers labels that start with a colon ( : ) as 2nd level local labels
- is Single Instruction Multiple Operands (SIMO), so
push cx si
translates topush cx
push si
.
这篇关于缓冲输入如何工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!