X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fkeysym.c;h=ef811bd2ccbb01b95d243dfdff89fb498018eebe;hb=cf228acd26b8798e077ae83b5a1351af0b78a287;hp=186a6e4d2756fb80996b44f087fe4db2edba773c;hpb=2d87ab08f33fdbc3a0fffe7c55aef6fdec08ce82;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/keysym.c b/src/keysym.c index 186a6e4..ef811bd 100644 --- a/src/keysym.c +++ b/src/keysym.c @@ -64,14 +64,14 @@ get_name(const struct name_keysym *entry) 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) { @@ -92,56 +92,28 @@ xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size) } /* - * Find the correct keysym if one case-insensitive match is given. - * - * The name_to_keysym table is sorted by istrcmp(). So the binary search may return - * _any_ of all possible case-insensitive duplicates. This function searches the - * returned entry @entry, all previous and all next entries that match by - * case-insensitive comparison and returns the exact match to @name. If @icase - * is true, then this returns the best case-insensitive match instead of a - * correct match. - * The "best" case-insensitive match is the lower-case keysym which we find with - * the help of xkb_keysym_is_lower(). - * The only keysyms that only differ by letter-case are keysyms that are - * available as lower-case and upper-case variant (like KEY_a and KEY_A). So - * returning the first lower-case match is enough in this case. + * 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 const struct name_keysym * -find_sym(const struct name_keysym *entry, const char *name, bool icase) +static bool +parse_keysym_hex(const char *s, uint32_t *out) { - const struct name_keysym *iter, *last; - size_t len = ARRAY_SIZE(name_to_keysym); - - if (!entry) - return NULL; - - if (!icase && strcmp(get_name(entry), name) == 0) - return entry; - if (icase && xkb_keysym_is_lower(entry->keysym)) - return entry; - - for (iter = entry - 1; iter >= name_to_keysym; --iter) { - if (!icase && strcmp(get_name(iter), name) == 0) - return iter; - if (istrcmp(get_name(iter), get_name(entry)) != 0) - break; - if (icase && xkb_keysym_is_lower(iter->keysym)) - return iter; - } - - last = name_to_keysym + len; - for (iter = entry + 1; iter < last; ++iter) { - if (!icase && strcmp(get_name(iter), name) == 0) - return iter; - if (istrcmp(get_name(iter), get_name(entry)) != 0) - break; - if (icase && xkb_keysym_is_lower(iter->keysym)) - return iter; + 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; } - - if (icase) - return entry; - return NULL; + *out = result; + return s[i] == '\0' && i > 0; } XKB_EXPORT xkb_keysym_t @@ -149,48 +121,96 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags) { const struct name_keysym *entry = NULL; char *tmp; - xkb_keysym_t val; + uint32_t val; bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE); if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE) return XKB_KEY_NoSymbol; - size_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[mid])); - if (cmp > 0) { - lo = mid + 1; - } else if (cmp < 0) { - hi = mid - 1; - } else { - entry = &name_to_keysym[mid]; - break; + /* + * We need to !icase case to be fast, for e.g. Compose file parsing. + * So do it in a fast path. + */ + if (!icase) { + 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 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 + * match. + * + * The "best" case-insensitive match is the lower-case keysym which we find + * with the help of xkb_keysym_is_lower(). The only keysyms that only differ + * by letter-case are keysyms that are available as lower-case and + * upper-case variant (like KEY_a and KEY_A). So returning the first + * lower-case match is enough in this case. + */ + else { + int32_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1; + while (hi >= lo) { + 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[mid]; + break; + } + } + if (entry) { + const struct name_keysym *iter, *last; + + if (icase && xkb_keysym_is_lower(entry->keysym)) + return entry->keysym; + + 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 + ARRAY_SIZE(name_to_keysym); + for (iter = entry + 1; iter < last; ++iter) { + if (istrcmp(get_name(iter), get_name(entry)) != 0) + break; + if (xkb_keysym_is_lower(iter->keysym)) + return iter->keysym; + } + + return entry->keysym; } } - entry = find_sym(entry, name, icase); - if (entry) - return entry->keysym; if (*name == 'U' || (icase && *name == 'u')) { - val = strtoul(&name[1], &tmp, 16); - if (tmp && *tmp != '\0') + if (!parse_keysym_hex(&name[1], &val)) return XKB_KEY_NoSymbol; if (val < 0x20 || (val > 0x7e && val < 0xa0)) return XKB_KEY_NoSymbol; if (val < 0x100) - return val; + return (xkb_keysym_t) val; if (val > 0x10ffff) return XKB_KEY_NoSymbol; - return val | 0x01000000; + return (xkb_keysym_t) val | 0x01000000; } else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) { - val = strtoul(&name[2], &tmp, 16); - if (tmp && *tmp != '\0') + if (!parse_keysym_hex(&name[2], &val)) return XKB_KEY_NoSymbol; - - return val; + if (val > XKB_KEYSYM_MAX) + return XKB_KEY_NoSymbol; + return (xkb_keysym_t) val; } /* Stupid inconsistency between the headers and XKeysymDB: the former has @@ -725,9 +745,9 @@ XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper) 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);