static vswap(WINDOW *wnd)
{
int x, y, chat;
int *bf = (int *) SAV;
for (y = 0; y < HEIGHT; y++)
for (x = 0; x < WIDTH; x++) {
chat = *bf;
*bf++ = dget(wnd, x, y);
displ(wnd, x, y, chat&255, (chat>>8)&255);
}
}
#else
/* сохраняет видеопамять в буфере сохранения */
static vsave(WINDOW *wnd)
{
int x, y;
int *bf = (int *) SAV;
for (y = 0; y < HEIGHT; y++)
for (x = 0; x < WIDTH; x++)
*bf++ = vpeek(VSG, vad(x+COL, y+ROW));
}
/* восстанавливает видеопамять из буфера сохранения */
static vrstr(WINDOW *wnd)
{
int x, y;
int *bf = (int *) SAV;
for (y = 0; y < HEIGHT; y++)
for (x = 0; x < WIDTH; x++)
vpoke(VSG,vad(x+COL, y+ROW), *bf++);
}
#endif
/* заменяет яркость строки, указываемой SELECT */
void acline(WINDOW *wnd, int set)
{
int x, ch;
if (!verify_wnd(&wnd))
return;
for (x = 1; x < WIDTH - 1; x++) {
ch = dget(wnd, x, SELECT) & 255;
displ(wnd, x, SELECT, ch, set);
}
}
/* ФУНКЦИИ ОБРАБОТКИ СПИСКА */
/* добавляет окно в конец списка */
static add_list(WINDOW *wnd)
{
if (listtail) {
PREV = listtail;
listtail->_nx = wnd;
}
listtail = wnd;
if (!listhead)
listhead = wnd;
}
/* добавляет окно в начало списка */
static beg_list(WINDOW *wnd)
{
if (listhead) {
NEXT = listhead;
listhead->_pv = wnd;
}
listhead = wnd;
if (!listtail)
listtail = wnd;
}
/* удаляет окно из списка */
static remove_list(WINDOW *wnd)
{
if (NEXT)
NEXT->_pv = PREV;
if (PREV)
PREV->_nx = NEXT;
if (listhead == wnd)
listhead = NEXT;
if (listtail == wnd)
listtail = PREV;
NEXT = PREV = NULL;
}
/* вставляет w 1 после w 2 */
static insert_list(WINDOW *w1, WINDOW *w2)
{
w1->_pv = w2;
w1->_nx = w2->_nx;
w2->_nx = w1;
if (w1->_nx == NULL)
listtail = w1;
else
w1->_nx->_pv = w1;
}
#ifndef FASTWINDOWS
/* проверяет наличие окна в списке */
static verify_wnd(WINDOW **w1)
{
WINDOW *wnd;
wnd = listhead;
if (*w1 == NULL)
*w1 = listtail;
else {
while (wnd != NULL) {
if (*w1 == wnd)
break;
wnd = NEXT;
}
}
return wnd != NULL;
}
#endif
WINDOW *ewnd = NULL;
/* сообщение об ошибках */
void error_message(char *s)
{
ewnd = establish_window(50, 22, 3, max(10, strlen(s)+2));
set_colors(ewnd, ALL, RED, YELLOW, BRIGHT);
set_title(ewnd, " ERROR! ");
display_window(ewnd);
wprintf(ewnd, s);
putchar(BELL);
}
void clear_message()
{
if (ewnd)
delete_window(ewnd);
ewnd = NULL;
}
Описание программы: twindow.c
-----------------------------
Далее описывается исходная программа twindow.c. Для каждой
функции описывается, что она делает и как работает. Программист
может использовать эти описания для понимания текста программы.
Объявления внешних данных в twindow.c включают прототипы для
каждой функции, локальные в исходном файле, массив структур для
определения пяти типов рамки окна, головной и хвостовой указатели
для списка структур WINDOW.
Рамка окна управляется элементом структуры WINDOW, которая
устанавливает окно. Этот элемент является целочисленным смещением
в таблице типов рамки. Вход, на который указывает смещение,
содержит шесть значений, каждое из которых представляет одну из
сторон или узлов окна. Первое значение определяет верхний левый
или северо-западный угол. Имя переменной (nw, ne, se, sw)
сообщает вам, какой угол определяется. Целое число side
относится к вертикальным сторонам рамки; целое число line
соответствует верхней и нижней горизонтальным линиям рамки.
Значения относятся к символам из набора графических символов
ПЭВМ.
Две WINDOW-ссылки listhead и listtail являются головным и
хвостовым указателями для списка окон. Когда создаются окна, они
добавляются к этому списку. Первоначально эти два указателя равны
NULL. Когда создается первое окно, выделяется память для
структуры WINDOW, и ее адрес копируется в оба указателя. У списка
имеется голова, указывающая на первое окно списка, и хвост,
указывающий на последнее. Когда создается второе окно, его адрес
копируется в хвостовой указатель. Кроме того, адрес второго окна
записывается в указатель _nx в первой структуре WINDOW, а адрес
первой записывается в указатель _pv второй. Голова списка
указывает на первое окно, которое указывает на второе и т.д.
Хвост списка указывает на последнее окно. Каждое окно также
указывает на своего предшественника в цепи, следовательно, список
является двунаправленной структурой данных, называемой двусвязным
списком. (Для знакомства со списковыми структурами данных см.:
Brady. С Development Tools for the IBM PC. - 1986.).
Функция establish_window инициализирует переменную VSG
адресом сегмента видеопамяти. Функция распределяет память для
структуры WINDOW и инициализирует эту структуру оконными
характеристиками, принимаемыми по умолчанию, а также размером и
координатами, заданными при вызове функции. Она выделяет память
для буфера сохранения видеопамяти и записывает адрес буфера в
структуру WINDOW. После инициализации структуры функция вызывает
add_list для добавления структуры к списку окон. Текстовая
область окна очищается, и образ окна выделяется, если
обрабатываются слоеные окна. Эти функции оперируют в буфере
сохранения, поэтому окно пока не изображается. Функция establish_
window возвращает адрес структуры WINDOW в точку вызова.
Функции set_border, set_colors, set_intensity и set_title
модифицируют характеристики созданного окна. Сначала они вызывают
verify_wnd для проверки того, что при вызове передан адрес
созданного окна. Затем они модифицируют заданный атрибут. В конце
они вызывают функцию redraw для записи изменений на экран.
Функция redraw перевыдает окно, если обрабатываются слоеные
окна.
Функция display_window оперирует по-разному для стековых и
слоеных окон. В любом случае она ничего не делает, если окно
является видимым для пользователя. Если окно невидимо, то путем
вызова функции vswap display_window замещает видеопамять
буфером сохранения, если действуют слоеные окна. Для стековых
окон делается проверка, не скрыто ли окно. Если окно скрыто, то
оконный буфер сохранения записывается в видеопамять вызовом
vrstr. Если окно не скрыто, то оно никогда не выдается, поэтому
вызывается vsave для сохранения текущего содержимого
видеопамяти, a clear_window и wframe вызываются для выдачи
пустого окна.
Функция close_all уничтожает все окна путем прохода по
списку структур WINDOW и вызова delete_window.
Функция delete_window удаляет окно из системы путем его
скрытия, освобождения памяти, занятой буфером сохранения,
удаления структуры WINDOW из списка и освобождения памяти,
содержащей структуру WINDOW.
Функция hide_window вызывает vswap для замены буфера
сохранения видеопамятью для слоеного окна и вызова vrstr для
восстановления видеопамяти для стекового окна.
Функция repos_window имеется только для слоеных окон. Она
вызывается одним из макросов move_window, rmove_window,
rear_window и forefront. Она изменяет положение окна путем
создания временного окна, помещая временное окно в список в
соответствии с информацией, полученной из макроса, записывая
оригинальное содержимое окна в буфер сохранения временного окна,
выдавая временное окно и скрывая оригинал.
Crear_window записывает пробелы в область данных окна, а
wframe и dtitle изображают окно с заголовком наверху. Эти функции
используют функцию displ для записи значений в окно.
Функция wprintf является примером нового предполагаемого
стандарта ANSI для функций с переменным числом параметров. В
прошлом большинство компиляторов обрабатывали printf на
ассемблере для просмотра переменного числа параметров из стека.
Предполагаемый стандарт использует многоточие (...) в списке
параметров функции для указания присутствия переменного числа
параметров с различными типами данных. Специальный тип массива
va_list используется для объявления списка, а va_start
устанавливает начало и конец списка. Функция vsprintf является
версией sprintf, которая допускает параметр va_list. В данном
случае параметры, передаваемые в wprintf,
перерабатываются vsprintf в строку с именем dlin. Затем строка
выдается в окно по одному символу за раз путем вызова wputchar.
Если у вас получится вызов wprintf, который образует строку
более 100 символов, придется увеличить длину массива dlin.
Функция wputchar выдает символ в окно в текущей позиции
курсора. Расположение оконного курсора является функцией двух
элементов структуры WINDOW, которые указываются макросами WCURS
(столбец) и SCROLL (строка). Функция реагирует на символы
новой строки (\n) и табуляции (\t) следующим образом. Для новой
строки, если переменная SCROLL соответствует низу окна,
содержимое окна проворачивается вверх на одну строку; иначе
значение переменной SCROLL увеличивается. В любом случае
переменная WCURS устанавливается на столбец 0. Если в
wputchar послан символ табуляции, переменная WCURS
продвигается к следующей позиции табуляции в окне. Остальные
символы отображаются в окне, а переменная WCURS возрастает.
Строки, длина которых превышает ширину окна, не переносятся;
они обрезаются.
Функция wcursor устанавливает переменные WCURS и SCROLL на
координаты, заданные при вызове. Она также устанавливает
видеокурсор на экранную позицию, соответствующую оконному
курсору.
Функция get_selection создает блок курсора в окне и
позволяет пользователю перемещать блок вверх и вниз, а также
производить выбор нажатием клавиши <Ввод>. Макроопределение
SELECT ссылается на переменную в структуре WINDOW и используется
для перемещения блока курсора в окне. Функции accent и deaccent
используются для включения и выключения блока курсора путем
изменения видеоатрибута строки на ACCENT и NORMAL. При нажатии
верхней и нижней клавиш со стрелками функция изменяет значение
переменной SELECT. При вызове можно также передать адрес массива
символов, содержащего список клавиш, используемых для выбора из
окна. Если пользователь нажимает одну из этих клавиш,
производится соответствующий выбор так же, как если бы блок
курсора находился в соответствующей строке и была нажата клавиша
<Ввод>.
Функция scroll проворачивает порцию текста в окне вверх или
вниз на одну строку. Если окно является последним и видимым,
функция прокрутки ROM-BIOS применяется для ускорения по сравнению
с программной прокруткой. Функция ROM-BIOS не применяется, если
окно имеет только одну строку текста из-за ошибки в IBM PC и
некоторых моделях АТ. Эта ошибка вызывает появление неверных
видеорезультатов при попытке провернуть единственную строку.
Ошибка была устранена IBM в АТ BIOS, но в некоторых моделях она
осталась. Если окно не является последним или если оно имеет одну
строку текста, текстовая область проворачивается программно с
помощью функций dget и displ для чтения и записи символов текста
из окна и в окно.
Функция waddr оперирует только со слоеными окнами. Она