Skip to content

Commit 0be0d2e

Browse files
committed
fixup! dynamically allocate JQ_COLORS escapes for truecolor support
reorganize and reword code to make it easier to read
1 parent 0bec126 commit 0be0d2e

File tree

1 file changed

+40
-33
lines changed

1 file changed

+40
-33
lines changed

src/jv_print.c

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,71 +27,78 @@
2727
// Color table. See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
2828
// for how to choose these. The order is same as jv_kind definition, and
2929
// the last color is used for object keys.
30-
#define DEF_COLORS \
30+
#define DEFAULT_COLORS \
3131
{COL("0;90"), COL("0;39"), COL("0;39"), COL("0;39"),\
3232
COL("0;32"), COL("1;39"), COL("1;39"), COL("1;34")};
33-
static const char *const def_colors[] = DEF_COLORS;
34-
static const char *colors[] = DEF_COLORS;
33+
static const char *const default_colors[] = DEFAULT_COLORS;
34+
static const char *colors[] = DEFAULT_COLORS;
3535
#define COLORS_LEN (sizeof(colors) / sizeof(colors[0]))
3636
#define FIELD_COLOR (colors[7])
3737

3838
static char *colors_buf = NULL;
39-
int jq_set_colors(const char *c) {
40-
if (c == NULL)
39+
int jq_set_colors(const char *code_str) {
40+
if (code_str == NULL)
4141
return 1;
42-
const char *offsets[COLORS_LEN + 1]; // extra item for the end of the last string
4342

44-
size_t cl = 0;
45-
size_t cn = 0;
43+
// the start of each color code in the env var, and the byte after the end of the last one
44+
const char *codes[COLORS_LEN + 1];
45+
size_t num_colors;
46+
// must be initialized before `goto reset`, used later to loop over every color
47+
size_t ci = 0;
4648

47-
while (cl < COLORS_LEN) {
48-
offsets[cl++] = c;
49-
// gcc won't optimize out strspn
49+
for (num_colors = 0; num_colors < COLORS_LEN; num_colors++) {
50+
codes[num_colors] = code_str;
5051
letter:
51-
switch (c++[0]) {
52+
switch (code_str[0]) {
5253
// technically posix doesn't specify ascii so a range wouldn't be portable
5354
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ';':
54-
goto letter;
55+
code_str++;
56+
goto letter; // loops until end of color code
5557
case ':':
56-
continue;
58+
code_str++;
59+
continue; // next color
5760
case '\0':
58-
goto var_end;
61+
goto set_codes_end; // done
5962
default:
60-
return 0;
63+
return 0; // invalid character
6164
}
6265
}
63-
var_end:
64-
// don't override last color on empty variable or trailing :
65-
if (offsets[--cl] != c - 1) {
66-
offsets[++cl] = c;
67-
} else if (cl == 0) {
66+
set_codes_end:
67+
if (codes[num_colors] != code_str) {
68+
// count the last color and store its end (plus one byte for consistency with starts)
69+
// an empty last color would be ignored (for cases like "" and "0:")
70+
num_colors++;
71+
codes[num_colors] = code_str + 1;
72+
} else if (num_colors == 0) {
6873
if (colors_buf != NULL) {
6974
jv_mem_free(colors_buf);
7075
colors_buf = NULL;
7176
}
72-
goto reset;
77+
goto default_colors;
7378
}
7479

7580
colors_buf = jv_mem_realloc(
7681
colors_buf,
7782
// add ESC '[' 'm' to each string
78-
// '\0' is already included in difference of offsets
79-
offsets[cl] - offsets[0] + 3 * cl
83+
// '\0' is already included in difference of codes
84+
codes[num_colors] - codes[0] + 3 * num_colors
8085
);
8186
char *cb = colors_buf;
82-
for (; cn < cl; cn++) {
83-
colors[cn] = cb;
87+
for (; ci < num_colors; ci++) {
88+
colors[ci] = cb;
89+
size_t len = codes[ci + 1] - 1 - codes[ci];
90+
8491
cb[0] = ESC[0];
8592
cb[1] = '[';
86-
size_t len = offsets[cn + 1] - 1 - offsets[cn];
87-
memcpy(cb + 2, offsets[cn], len);
88-
cb[len + 2] = 'm';
89-
cb[len + 3] = '\0';
93+
memcpy(cb + 2, codes[ci], len);
94+
cb[2 + len] = 'm';
95+
cb[3 + len] = '\0';
96+
9097
cb += len + 4;
9198
}
92-
reset:
93-
for (; cn < COLORS_LEN; cn++)
94-
colors[cn] = def_colors[cn];
99+
default_colors:
100+
for (; ci < COLORS_LEN; ci++)
101+
colors[ci] = default_colors[ci];
95102
return 1;
96103
}
97104

0 commit comments

Comments
 (0)