Читаем Linux API. Исчерпывающее руководство онлайн бесплатно
• При возобновлении работы, инициированном сигналом SIGCONT, обработчик повторно сохраняет текущие параметры терминала в переменной userTermios , так как за это время пользователь мог их поменять (например, с помощью команды stty). Затем обработчик возвращает терминал к состоянию, которое требуется для работы программы (ourTermios)
.
Листинг 58.4. Демонстрация режима без обработки и cbreak
tty/test_tty_functions.c
#include
#include
#include
#include "tty_functions.h" /* Объявление ttySetCbreak() и ttySetRaw() */
#include "tlpi_hdr.h"
static struct termios userTermios;
/* Параметры терминала, определенные пользователем */
static void /* Общий обработчик: восстанавливает параметры tty и завершается */
handler(int sig)
{
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &userTermios) == -1)
errExit("tcsetattr");
_exit(EXIT_SUCCESS);
}
static void /* Обработчик для SIGTSTP */
tstpHandler(int sig)
{
struct termios ourTermios; /* Для сохранения параметров нашего терминала */
sigset_t tstpMask, prevMask;
struct sigaction sa;
int savedErrno;
savedErrno = errno; /* Здесь можно было бы изменить 'errno' */
/* Сохраняем текущие параметры терминала, возвращаем терминал
к состоянию, в котором он был на момент запуска программы */
if (tcgetattr(STDIN_FILENO, &ourTermios) == -1)
errExit("tcgetattr");
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &userTermios) == -1)
errExit("tcsetattr");
/* Устанавливаем для SIGTSTP действие по умолчанию, посылаем сигнал
еще раз и разблокируем его, чтобы программа могла остановиться */
if (signal(SIGTSTP, SIG_DFL) == SIG_ERR)
errExit("signal");
raise(SIGTSTP);
sigemptyset(&tstpMask);
sigaddset(&tstpMask, SIGTSTP);
if (sigprocmask(SIG_UNBLOCK, &tstpMask, &prevMask) == -1)
errExit("sigprocmask");
/* Выполнение возобновляется после SIGCONT */
if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == -1)
errExit("sigprocmask"); /* Повторно блокируем SIGTSTP */
sigemptyset(&sa.sa_mask); /* Заново устанавливаем обработчик */
sa.sa_flags = SA_RESTART;
sa.sa_handler = tstpHandler;
if (sigaction(SIGTSTP, &sa, NULL) == -1)
errExit("sigaction");
/* С момента остановки программы пользователь мог изменить параметры
терминала; сохраняем параметры, чтобы позже их восстановить */
if (tcgetattr(STDIN_FILENO, &userTermios) == -1)
errExit("tcgetattr");
/* Восстанавливаем наши параметры терминала */
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &ourTermios) == -1)
errExit("tcsetattr");
errno = savedErrno;
}
int
main(int argc, char *argv[])
{
char ch;
struct sigaction sa, prev;
ssize_t n;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (argc > 1) { /* Используем режим cbreak */
if (ttySetCbreak(STDIN_FILENO, &userTermios) == -1)
errExit("ttySetCbreak");
/* В режиме cbreak специальные символы терминала могут генерировать сигналы.
Перехватываем их, чтобы откорректировать режим терминала. Устанавливаем
обработчики только для сигналов, которые не игнорируются. */
sa.sa_handler = handler;
if (sigaction(SIGQUIT, NULL, &prev) == -1)
errExit("sigaction");
if (prev.sa_handler!= SIG_IGN)
if (sigaction(SIGQUIT, &sa, NULL) == -1)
errExit("sigaction");
if (sigaction(SIGINT, NULL, &prev) == -1)
errExit("sigaction");
if (prev.sa_handler!= SIG_IGN)
if (sigaction(SIGINT, &sa, NULL) == -1)
errExit("sigaction");
sa.sa_handler = tstpHandler;
if (sigaction(SIGTSTP, NULL, &prev) == -1)
errExit("sigaction");
if (prev.sa_handler!= SIG_IGN)
if (sigaction(SIGTSTP, &sa, NULL) == -1)
errExit("sigaction");
} else { /* Используем режим без обработки */
if (ttySetRaw(STDIN_FILENO, &userTermios) == -1)
errExit("ttySetRaw");
}
sa.sa_handler = handler;
if (sigaction(SIGTERM, &sa, NULL) == -1)
errExit("sigaction");
setbuf(stdout, NULL); /* Отключаем буферизацию стандартного вывода */
for (;;) { /* Считываем и отображаем стандартный ввод */
n = read(STDIN_FILENO, &ch, 1);
if (n == -1) {
errMsg("read");
break;
}
if (n == 0) /* Может произойти после отключения терминала */
break;
if (isalpha((unsigned char) ch)) /* Буквы — > нижний регистр */
putchar(tolower((unsigned char) ch));
else if (ch == '\n' || ch == '\r')
putchar(ch);
else if (iscntrl((unsigned char) ch))
printf("^%c", ch ^ 64); /* Выводим Ctrl+A как ^A и т. д. */
else
putchar('*'); /* Остальные символы выводятся как '*' */
if (ch == 'q') /* Выходим из цикла */
break;
}
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &userTermios) == -1)
errExit("tcsetattr");
exit(EXIT_SUCCESS);
}
tty/test_tty_functions.c
Пример запуска программы из листинга 58.4 в режиме без обработки показан ниже:
$ stty
speed 38400 baud; line = 0;
$ ./test_tty_functions
abc
def
^C^Z
q$




