// cpphigh (c) 2011 org100h.com
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
const string header = "<html><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><body><font face=\"Consolas, Meiryo\">";
const string footer = "</font></body></html>";
const string hightable[] = {
"#if", "#ifdef", "#ifndef", "#elif", "#else",
"#endif", "#include", "#define", "#undef", "#line",
"#error", "#pragma",
"const_cast", "reinterpret_cast", "static_cast", "unsigned",
"asm", "auto", "bool", "break", "case",
"catch", "char", "class", "const", "const_cast",
"continue", "default", "delete", "do", "double",
"dynamic_cast", "else", "enum", "explicit", "export",
"extern", "false", "float", "for", "friend",
"goto", "if", "inline", "int", "long",
"mutable", "namespace", "new", "operator", "private",
"protected", "public", "register", "reinterpret_cast", "return",
"short", "signed", "sizeof", "static", "static_cast",
"struct", "switch", "template", "this", "throw",
"true", "try", "typedef", "typeid", "typename",
"union", "unsigned", "using", "virtual", "void",
"volatile", "wchar_t", "while",
};
const auto hightablesize = sizeof(hightable) / sizeof(*hightable);
const string delim = "{}[]#();:?.+-*/%^&|~!=<>, ";
const struct {
const char * ch;
const char * esc;
} esctable[] = {
"<", "<",
">", ">",
"&", "&",
"\"", """,
" ", " ",
};
const auto esctablesize = sizeof(esctable) / sizeof(*esctable);
string tab2space(const string & line, long tabstop) {
string dst;
auto index = 0;
for(auto I = line.begin(); I != line.end(); I++) {
if(*I == '\t') {
do {
dst.push_back(' ');
index++;
} while(index % tabstop != 0);
} else {
dst.push_back(*I);
index++;
}
}
return dst;
}
string line_escape(const string & line) {
string dst;
string target;
for(auto I = line.begin(); I != line.end(); ++I) {
target = *I;
for(auto index = 0; index < esctablesize; index++) {
if(string(esctable[index].ch) == target) {
target = esctable[index].esc;
}
}
dst += target;
}
return dst;
}
bool is_in_quot(const string & line) {
const string sq = "'";
const auto sql = sq.length();
const string dq = """;
const auto dql = dq.length();
bool single_open = false;
bool double_open = false;
for(auto pos = 0; pos < line.length(); pos++) {
if(pos + sql <= line.length() && line.substr(pos, sql) == sq) {
if(single_open) {
if(!double_open) {
single_open = false;
}
} else {
single_open = true;
}
}
if(pos + dql <= line.length() && line.substr(pos, dql) == dq) {
if(double_open) {
double_open = false;
} else {
double_open = true;
}
}
}
return double_open;
}
string make_newword(const string & target) {
stringstream dst;
dst << "&#" << dec << static_cast<unsigned int>(target[0]) << ";" << target.substr(1);
return dst.str();
}
bool is_delim(char ch) {
return delim.find(ch) != string::npos;
}
bool is_pure_target(const string & line, const string & target, string::size_type pos) {
const auto tl = target.length();
if(pos + tl == line.length() || (pos + tl < line.length() && is_delim(line[pos + tl]))) {
if(pos == 0 || is_delim(line[pos - 1])) {
return true;
}
}
return false;
}
bool one_replace(string & line, const string & target, const string & newword) {
auto pos = line.find(target);
if(pos == string::npos) return false;
if(is_pure_target(line, target, pos) && !is_in_quot(line.substr(0, pos))) {
line = line.substr(0, pos) + "<font color=\"#00f\">" + newword + "</font>" + line.substr(pos + target.length());
return true;
}
return false;
}
string all_replace(const string & line) {
string dst = line;
for(auto index = 0; index < hightablesize; index++) {
const string & target = hightable[index];
const string newword = make_newword(target);
while(one_replace(dst, target, newword));
}
return dst;
}
int main(int argc, char * argv[]) {
try {
if(argc > 2) throw "too many parameters.";
auto tabstop = (argc == 2) ? atol(argv[1]) : 4;
cout << header;
cin.unsetf(ios_base::skipws);
string line;
for(;;) {
getline(cin, line);
if(!cin) break;
cout << "<nobr>" << all_replace(line_escape(tab2space(line, tabstop))) << "</nobr><br />";
}
cout << footer;
return EXIT_SUCCESS;
} catch(const char * cause) {
cout << "error: " << cause << endl;
} catch(...) {
cout << "unknown error." << endl;
}
return EXIT_FAILURE;
}