× К оглавлению На главную Об авторе

Дата и время публикации:

Теория и практика


1. Теория

Название библиотеки curses происходит от английского термина cursor optimization(оптимизация курсора), которая заключается в нахождении наилучшего способа перерисовки курсора и его позиционирования на экране текстового терминала.

Поэтому основное назначение библиотеки ncurses создание дружественного интерфейса пользователя (терминальной программы) для взаимодействия с программой xterm эмуляции DEC-терминалов VT52, VT102/220, VT420 и т.д., которые используются активно при создании терминальных соединений, сессий с участием последовательных каналов передачи данных (ptty, tty, ttyS и т.п.), стека протоколы tcp/ip, например SSH-соединений.

Принцип работы терминального приложения показан на рисунке 1.1

Рисунок 1.1

Примечания. *) – терминал xterm показан условно вследствие совместной реализации с функциональной базой терминалов terminfo(5).

Как показано на рисунке 1.1, эмуляция обеспечивается c помощью функциональной базы данных терминалов terminfo(5).

Для перерисовки и позиционирования курсора в ncurses используются управляющие последовательности ( англ. escape sequences) терминала xterm с поддержкой 256 цветов, который обычно принято обзыватъ xterm-256color. Это достигается за счет обращения xterm к базе данных terminfo(5), которая осуществляет стандартизацию их управляющих последовательностей согласно типа терминала.

Таким образом можно резюмировать, что ncurses обращается (инициализирует) терминал. Нечто подобное реализуется в SHELL, как показано в листинге 1.1

Листинг 1.1

001 #! /bin/bash
002 tput smcup
003 cat "${1}"
004 read
005 tput rmcup

2. Практика

При создании терминальных приложений учитывается переменные окружения TERM и TERMCOLOR, показанные ниже из вывода env(1).

TERM=xterm-256color
TERMCOLOR=true

Команда tput(3), инициализирует терминал xterm, показанный на рисунке 1.1 и указанный в переменной окружения TERM или TERMCAP.

Для переключения на альтернативный экран (англ. alternate screen) в начале вызывается.

tput smcup

А после вывода с помощью read содержимого файла ${1}, обратно переключается в нормальный режим (англ. normal screen).

tput rmcup

Примерно так библиотека ncurses активизирует терминал c помощью функции терминала (англ. terminal capabilities) smcup, обеспечивающей переключение к альтернативному терминалу, а завершает работу с терминалом функция rmcup.

Терминальный обмен представляет собой что-то подобное, проводимое в дампе 2.2. Для этого, напишем простейшую программку с использованием ncurses, текст которой показан в листинге 2.1 и являющейся пародией на less(1) .

Листинг 2.1

001 #include <ncurses.h>
002 #include <stdio.h>
003 int main(int argc, char** argv) {
004   initscr();
005   FILE* f = fopen(argv[1], "r");
006   int c;
007   while ((c = getc(f)) != EOF) printw("%c", c);
008   fclose(f);
009   refresh();
010   getc(stdin);
011   endwin();
012   return 0;
013 }

Затем, собираем

gcc -o less.crappy less_crappy.c -lncurses

После чего создаем входной файл ${1}, как показано ниже

echo 'Hello, world!' > to_display.txt

Запускаем и перенаправления вывод на

$ ./less.crappy to_display.txt > output.txt

Раскрываем содержимое с использованием hexdump -С output.txt

00000000  1b 5b 3f 31 30 34 39 68  1b 5b 32 32 3b 30 3b 30  |.[?1049h.[22;0;0|
00000010  74 1b 5b 31 3b 35 33 72  1b 28 42 1b 5b 6d 1b 5b  |t.[1;53r.(B.[m.[|
00000020  34 6c 1b 5b 3f 37 68 1b  5b 48 1b 5b 32 4a 48 65  |4l.[?7h.[H.[2JHe|
00000030  6c 6c 6f 2c 20 77 6f 72  6c 64 21 0d 0a 1b 5b 35  |llo, world!...[5|
00000040  33 3b 31 48 1b 5b 3f 31  30 34 39 6c 1b 5b 32 33  |3;1H.[?1049l.[23|
00000050  3b 30 3b 30 74 0d 1b 5b  3f 31 6c 1b 3e           |;0;0t..[?1l.>|
0000005d

В начале и в конце (выделено жирным) показаны две управляющие последовательности – \e[?1049h и \e[?1049l. Первая соответствует tput rmcup и переключает на альтернативный экран, а вторая обратно к нормальному, что соответствует tcup rmcup

Приведенные последовательности верны для терминала xterm, впрочем как и для xterm-colord256. При задании в переменной TERM иного терминала значения могут меняться, например для VT100

$ TERM=vt100 ./less.crappy to_display.txt > output.txt

будет получена следующая управляющая последовательность.

00000000  1b 28 42 1b 29 30 1b 5b  31 3b 35 33 72 1b 5b 6d  |.(B.)0.[1;53r.[m|
00000010  0f 1b 5b 3f 37 68 1b 5b  48 1b 5b 4a 48 65 6c 6c  |..[?7h.[H.[JHell|
00000020  6f 2c 20 77 6f 72 6c 64  21 0d 0a 1b 5b 35 33 3b  |o, world!...[53;|
00000030  31 48 0d 1b 5b 3f 31 6c  1b 3e                    |1H..[?1l.>|
0000003a

Во время инициализации терминала, перехода к альтернативному отображению желанных форм, библиотека ncurses оперирует низкоуровневыми (системными) функциями tputs(3), которая опять же обращается к terminfo(5).

Таким образом, написанное на ncurses приложение является генератором управляющих последовательностей, которые передаются на отдельно запущенный терминал, обеспечивающий, в свою очередь, операции визуализации ввода и вывода информации.

3. Библиография

3.1 The-TERM-variable

3.2 terminfo(5)

3.3 how to get the screen state as set by tput smcup rmcup

3.4 Linux tput command

3.5 Xterm Control Sequences

3.6 Linux Programmer's Manual. TERMIOS(3)

3.7 Writing Programs with NCURSES.Intorduction

3.8 Handling ANSI Escape Sequences for Printing to Curses

3.9 How less works: the terminal’s alternative buffer