CodeNet / Языки программирования / C / C++ / Руководства и справочные материалы по C/C++ / Руководство программиста для Linux
Символьная графика
8. Символьная графика
Эта глава имеет дело с вводом/выводом символов на экран. Когда мы говорим "символ", то подразумеваем композицию пикселов, которая может меняться в зависимости от таблицы представлений символов (charset). Ваша графическая карта уже предлагает одну или более таких таблиц и по умолчанию работает в текстовом (charset) режиме, потому что текст обрабатывается быстрее, чем пиксельная графика. Терминалы можно использовать лучше, чем как простые и скучные текстовые дисплеи. Рассмотрим, как использовать специальные возможности, которые предлагает терминал Linux-а, особенно консоль Linux-а.
printf, sprintf, fprintf, scanf, sscanf, fscanf
С этими функциями libc вы можете выдавать форматированные строки в stdout (стандартный вывод), с stderr (стандартная ошибка) или другие потоки, определенные как FILE *stream (например, файлы). sscanf обеспечивает подобные возможности для чтения форматированного ввода из stdin.
termcap
База данных TERMinal CAPabilitie - это таблица элементов описания работы с терминалом в ASCII-файле /etc/termcap. Здесь вы можете найти информацию о том, как выводить специальные символы, как осуществлять операции (удаления, вставки символов или строк и т.д.) и как инициализировать терминал. База данных используется, например, редактором vi. Имеются библиотечные функции для чтения и использования возможностей терминала (смотри termcap(3x)). С этой базой данных программы могут работать с различными терминалами одним и тем же кодом. База данных termcap и библиотечные функции предоставляют только низкоуровневый доступ к терминалу. Изменение атрибутов или цветов, параметризованный вывод и оптимизация остаются программисту.
База данных terminfo
База данных TERMinal INFOrmation построена над базой данных termcap и описывает некоторые возможности терминалов на более высоком уровне. С terminfo программа может легко менять атрибуты экрана, используя специальные клавиши, такие как функциональные клавиши и др. Эта база данных может быть найдена в /usr/lib/terminfo/[A-z,0-9]*. Каждый файл описывает один терминал.
curses
Terminfo - хорошая база для работы с терминалом в программе.
Библиотека (BSD-)curses дает вам высокоуровневый доступ к терминалу, базируясь на terminfo. curses позволяет открывать и манипулировать окнами на экране, предоставляет весь необходимый набор функций ввода/вывода и может изменять видеоатрибуты терминально-независимым образом на более чем 150 терминалах. Библиотека находится в /usr/lib/libcurses.a. Это BSD-версия curses.
ncurses
ncurses - это развитие curses. В версии 1.8.6 она должна быть совместима с AT&T curses, как это определено в SYSVR4, и иметь несколько расширений, таких как манипулирование цветами, специальная оптимизация для вывода, оптимизации, зависящие от терминала, и др. ncurses была протестирована на множестве систем, таких как Sun-OS, HP и Linux. Автор рекомендует предпочесть ncurses всему остальному. В SYSV Unix системах (например, Solaris) должна существовать библиотека curses с теми же функциональными возможностями, что и ncurses (на самом деле солярисовская curses имеет немного больше функций и поддержку мыши).
В следующих разделах мы рассмотрим, как пользоваться различными пакетами доступа к терминалу. В Linux-е мы имеем GNU-версию termcap и можем пользоваться ncurses вместо curses.
8.1. Функции ввода/вывода в libc
8.1.1. Форматированный вывод
Функции printf(...) в libc обеспечивают форматированный вывод и позволяют трансформировать аргументы. * int fprintf(FILE *stream, const char *format, ...), преобразует выводимые аргументы в соответствии с шаблоном и записывает его в stream. Формат определяется аргументом format. Функция возвращает число записанных символов или отрицательное число в случае ошибки.
format содержит два типа объектов: обычные символы и информацию, как трансформировать или форматировать аргументы.
Форматная информация должна начинаться с %, за которым следуют значения для формата, дальше идет символ для трансляции (чтобы напечатать знак %, используйте %%). Возможны следующие значения для формата:
- Флаги * - Форматированный аргумент будет при печати прижат влево на своем поле. * + Каждое число будет напечатано со знаком, например, +12 или -2.32. - Пробел Если первый символ - не знак, то будет вставлен пробел. - 0 Для чисел ширина поля будет заполнена слева нулями. - #
Изменяет вывод в зависимости от трансформации для аргумента:
- Для o первое число будет 0.
- Для x или X будет напечатано в конце 0x или 0X соответственно.
- Для e, E, f, F вывод имеет десятичную точку.
- Для g или G в конце аргумента будут напечатаны нули.
- Число, указывающее минимальную ширину поля
Трансформированный аргумент печатается в поле, ширина которого не меньше, чем сам аргумент. С этим числом вы можете увеличить ширину поля. Если аргумент меньше, то оставшаяся часть поля заполняется пробелами или нулями. - Точка для отделения ширины поля и точности
- Число для точности
Возможные значения для трансформации смотри в таблице 8.1.
* int printf(const char *format, ...) То же самое, что fprintf(stdout, ...). * int sprintf(char *s, const char *format, ...) То же, что и printf(...), но вывод будет записан в символьный указатель s (с последующим \0). (Вы должны захватить достаточно памяти для s.) * vprintf(const char *format, va_list arg) vfprintf(FILE *stream, const char *format, va_list arg) vsprintf(char *s, const char *format, va_list arg)
То же, что и для вышеописанных функций, только список аргументов находится в arg.
8.1.2. Форматированный ввод
Точно так же, как printf(...) для форматированного вывода, вы можете использовать scanf(...) для форматированного ввода.
* int fscanf(FILE *stream, const char *format, ...)
fscanf(...) читает из stream и преобразует ввод по правилам, определяемым в format. Результаты помещаются в аргументы, заданные в "..." (эти аргументы должны быть указателями!). Чтение заканчивается, когда в format исчерпаны правила форматирования.
Таблица 8.1: Libc - трансформации printf
Символ | Форматируется в --------|----------------------------------- d,i | int signed, десятиричный o | int unsigned, восьмеричный, без предваряющего 0 x,X | int unsigned, шестнадцатиричный, без предваряющего 0x u | int unsigned, десятиричный c | int (unsigned) одиночный символ s | char * до \0 f | double как [-]mmm.ddd e,E | double как [-]m.dddddde+xx, [-]m.dddddde-xx g,G | double использует %e или %f когда нужно p | void * n | int * % | %
fscanf вернет EOF, при первом достижении конца файла или при возникшей ошибке. Если этого не случится, будет возвращено количество трансформированных аргументов.
format может содержать правила форматирования аргументов (см. табл. 8.2)
Он может также включать:
- пропуски или табуляции, которые игнорируются;
- любой нормальный символ, кроме %. Символы должны быть во вводе на соответствующих позициях.
- правила преобразования, заданные с %, необязательный символ * (позволит fscanf(...) присвоить аргументу), необязательное число, необязательный символ h, l или L (для задания длины считываемой инфомации) и символ трансформации.
* int scanf(const char *format, ...)
То же, что fscanf(stdin,...)
* int sscanf(char *str, const char *format, ...)
То же, что scanf, но ввод производится из строки str.
8.2. Библиотека termcap
8.2.1. Введение
Библиотека termcap - это API для базы данных termcap, которая находится в /etc/termcap/. Библиотечные функции позволяют:
* получить описание текущего терминала: tgetent(...);
Таблица 8.2: libc - трансформации sсanf
Символ | Вход - тип аргумента -------|--------------------------------------------------------------- d | десятичный integer - int* i | integer - int* (вход может быть восьме- или шестнадцатиричным) o | восьмеричный integer - int* (с или без предваряющего 0) u | десятичный unsigned - unsigned int* x | шестнадцатиричный integer - int* (с или без предваряющего 0x) c | одна или более литер - char* (без завершающего /0) e,f,gf | float - float* (такой как [-]m.dddddde+xx, [-]m.dddddde-xx) p | указатель - void* n | число трансформированных аргументов - int* [...] | непустое множество литер на входе - char* [^...] | исключая такие литеры - char* % | % ----------------------------------------------------------------------- перед d,i,n,o,u,x может стоять h, если указатель - short то же для l, если указатель - long l также может быть перед e,f,g, если указатель - double L может стоять перед e,f,g, если указатель - long double
* найти описание для информации: tgetnum(...), tgetflag(...), tgetstr(...);
* вычислить и произвести поточечный вывод: tputs()
Программы, использующие библиотеку termcap должны включать termcap.h и собираться с:
gcc [flags] files -ltermcap
Функции termcap терминально-независимые программы, но дают программисту только низкоуровневый доступ к терминалу. Для пакета более высокого уровня потребуется curses или ncurses.
8.2.2. Поиск описания терминала
* int tgetent(void *buffer, const char *termtype)
В операционной системе Linux текущее имя терминала содержится в переменой среды TERM. Поэтому termtype есть результат вызова getenv(3). Что касается buffer, то в GNU-версии Linux termcap не нужно захватывать память. В других версиях вам придется выделить 2048 байт (прежде buffer требовал 1024 байта, но сейчас размер удвоился).
tgetent(...) возвращает 1 в случае успеха и 0 когда база данных найдена, но не имеет точки входа для TERM. Другие ошибки возвращают различные значения.
Следующий пример объясняет как использовать getent(...):
#define buffer 0 char *termtype=getenv("TERM"); int ok; ok=tgetent(buffer,termtype); if(ok==1) /* все нормально, мы имеем вход */ else if(ok==0) /* ой, что-то не так с TERM * проверим сначала termtype, затем базу данных termcap */ else /* у-у-у, глобальная ошибка */
По умолчанию termcap использует /etc/termcap/ как базу данных. Если переменная среды TERMCAP установлена, например, в $HOME/mytermcap, то все функции будут пользоваться mytermcap вместо /etc/termcap. Без начального слэша в TERMCAP определенное значение понимается как имя для терминала.
8.2.3. Описание терминала
Каждый фрагмент информации называется свойством (capability). Каждое свойство - это двухлитерный код, за каждым двухлитерным кодом стоит значение свойства. Возможны следующие типы свойств.
- Числовой: например, co - число столбцов
- Логический или флаговый: например, hc - терминал твердой копии (hardcopy terminal)
- Строковый: например, st - установка табуляции (подробнее см. 8.22.3)
Каждое свойство связано с единственным типом значений (co всегда числовой, hc всегда флаг, а st всегда строка). Три типа значений - и три типа функций, их запрашивающих. char *name - это двухлитерный код свойства.
* int tgetnum(char *name)
Получение свойства с числовым значением, таким как co. Функция tgetnum(...) возвращает числовое значение, если свойство доступно, 1 в противном случае. (Заметьте, что возвращаемое значение всегда неотрицательно.)
* int tgetflag(char *name)
Получение логического свойства. Возвращает 1, если флаг установлен, 0 в противном случае.
* char *tgetstr(char *name, char **area)
Получение строкового свойства. Возвращает указатель на строку или NULL в случае отсутствия. В GNU-версии, если area есть NULL, termcap выделит память сам. termcap больше не позаботится об этом указателе, если вы не освободите name перед выходом из программы. Такой метод предпочтителен, поскольку вы не знаете сколько памяти потребуется для указателя, поэтому позвольте termcap сделать все за вас.
char *clstr, *cmstr; int lines, cols; void term_caps() { char *tmp; clstr=tgetstr("cl",0); /* очистка экрана */ cmstr=tgetstr("cm",0); /* перемещение y,x */ lines=tgetnum("li"); /* полосы терминала */ cols=tgetnum("co"); /* колонки терминала */ tmp=tgetstr("pc",0); /* символ дозаполнения */ PC=tmp ? *tmp : 0; BC=tgetstr("le",0); /* сдвиг курсора на символ влево */ UP=tgetstr("up",0); /* сдвиг курсора на линию вверх */ }
8.2.4. Свойства termcap
Логические свойства
5i | принтер не имеет эха на экране |
am | автоматические границы, что означает автоматическое форматирование строки |
bs | Crtl-H представляет backspace |
bw | backspace на левой границе переносит строку на правую границу предыдущей |
da | вывести сохраненное над текущим экраном |
db | вывести сохраненное под текущим экраном |
eo | пробел стирает литеру на позиции курсора |
es | esc-последовательности и специальные символы работают в строке состояния |
gn | родовое устройство |
hc | это терминал твердой копии (hardcopy terminal) |
HC | курсор плохо видно, когда он не на последней линии |
hs | присутствует линия статуса |
hz | терминал не может напечатать тильды (tilde characters) |
in | терминал вставляет нули вместо пробелов на пустые места |
km | терминал имеет мета клавишу |
mi | режим вставки для курсора |
ms | режим стандартного вывода / подчеркивания для курсора |
NP | нет символов-заполнителей |
NR | ti не обращает teos терминал может забивать ошибки |
ul | терминал подчеркивает, но ошибки забивать не может |
xb | сбой, вызванный столпотворением, F1 посылает ESCAPE, F2 посылает ^C |
xn | сбой новой линии / соединения строк |
xo | терминал использует xon/xoff протокол |
xs | текст, напечатанный поверх выделенного, будет выделен |
xt | сбой телевизионного луча, неверная табуляция и странный режим выделения |
Числовые свойства
co | число столбцов |
dB | приостановка на милисекунды для возврата на терминалах твердой копии |
dC | приостановка на милисекунды для перевода каретки на терминалах твердой копии |
dF | приостановка на милисекунды для заполнения страницы на терминалах твердой копии |
dN | приостановка на милисекунды для новой линии на терминалах твердой копии |
dT | приостановка на милисекунды для табуляции на терминалах твердой копии |
dV | приостановка на милисекунды для вертикальной табуляции на терминалах твердой копии |
it | раница между позициями табуляции |
lh | высота мягких меток |
lm | линии памяти |
lw | ширина |
li | число линий |
Nl | число мягких меток |
pb | наименьшая граница, когда требуется дозаполнение |
sg | сбой режима выделения |
ug | сбой режима подчеркивания |
vt | номер виртуального терминала |
ws | ширина линии статуса, если она отлична от ширины экрана |
Строковые свойства
!1 | клавиша сохранения в верхнем регистре |
!2 | клавиша подвешивания в верхнем регистре |
!3 | клавиша undo в верхнем регистре |
#1 | клавиша помощи в верхнем регистре |
#2 | клавиша home в верхнем регистре |
#3 | клавиша ввода в верхнем регистре |
#4 | клавиша курсор - влево в верхнем регистре |
%0 | клавиша redo |
%1 | клавиша помощи |
%2 | клавиша пометки |
%3 | клавиша сообщения |
%4 | клавиша перемещения |
%5 | клавиша следующего объекта |
%6 | клавиша открытия |
%7 | клавиша опций |
%8 | клавиша предыдущего объекта |
%9 | клавиша печати |
%a | клавиша сообщения в верхнем регистре |
%b | клавиша перемещения в верхнем регистре |
%c | клавиша следующего объекта в верхнем регистре |
%d | клавиша опций в верхнем регистре |
%e | клавиша предыдущего объекта в верхнем регистре |
%f | клавиша печати в верхнем регистре |
%g | клавиша redo в верхнем регистре |
%h | клавиша перестановки в верхнем регистре |
%i | клавиша курсор-вправо в верхнем регистре |
%j | клавиша продолжения в верхнем регистре |
&0 | клавиша cancel в верхнем регистре |
&1 | клавиша ссылки |
&2 | клавиша обновления |
&3 | клавиша перестановки |
&4 | клавиша перезапуска |
&5 | клавиша продолжения |
&6 | клавиша сохранения |
&7 | клавиша подвешивания |
&8 | клавиша undo |
&9 | клавиша начала в верхнем регистре |
*0 | клавиша поиска в верхнем регистре |
*1 | клавиша команды в верхнем регистре |
*2 | клавиша копирования в верхнем регистре |
*3 | клавиша создания в верхнем регистре |
*4 | клавиша удаления символа в верхнем регистре |
*5 | клавиша удаления строки в верхнем регистре |
*6 | клавиша выделения |
*7 | клавиша конца в верхнем регистре |
*8 | клавиша очистки линии в верхнем регистре |
*9 | клавиша выхода в верхнем регистре |
0 | клавиша поиска1 клавиша начала |
2 | клавиша cancel |
3 | клавиша закрытия |
4 | клавиша команды |
5 | клавиша копирования |
6 | клавиша создания |
7 | клавиша конца |
8 | клавиша ввода/посылки |
9 | клавиша выхода |
al | клавиша вставки одной линии |
AL | клавиша вставки %1 линий |
ac | цвет блока символов, отображаемых в другой таблице символов |
ae | конец множества символов из альтернативной таблицы |
as | начало блока символов в альтернативной таблице |
bc | backspace, если не ^H |
bl | символ звонка |
bt | переход к предыдущему месту табуляции |
cb | очистка от начала линии до курсора |
cc | странный командный символ |
cd | очистка до конца экрана |
ce | очистка до конца линии |
ch | перемещение курсора горизонтально до столбца %1 |
cl | очистка экрана, курсор помещается в начало |
cm | курсор перемещается на полосу %1 и колонку %2 (на экране) |
CM | курсор перемещается на линию %1 и колонку %2 (в памяти) |
cr | возврат каретки |
cs | область прокрутки от линии %1 до линии %2 |
ct | очистка табуляций |
cv | вертикальное движение курсора до линии %1 |
dc | удаление 1 символа |
DC | удаление %1 символов |
dl | удаление 1 линии |
DL | удаление %1 линий |
dm | начало режима удаления |
do | курсор на 1 линию вниз |
DO | курсор на %1 линию вниз |
ds | убрать линию статуса |
eA | активирование альтернативной символьной таблицы |
ec | удаление %1 символов начиная с позиции курсора |
ed | конец режима удаления |
ei | конец режима вставки |
ff | символ дозаполнения экрана на терминалах твердой копии |
fs | возврат символа на его позицию перед переходом на линию статуса |
F1 | строка послана функциональной клавишей F11 |
... | ... |
F9 | строка послана функциональной клавишей F19 |
FA | строка послана функциональной клавишей F20 |
... | ... |
FZ | строка послана функциональной клавишей F45 |
Fa | строка послана функциональной клавишей F46 |
... | ... |
Fr | строка послана функциональной клавишей F63 |
hd | перемещение курсора на пол-линии вниз |
ho | курсор в начало |
hu | перемещение курсора на пол-линии вверх |
i1 | инициализация строки 1 в начале сеанса |
i3 | инициализация строки 3 в начале сеанса |
is | инициализация строки 2 в начале сеанса |
ic | вставка 1 символа |
IC | вставка %1 символов |
if | файл инициализации |
im | начало режима вставки |
ip | вставка времени и необходимых специальных символов после вставки |
iP | программа инициализации |
K1 | верхняя левая клавиша на keypad |
K2 | центральная клавиша на keypad |
K3 | верхняя правая клавиша на keypad |
K4 | нижняя левая клавиша на keypad |
K5 | нижняя правая клавиша на keypad |
k0 | функциональная клавиша 0 |
... | ... |
k9 | функциональная клавиша 9 |
k; | функциональная клавиша 10 |
ka | клавиша очистки всех табуляций |
kA | клавиша вставки линии |
kb | клавиша backspace |
kB | клавиша возврата к предыдущему месту табуляции |
kC | клавиша очистки экрана |
kd | клавиша down |
kD | клавиша удаления символа под курсором |
ke | отключение keypad |
kE | клавиша очистки до конца линии |
kh | клавиша курсор - home |
kH | клавиша курсор home + down |
kI | вставка символа / клавиша режима вставки |
kl | клавиша курсор - left |
kL | клавиша удаления линии |
kM | Mклавиша выхода из режима вставки |
kN | клавиша следующей страницы |
kP | клавиша предыдущей страницы |
kr | клавиша курсор - right |
kR | клавиша прокрутки назад/вверх |
ks | включение keypad |
kS | клавиша очистки до конца экрана |
kt | клавиша очистки данной табуляции |
kT | клавиша установки табуляции на этом месте |
ku | клавиша курсор - up |
l0 | метка для нулевой функциональной клавиши, если не f0 |
l1 | метка для первой функциональной клавиши, если не f1 |
l2 | метка для второй функциональной клавиши, если не f2 |
... | |
la | метка для десятой функциональной клавиши, если не f10 |
le | курсор влево на 1 символ |
ll | перемещение курсора в нижний левый угол |
LE | курсор влево на %1 символов |
LF | отключение мягких меток |
LO | включение мягких меток |
mb | начало мерцания |
MC | очистка мягких границ |
md | начало режима верхнего регистра |
me | конец всех режимов типа so, us, mb, md, mr |
mh | начало полуяркого режима |
mk | начало темного режима (символы не видны) |
ML | установка левой мягкой границы |
mm | вход терминала в метарежим |
mo | выход терминала из метарежима |
mp | включение защищенного атрибута |
mr | начало режима обращения (reverse mode) |
MR | установка правой мягкой границы |
nd | курсор на 1 символ влево |
nw | команда возврата каретки |
pc | символ-заполнитель |
pf | отключение принтера |
pk | программная клавиша %1 для посылки строки %2, если нажата пользователем |
pl | программная клавиша %1 для исполнения строки %2 в локальном режиме |
pn | программная мягкая метка %1 для отображения строки %2 |
po | подключение принтера |
pO | подключение принтера для %1 (<256) байт |
ps | печать содержимого экрана на принтере |
px | программная клавиша %1 для посылки строки %2 в компьютер |
r1 | сброс строки 1, установка нормальных режимов |
r2 | сброс строки 2, установка нормальных режимов |
r3 | сброс строки 3, установка нормальных режимов |
RA | отключение автоматических границ |
rc | восстановление сохраненной позиции курсора |
rf | сброс строки имени файла |
RF | требование ввода с терминала |
RI | курсор вправо на %1 символов |
rp | повторение символа %1 %2 раз |
rP | заполнение после присланного символа в режиме замены |
rs | сброс строки |
RX | выключение XON/XOFF управления |
sa | установка атрибутов %1 %2 %3 %4 %5 %6 %7 %8 %9 |
SA | включение автоматических границ |
sc | сохранение позиции курсора |
se | конец режима стандартного вывода |
sf | нормальная прокрутка на одну линию |
SF | нормальная прокрутка на %1 линию |
so | начало режима стандартного вывода |
sr | обратная прокрутка |
SR | прокрутка назад на %1 линию |
st | установка табуляции во всех линиях в данной колонке |
SX | включение XON/XOFF управления |
ta | перемещение к следующей табуляции физического устройства |
tc | чтение в описании терминала с другой точки входа |
te | конец программы, использующей движение курсора |
ti | начало программы, использующей движение курсора |
ts | перемещение курсора на столбец %1 линии статуса |
uc | подчеркивание символа под курсором и движение курсора вправо |
ue | конец подчеркивания |
up | курсор на 1 линию вверх |
UP | курсор на %1 линию вверх |
us | начало подчеркивания |
vb | видимый звонок |
ve | нормальный видимый курсор |
vi | невидимый курсор |
vs | курсор стандартного вывода |
wi | установка окна с линии %1 до линии %2 и столбцов с %3 до %4 |
XF | символ XOFF, если не ^S |
8.3. Введение в ncurses
В этом разделе будем пользоваться следующей терминологией.
- окно (window) - внутреннее представление, содержащее изображение части экрана. WINDOW определен в ncurses.h.
- экран (screen) - это окно размером в целый экран (с верхнего левого до нижнего правого угла). Экранами являются stdscr и curscr.
- терминал (terminal) - специальный экран с информацией о том, как выглядит экран на данный момент.
- переменные - следующие переменные и константы, определенные в ncurses.h:
- WINDOW *curscr - текущий экран
- WINDOW *stdscr - стандартный экран
- int LINES - полосы на терминале
- int COLS - колонки на терминале
- bool TRUE - флаг истины, 1
- bool FALSE - флаг лжи, 0
- int ERR - флаг ошибки, -1
- int OK - флаг ok, 0
- функции - в описаниях функций аргументы будут следующих типов:
- win - WINDOW*
- bf - bool
- ch - chtype
- str - char*
- chstr - chtype*
- fmt - char*
- иначе int
Обычно программа, использующая ncurses, выглядит так:
#include <ncurses.h> ... main() { ... initscr(); /* вызов функции ncurses */ endwin(); ... }
Подключение ncurses.h определит переменные и типы для ncurses, такие как WINDOW, и прототипы функций. Автоматически подключатся stdio.h, stdarg.h, termios.h, unctrl.h.
initscr() используется для инициализации структур данных ncurses и для чтения файла terminfo. Будет захвачена память под stdscr и curscr. Если произойдет ошибка, то initscr вернет ERR. В противном случае возвращается указатель на stdscr. Кроме этого, экран будет очищен и будут проинициализированы LINES и COLS.
endwin() очистит все выделенные ресурсы ncurses и восстановит режимы tty, какими они были до вызова initscr(). Функция endwin() должна вызываться перед любой другой функцией из библиотеки ncurses и перед выходом из вашей программы. Если вы хотите использовать для вывода более чем один терминал, используйте newterm(...) вместо initscr().
Компилируйте программу посредством:
gcc [flags] files -lncurses
Вы можете устанавливать любые флаги (см. gcc(1)). Если путь к ncurses.h изменился, вы должны включить следующую строку, иначе ncurses.h, nterm.h, termcap.h и unctrl.h не будут найдены:
-I/usr/include/ncurses
Другие возможные в Linux-е флаги: -O2 -ansi -Wall -m486. O2 скажет gcc произвести некоторую оптимизацию; -ansi - для ANSI си-кода; -Wall выведет все предупреждения; -m486 оптимизирует код для Intel 486 (можно и для Intel 386).
Библиотека ncurses находится в /usr/lib/. Существует 3 версии библиотеки:
- libncurses.a - обычная ncurses
- libdcurses.a - ncurses для отладки
- libpcurses.a - ncurses для профилирования (существует ли что-нибудь после 1.8.6libcurses.a?)
- libcurses.a - не четвертая версия, это первоначальная BSD curses
Структуры данных для экрана называются windows и определены в ncurses.h. Окно - это нечто типа литерного массива в памяти, которым программист может манипулировать без вывода на терминал. При помощи newwin(...) вы можете создать другие окна.
Чтобы оптимально обновить физический терминал, ncurses имеет другое окно, curscr. Это изображение, реально выводимое на экран. Для отображения stdscr на экране используется функция refresh(). После этого ncurses обновит curscr и физический терминал содержимым stdscr. Библиотечные функции произведут внутреннюю оптимизацию для процесса обновления, поэтому вы можете менять различные окна и затем обновлять экран сразу самым оптимальным способом.
Функциями ncurses вы можете работать со структурой данных window. Функции, начинающиеся с w, позволяют назначать окно window, тогда как остальные обычно имеют дело с stdscr. Функции, начинающиеся с mv, прежде всего переместят курсор на позицию y,x.
Символы имеют тип chtype, который является long unsigned int, чтобы сохранять дополнительную информацию о себе (атрибуты и т.д.).
Библиотека ncurses использует базу данных terminfo. Обычно она находится в usr/lib/terminfo/, и ncurses обращается туда за локальными определениями терминала. Если вы хотите проверить некоторые другие определения для терминала, не исправляя первоначальную terminfo, установите соответственно переменную среды TERMINFO. Эта переменная будет протестирована ncurses, и вместо usr/lib/terminfo/ сохранятся ваши определения.
Tекущей версией ncurses является 1.8.6.
В конце этого раздела вы найдете обзорную таблицу для BSD-Curses, ncurses и Sun-OS 5.4 curses.
8.4. Инициализация
* WINDOW *initscr()
Обычно это первая функция, вызываемая из программы, использующей ncurses. В некоторых случаях полезно вызывать slk_init(int), filter(), ripoffline(...) или use_env(bf) перед initscr(). Для работы с несколькими терминалами (или тестирования возможностей системы) вы можете использовать newterm(...) вместо initscr(). initscr() прочитает terminfo файл и установит структуры данных ncurses, выделит память для curscr и stdscr и проинициализирует переменные LINES и COLS значениями, соответствующими вашему терминалу. Будет возвращен указатель на stdscr или ERR в случае ошибки. Вам НЕ нужно инициализировать указатель. stdscr=initscr(); поскольку initscr() сделает это за вас. Если возвращен ERR, ваша программа должна завершиться, поскольку ни одна функция ncurses не будет работать:
if(!(initscr())){ fprintf(stderr,"type: initscr() failed\n\n"); exit (1); }
* SCREEN *newterm(char *type, FILE *outfd, FILE *infd)
Работая в ncurses с несколькими терминалами, вы должны вызвать для каждого из них newterm(...) вместо initscr(). type - это имя терминала как оно содержится в $TERM (ansi, xterm, vt100, например); outfd - это указатель для вывода, infd - указатель для ввода. Для каждого терминала, открытого newterm(...), следует вызывать endwin().
* SCREEN *set_term(SCREEN *new)
При помощи set_term(SCREEN) вы можете переключать текущий терминал. Все функции будут работать с текущим терминалом, установленным set_term(SCREEN).
* int endwin()
endwin() произведет очистку, восстановит режимы терминала, сохраненные перед вызовом initscr(), и поставит курсор в левый верхний угол экрана. Не забудьте закрыть все окна перед тем, как вызвать endwin(), перед выходом из вашей программы. Дополнительный вызов refresh() после endwin() восстановит содержимое терминала, отображавшееся до вызова initscr() (visual-mode), в противном случае экран будет очищен (non-visual-mode).
* int isendwin()
Возвращает TRUE, если после endwin() была вызвана refresh(), иначе - FALSE.
* void delscreen(SCREEN *sp)
Вызывается после endwin() для высвобождения всех занятых ресурсов, когда SCREEN больше не нужен. (Пока не реализована.)
8.5. Окна
Окна могут быть созданы, уничтожены, перемещены, скопированы, задублированы и т.д.
* WINDOW *newwin(nlines, ncols, begy, begx)
begy и begx - координаты верхнего левого угла окна. nlines - это число линий (integer); ncols - число колонок (integer).
WINDOW *mywin; mywin=newwin(10,60,10,10);
Верхний левый угол нашего окна находится на линии 10 в колонке 10; окно имеет 10 линий и 60 колонок. Если nlines равна нулю, окно будет иметь (LINES - begy) полос. Точно так же, если ncols равна нулю, то окно будет иметь (COLS - begx) колонок. Когда мы вызываем newwin(...) с нулевыми аргументами:
WINDOW *mywin; mywin=newwin(0,0,0,0);
открытое окно получает размеры экрана.
При помощи LINES и COLS мы можем открыть окно на середине экрана, какую бы размерность оно ни имело:
0 begx | | 0 | | COLS - - - - -------|-------------------------|-------> | | ncols | begy | |<. . . . . . . . . . . .>| - - - -|- - - -|-------------------------| | ^| | | .| | | .| | |nlines.| newwin(nlines, ncols, | | .| begy, begx) | | v| | |- - - -|-------------------------| LINES | v #define MYLINE (int) ((LINES-22)/2) #define MYCOL ((COLS-70)/2) #define MYLINES 22 #define MYCOLS 70 ... WINDOW *win; ... if(!(initscr())){ fprintf(stderr, "type: iniscr() failed\n\n"); exit(1); } ... if ((LINES<22)||(COLS<70)){ fprintf(stderr, "screen too small\n\n"); endwin(); exit (1); } win=newwin(MYLINES,MYCOLS,MYLINE,MYCOL); ...
Откроется окно с 22 линиями и 70 колонками в середине экрана. Проверьте размер экрана перед тем, как открывать окно. Консоль Linux-а имеет не менее 25 линий и 80 колонок, но на x-терминалах это может не выполняться (их размеры изменяемы).
С другой стороны, используйте LINES и COLS, чтобы поместить два окна в один экран:
#define MYROWS (int) (LINES/2+LINES/4) #define MYCOLS (int) (COLS/2+COLS/4) #define LEFTROW (int) ((LINES-MYROWS)/2) #define LEFTCOL (int) (((COLS-2)-MYCOLS)/2) #define RIGHTROW (int) (LEFTROW) #define RIGHTCOL (int) (LEFTROW+2+MYCOLS) #define WCOLS (int) (MYCOLS/2) ... WINDOW *leftwin, *rightwin; ... leftwin=newwin(MYROWS, WCOLS, LEFTROW, LEFTCOL); rightwin=newwin(MYROWS, WCOLS, RIGHTROW, RIGHTCOL); ...
Подробнее смотрите screen.c в директории с примерами.
*int delwin(win)
Удаляет окно win. Подокна win удаляются перед win. Будут освобождены все ресурсы, занятые win. Удаляйте все открытые вами окна перед вызовом endwin().
*int mvwin(win, by, bx)
Перемещает окно на координаты by,bx. Если это означает выход за пределы экрана, то ничего не произойдет и будет возвращен ERR.
* WINDOW *subwin(origwin, nlines, ncols, begy, begx)
Возвращает подокно в середине origwin-а. Когда вы изменяете одно из двух окон (origwin или новое), это изменение отразится на обоих окнах. Вызывайте touchwin(origwin) перед следующим refresh(). begx и begy относятся не к origwin, а к экрану.
* WINDOW *derwin(origwin, nlines, ncols, begy, begx)
То же, что subwin(), begx и begy относятся не к экрану, а к origwin.
* int mvderwin(win, y, x)
Перенесет win за пределы родительского окна. (Пока не реализована.)
* WINDOW *dupwin(win)
Дублирует окно win.
* int syncok(win, bf)
void wsyncup(win)
void wcursyncup(win)
void wsyncdown(win)
(Пока не реализованы.)
* int overlay(win1, win2)
int overwrite(win1, win2)
overlay(...) скопирует весь текст из win1 в win2, игнорируя пропуски. overwrite(...) делает то же самое, но копирует вместе с пропусками.
* int copywin(win1, win2, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay)
То же, что overlay(...) и overwrite(...), но позволяет контролировать область окна для копирования.
8.6. Вывод
* int addch(ch) int waddch(win, ch) int mvaddch(y, x, ch) int mvwaddch(win, y, x, ch)
Эти функции выводят символ в окно. Они работают с окном; вам нужно вызвать refresh(), чтобы поместить окно на экран. Функции addch(...) и waddch(...) помещают символ ch в окно stdscr или win. mvaddch(...) и mvwaddch(...) предварительно ставят курсор на позицию y,x.
* int addstr(str) int addnstr(str, n) int waddstr(win, str) int waddnstr(win, str, n) int mvaddstr(y, x, str) int mvaddnstr(y, x, str, n) int mvwaddstr(win, y, x, str) int mvwaddnstr(win, y, x, str, n)
Эти функции заносят строку в окно и эквивалентны сериям вызовов addch(...). str - это строка, заканчивающаяся символом с кодом 0 ("кукареку\0"). Функции, начинающиеся с w, заносят str в окно win, остальные - в stdscr. Функции с n пишут n символов строки str. Если n равен -1, будет записана вся строка.
* int addchstr(chstr) int addchnstr(chstr, n) int waddchstr(win, chstr) int waddchnstr(win, chstr, n) int mvaddchstr(y, x, chstr) int mvaddchnstr(y, x, chstr, n) int mvwaddchstr(win, y, x, chstr) int mvwaddchnstr(win, y, x, chstr, n)
Эти функции копируют chstr в окно stdscr или win. Начальной позицией является позиция курсора. Функции с n пишут n символов строки chstr. Если n равен -1, будет записана вся строка. Курсор не двигается и символы не контролируются. Эти функции быстрее, чем addstr(...). chstr является указателем на массив элементов chtype.
* int echochar(ch) int wechochar(win, ch)
То же, что addch(...), waddch(win), с последующим refresh(), wrefresh(win).
8.6.1. Форматированный вывод
* int printw(fmt, ...) int wprintw(win, fmt, ...) int mvprintw(y, x, fmt, ...) int mvwprintw(win, y, x, fmt, ...) int vwprintw(win, fmt, va_list)
Эти функции соответствуют printf(...) и подобным ей функциям libc. В libc printf(...) используется для форматированного вывода. Вы можете определять выводимую строку и включать в нее переменные различных типов. Подробнее смотрите раздел 8.1.1. vwprintw(...) требует подключения varargs.h.
8.6.2. Вставка символов и линий
* int insch(c) int winsch(win, c) int mvinsch(y, x, c) int mvwinsch(win, y, x, c)
Символ ch вставляется слева от курсора, и все символы сдвигаются на одну позицию вправо. Самый правый символ строки может быть потерян.
* int insertln() int winsertln(win)
Вставляет чистую строку над текущей. Нижняя строка будет потеряна.
* int insdelln(n) int winsdelln(win, n)
Для положительного n эти функции вставляют n линий в соответствующем окне (n нижних линий будут потеряны). Для отрицательных n будут удалены n линий под курсором, оставшиеся сдвинутся вверх.
* int insstr(str) int insnstr(str, n) int winsstr(win, str) int winsnstr(win, str, n) int mvinsstr(y, x, str) int mvinsnstr(y, x, str, n) int mvwinsstr(win, y, x, str) int mvwinsnstr(win, y, x, str, n)
Эти функции занесут str в текущую строку слева от курсора (сколько возможно до конца строки). Символы справа от курсора сдвигаются вправо и удаляются достигнув конца строки. Курсор остается на месте. y и x - координаты, на которые переместится курсор перед вставкой str; n - это число вставляемых символов (n=0 вводит чистую строку).
8.6.3. Удаление символов и линий
* int delch() int wdelch(win) int mvdelch(y, x) int mvwdelch(win, y, x)
Удаление символа под курсором и сдвиг оставшейся справа от курсора строки на одну позицию влево.
y и x - координаты, на которые курсор переместится перед удалением.
* int deleteln() int wdeleteln(win)
Удаление строки под курсором и перемещение нижележащих линий на одну позицию вверх. Последняя линия окна будет очищена.
8.6.4. Боксы и линии
* int border(ls, rs, ts, bs, tl, tr, bl, br) int wborder(win, ls, rs, ts, bs, tl, tr, bl, br) int box(win, vert, hor)
Очерчивают соответствующее окно (stdscr или win). В таблице 8.3 вы увидите символы и их значения по умолчанию для box(...). На картинке вы увидите позиции символов для бокса.
* int vline(ch, n) int wvline(win, ch, n) int hline(ch, n) int whline(win, ch, n)
Эти функции вычерчивают вертикальную или горизонтальную прямую начиная с позиции курсора. ch - это используемый символ, n - число таких символов. Позиция курсора не изменяется.
8.6.5. Фоновый (background) символ
* void bkgdset(ch) void wbkgdset(win, ch)
Устанавливает фоновый символ и атрибут для экрана или окна. Атрибут в ch будет OR-нут с каждым непробельным символом окна. Фон становится частью окна и не изменяется при прокрутке и вводе/выводе.
Таблица 8.3: ncurses - ограничительные символы
Литера | Позиция | По умолчанию -------|----------------------|---------------------- tl | левая верхняя | ACS_ULCORNER ts | верхняя сторона | ACS_HLINE tr | правая верхняя | ACS_URCORNER ls | левая сторона | ACS_VLINE rs | правая сторона | ACS_VLINE bl | левая нижняя | ACS_LLCORNER bs | нижняя сторона | ACS_HLINE br | правая нижняя | ACS_LRCORNER rt | правая средняя | ACS_RTEE lt | левая средняя | ACS_LTEE tt | верхняя средняя | ACS_TTEE bt | нижняя средняя | ACS_BTEE Рисунок 8.2: ncurses - символы бокса tl ts tt ts tr |------------|------------| | | ls| | |rs | | | | | lt|- - - - - - - - - - - - -|rt | | | | | ls| | |rs | | |------------|------------| bl bs bt bs br * int bkgd(ch) int wbkgd(win, ch)
Установит в ch фоновый символ и атрибут.
8.7. Ввод
* int getch() int wgetch(win) int mvgetch(y, x) int mvwgetch(win, y, x) getch()
прочитает ввод с терминала. Если режим паузы установлен, getch() будет ждать нажатия клавиши. Если нет - вернет клавишу из буфера ввода или ERR, если буфер пуст. mvgetch(...) и mvwgetch(...) сначала установят курсор на позицию y,x. w-функции читают ввод с терминала, связанного с окном win, getch() и mvgetch(...) - с stdscr.
Со включенной keypad(...) при нажатии функциональной клавиши getch() вернет код, определенный в ncurses.h как макрос KEY_*. При нажатии ESCAPE (который может быть началом функциональной клавиши) ncurses запустит односекундный таймер. Если остаток не получен в течение этой секунды, то возвращается ESCAPE, иначе - значение функциональной клавиши. При необходимости секундный таймер можно отключить через notimeout().
* int ungetch(ch) Вернет ch в буфер ввода. * int getstr(str) int wgetstr(win, str) int mvgetstr(y, x, str) int mvwgetstr(win, y, x, str) int wgetnstr(win, str, n)
Эти функции проделают серию вызовов getch(), пока не будет получена новая линия. Символы помещаются в str, поэтому не забывайте захватывать память для вашего символьного указателя перед вызовом getstr(...). Если включено эхо, то строка отображается (используйте noecho(), чтобы его отключить) и пользовательские символы удаления будут проинтерпретированы.
* chtype inch() chtype winch(win) chtype mvinch(y, x) chtype mvwinch(win, y, x)
Эти функции возвращают литеру с экрана или окна. Поскольку возвращается тип chtype, возвращается и атрибут. Информация об атрибуте может быть получена с помощью констант A_* (см. таблицу 8.4).
* int instr(str) int innstr(str, n) int winstr(win, str) int winnstr(win, str, n) int mvinstr(y, x, str) int mvinnstr(y, x, str, n) int mvwinstr(win, y, x, str) int mvwinnstr(win, y, x, str, n)
Возвращает символьную строку из экрана или окна. (Пока не реализована.)
* int inchstr(chstr) int inchnstr(chstr, n) int winchstr(win, chstr) int winchnstr(win, chstr, n) int mvinchstr(y, x, chstr) int mvinchnstr(y, x, chstr, n) int mvwinchstr(win, y, x, chstr) int mvwinchnstr(win, y, x, chstr, n)
Возвращает строку типа chtype из экрана или окна вместе с атрибутом для каждого символа. (Пока не реализована; lib_inchstr не включена в библиотеку ncurses.)
8.7.1. Форматированный ввод
* int scanw(fmt, ...) int wscanw(win, fmt, ...) int mvscanw(y, x, fmt, ...) int mvwscanw(win, y, x, fmt, ...) int vwscanw(win, fmt, va_list)
Функции эквивалентны scanf(...) из libc (см. раздел 8.1.2). Входом для сканирования служит вызов wgetstr(...).
8.8. Опции
Опции вывода
* int idlok(win, bf) void idcok(win, bf)
Включение и отключение возможностей вставки/удаления для окна терминала (idlok(...) для линий, idcok(...) - для символов). (idcok(...) пока не реализована.)
* void immedok(win, bf)
Если устанавливается TRUE, то каждое изменение в окне вызывает физическое обновление экрана. Это может ухудшить характеристики программы, поэтому значение по умолчанию - FALSE. (Пока не реализована.)
|-------|-------|-------| |-------|-------|-------|-------| | ??? | KEY_ | KEY_ | | NUM | / | * | - | | | HOME | PPAGE | | | | | | |-------|-------|-------| |-------|-------|-------|-------| | CTRL | KEY_ | KEY_ | | KEY_ | KEY_ | KEY_ | | | +D | END | NPAGE | | HOME | UP | PPAGE | | |-------|-------|-------| |-------|-------|-------| + | | KEY_ | ??? | KEY_ | | | LEFT | | RIGHT | | |-------| |-------|-------|-------|-------| | KEY_ | | KEY_ | KEY_ | KEY_ | | | UP | | END | DOWN | NPAGE | CTRL | |-------|-------|-------| |-------|-------|-------| +M | | KEY_ | KEY_ | KEY_ | | ??? | KEY_ | | | LEFT | DOWN | RIGHT | | | DC | | |-------|-------|-------| |-------|-------|-------|-------| * int clearok(win, bf)
Если bf равен TRUE, то следующий вызов wrefresh(win) очистит экран и полностью его перерисует (Ctrl+L в редакторе vi).
* int leaveok(win, bf)
По умолчанию ncurses ставит курсор там, где он был при последнем обновлении окна. Программы, не использующие курсор, могут установить leaveok(...) TRUE и сэкономить время, требующееся движения курсора. Кроме того, ncurses попытается сделать курсор терминала невидимым.
* int nl() nonl()
Управление переходом на новую строку. После nl() произойдетт возврат каретки и дозаполнение; nonl() отключает контроль. В последнем случае ncurses может ускорить перемещение курсора.