assembly input dos x86-16

assembly - Cómo funciona la entrada almacenada



input dos (2)

La entrada en el siguiente programa funciona bien, pero cuando solicito 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 : '', ''$'' ; --------------------------------------


Ingresando texto usando int 21h AH=08h

Los tres métodos de entrada descritos hasta ahora (¡en la respuesta anterior!) Fueron diseñados específicamente para adaptarse a herramientas de Microsoft como EDLIN.EXE y COMMAND.COM.
Si está escribiendo su propia aplicación, entonces se pueden lograr mejores resultados al producir su propio procedimiento de entrada. En el corazón de tal procedimiento estará una de las funciones de entrada de caracteres únicos de DOS. Elegí la función de entrada STDIN 08h porque quiero permitir la comprobación de ctrl C / ctrl Break y tengo la intención de hacerme eco de los caracteres a través de BIOS Int 10h AH=09h Escribir carácter y atributo en la posición del cursor . De esta forma 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 en el teclado, la entrada será mucho más fácil ya que todas las teclas asociadas con la edición de plantilla antigua y difícil se han descartado y reemplazado por las teclas de edición habituales que le permiten mover libremente el cursor.

  • Izquierda Mueve el cursor hacia la izquierda.
  • Derecha Mueve el cursor hacia la derecha.
  • Inicio Mueve el cursor hacia el extremo izquierdo.
  • Fin Mueve el cursor hacia el extremo derecho.
  • Ctrl Inicio Elimina todos los caracteres a la izquierda.
  • Ctrl Fin Elimina todos los caracteres a la derecha.
  • Eliminar Elimina el carácter actual.
  • Retroceso Elimina el carácter a la izquierda del cursor.
  • Escape Elimina todos los personajes.
  • Regreso Finaliza la entrada.

Si el segundo byte del búfer de entrada contiene un valor distinto de cero, 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. Diferente de DOS es que:

  • no se requiere que la cadena anterior sea terminada por retorno de carro.
  • la cadena anterior se muestra inmediatamente en la pantalla.

Mientras la entrada está en progreso, 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 la expansión de pestañas (en la pantalla, el espacio de almacenamiento siempre tendrá ASCII 9) y ya no se limitará a una sola fila.

Este procedimiento hace ctrl C / ctrl Comprobación de interrupción .

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

Este procedimiento fue escrito con la redirección de entrada y la redirección de salida en mente, y por lo tanto, 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 a 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 tamponada 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, [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 ; --------------------------------------

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

  • considera las etiquetas que comienzan con un punto ( . ) como etiquetas locales de primer nivel
  • considera las etiquetas que comienzan con dos puntos (:) como etiquetas locales de segundo nivel
  • es Single Operaction Multiple Operands (SIMO), por lo que push cx si traduce en push cx push si .

Para un procedimiento de entrada de alto rendimiento, mire la entrada de formulario de edición enriquecida , una contribución de revisión de código.


Al observar cómo definió su búfer de entrada ( buf: db 20 dup (''$'') ), entiendo que desea cortar esquinas y tener la entrada ya 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 un posible desbordamiento del búfer.
Además, el uso de $ -terminación no es la opción más brillante 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 usarán terminación cero.

Ingresando texto usando int 21h AH=0Ah

Esta función de entrada STDIN tamponada obtiene caracteres del teclado y continúa haciéndolo hasta que el usuario presiona la tecla Intro . 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 suministrado por el programa de llamada a través del 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 de llamadas decirle a DOS qué tan grande es el espacio de almacenamiento. Por lo tanto, debe 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, configure el tamaño de almacenamiento en 255.
Si no desea poder recuperar de la plantilla ninguna entrada anterior, entonces es mejor también poner a cero 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 está disponible.

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

  • Escape Elimina 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.
  • Retroceso Elimina el último carácter de la entrada actual.
    Funciona como se espera si la entrada permanece dentro de una sola fila en la pantalla. Si, por otro lado, la entrada abarca varias filas, entonces este retroceso se detendrá en el borde izquierdo de la pantalla. ¡A partir de entonces habrá una gran discrepancia entre la entrada lógica y la entrada visual porque el retroceso lógico continuará hasta que se alcance la primera posición en el espacio de almacenamiento!
  • F6 Inserta un carácter de fin de archivo (1Ah) en la entrada actual.
    La pantalla mostrará "^ Z".
  • F7 Inserta un byte cero en la entrada actual.
    La pantalla mostrará "^ @".
  • ctrl Ingrese Transiciones a la siguiente fila (ejecutando un retorno de carro y salto de línea), no se agrega nada a la entrada actual y no puede regresar.

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

  • F1 Copia 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.
  • F3 Copia todos los caracteres restantes en la plantilla a la nueva línea.
  • F4 + ... Salta los caracteres de la plantilla, hasta el carácter especificado.
  • F5 Convierte la nueva línea en la nueva plantilla.
  • Escape Borra la entrada actual y deja la plantilla sin cambios.
  • Eliminar Omite un carácter en la plantilla.
  • Insertar Ingresa o sale del modo de inserción.
  • Retroceso Elimina el último carácter de la nueva línea y coloca el cursor hacia atrás un carácter en la plantilla.
  • Izquierda Igual que Retroceso.
  • Correcto Igual que F1.

Las pestañas se expanden con esta función. La expansión de tabulación 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 un múltiplo de 8.
La expansión de esta pestaña solo ocurre en la pantalla. El espacio de almacenamiento contendrá ASCII 9.

Esta función hace ctrl C / ctrl Comprobación de interrupción .

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

Ejemplo 1, entrada STDIN tamponada.

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

Ingresando texto usando int 21h AH=3Fh

Cuando se usa con el controlador 0 predefinido (en BX ), esta función Leer del 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. Esto ahora se convierte en la nueva plantilla.
En adelante, la función escribirá en el búfer proporcionado en DS:DX , la cantidad de bytes que se solicitaron en el parámetro CX . Si CX especificó un número que es 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 recoger, esta función no iniciará otra sesión de entrada usando el teclado! Esto es incluso cierto entre diferentes programas o sesiones del mismo programa.

Todas las teclas de edición descritas en la sección anterior están disponibles.

Las pestañas se expanden solo en la pantalla, no en la plantilla.

Esta función hace ctrl C / ctrl Comprobación de interrupción .

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

  • fila actual si el salto de línea de finalización no estaba entre los bytes devueltos.
  • siguiente fila si el salto de línea de terminación estaba entre los bytes devueltos.

Ejemplo 2a, Leer desde archivo o dispositivo, recoger todo de una 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, Leer desde archivo o dispositivo, tome 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 usando int 2Fh AX=4810h

Esta función de entrada STDIN con búfer de DOSKEY solo se puede invocar si se instaló el TSR de DOSKEY.COM . Funciona de manera muy similar a la función de entrada STDIN con búfer normal 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.

  • Arriba Obtiene el elemento anterior del historial.
  • Abajo Obtiene el siguiente elemento del historial.
  • F7 Muestra una lista de todos los elementos en el historial.
  • Alt F7 Borra la historia.
  • ... F8 Encuentra elementos que comienzan con ...
  • F9 Selecciona un elemento del historial por número.
  • Alt F10 Elimina 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 que siempre debe establecer 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 como doskey /line:255 . Es posible precargar el espacio de almacenamiento con una plantilla. Esto acerca la versión de Win95 a lo que es factible con la función de entrada 0Ah.

Esta función hace ctrl C / ctrl Comprobación de interrupción .

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 se expandió. ¡No puedes ver la línea no expandida! Se necesita 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 comandos múltiples ( $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.

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

Ejemplo 3, Invocación de 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 ; --------------------------------------

Ingresando texto usando int 21h AH=08h

Debido al límite de 30000 bytes que impone, el texto continúa en la respuesta a continuación ...

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

  • considera las etiquetas que comienzan con un punto ( . ) como etiquetas locales de primer nivel
  • considera las etiquetas que comienzan con dos puntos (:) como etiquetas locales de segundo nivel
  • es Single Operaction Multiple Operands (SIMO), por lo que push cx si traduce en push cx push si .