Техника
программирования на Turbo C
Глава 4
Автор: Ал. Стивенс
Функции
общего назначения
Эта книга посвящена программному обеспечению,
и следующие разделы содержат набор инструментальных программных средств,
которые могут быть использованы при создании прикладных систем. Эти
инструментальные средства написаны на языке Си, транслируются с помощью
компилятора Турбо Си и готовы к тому, чтобы быть включенными в ваши
программы. Эти функции могут рассматриваться как расширения языка Си,
если будут присоединены к и без того достаточно обширной библиотеке
стандартных расширений Турбо Си. Настоящий раздел описывает функции
первого уровня, которые необходимо включать в программы, использующие
эти библиотеки. Представленные в данном разделе функции являются функциями
общего назначения, выполняющими операции низкого уровня (специфическими
для аппаратуры IBM PC) по управлению дисплеем и клавиатурой. Вы можете
посчитать недостаточно обоснованным применение некоторых из этих функций
в своих программах. Назначением этих функций является поддержка функций
библиотеки высокого уровня, также рассматриваемых в этой книге. В этом
смысле они полезны, и вы можете найти для них применение. Кроме того,
глубина вашего понимания функций, представленных в книге, зависит от
осмысления вами всех функций, в том числе и тех, которые вы не будете
использовать в своих программах.
При чтении описаний этих функций обращайтесь
к листингу 4.1 программы ibmpc.c, который приводится после описаний.
void clear_screen()
Эта функция очищает экран и устанавливает
курсор в левый верхний угол. Экран заполняется символами пробела, и
атрибуты символов извлекаются из символьной переменной attrib, описанной
в программе ibmpc.c. Значение этого атрибута соответствует байту атрибута
в видеопамяти, сопутствующему каждому байту ASCII-кода при записи символа
в видеопамять. Более подробная информация по этому вопросу содержится
в разделе 5. Переменная attrib принимает значение, которое соответствует
установке черного цвета для фона символа и белого цвета для самого символа.
Если вы желаете другое значение атрибута, то должны изменить значение
этой переменной перед вызовом функции clear_screen.
int vmode()
Эта функция возвращает код текущего режима
системы формирования изображения. Она прeжде всего предназначена для
определения того, как программе интерпретировать содержимое видеопамяти:
как содержимое видеопамяти в монохромном режиме или в алфавитно-цифровом
режиме для Цветного Графического Адаптера (CGA) и для Усовершенствованного
Графического Адаптера (EGA). Эти устройства более подробно рассматриваются
в разделе 5. Функция vmode возвращает код 7, если IBM PC работает в
монохромном режиме. Любое другое значение обозначает алфавитно-цифровой
режим для контроллеров CGA и EGA.
void cursor(int x,int y)
Эта функция устанавливает курсор в позицию
на экране, определяемую координатами X и Y. Координаты (0,0) соответствуют
левому верхнему углу экрана. Значение координаты X изменяется в диапазоне
от 0 до 79, а координаты Y - в диапазоне от 0 до 24.
void curr_cursor(int *x, int *y)
Эта функция считывает текущее положение
курсора и записывает значения координат X и Y в адреса памяти, определяемые
с помощью указателей перед обращением к функции.
int set_cursor_type(int t)
Эта функция устанавливает текущий размер
курсора, интерпретируемый программами из этой книги как тип курсора.
Размер обозначается целочисленной переменной, которая содержит в старшем
байте номер начальной растровой линии курсора и в младшем байте - номер
конечной растровой линии курсора.
Редактор текстов и программа ввода данных,
представленные в следующих разделах, используют возможность изменения
размера курсора для обозначения того, какой из режимов установлен: Вставки
или Замены. Курсор прямоугольной формы обозначает, что установлен режим
Вставки, он определяется значением переменной, равным 0x0106. При этом
курсор занимает растровые линии с 1 по 6 того знакоместа, в котором
он находится. Курсор в виде знака подчеркивания обозначает режим Замены
и определяется значением переменной, равным 0x0607. При этом курсор
занимает растровые линии 6 и 7 знакоместа.
int get_char()
Эта функция является очень важной, так
как выполняет несколько крайне необходимых действий в вызывающих ее
программах. get_char принимает поступающий от клавиатуры символ путем
использования программ ROM-BIOS IBM PC. Ее главное назначение состоит
в приеме одиночного символа от клавиатуры без эха, без преобразования
и без обращения к функциям DOS. Кроме того, она выполняет следующие
дополнительные функции.В то время, как система ожидает нажатия клавиши,
функция get _char вызывает программные прерывания по вектору 0x28, так
называемые прерывания DOSOK. Это прерывание и его значение для создания
резидентных утилит более подробно рассматриваются в разделе 11.
Когда вы нажимаете функциональную клавишу,
ROM BIOS возвращает двубайтный код. Первый байт имеет нулевое значение
и обозначает, что следующий за ним код символа соответствует функциональной
клавише. Этот второй байт содержит 7-битный ASCII- код, который является
уникальным для каждой функциональной клавиши. Eсли не учитывать первый
нулевой байт, то реакция на нажатие функциональных клавиш сходна с реакцией
на нажатие клавиш, соответствующих ASCII-символам, в частности, буквам.
Функция get_char преобразует двубайтную последовательность, возвращаемую
ROM-BIOS в ответ на нажатие функциональной клавиши, в 8-битный код,
позволяющий отличать функциональные клавиши от нефункциональных. Функция
осуществляет это преобразование путем установки старшего разряда в байте,
содержащем АSCII-код символа и следующем за нулевым байтом. Формируемые
коды описыватся в исходном файле keys.h как глобальные символы (см.
листинг 4.2).
Функция get_char oжидает нажатия функциональной
клавиши, обозначенной Help. Код, соответствующий функциональной клавише
Help, присвоен целочисленной глобальной переменной, названной helpkey.
Первоначально этой переменной присваивается нулевое значение, но программные
средства, которые работают с окном Help, предназначенным для отображения
справочной информациии, будут присваивать этой переменной значение,
соответствующее функциональной клавише. При нажатии функциональной клавиши
Help функция get_char проверяет значение глобального указателя функций,
названного helpfunc. Если указатель имеет ненулевое значение, то функция
get_char вызывает адресуемую с помощью указателя helpfunc функцию выдачи
справочной информации.
void vpoke(unsigned vseg,unsigned adr,unsigned
chr) int
vpeek (unsigned vseg,unsigned adr)
Эти две функции считывают из видеопамяти
коды символов и атрибуты символов и записывают их в видеопамять. Для
того, чтобы использовать эти функции, вы должны разобраться в организации
видеопамяти IBM PC, а также принципах формирования изображения. В тело
функций vpoke и vpeek включены фрагменты на ассемблере. Для того, чтобы
оттранслировать эти функции, вы должны иметь программу Macro Assembler
(MASM) фирмы Microsoft, поскольку именно она используется в Турбо Си
для трансляции ассемблерных фрагментов. Включение ассемблерных фрагментов
необходимо только в том случае, если ваши программы работают в системах,
использущих Цветной Графический Адаптер (CGA) или совместимый с ним
адаптер. Смысл этого требования разъясняется в разделе 5. Если у вас
нет контроллера CGA или если вы хотите работать с функциями, не используя
ассемблер, то удалите эти функции из исходного модуля ibmpc.c и вставьте
в файл twindow.h из раздела 6 следующие операторы:
#define vpoke(vseg,adr,chr)
poke(vseg,adr,chr)
#define vpeek(vseg,adr) peek(vseg,adr)
Эти макроопределения заменят функции
vpoke и vpeek и избавят от необходимости использования макроассемблера
для функций работы с окнами из этой книги.
Исходные модули функций
общего назначения
Листинг 4.1 представляет собой исходный
текст программы ibmpc.c, которая содержит функции, описанные в данном
разделе. Вследствие того, что функции включают фрагменты на ассемблере,
программу лучше транслировать с помощью командного компилятора tcc,
а не компилятора tc Интегрированной Среды.Чтобы оттранслировать файл
ibmpc.c, введите следующую команду (не набирая промптер С>):
С>tcc -c ibmpc
Листинг 4.1: ibmpc.c
#pragma inline #include <dos.h>
static union REGS rg;
void cursor(int x,int
y) {
rg.x.ax = 0x0200;
rg.x.bx = 0;
rg.x.dx = ((y << 8) & 0xff00) + x;
int86( 16, &rg, &rg);
}
void curr_cursor( int *x, int *y )
{
rg.x.ax = 0x0300;
rg.x.bx = 0;
int86( 16, &rg, &rg );
*x = rg.h.dl;
*y = rg.h.dh;
}
void set_cursor_type( int t )
{
rg.x.ax = 0x0100;
rg.x.bx = 0;
rg.x.cx = t;
int86( 16, &rg, &rg );
}
char attrib = 7;
void clear_screen()
{
cursor(0, 0);
rg.h.al = ' ';
rg.h.ah = 9;
rg.x.bx = attrib;
rg.x.cx = 2000;
int86( 16, &rg, &rg );
}
int vmode()
{
rg.h.ah = 15;
int86( 16, &rg, &rg);
return rg.h.al;
}
int scroll_lock()
{
rg.x.ax = 0x0200;
int86( 0x16, &rg, &rg);
return rg.h.al & 0x10;
}
void (* helpfunc)();
int helpkey = 0;
int helping = 0;
int get_char()
{
int c;
while (1) {
rg.h.ah = 1;
int86(0x16, &rg, &rg);
if (rg.x.flags & 0x40) {
int86(0x28, &rg, &rg);
continue;
}
rg.h.ah = 0;
int86(0x16, &rg, &rg);
if (rg.h.al == 0)
c = rg.h.ah | 128;
else
c = rg.h.al;
if (c == helpkey && helpfunc) {
if (!helping) {
helping = 1;
(*helpfunc)();
helping = 0;
continue;
}
}
break;
}
return c;
}
void vroke(unsigned
vseg, unsigned adr, unsigned chr)
{
if (vseg == 45056)
poke(vseg, adr, chr);
else {
_DI = adr;
_ES = vseg;
asm cld;
_BX = chr;
_DX = 986;
do
asm in al,dx;
while (_AL & 1);
do
asm in al,dx;
while (!(_AL & 1));
_AL = _BL;
asm stosb;
do
asm in al,dx;
while (_AL & 1);
do
asm in al,dx;
while (!(_AL & 1));
_AL = _BL;
asm stosb;
}
}
int vpeek(unsigned
vseg, unsigned adr)
{
int ch, at;
if (vseg == 45056)
return peek(vseg, adr);
asm push ds;
_DX = 986;
_DS = vseg;
_SI = adr;
asm cld;
do
asm in al,dx;
while (_AL & 1);
do
asm in al,dx;
while (!(_AL & 1));
asm lodsb; /* считать символ */
_BL = _AL;
do
asm in al,dx;
while (_AL & 1);
do
asm in al,dx;
while (!(_AL & 1));
asm lodsb;
_BH = _AL;
_AX = _BX;
asm pop ds;
return _AX;
}
#define HT 9
#define RUBOUT 8
#define BELL 7
#define ESC 27
#define SHIFT_HT 143
#define CTRL_T 20
#define CTRL_B 2
#define CTRL_D 4
#define ALT_D 160
#define F1 187
#define F2 188
#define F3 189
#define F4 190
#define F5 191
#define F6 192
#define F7 193
#define F8 194
#define F9 195
#define F10 196
#define HOME 199
#define UP 200
#define PGUP 201
#define BS 203
#define FWD 205
#define END 207
#define DN 208
#define PGDN 209
#define INS 210
#define DEL 211
#define CTRL_HOME 247
#define CTRL_BS 243
#define CTRL_FWD 244
#define CTRL_END 245
Заключение
На основе представленных выше функций
нижнего уровня в разделе 5 будет развиваться и объясняться концепция
экранных окон, которая составляет следующий, более высокий, уровень
в многоуровневом наборе функций, описываемых в данной книге.
|