nyancat

Unnamed repository; edit this file 'description' to name the repository.
git clone https://git.inz.fi/nyancat
Log | Files | Refs | README

commit 37bc640e61bf2f5833dd5373bc5e8dbee99c5e43
parent 2abf293ba0c01cd37dac3c93e34258f6cda3f977
Author: Santtu Lakkala <inz@inz.fi>
Date:   Mon, 20 Jul 2020 14:40:33 +0300

Add support for background color

Background color is passed without modification. Also foreground 256 and
RGB colors are parsed.

Diffstat:
Mnyancat.c | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 142 insertions(+), 19 deletions(-)

diff --git a/nyancat.c b/nyancat.c @@ -42,13 +42,18 @@ struct lolcat { int sy; uint32_t fg; uint32_t bg; + bool bg_set; bool bold; bool reverse; bool underline; bool was_bold; bool was_reverse; bool was_underline; + bool was_bgset; enum { TRUECOLOR, INDEXED256, INDEXED16 } mode; + enum { NONE, + FCOLOR, FI256, FR, FG, FB, + BCOLOR, BI256, BR, BG, BB } cstate; void (*write)(const char *buffer, size_t buflen, void *data); void *write_data; @@ -143,12 +148,97 @@ struct lolcat *lolcat_init(void (*write_cb)(const char *buffer, size_t buflen, return rv; } +static inline int _bold(int color) +{ + if (!color) + return 0x808080; + if (color == 0xc0c0c0) + return 0xffffff; + return (color << 1) - (color >> 7); +} + +static uint32_t _color8(uint8_t color) +{ + if (color == 7) + return 0xc0c0c0; + return (color & 1) << 23 | + (color & 2) << 14 | + (color & 4) << 5; +} + +static uint32_t _ccube(uint8_t idx) +{ + if (!idx) + return 0; + return 255 - 40 * (5 - idx); +} + +static uint32_t _color256(uint8_t color) +{ + if (color < 8) + return _color8(color); + if (color < 16) + return _bold(_color8(color)); + if (color < 232) + return _ccube((color - 16) / 36) << 16 | + _ccube((color - 16) / 6 % 6) << 8 | + _ccube((color - 16) % 6); + return 0x010101 * (0xee - 10 * (255 - color)); +} + static int _lc_arg_m(int arg, void *data) { struct lolcat *lc = data; - if (arg == 38 || arg == 48) - return 1; + switch (lc->cstate) { + case FCOLOR: + if (arg == 2) + lc->cstate = FR; + else if (arg == 5) + lc->cstate = FI256; + else + return 1; + lc->fg = 0; + return 0; + case FI256: + lc->fg = _color256(arg); + lc->cstate = NONE; + return 0; + case FB: + lc->cstate = -1; + /* fall-through */ + case FR: + case FG: + lc->fg = lc->fg << 8 | arg; + lc->cstate++; + return 0; + + case BCOLOR: + if (arg == 2) + lc->cstate = BR; + else if (arg == 5) + lc->cstate = BI256; + else + return 1; + lc->bg = 0; + return 0; + case BI256: + lc->bg = _color256(arg); + lc->bg_set = true; + lc->cstate = NONE; + return 0; + case BB: + lc->cstate = -1; + lc->bg_set = true; + /* fall-through */ + case BR: + case BG: + lc->bg = lc->bg << 8 | arg; + lc->cstate++; + return 0; + default: + break; + } switch (arg) { case 0: @@ -156,6 +246,7 @@ static int _lc_arg_m(int arg, void *data) lc->reverse = false; lc->fg = 0xc0c0c0; lc->bg = 0x000000; + lc->bg_set = false; break; case 1: lc->bold = true; @@ -177,12 +268,15 @@ static int _lc_arg_m(int arg, void *data) case 35: case 36: lc->fg = ((arg - 30) & 1) << 23 | - ((arg - 30) & 2) << 14 | - ((arg - 30) & 4) << 5; + ((arg - 30) & 2) << 14 | + ((arg - 30) & 4) << 5; break; case 37: lc->fg = 0xc0c0c0; break; + case 38: + lc->cstate = FCOLOR; + break; case 40: case 41: case 42: @@ -191,8 +285,16 @@ static int _lc_arg_m(int arg, void *data) case 45: case 46: lc->bg = ((arg - 40) & 1) << 23 | - ((arg - 40) & 2) << 14 | - ((arg - 40) & 4) << 5; + ((arg - 40) & 2) << 14 | + ((arg - 40) & 4) << 5; + lc->bg_set = true; + break; + case 47: + lc->bg = 0xc0c0c0; + lc->bg_set = true; + break; + case 48: + lc->cstate = BCOLOR; break; default: @@ -202,15 +304,6 @@ static int _lc_arg_m(int arg, void *data) return 0; } -static inline int _bold(int color) -{ - if (!color) - return 0x808080; - if (color == 0xc0c0c0) - return 0xffffff; - return (color << 1) - (color >> 7); -} - #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) #define CLAMP(a, b, c) MIN(MAX(a, b), c) @@ -245,9 +338,11 @@ static inline int _index16(uint32_t col, bool *bright) ri = r > 127U; gi = g > 127U; bi = b > 127U; - *bright = true; + if (bright) + *bright = true; } else { - *bright = false; + if (bright) + *bright = false; } return ri | bi << 1 | gi << 2; @@ -283,7 +378,8 @@ static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len) char *bw = buffer + 2; if (len == 1 && u8_char[0] == ' ' && - !lc->reverse && !lc->was_reverse) { + !lc->reverse && !lc->was_reverse && + !lc->bg_set && !lc->was_bgset) { lc->write(" ", 1, lc->write_data); return; } @@ -300,10 +396,12 @@ static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len) col = _index256(col); if ((lc->was_bold && !lc->bold) || - (lc->was_reverse && !lc->reverse)) { + (lc->was_reverse && !lc->reverse) || + (lc->was_bgset && !lc->bg_set)) { lc->was_underline = false; lc->was_bold = false; lc->was_reverse = false; + lc->was_bgset = false; *bw++ = '0'; *bw++ = ';'; } @@ -325,6 +423,21 @@ static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len) lc->was_reverse = true; } + if (lc->bg_set) { + if (lc->mode == INDEXED16) + bw += sprintf(bw, "4%d;", + _index16(lc->bg, NULL)); + else if (lc->mode == INDEXED256) + bw += sprintf(bw, "48;5;%d;", + _index256(lc->bg)); + else + bw += sprintf(bw, "48;2;%d;%d;%d;", + lc->bg >> 16, + (lc->bg >> 8) & 255, + lc->bg & 255); + lc->was_bgset = true; + } + if (lc->mode == INDEXED16) bw += sprintf(bw, "3%dm%.*s", col, (int)len, u8_char); @@ -379,6 +492,7 @@ ssize_t lc_process(struct lolcat *lc, const char *buffer, size_t len) return ip; if (c == '\x1b') { + lc->cstate = NONE; if (i >= len) return ip; if (buffer[i] == '[') { @@ -519,6 +633,15 @@ ssize_t lc_process(struct lolcat *lc, const char *buffer, size_t len) lc->write("", 1, lc->write_data); continue; } else if (c == '\n') { + if ((lc->was_bgset && !lc->bg) || + (lc->was_reverse && !lc->reverse)) { + const char buffer[] = "\x1b[0m"; + lc->was_bgset = lc->was_reverse = + lc->was_bold = lc->was_underline = + false; + lc->write(buffer, sizeof(buffer), + lc->write_data); + } lc->x = 0; lc->y++; lc->write("\n", 1, lc->write_data);