Sep*_*and 5 assembly dos input 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 : ', '$'
; --------------------------------------
Run Code Online (Sandbox Code Playgroud)
看看你如何定义你的输入缓冲区 ( buf: db 20 dup ('$')),我知道你想偷工减料,并且输入已经 $-terminated 准备好重新显示它。遗憾的是,这弄乱了 DOS 输入函数 0Ah 所需的设置,并且您的程序存在潜在缓冲区溢出的严重问题。
此外,使用 $-termination 并不是您可以做出的最明智的选择,因为 $ 字符可能已经出现在输入的字符中。我在下面展示的所有示例程序都将使用零终止。
int 21h AH=0Ah此缓冲 STDIN 输入函数从键盘获取字符并继续这样做,直到用户按下该Enter键。所有字符和最后的回车符都放置在存储空间中,该存储空间从调用程序通过 in 中的指针提供的输入缓冲区的第 3 个字节开始DS:DX。
字符数(不包括最后的回车符)存储在输入缓冲区的第二个字节中。
调用程序有责任告诉 DOS 存储空间有多大。因此,在调用此函数之前,您必须将其长度放在输入缓冲区的第一个字节中。要允许输入 1 个字符,请将存储大小设置为 2。要输入 254 个字符,请将存储大小设置为 255。
如果您不想从模板中调用任何以前的输入,那么最好也将第二个字节归零。基本上,模板是调用程序提供的输入缓冲区中预先存在(和有效)的内容。如果预先存在的内容无效,则模板不可用。
令人惊讶的是,此功能的编辑功能有限。
还有更多的编辑键可用。它们都让人想起EDLIN.EXE,古老的 DOS 行编辑器,这是一个文本编辑器,其中每一行都成为您构建下一行的模板。
此功能可扩展选项卡。选项卡扩展是用一系列一个或多个空格 (ASCII 32) 替换 ASCII 9 直到光标到达 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
; --------------------------------------
Run Code Online (Sandbox Code Playgroud)
int 21h AH=3Fh当与预定义的句柄 0 (in 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
; --------------------------------------
Run Code Online (Sandbox Code Playgroud)
示例 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
; --------------------------------------
Run Code Online (Sandbox Code Playgroud)
int 2Fh AX=4810h只有安装了 DOSKEY.COM TSR,才能调用此DOSKEY 缓冲 STDIN 输入函数。它的操作很像常规的缓冲 STDIN 输入函数 0Ah(见上文),但具有与 DOS 命令行相同的所有编辑可能性,包括使用所有 DOSKEY 特殊键的能力。
在 DOS 6.2 上,存储空间始终限制为 128 字节,允许输入 127 个字符并为强制回车留出空间。无法预加载模板,因此始终将输入缓冲区的第二个字节设置为零。
在 DOS Win95 上,如果您使用类似doskey /line:255. 可以使用模板预加载存储空间。这使得 Win95 版本非常接近输入函数 0Ah 的可行性。
这个函数做ctrlC/ctrlBreak 检查。
此函数完成后,光标将位于当前行的最左侧列中。如果字符计数为零,则表示用户键入了尚未展开的 DOSKEY 宏的名称。你看不到未展开的线!需要再次调用该函数,这次返回时,光标将位于扩展文本的最后一个字符后面。
一个特点是当一个多命令宏 ( $T) 被扩展时,你只能得到第一个命令的扩展文本。需要额外调用该函数来获取其他扩展文本。尽管所有这些在像 COMMAND.COM 这样的命令 shell 中非常有用,但在用户应用程序中,你不知道什么时候发生这种情况真的很烦人。
由于输入的文本被添加到命令历史中,因此历史不可避免地被无关项目填满。当然不是你想在 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
; --------------------------------------
Run Code Online (Sandbox Code Playgroud)
int 21h AH=08h由于堆栈溢出强加的 30000 字节限制,文本在下面的答案中继续......
理解来源有问题?我使用的汇编程序:
push cx si
转换为push cx push si.