Cómo funciona la entrada almacenada en búfer

Resuelto Sep Roland asked hace 6 años • 3 respuestas

La entrada en el siguiente programa (usando la función DOS.BufferedInput 0Ah) funciona bien, pero cuando pido mostrar la salida, DOS no muestra nada en absoluto. ¿Cómo es esto posible?

        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 : ', '$'
; --------------------------------------

Tenga en cuenta que estas preguntas y respuestas autocontestadas vienen con una respuesta de dos partes. Cualquier persona interesada debe comenzar su lectura con la respuesta aceptada .

Sep Roland avatar Nov 19 '17 23:11 Sep Roland
Aceptado

Al observar cómo definió su búfer de entrada ( buf: db 20 dup ('$')), entiendo que desea tomar atajos y tener la entrada terminada en $ lista para volver a mostrarla. Lamentablemente, esto arruina la configuración requerida para la función de entrada de DOS 0Ah y su programa tiene serios problemas con una posible saturación del búfer.
Además, usar la terminación $ no es la elección más inteligente que puede hacer, ya que el carácter $ ya podría aparecer entre los caracteres ingresados. Todos los programas de ejemplo que presento a continuación utilizarán terminación cero en su lugar.

Ingresando texto usandoint 21h AH=0Ah

Esta función de entrada STDIN almacenada en búfer obtiene caracteres del teclado y continúa haciéndolo hasta que el usuario presiona la Entertecla. Todos los caracteres y el retorno de carro final se colocan en el espacio de almacenamiento que comienza en el tercer byte del búfer de entrada proporcionado por el programa que llama mediante el puntero en DS:DX.
El recuento de caracteres, sin incluir el retorno de carro final, se almacena en el segundo byte del búfer de entrada.
Es responsabilidad del programa que llama decirle a DOS qué tan grande es el espacio de almacenamiento. Por lo tanto, debes poner su longitud en el primer byte del búfer de entrada antes de llamar a esta función. Para permitir una entrada de 1 carácter, establezca el tamaño de almacenamiento en 2. Para permitir una entrada de 254 caracteres, establezca el tamaño de almacenamiento en 255.
Si no desea poder recuperar de la plantilla ninguna entrada anterior, entonces es mejor poner a cero también el segundo byte. Básicamente, la plantilla es el contenido preexistente (y válido) en el búfer de entrada que proporcionó el programa de llamada. Si el contenido preexistente no es válido, la plantilla no estará disponible.

Sorprendentemente, esta función tiene funciones de edición limitadas.

  • EscapeElimina todos los caracteres de la entrada actual.
    La entrada actual se abandona pero permanece en la pantalla y el cursor se coloca en la siguiente fila, debajo de donde comenzó la entrada.
  • BackspaceElimina el último carácter de la entrada actual.
    Funciona como se esperaba si la entrada permanece dentro de una sola fila en la pantalla. Si, por otro lado, la entrada abarca varias filas, este retroceso se detendrá en el borde izquierdo de la pantalla. A partir de entonces habrá una grave discrepancia entre la entrada lógica y la entrada visual porque lógicamente el retroceso continuará hasta que se alcance la primera posición en el espacio de almacenamiento.
  • F6Inserta un carácter de fin de archivo (1Ah) en la entrada actual.
    La pantalla mostrará "^Z".
  • F7Inserta un byte cero en la entrada actual.
    La pantalla mostrará "^@".
  • ctrlEnterPasa a la siguiente fila (ejecuta un retorno de carro y un salto de línea), no se agrega nada a la entrada actual y no se puede retroceder.

Hay muchas más claves de edición disponibles. Todos recuerdan a EDLIN.EXE , el antiguo editor de líneas de DOS, que es un editor de texto donde cada línea anterior se convierte en la plantilla sobre la cual se construye la siguiente línea.

  • F1Copia un carácter de la plantilla a la nueva línea.
  • F2+ ... Copia todos los caracteres de la plantilla a la nueva línea, hasta el carácter especificado.
  • F3Copia todos los caracteres restantes de la plantilla en la nueva línea.
  • F4+ ...Salta los caracteres de la plantilla, hasta el carácter especificado.
  • F5Convierte la nueva línea en la nueva plantilla.
  • EscapeBorra la entrada actual y deja la plantilla sin cambios.
  • DeleteSalta un carácter en la plantilla.
  • InsertEntra o sale del modo de inserción.
  • BackspaceElimina el último carácter de la nueva línea y coloca el cursor un carácter atrás en la plantilla.
  • LeftLo mismo que Retroceso.
  • RightLo mismo que la F1.

Esta función amplía las pestañas. La expansión de pestañas es el proceso de reemplazar ASCII 9 por una serie de uno o más espacios (ASCII 32) hasta que el cursor alcanza una posición de columna que es múltiplo de 8.
Esta expansión de pestañas solo ocurre en la pantalla. El espacio de almacenamiento contendrá ASCII 9.

Esta función hace ctrlC/ ctrlBreak verifica.

Cuando finalice esta función, el cursor estará en la columna del extremo izquierdo de la fila actual.

Ejemplo 1, entrada STDIN almacenada en búfer.

        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, byte [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
; --------------------------------------

Ingresando texto usandoint 21h AH=3Fh

Cuando se usa con el identificador predefinido 0 (en BX), esta función Leer desde archivo o dispositivo obtiene caracteres del teclado y continúa haciéndolo hasta que el usuario presiona Enter. Todos los caracteres (nunca más de 127) y el retorno de carro final más un salto de línea adicional se colocan en un búfer privado dentro del kernel de DOS. Esta ahora se convierte en la nueva plantilla.
De ahora en adelante la función escribirá en el buffer provisto en DS:DX, la cantidad de bytes que fueron solicitados en el CXparámetro. Si CXse especifica un número menor que el número de bytes generados por esta entrada, se requieren una o más llamadas adicionales a esta función para recuperar la entrada completa. Mientras queden caracteres por seleccionar, esta función no iniciará otra sesión de entrada usando el teclado. Esto es cierto incluso entre diferentes programas o sesiones del mismo programa.

Están disponibles todas las claves de edición descritas en el apartado anterior.

Las pestañas se expanden sólo en la pantalla, no en la plantilla.

Esta función hace ctrlC/ ctrlBreak verifica.

Cuando finalice esta función, el cursor estará en la columna del extremo izquierdo de la

  • fila actual si el salto de línea final no estaba entre los bytes devueltos.
  • siguiente fila si el salto de línea final estaba entre los bytes devueltos.

Ejemplo 2a, Leer desde archivo o dispositivo, seleccione todo a la vez.

        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
; --------------------------------------

Ejemplo 2b, Lectura desde archivo o dispositivo, seleccione un byte a la vez.

        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
; --------------------------------------

Ingresando texto usandoint 2Fh AX=4810h

Esta función de entrada STDIN almacenada en búfer de DOSKEY sólo se puede invocar si se instaló DOSKEY.COM TSR . Funciona de manera muy similar a la función de entrada STDIN almacenada en búfer 0Ah (ver arriba), pero tiene las mismas posibilidades de edición que la línea de comando de DOS, incluida la capacidad de usar todas las teclas especiales de DOSKEY.

  • UpObtiene el elemento anterior del historial.
  • DownObtiene el siguiente elemento del historial.
  • F7Muestra una lista de todos los elementos del historial.
  • AltF7Borra el historial.
  • ...F8Encuentra elementos que comienzan con...
  • F9Selecciona un elemento del historial por número.
  • AltF10Elimina todas las macrodefiniciones.

En DOS 6.2, el espacio de almacenamiento siempre está limitado a 128 bytes, lo que permite una entrada de 127 caracteres y espacio para el retorno de carro obligatorio. No es posible precargar una plantilla, por lo tanto, establezca siempre el segundo byte del búfer de entrada en cero.
En DOS Win95, el espacio de almacenamiento puede ser tan grande como 255 bytes si instaló DOSKEY.COM TSR con un comando comodoskey /line:255 . Es posible precargar el espacio de almacenamiento con una plantilla. Esto acerca la versión Win95 a lo que es factible con la función de entrada 0Ah.

Esta función hace ctrlC/ ctrlBreak verifica.

Cuando finalice esta función, el cursor estará en la columna del extremo izquierdo de la fila actual. Si el recuento de caracteres es cero, significa que el usuario escribió el nombre de una macro DOSKEY que aún no estaba expandida. ¡No podrás ver la línea no expandida! Es necesaria una segunda invocación de la función y al regresar esta vez, el cursor estará detrás del último carácter del texto expandido.
Una peculiaridad es que cuando se expande una macro de múltiples comandos ( $T), solo se obtiene el texto expandido del primer comando. Se necesitan invocaciones adicionales de la función para obtener los otros textos expandidos. Aunque todo esto es muy útil desde un shell de comandos como COMMAND.COM, desde una aplicación de usuario es realmente molesto que no puedas saber cuándo sucede esto.

Dado que el texto ingresado se agrega al historial de comandos, es inevitable que el historial se llene con elementos no relacionados. ¡Ciertamente no es lo que desea ver en el indicador de DOS!

Ejemplo 3, invocando 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, byte [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
; --------------------------------------

Ingresando texto usandoint 21h AH=08h

Debido al límite de 30000 bytes que impone Stack Overflow, el texto continúa en la siguiente respuesta...

¿Problemas para entender la fuente? El ensamblador que utilicé:

  • considera etiquetas que comienzan con un punto ( . ) como etiquetas locales de 1er nivel
  • considera las etiquetas que comienzan con dos puntos ( : ) como etiquetas locales de segundo nivel
  • es Instrucción única de múltiples operandos (SIMO), por lo que push cx si se traduce como push cx push si.
Sep Roland avatar Nov 19 '2017 16:11 Sep Roland

Ingresando texto usandoint 21h AH=08h

Los tres métodos de entrada descritos hasta ahora (¡en la respuesta anterior!) fueron claramente hechos a medida para adaptarse a herramientas de Microsoft como EDLIN.EXE y COMMAND.COM.
Si está escribiendo su propia aplicación, podrá lograr mejores resultados produciendo su propio procedimiento de entrada. En el centro de dicho procedimiento estará una de las funciones de entrada de un solo carácter de DOS. Elegí la función de entrada STDIN 08h porque quiero permitir ctrlC/ ctrlBreakverificar y tengo la intención de hacer eco de los caracteres yo mismo a través del BIOS Int 10h AH=09h Escribir caracteres y atributos en la posición del cursor . De esta manera puedo evitar estropear cualquier salida redirigida.

Programáticamente no hay diferencia en el uso de este procedimiento BufferedInput o la llamada al sistema DOS.BufferedInput . Sin embargo, para el usuario escribir en el teclado será mucho más fácil ya que todas las teclas asociadas con la antigua y difícil edición de plantillas han sido descartadas y reemplazadas por las teclas de edición habituales que le permiten mover libremente el cursor.

  • LeftMueve el cursor hacia la izquierda.
  • RightMueve el cursor hacia la derecha.
  • HomeMueve el cursor hacia el extremo izquierdo.
  • EndMueve el cursor hacia el extremo derecho.
  • CtrlHomeElimina todos los caracteres a la izquierda.
  • CtrlEndElimina todos los caracteres a la derecha.
  • DeleteElimina el carácter actual.
  • BackspaceElimina el carácter a la izquierda del cursor.
  • EscapeElimina todos los personajes.
  • ReturnFinaliza la entrada.

Si el segundo byte del búfer de entrada contiene un valor distinto de cero, entonces se supone que el espacio de almacenamiento contiene una cadena antigua (quizás de una entrada anterior). DOS habría llamado a esto la plantilla. A diferencia de DOS es que:

  • No es necesario que la cadena antigua tenga terminación de retorno de carro.
  • la cadena antigua se muestra inmediatamente en la pantalla.

Mientras la entrada está en curso, las pestañas no se expanden y la entrada se limita a permanecer dentro de la fila actual. Los textos más largos se desplazarán horizontalmente.
Cuando finalmente se realiza la entrada, el texto completo se escribe una vez con expansión de pestañas (en la pantalla, el espacio de almacenamiento siempre tendrá ASCII 9) y ya no estará restringido a una sola fila.

Este procedimiento hace ctrlC/ ctrlBreak verifica.

Cuando finalice este procedimiento, el cursor estará en la columna del extremo izquierdo de la fila actual.

Este procedimiento se escribió teniendo en cuenta la redirección de entrada y la redirección de salida y, por lo tanto, es muy adecuado para aplicaciones de consola.
Un efecto de la redirección de entrada es que es inútil hacer eco de cualquier salida temporal en la pantalla. O el usuario no está allí para mirar la pantalla o la salida temporal desaparecerá en un abrir y cerrar de ojos.

Ejemplo 4, entrada STDIN almacenada en búfer mejorada.

        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, byte [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, byte [bp-6]         ;INBOX
        movzx   si, byte [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, byte [bp-8]         ;CIX
        movzx   cx, byte [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, byte [bp-8]              ;CIX
        movzx   si, byte [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
; --------------------------------------

¿Problemas para entender la fuente? El ensamblador que utilicé:

  • considera etiquetas que comienzan con un punto ( . ) como etiquetas locales de 1er nivel
  • considera las etiquetas que comienzan con dos puntos ( : ) como etiquetas locales de segundo nivel
  • es Instrucción única de múltiples operandos (SIMO), por lo que push cx si se traduce como push cx push si.

Para conocer un procedimiento de entrada de muy alto rendimiento, consulte Entrada de formulario de edición enriquecida , una contribución de revisión de código.

Sep Roland avatar Dec 10 '2017 18:12 Sep Roland