XKB_EXPORT int
xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
{
- if ((ks & ((unsigned long) ~0x1fffffff)) != 0) {
+ if (ks > XKB_KEYSYM_MAX) {
snprintf(buffer, size, "Invalid");
return -1;
}
- size_t lo = 0, hi = ARRAY_SIZE(keysym_to_name) - 1;
+ int32_t lo = 0, hi = ARRAY_SIZE(keysym_to_name) - 1;
while (hi >= lo) {
- size_t mid = (lo + hi) / 2;
+ int32_t mid = (lo + hi) / 2;
if (ks > keysym_to_name[mid].keysym) {
lo = mid + 1;
} else if (ks < keysym_to_name[mid].keysym) {
return snprintf(buffer, size, "0x%08x", ks);
}
+/*
+ * Parse the numeric part of a 0xXXXX and UXXXX keysym.
+ * Not using strtoul -- it's slower and accepts a bunch of stuff
+ * we don't want to allow, like signs, spaces, even locale stuff.
+ */
+static bool
+parse_keysym_hex(const char *s, uint32_t *out)
+{
+ uint32_t result = 0;
+ int i;
+ for (i = 0; i < 8 && s[i] != '\0'; i++) {
+ result <<= 4;
+ if ('0' <= s[i] && s[i] <= '9')
+ result += s[i] - '0';
+ else if ('a' <= s[i] && s[i] <= 'f')
+ result += 10 + s[i] - 'a';
+ else if ('A' <= s[i] && s[i] <= 'F')
+ result += 10 + s[i] - 'A';
+ else
+ return false;
+ }
+ *out = result;
+ return s[i] == '\0' && i > 0;
+}
+
XKB_EXPORT xkb_keysym_t
xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
{
const struct name_keysym *entry = NULL;
char *tmp;
- unsigned long val;
+ uint32_t val;
bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
* So do it in a fast path.
*/
if (!icase) {
- size_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1;
- while (hi >= lo) {
- size_t mid = (lo + hi) / 2;
- int cmp = strcmp(name, get_name(&name_to_keysym[mid]));
- if (cmp > 0)
- lo = mid + 1;
- else if (cmp < 0)
- hi = mid - 1;
- else
- return name_to_keysym[mid].keysym;
+ size_t pos = keysym_name_perfect_hash(name);
+ if (pos < ARRAY_SIZE(name_to_keysym)) {
+ const char *s = get_name(&name_to_keysym[pos]);
+ if (strcmp(name, s) == 0)
+ return name_to_keysym[pos].keysym;
}
}
/*
* Find the correct keysym for case-insensitive match.
*
- * The name_to_keysym_icase table is sorted by istrcmp(). So the binary
+ * The name_to_keysym table is sorted by istrcmp(). So the binary
* search may return _any_ of all possible case-insensitive duplicates. This
* code searches the entry, all previous and all next entries that match by
* case-insensitive comparison and returns the "best" case-insensitive
* lower-case match is enough in this case.
*/
else {
- size_t lo = 0, hi = ARRAY_SIZE(name_to_keysym_icase) - 1;
+ int32_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1;
while (hi >= lo) {
- size_t mid = (lo + hi) / 2;
- int cmp = istrcmp(name, get_name(&name_to_keysym_icase[mid]));
+ int32_t mid = (lo + hi) / 2;
+ int cmp = istrcmp(name, get_name(&name_to_keysym[mid]));
if (cmp > 0) {
lo = mid + 1;
} else if (cmp < 0) {
hi = mid - 1;
} else {
- entry = &name_to_keysym_icase[mid];
+ entry = &name_to_keysym[mid];
break;
}
}
if (icase && xkb_keysym_is_lower(entry->keysym))
return entry->keysym;
- for (iter = entry - 1; iter >= name_to_keysym_icase; --iter) {
+ for (iter = entry - 1; iter >= name_to_keysym; --iter) {
if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
if (xkb_keysym_is_lower(iter->keysym))
return iter->keysym;
}
- last = name_to_keysym_icase + ARRAY_SIZE(name_to_keysym_icase);
+ last = name_to_keysym + ARRAY_SIZE(name_to_keysym);
for (iter = entry + 1; iter < last; ++iter) {
if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
}
if (*name == 'U' || (icase && *name == 'u')) {
- errno = 0;
- val = strtoul(&name[1], &tmp, 16);
- if ((tmp && *tmp != '\0') || errno != 0)
+ if (!parse_keysym_hex(&name[1], &val))
return XKB_KEY_NoSymbol;
if (val < 0x20 || (val > 0x7e && val < 0xa0))
return (xkb_keysym_t) val | 0x01000000;
}
else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) {
- errno = 0;
- val = strtoul(&name[2], &tmp, 16);
- if ((tmp && *tmp != '\0') || errno != 0)
+ if (!parse_keysym_hex(&name[2], &val))
return XKB_KEY_NoSymbol;
- if (val > UINT32_MAX)
+ if (val > XKB_KEYSYM_MAX)
return XKB_KEY_NoSymbol;
-
return (xkb_keysym_t) val;
}
break;
case 6: /* Cyrillic */
/* Assume the KeySym is a legal value (ignore discontinuities) */
- if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE)
+ if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Cyrillic_DZHE)
*lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
- else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze)
+ else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Cyrillic_dzhe)
*upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN)
*lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);