Use CARD32 instead of Atom, move geom headers in
[platform/upstream/libxkbcommon.git] / src / xkbcomp / listing.c
1 /************************************************************
2  Copyright 1996 by Silicon Graphics Computer Systems, Inc.
3
4  Permission to use, copy, modify, and distribute this
5  software and its documentation for any purpose and without
6  fee is hereby granted, provided that the above copyright
7  notice appear in all copies and that both that copyright
8  notice and this permission notice appear in supporting
9  documentation, and that the name of Silicon Graphics not be
10  used in advertising or publicity pertaining to distribution
11  of the software without specific prior written permission.
12  Silicon Graphics makes no representation about the suitability
13  of this software for any purpose. It is provided "as is"
14  without any express or implied warranty.
15
16  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25  ********************************************************/
26 /***********************************************************
27
28 Copyright 1988, 1998  The Open Group
29
30 Permission to use, copy, modify, distribute, and sell this software and its
31 documentation for any purpose is hereby granted without fee, provided that
32 the above copyright notice appear in all copies and that both that
33 copyright notice and this permission notice appear in supporting
34 documentation.
35
36 The above copyright notice and this permission notice shall be included in
37 all copies or substantial portions of the Software.
38
39 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
42 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
43 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
44 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45
46 Except as contained in this notice, the name of The Open Group shall not be
47 used in advertising or otherwise to promote the sale, use or other dealings
48 in this Software without prior written authorization from The Open Group.
49
50
51 Copyright 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
52
53                         All Rights Reserved
54
55 Permission to use, copy, modify, and distribute this software and its
56 documentation for any purpose and without fee is hereby granted,
57 provided that the above copyright notice appear in all copies and that
58 both that copyright notice and this permission notice appear in
59 supporting documentation, and that the name of Digital not be
60 used in advertising or publicity pertaining to distribution of the
61 software without specific, written prior permission.
62
63 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
64 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
65 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
66 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
67 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
68 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
69 SOFTWARE.
70
71 ******************************************************************/
72
73 #include <stdio.h>
74 #include <ctype.h>
75 #include <sys/types.h>
76 #include <sys/stat.h>
77 #include <X11/keysym.h>
78
79 #if defined(sgi)
80 #include <malloc.h>
81 #endif
82
83 #define DEBUG_VAR listingDebug
84 #include "xkbcomp.h"
85 #include <stdlib.h>
86
87 #ifdef _POSIX_SOURCE
88 # include <limits.h>
89 #else
90 # define _POSIX_SOURCE
91 # include <limits.h>
92 # undef _POSIX_SOURCE
93 #endif
94
95 #ifndef PATH_MAX
96 #ifdef WIN32
97 #define PATH_MAX 512
98 #else
99 #include <sys/param.h>
100 #endif
101 #ifndef PATH_MAX
102 #ifdef MAXPATHLEN
103 #define PATH_MAX MAXPATHLEN
104 #else
105 #define PATH_MAX 1024
106 #endif
107 #endif
108 #endif
109
110 #ifdef WIN32
111 # include <windows.h>
112 # define FileName(file) file.cFileName
113 # undef TEXT
114 # undef ALTERNATE
115 #else
116 # include <dirent.h>
117 # define FileName(file) file->d_name
118 #endif
119
120 #include "xkbmisc.h"
121 #include "xkbpath.h"
122 #include "parseutils.h"
123 #include "misc.h"
124 #include "tokens.h"
125
126 #ifndef DFLT_XKB_CONFIG_ROOT
127 #define DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb"
128 #endif
129
130 unsigned int listingDebug;
131
132 typedef struct _CompPair {
133     int num;
134     int sz;
135
136     XkbComponentNamePtr comp;
137 } CompPair;
138
139 /***====================================================================***/
140
141 static Bool
142 AddComponent(CompPair *cp, char *fileName, XkbFile *map, unsigned dirsToStrip)
143 {
144     if (!cp || !fileName || !map)
145         return False;
146
147     if (cp->num >= cp->sz) {
148         int orig_sz = cp->sz;
149         XkbComponentNamePtr orig_comp = cp->comp;
150
151         if (cp->sz < 1)
152             cp->sz = 8;
153         else
154             cp->sz *= 2;
155
156         cp->comp = _XkbRealloc(cp->comp,
157                                cp->sz * sizeof(XkbComponentNameRec));
158         if (!cp->comp) {
159             ERROR("Failed reallocating component name list\n");
160             cp->sz = orig_sz;
161             cp->comp = orig_comp;
162             return False;
163         }
164     }
165
166     /* Strip off leading directories of component */
167     if (dirsToStrip > 0) {
168         char *tmp, *last;
169         int i;
170
171         for (i = 0, tmp = last = fileName; (i <= dirsToStrip) && tmp; i++) {
172             last = tmp;
173             tmp = strchr(tmp, '/');
174             if (tmp != NULL)
175                 tmp++;
176         }
177
178         fileName = (tmp ? tmp : last);
179     }
180
181     if (map->name) {
182         size_t len = strlen(fileName) + strlen(map->name) + 3;
183
184         cp->comp[cp->num].name = _XkbAlloc(len * sizeof(char));
185         if (!cp->comp[cp->num].name) {
186             ERROR("Could not allocate space for component name\n");
187             return False;
188         }
189         sprintf(cp->comp[cp->num].name, "%s(%s)", fileName, map->name);
190     }
191     else {
192         cp->comp[cp->num].name = strdup(fileName);
193         if (!cp->comp[cp->num].name) {
194             ERROR("Could not duplicate component name\n");
195             return False;
196         }
197     }
198
199     cp->comp[cp->num].flags = map->flags;
200     cp->num++;
201
202     return True;
203 }
204
205 static Bool
206 MapMatches(char *mapToConsider, char *ptrn)
207 {
208     return ptrn ? XkbcNameMatchesPattern(mapToConsider, ptrn) : True;
209 }
210
211 static int
212 ParseComponents(CompPair *cp, char *path, char *map, int *max, unsigned strip)
213 {
214     int extra = 0;
215     FILE *inputFile;
216     XkbFile *rtrn, *mapToUse;
217     unsigned oldWarningLevel;
218
219     if (!cp || !path || !max)
220         return 0;
221
222 #ifdef DEBUG
223     if (warningLevel > 9)
224         fprintf(stderr, "should list:\n");
225 #endif
226
227     oldWarningLevel = warningLevel;
228     warningLevel = 0;
229
230 #ifdef DEBUG
231     if (oldWarningLevel > 9)
232         fprintf(stderr, "%s(%s)\n", path ? path : "*", map ? map : "*");
233 #endif
234
235     inputFile = fopen(path, "r");
236     if (!inputFile) {
237         if (oldWarningLevel > 5)
238             WARN("Couldn't open \"%s\"\n", path);
239         return 0;
240     }
241
242     setScanState(path, 1);
243     if (!XKBParseFile(inputFile, &rtrn) || !rtrn) {
244         if (oldWarningLevel > 5)
245             WARN("Couldn't parse file \"%s\"\n", path);
246         fclose(inputFile);
247         return 0;
248     }
249
250     mapToUse = rtrn;
251     for (; mapToUse; mapToUse = (XkbFile *)mapToUse->common.next) {
252         if (!MapMatches(mapToUse->name, map))
253             continue;
254         if (*max <= 0) {
255             extra++;
256             continue;
257         }
258         if (AddComponent(cp, path, mapToUse, strip))
259             (*max)--;
260     }
261
262     warningLevel = oldWarningLevel;
263
264     if (extra)
265         *max = 0;
266
267     return extra;
268 }
269
270 /***====================================================================***/
271
272 static int
273 AddDirectory(CompPair *cp, char *head, char *ptrn, char *rest, char *map,
274              int *max, unsigned strip)
275 {
276 #ifdef WIN32
277     HANDLE dirh;
278     WIN32_FIND_DATA file;
279 #else
280     DIR *dirp;
281     struct dirent *file;
282 #endif
283     int nMatch;
284     size_t baselen;
285     char path[PATH_MAX];
286
287     if (!head) {
288         ERROR("Must specify directory name\n");
289         return 0;
290     }
291
292     strncpy(path, head, sizeof(path));
293     path[PATH_MAX - 1] = '\0';
294     baselen = strlen(path);
295
296     if (!map) {
297         char *tmp = ptrn;
298
299         if (!rest && ptrn && !strchr(ptrn, '/')) {
300             tmp = ptrn;
301             map = strchr(ptrn, '(');
302         }
303         else if (!rest && !ptrn && !strchr(head, '/')) {
304             tmp = head;
305             map = strchr(head, '(');
306         }
307
308         if (map) {
309             tmp = strchr(tmp, ')');
310             if (!tmp || tmp[1] != '\0') {
311                 ERROR("File and map must have the format file(map)\n");
312                 return 0;
313             }
314             *map = '\0';
315             map++;
316             *tmp = '\0';
317         }
318     }
319
320 #ifdef WIN32
321     if ((dirh = FindFirstFile("*.*", &file)) == INVALID_HANDLE_VALUE)
322         return 0;
323 #else
324     if (!(dirp = opendir(head))) {
325         ERROR("Could not open directory \"%s\"\n", head ? head : ".");
326         return 0;
327     }
328 #endif
329     nMatch = 0;
330 #ifdef WIN32
331     do
332 #else
333     while ((file = readdir(dirp)) != NULL)
334 #endif
335     {
336         char *filename;
337         struct stat sbuf;
338
339         filename = FileName(file);
340         if (!filename || filename[0] == '.')
341             continue;
342         if (ptrn && (!XkbcNameMatchesPattern(filename, ptrn)))
343             continue;
344
345         snprintf(&path[baselen], sizeof(path) - baselen, "/%s", filename);
346         if (stat(path, &sbuf) < 0) {
347             ERROR("Could not read file \"%s\"\n", path);
348             continue;
349         }
350
351         if ((rest && !S_ISDIR(sbuf.st_mode)) ||
352             (map && S_ISDIR(sbuf.st_mode)))
353             continue;
354
355         if (S_ISDIR(sbuf.st_mode))
356             nMatch += AddDirectory(cp, path, rest, NULL, map, max, strip);
357         else
358             nMatch += ParseComponents(cp, path, map, max, strip);
359     }
360 #ifdef WIN32
361     while (FindNextFile(dirh, &file));
362 #endif
363     return nMatch;
364 }
365
366 /***====================================================================***/
367
368 static int
369 GenerateComponent(XkbComponentListPtr complist, unsigned type, char *head_in,
370                  char *base, int *max)
371 {
372     char *str, *head, *ptrn = NULL, *rest = NULL;
373     char buf[PATH_MAX];
374     size_t len;
375     CompPair cp;
376     unsigned dirsToStrip;
377     int extra;
378
379     if (!complist || !head_in || !max)
380         return 0;
381
382     ptrn = NULL;
383     for (str = head_in; (*str != '\0') && (*str != '?') && (*str != '*');
384          str++)
385     {
386         if ((str != head_in) && (*str == '/'))
387             ptrn = str;
388     }
389
390     if (*str == '\0') {
391         /* no wildcards */
392         head = head_in;
393     }
394     else if (!ptrn) {
395         /* no slash before the first wildcard */
396         head = NULL;
397         ptrn = head_in;
398     }
399     else {
400         /* slash followed by wildcard */
401         head = head_in;
402         *ptrn = '\0';
403         ptrn++;
404     }
405
406     if (ptrn) {
407         rest = strchr(ptrn, '/');
408         if (rest) {
409             *rest = '\0';
410             rest++;
411         }
412     }
413
414     if ((rest && ptrn && (strchr(ptrn, '(') || strchr(ptrn, ')'))) ||
415         (head && (strchr(head, '(') || strchr(head, ')')))) {
416         ERROR("Files/maps to list must have the form file(map)\n");
417         return 0;
418     }
419
420     /* Prepend XKB directory */
421     snprintf(buf, sizeof(buf), "%s%s%s", base ? base : "", base ? "/" : "",
422              XkbDirectoryForInclude(type));
423     len = strlen(buf);
424
425     /* Figure out directory stripping */
426     str = buf;
427     dirsToStrip = 0;
428     while ((str = strchr(str, '/')) != NULL) {
429         str++;
430         dirsToStrip++;
431     }
432
433     if (head)
434         snprintf(&buf[len], PATH_MAX - len, "/%s", head);
435     head = buf;
436
437     memset(&cp, 0, sizeof(CompPair));
438     extra = AddDirectory(&cp, head, ptrn, rest, NULL, max, dirsToStrip);
439
440     /* Trim excess component slots */
441     if (cp.sz > 0 && cp.sz > cp.num) {
442         if (_XkbRealloc(cp.comp, cp.num * sizeof(XkbComponentNameRec)))
443             cp.sz = cp.num;
444         else
445             WARN("Could not reallocate component name list\n");
446     }
447
448     switch (type) {
449     case XkmKeymapFile:
450         complist->num_keymaps = cp.num;
451         complist->keymaps = cp.comp;
452         break;
453     case XkmKeyNamesIndex:
454         complist->num_keycodes = cp.num;
455         complist->keycodes = cp.comp;
456         break;
457     case XkmTypesIndex:
458         complist->num_types = cp.num;
459         complist->types = cp.comp;
460         break;
461     case XkmCompatMapIndex:
462         complist->num_compat = cp.num;
463         complist->compat = cp.comp;
464         break;
465     case XkmSymbolsIndex:
466         complist->num_symbols = cp.num;
467         complist->symbols = cp.comp;
468         break;
469     case XkmGeometryIndex:
470         complist->num_geometry = cp.num;
471         complist->geometry = cp.comp;
472         break;
473     }
474
475     return extra;
476 }
477
478 /***====================================================================***/
479
480 XkbComponentListPtr
481 XkbcListComponents(XkbComponentNamesPtr ptrns, int *maxMatch)
482 {
483     XkbComponentListPtr complist = NULL;
484     int extra = 0;
485
486     complist = _XkbTypedCalloc(1, XkbComponentListRec);
487     if (!complist) {
488         ERROR("could not allocate space for listing\n");
489         goto out;
490     }
491
492     if (!maxMatch || *maxMatch <= 0)
493         goto out;
494
495     if (ptrns->keymap && *ptrns->keymap != '\0')
496         extra += GenerateComponent(complist, XkmKeymapFile, ptrns->keycodes,
497                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
498
499     if (ptrns->keycodes && *ptrns->keycodes != '\0')
500         extra += GenerateComponent(complist, XkmKeyNamesIndex, ptrns->keycodes,
501                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
502
503     if (ptrns->types && *ptrns->types != '\0')
504         extra += GenerateComponent(complist, XkmTypesIndex, ptrns->types,
505                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
506
507     if (ptrns->compat && *ptrns->compat != '\0')
508         extra += GenerateComponent(complist, XkmCompatMapIndex, ptrns->compat,
509                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
510
511     if (ptrns->symbols && *ptrns->symbols != '\0')
512         extra += GenerateComponent(complist, XkmSymbolsIndex, ptrns->symbols,
513                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
514
515     if (ptrns->geometry && *ptrns->geometry != '\0')
516         extra += GenerateComponent(complist, XkmGeometryIndex, ptrns->geometry,
517                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
518
519 out:
520     if (maxMatch)
521         *maxMatch = extra;
522     return complist;
523 }