listing: Drop unused deviceSpec argument
[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 #include <X11/extensions/XKBgeomcommon.h>
126
127 #ifndef DFLT_XKB_CONFIG_ROOT
128 #define DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb"
129 #endif
130
131 unsigned int listingDebug;
132
133 typedef struct _CompPair {
134     int num;
135     int sz;
136
137     XkbComponentNamePtr comp;
138 } CompPair;
139
140 /***====================================================================***/
141
142 static Bool
143 AddComponent(CompPair *cp, char *fileName, XkbFile *map, unsigned dirsToStrip)
144 {
145     if (!cp || !fileName || !map)
146         return False;
147
148     if (cp->num >= cp->sz) {
149         int orig_sz = cp->sz;
150         XkbComponentNamePtr orig_comp = cp->comp;
151
152         if (cp->sz < 1)
153             cp->sz = 8;
154         else
155             cp->sz *= 2;
156
157         cp->comp = _XkbRealloc(cp->comp,
158                                cp->sz * sizeof(XkbComponentNameRec));
159         if (!cp->comp) {
160             ERROR("Failed reallocating component name list\n");
161             cp->sz = orig_sz;
162             cp->comp = orig_comp;
163             return False;
164         }
165     }
166
167     /* Strip off leading directories of component */
168     if (dirsToStrip > 0) {
169         char *tmp, *last;
170         int i;
171
172         for (i = 0, tmp = last = fileName; (i <= dirsToStrip) && tmp; i++) {
173             last = tmp;
174             tmp = strchr(tmp, '/');
175             if (tmp != NULL)
176                 tmp++;
177         }
178
179         fileName = (tmp ? tmp : last);
180     }
181
182     if (map->name) {
183         size_t len = strlen(fileName) + strlen(map->name) + 3;
184
185         cp->comp[cp->num].name = _XkbAlloc(len * sizeof(char));
186         if (!cp->comp[cp->num].name) {
187             ERROR("Could not allocate space for component name\n");
188             return False;
189         }
190         sprintf(cp->comp[cp->num].name, "%s(%s)", fileName, map->name);
191     }
192     else {
193         cp->comp[cp->num].name = strdup(fileName);
194         if (!cp->comp[cp->num].name) {
195             ERROR("Could not duplicate component name\n");
196             return False;
197         }
198     }
199
200     cp->comp[cp->num].flags = map->flags;
201     cp->num++;
202
203     return True;
204 }
205
206 static Bool
207 MapMatches(char *mapToConsider, char *ptrn)
208 {
209     return ptrn ? XkbcNameMatchesPattern(mapToConsider, ptrn) : True;
210 }
211
212 static int
213 ParseComponents(CompPair *cp, char *path, char *map, int *max, unsigned strip)
214 {
215     int extra = 0;
216     FILE *inputFile;
217     XkbFile *rtrn, *mapToUse;
218     unsigned oldWarningLevel;
219
220     if (!cp || !path || !max)
221         return 0;
222
223 #ifdef DEBUG
224     if (warningLevel > 9)
225         fprintf(stderr, "should list:\n");
226 #endif
227
228     oldWarningLevel = warningLevel;
229     warningLevel = 0;
230
231 #ifdef DEBUG
232     if (oldWarningLevel > 9)
233         fprintf(stderr, "%s(%s)\n", path ? path : "*", map ? map : "*");
234 #endif
235
236     inputFile = fopen(path, "r");
237     if (!inputFile) {
238         if (oldWarningLevel > 5)
239             WARN("Couldn't open \"%s\"\n", path);
240         return 0;
241     }
242
243     setScanState(path, 1);
244     if (!XKBParseFile(inputFile, &rtrn) || !rtrn) {
245         if (oldWarningLevel > 5)
246             WARN("Couldn't parse file \"%s\"\n", path);
247         fclose(inputFile);
248         return 0;
249     }
250
251     mapToUse = rtrn;
252     for (; mapToUse; mapToUse = (XkbFile *)mapToUse->common.next) {
253         if (!MapMatches(mapToUse->name, map))
254             continue;
255         if (*max <= 0) {
256             extra++;
257             continue;
258         }
259         if (AddComponent(cp, path, mapToUse, strip))
260             (*max)--;
261     }
262
263     warningLevel = oldWarningLevel;
264
265     if (extra)
266         *max = 0;
267
268     return extra;
269 }
270
271 /***====================================================================***/
272
273 static int
274 AddDirectory(CompPair *cp, char *head, char *ptrn, char *rest, char *map,
275              int *max, unsigned strip)
276 {
277 #ifdef WIN32
278     HANDLE dirh;
279     WIN32_FIND_DATA file;
280 #else
281     DIR *dirp;
282     struct dirent *file;
283 #endif
284     int nMatch;
285     size_t baselen;
286     char path[PATH_MAX];
287
288     if (!head) {
289         ERROR("Must specify directory name\n");
290         return 0;
291     }
292
293     strncpy(path, head, sizeof(path));
294     path[PATH_MAX - 1] = '\0';
295     baselen = strlen(path);
296
297     if (!map) {
298         char *tmp = ptrn;
299
300         if (!rest && ptrn && !strchr(ptrn, '/')) {
301             tmp = ptrn;
302             map = strchr(ptrn, '(');
303         }
304         else if (!rest && !ptrn && !strchr(head, '/')) {
305             tmp = head;
306             map = strchr(head, '(');
307         }
308
309         if (map) {
310             tmp = strchr(tmp, ')');
311             if (!tmp || tmp[1] != '\0') {
312                 ERROR("File and map must have the format file(map)\n");
313                 return 0;
314             }
315             *map = '\0';
316             map++;
317             *tmp = '\0';
318         }
319     }
320
321 #ifdef WIN32
322     if ((dirh = FindFirstFile("*.*", &file)) == INVALID_HANDLE_VALUE)
323         return 0;
324 #else
325     if (!(dirp = opendir(head))) {
326         ERROR("Could not open directory \"%s\"\n", head ? head : ".");
327         return 0;
328     }
329 #endif
330     nMatch = 0;
331 #ifdef WIN32
332     do
333 #else
334     while ((file = readdir(dirp)) != NULL)
335 #endif
336     {
337         char *filename;
338         struct stat sbuf;
339
340         filename = FileName(file);
341         if (!filename || filename[0] == '.')
342             continue;
343         if (ptrn && (!XkbcNameMatchesPattern(filename, ptrn)))
344             continue;
345
346         snprintf(&path[baselen], sizeof(path) - baselen, "/%s", filename);
347         if (stat(path, &sbuf) < 0) {
348             ERROR("Could not read file \"%s\"\n", path);
349             continue;
350         }
351
352         if ((rest && !S_ISDIR(sbuf.st_mode)) ||
353             (map && S_ISDIR(sbuf.st_mode)))
354             continue;
355
356         if (S_ISDIR(sbuf.st_mode))
357             nMatch += AddDirectory(cp, path, rest, NULL, map, max, strip);
358         else
359             nMatch += ParseComponents(cp, path, map, max, strip);
360     }
361 #ifdef WIN32
362     while (FindNextFile(dirh, &file));
363 #endif
364     return nMatch;
365 }
366
367 /***====================================================================***/
368
369 static int
370 GenerateComponent(XkbComponentListPtr complist, unsigned type, char *head_in,
371                  char *base, int *max)
372 {
373     char *str, *head, *ptrn = NULL, *rest = NULL;
374     char buf[PATH_MAX];
375     size_t len;
376     CompPair cp;
377     unsigned dirsToStrip;
378     int extra;
379
380     if (!complist || !head_in || !max)
381         return 0;
382
383     ptrn = NULL;
384     for (str = head_in; (*str != '\0') && (*str != '?') && (*str != '*');
385          str++)
386     {
387         if ((str != head_in) && (*str == '/'))
388             ptrn = str;
389     }
390
391     if (*str == '\0') {
392         /* no wildcards */
393         head = head_in;
394     }
395     else if (!ptrn) {
396         /* no slash before the first wildcard */
397         head = NULL;
398         ptrn = head_in;
399     }
400     else {
401         /* slash followed by wildcard */
402         head = head_in;
403         *ptrn = '\0';
404         ptrn++;
405     }
406
407     if (ptrn) {
408         rest = strchr(ptrn, '/');
409         if (rest) {
410             *rest = '\0';
411             rest++;
412         }
413     }
414
415     if ((rest && ptrn && (strchr(ptrn, '(') || strchr(ptrn, ')'))) ||
416         (head && (strchr(head, '(') || strchr(head, ')')))) {
417         ERROR("Files/maps to list must have the form file(map)\n");
418         return 0;
419     }
420
421     /* Prepend XKB directory */
422     snprintf(buf, sizeof(buf), "%s%s%s", base ? base : "", base ? "/" : "",
423              XkbDirectoryForInclude(type));
424     len = strlen(buf);
425
426     /* Figure out directory stripping */
427     str = buf;
428     dirsToStrip = 0;
429     while ((str = strchr(str, '/')) != NULL) {
430         str++;
431         dirsToStrip++;
432     }
433
434     if (head)
435         snprintf(&buf[len], PATH_MAX - len, "/%s", head);
436     head = buf;
437
438     memset(&cp, 0, sizeof(CompPair));
439     extra = AddDirectory(&cp, head, ptrn, rest, NULL, max, dirsToStrip);
440
441     /* Trim excess component slots */
442     if (cp.sz > 0 && cp.sz > cp.num) {
443         if (_XkbRealloc(cp.comp, cp.num * sizeof(XkbComponentNameRec)))
444             cp.sz = cp.num;
445         else
446             WARN("Could not reallocate component name list\n");
447     }
448
449     switch (type) {
450     case XkmKeymapFile:
451         complist->num_keymaps = cp.num;
452         complist->keymaps = cp.comp;
453         break;
454     case XkmKeyNamesIndex:
455         complist->num_keycodes = cp.num;
456         complist->keycodes = cp.comp;
457         break;
458     case XkmTypesIndex:
459         complist->num_types = cp.num;
460         complist->types = cp.comp;
461         break;
462     case XkmCompatMapIndex:
463         complist->num_compat = cp.num;
464         complist->compat = cp.comp;
465         break;
466     case XkmSymbolsIndex:
467         complist->num_symbols = cp.num;
468         complist->symbols = cp.comp;
469         break;
470     case XkmGeometryIndex:
471         complist->num_geometry = cp.num;
472         complist->geometry = cp.comp;
473         break;
474     }
475
476     return extra;
477 }
478
479 /***====================================================================***/
480
481 XkbComponentListPtr
482 XkbcListComponents(XkbComponentNamesPtr ptrns, int *maxMatch)
483 {
484     XkbComponentListPtr complist = NULL;
485     int extra = 0;
486
487     complist = _XkbTypedCalloc(1, XkbComponentListRec);
488     if (!complist) {
489         ERROR("could not allocate space for listing\n");
490         goto out;
491     }
492
493     if (!maxMatch || *maxMatch <= 0)
494         goto out;
495
496     if (ptrns->keymap && *ptrns->keymap != '\0')
497         extra += GenerateComponent(complist, XkmKeymapFile, ptrns->keycodes,
498                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
499
500     if (ptrns->keycodes && *ptrns->keycodes != '\0')
501         extra += GenerateComponent(complist, XkmKeyNamesIndex, ptrns->keycodes,
502                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
503
504     if (ptrns->types && *ptrns->types != '\0')
505         extra += GenerateComponent(complist, XkmTypesIndex, ptrns->types,
506                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
507
508     if (ptrns->compat && *ptrns->compat != '\0')
509         extra += GenerateComponent(complist, XkmCompatMapIndex, ptrns->compat,
510                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
511
512     if (ptrns->symbols && *ptrns->symbols != '\0')
513         extra += GenerateComponent(complist, XkmSymbolsIndex, ptrns->symbols,
514                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
515
516     if (ptrns->geometry && *ptrns->geometry != '\0')
517         extra += GenerateComponent(complist, XkmGeometryIndex, ptrns->geometry,
518                                    DFLT_XKB_CONFIG_ROOT, maxMatch);
519
520 out:
521     if (maxMatch)
522         *maxMatch = extra;
523     return complist;
524 }