Так Вам нравится цвет!!!
(Таинственные символы ^[[)

  Автор: © Pradeep Padala
Перевод: © Иван Песин.


 

Пробовали ли вы когда-нибудь перенаправлять вывод программы, использующей библиотеку curses? Удивляли ли вас таинственные символы ^[[ ? Пробовали ли вы получать цвета с помощью команды printf, без использования библиотек curses? Если хотя бы на один из этих вопросов ответ - "да", то эта статья для вас...

Статья попытается объяснить загадочные символы, которые можно найти в выводе "curses-программы", работающей с цветами. Потом, мы расширим наши представления, дабы получать цвета с помощью обычной команды printf.

Терминальные коды

В старые времена телетайпных терминалов, последние находились далеко от компьютеров и были связаны с ними последовательными кабелями. Терминалы могли быть настроены с помощью посылки набора байтов к каждому из них. Всеми возможностями терминалов можно было управлять такими наборами байтов, которые обычно назывались эскейп-последовательностями (esc-последовательностями), потому как начинаются они с символа escape(0x1B). Даже в наши дни, работая с эмуляцией терминала vt100, мы можем послать esc-последовательность эмулятору, и это будет иметь тот же эффект, что и на терминале.

Наберите на вашей консоли следующее:

	echo "^[[0;31;40mIn Color"

Первый символ является символом escape, и выглядит как два символа ^ и [. Что бы ввести этот символ, вам необходимо нажать CTRL+V а потом клавишу ESC. Все остальные символы являются обычными печатными. Вы увидите строку "В цвете" красного цвета. Консоль так и останется в режиме красного цвета и что бы вернуть обычное состояние, надо ввести теперь:

	echo "^[[0;37;40m"

Как вы можете видеть, достаточно просто устанавливать и сбрасывать цвет. Существует несметное число esc-последовательностей, с помощью которых вы можете выполнять множество вещей, как-то: перемещать курсор, сбрасывать терминал и т.п.

Последовательность для установки цветов: [{attr};{fg};{bg}m

Я объясню esc-последовательность для установки цветов. Последовательность, которая должна быть выведена на терминал, следующая:

	<ESC>[{attr};{fg};{bg}m

Первый символ - это ESC, который вводится нажатием CTRL+V и ESC на Linux-консоли или же в xterm, konsole, kvt, и т.д. ("CTRL+V ESC" можно применять и в vim для вставки символа ESC). Далее {attr}, {fg}, {bg} должны быть заменены верными значениями для получения соответствующего эффекта. attr - это атрибут, вроде мигания или подчёркивания. fg и bg - это цвета символов и фона соответственно. Вам не нужно брать номера в фигурные скобки. Просто напишите их, и этого достаточно.

{attr} может принимать следующие значения:

	0	сбросить все атрибуты (вернуться в нормальный режим)
	1	яркий (обычно включает толстый шрифт)
	2 	тусклый
	3	подчёркнутый
	5	мигающий
	7 	реверсный
	8	невидимый


{fg} может принимать следующие значения:

	30	чёрный
	31	красный
	32	зелёный
	33	жёлтый
	34	синий
	35	фиолетовый
	36	голубой
	37	белый


{bg} может принимать следующие значения:

	40	чёрный
	41	красный
	42	зелёный
	43	жёлтый
	44	синий
	45	фиолетовый
	46	голубой
	47	белый

Так, для получения мигающего синего текста на зелёном фоне, нужно вывести следующую комбинацию:

echo "^[[5;34;42mIn color"
что выглядит очень мерзко. :-) Вернём все назад:
echo "^[0;37;40m"

С помощью функции printf() ...

Что, если вы хотите использовать эти возможности в С-программе? Элементарно! Перед тем, как что-либо вывести функцией printf, необходимо вывести нужную последовательность. Я написал небольшую функцию textcolor(), которая делает это автоматически. Вы можете использовать её в своих программах вместе с #define константами. Текстовая версия программы находится здесь

textcolor()

#include <stdio.h>

#define RESET		0
#define BRIGHT 		1
#define DIM		2
#define UNDERLINE 	3
#define BLINK		4
#define REVERSE		7
#define HIDDEN		8

#define BLACK 		0
#define RED		1
#define GREEN		2
#define YELLOW		3
#define BLUE		4
#define MAGENTA		5
#define CYAN		6
#define	WHITE		7

void textcolor(int attr, int fg, int bg);
int main()
{	textcolor(BRIGHT, RED, BLACK);	
	printf("В цвете\n");
	textcolor(RESET, WHITE, BLACK);	
	return 0;
}

void textcolor(int attr, int fg, int bg)
{	char command[13];

	/* Command - это управляющая команда терминалу */
	sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
	printf("%s", command);
}

Функция textcolor() - аналог функции API из Turbo C . Вы вызываете функцию для установки цвета, а после выводите информацию командой sprintf() (функция, которая используется в Turbo C для вывода в цвете).

Демонстрация цветов

#include <stdio.h>

#define RESET		0
#define BRIGHT 		1
#define DIM		2
#define UNDERLINE 	3
#define BLINK		4
#define REVERSE		7
#define HIDDEN		8

#define BLACK 		0
#define RED		1
#define GREEN		2
#define YELLOW		3
#define BLUE		4
#define MAGENTA		5
#define CYAN		6
#define	WHITE		7

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

char *attrs[] = {"NORMAL", "BRIGHT", "DIM", "UNDERLINE", "BLINK",
		 "REVERSE", "HIDDEN", "EXIT"};
char *colors[] = {"BLACK", "RED", "GREEN", "YELLOW", "BLUE", "MAGENTA",
		 "CYAN", "WHITE", "EXIT"};
void textcolor(int attr, int fg, int bg);
int print_menu(char *array[], int n_options, char *title);
int main()
{	int attr, fg, bg;
	int attr_size, colors_size;
	
	attr_size = ARRAY_SIZE(attrs);
	colors_size = ARRAY_SIZE(colors);
	while(1)
	{	printf("\n");
		attr = print_menu(attrs, attr_size, "Выберите атрибут:");
		if(attr == attr_size - 1)
			break;
		fg = print_menu(colors, colors_size, "Выберите цвет символов:");
		if(attr == colors_size - 1)
			break;
		bg = print_menu(colors, colors_size, "Выберите цвет фона:");
		if(attr == colors_size - 1)
			break;
		printf("\n");
		textcolor(attr, fg, bg);	
		printf("Это - пример того, что вы получите, используя комбинацию 
атрибута %s, цвета символов %s, и цвета фона - %s", attrs[attr], colors[fg], colors[bg]);
		textcolor(RESET, WHITE, BLACK);
		system("clear");
	}
	return 0;
}

int print_menu(char *array[], int n_options, char *title)
{	int choice, i;
	for(i = 0;i < n_options; ++i)
		printf("%d.%s\n", i, array[i]);
	printf("%s", title);
	scanf("%d", &choice);
	return choice;
}		
void textcolor(int attr, int fg, int bg)
{	char command[13];

	/*  Command - это управляющая команда терминалу  */
	sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
	printf("%s", command);
}

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

Выгода

В чем же выгода? Если получение цветов так просто, почему люди гробят своё время на написание громоздких программ с помощью curses, которая направляет запрос в базу данных terminfo общим путём? Как мы знаем, существует много типов терминалов с малыми возможностями и терминалов, которые не распознают указанных esc-последовательностей, либо имеют другой набор кодов. Так что, если вы хотите написать портируемую программу, которая работала бы с любым терминалом с аналогичной (или уменьшенной) функциональностью, вы должны использовать библиотеку curses. Она использует базу terminfo для нахождения верных последовательностей, необходимых для корректного выполнения задачи. Terminfo - это большая база, которая содержит информацию о различных возможностях разных терминалов.

Если же вы желаете написать маленькую программу, которая работает с цветами на консоли Linux, либо в окне эмулятора xterm, вы можете преспокойно использовать esc-последовательности. Консоль Linux, в основном, эмулирует vt100, так что она понимает указанные выше последовательности.

С помощью tput ...

Существует, однако, способ сделать запрос к базе данных terminfo и выполнить соответствующие указания. Команда tput посылает запрос и выполняет указанную вами функцию. Две опции setf и setb используются для установки цвета текста и фона. Что бы установить цвет текста в красный, а цвет фона в зелёный, необходимо выполнить следующие команды:

	tput setf 4	# tput setf {номер цвета символов }
	tput setb 2	# tput setb {номер цвета фона}

Это можно использовать в сценариях shell где угодно. Другие возможности команды tput описаны в руководстве. Руководство по terminfo содержит много информации, касающейся возможностей терминалов - как получить и установить их значения и многое другое. Есть два руководства по terminfo. "man 5 terminfo" описывает базу данных terminfo. "man 3ncurses terminfo" описывает C-функции, которые используют эту базу.

Тут приведены номера цветов, которые нужно передавать в качестве аргументов командам "tput setf" и "tput setb".

	0	чёрный
	1	красный
	2	зелёный
	3	жёлтый
	4	синий
	5	фиолетовый
	6	голубой
	7	белый

Веселитесь!!!

Ссылки

 


Copyright © 2001, Pradeep Padala.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 65 of Linux Gazette, April 2001

Вернуться на главную страницу