makekeys.c revision eb411b4b
1/*
2
3Copyright 1990, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/* Constructs hash tables for XStringToKeysym and XKeysymToString. */
30
31#include <X11/X.h>
32#include <X11/Xos.h>
33#include <X11/Xresource.h>
34#include <X11/keysymdef.h>
35#include <stdio.h>
36#include <stdlib.h>
37
38#include "../Xresinternal.h"
39
40#define KTNUM 4000
41
42static struct info {
43    char	*name;
44    KeySym	val;
45} info[KTNUM];
46
47#define MIN_REHASH 15
48#define MATCHES 10
49
50static char tab[KTNUM];
51static unsigned short offsets[KTNUM];
52static unsigned short indexes[KTNUM];
53static KeySym values[KTNUM];
54static int ksnum = 0;
55
56static int
57parse_line(const char *buf, char *key, KeySym *val, char *prefix)
58{
59    int i;
60    char alias[128];
61    char *tmp, *tmpa;
62
63    /* See if we can catch a straight XK_foo 0x1234-style definition first;
64     * the trickery around tmp is to account for prefices. */
65    i = sscanf(buf, "#define %127s 0x%lx", key, val);
66    if (i == 2 && (tmp = strstr(key, "XK_"))) {
67        memcpy(prefix, key, tmp - key);
68        prefix[tmp - key] = '\0';
69        tmp += 3;
70        memmove(key, tmp, strlen(tmp) + 1);
71        return 1;
72    }
73
74    /* Now try to catch alias (XK_foo XK_bar) definitions, and resolve them
75     * immediately: if the target is in the form XF86XK_foo, we need to
76     * canonicalise this to XF86foo before we do the lookup. */
77    i = sscanf(buf, "#define %127s %127s", key, alias);
78    if (i == 2 && (tmp = strstr(key, "XK_")) && (tmpa = strstr(alias, "XK_"))) {
79        memcpy(prefix, key, tmp - key);
80        prefix[tmp - key] = '\0';
81        tmp += 3;
82        memmove(key, tmp, strlen(tmp) + 1);
83        memmove(tmpa, tmpa + 3, strlen(tmpa + 3) + 1);
84
85        for (i = ksnum - 1; i >= 0; i--) {
86            if (strcmp(info[i].name, alias) == 0) {
87                *val = info[i].val;
88                return 1;
89            }
90        }
91
92        fprintf(stderr, "can't find matching definition %s for keysym %s%s\n",
93                alias, prefix, key);
94    }
95
96    return 0;
97}
98
99int
100main(int argc, char *argv[])
101{
102    int max_rehash;
103    Signature sig;
104    int i, j, k, l, z;
105    FILE *fptr;
106    char *name;
107    char c;
108    int first;
109    int best_max_rehash;
110    int best_z = 0;
111    int num_found;
112    KeySym val;
113    char key[128], prefix[128];
114    static char buf[1024];
115
116    for (l = 1; l < argc; l++) {
117        fptr = fopen(argv[l], "r");
118        if (!fptr) {
119            fprintf(stderr, "couldn't open %s\n", argv[l]);
120            continue;
121        }
122
123        while (fgets(buf, sizeof(buf), fptr)) {
124            if (!parse_line(buf, key, &val, prefix))
125                continue;
126
127            if (val == XK_VoidSymbol)
128                val = 0;
129            if (val > 0x1fffffff) {
130                fprintf(stderr, "ignoring illegal keysym (%s, %lx)\n", key,
131                        val);
132                continue;
133            }
134
135            name = malloc(strlen(prefix) + strlen(key) + 1);
136            if (!name) {
137                fprintf(stderr, "makekeys: out of memory!\n");
138                exit(1);
139            }
140            sprintf(name, "%s%s", prefix, key);
141            info[ksnum].name = name;
142            info[ksnum].val = val;
143            ksnum++;
144            if (ksnum == KTNUM) {
145                fprintf(stderr, "makekeys: too many keysyms!\n");
146                exit(1);
147            }
148        }
149
150        fclose(fptr);
151    }
152
153    printf("/* This file is generated from keysymdef.h. */\n");
154    printf("/* Do not edit. */\n");
155    printf("\n");
156
157    best_max_rehash = ksnum;
158    num_found = 0;
159    for (z = ksnum; z < KTNUM; z++) {
160	max_rehash = 0;
161	for (name = tab, i = z; --i >= 0;)
162		*name++ = 0;
163	for (i = 0; i < ksnum; i++) {
164	    name = info[i].name;
165	    sig = 0;
166	    while ((c = *name++))
167		sig = (sig << 1) + c;
168	    first = j = sig % z;
169	    for (k = 0; tab[j]; k++) {
170		j += first + 1;
171		if (j >= z)
172		    j -= z;
173		if (j == first)
174		    goto next1;
175	    }
176	    tab[j] = 1;
177	    if (k > max_rehash)
178		max_rehash = k;
179	}
180	if (max_rehash < MIN_REHASH) {
181	    if (max_rehash < best_max_rehash) {
182		best_max_rehash = max_rehash;
183		best_z = z;
184	    }
185	    num_found++;
186	    if (num_found >= MATCHES)
187		break;
188	}
189next1:	;
190    }
191
192    z = best_z;
193    if (z == 0) {
194	fprintf(stderr, "makekeys: failed to find small enough hash!\n"
195		"Try increasing KTNUM in makekeys.c\n");
196	exit(1);
197    }
198    printf("#ifdef NEEDKTABLE\n");
199    printf("const unsigned char _XkeyTable[] = {\n");
200    printf("0,\n");
201    k = 1;
202    for (i = 0; i < ksnum; i++) {
203	name = info[i].name;
204	sig = 0;
205	while ((c = *name++))
206	    sig = (sig << 1) + c;
207	first = j = sig % z;
208	while (offsets[j]) {
209	    j += first + 1;
210	    if (j >= z)
211		j -= z;
212	}
213	offsets[j] = k;
214	indexes[i] = k;
215	val = info[i].val;
216	printf("0x%.2"PRIx32", 0x%.2"PRIx32", 0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, ",
217	       (sig >> 8) & 0xff, sig & 0xff,
218	       (val >> 24) & 0xff, (val >> 16) & 0xff,
219	       (val >> 8) & 0xff, val & 0xff);
220	for (name = info[i].name, k += 7; (c = *name++); k++)
221	    printf("'%c',", c);
222	printf((i == (ksnum-1)) ? "0\n" : "0,\n");
223    }
224    printf("};\n");
225    printf("\n");
226    printf("#define KTABLESIZE %d\n", z);
227    printf("#define KMAXHASH %d\n", best_max_rehash + 1);
228    printf("\n");
229    printf("static const unsigned short hashString[KTABLESIZE] = {\n");
230    for (i = 0; i < z;) {
231	printf("0x%.4x", offsets[i]);
232	i++;
233	if (i == z)
234	    break;
235	printf((i & 7) ? ", " : ",\n");
236    }
237    printf("\n");
238    printf("};\n");
239    printf("#endif /* NEEDKTABLE */\n");
240
241    best_max_rehash = ksnum;
242    num_found = 0;
243    for (z = ksnum; z < KTNUM; z++) {
244	max_rehash = 0;
245	for (name = tab, i = z; --i >= 0;)
246		*name++ = 0;
247	for (i = 0; i < ksnum; i++) {
248	    val = info[i].val;
249	    first = j = val % z;
250	    for (k = 0; tab[j]; k++) {
251		if (values[j] == val)
252		    goto skip1;
253		j += first + 1;
254		if (j >= z)
255		    j -= z;
256		if (j == first)
257		    goto next2;
258	    }
259	    tab[j] = 1;
260	    values[j] = val;
261	    if (k > max_rehash)
262		max_rehash = k;
263skip1:	;
264	}
265	if (max_rehash < MIN_REHASH) {
266	    if (max_rehash < best_max_rehash) {
267		best_max_rehash = max_rehash;
268		best_z = z;
269	    }
270	    num_found++;
271	    if (num_found >= MATCHES)
272		break;
273	}
274next2:	;
275    }
276
277    z = best_z;
278    if (z == 0) {
279	fprintf(stderr, "makekeys: failed to find small enough hash!\n"
280		"Try increasing KTNUM in makekeys.c\n");
281	exit(1);
282    }
283    for (i = z; --i >= 0;)
284	offsets[i] = 0;
285    for (i = 0; i < ksnum; i++) {
286	val = info[i].val;
287	first = j = val % z;
288	while (offsets[j]) {
289	    if (values[j] == val)
290		goto skip2;
291	    j += first + 1;
292	    if (j >= z)
293		j -= z;
294	}
295	offsets[j] = indexes[i] + 2;
296	values[j] = val;
297skip2:	;
298    }
299    printf("\n");
300    printf("#ifdef NEEDVTABLE\n");
301    printf("#define VTABLESIZE %d\n", z);
302    printf("#define VMAXHASH %d\n", best_max_rehash + 1);
303    printf("\n");
304    printf("static const unsigned short hashKeysym[VTABLESIZE] = {\n");
305    for (i = 0; i < z;) {
306	printf("0x%.4x", offsets[i]);
307	i++;
308	if (i == z)
309	    break;
310	printf((i & 7) ? ", " : ",\n");
311    }
312    printf("\n");
313    printf("};\n");
314    printf("#endif /* NEEDVTABLE */\n");
315
316    exit(0);
317}
318