4.4.1. Средства DOS
Как и в случае вывода на экран, DOS предоставляет набор функций для чтения данных с клавиатуры, которые используют стандартное устройство ввода
STDIN, так что в качестве источника данных можно применить файл или стандартный вывод другой программы.
Функция DOSOAh: Считать строку символов из STDIN в буфер
Вход: АН = OAh
DS:DX = адрес буфера
Выход: Буфер содержит введенную строку
Для вызова этой функции надо подготовить буфер, первый байт которого заключает в себе максимальное число символов для ввода а содержимое, если оно задано, может использоваться как подсказка для ввода. При наборе строки обрабатываются клавиши Esc, F3, F5, BS, Ctrl-C/Ctri-Break и т. д., как при наборе команд DOS (то есть Esc начинает ввод сначала, F3 восстанавливает подсказку для ввода, F5 запоминает текущую строку как подсказку, Backspace стирает предыдущий символ). После нажатия клавиши Enter строка (включая последний символ CR (ODh)) записывается в буфер, начиная с третьего байта. Во второй байт записывается длина реально введенной строки без учета последнего CR.
Рассмотрим пример программы, выполняющей преобразование десятичного
числа в шестнадцатеричное. ; dosin.1. asm
; Переводит десятичное число в шестнадцатеричное.
start:
asc2hex
.model |
tiny |
|
.code |
|
|
.286 |
; |
Для команды эЬг а1,4. |
org |
; |
Начало СОМ-файла. |
mov |
dx, offset messagel |
|
mov |
ah, 9 |
|
int |
21h ; |
Вывести приглашение ко вводу тезБадеі, |
mov |
dx, offset buffer |
|
mov |
ah.OAh |
|
int |
21h ; |
Считать строку символов в- буфер. |
mov |
dx, offset crlf |
|
mov |
ah, 9 |
|
int |
21h ; |
Перевод строки. |
од числа |
в ASCII-формате из |
буфера в бинарное число в АХ. . |
xor |
; |
БІ = 0 - номер байта в буфере. |
xor |
ax, ax ; |
АХ = 0 - текущее значение' результата. |
mov |
cl,blength |
|
xor |
ch, ch |
|
xor |
bx, bx |
|
mov |
; |
й - длина буфера |
mov |
; |
СІ. = 10/ множитель для МІІЬ |
mov |
bl.byte ptr bcontents[di] |
|
sub |
; |
Цифра = код цифры - код символа "0". |
Основы программирования для MS DOS
|
asc_error |
|
Если код символа был меньше, чем код "0", |
cmp |
bl,9 |
|
или больше, чем "9", |
ja |
asc_error |
|
выйти из программы с сообщением об ошибке. |
raul |
cx |
|
Иначе: умножить текущий результат на 10, |
add |
ax, bx |
|
добавить к нему новую цифру, |
inc |
di |
|
увеличить счетчик. |
cmp |
di.si |
і |
Если меньше числа символов - |
jb |
asc2hex |
|
продолжить (счетчик ведет отсчет от 0). |
на экран |
message2. |
|
|
push |
ax |
|
Сохранить результат преобразования. |
mov |
ah,9 |
|
|
mov |
dx, offset message2 |
|
|
int |
21h |
|
|
pop |
ax |
|
|
на экран |
числа из |
регистра |
АХ. |
push |
ax |
|
|
xchg |
ah,al |
; |
Поместить в АЬ старший байт. |
call |
print_al |
|
Вывести его на экран. |
pop |
ax |
|
Восстановить в АЬ младший байт. |
call |
print_al |
; |
Вывести его на экран. |
ret |
|
|
Завершение СОМ-файла. |
r: mov |
dx, offset |
errjnsg |
|
mov |
ah,9 |
|
|
int |
21h |
|
Вывести сообщение об ошибке |
ret |
|
|
и завершить программу. |
; Процедура рппс_а1.
; Выводит на экран число в регистре АЬ
; в шестнадцатеричном формате,
; модифицирует значения регистров АХ и БХ.
print_al:
mov
and
shr
call
mov
print_nibble:
cmp sbb
das dh.al
dh,0Fh
al,4
print.nibble al.dh
al, 10 al,69h
DH - младшие 4 бита.
AL - старшие.
Вывести старшую цифру.
Теперь AL содержит младшие 4 бита.
Процедура вывода 4 бит (шестнадцатеричной цифры).
Три команды, переводящие цифру в AL
в соответствующий ASCII-код.
(см. описание команды DAS)
mov mov int
ret dl.al ah,2 21h
Код символа в DL. Номер функции DOS в АН. Вывод символа.
Этот RET работает два раза - один раз для возврата из процедуры print_nibble,жтт
; вызванной для старшей цифры,
; и второй раз - для возврата из ргМ_а1.
messagel |
do |
"Десятичное число: $" |
message2 |
db |
"Шестнадцатеричное число: $" |
errjnsg |
db |
"Ошибка ввода" |
crlf |
(to |
Ойгі, 0АҐ1, '$' |
buffer |
db |
6 ; Максимальный размер буфера ввода. |
blength |
db |
? ; Размер буфера после считывания. |
bcontents: |
|
; Содержимое буфера располагается за |
; концом СОМ-файла.
end start
Функция OAh предоставляет удобный, но ограниченный способ ввода данных. Чаще -всего используют функции посимвольного ввода, позволяющие контролировать отображение символов на экране, реакцию программы на функциональные и управляющие клавиши и т. д.
Функция DOSOIh: Считать символ из STDIN с эхом, ожиданием и проверкой на Ctrl-Break Вход: АН = Olh
Выход: AL = ASCII-код символа или 0. Если AL = 0, второй вызов этой функции возвратит в AL расширенный ASCII-код символа.
При чтении с помощью этой функции введенный символ автоматически отображается на экране (посылается в устройство STDOUT - так что его можно перенаправить в файл). При нажатии Ctrl-C или Ctrl-Break выполняется команда INT 23h. Если нажата клавиша, не соответствующая какому-нибудь символу (стрелки, функциональные клавиши Ins, Del и т. д.), то в AL возвращается О и функцию надо вызвать еще один раз, чтобы получить расширенный ASCII-код (см. приложение 1).
В трех следующих вариантах этой функции код символа возвращается в AL по такому же принципу.
Функция DOS Считать символ из STDIN без эха, с ожиданием и проверкой
на Ctrl-Break
Вход: АН - 08h Выход: AL - код символа
Функция DOS Считать символ из STDIN без эха, с ожиданием и без проверки на Ctrl-Break
Вход: АН - 07h
Выход: = код символа
Функция DOS06h: Считать символ из STDIN без эха, без ожидания и без проверки на Ctrl-Break Вход: АН = 06h
= (ipph
Выход: Х¥ = 1, если не была нажата клавиша, и АЬ = 00
XV = 0, если клавиша была нажата. В этом случае АЬ :
код символа
Кроме перечисленных могут потребоваться и некоторые служебные функции DOS для работы с клавиатурой.
Функция DOSOBh: Проверить состояние клавиатуры Вход: АН = OBh
Выход: AL = 0, если не была нажата клавиша AL = OFFh, если была нажата клавиша
Данную функцию удобно использовать перед функциями 01, 07 и 08, чтобы не ждать нажатия клавиши. Кроме того, вызов указанной функции позволяет проверить, не считывая символ с клавиатуры, была ли нажата комбинация клавиш Ctrl-Break; если это произошло, выполнится прерывание 23h.
Функция DOS ОСЬ: Очистить буфер и считать символ Вход: АН = ОСЬ
AL = Номер функции DOS (01, 06, 07, 08, OAh) Выход: Зависит от вызванной функции
Функция ОСЬ очищает буфер клавиатуры, так что следующая функция чтения символа будет ждать ввода с клавиатуры, а не использовать нажатый ранее и еще не обработанный символ. Например, именно эта функция используется для считывания ответа на вопрос «Уверен ли пользователь в том, что он хочет отформатировать
Функции посимвольного ввода без эха можно использовать для интерактивного управления программой, как в следующем примере.
dosin2.asm
Изображает
управления курсором
line_length = 3 number of lines = 3
start:
F, которое можно перемещать по экрану клавишами и вращать клавишами X и Z. Выход из программы -
Esc.
Число символов в строке изображения. Число строк.
.model |
tiny |
|
. code |
|
|
org |
100h |
: Начало СОМ-файла. |
eld |
|
; Будут использоваться команды |
|
|
; строковой обработки. |
mov |
ax,0B800h |
; Адрес начала текстовой видеопамяти - |
mov |
es, ax' |
; в ES. |
mov - |
ax,0003h |
|
int |
10h |
; Текстовый режим 03 (80x25). |
mov |
ah,02h |
, ; Установить курсор |
mov |
,bh,0 |
|
mov |
dh,26 |
; на строку 26, то есть за пределы экрана. |
Ml
mov
int dl,l 10h
call update.screen
; Теперь курсора на экране нет.
; Вывести изображение.
Основной цикл опроса клавиатуры. main_lobp
p: mov |
ah,08h ; |
Считать символ с клавиатуры |
int |
21h |
; без эха, с ожиданием, с проверкой на Ctrl-Break. |
test |
al.al |
; Если AL = 0, |
jz |
eASCII_entered |
; введен символ расширенного ASCII. |
cmp |
al,1Bh |
; Иначе: если введен символ 1Bh (Esc), |
je |
key_ESC |
выйти из программы. |
cmp |
al, 'Z' |
Если введен символ Z, |
je |
key_Z |
перейти на его обработчик. |
cmp |
al,'z' |
; То же для г. |
je |
key_Z |
|
cmp |
al, 'X' |
Если введен символ X, |
je |
key_X |
перейти на его обработчик. |
cmp |
al,' x' |
; То же для х. |
je |
key_X |
|
jmp |
short maintop |
; Считать следующую клавишу. |
ntered: |
|
; Был введен расширенный ASCII-символ. |
int |
2lh |
; Получить его код (повторный вызов функции). |
cmp |
al,48h |
Стрелка вверх. |
je |
keyJJP |
|
cmp |
al,50h |
Стрелка вниз. |
je |
key_DOWN |
|
cmp |
al,4Bh |
Стрелка влево. |
je |
key_LEFT |
|
cmp |
al,4Dh |
Стрелка вправо. |
je |
key RIGHT |
|
jmp |
short main loop |
Считать следующую клавишу. |
; Обработчики нажатий клавиш.
key_ESC:
key_UP:
key_DOWM:
ret
cmp jna
dec call
jmp
cmp jnb
byte ptr mainJLoop
byte ptr start_row update_screen
short main loop
Esc
Завершить СОМ-программу.
Стрелка вверх.
Если изображение на верхнем
краю экрана,
считать следующую клавишу. Иначе - уменьшить номер строки,
вывести новое изображение
и считать следующую клавишу.
Стрелка вниз.
byte ptr start_row,25-number_of_lines ; Если
изображение на нижнем краю экрана, main_loop считать следующую клавишу.
inc
call jmp
key_LEFT:
cmp jna
dec
call jmp
key_RIGHT:
cmp
jnb
inc call
jmp
key^Z:
■ mov
dec
jns
mov
key_Z_ok:
key_X:
mov
call
jmp
inc
cmp jne xor
key_X_ok:
byte ptr start_row update screen short main_loop
byte ptr start_col,0 main_loop
byte ptr start_col update_screen
short
Иначе - увеличить номер строки, вывести новое изображение и считать следующую- клавишу.
Стрелка влево.
Если изображение на левом краю экрана, считать следующую клавишу. Иначе - уменьшить номер столбца,
вывести новое изображение
и считать следующую клавишу.
Стрелка вправо.
byte ptr start_col,80-line_length. ; Если
изображение на правом краю экрана, main_loop считать следующую клавишу.
byte ptr start_col Иначе - увеличить номер столбца,
update_screen
short
ax,current_screen
ax
key_Z_ok ax,3
current_screen,ax update_screen
main_loop
ax,current__screen
ax
ax,4
keyJ<_ok
ax,
ax
upclate.screen main_loop
mov
call
jmp
Процедура
; Очищает экран и выводит текущее ; Модифицирует значения регистров update_screen:
mov cx,25*80
mov
вывести новое изображение и считать следующую клавишу.
Клавиша Z (вращение влево). Считать номер текущего изображения (значения 0, 1, 2, 3), уменьшить его на 1. Если получился -1 (поменялся знак), АХ = 3.
Записать номер обратно,
вывести новое изображение
и считать следующую клавишу. Клавиша X (вращение вправо). Считать номер текущего
(значения 0, 1, 2, 3),
увеличить его на 1. Если номер стал равен
АХ = 0.
Записать номер обратно, вывести новое изображение
и считать следующую клавишу.
изображение.
АХ, ВХ, CX, DX, SI, DI.
xor rep
di,di
stosw
Число символов на экране.
Символ 20п (пробел) с атрибутом ОБЬ
(белый на черном).
Е5:Б1 = начало видеопамяти.
Очистить экран.
Ввод с
том |
bx,current_screen; |
Номер текущего изображения в ВХ. |
|
shl |
bx, 1 |
|
Умножить на 2, так как screens - массив |
mov |
si,screens[bx] ; |
Поместить в ВХ смещение начала |
|
|
|
|
текущего изображения из массива screens. |
mov |
ax,start_row ; |
Вычислить адрес начала |
|
mul |
row_length |
изображения в видеопамяти: |
|
add |
ax,start_col ; |
(строка x 80 + столбец) x 2. |
|
shl |
ax, I |
|
|
mov |
di, ax |
|
- начало изображения в видеопамяти. |
mov |
ah.OFh |
|
Используемый атрибут - белый на черном. |
mov |
dx, number_of_lines |
; Число строк в изображении. |
|
copy_lines: |
|
|
|
mov |
cx,line_length |
Число символов в строке. |
|
copy_1: lodsb |
|
|
Считать ASCII-код в AL, |
stosw |
|
|
записать его в видеопамять |
|
|
|
(AL - ASCII, АН - атрибут). |
loop |
copy_l |
|
Вывести так все символы в строке. |
add |
di, (80- |
-line_length) |
* 2 ; Перевести DI на начало |
|
|
|
следующей строки экрана. |
dec |
dx |
|
Если строки не закончились - |
jnz |
copy_lines |
вывести следующую. |
|
ret |
|
; |
Конец процедуры |
; Изображение |
F. |
|
|
screen1 |
db |
" XX" ; |
Выводимое изображение. |
|
db |
"XX ■■ |
|
|
db |
" x ■' |
|
screen2 |
db |
; |
Поворот на 90 градусов вправо. |
|
db |
"XXX" |
|
|
db |
|
|
screen3 |
db |
" X" ; |
Поворот на I80 градусов. |
|
db |
" XX" |
|
|
db |
"XX" |
|
screen4 d |
b |
"X " ; |
Поворот на 90 градусов влево. |
|
db |
"XXX" |
|
|
db |
" X " |
|
; Массив, содержащий адреса всех вариантов изображения. |
|||
screens |
dw |
sc screen2, screen4 |
|
current_screen |
dw |
0 |
Текущий вариант изображения. |
start_row |
dw |
10 ; |
Текущая верхняя строка изображения. |
start_col |
dw |
37 |
Текущий левый столбец. |
row_length |
db |
80 ; |
Длина строки экрана для команды МЦ1. |
end |
start |
|
|
слов.
В этом примере для вывода на экран используется прямое копирование в видеопамять, так как вызов функции BIOS вывода строки (INT 10h, АН - 13Ь>
ШННШ: Основы программирования для MS DOS
прокручивает экран вверх на одну строку при выводе символа в нижнем правом углу экрана.