Все манипуляции tty осуществляются с помощью одной структуры,
struct termios
, а также нескольких функций, определенных в заголовочном файле
<termios.h>
. Из этих функций широко применяются только шесть. Когда не нужно устанавливать скорость передачи данных по линии, используются только две наиболее важных функции —
tcgetattr
и
tcsetattr
.
#include <termios.h>
struct termios {
tcflag_t c_iflag; /* флаги режима ввода */
tcflag_t c_oflag; /* флаги режима вывода */
tcflag_t c_cflag; /* флаги управляющего режима */
tcflag_t c_lflag; /* флаги локального режима */
cc_t c_line; /* дисциплина линии связи */
cc_t c_cc[NCCS]; /* управляющие символы */
};
int tcgetattr(int fd, struct termios * tp);
int tcsetattr(int fd, int oact, struct termios * tp);
Почти в каждом случае программы должны использовать
tcgetattr
для получения текущих установок устройства, модифицировать эти установки, а затем применять
tcsetattr
для активизации модифицированных установок. Многие программы также сохраняют копии оригинальных установок и восстанавливают их перед завершением. В общем случае, следует модифицировать только интересующие вас установки; изменение других установок может усложнить работу пользователей с необычными системными конфигурациями (или сбоями в вашем коде).
Вызов
tcsetattr
может не принять на обработку выбранные вами установки; разрешено игнорировать произвольные установки. Если оборудование просто не поддерживает установку,
tcsetattr
игнорирует ее, а не возвращает ошибку. Если вам небезразлично воздействие, оказываемое установкой, следует использовать
tcgetattr
после
tcsetattr
и проверить, оказало ли воздействие внесенное вами изменение.
Для получения установок устройства tty необходимо открыть устройство и передать файловый дескриптор
tcgetattr
. Это вызывает проблемы с некоторыми устройствами tty; некоторые обычно можно открыть лишь один раз с
целью предотвращения конфликта устройств. К счастью, передача флага
O_NONBLOCK
в
open
вызывает его немедленное открытие и предотвращает блокирование любых операций. Однако все равно можно предпочесть блокирование
read
; в таком случае используйте
fcntl
для отключения режима
O_NONBLOCK
перед тем, как появится возможность читать или записывать в него.
контролируют четыре отдельных части управления вводом и выводом. Флаг входных данных,
с_iflag
, определяет, каким образом интерпретируются и обрабатываются принятые символы. Флаг выходных данных,
c_oflag
, определяет, каким образом интерпретируются и обрабатываются символы, записываемые вашим процессом в tty. Управляющий флаг,
c_cflag
, определяет характеристики последовательного протокола устройства и полезен лишь для физических устройств. Локальный флаг,
c_lflag
, определяет, каким образом символы собираются и обрабатываются перед отправкой на обработку выходных данных. На рис. 16.1 показана упрощенная схема того, какое место занимает каждый флаг в общей схеме обработки символов.
Рис. 16.1. Упрощенная схема обработки tty
Сначала мы продемонстрируем способы применения
termios
, а затем представим короткую справку о нем.
16.3. Примеры использования
termios
16.3.1. Пароли
Самой распространенной причиной модификации установок
termios
является чтение пароля без эхо-контроля символов. Для этого следует отключить локальное эхо во время чтения пароля. Ваш код должен выглядеть следующим образом:
struct termios ts, ots;
Первая структура хранит оригинальные установки для восстановления, а вторая является копией для модификации.
tcgetattr(STDIN_FILENO, &ts);
Обычно пароли читаются со стандартного устройства ввода.
ots = ts;
Сохраните копию оригинальных установок
termios
, чтобы позже восстановить их.
ts.c_lflag &= ~ECHO;
ts.c_lflag |= ECHONL;
tcsetattr(STDIN_FILENO, TCSAFLUSH, fits);
Отключите эхо-контроль символов (кроме символов новой строки) после завершения обработки всех выходных данных. (Первая
l
в
c_lflag
означает локальную (local) обработку.)
read_password;
Теперь вы читаете пароль. Это может быть простой вызов
fgets
или
read
, либо же более сложная обработка, в зависимости от режима tty (неформатируемый режим или режим обработки) и от требований программы.
tcsetattr(STDIN_FILENO, TCSANOW, &ots);
Это немедленно восстанавливает исходные установки
termios
. (Остальные опции объясняются позже, в справочном разделе далее в главе.)