Четыре флага termios
контролируют четыре отдельных части управления вводом и выводом. Флаг входных данных, с_iflag
, определяет, каким образом интерпретируются и обрабатываются принятые символы. Флаг выходных данных, c_oflag
, определяет, каким образом интерпретируются и обрабатываются символы, записываемые вашим процессом в tty. Управляющий флаг, c_cflag
, определяет характеристики последовательного протокола устройства и полезен лишь для физических устройств. Локальный флаг, c_lflag
, определяет, каким образом символы собираются и обрабатываются перед отправкой на обработку выходных данных. На рис. 16.1 показана упрощенная схема того, какое место занимает каждый флаг в общей схеме обработки символов.
Рис. 16.1. Упрощенная схема обработки tty
Сначала мы продемонстрируем способы применения termios
, а затем представим короткую справку о нем.
16.3. Примеры использования termios
Самой распространенной причиной модификации установок 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
. (Остальные опции объясняются позже, в справочном разделе далее в главе.)
Полный код программы-примера, readpass
, показан ниже.
1: /* readpass.с */
2:
3: #include
4: #include
5: #include
6: #include
7:
8: int main (void) {
9: struct termios ts, ots;
10: char passbuf[1024];
11:
12: /* получить и сохранить текущие настройки termios */
13: tcgetattr(STDIN_FILENO, &ts);
14: ots = ts;
15:
16: /* изменить и установить новые настройки termios */
17: ts.c_lflag & = ~ECHO;
18: ts.c_lflag |= ECHONL;
19: tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts);
20:
21: /*хоть это и параноидально, но проверить, возымели ли эффект новые настройки*/
22: tcgetattr(STDIN_FILENO, &ts);
23: if (ts.c_lflag & ECHO) {
24: fprintf(stderr, "Сбой при отключении эхо-контроля\n");
25: tcsetattr(STDIN_FILENO, TCSANOW, &ots);
26: exit(1);
27: }
28:
29: /* получить и вывести пароль */
30: printf("введите пароль:");
31: fflush(stdout);
32: fgets(passbuf, 1024, stdin);
33: printf("прочитан пароль: %s", passbuf);
34: /* в passbuf был завершающий символ \n */
35:
36: /* восстановить старые настройки termios */
37: tcsetattr(STDIN_FILENO, TCSANOW, &ots);
38:
39: exit(0);
40: }
16.3.2. Последовательные коммуникации
В качестве примера программирования обоих концов tty рассмотрим программу, подключающую текущий терминал к последовательному порту. На одном tty программа под названием robin
сообщается с вами во время набора. На другом tty она взаимодействует с последовательным портом. С целью мультиплексирования вводных и выходных данных на локальном tty и последовательном порте программа использует системный вызов poll()
, описанный в главе 13.
Ниже приведен полный код программы robin.с
, за которым даны объяснения.
1: /* robin.с */
2:
3: #include
4: #include
5: #include
6: #include
7: #include
8: #include
9: #include
10: #include /* для strerror() */
11: #include
12: #include
13:
14: void die(int exitcode, const char *error, const char *addl) {
15: if (error) fprintf(stderr, "%s: %s\n", error, addl);
16: exit(exitcode);
Читать дальше