makekeys.c revision 9c019ec5
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#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <stdint.h>
39#include <inttypes.h>
40
41typedef uint32_t Signature;
42
43#define KTNUM 4000
44
45#define XK_VoidSymbol                  0xffffff  /* Void symbol */
46
47typedef unsigned long KeySym;
48
49static struct info {
50    char	*name;
51    KeySym	val;
52} info[KTNUM];
53
54#define MIN_REHASH 15
55#define MATCHES 10
56
57static char tab[KTNUM];
58static unsigned short offsets[KTNUM];
59static unsigned short indexes[KTNUM];
60static KeySym values[KTNUM];
61static int ksnum = 0;
62
63static int
64parse_line(const char *buf, char *key, KeySym *val, char *prefix)
65{
66    int i;
67    char alias[128];
68    char *tmp, *tmpa;
69
70    /* See if we can catch a straight XK_foo 0x1234-style definition first;
71     * the trickery around tmp is to account for prefixes. */
72    i = sscanf(buf, "#define %127s 0x%lx", key, val);
73    if (i == 2 && (tmp = strstr(key, "XK_"))) {
74        memcpy(prefix, key, (size_t)(tmp - key));
75        prefix[tmp - key] = '\0';
76        tmp += 3;
77        memmove(key, tmp, strlen(tmp) + 1);
78        return 1;
79    }
80
81    /* Now try to catch alias (XK_foo XK_bar) definitions, and resolve them
82     * immediately: if the target is in the form XF86XK_foo, we need to
83     * canonicalise this to XF86foo before we do the lookup. */
84    i = sscanf(buf, "#define %127s %127s", key, alias);
85    if (i == 2 && (tmp = strstr(key, "XK_")) && (tmpa = strstr(alias, "XK_"))) {
86        memcpy(prefix, key, (size_t)(tmp - key));
87        prefix[tmp - key] = '\0';
88        tmp += 3;
89        memmove(key, tmp, strlen(tmp) + 1);
90        memmove(tmpa, tmpa + 3, strlen(tmpa + 3) + 1);
91
92        for (i = ksnum - 1; i >= 0; i--) {
93            if (strcmp(info[i].name, alias) == 0) {
94                *val = info[i].val;
95                return 1;
96            }
97        }
98
99        fprintf(stderr, "can't find matching definition %s for keysym %s%s\n",
100                alias, prefix, key);
101    }
102
103    return 0;
104}
105
106int
107main(int argc, char *argv[])
108{
109    int max_rehash;
110    Signature sig;
111    int i, j, k, l, z;
112    FILE *fptr;
113    char *name;
114    char c;
115    int first;
116    int best_max_rehash;
117    int best_z = 0;
118    int num_found;
119    KeySym val;
120    char key[128], prefix[128];
121    static char buf[1024];
122
123    for (l = 1; l < argc; l++) {
124        fptr = fopen(argv[l], "r");
125        if (!fptr) {
126            fprintf(stderr, "couldn't open %s\n", argv[l]);
127            continue;
128        }
129
130        while (fgets(buf, sizeof(buf), fptr)) {
131            if (!parse_line(buf, key, &val, prefix))
132                continue;
133
134            if (val == XK_VoidSymbol)
135                val = 0;
136            if (val > 0x1fffffff) {
137                fprintf(stderr, "ignoring illegal keysym (%s, %lx)\n", key,
138                        val);
139                continue;
140            }
141
142            name = malloc(strlen(prefix) + strlen(key) + 1);
143            if (!name) {
144                fprintf(stderr, "makekeys: out of memory!\n");
145                exit(1);
146            }
147            sprintf(name, "%s%s", prefix, key);
148            info[ksnum].name = name;
149            info[ksnum].val = val;
150            ksnum++;
151            if (ksnum == KTNUM) {
152                fprintf(stderr, "makekeys: too many keysyms!\n");
153                exit(1);
154            }
155        }
156
157        fclose(fptr);
158    }
159
160    printf("/* This file is generated from keysymdef.h. */\n");
161    printf("/* Do not edit. */\n");
162    printf("\n");
163
164    best_max_rehash = ksnum;
165    num_found = 0;
166    for (z = ksnum; z < KTNUM; z++) {
167	max_rehash = 0;
168	for (name = tab, i = z; --i >= 0;)
169		*name++ = 0;
170	for (i = 0; i < ksnum; i++) {
171	    name = info[i].name;
172	    sig = 0;
173	    while ((c = *name++))
174		sig = (sig << 1) + c;
175	    first = j = sig % z;
176	    for (k = 0; tab[j]; k++) {
177		j += first + 1;
178		if (j >= z)
179		    j -= z;
180		if (j == first)
181		    goto next1;
182	    }
183	    tab[j] = 1;
184	    if (k > max_rehash)
185		max_rehash = k;
186	}
187	if (max_rehash < MIN_REHASH) {
188	    if (max_rehash < best_max_rehash) {
189		best_max_rehash = max_rehash;
190		best_z = z;
191	    }
192	    num_found++;
193	    if (num_found >= MATCHES)
194		break;
195	}
196next1:	;
197    }
198
199    z = best_z;
200    if (z == 0) {
201	fprintf(stderr, "makekeys: failed to find small enough hash!\n"
202		"Try increasing KTNUM in makekeys.c\n");
203	exit(1);
204    }
205    printf("#ifdef NEEDKTABLE\n");
206    printf("const unsigned char _XkeyTable[] = {\n");
207    printf("0,\n");
208    k = 1;
209    for (i = 0; i < ksnum; i++) {
210	name = info[i].name;
211	sig = 0;
212	while ((c = *name++))
213	    sig = (sig << 1) + c;
214	first = j = sig % z;
215	while (offsets[j]) {
216	    j += first + 1;
217	    if (j >= z)
218		j -= z;
219	}
220	offsets[j] = k;
221	indexes[i] = k;
222	val = info[i].val;
223	printf("0x%.2"PRIx32", 0x%.2"PRIx32", 0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, ",
224	       (sig >> 8) & 0xff, sig & 0xff,
225	       (val >> 24) & 0xff, (val >> 16) & 0xff,
226	       (val >> 8) & 0xff, val & 0xff);
227	for (name = info[i].name, k += 7; (c = *name++); k++)
228	    printf("'%c',", c);
229	printf((i == (ksnum-1)) ? "0\n" : "0,\n");
230    }
231    printf("};\n");
232    printf("\n");
233    printf("#define KTABLESIZE %d\n", z);
234    printf("#define KMAXHASH %d\n", best_max_rehash + 1);
235    printf("\n");
236    printf("static const unsigned short hashString[KTABLESIZE] = {\n");
237    for (i = 0; i < z;) {
238	printf("0x%.4x", offsets[i]);
239	i++;
240	if (i == z)
241	    break;
242	printf((i & 7) ? ", " : ",\n");
243    }
244    printf("\n");
245    printf("};\n");
246    printf("#endif /* NEEDKTABLE */\n");
247
248    best_max_rehash = ksnum;
249    num_found = 0;
250    for (z = ksnum; z < KTNUM; z++) {
251	max_rehash = 0;
252	for (name = tab, i = z; --i >= 0;)
253		*name++ = 0;
254	for (i = 0; i < ksnum; i++) {
255	    val = info[i].val;
256	    first = j = val % z;
257	    for (k = 0; tab[j]; k++) {
258		if (values[j] == val)
259		    goto skip1;
260		j += first + 1;
261		if (j >= z)
262		    j -= z;
263		if (j == first)
264		    goto next2;
265	    }
266	    tab[j] = 1;
267	    values[j] = val;
268	    if (k > max_rehash)
269		max_rehash = k;
270skip1:	;
271	}
272	if (max_rehash < MIN_REHASH) {
273	    if (max_rehash < best_max_rehash) {
274		best_max_rehash = max_rehash;
275		best_z = z;
276	    }
277	    num_found++;
278	    if (num_found >= MATCHES)
279		break;
280	}
281next2:	;
282    }
283
284    z = best_z;
285    if (z == 0) {
286	fprintf(stderr, "makekeys: failed to find small enough hash!\n"
287		"Try increasing KTNUM in makekeys.c\n");
288	exit(1);
289    }
290    for (i = z; --i >= 0;)
291	offsets[i] = 0;
292    for (i = 0; i < ksnum; i++) {
293	val = info[i].val;
294	first = j = val % z;
295	while (offsets[j]) {
296	    if (values[j] == val)
297		goto skip2;
298	    j += first + 1;
299	    if (j >= z)
300		j -= z;
301	}
302	offsets[j] = indexes[i] + 2;
303	values[j] = val;
304skip2:	;
305    }
306    printf("\n");
307    printf("#ifdef NEEDVTABLE\n");
308    printf("#define VTABLESIZE %d\n", z);
309    printf("#define VMAXHASH %d\n", best_max_rehash + 1);
310    printf("\n");
311    printf("static const unsigned short hashKeysym[VTABLESIZE] = {\n");
312    for (i = 0; i < z;) {
313	printf("0x%.4x", offsets[i]);
314	i++;
315	if (i == z)
316	    break;
317	printf((i & 7) ? ", " : ",\n");
318    }
319    printf("\n");
320    printf("};\n");
321    printf("#endif /* NEEDVTABLE */\n");
322
323    exit(0);
324}
325