Xlib: Fixes for util/makekeys

Bernardo Innocenti bernie at codewiz.org
Thu Aug 23 20:44:13 PDT 2007


Daniel Stone wrote:

> This was one of the branches on my now-stolen laptop that I forgot
> about.  Still, might be worth making KTNUM a dynamic variable and
> calculating something optimal?

If only I could go back in time and warn myself not to attempt it I
would have saved a couple of hours of my time.

Next time makekeys needs changing, I'd suggest rewriting it in Perl
or Python right from the start.


>From dd3ea3a9604c806ae4a545b0a3334ce53fd8af32 Mon Sep 17 00:00:00 2001
From: Bernardo Innocenti <bernie at codewiz.org>
Date: Thu, 23 Aug 2007 23:39:50 -0400
Subject: [PATCH] makekeys: Remove hardcoded hashtable size.

In an attempt to avoid infinite loops with this naive collision resolution
strategy, the table size is now a prime number at least twice as large as
the number of entries.

The hashing algorithm could use a good rewrite, as it causes lots of
collisions even for a reasonable table size to entries ratio.
---
 src/util/makekeys.c |   74 +++++++++++++++++++++++++++++++++++----------------
 1 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/src/util/makekeys.c b/src/util/makekeys.c
index 214ea5c..0d66a1a 100644
--- a/src/util/makekeys.c
+++ b/src/util/makekeys.c
@@ -36,32 +36,43 @@ from The Open Group.
 #include <X11/keysymdef.h>
 #include <stdio.h>
 #include <stdlib.h>
-#if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
-char *malloc();
-#endif /* macII */
 
 typedef unsigned long Signature;
 
-#define KTNUM 3000
-
-static struct info {
+struct info {
     char	*name;
     KeySym	val;
-} info[KTNUM];
+};
 
 #define MIN_REHASH 15
 #define MATCHES 10
 
-char tab[KTNUM];
-unsigned short offsets[KTNUM];
-unsigned short indexes[KTNUM];
-KeySym values[KTNUM];
-char buf[1024];
+/* Silly, but simple algorithm for computing the next prime number */
+static size_t next_prime(size_t prime)
+{
+    size_t n, end;
+    do {
+        prime += 1;
+        end = (prime / 2) + 1;
+        for (n = 2; n < end; n += 1) {
+            if ((prime % n) == 0)
+                break;
+        }
+    }
+    while (n < end);
+
+    return prime;
+}
 
 int
 main(int argc, char *argv[])
 {
-    int ksnum = 0;
+    int ksnum = 0, ksalloc = 0;
+    struct info *info = NULL;
+    KeySym val, *values;
+    char *tab;
+    unsigned short *offsets;
+    unsigned short *indexes;
     int max_rehash;
     Signature sig;
     register int i, j, k, z;
@@ -71,12 +82,23 @@ main(int argc, char *argv[])
     int best_max_rehash;
     int best_z = 0;
     int num_found;
-    KeySym val;
     char key[128];
     char alias[128];
+    char buf[1024];
 
 
     while (fgets(buf, sizeof(buf), stdin)) {
+	/* Extend info vector if needed */
+	if (ksnum >= ksalloc / 2)
+	{
+	    ksalloc = next_prime(ksalloc);
+	    info = (struct info *)realloc(info, ksalloc * sizeof(*info));
+	    if (!info) {
+		fprintf(stderr, "makekeys: out of memory!\n");
+		exit(1);
+	    }
+	}
+
 	i = sscanf(buf, "#define XK_%127s 0x%lx", key, &info[ksnum].val);
 	if (i != 2) {
 	    i = sscanf(buf, "#define XK_%127s XK_%127s", key, alias);
@@ -103,19 +125,24 @@ main(int argc, char *argv[])
 		    key);
 	    continue;
 	}
-	name = malloc((unsigned)strlen(key)+1);
-	if (!name) {
+
+	info[ksnum].name = strdup(key);
+	if (!info[ksnum].name) {
 	    fprintf(stderr, "makekeys: out of memory!\n");
 	    exit(1);
 	}
-	(void)strcpy(name, key);
-	info[ksnum].name = name;
 	ksnum++;
-	if (ksnum == KTNUM) {
-	    fprintf(stderr, "makekeys: too many keysyms!\n");
+    }
+
+    /* Allocate auxiliary vectors */
+    values  = (KeySym *) calloc(ksalloc, sizeof(KeySym));
+    tab     = (char *) calloc(ksalloc, sizeof(char));
+    offsets = (unsigned short *) calloc(ksalloc, sizeof(unsigned short));
+    indexes = (unsigned short *) calloc(ksalloc, sizeof(unsigned short));
+	if (!(values && tab && offsets && indexes)) {
+	    fprintf(stderr, "makekeys: out of memory!\n");
 	    exit(1);
 	}
-    }
 
     printf("/* This file is generated from keysymdef.h. */\n");
     printf("/* Do not edit. */\n");
@@ -123,7 +150,7 @@ main(int argc, char *argv[])
 
     best_max_rehash = ksnum;
     num_found = 0;
-    for (z = ksnum; z < KTNUM; z++) {
+    for (z = ksnum; z < ksalloc; z++) {
 	max_rehash = 0;
 	for (name = tab, i = z; --i >= 0;)
 		*name++ = 0;
@@ -157,6 +184,7 @@ next1:	;
     }
 
     z = best_z;
+    //z = ksalloc;
     printf("#ifdef NEEDKTABLE\n");
     printf("const unsigned char _XkeyTable[] = {\n");
     printf("0,\n");
@@ -202,7 +230,7 @@ next1:	;
 
     best_max_rehash = ksnum;
     num_found = 0;
-    for (z = ksnum; z < KTNUM; z++) {
+    for (z = ksnum; z < ksalloc; z++) {
 	max_rehash = 0;
 	for (name = tab, i = z; --i >= 0;)
 		*name++ = 0;
-- 
1.5.2.4



-- 
   // Bernardo Innocenti
 \X/  http://www.codewiz.org/



More information about the xorg mailing list