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

прокручивает экран вверх на одну строку при выводе символа в нижнем правом углу экрана.