From add8b7177892df8775a202beec2dc5f540ebcc12 Mon Sep 17 00:00:00 2001 From: Boris Faure Date: Sat, 15 Dec 2018 23:41:46 +0100 Subject: [PATCH] termptyesc: fix truecolors parsing + tests --- src/bin/termptyesc.c | 232 +++++++++++++++++++++++++++++++--------- tests/sgr-truecolors.sh | 152 ++++++++++++++++++++++++++ tests/tests.results | 1 + 3 files changed, 333 insertions(+), 52 deletions(-) create mode 100755 tests/sgr-truecolors.sh diff --git a/src/bin/termptyesc.c b/src/bin/termptyesc.c index d1a0d9ae..623e7ea6 100644 --- a/src/bin/termptyesc.c +++ b/src/bin/termptyesc.c @@ -100,7 +100,7 @@ _csi_arg_get(Termpty *ty, Eina_Unicode **ptr) Eina_Unicode *b = *ptr; int sum = 0; - if (!b) + if ((b == NULL) || (*b == '\0')) { *ptr = NULL; return -CSI_ARG_NO_VALUE; @@ -128,6 +128,7 @@ _csi_arg_get(Termpty *ty, Eina_Unicode **ptr) if (sum > INT32_MAX/10 ) { ERR("Invalid sequence: argument is too large"); + ty->decoding_error = EINA_TRUE; goto error; } sum *= 10; @@ -135,7 +136,7 @@ _csi_arg_get(Termpty *ty, Eina_Unicode **ptr) b++; } - if (*b == ';') + if ((*b == ';') || (*b == ':')) { if (b[1]) b++; @@ -540,41 +541,66 @@ _handle_esc_csi_reset_mode(Termpty *ty, Eina_Unicode cc, Eina_Unicode *b, } static int -_csi_truecolor_arg_get(Eina_Unicode **ptr) +_csi_truecolor_arg_get(Termpty *ty, Eina_Unicode **ptr) { Eina_Unicode *b = *ptr; int sum = 0; + char separator; - if (!b) - goto error; + if ((b == NULL) || (*b == '\0')) + { + *ptr = NULL; + return -CSI_ARG_NO_VALUE; + } - if ((*b == ';') || (*b == ':')) + /* by construction, shall be the same separator as the following ones */ + separator = *(b-1); + if ((separator != ';') && (separator != ':')) + { + *ptr = NULL; + return -CSI_ARG_NO_VALUE; + } + + if (*b == separator) { b++; *ptr = b; - return 0; + return -CSI_ARG_NO_VALUE; } - if (!*b) - goto error; + if (*b == '\0') + { + *ptr = NULL; + return -CSI_ARG_NO_VALUE; + } while ((*b >= '0') && (*b <= '9')) { if (sum > INT32_MAX/10 ) - goto error; + { + *ptr = NULL; + ERR("Invalid sequence: argument is too large"); + ty->decoding_error = EINA_TRUE; + return -CSI_ARG_ERROR; + } sum *= 10; sum += *b - '0'; b++; } - if ((*b == ';') || (*b == ':')) - b++; - - *ptr = b; + if (*b == separator) + { + b++; + *ptr = b; + } + else if (*b == '\0') + { + *ptr = NULL; + } + else + { + *ptr = b; + } return sum; - -error: - *ptr = NULL; - return -1; } @@ -631,68 +657,171 @@ _approximate_truecolor_rgb(Termpty *ty, int r0, int g0, int b0) static int _handle_esc_csi_truecolor_rgb(Termpty *ty, Eina_Unicode **ptr) { - int r0, g0, b0, other; + int r, g, b; + Eina_Unicode *u = *ptr; + char separator; - r0 = _csi_truecolor_arg_get(ptr); - g0 = _csi_truecolor_arg_get(ptr); - b0 = _csi_truecolor_arg_get(ptr); - other = _csi_truecolor_arg_get(ptr); - if (other >= 0) + if ((u == NULL) || (*u == '\0')) { - r0 = g0; - g0 = b0; - b0 = other; + return COL_DEF; } + separator = *(u-1); - if ((r0 < 0) || (g0 < 0) || (b0 < 0)) + r = _csi_truecolor_arg_get(ty, ptr); + g = _csi_truecolor_arg_get(ty, ptr); + b = _csi_truecolor_arg_get(ty, ptr); + if ((r == -CSI_ARG_ERROR) || + (g == -CSI_ARG_ERROR) || + (b == -CSI_ARG_ERROR)) return COL_DEF; - return _approximate_truecolor_rgb(ty, r0, g0, b0); + if (separator == ':' && *ptr) + { + if (**ptr != ';') + { + /* then the first parameter was a color-space-id (ignored) */ + r = g; + g = b; + b = _csi_truecolor_arg_get(ty, ptr); + /* Skip other parameters */ + while ((*ptr) && (**ptr != ';')) + { + _csi_truecolor_arg_get(ty, ptr); + } + } + if ((*ptr) && (**ptr == ';')) + { + *ptr = (*ptr) + 1; + } + } + + if (r == -CSI_ARG_NO_VALUE) + r = 0; + if (g == -CSI_ARG_NO_VALUE) + g = 0; + if (b == -CSI_ARG_NO_VALUE) + b = 0; + + return _approximate_truecolor_rgb(ty, r, g, b); } static int _handle_esc_csi_truecolor_cmy(Termpty *ty, Eina_Unicode **ptr) { - int r0, g0, b0, c0, m0, y0; + int r, g, b, c, m, y; + Eina_Unicode *u = *ptr; + char separator; + + if ((u == NULL) || (*u == '\0')) + { + return COL_DEF; + } + separator = *(u-1); /* Considering CMY stored as percents */ - c0 = _csi_truecolor_arg_get(ptr); - m0 = _csi_truecolor_arg_get(ptr); - y0 = _csi_truecolor_arg_get(ptr); + c = _csi_truecolor_arg_get(ty, ptr); + m = _csi_truecolor_arg_get(ty, ptr); + y = _csi_truecolor_arg_get(ty, ptr); - if ((c0 < 0) || (m0 < 0) || (y0 < 0)) + if ((c == -CSI_ARG_ERROR) || + (m == -CSI_ARG_ERROR) || + (y == -CSI_ARG_ERROR)) return COL_DEF; - r0 = 255 - ((c0 * 255) / 100); - g0 = 255 - ((m0 * 255) / 100); - b0 = 255 - ((y0 * 255) / 100); + if (separator == ':' && *ptr) + { + if (**ptr != ';') + { + /* then the first parameter was a color-space-id (ignored) */ + c = m; + m = y; + y = _csi_truecolor_arg_get(ty, ptr); + /* Skip other parameters */ + while ((*ptr) && (**ptr != ';')) + { + _csi_truecolor_arg_get(ty, ptr); + } + } + if ((*ptr) && (**ptr == ';')) + { + *ptr = (*ptr) + 1; + } + } - return _approximate_truecolor_rgb(ty, r0, g0, b0); + if (c == -CSI_ARG_NO_VALUE) + c = 0; + if (m == -CSI_ARG_NO_VALUE) + m = 0; + if (y == -CSI_ARG_NO_VALUE) + y = 0; + + r = 255 - ((c * 255) / 100); + g = 255 - ((m * 255) / 100); + b = 255 - ((y * 255) / 100); + + return _approximate_truecolor_rgb(ty, r, g, b); } static int _handle_esc_csi_truecolor_cmyk(Termpty *ty, Eina_Unicode **ptr) { - int r0, g0, b0, c0, m0, y0, k0; + int r, g, b, c, m, y, k; + Eina_Unicode *u = *ptr; + char separator; + + if ((u == NULL) || (*u == '\0')) + { + return COL_DEF; + } + separator = *(u-1); /* Considering CMYK stored as percents */ - c0 = _csi_truecolor_arg_get(ptr); - m0 = _csi_truecolor_arg_get(ptr); - y0 = _csi_truecolor_arg_get(ptr); - k0 = _csi_truecolor_arg_get(ptr); + c = _csi_truecolor_arg_get(ty, ptr); + m = _csi_truecolor_arg_get(ty, ptr); + y = _csi_truecolor_arg_get(ty, ptr); + k = _csi_truecolor_arg_get(ty, ptr); - if ((c0 < 0) || (m0 < 0) || (y0 < 0) || (k0 < 0)) + if ((c == -CSI_ARG_ERROR) || + (m == -CSI_ARG_ERROR) || + (y == -CSI_ARG_ERROR) || + (k == -CSI_ARG_ERROR)) return COL_DEF; - c0 = c0 * (100 - k0) + k0; - m0 = m0 * (100 - k0) + k0; - y0 = y0 * (100 - k0) + k0; + if (separator == ':' && *ptr) + { + if (**ptr != ';') + { + /* then the first parameter was a color-space-id (ignored) */ + c = m; + m = y; + y = k; + k = _csi_truecolor_arg_get(ty, ptr); + /* Skip other parameters */ + while ((*ptr) && (**ptr != ';')) + { + _csi_truecolor_arg_get(ty, ptr); + } + } + if ((*ptr) && (**ptr == ';')) + { + *ptr = (*ptr) + 1; + } + } - r0 = 255 - ((c0 * 255) / 100); - g0 = 255 - ((m0 * 255) / 100); - b0 = 255 - ((y0 * 255) / 100); + if (c == -CSI_ARG_NO_VALUE) + c = 0; + if (m == -CSI_ARG_NO_VALUE) + m = 0; + if (y == -CSI_ARG_NO_VALUE) + y = 0; + if (k == -CSI_ARG_NO_VALUE) + k = 0; - return _approximate_truecolor_rgb(ty, r0, g0, b0); + r = (255 * (100 - c) * (100 - k)) / 100 / 100; + g = (255 * (100 - m) * (100 - k)) / 100 / 100; + b = (255 * (100 - y) * (100 - k)) / 100 / 100; + + return _approximate_truecolor_rgb(ty, r, g, b); } static void @@ -715,7 +844,6 @@ _handle_esc_csi_color_set(Termpty *ty, Eina_Unicode **ptr, { case -CSI_ARG_ERROR: return; - /* TODO: -CSI_ARG_NO_VALUE */ case -CSI_ARG_NO_VALUE: EINA_FALLTHROUGH; case 0: // reset to normal diff --git a/tests/sgr-truecolors.sh b/tests/sgr-truecolors.sh new file mode 100755 index 00000000..fcff3d95 --- /dev/null +++ b/tests/sgr-truecolors.sh @@ -0,0 +1,152 @@ +#!/bin/sh + +# pick 2 colors as RGB (orange for background, blue for foreground) +# compute the values for CMY and CMYK colorspaces +# Have 4 colums for each kind of format used in TrueColor escape codes + +#BG-48: #f49019 +# R:244 G:144 B:25 +# C:4 M:43 Y:90 +# C:0 M:41 Y:90 K:4 + +#FG-38: #3896c7 +# R:56 G:150 B:199 +# C:78 M:41 Y:22 +# C:72 M:25 Y:0 K:22 + + +# cursor to 0,0 and clear line +printf '\033[H\033[2K' + +# formats for each columns +printf '\033[1;1H\033[0m38:2:n:n:nm' +printf '\033[1;13H\033[0m38:2:42:n:n:nm' +printf '\033[1;28H\033[0m38:2:42:n:n:n:4m' +printf '\033[1;45H\033[0m38;2;n;n;nm' + +## +# RGB +## +printf '\033[3;1H\033[0;1;37mRGB' + +# 1 +printf '\033[4;1H\033[0;1;37m1' +printf '\033[48:2:244:144:25m' +printf '\033[38:2:56:150:199m' +printf '\033[4;5H▗▖' +printf '\033[5;5H▝▘' + +# 2 +printf '\033[4;13H\033[0;1;37m2' +printf '\033[48:2:42:244:144:25m' +printf '\033[38:2:42:56:150:199m' +printf '\033[4;17H▗▖' +printf '\033[5;17H▝▘' + +# 3 +printf '\033[4;28H\033[0;1;37m3' +printf '\033[48:2:42:244:144:25:4m' +printf '\033[38:2:42:56:150:199:4m' +printf '\033[4;32H▗▖' +printf '\033[5;32H▝▘' + +# 4 +printf '\033[4;45H\033[0;1;37m4' +printf '\033[48;2;244;144;25m' +printf '\033[38;2;56;150;199m' +printf '\033[4;49H▗▖' +printf '\033[5;49H▝▘' + +# Same but on one sequence +printf '\033[6;1H\033[0mSame but fg+bg on one sequence' + +#1 +printf '\033[7;1H\033[0;1;37m1' +printf '\033[48:2:244:144:25;38:2:56:150:199m' +printf '\033[7;5H▗▖' +printf '\033[8;5H▝▘' + +# 2 +printf '\033[7;13H\033[0;1;37m2' +printf '\033[1;13H\033[0m38:2:42:n:n:nm' +printf '\033[48:2:42:244:144:25;38:2:42:56:150:199m' +printf '\033[7;17H▗▖' +printf '\033[8;17H▝▘' + +# 3 +printf '\033[7;28H\033[0;1;37m3' +printf '\033[48:2:42:244:144:25:4;38:2:42:56:150:199:4m' +printf '\033[7;32H▗▖' +printf '\033[8;32H▝▘' + +# 4 +printf '\033[7;45H\033[0;1;37m4' +printf '\033[48;2;244;144;25;38;2;56;150;199m' +printf '\033[7;49H▗▖' +printf '\033[8;49H▝▘' + + +## +# CMY +## +printf '\033[10;1H\033[0;1;37mCMY' +# 1 +printf '\033[11;1H\033[0;1;37m1' +printf '\033[48:3:4:43:90m' +printf '\033[38:3:78:41:22m' +printf '\033[11;5H▗▖' +printf '\033[12;5H▝▘' + +# 2 +printf '\033[11;13H\033[0;1;37m2' +printf '\033[48:3:42:4:43:90m' +printf '\033[38:3:42:78:41:22m' +printf '\033[11;17H▗▖' +printf '\033[12;17H▝▘' + +# 3 +printf '\033[11;28H\033[0;1;37m3' +printf '\033[48:3:42:4:43:90:4m' +printf '\033[38:3:42:78:41:22:4m' +printf '\033[11;32H▗▖' +printf '\033[12;32H▝▘' + +# 4 +printf '\033[11;45H\033[0;1;37m4' +printf '\033[48;3;4;43;90m' +printf '\033[38;3;78;41;22m' +printf '\033[11;49H▗▖' +printf '\033[12;49H▝▘' + + +## +# CMYK +## +printf '\033[14;1H\033[0;1;37mCMYK' +# 1 +printf '\033[15;1H\033[0;1;37m1' +printf '\033[48:4::0:41:90:4m' +printf '\033[38:4::72:25:0:22m' +printf '\033[15;5H▗▖' +printf '\033[16;5H▝▘' + +# 2 +printf '\033[15;13H\033[0;1;37m2' +printf '\033[48:4:42:0:41:90:4m' +printf '\033[38:4:42:72:25:0:22m' +printf '\033[15;17H▗▖' +printf '\033[16;17H▝▘' + +# 3 +printf '\033[15;28H\033[0;1;37m3' +printf '\033[48:4:42:0:41:90:4:4m' +printf '\033[38:4:42:72:25:0:22:4m' +printf '\033[15;32H▗▖' +printf '\033[16;32H▝▘' + +# 4 +printf '\033[15;45H\033[0;1;37m4' +printf '\033[48;4;0;41;90;4m' +printf '\033[38;4;72;25;0;22m' +printf '\033[15;49H▗▖' +printf '\033[16;49H▝▘' diff --git a/tests/tests.results b/tests/tests.results index 4a2be95d..182cac28 100644 --- a/tests/tests.results +++ b/tests/tests.results @@ -27,3 +27,4 @@ dsr-pp.sh 0f0a7d5beccefbad4f4984fc4611276e dsr-udk.sh f3a20968a2f25bfd36875dbc5f64ab16 colors.sh 532494a2e56c102ee10ab1a9b8f176d7 sgr-leading-trailing-semicolon.sh d7701f1193bde63412a9b969f17e10ec +sgr-truecolors.sh 9db4becc728bb9f1730f3573dc7fc668