ansicolor.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. #ifndef ANSICOLOR_H
  2. #define ANSICOLOR_H
  3. #include <cstdint>
  4. #include <string>
  5. #include <stdexcept>
  6. #define CSI "\x1b["
  7. /**
  8. * ANSI Color codes
  9. */
  10. /**
  11. * @brief The colors available under ANSI-BBS
  12. */
  13. enum class COLOR : std::int8_t {
  14. /// BLACK (0)
  15. BLACK,
  16. /// RED (1)
  17. RED,
  18. /// GREEN (2)
  19. GREEN,
  20. /// BROWN (3)
  21. BROWN,
  22. /// YELLOW (3)
  23. YELLOW = 3,
  24. /// BLUE (4)
  25. BLUE,
  26. /// MAGENTA (5)
  27. MAGENTA,
  28. /// CYAN (6)
  29. CYAN,
  30. /// WHITE (7)
  31. WHITE
  32. };
  33. /**
  34. * @brief ANSI-BBS text attributes
  35. */
  36. enum class ATTR : std::int8_t {
  37. /// RESET forces all attributes (and Colors) to be sent.
  38. RESET,
  39. /// BOLD is the same as BRIGHT.
  40. BOLD,
  41. /// BRIGHT is the same as BOLD.
  42. BRIGHT = 1,
  43. /// SLOW BLINK
  44. BLINK = 5,
  45. /// INVERSE is Background on Foreground.
  46. INVERSE = 7
  47. };
  48. // std::int32_t
  49. constexpr long strhash(const char *txt) {
  50. long result = 0;
  51. for (int x = 0; x < 3; ++x) {
  52. if (txt[x] == 0) break;
  53. char c = txt[x];
  54. // toupper
  55. if ((c >= 'a') && (c <= 'z')) c &= ~0x20;
  56. result = (result << 8) | c;
  57. }
  58. return result;
  59. };
  60. #define A_BOLD 0x01
  61. #define A_BLINK 0x02
  62. #define A_INVERSE 0x04
  63. #define A_RESET 0x10
  64. /**
  65. * @class ANSIColor
  66. * This holds foreground, background and ANSI-BBS attribute
  67. * information.
  68. * The special attribute RESET forces attribute and color
  69. * output always.
  70. *
  71. * @brief Foreground, Background and Attributes
  72. *
  73. */
  74. class ANSIColor {
  75. /** Foreground color */
  76. COLOR fg;
  77. /** Background color */
  78. COLOR bg;
  79. int attr;
  80. public:
  81. ANSIColor();
  82. ANSIColor(ATTR a);
  83. ANSIColor(COLOR f);
  84. ANSIColor(COLOR f, ATTR a);
  85. ANSIColor(COLOR f, ATTR a1, ATTR a2);
  86. ANSIColor(COLOR f, COLOR b);
  87. ANSIColor(COLOR f, COLOR b, ATTR a);
  88. ANSIColor(COLOR f, COLOR b, ATTR a1, ATTR a2);
  89. ANSIColor(std::initializer_list<int> il);
  90. constexpr ANSIColor(const char *text)
  91. : fg(COLOR::WHITE), bg(COLOR::BLACK), attr(0) {
  92. const char *cp = text;
  93. bool use_on = false;
  94. while (*cp != 0) {
  95. long key = strhash(cp);
  96. switch (key) {
  97. case strhash("BRI"):
  98. attr |= A_BOLD;
  99. break;
  100. case strhash("BOL"):
  101. attr |= A_BOLD;
  102. break;
  103. case strhash("BLI"):
  104. attr |= A_BLINK;
  105. break;
  106. case strhash("INV"):
  107. attr |= A_INVERSE;
  108. break;
  109. case strhash("RES"):
  110. attr |= A_RESET;
  111. break;
  112. case strhash("ON "):
  113. use_on = true;
  114. break;
  115. case strhash("BLA"):
  116. if (use_on)
  117. bg = COLOR::BLACK;
  118. else
  119. fg = COLOR::BLACK;
  120. break;
  121. case strhash("RED"):
  122. if (use_on)
  123. bg = COLOR::RED;
  124. else
  125. fg = COLOR::RED;
  126. break;
  127. case strhash("GRE"):
  128. if (use_on)
  129. bg = COLOR::GREEN;
  130. else
  131. fg = COLOR::GREEN;
  132. break;
  133. case strhash("BRO"):
  134. if (use_on)
  135. bg = COLOR::BROWN;
  136. else
  137. fg = COLOR::BROWN;
  138. break;
  139. case strhash("YEL"):
  140. if (use_on)
  141. bg = COLOR::YELLOW;
  142. else {
  143. fg = COLOR::YELLOW;
  144. attr |= A_BOLD;
  145. }
  146. // if (use_on) throw error!
  147. break;
  148. case strhash("BLU"):
  149. if (use_on)
  150. bg = COLOR::BLUE;
  151. else
  152. fg = COLOR::BLUE;
  153. break;
  154. case strhash("MAG"):
  155. if (use_on)
  156. bg = COLOR::MAGENTA;
  157. else
  158. fg = COLOR::MAGENTA;
  159. break;
  160. case strhash("CYA"):
  161. if (use_on)
  162. bg = COLOR::CYAN;
  163. else
  164. fg = COLOR::CYAN;
  165. break;
  166. case strhash("WHI"):
  167. if (use_on)
  168. bg = COLOR::WHITE;
  169. else
  170. fg = COLOR::WHITE;
  171. break;
  172. default:
  173. throw std::range_error("Invalid/unknown color or attribute");
  174. }
  175. // skip to the space character
  176. while ((*cp != ' ') && (*cp != 0)) ++cp;
  177. // skip past the space character
  178. while (*cp == ' ') ++cp;
  179. }
  180. };
  181. /*
  182. ANSIColor(int c1);
  183. ANSIColor(int c1, int c2);
  184. */
  185. ANSIColor &Attr(ATTR a);
  186. bool operator==(const ANSIColor &c) const;
  187. bool operator!=(const ANSIColor &c) const;
  188. void setFg(COLOR f);
  189. void setFg(COLOR f, ATTR a);
  190. void setBg(COLOR b);
  191. /**
  192. * Get the foreground color
  193. * @return COLOR
  194. */
  195. COLOR getFg() { return fg; };
  196. /**
  197. * Get the background color
  198. * @return COLOR
  199. */
  200. COLOR getBg() { return bg; };
  201. void setAttr(ATTR a);
  202. std::string output(void) const;
  203. std::string operator()(void) const;
  204. };
  205. #ifdef NON_WORKING
  206. #include <vector>
  207. constexpr std::vector<int> from_text(const char *text) {
  208. std::vector<int> vi;
  209. const char *cp = text;
  210. bool use_on = false;
  211. while (*cp != 0) {
  212. int key = strhash(cp);
  213. switch (key) {
  214. case strhash("BRI"):
  215. vi.push_back(1);
  216. break;
  217. case strhash("BOL"):
  218. vi.push_back(1);
  219. break;
  220. case strhash("BLI"):
  221. vi.push_back(5);
  222. break;
  223. case strhash("INV"):
  224. vi.push_back(7);
  225. break;
  226. case strhash("ON "):
  227. use_on = true;
  228. break;
  229. case strhash("BLU"):
  230. if (use_on)
  231. ac.setBg(COLOR::BLUE);
  232. else
  233. ac.setFg(COLOR::BLUE);
  234. break;
  235. case strhash("RED"):
  236. if (use_on)
  237. ac.setBg(COLOR::RED);
  238. else
  239. ac.setFg(COLOR::RED);
  240. break;
  241. case strhash("GRE"):
  242. if (use_on)
  243. ac.setBg(COLOR::GREEN);
  244. else
  245. ac.setFg(COLOR::GREEN);
  246. break;
  247. case strhash("YEL"):
  248. // if (use_on) throw error!
  249. ac.setFg(COLOR::YELLOW);
  250. ac.Attr(ATTR::BOLD);
  251. break;
  252. case strhash("BRO"):
  253. if (use_on)
  254. ac.setBg(COLOR::BROWN);
  255. else
  256. ac.setFg(COLOR::BROWN);
  257. break;
  258. case strhash("CYA"):
  259. if (use_on)
  260. ac.setBg(COLOR::CYAN);
  261. else
  262. ac.setFg(COLOR::CYAN);
  263. break;
  264. case strhash("MAG"):
  265. if (use_on)
  266. ac.setBg(COLOR::MAGENTA);
  267. else
  268. ac.setFg(COLOR::MAGENTA);
  269. break;
  270. case strhash("BLA"):
  271. if (use_on)
  272. ac.setBg(COLOR::BLACK);
  273. else
  274. ac.setFg(COLOR::BLACK);
  275. break;
  276. case strhash("WHI"):
  277. if (use_on)
  278. ac.setBg(COLOR::WHITE);
  279. else
  280. ac.setFg(COLOR::WHITE);
  281. break;
  282. }
  283. // skip to the space character
  284. while ((*cp != ' ') && (*cp != 0)) ++cp;
  285. // skip past the space character
  286. while (*cp == ' ') ++cp;
  287. }
  288. return vi;
  289. }
  290. #endif
  291. /*
  292. Maybe make char, char, char (fg, bg, attr) and store those from
  293. the constexpr.
  294. This "works", in that it does construct an ANSIColor from text.
  295. However, it isn't stored as an ANSIColor, but calls the function
  296. at run-time. (I was hoping for an efficient way to construct
  297. ANSIColor from a string.)
  298. Maybe a template that constructs it from a initializer_list?
  299. */
  300. constexpr ANSIColor ac_from_text(const char *text) {
  301. ANSIColor ac(nullptr);
  302. const char *cp = text;
  303. bool use_on = false;
  304. while (*cp != 0) {
  305. int key = strhash(cp);
  306. switch (key) {
  307. case strhash("BRI"):
  308. ac.Attr(ATTR::BRIGHT);
  309. break;
  310. case strhash("BOL"):
  311. ac.Attr(ATTR::BOLD);
  312. break;
  313. case strhash("BLI"):
  314. ac.Attr(ATTR::BLINK);
  315. break;
  316. case strhash("INV"):
  317. ac.Attr(ATTR::INVERSE);
  318. break;
  319. case strhash("ON "):
  320. use_on = true;
  321. break;
  322. case strhash("BLU"):
  323. if (use_on)
  324. ac.setBg(COLOR::BLUE);
  325. else
  326. ac.setFg(COLOR::BLUE);
  327. break;
  328. case strhash("RED"):
  329. if (use_on)
  330. ac.setBg(COLOR::RED);
  331. else
  332. ac.setFg(COLOR::RED);
  333. break;
  334. case strhash("GRE"):
  335. if (use_on)
  336. ac.setBg(COLOR::GREEN);
  337. else
  338. ac.setFg(COLOR::GREEN);
  339. break;
  340. case strhash("YEL"):
  341. // if (use_on) throw error!
  342. ac.setFg(COLOR::YELLOW);
  343. ac.Attr(ATTR::BOLD);
  344. break;
  345. case strhash("BRO"):
  346. if (use_on)
  347. ac.setBg(COLOR::BROWN);
  348. else
  349. ac.setFg(COLOR::BROWN);
  350. break;
  351. case strhash("CYA"):
  352. if (use_on)
  353. ac.setBg(COLOR::CYAN);
  354. else
  355. ac.setFg(COLOR::CYAN);
  356. break;
  357. case strhash("MAG"):
  358. if (use_on)
  359. ac.setBg(COLOR::MAGENTA);
  360. else
  361. ac.setFg(COLOR::MAGENTA);
  362. break;
  363. case strhash("BLA"):
  364. if (use_on)
  365. ac.setBg(COLOR::BLACK);
  366. else
  367. ac.setFg(COLOR::BLACK);
  368. break;
  369. case strhash("WHI"):
  370. if (use_on)
  371. ac.setBg(COLOR::WHITE);
  372. else
  373. ac.setFg(COLOR::WHITE);
  374. break;
  375. }
  376. // skip to the space character
  377. while ((*cp != ' ') && (*cp != 0)) ++cp;
  378. // skip past the space character
  379. while (*cp == ' ') ++cp;
  380. }
  381. return ac;
  382. };
  383. extern ANSIColor reset;
  384. #endif