Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 9:

Общий терминальный интерфейс

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >

Некоторые, хотя и весьма ограниченные, возможности управления терминалами предоставляет служебная программа tput:

tput  [-T тип_терминала] действие

Стандарт POSIX-2001 предусматривает всего три действия: clear (очистка экрана), init (инициализация терминала ), reset (переустановка терминала ). Действие осуществляется путем посылки на терминал соответствующей управляющей последовательности. Стандарт не специфицирует, как эта последовательность определяется, каковы все результаты ее посылки и чем инициализация отличается от переустановки.

Служебная программа tput дает хорошие примеры немобильности. Во-первых, она входит в необязательную часть стандарта POSIX-2001. Во-вторых, в общем случае управляющие действия с терминалом могут реализовываться не только путем посылки на него некоторой последовательности символов, но и путем обращения к системным вызовам, поэтому присваивание

ClearScreen=`tput clear`

может и не достичь цели ( tput ничего не выдаст). В-третьих, стандартизованный перечень действий слишком ограничен, так что реально можно рекомендовать лишь включение строки вида

tput init

в разного рода инициализационные файлы. Тем не менее, показанный в листинге 9.6 фрагмент командного файла, выполняющегося при загрузке ОС Linux, демонстрирует поучительные способы борьбы с немобильностью.

if [ -x /usr/bin/tput ]; then
 if [ "x`tput kbs`" != "x" ]; then
   stty erase `tput kbs`
 elif [ -x /usr/bin/wc ]; then
   if [ "`tput kbs | wc -c `" -gt 0 ]; then
     stty erase `tput kbs`
   fi
 fi
fi
Листинг 9.6. Пример совместного использования утилит stty и tput.

Здесь задается управляющая последовательность для выполнения функции забоя. Впрочем, несмотря на все проверки, немобильность все-таки осталась, поскольку действие kbs не входит в число стандартных.

На уровне функций опрос и изменение характеристик терминала разбиты на два семейства: tc*() (см. листинг 9.7) и cf*() (см. листинг 9.8), которые в стандарте POSIX введены в качестве замены исторически сложившейся, универсальной, но чрезмерно эклектичной, не вписывающейся ни в какие синтаксические рамки функции ioctl().

#include <termios.h>
int tcgetattr (int fildes, struct termios *termios_p);
int tcsetattr (int fildes, int optional_actions, const struct termios *termios_p);
int tcflow (int fildes, int action);
int tcflush (int fildes, int queue_selector);
int tcdrain (int fildes);
int tcsendbreak (int fildes, int duration);
Листинг 9.7. Описание функций семейства tc*().
#include <termios.h>
speed_t cfgetispeed (const struct termios *termios_p);
speed_t cfgetospeed (const struct termios *termios_p);
int cfsetispeed (struct termios *termios_p, speed_t speed);
int cfsetospeed (struct termios *termios_p, speed_t speed);
Листинг 9.8. Описание функций семейства cf*().

Пара функций tcgetattr() / tcsetattr() позволяет стандартным образом опросить/изменить характеристики терминала, ассоциированного с открытым файловым дескриптором fildes. Значения характеристик помещаются в структуру, на которую указывает аргумент termios_p. Нюансами изменения ведает аргумент optional_actions. Если его значение равно TCSANOW, изменение выполняется немедленно. Значение TCSADRAIN предписывает сначала дождаться передачи на терминальное устройство всех записанных по дескриптору fildes данных; это полезно, если изменения затрагивают режимы вывода. Значение TCSAFLUSH дополнительно означает предварительный сброс введенных устройством, но не прочитанных прикладными процессами символов.

Отметим, что вызов tcsetattr() завершается успешно (и возвращает нулевое значение), если удалось осуществить хотя бы одно из запрошенных изменений характеристик терминала. Это сделано по соображениям мобильности, поскольку разные реализации могут поддерживать разные подмножества характеристик. После tcsetattr() целесообразно снова вызвать tcgetattr() и узнать реальное состояние терминального устройства.

Приложение, изменяющее характеристики терминала, обязано позаботиться об их последующем восстановлении (например, при завершении процесса). Завершение должно выполняться аккуратно, с обработкой сигналов.

Функция tcflow() позволяет приостановить или возобновить терминальный ввод/вывод. Если значение аргумента action равно TCOOFF, приостанавливается вывод; по значению TCOON он возобновляется. Значение TCIOFF вызывает передачу на терминал символа STOP, значение TCION - символа START, что оказывает соответствующее воздействие на ввод.

С помощью функции tcflush() можно сбросить очередь ввода (значение TCIFLUSH аргумента queue_selector ), вывода ( TCOFLUSH ) или совместить их (значение TCIOFLUSH ).

Функция tcdrain() действует мягче. Она блокирует вызывающий процесс, пока все данные, записанные по дескриптору fildes, не будут переданы на терминальное устройство, дожидаясь тем самым физического окончания вывода.

Функция tcsendbreak() носит технический характер, позволяя организовать разрыв соединения путем посылки на терминал нулевых бит в течение заданного интервала времени. Если значение аргумента duration равно нулю, посылка продолжается от четверти до половины секунды.

Поскольку стандарт POSIX-2001 не специфицирует способ представления в структуре termios данных о скорости передачи, для выборки/записи данной характеристики из/в termios потребовалось ввести семейство функций cf*(), что, конечно, хорошо, ибо это проявление (возможно, невольное) объектно-ориентированного подхода. Кроме того, в общем случае терминальное устройство может поддерживать для ввода и вывода разные скорости, поэтому определено четыре функции, названия которых говорят сами за себя. Разумеется, для реального опроса/изменения скорости обмена с терминалом нужно воспользоваться функциями tcgetattr() / tcsetattr(). Отметим также, что скорость должна задаваться не в виде целого числа, а с помощью определенных в заголовочном файле <termios.h> констант B0, ..., B38400.

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >
Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?