缓冲输入的工作原理

How buffered input works

下一个程序的输入工作正常,但是当我要求显示输出时,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 ('$')),我明白了 你想偷工减料并让输入已经 $-terminated 准备好 re-displaying它。遗憾的是,这搞乱了 DOS 输入所需的设置 功能 0Ah 并且您的程序存在潜在缓冲区的严重问题 超限。
此外,使用 $-termination 并不是您可以做出的最明智的选择 因为 $ 字符可能已经出现在输入的字符中。 我在下面展示的所有示例程序都将使用 zero-termination 相反。

正在使用 int 21h AH=0Ah

输入文本

这个Buffered STDIN Input函数从键盘获取字符并 继续这样做,直到用户按下 Enter 键。全部 字符和最后的回车 return 被放置在存储 space 中 从调用程序提供的输入缓冲区的第 3 个字节开始 通过 DS:DX.
中的指针 字符数,不包括最后的回车 return,存储在 输入缓冲区的第二个字节。
调用程序有责任告诉 DOS 有多大 存储 space 是。因此你必须把它的长度放在 调用此函数之前输入缓冲区。允许输入 1 您将存储大小设置为 2 的字符。允许输入 254 您将存储大小设置为 255 个字符。
如果您不想从模板中调用任何以前的输入, 那么最好也将第二个字节归零。基本上模板是 pre-existing 调用程序输入缓冲区中的(有效)内容 假如。如果 pre-existing 内容无效则模板不可用 可用的。

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

  • Escape 从当前输入中删除所有字符。
    当前输入被放弃但停留在屏幕上并且光标位于 下一行,在输入开始的位置下方。
  • 返回space 从当前输入中删除最后一个字符。
    如果输入在屏幕上保持在一行内,则按预期工作。 另一方面,如果输入跨越多行,那么这个退格将 停在屏幕的左边缘。从此以后会有严重的 逻辑输入和视觉输入之间的差异,因为逻辑上 退格将继续,直到到达存储中的第一个位置 space!
  • F6 在当前输入中插入一个 end-of-file 字符 (1Ah)。
    屏幕将显示“^Z”。
  • F7 在当前输入中插入一个零字节。
    屏幕将显示“^@”。
  • ctrlEnter 过渡到下一行(执行 carriage return and linefeed),当前输入没有添加任何内容,你 回不去了

可以使用更多的编辑键。都让人联想到EDLIN.EXE, 古老的 DOS 行编辑器,这是一个文本编辑器,每个前一行 成为您构建下一行的模板。

  • F1 从模板复制一个字符到新行。
  • F2 + ... 将模板中的所有字符复制到新行,直到指定的字符。
  • F3 将模板中所有剩余的字符复制到新行。
  • F4 + ... 跳过模板中的字符,向上 到指定的字符。
  • F5 使新行成为新模板。
  • Escape 清除当前输入并保持模板不变。
  • 删除 跳过模板中的一个字符。
  • Insert 进入或退出插入模式。
  • 后退space 删除新行的最后一个字符并将光标在模板中后退一个字符。
  • 同后space.
  • 同F1

此功能扩展了选项卡。 Tab展开就是替换的过程 ASCII 9 通过一系列一个或多个 spaces (ASCII 32) 直到光标到达 8 的倍数的列位置。
此选项卡扩展仅发生在屏幕上。存储 space 将保存 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 个)和 最后的回车 return 加一个 additio所有换行都放在一个私人 DOS 内核中的缓冲区。这现在成为新模板。
此后该函数将写入 DS:DX 处提供的缓冲区,金额 CX 参数中请求的字节数。如果CX指定了一个数字 小于此输入生成的字节数,一个或多个 需要额外调用此函数才能检索完整的输入。 只要还有剩余的字符需要拾取,这个函数就会 不要使用键盘启动另一个输入 session!这甚至是真实的 不同的程序或 session 个相同的程序。

上一节中描述的所有编辑键都可用。

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

这个函数做ctrlC/ctrlBreak 检查。

当此函数完成时,光标将位于

上最左侧的列
  • 当前行,如果终止换行符不在 returned 字节中。
  • 下一行,如果终止换行符在 returned 字节中。

示例 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 函数只能被调用 如果 DOSKEY.COM TSR 已安装。它的操作很像常规的 Buffered STDIN 输入函数 0Ah(见上),但具有相同的编辑 作为 DOS 命令行的可能性,包括使用所有的能力 DOSKEY 特殊键。

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

在 DOS 6.2 上,存储 space 总是限制在 128 字节,允许输入 127 个字符和强制运输的空间 return。它不是 可能 pre-load 一个模板,所以总是设置输入的第二个字节 缓冲区为零。
在 DOS Win95 上,如果安装了 DOSKEY.COM TSR 带有类似 doskey /line:255 的命令。有可能 pre-load 存储space 带有模板。这带来了Win95版本 非常接近输入函数 0Ah 的可行性。

这个函数做ctrlC/ctrlBreak 检查。

当这个函数完成后,光标将在最左边的列中 当前行。如果字符数为零,则表示用户输入 尚未扩展的 DOSKEY 宏的名称。你不 去看看 un-expanded 行!需要第二次调用该函数 并且这次 returning 时,光标将在最后一个字符的后面 展开的文本。
一个特点是当 multi-command 宏 ($T) 被展开时,你只 获取第一个命令的扩展文本。的额外调用 需要函数来获取其他扩展文本。虽然这一切都是 从用户内部的命令 shell 中非常有用,例如 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

输入文本

Because of the 30000 byte limit that Stack Overflow imposes the text continues in the below answer...

无法理解来源?我使用的汇编程序:

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

正在使用 int 21h AH=08h

输入文本

到目前为止描述的所有三种输入法(在上面的回答中!)显然是为适合 EDLIN.EXE 和 COMMAND.COM.
等 Microsoft 工具而量身定制的 如果您正在编写自己的应用程序,那么可以获得更好的结果 通过生成您自己的输入程序。这种程序的核心 将是DOS单字符输入功能之一。我选择了 STDIN input function 08h 因为我要让 ctrlC/ctrlBreak 检查和我 打算自己通过 BIOS 回显字符 Int 10h AH=09h Write Character And Attribute At Cursor Position。这样我可以 避免弄乱任何重定向的输出。

以编程方式使用此 BufferedInput 过程没有区别 或 DOS.BufferedInput 系统调用。但是对于键盘上的用户 输入会容易得多,因为所有的键都与旧的和 困难的模板编辑已被取消,取而代之的是通常的 使您能够自由移动光标的编辑键。

  • 向左 向左移动光标。
  • 向右 向右移动光标。
  • 主页 将光标移动到最左边。
  • End 将光标移到最右边。
  • CtrlHome 删除左边的所有字符。
  • CtrlEnd 删除右边的所有字符。
  • 删除 删除当前字符。
  • 返回space 删除光标左侧的字符。
  • Escape 删除所有字符。
  • Return 结束输入。

如果输入缓冲区的第 2 个字节包含非零值,则存储 space 应该包含一个旧字符串(可能来自以前的输入)。 DOS 会 称此为模板。与DOS不同的是:

  • 旧字符串不需要回车 return 终止。
  • 旧字符串立即显示在屏幕上。

在输入过程中,制表符展开并且输入是 仅限于停留在当前行内。较长的文本将水平滚动。
当输入最后完成时,完成的文本写一次 tab 扩展(在屏幕上,存储 space 将始终保持 ASCII 9)并且不再局限于一行。

这个程序做ctrlC/ctrlBreak 检查。

此过程完成后,光标将位于 当前行。

这个程序是用input redirection and output redirection写的 记住,因此非常适合控制台应用程序。
输入重定向的一个影响是将任何临时输出回显到屏幕上是无用的。要么用户不在那里注视屏幕,要么临时输出将在眨眼间消失。

示例 4,改进的缓冲 STDIN 输入。

        ORG     256                     ;Create .COM program
        cld
        mov     si, msg1
        call    WriteStringDOS
        mov     dx, buf
        call    BufferedInput           ;Replaces 'mov ah, 0Ah : 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
; --------------------------------------
; IN (ds:dx) OUT ()
BufferedInput:

; Entry DS:DX   Buffer of max 1+1+255 bytes
;               1st byte is size of storage space starting at 3rd byte
;               2nd byte is size of old (CR-terminated) string, 0 if none
;               Storage space can contain old (CR-terminated) string
; Exit  DS:DX   Nothing changed if header bytes were invalid
;               1st byte unchanged
;               2nd byte is size of new CR-terminated string
;               Storage space contains new CR-terminated string
; Local [bp-1]  PAGE    Display page
;       [bp-2]  STORE   Size of storage space
;       [bp-3]  ROW     Row of input box
;       [bp-4]  COL     Column of input box
;       [bp-5]  SHIFT   Number of characters shifted out on the leftside
;       [bp-6]  INBOX   Size of input box
;       [bp-7]  LIX     Number of characters in current input string
;       [bp-8]  CIX     Position of cursor in current input string
;       [bp-10] FLAGS   Bit[0] is ON for normal keyboard input

        pusha
        mov     si, dx
        lodsw                           ; -> SI points at storage space
        test    al, al                  ;AL is size of storage space
        jz      .Quit                   ;No storage space!
        cmp     ah, al                  ;AH is size of old string
        jnb     .Quit                   ;Old string too long!
        mov     bl, al

        sub     sp, 256                 ;Local edit buffer (max size)
        mov     bp, sp
        mov     ah, 0Fh                 ;BIOS.GetVideoMode
        int     10h                     ; -> AL=Mode AH=Cols BH=Page
        push    bx                      ;STORE and PAGE
        mov     bl, ah
        mov     ah, 03h                 ;BIOS.GetCursor
        int     10h                     ; -> CX=Shape DL=Col DH=Row
        push    dx                      ;COL and ROW
        sub     bl, dl                  ;Size of the widest inbox
        xor     bh, bh
        push    bx                      ;INBOX and SHIFT
        push    bx                      ;CIX and LIX (replaces 'sub sp, 2')

        call    .ESC                    ;Clear edit buffer, reset some vars
        mov     cl, [si-1]              ;Size of old string (starts at SI)
        jmps    .b
.a:     lodsb                           ;Storage space gives old string
        push    cx si
        call    .Asc                    ;Input old string
        pop     si cx
.b:     sub     cl, 1
        jnb     .a

        xor     bx, bx                  ;STDIN
        mov     ax, 4400h               ;DOS.GetDeviceInformation
        int     21h                     ; -> AX DX CF
        jc      .c                      ;Go default to keyboard
        test    dl, dl
        jns     .d                      ;Block device, not keyboard
        shr     dl, 1
.c:     adc     bx, bx                  ; -> BX=1 if Keyboard
.d:     push    bx                      ;FLAGS

.Main:  call    .Show                   ;Refresh input box on screen
        call    .Key                    ;Get key from DOS -> AX
        mov     bx, .Scans
        test    ah, ah
        jz      .f                      ;Not an extended ASCII
        mov     [cs:.Fail], ah          ;Sentinel
.e:     lea     bx, [bx+3]
        cmp     ah, [cs:bx-1]
        jne     .e
.f:     call    [cs:bx]
        jmps    .Main

.Quit:  popa                            ;Silently quiting just like DOS
        ret
; - - - - - - - - - - - - - - - - - - -
.Scans: db           .Asc
        db      4Bh, .s4B               ;<LEFT>
        db      4Dh, .s4D               ;<RIGHT>
        db      47h, .s47               ;<HOME>
        db      4Fh, .s4F               ;<END>
        db      77h, .s77               ;<CTRL-HOME>
        db      75h, .s75               ;<CTRL-END>
        db      53h, .s53               ;<DELETE>
.Fail:  db        ?, .Beep
; - - - - - - - - - - - - - - - - - - -
.Beep:  mov     ax, 0E07h               ;BIOS.TeletypeBell
        int     10h
        ret
; - - - - - - - - - - - - - - - - - - -
.Key:   call    :1
        test    ah, ah                  ;Extended ASCII requires 2 calls
        jnz     :2
:1:     mov     ah, 08h                 ;DOS.STDINInput
        int     21h                     ; -> AL
        mov     ah, 0
:2:     xchg    al, ah
        ret
; - - - - - - - - - - - - - - - - - - -
.Show:  test    word [bp-10], 1         ;FLAGS.Keyboard ?
        jz      :Ready                  ;No, input is redirected
        movzx   di, [bp-6]              ;INBOX
        movzx   si, [bp-5]              ;SHIFT
        mov     dx, [bp-4]              ;COL and ROW
        mov     cx, 1                   ;Replication count
        mov     bh, [bp-1]              ;PAGE
        mov     bl, 07h                 ;WhiteOnBlack
:Next:  mov     ah, 02h                 ;BIOS.SetCursor
        int     10h
        mov     al, [bp+si]
        mov     ah, 09h                 ;BIOS.WriteCharacterAndAttribute
        int     10h
        inc     dl                      ;Next column
        inc     si                      ;Next character
        dec     di
        jnz     :Next                   ;Process all of the input box

        mov     dx, [bp-4]              ;COL and ROW
        add     dl, [bp-8]              ;CIX
        sub     dl, [bp-5]              ;SHIFT
        mov     ah, 02h                 ;BIOS.SetCursor
        int     10h
:Ready: ret
; - - - - - - - - - - - - - - - - - - -
.BS:    cmp     byte [bp-8], 0          ;CIX
        jne     :1
        ret
:1:     call    .s4B                    ;<LEFT>
; ---   ---   ---   ---   ---   ---   --
; <DELETE>
.s53:   movzx   di, [bp-8]              ;CIX
        movzx   cx, [bp-7]              ;LIX
        sub     cx, di
        je      :2                      ;Cursor behind the current input
:1:     mov     dl, [bp+di+1]           ;Move down in edit buffer
        mov     [bp+di], dl
        inc     di
        dec     cx
        jnz     :1
        dec     byte [bp-7]             ;LIX
:2:     ret
; - - - - - - - - - - - - - - - - - - -
.RET:   xor     si, si
        mov     bx, [bp+256+10]         ;pusha.DX -> DS:BX
        mov     al, [bp-7]              ;LIX
        inc     bx
        mov     [bx], al                ;2nd byte is size of new string
        inc     bx
        jmps    :2
:1:     mov     dl, [bp+si]
        mov     [bx+si], dl             ;Storage space receives new string
        inc     si
:2:     sub     al, 1
        jnb     :1
        mov     byte [bx+si], 13        ;Terminating CR

        push    bx                      ;(1)
        call    .ESC                    ;Wipe clean the input box
        call    .Show                   ; and reset cursor
        pop     si                      ;(1) -> DS:SI
:3:     lodsb                           ;Final unrestricted display,
        mov     dl, al                  ; expanding tabs
        mov     ah, 02h                 ;DOS.DisplayCharacter
        int     21h                     ; -> AL
        cmp     dl, 13                  ;Cursor ends in far left column
        jne     :3

        lea     sp, [bp+256]            ;Free locals and edit buffer
        popa
        ret
; - - - - - - - - - - - - - - - - - - -
.ESC:   mov     di, 256                 ;Fill edit buffer with spaces
:1:     sub     di, 2
        mov     word [bp+di], "  "
        jnz     :1
        mov     [bp-8], di              ;DI=0 -> CIX=0 LIX=0
        mov     byte [bp-5], 0          ;SHIFT=0
        ret
; - - - - - - - - - - - - - - - - - - -
.Asc:   cmp     al, 8                   ;<BACKSPACE>
        je      .BS
        cmp     al, 13                  ;<RETURN>
        je      .RET
        cmp     al, 27                  ;<ESCAPE>
        je      .ESC
        cmp     al, 10                  ;Silently ignoring linefeed
        jne     :1                      ; in favor of input redirection
        ret
:1:     movzx   di, [bp-8]              ;CIX
        movzx   si, [bp-7]              ;LIX
        lea     dx, [si+1]
        cmp     dl, [bp-2]              ;STORE
        jb      :3
        jmp     .Beep                   ;Storage capacity reached
:2:     mov     dl, [bp+si-1]           ;Move up in edit buffer
        mov     [bp+si], dl
        dec     si
:3:     cmp     si, di
        ja      :2
        mov     [bp+si], al             ;Add newest character
        inc     byte [bp-7]             ;LIX
; ---   ---   ---   ---   ---   ---   --
; <RIGHT>
.s4D:   inc     byte [bp-8]             ;CIX
        mov     al, [bp-7]              ;LIX
        cmp     [bp-8], al              ;CIX
        jbe     .Shift
        mov     [bp-8], al              ;CIX
        ret
; - - - - - - - - - - - - - - - - - - -
; <LEFT>
.s4B:   sub     byte [bp-8], 1           ;CIX
        jnb     .Shift
; ---   ---   ---   ---   ---   ---   --
; <HOME>
.s47:   mov     byte [bp-8], 0          ;CIX
        jmps    .Shift
; - - - - - - - - - - - - - - - - - - -
; <END>
.s4F:   mov     al, [bp-7]              ;LIX
        mov     [bp-8], al              ;CIX
; ---   ---   ---   ---   ---   ---   --
.Shift: mov     dl, [bp-5]              ;SHIFT
        mov     al, [bp-8]              ;CIX
        cmp     al, dl
        jb      :1
        add     dl, [bp-6]              ;INBOX
        sub     al, dl
        jb      :2
        inc     al
        add     al, [bp-5]              ;SHIFT
:1:     mov     [bp-5], al              ;SHIFT
:2:     ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-HOME>
.s77:   call    .BS
        cmp     byte [bp-8], 0          ;CIX
        ja      .s77
        ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-END>
.s75:   call    .s53                    ;<DELETE>
        mov     al, [bp-8]              ;CIX
        cmp     al, [bp-7]              ;LIX
        jb      .s75
        ret
; --------------------------------------
buf:    db      255, 16, "I'm an OldString", 13, 255-16-1+2 dup (0)
msg1:   db      'Choose color ? ', 0
msg2:   db      10, 'You chose ', 0
; --------------------------------------

无法理解来源?我使用的汇编程序:

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

For a really high performing input procedure, look at Rich Edit Form Input, a Code Review contribution.