Дата и время публикации:
Теория и практика
1. Теория
Название библиотеки curses происходит от английского термина cursor optimization(оптимизация курсора), которая заключается в нахождении наилучшего способа перерисовки курсора и его позиционирования на экране текстового терминала.
Поэтому основное назначение библиотеки ncurses создание дружественного интерфейса пользователя (терминальной программы) для взаимодействия с программой xterm эмуляции DEC-терминалов VT52, VT102/220, VT420 и т.д., которые используются активно при создании терминальных соединений, сессий с участием последовательных каналов передачи данных (ptty, tty, ttyS и т.п.), стека протоколы tcp/ip, например SSH-соединений.
Принцип работы терминального приложения показан на рисунке 1.1
Рисунок 1.1
Как показано на рисунке 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.2 terminfo(5)
3.3 how to get the screen state as set by tput smcup rmcup
3.6 Linux Programmer's Manual. TERMIOS(3)
3.7 Writing Programs with NCURSES.Intorduction