Reputation: 165
I am trying to change the color of text in the console.
We are supposed to use a config file to read the ansi escape codes from:
this is what's in my file
red \033[0;31m #red
blue \033[0;34m #blue
green \033[0;32m #green
grey \033[0;37m #grey
Here is my code:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <fstream>
#include <map>
using namespace std;
int main(int argc, char * argv[]){
string file = "config.txt";
string line = "";
string tag = "";
string ansi = "";
map <string, string> m;
if(argc == 2){
file = argv[1];
}
ifstream in(file, ios_base::in | ios_base::binary);
if(!in){
cerr<<"could not open file";
}
while (getline(in, line)){
istringstream iss(line);
if(iss>>tag>>ansi){
auto it = m.find(tag);
if(it == m.end()){
m.insert(make_pair(tag,ansi));
}
}
}
for(auto x: m){
cout<<x.second<<x.first<<endl;
}
cout<<"\033[0;35mhello";
return 0;
}
Not sure why but only the last print statement actually displays in color the other outputs the ansi escape codes as text.
Here is my output :
\033[0;34mblue
\033[0;32mgreen
\033[0;37mgrey
\033[0;31mred
hello (in purple)
Upvotes: 5
Views: 5209
Reputation: 201
Instead of doing this:
cout<<"\033[0;35mhello";
C++ offers possibility to write your own stream manipilator like std::endl to handle escape code.
The goal is to write code like this that seems more readable for me:
cout << ansi::foreground_magenta << "hello" ;
For writing your own stream manipulators you can proceed like this for instance (simple raw implementation, but you will require to take value from your map...):
#include <ostream>
namespace ansi {
template < class CharT, class Traits >
constexpr
std::basic_ostream< CharT, Traits > & reset( std::basic_ostream< CharT, Traits > &os )
{
return os << "\033[0m";
}
template < class CharT, class Traits >
constexpr
std::basic_ostream< CharT, Traits > & foreground_black( std::basic_ostream< CharT, Traits > &os )
{
return os << "\033[30m";
}
template < class CharT, class Traits >
constexpr
std::basic_ostream< CharT, Traits > & foreground_red( std::basic_ostream< CharT, Traits > &os )
{
return os << "\033[31m";
}
...
} // ansi
Alternatively, C offers possiblity to use #define to create constants.
#define foreground_magenta "\033[35m"
Upvotes: 6
Reputation: 206577
The problem with reading the config.txt files is that the string is read as though it is assigned to be:
std::string str = "\\033[0;31m";
i.e. the \
is treated as a character. What you need in code is "\033"
, i.e. the character represented by the octal number 033
.
You can change the following lines in your code to ignore the "\\033"
part of the string and print the octal number.
cout << x.second << x.first <<endl;
needs to be:
cout << '\033' << x.second.substr(4) << x.first <<endl;
With that change, I tried your program on my desktop and it works as expected.
Upvotes: 2
Reputation: 75062
The escape sequence in the file won't converted to ESC character.
Moreover, your file has common parts.
For that reason, I moved the common parts that contain ESC character to program and had the configuration file have only the color codes.
File:
red 31 #red
blue 34 #blue
green 32 #green
grey 37 #grey
Program:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <fstream>
#include <map>
using namespace std;
int main(int argc, char * argv[]){
string file = "config.txt";
string line = "";
string tag = "";
string ansi = "";
map <string, string> m;
if(argc == 2){
file = argv[1];
}
ifstream in(file, ios_base::in | ios_base::binary);
if(!in){
cerr<<"could not open file";
}
while (getline(in, line)){
istringstream iss(line);
if(iss>>tag>>ansi){
auto it = m.find(tag);
if(it == m.end()){
m.insert(make_pair(tag,ansi));
}
}
}
for(auto x: m){
cout<<"\033[0;"<<x.second<<"m"<<x.first<<endl;
}
cout<<"\033[0;35mhello";
return 0;
}
Upvotes: 1