From ead8e39a0a8f80180a17399ebc4d40f10c1579d5 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Tue, 5 Dec 2023 15:01:25 +0100 Subject: [PATCH] keysyms: Add XKB_KEYSYM_NAME_MAX_SIZE Currently there is no indication of the maximum length of keysym names. This is statically known, so add the new following API: `XKB_KEYSYM_NAME_MAX_SIZE`. --- doc/quick-guide.md | 2 +- include/xkbcommon/xkbcommon.h | 14 ++++++++++++-- include/xkbcommon/xkbcommon.h.jinja | 14 ++++++++++++-- scripts/update-headers.py | 10 ++++++++++ src/text.c | 4 ++-- test/common.c | 2 +- test/compose.c | 2 +- test/keysym.c | 14 +++++++++----- tools/compile-compose.c | 2 +- tools/how-to-type.c | 2 +- tools/tools-common.c | 5 ++++- 11 files changed, 54 insertions(+), 17 deletions(-) diff --git a/doc/quick-guide.md b/doc/quick-guide.md index eb1a757e8..07523f75e 100644 --- a/doc/quick-guide.md +++ b/doc/quick-guide.md @@ -135,7 +135,7 @@ from it. Given a keycode for a key, we can get its keysym: We can see which keysym we got, and get its name: ~~~{.c} - char keysym_name[64]; + char keysym_name[XKB_KEYSYM_NAME_MAX_SIZE]; if (keysym == XKB_KEY_Space) diff --git a/include/xkbcommon/xkbcommon.h b/include/xkbcommon/xkbcommon.h index dbc39b915..f203f6f38 100644 --- a/include/xkbcommon/xkbcommon.h +++ b/include/xkbcommon/xkbcommon.h @@ -321,6 +321,15 @@ typedef uint32_t xkb_led_mask_t; */ #define XKB_KEYSYM_MAX 0x1fffffff +/** + * Maximum keysym name length. + * + * @since 1.7.0 + * @sa xkb_keysym_get_name + * @ingroup keysyms + */ +#define XKB_KEYSYM_NAME_MAX_SIZE 27 + /** * Test whether a value is a valid extended keycode. * @sa xkb_keycode_t @@ -442,7 +451,8 @@ struct xkb_rule_names { * @param[in] size Size of the buffer. * * @warning If the buffer passed is too small, the string is truncated - * (though still NUL-terminated); a size of at least 64 bytes is recommended. + * (though still NUL-terminated); a size of at least + * `XKB_KEYSYM_NAME_MAX_SIZE` bytes is recommended. * * @returns The number of bytes in the name, excluding the NUL byte. If * the keysym is invalid, returns -1. @@ -450,7 +460,7 @@ struct xkb_rule_names { * You may check if truncation has occurred by comparing the return value * with the length of buffer, similarly to the snprintf(3) function. * - * @sa xkb_keysym_t + * @sa xkb_keysym_t, XKB_KEYSYM_NAME_MAX_SIZE */ int xkb_keysym_get_name(xkb_keysym_t keysym, char *buffer, size_t size); diff --git a/include/xkbcommon/xkbcommon.h.jinja b/include/xkbcommon/xkbcommon.h.jinja index dbc39b915..dbf93d3b4 100644 --- a/include/xkbcommon/xkbcommon.h.jinja +++ b/include/xkbcommon/xkbcommon.h.jinja @@ -321,6 +321,15 @@ typedef uint32_t xkb_led_mask_t; */ #define XKB_KEYSYM_MAX 0x1fffffff +/** + * Maximum keysym name length. + * + * @since 1.7.0 + * @sa xkb_keysym_get_name + * @ingroup keysyms + */ +#define XKB_KEYSYM_NAME_MAX_SIZE {{ XKB_KEYSYM_NAME_MAX_SIZE }} + /** * Test whether a value is a valid extended keycode. * @sa xkb_keycode_t @@ -442,7 +451,8 @@ struct xkb_rule_names { * @param[in] size Size of the buffer. * * @warning If the buffer passed is too small, the string is truncated - * (though still NUL-terminated); a size of at least 64 bytes is recommended. + * (though still NUL-terminated); a size of at least + * `XKB_KEYSYM_NAME_MAX_SIZE` bytes is recommended. * * @returns The number of bytes in the name, excluding the NUL byte. If * the keysym is invalid, returns -1. @@ -450,7 +460,7 @@ struct xkb_rule_names { * You may check if truncation has occurred by comparing the return value * with the length of buffer, similarly to the snprintf(3) function. * - * @sa xkb_keysym_t + * @sa xkb_keysym_t, XKB_KEYSYM_NAME_MAX_SIZE */ int xkb_keysym_get_name(xkb_keysym_t keysym, char *buffer, size_t size); diff --git a/scripts/update-headers.py b/scripts/update-headers.py index c24930b0e..70067758e 100755 --- a/scripts/update-headers.py +++ b/scripts/update-headers.py @@ -19,17 +19,27 @@ def load_keysyms(path: Path) -> dict[str, int]: keysym_max = 0 min_unicode_keysym = 0x01000100 max_unicode_keysym = 0x0110FFFF + canonical_names: dict[int, str] = {} + max_unicode_name = "U10FFFF" + max_keysym_name = "0x1fffffff" # XKB_KEYSYM_MAX with path.open("rt", encoding="utf-8") as fd: for line in fd: if m := KEYSYM_PATTERN.match(line): value = int(m.group("value"), 16) keysym_min = min(keysym_min, value) keysym_max = max(keysym_max, value) + if value not in canonical_names: + canonical_names[value] = m.group("name") return { "XKB_KEYSYM_MIN_ASSIGNED": min(keysym_min, min_unicode_keysym), "XKB_KEYSYM_MAX_ASSIGNED": max(keysym_max, max_unicode_keysym), "XKB_KEYSYM_MIN_EXPLICIT": keysym_min, "XKB_KEYSYM_MAX_EXPLICIT": keysym_max, + "XKB_KEYSYM_NAME_MAX_SIZE": max( + max(len(name) for name in canonical_names.values()), + len(max_unicode_name), + len(max_keysym_name), + ), } diff --git a/src/text.c b/src/text.c index 290a5ae24..e2b04b324 100644 --- a/src/text.c +++ b/src/text.c @@ -235,8 +235,8 @@ ActionTypeText(enum xkb_action_type type) const char * KeysymText(struct xkb_context *ctx, xkb_keysym_t sym) { - char *buffer = xkb_context_get_buffer(ctx, 64); - xkb_keysym_get_name(sym, buffer, 64); + char *buffer = xkb_context_get_buffer(ctx, XKB_KEYSYM_NAME_MAX_SIZE); + xkb_keysym_get_name(sym, buffer, XKB_KEYSYM_NAME_MAX_SIZE); return buffer; } diff --git a/test/common.c b/test/common.c index cb911e802..ccafa13b6 100644 --- a/test/common.c +++ b/test/common.c @@ -76,7 +76,7 @@ test_key_seq_va(struct xkb_keymap *keymap, va_list ap) const xkb_keysym_t *syms; xkb_keysym_t sym; unsigned int nsyms, i; - char ksbuf[64]; + char ksbuf[XKB_KEYSYM_NAME_MAX_SIZE]; fprintf(stderr, "----\n"); diff --git a/test/compose.c b/test/compose.c index 56e2e2c60..7092989ed 100644 --- a/test/compose.c +++ b/test/compose.c @@ -73,7 +73,7 @@ test_compose_seq_va(struct xkb_compose_table *table, va_list ap) { int ret; struct xkb_compose_state *state; - char buffer[64]; + char buffer[XKB_KEYSYM_NAME_MAX_SIZE]; state = xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS); assert(state); diff --git a/test/keysym.c b/test/keysym.c index eba6aa218..8f5689416 100644 --- a/test/keysym.c +++ b/test/keysym.c @@ -56,7 +56,7 @@ test_casestring(const char *string, xkb_keysym_t expected) static int test_keysym(xkb_keysym_t keysym, const char *expected) { - char s[16]; + char s[XKB_KEYSYM_NAME_MAX_SIZE]; xkb_keysym_get_name(keysym, s, sizeof(s)); @@ -117,11 +117,11 @@ get_keysym_name(xkb_keysym_t keysym, char *buffer, size_t size) static int test_utf32_to_keysym(uint32_t ucs, xkb_keysym_t expected) { - char expected_name[64]; - char actual_name[64]; + char expected_name[XKB_KEYSYM_NAME_MAX_SIZE]; + char actual_name[XKB_KEYSYM_NAME_MAX_SIZE]; xkb_keysym_t actual = xkb_utf32_to_keysym(ucs); - get_keysym_name(expected, expected_name, 64); - get_keysym_name(actual, actual_name, 64); + get_keysym_name(expected, expected_name, XKB_KEYSYM_NAME_MAX_SIZE); + get_keysym_name(actual, actual_name, XKB_KEYSYM_NAME_MAX_SIZE); fprintf(stderr, "Code point 0x%lx: expected keysym: %s, actual: %s\n\n", (unsigned long)ucs, expected_name, actual_name); @@ -170,6 +170,10 @@ main(void) char utf8[7]; int count = xkb_keysym_to_utf8(ks, utf8, sizeof(utf8)); assert(0 <= count && count <= 5); + /* Check maximum name length */ + char name[XKB_KEYSYM_NAME_MAX_SIZE]; + count = xkb_keysym_iterator_name(iter, name, sizeof(name)); + assert(0 < count && (size_t)count <= sizeof(name)); } while (xkb_keysym_iterator_next(iter)); xkb_keysym_iterator_unref(iter); assert(ks_prev == XKB_KEYSYM_MAX_ASSIGNED); diff --git a/tools/compile-compose.c b/tools/compile-compose.c index 2c5bac3c4..3c5da2b48 100644 --- a/tools/compile-compose.c +++ b/tools/compile-compose.c @@ -57,7 +57,7 @@ print_compose_table_entry(struct xkb_compose_table_entry *entry) { size_t nsyms; const xkb_keysym_t *syms = xkb_compose_table_entry_sequence(entry, &nsyms); - char buf[128]; + char buf[XKB_KEYSYM_NAME_MAX_SIZE]; for (size_t i = 0; i < nsyms; i++) { xkb_keysym_get_name(syms[i], buf, sizeof(buf)); printf("<%s>", buf); diff --git a/tools/how-to-type.c b/tools/how-to-type.c index 91ebd000e..589fead41 100644 --- a/tools/how-to-type.c +++ b/tools/how-to-type.c @@ -57,7 +57,7 @@ main(int argc, char *argv[]) uint32_t codepoint; xkb_keysym_t keysym; int ret; - char name[200]; + char name[XKB_KEYSYM_NAME_MAX_SIZE]; struct xkb_keymap *keymap = NULL; xkb_keycode_t min_keycode, max_keycode; xkb_mod_index_t num_mods; diff --git a/tools/tools-common.c b/tools/tools-common.c index b163438fe..09045d309 100644 --- a/tools/tools-common.c +++ b/tools/tools-common.c @@ -49,6 +49,7 @@ #endif #include "tools-common.h" +#include "src/utils.h" static void print_keycode(struct xkb_keymap *keymap, const char* prefix, @@ -155,7 +156,9 @@ tools_print_keycode_state(char *prefix, xkb_keysym_t sym; const xkb_keysym_t *syms; int nsyms; - char s[16]; + // FIXME: this buffer is used for xkb_compose_state_get_utf8, + // which can have a length up to 256. Need to import this constant from compose. + char s[MAX(16, XKB_KEYSYM_NAME_MAX_SIZE)]; xkb_layout_index_t layout; enum xkb_compose_status status;