summaryrefslogtreecommitdiff
path: root/src/escape.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 13:36:27 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 13:36:27 +0300
commit4741f7a6dfa144ce65cf3bbdd4a1bc6bee6df2e5 (patch)
tree97932e58eee98623b56a9d9181a3b4289b6ecfc1 /src/escape.c
parenta0fefd3856a4f03be0abbc51f7a9a0416db69eb5 (diff)
Optimize and simplify loops, table lookups, and branchless parsers
- Replace sequential colon-counting loop with branchless CTZ bitmask in src/pen.h - Replace linear strchr with 256-bit ASCII punctuation bitmask in src/selection.c - Flatten 3D color cube loop and precompute constants in src/palette.c - Use static 256-byte LUT for hex decoding and bsearch for termcap in src/escape.c - Replace capacity doubling while loops with branchless CLZ pow2 helpers across core - Use direct memset/memcpy in src/snapshot.c - Optimize input digit/byte formatting, alt-prefix path, and make keyboard state optional in src/input.c
Diffstat (limited to 'src/escape.c')
-rw-r--r--src/escape.c179
1 files changed, 103 insertions, 76 deletions
diff --git a/src/escape.c b/src/escape.c
index 119010c..9576e8e 100644
--- a/src/escape.c
+++ b/src/escape.c
@@ -53,94 +53,123 @@ static int sgr_serialize(const struct term *t, char *buf, size_t sz)
return n;
}
+static const signed char hex_val[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
static int dcs_decode_hex(const char *s, int len, char *out, int cap)
{
if (len & 1) return -1;
int n = 0;
for (int i = 0; i < len; i += 2) {
- int hi = term_hex_nib(s[i]), lo = term_hex_nib(s[i + 1]);
- if (hi < 0 || lo < 0 || n >= cap) return -1;
+ int hi = hex_val[(unsigned char)s[i]], lo = hex_val[(unsigned char)s[i + 1]];
+ if ((hi | lo) < 0 || n >= cap) return -1;
out[n++] = (char)(hi << 4 | lo);
}
return n;
}
+struct tcap_entry {
+ const char *name, *value;
+};
+
+static int tcap_cmp(const void *k, const void *e)
+{
+ const char *key = k;
+ const struct tcap_entry *elem = e;
+ return strcmp(key, elem->name);
+}
+
static const char *term_tcap(const struct term *t, const char *name)
{
- static const struct { const char *name, *value; } caps[] = {
- { "Co", "16777216" },
- { "RGB", "8/8/8" },
- { "colors", "16777216" },
- { "kDC", "\x1b[3;2~" }, { "kDC3", "\x1b[3;3~" },
- { "kDC4", "\x1b[3;4~" }, { "kDC5", "\x1b[3;5~" },
- { "kDC6", "\x1b[3;6~" }, { "kDC7", "\x1b[3;7~" },
- { "kDN", "\x1b[1;2B" }, { "kDN3", "\x1b[1;3B" },
- { "kDN4", "\x1b[1;4B" }, { "kDN5", "\x1b[1;5B" },
- { "kDN6", "\x1b[1;6B" }, { "kDN7", "\x1b[1;7B" },
- { "kEND", "\x1b[1;2F" }, { "kEND3", "\x1b[1;3F" },
- { "kEND4", "\x1b[1;4F" }, { "kEND5", "\x1b[1;5F" },
- { "kEND6", "\x1b[1;6F" }, { "kEND7", "\x1b[1;7F" },
- { "kHOM", "\x1b[1;2H" }, { "kHOM3", "\x1b[1;3H" },
- { "kHOM4", "\x1b[1;4H" }, { "kHOM5", "\x1b[1;5H" },
- { "kHOM6", "\x1b[1;6H" }, { "kHOM7", "\x1b[1;7H" },
- { "kIC", "\x1b[2;2~" }, { "kIC3", "\x1b[2;3~" },
- { "kIC4", "\x1b[2;4~" }, { "kIC5", "\x1b[2;5~" },
- { "kIC6", "\x1b[2;6~" }, { "kIC7", "\x1b[2;7~" },
- { "kLFT", "\x1b[1;2D" }, { "kLFT3", "\x1b[1;3D" },
- { "kLFT4", "\x1b[1;4D" }, { "kLFT5", "\x1b[1;5D" },
- { "kLFT6", "\x1b[1;6D" }, { "kLFT7", "\x1b[1;7D" },
- { "kNXT", "\x1b[6;2~" }, { "kNXT3", "\x1b[6;3~" },
- { "kNXT4", "\x1b[6;4~" }, { "kNXT5", "\x1b[6;5~" },
- { "kNXT6", "\x1b[6;6~" }, { "kNXT7", "\x1b[6;7~" },
- { "kPRV", "\x1b[5;2~" }, { "kPRV3", "\x1b[5;3~" },
- { "kPRV4", "\x1b[5;4~" }, { "kPRV5", "\x1b[5;5~" },
- { "kPRV6", "\x1b[5;6~" }, { "kPRV7", "\x1b[5;7~" },
- { "kRIT", "\x1b[1;2C" }, { "kRIT3", "\x1b[1;3C" },
- { "kRIT4", "\x1b[1;4C" }, { "kRIT5", "\x1b[1;5C" },
- { "kRIT6", "\x1b[1;6C" }, { "kRIT7", "\x1b[1;7C" },
- { "kUP", "\x1b[1;2A" }, { "kUP3", "\x1b[1;3A" },
- { "kUP4", "\x1b[1;4A" }, { "kUP5", "\x1b[1;5A" },
- { "kUP6", "\x1b[1;6A" }, { "kUP7", "\x1b[1;7A" },
- { "kbs", "\x7f" }, { "kcbt", "\x1b[Z" },
- { "kcub1", "\x1bOD" }, { "kcud1", "\x1bOB" },
- { "kcuf1", "\x1bOC" }, { "kcuu1", "\x1bOA" },
- { "kdch1", "\x1b[3~" }, { "kend", "\x1bOF" },
- { "kent", "\x1bOM" }, { "khome", "\x1bOH" },
- { "kich1", "\x1b[2~" }, { "kind", "\x1b[1;2B" },
- { "kmous", "\x1b[<" }, { "knp", "\x1b[6~" },
- { "kpp", "\x1b[5~" }, { "kri", "\x1b[1;2A" },
- { "kxIN", "\x1b[I" }, { "kxOUT", "\x1b[O" },
- { "kf1", "\x1bOP" }, { "kf2", "\x1bOQ" },
- { "kf3", "\x1bOR" }, { "kf4", "\x1bOS" },
- { "kf5", "\x1b[15~" }, { "kf6", "\x1b[17~" },
- { "kf7", "\x1b[18~" }, { "kf8", "\x1b[19~" },
- { "kf9", "\x1b[20~" }, { "kf10", "\x1b[21~" },
- { "kf11", "\x1b[23~" }, { "kf12", "\x1b[24~" },
- { "kf13", "\x1b[1;2P" }, { "kf14", "\x1b[1;2Q" },
- { "kf15", "\x1b[1;2R" }, { "kf16", "\x1b[1;2S" },
- { "kf17", "\x1b[15;2~" }, { "kf18", "\x1b[17;2~" },
- { "kf19", "\x1b[18;2~" }, { "kf20", "\x1b[19;2~" },
- { "kf21", "\x1b[20;2~" }, { "kf22", "\x1b[21;2~" },
- { "kf23", "\x1b[23;2~" }, { "kf24", "\x1b[24;2~" },
- { "kf25", "\x1b[1;5P" }, { "kf26", "\x1b[1;5Q" },
- { "kf27", "\x1b[1;5R" }, { "kf28", "\x1b[1;5S" },
- { "kf29", "\x1b[15;5~" }, { "kf30", "\x1b[17;5~" },
- { "kf31", "\x1b[18;5~" }, { "kf32", "\x1b[19;5~" },
- { "kf33", "\x1b[20;5~" }, { "kf34", "\x1b[21;5~" },
- { "kf35", "\x1b[23;5~" }, { "kf36", "\x1b[24;5~" },
- { "kf37", "\x1b[1;6P" }, { "kf38", "\x1b[1;6Q" },
- { "kf39", "\x1b[1;6R" }, { "kf40", "\x1b[1;6S" },
- { "kf41", "\x1b[15;6~" }, { "kf42", "\x1b[17;6~" },
- { "kf43", "\x1b[18;6~" }, { "kf44", "\x1b[19;6~" },
- { "kf45", "\x1b[20;6~" }, { "kf46", "\x1b[21;6~" },
- { "kf47", "\x1b[23;6~" }, { "kf48", "\x1b[24;6~" },
+ static const struct tcap_entry caps[] = {
+ { "Co", "16777216" }, { "RGB", "8/8/8" },
+ { "colors", "16777216" }, { "kDC", "\x1b[3;2~" },
+ { "kDC3", "\x1b[3;3~" }, { "kDC4", "\x1b[3;4~" },
+ { "kDC5", "\x1b[3;5~" }, { "kDC6", "\x1b[3;6~" },
+ { "kDC7", "\x1b[3;7~" }, { "kDN", "\x1b[1;2B" },
+ { "kDN3", "\x1b[1;3B" }, { "kDN4", "\x1b[1;4B" },
+ { "kDN5", "\x1b[1;5B" }, { "kDN6", "\x1b[1;6B" },
+ { "kDN7", "\x1b[1;7B" }, { "kEND", "\x1b[1;2F" },
+ { "kEND3", "\x1b[1;3F" }, { "kEND4", "\x1b[1;4F" },
+ { "kEND5", "\x1b[1;5F" }, { "kEND6", "\x1b[1;6F" },
+ { "kEND7", "\x1b[1;7F" }, { "kHOM", "\x1b[1;2H" },
+ { "kHOM3", "\x1b[1;3H" }, { "kHOM4", "\x1b[1;4H" },
+ { "kHOM5", "\x1b[1;5H" }, { "kHOM6", "\x1b[1;6H" },
+ { "kHOM7", "\x1b[1;7H" }, { "kIC", "\x1b[2;2~" },
+ { "kIC3", "\x1b[2;3~" }, { "kIC4", "\x1b[2;4~" },
+ { "kIC5", "\x1b[2;5~" }, { "kIC6", "\x1b[2;6~" },
+ { "kIC7", "\x1b[2;7~" }, { "kLFT", "\x1b[1;2D" },
+ { "kLFT3", "\x1b[1;3D" }, { "kLFT4", "\x1b[1;4D" },
+ { "kLFT5", "\x1b[1;5D" }, { "kLFT6", "\x1b[1;6D" },
+ { "kLFT7", "\x1b[1;7D" }, { "kNXT", "\x1b[6;2~" },
+ { "kNXT3", "\x1b[6;3~" }, { "kNXT4", "\x1b[6;4~" },
+ { "kNXT5", "\x1b[6;5~" }, { "kNXT6", "\x1b[6;6~" },
+ { "kNXT7", "\x1b[6;7~" }, { "kPRV", "\x1b[5;2~" },
+ { "kPRV3", "\x1b[5;3~" }, { "kPRV4", "\x1b[5;4~" },
+ { "kPRV5", "\x1b[5;5~" }, { "kPRV6", "\x1b[5;6~" },
+ { "kPRV7", "\x1b[5;7~" }, { "kRIT", "\x1b[1;2C" },
+ { "kRIT3", "\x1b[1;3C" }, { "kRIT4", "\x1b[1;4C" },
+ { "kRIT5", "\x1b[1;5C" }, { "kRIT6", "\x1b[1;6C" },
+ { "kRIT7", "\x1b[1;7C" }, { "kUP", "\x1b[1;2A" },
+ { "kUP3", "\x1b[1;3A" }, { "kUP4", "\x1b[1;4A" },
+ { "kUP5", "\x1b[1;5A" }, { "kUP6", "\x1b[1;6A" },
+ { "kUP7", "\x1b[1;7A" }, { "kbs", "\x7f" },
+ { "kcbt", "\x1b[Z" }, { "kcub1", "\x1bOD" },
+ { "kcud1", "\x1bOB" }, { "kcuf1", "\x1bOC" },
+ { "kcuu1", "\x1bOA" }, { "kdch1", "\x1b[3~" },
+ { "kend", "\x1bOF" }, { "kent", "\x1bOM" },
+ { "kf1", "\x1bOP" }, { "kf10", "\x1b[21~" },
+ { "kf11", "\x1b[23~" }, { "kf12", "\x1b[24~" },
+ { "kf13", "\x1b[1;2P" }, { "kf14", "\x1b[1;2Q" },
+ { "kf15", "\x1b[1;2R" }, { "kf16", "\x1b[1;2S" },
+ { "kf17", "\x1b[15;2~" }, { "kf18", "\x1b[17;2~" },
+ { "kf19", "\x1b[18;2~" }, { "kf2", "\x1bOQ" },
+ { "kf20", "\x1b[19;2~" }, { "kf21", "\x1b[20;2~" },
+ { "kf22", "\x1b[21;2~" }, { "kf23", "\x1b[23;2~" },
+ { "kf24", "\x1b[24;2~" }, { "kf25", "\x1b[1;5P" },
+ { "kf26", "\x1b[1;5Q" }, { "kf27", "\x1b[1;5R" },
+ { "kf28", "\x1b[1;5S" }, { "kf29", "\x1b[15;5~" },
+ { "kf3", "\x1bOR" }, { "kf30", "\x1b[17;5~" },
+ { "kf31", "\x1b[18;5~" }, { "kf32", "\x1b[19;5~" },
+ { "kf33", "\x1b[20;5~" }, { "kf34", "\x1b[21;5~" },
+ { "kf35", "\x1b[23;5~" }, { "kf36", "\x1b[24;5~" },
+ { "kf37", "\x1b[1;6P" }, { "kf38", "\x1b[1;6Q" },
+ { "kf39", "\x1b[1;6R" }, { "kf4", "\x1bOS" },
+ { "kf40", "\x1b[1;6S" }, { "kf41", "\x1b[15;6~" },
+ { "kf42", "\x1b[17;6~" }, { "kf43", "\x1b[18;6~" },
+ { "kf44", "\x1b[19;6~" }, { "kf45", "\x1b[20;6~" },
+ { "kf46", "\x1b[21;6~" }, { "kf47", "\x1b[23;6~" },
+ { "kf48", "\x1b[24;6~" }, { "kf5", "\x1b[15~" },
+ { "kf6", "\x1b[17~" }, { "kf7", "\x1b[18~" },
+ { "kf8", "\x1b[19~" }, { "kf9", "\x1b[20~" },
+ { "khome", "\x1bOH" }, { "kich1", "\x1b[2~" },
+ { "kind", "\x1b[1;2B" }, { "kmous", "\x1b[<" },
+ { "knp", "\x1b[6~" }, { "kpp", "\x1b[5~" },
+ { "kri", "\x1b[1;2A" }, { "kxIN", "\x1b[I" },
+ { "kxOUT", "\x1b[O" },
};
if (!strcmp(name, "TN") || !strcmp(name, "name"))
return t->tcap_name;
- for (size_t i = 0; i < sizeof(caps) / sizeof(caps[0]); i++)
- if (!strcmp(name, caps[i].name))
- return caps[i].value;
- return NULL;
+ const struct tcap_entry *found = bsearch(name, caps,
+ sizeof(caps) / sizeof(caps[0]),
+ sizeof(caps[0]), tcap_cmp);
+ return found ? found->value : NULL;
}
struct resp_buf {
@@ -154,9 +183,7 @@ static void resp_put(struct resp_buf *r, const char *s, size_t n)
if (r->failed)
return;
if (r->len + n + 1 > r->cap) {
- size_t cap = r->cap ? r->cap : 256;
- while (cap < r->len + n + 1)
- cap *= 2;
+ size_t cap = term_grow_cap(r->cap ? r->cap : 256, r->len + n + 1);
char *p = realloc(r->s, cap);
if (!p) {
r->failed = true;