Instead of using a home-brew hashtable generator, we should instead use
the gperf program which is known to work.

This removes the "makekeys" programs and instead replaces it by a file
that can generate input files for gperf. Gperf then generates hashtables
for all of these input files and writes them concatenated into
ks_tables.h which then can be used from keysym.c

Unfortunately, gperf does not support integer keys but only strings or
binary data. Therefore, we have to make the keysym->name lookup
little-endian to avoid errors during cross compilation.

Signed-off-by: David Herrmann <[email protected]>
---
 .gitignore           |   1 +
 Makefile.am          |  24 +-
 configure.ac         |   6 +-
 makekeys/Makefile.am |  10 -
 makekeys/makekeys.c  | 616 ++++++++++++++++++++++++++++-----------------------
 src/keysym.c         |  86 ++-----
 6 files changed, 383 insertions(+), 360 deletions(-)
 delete mode 100644 makekeys/Makefile.am

diff --git a/.gitignore b/.gitignore
index 22b4465..5a309a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,3 +81,4 @@ core
 cscope.out
 test-suite.log
 test-driver
+*.gperf
diff --git a/Makefile.am b/Makefile.am
index 26646fb..763e1bc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,5 @@
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = makekeys
-
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = xkbcommon.pc
 
@@ -92,11 +90,25 @@ src/xkbcomp/parser.c: $(top_builddir)/src/$(am__dirstamp) 
$(top_builddir)/src/xk
 src/xkbcomp/parser.h: $(top_builddir)/src/$(am__dirstamp) 
$(top_builddir)/src/xkbcomp/$(am__dirstamp)
 src/xkbcomp/scanner.c: $(top_builddir)/src/$(am__dirstamp) 
$(top_builddir)/src/xkbcomp/$(am__dirstamp)
 
-src/ks_tables.h: $(top_builddir)/makekeys/makekeys$(EXEEXT)
-       $(AM_V_GEN)$(top_builddir)/makekeys/makekeys 
$(top_srcdir)/xkbcommon/xkbcommon-keysyms.h > $@
+# makekeys program and src/ks_tables.h file
+
+noinst_PROGRAMS = makekeys/makekeys
+makekeys_makekeys_SOURCES = makekeys/makekeys.c
+CLEANFILES += \
+       makekeys/name2key.gperf \
+       makekeys/key2name.gperf
+
+src/ks_tables.h: \
+               $(top_builddir)/makekeys/name2key.gperf \
+               $(top_builddir)/makekeys/key2name.gperf
+       $(AM_V_GEN)$(GPERF) --language="ANSI-C" 
$(top_builddir)/makekeys/name2key.gperf > $@
+       $(AM_V_GEN)$(GPERF) --language="ANSI-C" 
$(top_builddir)/makekeys/key2name.gperf >> $@
+
+$(top_builddir)/makekeys/name2key.gperf: 
$(top_builddir)/makekeys/makekeys$(EXEEXT)
+       $(AM_V_GEN)$< --name2key $(top_srcdir)/xkbcommon/xkbcommon-keysyms.h > 
$@
 
-$(top_builddir)/makekeys/makekeys$(EXEEXT): $(top_srcdir)/makekeys/makekeys.c
-       $(MAKE) -C makekeys
+$(top_builddir)/makekeys/key2name.gperf: 
$(top_builddir)/makekeys/makekeys$(EXEEXT)
+       $(AM_V_GEN)$< --key2name $(top_srcdir)/xkbcommon/xkbcommon-keysyms.h > 
$@
 
 # Documentation
 
diff --git a/configure.ac b/configure.ac
index df8a99e..4200118 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,6 +62,11 @@ if test ! -f "src/xkbcomp/parser.c"; then
    fi
 fi
 
+AC_PATH_PROG([GPERF], "gperf", "")
+if test -z "$GPERF"; then
+   AC_MSG_ERROR([gperf not found - enable to create src/ks_tables.h])
+fi
+
 # Checks for library functions.
 AC_CHECK_FUNCS([strcasecmp strncasecmp])
 if test "x$ac_cv_func_strcasecmp" = xno || \
@@ -121,7 +126,6 @@ AC_DEFINE_UNQUOTED([DEFAULT_XKB_LAYOUT], 
["$DEFAULT_XKB_LAYOUT"],
 
 AC_CONFIG_FILES([
     Makefile
-    makekeys/Makefile
     xkbcommon-uninstalled.pc
     xkbcommon.pc
     doc/Doxyfile
diff --git a/makekeys/Makefile.am b/makekeys/Makefile.am
deleted file mode 100644
index 5d9a441..0000000
--- a/makekeys/Makefile.am
+++ /dev/null
@@ -1,10 +0,0 @@
-AM_CFLAGS = $(BASE_CFLAGS) -I$(top_srcdir)
-
-# need to use build-native compiler
-
-CC = $(CC_FOR_BUILD)
-CPPFLAGS = $(CPPFLAGS_FOR_BUILD)
-CFLAGS = $(CFLAGS_FOR_BUILD)
-LDFLAGS = $(LDFLAGS_FOR_BUILD)
-noinst_PROGRAMS = makekeys
-
diff --git a/makekeys/makekeys.c b/makekeys/makekeys.c
index 62d7255..22ece2f 100644
--- a/makekeys/makekeys.c
+++ b/makekeys/makekeys.c
@@ -1,302 +1,362 @@
 /*
+ * Copyright (c) 2012 David Herrmann <[email protected]>
  *
- * Copyright 1990, 1998  The Open Group
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
  *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation.
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Except as contained in this notice, the name of The Open Group shall
- * not be used in advertising or otherwise to promote the sale, use or
- * other dealings in this Software without prior written authorization
- * from The Open Group.
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
  */
 
 /*
- * Constructs hash tables for xkb_keysym_to_string and
- * xkb_string_from_keysym.
+ * Prepare source files for "gperf" which generates perfect hash-tables for
+ * xkb_keysym_get_name() and xkb_keysym_from_name().
  */
 
-#include "xkbcommon/xkbcommon.h"
-
+#include <endian.h>
 #include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "xkbcommon/xkbcommon.h"
+
+/* maximum length of a keysym name including XKB_KEY_* */
+#define MAX_KEYSYM_LEN 127
+
+/* stringification of constants */
+#define xstr(x) #x
+#define str(x) xstr(x)
+
+/*
+ * Parse one line that was read as input from a keysym-defintion. @buf contains
+ * the line and is zero-terminated. @key is a buffer that can hold any keysym 
of
+ * maximum length MAX_KEYSYM_LEN.
+ * Returns true if a keysym has been parsed and stores the symbol in @key and
+ * the value in @val.
+ */
+static bool parse_line(const char *buf, char *key, uint32_t *val)
+{
+       unsigned int i;
+
+       i = sscanf(buf, "#define %" str(MAX_KEYSYM_LEN) "s 0x%" SCNx32,
+                  key, val);
+       if (i == 2 && !strncmp(key, "XKB_KEY_", 8)) {
+               memmove(key, &key[8], strlen(&key[8]) + 1);
+               return true;
+       }
+
+       return false;
+}
+
+/* If we already have a keysym named @old in our list and a new keysym named
+ * @new is added, this function returns true if @new should overwrite @old.
+ * The caller must go sure that strcasecmp(@new, @old) returns "equal" before
+ * calling this.
+ *
+ * In general, we want lower-case letters to overwrite upper-case letters. As 
we
+ * generally not know which keysym-name is upper-case and which one is
+ * lower-case, we use a little hack:
+ *   We simply sum up the ASCII values of both strings and use the greater
+ *   value. This works because we know that the names of keysyms are written in
+ *   upper-case letters if it is an upper case keysym. And upper-case letters
+ *   have lower ASCII values than their respective lower-case letters. */
+static bool should_overwrite(const char *new, const char *old)
+{
+       unsigned int sum1, sum2, i;
+       const unsigned char *newu, *oldu;
+
+       newu = (const void*)new;
+       oldu = (const void*)old;
+       sum1 = 0;
+       sum2 = 0;
+       for (i = 0; new[i] && old[i]; ++i) {
+               sum1 += newu[i];
+               sum2 += oldu[i];
+       }
+
+       if (newu > oldu)
+               return true;
+
+       return false;
+}
+
+/*
+ * Flags for the gperf generator
+ *
+ * IGNORE_CASE causes the generator to create a case-insensitive hash-map and
+ * skips all duplicates. If a keysym is available as lower-case and upper-case
+ * keysym, then the lower-case keysym is taken.
+ *
+ * USE_NULL_STRINGS causes the hashtable to use NULL instead of "" for empty
+ * entries. This reduces memory space but causes a little performance-penalty.
+ *
+ * COMPARE_LENGTHS causes the hashtable to compare legths before doing a 
lookup.
+ * This causes a separate length-map to be added but can reduce performance for
+ * lookup-misses.
+ *
+ * REVERSE generates a reversed table, that is, the value is used as key and 
the
+ * name is returned. We simply convert the 4-byte keysym into a raw binary
+ * string and escape it correctly so gperf can read it.
+ */
+#define FLAG_IGNORE_CASE       0x01
+#define FLAG_USE_NULL_STRINGS  0x02
+#define FLAG_COMPARE_LENGTHS   0x04
+#define FLAG_REVERSE           0x08
+
+struct entry {
+       char name[MAX_KEYSYM_LEN + 1];
+       uint32_t value;
+};
+
+struct entry *entries;
+unsigned int ent_used;
+unsigned int ent_size;
+
+/* Pushes one keysym+value entry into the global list. Depending on @flags this
+ * might first check whether this entry wasn't added before. */
+static bool push_entry(const char *name, uint32_t value, unsigned int flags)
+{
+       struct entry *tmp;
+       unsigned int nsize, i;
+
+       if (strlen(name) > MAX_KEYSYM_LEN) {
+               fprintf(stderr, "keysym name is too long: %s\n", name);
+               return false;
+       }
+
+       if (ent_used == ent_size) {
+               nsize = ent_size * 2;
+               if (!nsize)
+                       nsize = 1024;
+
+               tmp = realloc(entries, sizeof(struct entry) * nsize);
+               if (!tmp) {
+                       fprintf(stderr, "cannot allocate enough memory\n");
+                       return false;
+               }
 
-typedef uint32_t Signature;
+               entries = tmp;
+               ent_size = nsize;
+       }
 
-#define KTNUM 4000
+       if (flags & FLAG_IGNORE_CASE) {
+               for (i = 0; i < ent_used; ++i) {
+                       tmp = &entries[i];
+                       if (!strcasecmp(tmp->name, name)) {
+                               if (should_overwrite(name, tmp->name))
+                                       break;
+                               else
+                                       return true;
+                       }
+               }
+       } else if (flags & FLAG_REVERSE) {
+               /* if two symbols resolve to the same value, we prefer the first
+                * value for backwards compatibility. */
+               for (i = 0; i < ent_used; ++i) {
+                       tmp = &entries[i];
+                       if (tmp->value == value)
+                               return true;
+               }
+       } else {
+               i = ent_used;
+       }
 
-static struct info {
-    char        *name;
-    xkb_keysym_t val;
-} info[KTNUM];
+       strcpy(entries[i].name, name);
+       entries[i].value = value;
 
-#define MIN_REHASH 15
-#define MATCHES    10
+       if (i == ent_used)
+               ++ent_used;
 
-static char tab[KTNUM];
-static unsigned short offsets[KTNUM];
-static unsigned short indexes[KTNUM];
-static xkb_keysym_t values[KTNUM];
-static int ksnum = 0;
+       return true;
+}
+
+/*
+ * This parses all files that are given on the command-line and pushes the
+ * symbols into the global symbol list. Command-line arguments starting with 
"-"
+ * are ignored. If your file starts with "-", then use "./-<file>".
+ */
+static bool parse_all(unsigned int flags, int argc, char **argv)
+{
+       unsigned int i;
+       FILE *f;
+       char buf[1024], key[128];
+       uint32_t val;
+
+       for (i = 1; i < argc; ++i) {
+               if (argv[i][0] == '-')
+                       continue;
+
+               f = fopen(argv[i], "rb");
+               if (!f) {
+                       fprintf(stderr, "cannot open input file %s\n", argv[i]);
+                       return false;
+               }
+
+               while (fgets(buf, sizeof(buf), f)) {
+                       if (!parse_line(buf, key, &val))
+                               continue;
+
+                       if (!push_entry(key, val, flags)) {
+                               fprintf(stderr, "cannot save entry %s\n", key);
+                               return false;
+                       }
+               }
+
+               if (!feof(f)) {
+                       fprintf(stderr, "error while reading input file %s\n",
+                               argv[i]);
+                       return false;
+               }
+
+               fclose(f);
+       }
+
+       return true;
+}
+
+static void write_header(FILE *out, const char *prefix, unsigned int flags)
+{
+       fprintf(out, "%%struct-type\n"
+                    "%%readonly-tables\n"
+                    "%%enum\n"
+                    "%%pic\n");
+
+       if (flags & FLAG_USE_NULL_STRINGS)
+               fprintf(out, "%%null-strings\n");
+       if (flags & (FLAG_COMPARE_LENGTHS | FLAG_REVERSE))
+               fprintf(out, "%%compare-lengths\n");
+       if (flags & FLAG_IGNORE_CASE)
+               fprintf(out, "%%ignore-case\n");
+
+       fprintf(out, "%%define hash-function-name %1$shash\n"
+                    "%%define lookup-function-name %1$slookup\n"
+                    "%%define string-pool-name %1$sstringpool\n"
+                    "%%define word-array-name %1$swordarray\n"
+                    "%%define length-table-name %1$slengthtable\n",
+                    prefix);
+
+       if (flags & FLAG_REVERSE)
+               fprintf(out, "struct %1$sentry {\n"
+                            "        int name;\n"
+                            "        const char *value;\n"
+                            "};\n"
+                            "%%%%\n", prefix);
+       else
+               fprintf(out, "struct %1$sentry {\n"
+                            "        int name;\n"
+                            "        uint32_t value;\n"
+                            "};\n"
+                            "%%%%\n", prefix);
+}
 
-static int
-parse_line(const char *buf, char *key, xkb_keysym_t *val, char *prefix)
+static void write_footer(FILE *out)
 {
-    int i;
-    char alias[128];
-
-    /* See if we can catch a straight XK_foo 0x1234-style definition first;
-     * the trickery around tmp is to account for prefices. */
-    i = sscanf(buf, "#define %127s 0x%" SCNx32, key, val);
-    if (i == 2 && strncmp(key, "XKB_KEY_", 8) == 0) {
-        prefix[0] = '\0';
-        memmove(key, key + 8, strlen(key + 8) + 1);
-        return 1;
-    }
-
-    i = sscanf(buf, "#define %127s %127s", key, alias);
-    if (i == 2)
-        fprintf(stderr, "can't parse keysym definition: %s", buf);
-
-    return 0;
+       fprintf(out, "%%%%\n");
+}
+
+/*
+ * Creates a single gperf configuration file with the given function prefix
+ * @prefix, the options @flags and the files given in @argv.
+ * Output is written to @out.
+ */
+static bool create_file(FILE *out, const char *prefix, unsigned int flags,
+                       int argc, char **argv)
+{
+       unsigned int i;
+       uint32_t val;
+       const char *name;
+       uint8_t *ptr;
+
+       if (!parse_all(flags, argc, argv))
+               return false;
+
+       write_header(out, prefix, flags);
+
+       for (i = 0; i < ent_used; ++i) {
+               name = entries[i].name;
+               val = entries[i].value;
+
+               if (flags & FLAG_REVERSE) {
+                       /* For reversed lookup we make the keys little-endian
+                        * to guarantee that the resulting gperf file can be
+                        * cross-compiled.
+                        * This adds a small performance-penalty to the runtime
+                        * lookup function, but this is neglectable. */
+                       val = htole32(val);
+                       ptr = (uint8_t*)&val;
+                       fprintf(out, "\"\\x%" PRIx8 "\\x%" PRIx8,
+                               ptr[0], ptr[1]);
+                       fprintf(out, "\\x%" PRIx8 "\\x%" PRIx8 "\"",
+                               ptr[2], ptr[3]);
+                       fprintf(out, ", ");
+                       fprintf(out, "\"%s\"", name);
+               } else {
+                       fprintf(out, "\"%s\"", name);
+                       fprintf(out, ", ");
+                       fprintf(out, "%" PRIu32, val);
+               }
+               fprintf(out, "\n");
+       }
+
+       write_footer(out);
+
+       return true;
 }
 
-int
-main(int argc, char *argv[])
+/*
+ * Main Entry
+ * This checks the argument-list for one of --name2key and --key2name. All 
other
+ * arguments are taken as file-list that should be parsed. The generated gperf
+ * input is written to STDOUT.
+ */
+int main(int argc, char **argv)
 {
-    FILE *fptr;
-    int max_rehash;
-    Signature sig;
-    int i, j, k, l, z;
-    char *name;
-    char c;
-    int first;
-    int best_max_rehash;
-    int best_z = 0;
-    int num_found;
-    xkb_keysym_t val;
-    char key[128], prefix[128];
-    char buf[1024];
-
-    for (l = 1; l < argc; l++) {
-        fptr = fopen(argv[l], "r");
-        if (!fptr) {
-            fprintf(stderr, "couldn't open %s\n", argv[l]);
-            continue;
-        }
-
-        while (fgets(buf, sizeof(buf), fptr)) {
-            if (!parse_line(buf, key, &val, prefix))
-                continue;
-
-            if (val == XKB_KEY_VoidSymbol)
-                val = 0;
-            if (val > 0x1fffffff) {
-                fprintf(stderr, "ignoring illegal keysym (%s, %" PRIx32 ")\n",
-                        key,
-                        val);
-                continue;
-            }
-
-            name = malloc(strlen(prefix) + strlen(key) + 1);
-            if (!name) {
-                fprintf(stderr, "makekeys: out of memory!\n");
-                exit(1);
-            }
-            sprintf(name, "%s%s", prefix, key);
-            info[ksnum].name = name;
-            info[ksnum].val = val;
-            ksnum++;
-            if (ksnum == KTNUM) {
-                fprintf(stderr, "makekeys: too many keysyms!\n");
-                exit(1);
-            }
-        }
-
-        fclose(fptr);
-    }
-
-    printf("/* This file is generated from keysymdef.h. */\n");
-    printf("/* Do not edit. */\n");
-    printf("\n");
-
-    best_max_rehash = ksnum;
-    num_found = 0;
-    for (z = ksnum; z < KTNUM; z++) {
-        max_rehash = 0;
-        for (name = tab, i = z; --i >= 0; )
-            *name++ = 0;
-        for (i = 0; i < ksnum; i++) {
-            name = info[i].name;
-            sig = 0;
-            while ((c = *name++))
-                sig = (sig << 1) + c;
-            first = j = sig % z;
-            for (k = 0; tab[j]; k++) {
-                j += first + 1;
-                if (j >= z)
-                    j -= z;
-                if (j == first)
-                    goto next1;
-            }
-            tab[j] = 1;
-            if (k > max_rehash)
-                max_rehash = k;
-        }
-        if (max_rehash < MIN_REHASH) {
-            if (max_rehash < best_max_rehash) {
-                best_max_rehash = max_rehash;
-                best_z = z;
-            }
-            num_found++;
-            if (num_found >= MATCHES)
-                break;
-        }
-next1:;
-    }
-
-    z = best_z;
-    printf("#ifndef KS_TABLES_H\n");
-    printf("#define KS_TABLES_H\n\n");
-    printf("static const unsigned char _XkeyTable[] = {\n");
-    if (z == 0) {
-        fprintf(stderr, "makekeys: failed to find small enough hash!\n"
-                "Try increasing KTNUM in makekeys.c\n");
-        exit(1);
-    }
-    printf("0,\n");
-    k = 1;
-    for (i = 0; i < ksnum; i++) {
-        name = info[i].name;
-        sig = 0;
-        while ((c = *name++))
-            sig = (sig << 1) + c;
-        first = j = sig % z;
-        while (offsets[j]) {
-            j += first + 1;
-            if (j >= z)
-                j -= z;
-        }
-        offsets[j] = k;
-        indexes[i] = k;
-        val = info[i].val;
-        printf("0x%.2" PRIx32 ", 0x%.2" PRIx32 ", 0x%.2" PRIx32 ", "
-               "0x%.2" PRIx32 ", 0x%.2" PRIx32 ", 0x%.2" PRIx32 ", ",
-               (sig >> 8) & 0xff, sig & 0xff, (val >> 24) & 0xff,
-               (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
-        for (name = info[i].name, k += 7; (c = *name++); k++)
-            printf("'%c',", c);
-        printf((i == (ksnum - 1)) ? "0\n" : "0,\n");
-    }
-    printf("};\n");
-    printf("\n");
-    printf("#define KTABLESIZE %d\n", z);
-    printf("#define KMAXHASH %d\n", best_max_rehash + 1);
-    printf("\n");
-    printf("static const unsigned short hashString[KTABLESIZE] = {\n");
-    for (i = 0; i < z; ) {
-        printf("0x%.4x", offsets[i]);
-        i++;
-        if (i == z)
-            break;
-        printf((i & 7) ? ", " : ",\n");
-    }
-    printf("\n");
-    printf("};\n");
-
-    best_max_rehash = ksnum;
-    num_found = 0;
-    for (z = ksnum; z < KTNUM; z++) {
-        max_rehash = 0;
-        for (name = tab, i = z; --i >= 0; )
-            *name++ = 0;
-        for (i = 0; i < ksnum; i++) {
-            val = info[i].val;
-            first = j = val % z;
-            for (k = 0; tab[j]; k++) {
-                if (values[j] == val)
-                    goto skip1;
-                j += first + 1;
-                if (j >= z)
-                    j -= z;
-                if (j == first)
-                    goto next2;
-            }
-            tab[j] = 1;
-            values[j] = val;
-            if (k > max_rehash)
-                max_rehash = k;
-skip1:;
-        }
-        if (max_rehash < MIN_REHASH) {
-            if (max_rehash < best_max_rehash) {
-                best_max_rehash = max_rehash;
-                best_z = z;
-            }
-            num_found++;
-            if (num_found >= MATCHES)
-                break;
-        }
-next2:;
-    }
-
-    z = best_z;
-    if (z == 0) {
-        fprintf(stderr, "makekeys: failed to find small enough hash!\n"
-                "Try increasing KTNUM in makekeys.c\n");
-        exit(1);
-    }
-    for (i = z; --i >= 0; )
-        offsets[i] = 0;
-    for (i = 0; i < ksnum; i++) {
-        val = info[i].val;
-        first = j = val % z;
-        while (offsets[j]) {
-            if (values[j] == val)
-                goto skip2;
-            j += first + 1;
-            if (j >= z)
-                j -= z;
-        }
-        offsets[j] = indexes[i] + 2;
-        values[j] = val;
-skip2:;
-    }
-    printf("\n");
-    printf("#define VTABLESIZE %d\n", z);
-    printf("#define VMAXHASH %d\n", best_max_rehash + 1);
-    printf("\n");
-    printf("static const unsigned short hashKeysym[VTABLESIZE] = {\n");
-    for (i = 0; i < z; ) {
-        printf("0x%.4x", offsets[i]);
-        i++;
-        if (i == z)
-            break;
-        printf((i & 7) ? ", " : ",\n");
-    }
-    printf("\n");
-    printf("};\n");
-    printf("\n#endif /* KS_TABLES_H */\n");
-
-    for (i = 0; i < ksnum; i++)
-        free(info[i].name);
-
-    exit(0);
+       unsigned int i, flags;
+       const char *prefix;
+       bool res;
+
+       prefix = NULL;
+       for (i = 1; i < argc; ++i) {
+               if (!strcmp(argv[i], "--name2key")) {
+                       prefix = "name2key_";
+                       flags  = FLAG_USE_NULL_STRINGS;
+                       flags |= FLAG_COMPARE_LENGTHS;
+               } else if (!strcmp(argv[i], "--key2name")) {
+                       prefix = "key2name_";
+                       flags  = FLAG_USE_NULL_STRINGS;
+                       flags |= FLAG_COMPARE_LENGTHS;
+                       flags |= FLAG_REVERSE;
+               } else if (argv[i][0] == '-') {
+                       fprintf(stderr, "invalid option %s\n", argv[i]);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (!prefix) {
+               fprintf(stderr, "none of --name2key and --key2name 
specified\n");
+               return EXIT_FAILURE;
+       }
+
+       res = create_file(stdout, prefix, flags, argc, argv);
+       if (!res) {
+               fprintf(stderr, "cannot create gperf file\n");
+               return EXIT_FAILURE;
+       }
+
+       return EXIT_SUCCESS;
 }
diff --git a/src/keysym.c b/src/keysym.c
index d659354..3ee0499 100644
--- a/src/keysym.c
+++ b/src/keysym.c
@@ -47,49 +47,35 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <endian.h>
+#include <inttypes.h>
+#include <string.h>
 #include "xkbcommon/xkbcommon.h"
 #include "utils.h"
-#include "ks_tables.h"
 #include "keysym.h"
 
+const struct name2key_entry *name2key_lookup(register const char *str,
+                                            register unsigned int len);
+const struct key2name_entry *key2name_lookup(register const char *str,
+                                            register unsigned int len);
+
+#include "ks_tables.h"
+
 XKB_EXPORT int
 xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
 {
-    int i, n, h, idx;
-    const unsigned char *entry;
-    unsigned char val1, val2, val3, val4;
+    const struct key2name_entry *e;
+    uint32_t val;
 
     if ((ks & ((unsigned long) ~0x1fffffff)) != 0) {
         snprintf(buffer, size, "Invalid");
         return -1;
     }
 
-    /* Try to find it in our hash table. */
-    if (ks <= 0x1fffffff) {
-        val1 = ks >> 24;
-        val2 = (ks >> 16) & 0xff;
-        val3 = (ks >> 8) & 0xff;
-        val4 = ks & 0xff;
-        i = ks % VTABLESIZE;
-        h = i + 1;
-        n = VMAXHASH;
-
-        while ((idx = hashKeysym[i])) {
-            entry = &_XkeyTable[idx];
-
-            if ((entry[0] == val1) && (entry[1] == val2) &&
-                (entry[2] == val3) && (entry[3] == val4)) {
-                return snprintf(buffer, size, "%s", entry + 4);
-            }
-
-            if (!--n)
-                break;
-
-            i += h;
-            if (i >= VTABLESIZE)
-                i -= VTABLESIZE;
-        }
-    }
+    val = htole32(ks);
+    e = key2name_lookup((void*)&val, sizeof(val));
+    if (e)
+        return snprintf(buffer, size, "%s", e->value);
 
     if (ks >= 0x01000100 && ks <= 0x0110ffff)
         /* Unnamed Unicode codepoint. */
@@ -102,42 +88,13 @@ xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t 
size)
 XKB_EXPORT xkb_keysym_t
 xkb_keysym_from_name(const char *s)
 {
-    int i, n, h, c, idx;
-    uint32_t sig = 0;
-    const char *p = s;
+    const struct name2key_entry *e;
     char *tmp;
-    const unsigned char *entry;
-    unsigned char sig1, sig2;
-    xkb_keysym_t val;
-
-    while ((c = *p++))
-        sig = (sig << 1) + c;
-
-    i = sig % KTABLESIZE;
-    h = i + 1;
-    sig1 = (sig >> 8) & 0xff;
-    sig2 = sig & 0xff;
-    n = KMAXHASH;
-
-    while ((idx = hashString[i])) {
-        entry = &_XkeyTable[idx];
+    xkb_keysym_t val, ret;
 
-        if ((entry[0] == sig1) && (entry[1] == sig2) &&
-            streq(s, (const char *) entry + 6)) {
-            val = (entry[2] << 24) | (entry[3] << 16) |
-                  (entry[4] << 8) | entry[5];
-            if (!val)
-                val = XKB_KEY_VoidSymbol;
-            return val;
-        }
-
-        if (!--n)
-            break;
-
-        i += h;
-        if (i >= KTABLESIZE)
-            i -= KTABLESIZE;
-    }
+    e = name2key_lookup(s, strlen(s));
+    if (e)
+        return e->value;
 
     if (*s == 'U') {
         val = strtoul(&s[1], &tmp, 16);
@@ -164,7 +121,6 @@ xkb_keysym_from_name(const char *s)
      * no separating underscore, while some XF86* syms in the latter did.
      * As a last ditch effort, try without. */
     if (strncmp(s, "XF86_", 5) == 0) {
-        xkb_keysym_t ret;
         tmp = strdup(s);
         if (!tmp)
             return XKB_KEY_NoSymbol;
-- 
1.7.12.2

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to