же текст, что и в предыдущем случае - тем самым опрос достигнут. Вот
текст программы:
1 #include
2 #include
4 struct termio tsav, tchg;
6 main (argc, argv)
7 {
8 int c;
10 /* change the terminal based on file primitives */
изменить режим терминала с помощью файловых примитивов
11 close(0);
12 if (open("/dev/tty",O_RDWR|O_NDELAY) == -1) {
13 perror("can't open tty");
невозможно открыть tty
14 exit(1);
15 }
17 /* change the terminal based on line disciplines */
изменить режим терминала с помощью протокола работы
18 if (ioctl (0, TCGETA, &tsav) == -1) {
19 perror("can't get original settings");
невозможно получить исходные установки
20 exit(2);
21 }
23 tchg = tsav;
25 tchg.c_lflag &= ~(ICANON | ECHO);
26 tchg.c_cc[VMIN] = 1;
27 tchg.c_cc[VTIME] = 0;
29 if (ioctl (0, TCSETA, &tchg) == -1) {
30 perror(can't initiate new settings");
невозможно задать новые установки
31 }
33 while (1)
34 {
35 putchar('.');
36 c = getchar();
38 if (c == 'x')
39 break;
41 putchar(c);
42 }
44 if (ioctl(0, TCSETA, &tsav) == -1) {
45 perror("can't reset original settings");
невозможно вернуть исходные установки
46 exit(3);
47 }
48 }
Основное изменение производится в строках 11-15. Закрытие файла с
нулевым дескриптором (который обозначает стандартное устройство ввода)
закрывает стандартный ввод. Затем мы снова открываем файл /dev/tty.
Значение дескриптора файла равно нулю, так что мы переназначили стан-
дартный ввод на новое устройство. Фокус в том, что при открытии файла
используется режим, называемый NODELAY. Это означает, что когда выпол-
няется чтение по данному дескриптору файла (т.е. чтение стандартного
ввода), вместо ожидания ввода выполняется просмотр, есть ли там
что-нибудь, а затем работа продолжается.
В бесконечном цикле строка 35 печатает точку. Когда вы запускаете
эту программу, на экран выводится точка, как только программа попадает
в цикл. Если вы ждете, то продолжают выводиться точки. Как только вы
нажмете клавишу, выполнится эхо-отображение символа в промежутке между
выводом точек. Это демонстрирует, что программа работает в то время,
когда вы ничего не делаете.
ВОЗМОЖНОСТИ ТЕРМИНАЛОВ
Теперь, когда мы имеем понятие о характеристиках терминальных ин-
терфейсов, давайте перейдем к возможностям терминалов. ВОЗМОЖНОСТИ -
это те функции, которые выполняет аппаратура терминала. Если мы знаем
эту информацию, мы можем создать список возможных функций и использо-
вать его, например, для работы редактора vi. Это осуществляется при
помощи специального файла данных termcap (terminal capabilities - воз-
можности терминала), который описывает возможности терминала.
Большинство из существующих типов терминалов уже занесены в файл
termcap. Это файл /etc/termcap. Файл termcap и редактор vi происходят
из системы Berkeley. Такая комбинация оказалась настолько эффективной,
что была перенесена в System V. В более поздней System V Release 3
файл termcap уже не используется, его заменяет файл terminfo фирмы
AT&T. Мы применяли файл terminfo совместно с командным файлом today в
главе 5, но подробное обсуждение terminfo выходит за пределы нашей
книги. В системе Berkeley файл termcap по-прежнему остается стандар-
том, и он заслуживает более детального рассмотрения.
Имеется документация по termcap, но не думайте, что вы из нее
много узнаете. В документации приводятся имена и однострочные описания
поддерживаемых функций, но нет информации о том, как формировать из
ничего записи этого файла. Самое лучшее, что мы можем посоветовать,
это взять имеющуюся запись и изменить ее.
В качестве примера мы приводим запись файла termcap для компьюте-
ра Apple II. Это описание распространено в различных формах, но наш
пример относится к видеоплате Videx UltraTerm для Apple II+. Заметим,
что возможности, предоставляемые файлом termcap, являются обычно подм-
ножеством тех возможностей, которые фактически предоставляет аппарату-
ра. В частности, видеоплата в компьютере Apple выполняет некоторые
функции, которые не умеет делать файл termcap, например комбинации
настроечных битов для изменения видеоатрибутов. Самое большее, что мы
можем сделать с видеоатрибутами посредством файла termcap, это вклю-
чить или выключить инверсное отображение.
С другой стороны, некоторые типы аппаратуры не обладают всеми
возможностями, обеспечиваемыми файлом termcap. Например, одной из
функций, которой недостает в Apple, является функция прокрутки
("scroll reverse"). Аппаратура не делает этого, поэтому и в termcap
нет необходимости иметь описание этой функции. Вместо скроллинга
(прокрутки) вниз, отображаемый на экране текст продолжает выводиться в
верхней строке.
Для того, чтобы получить представление о том, как termcap соот-
носит общие характеристики терминала с конкретными возможностями,
сравним терминалы Apple и vt52. Две соответствующие записи в termcap
имеют много похожих функций, но совершенно разные коды для их выполне-
ния. Приведем пример содержимого файла termcap:
a2|aii|Apple II with UltraTerm :\
:bl=^G:\
:bs:\
:cd=^K:\
:ce=^]:\
:cl=^L:\
:cm=^^%r%+ %+ :\
:co#80:\
:cr=^M:\
:do=^J:\
:ho=^Y:\
:kb=^H:\
:kd=^J:\
:kl=^H:\
:kr=^\\:\
:ku=^_:\
:le=^H:\
:li#24:\
:nd=^\\:\
:nl=^J:\
:se=^O:\
:so=^N:\
:up=^_:
В табл. 7-1 представлен список функций файла termcap с сопостав-
лением терминалов Apple и vt52. Если какая-либо функция отсутствует у
одного или другого терминала, это отмечается словом "нет".
Таблица 7-1
Терминальные возможности и их конкретные значения
---------------------------------------------------------------------------
Функция Apple II vt52
---------------------------------------------------------------------------
bl - звуковой сигнал ^G ^G
(bell)
bs - возврат на шаг по коду ^H да да
(can backspace with ^H)
cd - очистка до конца экрана ^K \EJ
(clear to end of display)
ce - очистка до конца строки ^] \EK
(clear to end of line)
cl - очистка всего экрана ^L \EH\EJ
(clear entire screen)
cm - движение курсора ^^%r%+ %+ \EY%+ %+
(cursor motion)
co - число позиций в строке #80 #80
(number of columns in a line)
cr - возврат каретки ^M ^M
(carriage return)
do - сдвиг на строку вниз ^J ^J
(down one line)
ho - курсор в начало экрана
(без команды cm) ^Y \EH
(home cursor)
kb - код клавиши backspace ^H ^H
(sent by backspace key)
kd - код клавиши "стрелка вниз" ^J \EB
(sent by down arrow key)
kl - код клавиши "стрелка влево" ^H \ED
(sent by left arrow key)
kr - код клавиши "стрелка вправо" ^\\ \EC
(sent by right arrow key)
ku - код клавиши "стрелка вверх" ^_ \EA
(sent by up arrow key)
le - курсор влево ^H ^H
(cursor left)
li - число строк экрана #24 #24
(number of lines per screen)
nd - нестирающий пробел ^\\ \EC
(nondestructive space)
nl - символ перевода строки ^J ^J
(newline character)
pt - наличие аппаратной табуляции нет да
(has hardware tabs)
se - обычный экран ^O нет
(end stand out mode (normal))
so - инверсный экран ^N нет
(begin stand out mode (inverse))
sr - прокрутка нет \EI
(scroll reverse)
ta - символ табуляции ^I ^I
(tab)
up - сдвиг вверх на строку нет ^_
(up a line)
---------------------------------------------------------------------------
Самое интересное здесь, наверное, то, что терминалы vt52 и Apple
имеют взаимно обратный порядок указания координат в команде движения
курсора. Терминал vt52 воспринимает значения x и y в порядке YX, что
является умолчанием для файла termcap. Apple воспринимает их в порядке
XY, поэтому в записи файла termcap требуется поменять координаты
местами, что указано обозначением %r в функции cm.
Файл termcap позволяет вам спрятать основную информацию о специ-
фических характеристиках терминала (за исключением характеристик, ко-
торые могут отсутствовать у терминала, или специальных возможностей,
которые не описаны в termcap). Это значит, что вы можете создавать
терминально-независимые программы. При этом вам нет необходимости из-
менять все специфические обращения к терминалу, такие как ESC-последо-
вательности (символы, указывающие терминалу, что передаваемые после
них символы (символ) должны интерпретироваться как управляющие коды).
Это символы (\E) для терминала vt52 и (^) для Apple.
Наилучший пример - способ использования файла termcap редактором
vi. Он начинает выполнять указанную ему функцию, например движение
курсора, после чего ставит вопрос: "Какой код функции, которую мы хо-
тим выполнить?". Затем он ищет соответствующую последовательность в
той информации, которую предоставляет termcap.
С другой стороны, иногда вам необходимо оптимизировать какую-либо
функцию по скорости, заставив ее посылать коды непосредственно на оп-
ределенный терминал. В этом случае вам опять-таки полезен файл
termcap, поскольку вы можете найти необходимую информацию в соот-
ветствующем файле termcap, после чего закодировать эту информацию в
вашей программе. Это мы и делаем в первой инструментальной программе
данной главы - программе 'c'.
---------------------------------------------------------------------------
ИМЯ: c
---------------------------------------------------------------------------
c Быстрая очистка экрана
НАЗНАЧЕНИЕ
Выводит последовательность символов очистки экрана с использова-
нием быстрой программы на языке Си. Код очистки, указанный в тексте
программы, следует изменить в соответствии с используемым терминалом.
ФОРМАТ ВЫЗОВА
c
ПРИМЕР ВЫЗОВА
c Очистка экрана
ТЕКСТ ПРОГРАММЫ
1 char id[] = "@(#) c v1.0 Fast clear screen Author: Russ Sage";
Быстрая очистка экрана
3 #define FF "\014"
5 main()
6 {
7 if (write(1, FF, 1) == -1)
8 write(2,"c: write error to stdout\n",25);
ошибка записи в стандартный вывод
9 }
ОПИСАНИЕ
ЗАЧЕМ НАМ НУЖНА ПРОГРАММА c?
В System V уже имеется команда для очистки экрана терминала - это
команда clear. Она работает путем определения типа вашего терминала и
затем вывода на экран символа очистки для данного терминала. Все прек-
расно, но есть один существенный недостаток: она очень МЕДЛЕННАЯ!
Мы же хотим как можно быстрее выполнить очистку экрана. Самой
быстрой операцией ввода-вывода в системе является прямой системный вы-
зов для чтения или записи. Мы применяем этот вызов, а также выполняем