В стандарте POSIX-2001
Наряду с физическими устройствами в стандарте рассматриваются
{MAX_INPUT}.
{MAX_CANON}.
(Отметим, что в
MIN и TIME.
Запрос на чтение не будет удовлетворен, пока не поступит по крайней мере MIN байт или не
истечет время задержки TIME (время задается в десятых долях секунды). Нулевое
значение TIME трактуется как бесконечная задержка
Более точно, если MIN > 0, TIME трактуется как задержка между поступлениями байт;
следовательно, отсчет времени начинается после прихода очередного байта. Если MIN = 0, TIME означает общее время обслуживания запроса на чтение. Такой подход
позволяет эффективно читать во время вспышек активности ввода и не препятствует
побайтному вводу.
Помимо O_NONBLOCK, устанавливаемый функциями open() или fcntl(),
а на обработку входных символов -
Подвергаются обработке системой (в соответствии с
Ряд управляющих символов играет специальную роль при вводе и/или выводе. Кратко
опишем эти функции, не уточняя их соответствия с нажатиями на клавиатуре, поскольку
оно зависит от реализации. Отметим, что за некоторыми очевидными исключениями (например,
INTR
Генерирует SIGINT ), посылаемый всем процессам, для которых данный
QUIT
Генерирует сигнал выхода.
ERASE
При
KILL
При
EOF
При EOF отбрасывается. Таким образом, если EOF встретился в начале строки, в процесс будет передано нуль байт,
что и является стандартным обозначением конца файла.
NL
Стандартный разделитель строк (
EOL
Дополнительный разделитель строк, аналогичный NL, при
SUSP
Генерирует сигнал остановки.
STOP
Специальный символ как при вводе, так и при выводе, распознаваемый в случае наличия флагов IXON
(управление выводом) или IXOFF (управление вводом). Обычно используется для временной приостановки
вывода, когда нужно прочитать текст на экране
START
Употребляется для возобновления вывода, приостановленного с помощью символа STOP.
CR
При
Центральную роль в управлении termios, определенная во
включаемом файле <termios.h>. Она должна содержать по крайней мере следующие поля.
tcflag_t c_iflag; /* Режимы ввода */
tcflag_t c_oflag; /* Режимы вывода */
tcflag_t c_cflag; /* Управляющие режимы */
tcflag_t c_lflag; /* Локальные режимы */
cc_t c_cc [NCCS]; /* Специальные управ-
ляющие символы */
Типы tcflag_t, cc_t и фигурирующий далее speed_t должны определяться реализацией
посредством typedef как беззнаковые целые.
Обращение к элементам массива c_cc, хранящего VEOF, VEOL, VERASE, VINTR, VKILL, VQUIT, VSTART, VSTOP, VSUSP. Кроме того, еще
два индекса, VMIN и VTIME, используются для
работы со значениями MIN и TIME и могут совпадать с VEOF и VEOL, соответственно (поскольку символы EOF и нужны только в MIN и TIME - только в неканоническом).
Поле c_iflag структуры termios описывает основные параметры терминального ввода.
BRKINT
При
ICRNL
Преобразовывать
IGNBRK
Игнорировать
IGNCR
Игнорировать
IGNPAR
Игнорировать символы с ошибками четности.
INLCR
Преобразовывать
INPCK
Разрешить
ISTRIP
Отбрасывать старший бит, обрезая байты до семи бит.
IXOFF
Разрешить
IXON
Разрешить
PARMRK
Отмечать ошибки четности.
Поле c_oflag определяет системную обработку вывода. К числу обязательных для
поддержки стандарт POSIX-2001 относит только один флаг - OPOST>
(постпроцессировать вывод). В расширение XSI входят флаги, определяющие
характер постпроцессирования: ONLCR (преобразовывать OCRNL (преобразовывать NLDLY (выбрать задержку для
Поле c_cflag описывает аппаратные характеристики линии и CSIZE: от CS5 - 5 бит до CS8 - 8 бит), число
стоп-бит ( CSTOPB: два стоп-бита), освобождение линии при закрытии последнего
файлового дескриптора, ассоциированного с HUPCL ), PARENB: контроль включен; PARODD: проверка на нечетность) и т.п.
Стандарт осторожен в части представления termios как значение типа speed_t, но не
утверждается, что она представлена как часть поля c_cflag (хотя в исторически
сложившихся реализациях это так). Допустимые значения B0 - нулевой, означающей B38400 - 38400 бит/сек.
Поле c_lflag структуры termios используется для управления
различными
ECHO
Включить
ECHOE
Отображать символ
ECHOK
Отображать символ
ECHONL
Включить
ICANON
ISIG
Разрешить сигналы. Если установлен флаг ISIG, то каждый вводимый символ сравнивается
со , QUIT и SUSP.
В случае совпадения выполняется ассоциированная функция.
Служебная программа
tty
позволяет узнать
Если для примера перенаправить стандартный ввод (см. листинг 9.1), можно получить результат, показанный в листинге 9.2.
tty > /tmp/tty.res tty < /tmp/tty.res > /tmp/tty.res
/dev/ttyS4 not a tty
Узнать, ассоциирован ли открытый файловый дескриптор с isatty() и ttyname() (см. листинг 9.3).
#include <unistd.h> int isatty (int fildes); char *ttyname (int fildes);
Если с дескриптором ассоциирован isatty() возвращает единицу,
а ttyname() - указатель на цепочку символов (располагающуюся, быть может, в
перезаписываемой каждым вызовом статической области). В противном случае возвращаются,
соответственно, нуль и пустой указатель.
Каждый stty:
stty [ -a | -g] stty характеристика ...
Будучи вызванной без опций и операндов, она выдает значения основных
-a
Выдать значение всех установленных
-g
Выдать текущие установки в формате, который может быть использован в качестве
аргумента другой команды stty.
В частности, выдача команды
stty -a
может выглядеть так, как показано в листинге 9.4. Здесь присутствуют как стандартные,
так и специфичные для ОС Linux
speed 19200 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; start = ^Q; stop = ^S; susp = <undef>; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl ixon ixoff -iuclc -ixany -imaxbel opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt -echoctl echoke
Чтобы переустановить какую-либо
stty kill '^k'
для отмены строки придется нажимать CTRL+K. Вслед за выполнением команды
stty -echo
на экране перестанут отображаться символы, вводимые пользователем, что,
правда, не повлияет на выдачу результатов работы команд. Подобный режим
применяется для обеспечения секретности, например, во время ввода пароля.
Для восстановления
stty echo
Сохранение и восстановление
saved="$(stty -g)" stty новые_характеристики . . . stty $saved
Некоторые, хотя и весьма ограниченные, возможности управления 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
Здесь задается управляющая последовательность для выполнения функции не
входит в число стандартных.
На уровне функций опрос и изменение 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);
#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);
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.
При работе с poll()
(см. листинг 9.9), входящая в расширение XSI и позволяющая
#include <poll.h>
int poll (struct pollfd fds [],
nfds_t nfds, int timeout);
Для каждого элемента массива (с числом элементов nfds ) функция проверяет, наступили ли
заданные события; в частности, возможны ли чтение или запись без
Согласно стандарту, структура pollfd содержит по крайней мере следующие поля.
int fd; /* Опрашиваемый файловый дескриптор */ short events; /* Флаги опрашиваемых событий */ short revents; /* Флаги произошедших событий */
Среди событий, обрабатываемых функцией poll(), выделим POLLIN (информирует о том, что можно
без блокирования прочитать данные, не являющиеся высокоприоритетными), POLLRDNORM
(можно прочитать обычные данные), POLLOUT (без блокирования можно записать обычные данные), POLLERR (выходной флаг - зафиксирована ошибка устройства или потока).
Разделение данных на обычные, приоритетные и высокоприоритетные зависит от реализации.
Если запрашиваемые события не наступают, poll() ждет по крайней мере timeout миллисекунд.
Значение -1 задает бесконечную задержку.
В качестве примера описанных функций приведем упрощенную версию программы, запускающей
командный интерпретатор на для высокоуровневой работы с endwin()
восстанавливает
/* * * * * * * * * * * * * * * * * * * * * * * * */
/* Программа запускает shell на псевдотерминале */
/* * * * * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <signal.h>
#include <poll.h>
#include <sys/resource.h>
#include <curses.h>
/* Действия при завершении процесса */
static void termination (int errcode) {
endwin ();
exit (errcode);
}
/* Функция обработки сигнала SIGCHLD */
static void chldied (int dummy) {
/* Просто завершимся*/
termination (34);
}
int main (void) {
WINDOW *win1, *win2;
/* win1 - окно только для рамки */
/* win2 - окно для shell */
int pty, tty; /* Дескрипторы обеих сторон псевдотерминала */
int fr; /* Результат fork'а */
unsigned char ch; /* Прочитанный символ */
struct termios pt; /* Структура для смены характеристик псевдотерминала */
struct pollfd fds [2]; /* Массив параметров для вызова poll */
char ptybuf [L_ctermid]; /* Массив для хранения имени псевдотерминала */
char *s, *t; /* Указатели для перебора компонентов имени псевдотерминала */
int w2lines, w2cols; /* Размер создаваемого окна */
int x, y; /* Координаты в окне */
struct sigaction sact;
int i;
initscr ();
cbreak ();
noecho ();
win1 = newwin (LINES, COLS, 0, 0);
box (win1, 0, 0);
wrefresh (win1);
w2lines = LINES - 2;
w2cols = COLS - 4;
win2 = newwin (w2lines, w2cols, 1, 2);
scrollok (win2, TRUE);
/* Откроем первый свободный псевдотерминал */
for (s = "pqrs"; *s; s++) {
for (t = "0123456789abcdef"; *t; t++) {
sprintf (ptybuf, "/dev/pty%c%c", *s, *t);
if ((pty = open (ptybuf, O_RDWR)) >= 0) {
goto findpty;
}
}
}
fprintf (stderr, "Не удалось найти свободный псевдотерминал\n");
termination (-1);
findpty:
ptybuf [5] = 't';
if ((tty = open (ptybuf, O_RDWR)) < 0) {
perror ("TTY OPEN ERROR");
termination (-1);
}
/* Установим подходящие характеристики псевдотерминала */
if (tcgetattr (pty, pt) < 0) {
perror ("PTY TERMIOS GET ERROR");
return (1);
}
pt.c_iflag = 0;
pt.c_oflag = ONLCR;
pt.c_cflag = CS8 | HUPCL;
pt.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
pt.c_cc [VINTR] = 3; /* CTRL+C */
pt.c_cc [VEOF] = 4; /* CTRL+D */
if (tcsetattr (pty, TCSADRAIN, pt) < 0) {
perror ("PTY TERMIOS SET ERROR");
return (2);
}
/* То же - для стандартного ввода */
(void) tcgetattr (0, pt);
pt.c_lflag = ~ISIG;
(void) tcsetattr (0, TCSADRAIN, pt);
/* Установим обработку сигнала о завершении потомка */
sact.sa_handler = chldied;
(void) sigemptyset (sact.sa_mask);
sact.sa_flags = 0;
(void) sigaction (SIGCHLD, sact, (struct sigaction *) NULL);
/* Раздвоимся на процесс чтения с клавиатуры и вывода на экран */
/* и на процесс, в рамках которого запустим shell */
if ((fr = fork ()) < 0) {
perror ("FORK1 ERROR");
termination (-1);
} else if (fr) {
/* Это процесс, читающий с клавиатуры */
/* и выводящий на экран */
close (tty);
/* Будем ждать ввода с клавиатуры или псевдотерминала */
fds [0].fd = 0;
fds [0].events = POLLIN;
fds [1].fd = pty;
fds [1].events = POLLIN;
while (1) {
if (poll (fds, 2, -1) < 0) {
perror ("POLL ERROR");
termination (0);
}
if (fds [0].revents POLLIN) {
/* Пришел символ со стандартного ввода */
read (0, ch, 1);
write (pty, ch, 1);
}
if (fds [1].revents POLLIN) {
/* Пришел символ с псевдотерминала */
read (pty, ch, 1);
switch (ch) {
case '\n': {
/* Проинтерпретируем перевод строки */
getyx (win2, y, x);
if (y == (w2lines - 1)) {
wmove (win2, y, w2cols - 1);
waddch (win2, (chtype) ch);
} else {
wmove (win2, y + 1, 0);
}
break;
}
default: {
/* Символ не интерпретируется */
waddch (win2, (chtype) ch);
break;
}
}
wrefresh (win2);
}
}
/* Просто завершимся */
termination (0);
} else { /* Порожденный процесс - запустим в нем shell */
/* Закроем все файлы, кроме псевдотерминала */
for (i = 0; i < RLIMIT_NOFILE; i++) {
if (i != tty) {
(void) close (i);
}
}
/* Сделаем процесс лидером сеанса */
(void) setsid ();
/* Свяжем стандартные ввод, вывод и протокол с псевдотерминалом */
(void) fcntl (tty, F_DUPFD, 0);
(void) fcntl (tty, F_DUPFD, 0);
(void) fcntl (tty, F_DUPFD, 0);
close (tty);
/* Сделаем псевдотерминал управляющим */
if ((tty = open (ptybuf, O_RDWR)) < 0) {
perror ("TTY OPEN ERROR");
exit (-1);
}
close (tty);
/* Поместим в окружение параметры псевдотерминала */
{
char lnbuf [20];
char clbuf [20];
sprintf (lnbuf, "LINES=%2d", w2lines);
sprintf (clbuf, "COLUMNS=%2d", w2cols);
putenv (lnbuf);
putenv (clbuf);
}
if (execl ("/bin/sh", "sh", (char *) NULL) < 0) {
perror ("EXECL ERROR");
exit (-1);
}
}
return 0;
}
В соответствии с определением, выводимые на pty, а затем
интерпретируются и выводятся на физический ISIG: сигналы разрешены только для
В целях полноты изложения укажем, что в (частично) описанное выше семейство tc*() входят еще три функции, предназначенные для работы с
#include <unistd.h> pid_t tcgetpgrp (int fildes); #include <unistd.h> int tcsetpgrp (int fildes, pid_t pgid_id); #include <termios.h> pid_t tcgetsid (int fildes);
Функция tcgetpgrp() позволяет узнать fildes. Для
установки идентификатора группы служит функция tcsetpgrp(). Требуется, чтобы аргумент fildes соответствовал tcgetsid(), входящая в расширение XSI, по сути аналогична tcgetpgrp().
Она позволяет узнать fildes, является
Для выполнения в известном смысле обратной операции - получения маршрутного ctermid() (см. листинг 9.12).
#include <stdio.h> char *ctermid (char *s);
Если значение аргумента s отлично от NULL, маршрутное s имеет длину не менее L_ctermid байт. В противном случае имя помещается в область статической памяти,
которая перезаписывается каждым вызовом.
В стандарте POSIX-2001
Наряду с физическими устройствами в стандарте рассматриваются
{MAX_INPUT}.
{MAX_CANON}.
(Отметим, что в
MIN и TIME.
Запрос на чтение не будет удовлетворен, пока не поступит по крайней мере MIN байт или не
истечет время задержки TIME (время задается в десятых долях секунды). Нулевое
значение TIME трактуется как бесконечная задержка
Более точно, если MIN > 0, TIME трактуется как задержка между поступлениями байт;
следовательно, отсчет времени начинается после прихода очередного байта. Если MIN = 0, TIME означает общее время обслуживания запроса на чтение. Такой подход
позволяет эффективно читать во время вспышек активности ввода и не препятствует
побайтному вводу.
Помимо O_NONBLOCK, устанавливаемый функциями open() или fcntl(),
а на обработку входных символов -
Подвергаются обработке системой (в соответствии с
Ряд управляющих символов играет специальную роль при вводе и/или выводе. Кратко
опишем эти функции, не уточняя их соответствия с нажатиями на клавиатуре, поскольку
оно зависит от реализации. Отметим, что за некоторыми очевидными исключениями (например,
INTR
Генерирует SIGINT ), посылаемый всем процессам, для которых данный
QUIT
Генерирует сигнал выхода.
ERASE
При
KILL
При
EOF
При EOF отбрасывается. Таким образом, если EOF встретился в начале строки, в процесс будет передано нуль байт,
что и является стандартным обозначением конца файла.
NL
Стандартный разделитель строк (
EOL
Дополнительный разделитель строк, аналогичный NL, при
SUSP
Генерирует сигнал остановки.
STOP
Специальный символ как при вводе, так и при выводе, распознаваемый в случае наличия флагов IXON
(управление выводом) или IXOFF (управление вводом). Обычно используется для временной приостановки
вывода, когда нужно прочитать текст на экране
START
Употребляется для возобновления вывода, приостановленного с помощью символа STOP.
CR
При
Центральную роль в управлении termios, определенная во
включаемом файле <termios.h>. Она должна содержать по крайней мере следующие поля.
tcflag_t c_iflag; /* Режимы ввода */
tcflag_t c_oflag; /* Режимы вывода */
tcflag_t c_cflag; /* Управляющие режимы */
tcflag_t c_lflag; /* Локальные режимы */
cc_t c_cc [NCCS]; /* Специальные управ-
ляющие символы */
Типы tcflag_t, cc_t и фигурирующий далее speed_t должны определяться реализацией
посредством typedef как беззнаковые целые.
Обращение к элементам массива c_cc, хранящего VEOF, VEOL, VERASE, VINTR, VKILL, VQUIT, VSTART, VSTOP, VSUSP. Кроме того, еще
два индекса, VMIN и VTIME, используются для
работы со значениями MIN и TIME и могут совпадать с VEOF и VEOL, соответственно (поскольку символы EOF и нужны только в MIN и TIME - только в неканоническом).
Поле c_iflag структуры termios описывает основные параметры терминального ввода.
BRKINT
При
ICRNL
Преобразовывать
IGNBRK
Игнорировать
IGNCR
Игнорировать
IGNPAR
Игнорировать символы с ошибками четности.
INLCR
Преобразовывать
INPCK
Разрешить
ISTRIP
Отбрасывать старший бит, обрезая байты до семи бит.
IXOFF
Разрешить
IXON
Разрешить
PARMRK
Отмечать ошибки четности.
Поле c_oflag определяет системную обработку вывода. К числу обязательных для
поддержки стандарт POSIX-2001 относит только один флаг - OPOST>
(постпроцессировать вывод). В расширение XSI входят флаги, определяющие
характер постпроцессирования: ONLCR (преобразовывать OCRNL (преобразовывать NLDLY (выбрать задержку для
Поле c_cflag описывает аппаратные характеристики линии и CSIZE: от CS5 - 5 бит до CS8 - 8 бит), число
стоп-бит ( CSTOPB: два стоп-бита), освобождение линии при закрытии последнего
файлового дескриптора, ассоциированного с HUPCL ), PARENB: контроль включен; PARODD: проверка на нечетность) и т.п.
Стандарт осторожен в части представления termios как значение типа speed_t, но не
утверждается, что она представлена как часть поля c_cflag (хотя в исторически
сложившихся реализациях это так). Допустимые значения B0 - нулевой, означающей B38400 - 38400 бит/сек.
Поле c_lflag структуры termios используется для управления
различными
ECHO
Включить
ECHOE
Отображать символ
ECHOK
Отображать символ
ECHONL
Включить
ICANON
ISIG
Разрешить сигналы. Если установлен флаг ISIG, то каждый вводимый символ сравнивается
со , QUIT и SUSP.
В случае совпадения выполняется ассоциированная функция.
Служебная программа
tty
позволяет узнать
Если для примера перенаправить стандартный ввод (см. листинг 9.1), можно получить результат, показанный в листинге 9.2.
tty > /tmp/tty.res tty < /tmp/tty.res > /tmp/tty.res
/dev/ttyS4 not a tty
Узнать, ассоциирован ли открытый файловый дескриптор с isatty() и ttyname() (см. листинг 9.3).
#include <unistd.h> int isatty (int fildes); char *ttyname (int fildes);
Если с дескриптором ассоциирован isatty() возвращает единицу,
а ttyname() - указатель на цепочку символов (располагающуюся, быть может, в
перезаписываемой каждым вызовом статической области). В противном случае возвращаются,
соответственно, нуль и пустой указатель.
Каждый stty:
stty [ -a | -g] stty характеристика ...
Будучи вызванной без опций и операндов, она выдает значения основных
-a
Выдать значение всех установленных
-g
Выдать текущие установки в формате, который может быть использован в качестве
аргумента другой команды stty.
В частности, выдача команды
stty -a
может выглядеть так, как показано в листинге 9.4. Здесь присутствуют как стандартные,
так и специфичные для ОС Linux
speed 19200 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; start = ^Q; stop = ^S; susp = <undef>; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl ixon ixoff -iuclc -ixany -imaxbel opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt -echoctl echoke
Чтобы переустановить какую-либо
stty kill '^k'
для отмены строки придется нажимать CTRL+K. Вслед за выполнением команды
stty -echo
на экране перестанут отображаться символы, вводимые пользователем, что,
правда, не повлияет на выдачу результатов работы команд. Подобный режим
применяется для обеспечения секретности, например, во время ввода пароля.
Для восстановления
stty echo
Сохранение и восстановление
saved="$(stty -g)" stty новые_характеристики . . . stty $saved
Некоторые, хотя и весьма ограниченные, возможности управления 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
Здесь задается управляющая последовательность для выполнения функции не
входит в число стандартных.
На уровне функций опрос и изменение 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);
#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);
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.
При работе с poll()
(см. листинг 9.9), входящая в расширение XSI и позволяющая
#include <poll.h>
int poll (struct pollfd fds [],
nfds_t nfds, int timeout);
Для каждого элемента массива (с числом элементов nfds ) функция проверяет, наступили ли
заданные события; в частности, возможны ли чтение или запись без
Согласно стандарту, структура pollfd содержит по крайней мере следующие поля.
int fd; /* Опрашиваемый файловый дескриптор */ short events; /* Флаги опрашиваемых событий */ short revents; /* Флаги произошедших событий */
Среди событий, обрабатываемых функцией poll(), выделим POLLIN (информирует о том, что можно
без блокирования прочитать данные, не являющиеся высокоприоритетными), POLLRDNORM
(можно прочитать обычные данные), POLLOUT (без блокирования можно записать обычные данные), POLLERR (выходной флаг - зафиксирована ошибка устройства или потока).
Разделение данных на обычные, приоритетные и высокоприоритетные зависит от реализации.
Если запрашиваемые события не наступают, poll() ждет по крайней мере timeout миллисекунд.
Значение -1 задает бесконечную задержку.
В качестве примера описанных функций приведем упрощенную версию программы, запускающей
командный интерпретатор на для высокоуровневой работы с endwin()
восстанавливает
/* * * * * * * * * * * * * * * * * * * * * * * * */
/* Программа запускает shell на псевдотерминале */
/* * * * * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <signal.h>
#include <poll.h>
#include <sys/resource.h>
#include <curses.h>
/* Действия при завершении процесса */
static void termination (int errcode) {
endwin ();
exit (errcode);
}
/* Функция обработки сигнала SIGCHLD */
static void chldied (int dummy) {
/* Просто завершимся*/
termination (34);
}
int main (void) {
WINDOW *win1, *win2;
/* win1 - окно только для рамки */
/* win2 - окно для shell */
int pty, tty; /* Дескрипторы обеих сторон псевдотерминала */
int fr; /* Результат fork'а */
unsigned char ch; /* Прочитанный символ */
struct termios pt; /* Структура для смены характеристик псевдотерминала */
struct pollfd fds [2]; /* Массив параметров для вызова poll */
char ptybuf [L_ctermid]; /* Массив для хранения имени псевдотерминала */
char *s, *t; /* Указатели для перебора компонентов имени псевдотерминала */
int w2lines, w2cols; /* Размер создаваемого окна */
int x, y; /* Координаты в окне */
struct sigaction sact;
int i;
initscr ();
cbreak ();
noecho ();
win1 = newwin (LINES, COLS, 0, 0);
box (win1, 0, 0);
wrefresh (win1);
w2lines = LINES - 2;
w2cols = COLS - 4;
win2 = newwin (w2lines, w2cols, 1, 2);
scrollok (win2, TRUE);
/* Откроем первый свободный псевдотерминал */
for (s = "pqrs"; *s; s++) {
for (t = "0123456789abcdef"; *t; t++) {
sprintf (ptybuf, "/dev/pty%c%c", *s, *t);
if ((pty = open (ptybuf, O_RDWR)) >= 0) {
goto findpty;
}
}
}
fprintf (stderr, "Не удалось найти свободный псевдотерминал\n");
termination (-1);
findpty:
ptybuf [5] = 't';
if ((tty = open (ptybuf, O_RDWR)) < 0) {
perror ("TTY OPEN ERROR");
termination (-1);
}
/* Установим подходящие характеристики псевдотерминала */
if (tcgetattr (pty, pt) < 0) {
perror ("PTY TERMIOS GET ERROR");
return (1);
}
pt.c_iflag = 0;
pt.c_oflag = ONLCR;
pt.c_cflag = CS8 | HUPCL;
pt.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
pt.c_cc [VINTR] = 3; /* CTRL+C */
pt.c_cc [VEOF] = 4; /* CTRL+D */
if (tcsetattr (pty, TCSADRAIN, pt) < 0) {
perror ("PTY TERMIOS SET ERROR");
return (2);
}
/* То же - для стандартного ввода */
(void) tcgetattr (0, pt);
pt.c_lflag = ~ISIG;
(void) tcsetattr (0, TCSADRAIN, pt);
/* Установим обработку сигнала о завершении потомка */
sact.sa_handler = chldied;
(void) sigemptyset (sact.sa_mask);
sact.sa_flags = 0;
(void) sigaction (SIGCHLD, sact, (struct sigaction *) NULL);
/* Раздвоимся на процесс чтения с клавиатуры и вывода на экран */
/* и на процесс, в рамках которого запустим shell */
if ((fr = fork ()) < 0) {
perror ("FORK1 ERROR");
termination (-1);
} else if (fr) {
/* Это процесс, читающий с клавиатуры */
/* и выводящий на экран */
close (tty);
/* Будем ждать ввода с клавиатуры или псевдотерминала */
fds [0].fd = 0;
fds [0].events = POLLIN;
fds [1].fd = pty;
fds [1].events = POLLIN;
while (1) {
if (poll (fds, 2, -1) < 0) {
perror ("POLL ERROR");
termination (0);
}
if (fds [0].revents POLLIN) {
/* Пришел символ со стандартного ввода */
read (0, ch, 1);
write (pty, ch, 1);
}
if (fds [1].revents POLLIN) {
/* Пришел символ с псевдотерминала */
read (pty, ch, 1);
switch (ch) {
case '\n': {
/* Проинтерпретируем перевод строки */
getyx (win2, y, x);
if (y == (w2lines - 1)) {
wmove (win2, y, w2cols - 1);
waddch (win2, (chtype) ch);
} else {
wmove (win2, y + 1, 0);
}
break;
}
default: {
/* Символ не интерпретируется */
waddch (win2, (chtype) ch);
break;
}
}
wrefresh (win2);
}
}
/* Просто завершимся */
termination (0);
} else { /* Порожденный процесс - запустим в нем shell */
/* Закроем все файлы, кроме псевдотерминала */
for (i = 0; i < RLIMIT_NOFILE; i++) {
if (i != tty) {
(void) close (i);
}
}
/* Сделаем процесс лидером сеанса */
(void) setsid ();
/* Свяжем стандартные ввод, вывод и протокол с псевдотерминалом */
(void) fcntl (tty, F_DUPFD, 0);
(void) fcntl (tty, F_DUPFD, 0);
(void) fcntl (tty, F_DUPFD, 0);
close (tty);
/* Сделаем псевдотерминал управляющим */
if ((tty = open (ptybuf, O_RDWR)) < 0) {
perror ("TTY OPEN ERROR");
exit (-1);
}
close (tty);
/* Поместим в окружение параметры псевдотерминала */
{
char lnbuf [20];
char clbuf [20];
sprintf (lnbuf, "LINES=%2d", w2lines);
sprintf (clbuf, "COLUMNS=%2d", w2cols);
putenv (lnbuf);
putenv (clbuf);
}
if (execl ("/bin/sh", "sh", (char *) NULL) < 0) {
perror ("EXECL ERROR");
exit (-1);
}
}
return 0;
}
В соответствии с определением, выводимые на pty, а затем
интерпретируются и выводятся на физический ISIG: сигналы разрешены только для
В целях полноты изложения укажем, что в (частично) описанное выше семейство tc*() входят еще три функции, предназначенные для работы с
#include <unistd.h> pid_t tcgetpgrp (int fildes); #include <unistd.h> int tcsetpgrp (int fildes, pid_t pgid_id); #include <termios.h> pid_t tcgetsid (int fildes);
Функция tcgetpgrp() позволяет узнать fildes. Для
установки идентификатора группы служит функция tcsetpgrp(). Требуется, чтобы аргумент fildes соответствовал tcgetsid(), входящая в расширение XSI, по сути аналогична tcgetpgrp().
Она позволяет узнать fildes, является
Для выполнения в известном смысле обратной операции - получения маршрутного ctermid() (см. листинг 9.12).
#include <stdio.h> char *ctermid (char *s);
Если значение аргумента s отлично от NULL, маршрутное s имеет длину не менее L_ctermid байт. В противном случае имя помещается в область статической памяти,
которая перезаписывается каждым вызовом.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.