Отправка ввода 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 в текущем (основном) терминале, и перенаправить все сообщения отладки из других потоков в файл журнала / труба / каротаж (и, если хотите, представьте их внутри проклятий)

Другие вопросы по тегам