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 enpush 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 enpush cx
push si
.