Отправка ввода curses на другой терминал в C через FIFO
Моя C программа запускает несколько потоков в терминале, которые печатают сообщения асинхронно. Я бы хотел, чтобы поток показывал выходные данные curses, но поскольку он асинхронный, он должен быть в другом терминале.
Моя идея - записать вывод curses в fifo и открыть терминал с помощьюcat fifo
,
Но как я могу восстановить исходящие проклятия и вывести их в файл?
Спасибо.
3 ответа
curses использует терминал для своего ввода и вывода, поэтому, если вы хотите перехватить это и заставить его пойти куда-нибудь, кроме терминала, самый простой способ (хотя и нетривиальный) - это использовать псевдотерминал. Вы делаете это по телефону posix_openpt
который дает вам псевдотерминальное мастер-устройство. Вы тогда звоните grantpt
, unlockpt
, а также ptsname
чтобы получить имя терминального устройства, которое вы можете затем fopen
и перейти к проклятиям newterm
инициализировать терминал.
Как только это будет сделано, все, что curses записывает в терминал, будет доступно для чтения из мастера, а все, что записано в master, будет введено в curses. Это как fifo, только со всеми дополнительными функциями терминала, которые ожидают проклятия.
ncurses нужен терминал, потому что он инициализирует соединение ввода / вывода. FIFO не подходит, так как он односторонний и (см., Например, Выполнить действие, если ввод перенаправлен), вероятно, не может быть инициализирован как терминал. ncurses использует TERM
Переменная окружения для поиска описания терминала (фактический терминал не рассматривается по данному вопросу).
Есть простой пример, ditto
в ncurses-примерах, которые используют xterm
для нескольких экранов ввода / вывода. Который использует интерфейс pty, например,
#ifdef USE_XTERM_PTY
int amaster;
int aslave;
char slave_name[1024];
char s_option[sizeof(slave_name) + 80];
const char *xterm_prog = 0;
if ((xterm_prog = getenv("XTERM_PROG")) == 0)
xterm_prog = "xterm";
if (openpty(&amaster, &aslave, slave_name, 0, 0) != 0
|| strlen(slave_name) > sizeof(slave_name) - 1)
failed("openpty");
if (strrchr(slave_name, '/') == 0) {
errno = EISDIR;
failed(slave_name);
}
sprintf(s_option, "-S%s/%d", slave_name, aslave);
if (fork()) {
execlp(xterm_prog, xterm_prog, s_option, "-title", path, (char *) 0);
_exit(0);
}
fp = fdopen(amaster, "r+");
if (fp == 0)
failed(path);
#else
а также newterm
передать этот файловый дескриптор ncurses:
static void
open_screen(DITTO * target, char **source, int length, int which1)
{
if (which1 != 0) {
target->input =
target->output = open_tty(source[which1]);
} else {
target->input = stdin;
target->output = stdout;
}
target->which1 = which1;
target->titles = source;
target->length = length;
target->fifo.head = -1;
target->screen = newterm((char *) 0, /* assume $TERM is the same */
target->output,
target->input);
if (target->screen == 0)
failed("newterm");
(void) USING_SCREEN(target->screen, init_screen, target);
}
Если вы читаете первый цитируемый раздел ditto
, вы заметите, что он использует опцию xterm
который позволяет приложению передавать файловый дескриптор к нему:
-Sccn This option allows xterm to be used as an input and output
channel for an existing program and is sometimes used in spe-
cialized applications. The option value specifies the last few
letters of the name of a pseudo-terminal to use in slave mode,
plus the number of the inherited file descriptor. If the
option contains a "/" character, that delimits the characters
used for the pseudo-terminal name from the file descriptor.
Otherwise, exactly two characters are used from the option for
the pseudo-terminal name, the remainder is the file descriptor.
Examples (the first two are equivalent since the descriptor
follows the last "/"):
-S/dev/pts/123/45
-S123/45
-Sab34
Note that xterm does not close any file descriptor which it did
not open for its own use. It is possible (though probably not
portable) to have an application which passes an open file
descriptor down to xterm past the initialization or the -S
option to a process running in the xterm.
Вот скриншот, показывающий ditto
:
curses требует прямого доступа к терминалу для поиска escape-кодов, определения разрешения и т. д. Вам, вероятно, следует попытаться выделить один поток, выделенный для вывода curses в текущем (основном) терминале, и перенаправить все сообщения отладки из других потоков в файл журнала / труба / каротаж (и, если хотите, представьте их внутри проклятий)