From b381d2eb65db7cfe3b2fa3c4aca675c33091254a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 18 Aug 2026 08:05:51 +0530 Subject: [PATCH] Cleanup OSC/APC number parsing --- gen/apc_parsers.py | 10 +- kitty/parse-dnd-command.h | 52 ++- kitty/parse-graphics-command.h | 581 ++++++++++++-------------------- kitty/parse-multicell-command.h | 304 +++++++---------- kitty/vt-parser.c | 30 +- 5 files changed, 365 insertions(+), 612 deletions(-) diff --git a/gen/apc_parsers.py b/gen/apc_parsers.py index 3e993dcfc..9fef0f46e 100755 --- a/gen/apc_parsers.py +++ b/gen/apc_parsers.py @@ -168,7 +168,7 @@ static inline void enum PARSER_STATES state = KEY, value_state = FLAG; {command_class} g = {{0}};{post_init_line} unsigned int i, code; - uint64_t lcode; int64_t accumulator; + uint64_t lcode; bool is_negative; (void)is_negative; size_t sz; {keys_enum} @@ -207,12 +207,12 @@ static inline void case INT: #define READ_UINT \\ - for (i = pos, accumulator=0; i < MIN(parser_buf_pos, pos + 10); i++) {{ \\ - int64_t n = parser_buf[i] - '0'; if (n < 0 || n > 9) break; \\ - accumulator += n * digit_multipliers[i - pos]; \\ + for (i = pos, lcode=0; i < MIN(parser_buf_pos, pos + 10); i++) {{ \\ + uint8_t n = parser_buf[i] - '0'; if (n > 9) break; \\ + lcode = lcode * 10 + n; \\ }} \\ if (i == pos) {{ REPORT_ERROR("Malformed {command_class} control block, expecting an integer value for key: %c", key & 0xFF); return; }} \\ - lcode = accumulator / digit_multipliers[i - pos - 1]; pos = i; \\ + pos = i; \\ if (lcode > UINT32_MAX) {{ REPORT_ERROR("Malformed {command_class} control block, number is too large"); return; }} \\ code = lcode; diff --git a/kitty/parse-dnd-command.h b/kitty/parse-dnd-command.h index 7bb115d6f..7af764bd4 100644 --- a/kitty/parse-dnd-command.h +++ b/kitty/parse-dnd-command.h @@ -13,7 +13,6 @@ parse_dnd_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { DnDCommand g = {0}; unsigned int i, code; uint64_t lcode; - int64_t accumulator; bool is_negative; (void)is_negative; size_t sz; @@ -43,10 +42,7 @@ parse_dnd_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { case EQUAL: if (parser_buf[pos++] != '=') { - REPORT_ERROR( - "Malformed DnDCommand control block, no = after key, " - "found: 0x%x instead", - parser_buf[pos - 1]); + REPORT_ERROR("Malformed DnDCommand control block, no = after key, found: 0x%x instead", parser_buf[pos - 1]); return; } state = value_state; @@ -58,10 +54,7 @@ parse_dnd_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { g.type = parser_buf[pos++]; if (g.type != 'A' && g.type != 'E' && g.type != 'M' && g.type != 'P' && g.type != 'R' && g.type != 'a' && g.type != 'e' && g.type != 'k' && g.type != 'm' && g.type != 'o' && g.type != 'p' && g.type != 'q' && g.type != 'r') { - REPORT_ERROR( - "Malformed DnDCommand control block, unknown flag value " - "for type: 0x%x", - g.type); + REPORT_ERROR("Malformed DnDCommand control block, unknown flag value for type: 0x%x", g.type); return; }; } break; @@ -72,25 +65,21 @@ parse_dnd_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { break; case INT: -#define READ_UINT \ - for (i = pos, accumulator = 0; i < MIN(parser_buf_pos, pos + 10); i++) { \ - int64_t n = parser_buf[i] - '0'; \ - if (n < 0 || n > 9) break; \ - accumulator += n * digit_multipliers[i - pos]; \ - } \ - if (i == pos) { \ - REPORT_ERROR( \ - "Malformed DnDCommand control block, expecting an integer " \ - "value for key: %c", \ - key & 0xFF); \ - return; \ - } \ - lcode = accumulator / digit_multipliers[i - pos - 1]; \ - pos = i; \ - if (lcode > UINT32_MAX) { \ - REPORT_ERROR("Malformed DnDCommand control block, number is too large"); \ - return; \ - } \ +#define READ_UINT \ + for (i = pos, lcode = 0; i < MIN(parser_buf_pos, pos + 10); i++) { \ + uint8_t n = parser_buf[i] - '0'; \ + if (n > 9) break; \ + lcode = lcode * 10 + n; \ + } \ + if (i == pos) { \ + REPORT_ERROR("Malformed DnDCommand control block, expecting an integer value for key: %c", key & 0xFF); \ + return; \ + } \ + pos = i; \ + if (lcode > UINT32_MAX) { \ + REPORT_ERROR("Malformed DnDCommand control block, number is too large"); \ + return; \ + } \ code = lcode; is_negative = false; @@ -128,16 +117,14 @@ parse_dnd_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { case AFTER_VALUE: switch (parser_buf[pos++]) { default: - REPORT_ERROR( - "Malformed DnDCommand control block, expecting a : or " - "semi-colon after a value, found: 0x%x", - parser_buf[pos - 1]); + REPORT_ERROR("Malformed DnDCommand control block, expecting a : or semi-colon after a value, found: 0x%x", parser_buf[pos - 1]); return; case ':': state = KEY; break; case ';': state = PAYLOAD; break; } break; + case PAYLOAD: { sz = parser_buf_pos - pos; payload_start = pos; @@ -145,6 +132,7 @@ parse_dnd_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { pos = parser_buf_pos; } break; + } // end switch } // end while diff --git a/kitty/parse-graphics-command.h b/kitty/parse-graphics-command.h index 68bf70b0d..e772f3aa3 100644 --- a/kitty/parse-graphics-command.h +++ b/kitty/parse-graphics-command.h @@ -2,395 +2,238 @@ #pragma once -#include "base64.h" + #include "base64.h" -static inline void parse_graphics_code(PS *self, uint8_t *parser_buf, - const size_t parser_buf_pos) { - unsigned int pos = 1; +static inline void +parse_graphics_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { + unsigned int pos = 1; + + enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE , PAYLOAD }; + enum PARSER_STATES state = KEY, value_state = FLAG; + GraphicsCommand g = {0}; + unsigned int i, code; + uint64_t lcode; + bool is_negative; (void)is_negative; + size_t sz; + + enum KEYS { + action='a', +delete_action='d', +transmission_type='t', +compressed='o', +format='f', +more='m', +id='i', +image_number='I', +placement_id='p', +quiet='q', +width='w', +height='h', +x_offset='x', +y_offset='y', +data_height='v', +data_width='s', +data_sz='S', +data_offset='O', +num_cells='c', +num_lines='r', +cell_x_offset='X', +cell_y_offset='Y', +z_index='z', +cursor_movement='C', +unicode_placement='U', +parent_id='P', +parent_placement_id='Q', +usage_hints='N', +offset_from_parent_x='H', +offset_from_parent_y='V' + }; + + enum KEYS key = 'a'; + if (parser_buf[pos] == ';') state = AFTER_VALUE; - enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD }; - enum PARSER_STATES state = KEY, value_state = FLAG; - GraphicsCommand g = {0}; - unsigned int i, code; - uint64_t lcode; - int64_t accumulator; - bool is_negative; - (void)is_negative; - size_t sz; + while (pos < parser_buf_pos) { + switch(state) { + case KEY: + key = parser_buf[pos++]; + state = EQUAL; + switch(key) { + case action: value_state = FLAG; break; +case delete_action: value_state = FLAG; break; +case transmission_type: value_state = FLAG; break; +case compressed: value_state = FLAG; break; +case format: value_state = UINT; break; +case more: value_state = UINT; break; +case id: value_state = UINT; break; +case image_number: value_state = UINT; break; +case placement_id: value_state = UINT; break; +case quiet: value_state = UINT; break; +case width: value_state = UINT; break; +case height: value_state = UINT; break; +case x_offset: value_state = UINT; break; +case y_offset: value_state = UINT; break; +case data_height: value_state = UINT; break; +case data_width: value_state = UINT; break; +case data_sz: value_state = UINT; break; +case data_offset: value_state = UINT; break; +case num_cells: value_state = UINT; break; +case num_lines: value_state = UINT; break; +case cell_x_offset: value_state = UINT; break; +case cell_y_offset: value_state = UINT; break; +case z_index: value_state = INT; break; +case cursor_movement: value_state = UINT; break; +case unicode_placement: value_state = UINT; break; +case parent_id: value_state = UINT; break; +case parent_placement_id: value_state = UINT; break; +case usage_hints: value_state = UINT; break; +case offset_from_parent_x: value_state = INT; break; +case offset_from_parent_y: value_state = INT; break; + default: + REPORT_ERROR("Malformed GraphicsCommand control block, invalid key character: 0x%x", key); + return; + } + break; - enum KEYS { - action = 'a', - delete_action = 'd', - transmission_type = 't', - compressed = 'o', - format = 'f', - more = 'm', - id = 'i', - image_number = 'I', - placement_id = 'p', - quiet = 'q', - width = 'w', - height = 'h', - x_offset = 'x', - y_offset = 'y', - data_height = 'v', - data_width = 's', - data_sz = 'S', - data_offset = 'O', - num_cells = 'c', - num_lines = 'r', - cell_x_offset = 'X', - cell_y_offset = 'Y', - z_index = 'z', - cursor_movement = 'C', - unicode_placement = 'U', - parent_id = 'P', - parent_placement_id = 'Q', - usage_hints = 'N', - offset_from_parent_x = 'H', - offset_from_parent_y = 'V' - }; + case EQUAL: + if (parser_buf[pos++] != '=') { + REPORT_ERROR("Malformed GraphicsCommand control block, no = after key, found: 0x%x instead", parser_buf[pos-1]); + return; + } + state = value_state; + break; - enum KEYS key = 'a'; - if (parser_buf[pos] == ';') - state = AFTER_VALUE; + case FLAG: + switch(key) { + + case action: { + g.action = parser_buf[pos++]; + if (g.action != 'T' && g.action != 'a' && g.action != 'c' && g.action != 'd' && g.action != 'f' && g.action != 'p' && g.action != 'q' && g.action != 't') { + REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag value for action: 0x%x", g.action); + return; + }; + } + break; + - while (pos < parser_buf_pos) { - switch (state) { - case KEY: - key = parser_buf[pos++]; - state = EQUAL; - switch (key) { - case action: - value_state = FLAG; - break; - case delete_action: - value_state = FLAG; - break; - case transmission_type: - value_state = FLAG; - break; - case compressed: - value_state = FLAG; - break; - case format: - value_state = UINT; - break; - case more: - value_state = UINT; - break; - case id: - value_state = UINT; - break; - case image_number: - value_state = UINT; - break; - case placement_id: - value_state = UINT; - break; - case quiet: - value_state = UINT; - break; - case width: - value_state = UINT; - break; - case height: - value_state = UINT; - break; - case x_offset: - value_state = UINT; - break; - case y_offset: - value_state = UINT; - break; - case data_height: - value_state = UINT; - break; - case data_width: - value_state = UINT; - break; - case data_sz: - value_state = UINT; - break; - case data_offset: - value_state = UINT; - break; - case num_cells: - value_state = UINT; - break; - case num_lines: - value_state = UINT; - break; - case cell_x_offset: - value_state = UINT; - break; - case cell_y_offset: - value_state = UINT; - break; - case z_index: - value_state = INT; - break; - case cursor_movement: - value_state = UINT; - break; - case unicode_placement: - value_state = UINT; - break; - case parent_id: - value_state = UINT; - break; - case parent_placement_id: - value_state = UINT; - break; - case usage_hints: - value_state = UINT; - break; - case offset_from_parent_x: - value_state = INT; - break; - case offset_from_parent_y: - value_state = INT; - break; - default: - REPORT_ERROR("Malformed GraphicsCommand control block, invalid key " - "character: 0x%x", - key); - return; - } - break; + case delete_action: { + g.delete_action = parser_buf[pos++]; + if (g.delete_action != 'A' && g.delete_action != 'C' && g.delete_action != 'F' && g.delete_action != 'I' && g.delete_action != 'N' && g.delete_action != 'P' && g.delete_action != 'Q' && g.delete_action != 'R' && g.delete_action != 'X' && g.delete_action != 'Y' && g.delete_action != 'Z' && g.delete_action != 'a' && g.delete_action != 'c' && g.delete_action != 'f' && g.delete_action != 'i' && g.delete_action != 'n' && g.delete_action != 'p' && g.delete_action != 'q' && g.delete_action != 'r' && g.delete_action != 'x' && g.delete_action != 'y' && g.delete_action != 'z') { + REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag value for delete_action: 0x%x", g.delete_action); + return; + }; + } + break; + - case EQUAL: - if (parser_buf[pos++] != '=') { - REPORT_ERROR("Malformed GraphicsCommand control block, no = after key, " - "found: 0x%x instead", - parser_buf[pos - 1]); - return; - } - state = value_state; - break; + case transmission_type: { + g.transmission_type = parser_buf[pos++]; + if (g.transmission_type != 'd' && g.transmission_type != 'f' && g.transmission_type != 's' && g.transmission_type != 't') { + REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag value for transmission_type: 0x%x", g.transmission_type); + return; + }; + } + break; + - case FLAG: - switch (key) { + case compressed: { + g.compressed = parser_buf[pos++]; + if (g.compressed != 'z') { + REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag value for compressed: 0x%x", g.compressed); + return; + }; + } + break; + + default: + break; + } + state = AFTER_VALUE; + break; - case action: { - g.action = parser_buf[pos++]; - if (g.action != 'T' && g.action != 'a' && g.action != 'c' && - g.action != 'd' && g.action != 'f' && g.action != 'p' && - g.action != 'q' && g.action != 't') { - REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag " - "value for action: 0x%x", - g.action); - return; - }; - } break; + case INT: +#define READ_UINT \ + for (i = pos, lcode=0; i < MIN(parser_buf_pos, pos + 10); i++) { \ + uint8_t n = parser_buf[i] - '0'; if (n > 9) break; \ + lcode = lcode * 10 + n; \ + } \ + if (i == pos) { REPORT_ERROR("Malformed GraphicsCommand control block, expecting an integer value for key: %c", key & 0xFF); return; } \ + pos = i; \ + if (lcode > UINT32_MAX) { REPORT_ERROR("Malformed GraphicsCommand control block, number is too large"); return; } \ + code = lcode; - case delete_action: { - g.delete_action = parser_buf[pos++]; - if (g.delete_action != 'A' && g.delete_action != 'C' && - g.delete_action != 'F' && g.delete_action != 'I' && - g.delete_action != 'N' && g.delete_action != 'P' && - g.delete_action != 'Q' && g.delete_action != 'R' && - g.delete_action != 'X' && g.delete_action != 'Y' && - g.delete_action != 'Z' && g.delete_action != 'a' && - g.delete_action != 'c' && g.delete_action != 'f' && - g.delete_action != 'i' && g.delete_action != 'n' && - g.delete_action != 'p' && g.delete_action != 'q' && - g.delete_action != 'r' && g.delete_action != 'x' && - g.delete_action != 'y' && g.delete_action != 'z') { - REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag " - "value for delete_action: 0x%x", - g.delete_action); - return; - }; - } break; - - case transmission_type: { - g.transmission_type = parser_buf[pos++]; - if (g.transmission_type != 'd' && g.transmission_type != 'f' && - g.transmission_type != 's' && g.transmission_type != 't') { - REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag " - "value for transmission_type: 0x%x", - g.transmission_type); - return; - }; - } break; - - case compressed: { - g.compressed = parser_buf[pos++]; - if (g.compressed != 'z') { - REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag " - "value for compressed: 0x%x", - g.compressed); - return; - }; - } break; - - default: - break; - } - state = AFTER_VALUE; - break; - - case INT: -#define READ_UINT \ - for (i = pos, accumulator = 0; i < MIN(parser_buf_pos, pos + 10); i++) { \ - int64_t n = parser_buf[i] - '0'; \ - if (n < 0 || n > 9) \ - break; \ - accumulator += n * digit_multipliers[i - pos]; \ - } \ - if (i == pos) { \ - REPORT_ERROR("Malformed GraphicsCommand control block, expecting an " \ - "integer value for key: %c", \ - key & 0xFF); \ - return; \ - } \ - lcode = accumulator / digit_multipliers[i - pos - 1]; \ - pos = i; \ - if (lcode > UINT32_MAX) { \ - REPORT_ERROR( \ - "Malformed GraphicsCommand control block, number is too large"); \ - return; \ - } \ - code = lcode; - - is_negative = false; - if (parser_buf[pos] == '-') { - is_negative = true; - pos++; - } -#define I(x) \ - case x: \ - g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; \ - break - READ_UINT; - switch (key) { - I(z_index); - I(offset_from_parent_x); - I(offset_from_parent_y); - default: - break; - } - state = AFTER_VALUE; - break; + is_negative = false; + if(parser_buf[pos] == '-') { is_negative = true; pos++; } +#define I(x) case x: g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; break + READ_UINT; + switch(key) { + I(z_index); I(offset_from_parent_x); I(offset_from_parent_y); + default: break; + } + state = AFTER_VALUE; + break; #undef I - case UINT: - READ_UINT; -#define U(x) \ - case x: \ - g.x = code; \ - break - switch (key) { - U(format); - U(more); - U(id); - U(image_number); - U(placement_id); - U(quiet); - U(width); - U(height); - U(x_offset); - U(y_offset); - U(data_height); - U(data_width); - U(data_sz); - U(data_offset); - U(num_cells); - U(num_lines); - U(cell_x_offset); - U(cell_y_offset); - U(cursor_movement); - U(unicode_placement); - U(parent_id); - U(parent_placement_id); - U(usage_hints); - default: - break; - } - state = AFTER_VALUE; - break; + case UINT: + READ_UINT; +#define U(x) case x: g.x = code; break + switch(key) { + U(format); U(more); U(id); U(image_number); U(placement_id); U(quiet); U(width); U(height); U(x_offset); U(y_offset); U(data_height); U(data_width); U(data_sz); U(data_offset); U(num_cells); U(num_lines); U(cell_x_offset); U(cell_y_offset); U(cursor_movement); U(unicode_placement); U(parent_id); U(parent_placement_id); U(usage_hints); + default: break; + } + state = AFTER_VALUE; + break; #undef U #undef READ_UINT - case AFTER_VALUE: - switch (parser_buf[pos++]) { - default: - REPORT_ERROR("Malformed GraphicsCommand control block, expecting a , " - "or semi-colon after a value, found: 0x%x", - parser_buf[pos - 1]); - return; - case ',': - state = KEY; - break; - case ';': - state = PAYLOAD; - break; - } - break; + case AFTER_VALUE: + switch (parser_buf[pos++]) { + default: + REPORT_ERROR("Malformed GraphicsCommand control block, expecting a , or semi-colon after a value, found: 0x%x", + parser_buf[pos - 1]); + return; + case ',': + state = KEY; + break; + case ';': state = PAYLOAD; break; + } + break; - case PAYLOAD: { - sz = parser_buf_pos - pos; - g.payload_sz = MAX(BUF_EXTRA, sz); - if (!base64_decode8(parser_buf + pos, sz, parser_buf, &g.payload_sz)) { - g.payload_sz = MAX(BUF_EXTRA, sz); - REPORT_ERROR("Failed to parse GraphicsCommand command payload with " - "error: invalid base64 data in chunk of size: %zu " - "with output buffer size: %zu", - sz, g.payload_sz); - return; - } - pos = parser_buf_pos; - } break; + + case PAYLOAD: { + sz = parser_buf_pos - pos; + g.payload_sz = MAX(BUF_EXTRA, sz); + if (!base64_decode8(parser_buf + pos, sz, parser_buf, &g.payload_sz)) { + g.payload_sz = MAX(BUF_EXTRA, sz); + REPORT_ERROR("Failed to parse GraphicsCommand command payload with error: invalid base64 data in chunk of size: %zu with output buffer size: %zu", sz, g.payload_sz); return; } + pos = parser_buf_pos; + } break; + - } // end switch - } // end while + } // end switch + } // end while - switch (state) { - case EQUAL: - REPORT_ERROR("Malformed GraphicsCommand control block, no = after key"); - return; - case INT: - case UINT: - REPORT_ERROR( - "Malformed GraphicsCommand control block, expecting an integer value"); - return; - case FLAG: - REPORT_ERROR( - "Malformed GraphicsCommand control block, expecting a flag value"); - return; - default: - break; - } + switch(state) { + case EQUAL: + REPORT_ERROR("Malformed GraphicsCommand control block, no = after key"); return; + case INT: + case UINT: + REPORT_ERROR("Malformed GraphicsCommand control block, expecting an integer value"); return; + case FLAG: + REPORT_ERROR("Malformed GraphicsCommand control block, expecting a flag value"); return; + default: + break; + } - REPORT_VA_COMMAND( - "K s {sc sc sc sc sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI " - "sI sI sI sI sI si si si ss#}", - self->window_id, "graphics_command", + REPORT_VA_COMMAND("K s {sc sc sc sc sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI si si si ss#}", self->window_id, "graphics_command", - "action", g.action, "delete_action", g.delete_action, "transmission_type", - g.transmission_type, "compressed", g.compressed, +"action", g.action, "delete_action", g.delete_action, "transmission_type", g.transmission_type, "compressed", g.compressed, - "format", (unsigned int)g.format, "more", (unsigned int)g.more, "id", - (unsigned int)g.id, "image_number", (unsigned int)g.image_number, - "placement_id", (unsigned int)g.placement_id, "quiet", - (unsigned int)g.quiet, "width", (unsigned int)g.width, "height", - (unsigned int)g.height, "x_offset", (unsigned int)g.x_offset, "y_offset", - (unsigned int)g.y_offset, "data_height", (unsigned int)g.data_height, - "data_width", (unsigned int)g.data_width, "data_sz", - (unsigned int)g.data_sz, "data_offset", (unsigned int)g.data_offset, - "num_cells", (unsigned int)g.num_cells, "num_lines", - (unsigned int)g.num_lines, "cell_x_offset", (unsigned int)g.cell_x_offset, - "cell_y_offset", (unsigned int)g.cell_y_offset, "cursor_movement", - (unsigned int)g.cursor_movement, "unicode_placement", - (unsigned int)g.unicode_placement, "parent_id", (unsigned int)g.parent_id, - "parent_placement_id", (unsigned int)g.parent_placement_id, "usage_hints", - (unsigned int)g.usage_hints, +"format", (unsigned int)g.format, "more", (unsigned int)g.more, "id", (unsigned int)g.id, "image_number", (unsigned int)g.image_number, "placement_id", (unsigned int)g.placement_id, "quiet", (unsigned int)g.quiet, "width", (unsigned int)g.width, "height", (unsigned int)g.height, "x_offset", (unsigned int)g.x_offset, "y_offset", (unsigned int)g.y_offset, "data_height", (unsigned int)g.data_height, "data_width", (unsigned int)g.data_width, "data_sz", (unsigned int)g.data_sz, "data_offset", (unsigned int)g.data_offset, "num_cells", (unsigned int)g.num_cells, "num_lines", (unsigned int)g.num_lines, "cell_x_offset", (unsigned int)g.cell_x_offset, "cell_y_offset", (unsigned int)g.cell_y_offset, "cursor_movement", (unsigned int)g.cursor_movement, "unicode_placement", (unsigned int)g.unicode_placement, "parent_id", (unsigned int)g.parent_id, "parent_placement_id", (unsigned int)g.parent_placement_id, "usage_hints", (unsigned int)g.usage_hints, - "z_index", (int)g.z_index, "offset_from_parent_x", - (int)g.offset_from_parent_x, "offset_from_parent_y", - (int)g.offset_from_parent_y, +"z_index", (int)g.z_index, "offset_from_parent_x", (int)g.offset_from_parent_x, "offset_from_parent_y", (int)g.offset_from_parent_y, - "", (char *)parser_buf, g.payload_sz); +"", (char*)parser_buf, g.payload_sz +); - screen_handle_graphics_command(self->screen, &g, parser_buf); + screen_handle_graphics_command(self->screen, &g, parser_buf); } + diff --git a/kitty/parse-multicell-command.h b/kitty/parse-multicell-command.h index 3b1121f41..046715f7d 100644 --- a/kitty/parse-multicell-command.h +++ b/kitty/parse-multicell-command.h @@ -2,201 +2,145 @@ #pragma once -#include "base64.h" + #include "base64.h" -static inline void parse_multicell_code(PS *self, uint8_t *parser_buf, - const size_t parser_buf_pos) { - unsigned int pos = 0; - size_t payload_start = 0; - enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD }; - enum PARSER_STATES state = KEY, value_state = FLAG; - MultiCellCommand g = {0}; - unsigned int i, code; - uint64_t lcode; - int64_t accumulator; - bool is_negative; - (void)is_negative; - size_t sz; +static inline void +parse_multicell_code(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) { + unsigned int pos = 0; + size_t payload_start = 0; + enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE , PAYLOAD }; + enum PARSER_STATES state = KEY, value_state = FLAG; + MultiCellCommand g = {0}; + unsigned int i, code; + uint64_t lcode; + bool is_negative; (void)is_negative; + size_t sz; + + enum KEYS { + width='w', +scale='s', +subscale_n='n', +subscale_d='d', +vertical_align='v', +horizontal_align='h' + }; + + enum KEYS key = 'a'; + if (parser_buf[pos] == ';') state = AFTER_VALUE; - enum KEYS { - width = 'w', - scale = 's', - subscale_n = 'n', - subscale_d = 'd', - vertical_align = 'v', - horizontal_align = 'h' - }; + while (pos < parser_buf_pos) { + switch(state) { + case KEY: + key = parser_buf[pos++]; + state = EQUAL; + switch(key) { + case width: value_state = UINT; break; +case scale: value_state = UINT; break; +case subscale_n: value_state = UINT; break; +case subscale_d: value_state = UINT; break; +case vertical_align: value_state = UINT; break; +case horizontal_align: value_state = UINT; break; + default: + REPORT_ERROR("Malformed MultiCellCommand control block, invalid key character: 0x%x", key); + return; + } + break; - enum KEYS key = 'a'; - if (parser_buf[pos] == ';') - state = AFTER_VALUE; + case EQUAL: + if (parser_buf[pos++] != '=') { + REPORT_ERROR("Malformed MultiCellCommand control block, no = after key, found: 0x%x instead", parser_buf[pos-1]); + return; + } + state = value_state; + break; - while (pos < parser_buf_pos) { - switch (state) { - case KEY: - key = parser_buf[pos++]; - state = EQUAL; - switch (key) { - case width: - value_state = UINT; - break; - case scale: - value_state = UINT; - break; - case subscale_n: - value_state = UINT; - break; - case subscale_d: - value_state = UINT; - break; - case vertical_align: - value_state = UINT; - break; - case horizontal_align: - value_state = UINT; - break; - default: - REPORT_ERROR("Malformed MultiCellCommand control block, invalid key " - "character: 0x%x", - key); - return; - } - break; + case FLAG: + switch(key) { + + default: + break; + } + state = AFTER_VALUE; + break; - case EQUAL: - if (parser_buf[pos++] != '=') { - REPORT_ERROR("Malformed MultiCellCommand control block, no = after " - "key, found: 0x%x instead", - parser_buf[pos - 1]); - return; - } - state = value_state; - break; + case INT: +#define READ_UINT \ + for (i = pos, lcode=0; i < MIN(parser_buf_pos, pos + 10); i++) { \ + uint8_t n = parser_buf[i] - '0'; if (n > 9) break; \ + lcode = lcode * 10 + n; \ + } \ + if (i == pos) { REPORT_ERROR("Malformed MultiCellCommand control block, expecting an integer value for key: %c", key & 0xFF); return; } \ + pos = i; \ + if (lcode > UINT32_MAX) { REPORT_ERROR("Malformed MultiCellCommand control block, number is too large"); return; } \ + code = lcode; - case FLAG: - switch (key) { - - default: - break; - } - state = AFTER_VALUE; - break; - - case INT: -#define READ_UINT \ - for (i = pos, accumulator = 0; i < MIN(parser_buf_pos, pos + 10); i++) { \ - int64_t n = parser_buf[i] - '0'; \ - if (n < 0 || n > 9) \ - break; \ - accumulator += n * digit_multipliers[i - pos]; \ - } \ - if (i == pos) { \ - REPORT_ERROR("Malformed MultiCellCommand control block, expecting an " \ - "integer value for key: %c", \ - key & 0xFF); \ - return; \ - } \ - lcode = accumulator / digit_multipliers[i - pos - 1]; \ - pos = i; \ - if (lcode > UINT32_MAX) { \ - REPORT_ERROR( \ - "Malformed MultiCellCommand control block, number is too large"); \ - return; \ - } \ - code = lcode; - - is_negative = false; - if (parser_buf[pos] == '-') { - is_negative = true; - pos++; - } -#define I(x) \ - case x: \ - g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; \ - break - READ_UINT; - switch (key) { - ; - default: - break; - } - state = AFTER_VALUE; - break; + is_negative = false; + if(parser_buf[pos] == '-') { is_negative = true; pos++; } +#define I(x) case x: g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; break + READ_UINT; + switch(key) { + ; + default: break; + } + state = AFTER_VALUE; + break; #undef I - case UINT: - READ_UINT; -#define U(x) \ - case x: \ - g.x = code; \ - break - switch (key) { - U(width); - U(scale); - U(subscale_n); - U(subscale_d); - U(vertical_align); - U(horizontal_align); - default: - break; - } - state = AFTER_VALUE; - break; + case UINT: + READ_UINT; +#define U(x) case x: g.x = code; break + switch(key) { + U(width); U(scale); U(subscale_n); U(subscale_d); U(vertical_align); U(horizontal_align); + default: break; + } + state = AFTER_VALUE; + break; #undef U #undef READ_UINT - case AFTER_VALUE: - switch (parser_buf[pos++]) { - default: - REPORT_ERROR("Malformed MultiCellCommand control block, expecting a : " - "or semi-colon after a value, found: 0x%x", - parser_buf[pos - 1]); - return; - case ':': - state = KEY; - break; - case ';': - state = PAYLOAD; - break; - } - break; + case AFTER_VALUE: + switch (parser_buf[pos++]) { + default: + REPORT_ERROR("Malformed MultiCellCommand control block, expecting a : or semi-colon after a value, found: 0x%x", + parser_buf[pos - 1]); + return; + case ':': + state = KEY; + break; + case ';': state = PAYLOAD; break; + } + break; - case PAYLOAD: { - sz = parser_buf_pos - pos; - payload_start = pos; - g.payload_sz = sz; - pos = parser_buf_pos; - } break; + + case PAYLOAD: { + sz = parser_buf_pos - pos; + payload_start = pos; + g.payload_sz = sz; + pos = parser_buf_pos; + } break; + - } // end switch - } // end while + } // end switch + } // end while - switch (state) { - case EQUAL: - REPORT_ERROR("Malformed MultiCellCommand control block, no = after key"); - return; - case INT: - case UINT: - REPORT_ERROR( - "Malformed MultiCellCommand control block, expecting an integer value"); - return; - case FLAG: - REPORT_ERROR( - "Malformed MultiCellCommand control block, expecting a flag value"); - return; - default: - break; - } + switch(state) { + case EQUAL: + REPORT_ERROR("Malformed MultiCellCommand control block, no = after key"); return; + case INT: + case UINT: + REPORT_ERROR("Malformed MultiCellCommand control block, expecting an integer value"); return; + case FLAG: + REPORT_ERROR("Malformed MultiCellCommand control block, expecting a flag value"); return; + default: + break; + } - REPORT_VA_COMMAND( - "K s { sI sI sI sI sI sI ss#}", self->window_id, "multicell_command", + REPORT_VA_COMMAND("K s { sI sI sI sI sI sI ss#}", self->window_id, "multicell_command", - "width", (unsigned int)g.width, "scale", (unsigned int)g.scale, - "subscale_n", (unsigned int)g.subscale_n, "subscale_d", - (unsigned int)g.subscale_d, "vertical_align", - (unsigned int)g.vertical_align, "horizontal_align", - (unsigned int)g.horizontal_align, +"width", (unsigned int)g.width, "scale", (unsigned int)g.scale, "subscale_n", (unsigned int)g.subscale_n, "subscale_d", (unsigned int)g.subscale_d, "vertical_align", (unsigned int)g.vertical_align, "horizontal_align", (unsigned int)g.horizontal_align, - "", (char *)parser_buf + payload_start, g.payload_sz); +"", (char*)parser_buf + payload_start, g.payload_sz +); - screen_handle_multicell_command(self->screen, &g, parser_buf + payload_start); + screen_handle_multicell_command(self->screen, &g, parser_buf + payload_start); } + diff --git a/kitty/vt-parser.c b/kitty/vt-parser.c index 9973d15d7..ae52839d8 100644 --- a/kitty/vt-parser.c +++ b/kitty/vt-parser.c @@ -179,24 +179,6 @@ _report_params_with_first(PyObject *dump_callback, id_type window_id, const char // }}} // Utils {{{ -static const int64_t digit_multipliers[] = { - 10000000000000000l, - 1000000000000000l, - 100000000000000l, - 10000000000000l, - 1000000000000l, - 100000000000l, - 10000000000l, - 1000000000l, - 100000000l, - 10000000l, - 1000000l, - 100000l, - 10000l, - 1000l, - 100l, - 1l}; - // }}} // Data structures {{{ @@ -548,18 +530,14 @@ dispatch_osc(PS *self, uint8_t *buf, size_t limit, bool is_extended_osc) { break; \ } - int64_t accumulator = 0; int code = 0; unsigned int i; for (i = 0; i < MIN(limit, 5u); i++) { - int64_t num = buf[i] - '0'; - if (num < 0 || num > 9) break; - accumulator += num * digit_multipliers[i]; - } - if (i > 0) { - code = accumulator / digit_multipliers[i - 1]; - if (i < limit && buf[i] == ';') i++; + uint8_t num = buf[i] - '0'; + if (num > 9) break; + code = code * 10 + num; } + if (i < limit && buf[i] == ';') i++; switch (code) { case 0: