listing.c revision bfe6082c
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
28Copyright 1988, 1998  The Open Group
29
30Permission to use, copy, modify, distribute, and sell this software and its
31documentation for any purpose is hereby granted without fee, provided that
32the above copyright notice appear in all copies and that both that
33copyright notice and this permission notice appear in supporting
34documentation.
35
36The above copyright notice and this permission notice shall be included in
37all copies or substantial portions of the Software.
38
39THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
42OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
43AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
44CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45
46Except as contained in this notice, the name of The Open Group shall not be
47used in advertising or otherwise to promote the sale, use or other dealings
48in this Software without prior written authorization from The Open Group.
49
50
51Copyright 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
52
53                        All Rights Reserved
54
55Permission to use, copy, modify, and distribute this software and its
56documentation for any purpose and without fee is hereby granted,
57provided that the above copyright notice appear in all copies and that
58both that copyright notice and this permission notice appear in
59supporting documentation, and that the name of Digital not be
60used in advertising or publicity pertaining to distribution of the
61software without specific, written prior permission.
62
63DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
64ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
65DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
66ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
67WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
68ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
69SOFTWARE.
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# define WIN32_LEAN_AND_MEAN
112# include <X11/Xwindows.h>
113# define FileName(file) file.cFileName
114# undef TEXT
115# undef ALTERNATE
116#else
117# include <dirent.h>
118# define FileName(file) file->d_name
119#endif
120
121#include "xkbpath.h"
122#include "parseutils.h"
123#include "misc.h"
124#include "tokens.h"
125#include <X11/extensions/XKBgeom.h>
126
127#define	lowbit(x)	((x) & (-(x)))
128
129unsigned int listingDebug;
130
131static int szListing = 0;
132static int nListed = 0;
133static int nFilesListed = 0;
134
135typedef struct _Listing
136{
137    char *file;
138    char *map;
139} Listing;
140
141static int szMapOnly;
142static int nMapOnly;
143static char **mapOnly;
144
145static Listing *list = NULL;
146
147/***====================================================================***/
148
149int
150AddMapOnly(char *map)
151{
152    if (nMapOnly >= szMapOnly)
153    {
154        if (szMapOnly < 1)
155            szMapOnly = 5;
156        else
157            szMapOnly *= 2;
158        mapOnly = uTypedRealloc(list, szMapOnly, char *);
159        if (!mapOnly)
160        {
161            WSGO("Couldn't allocate list of maps\n");
162            return 0;
163        }
164    }
165    mapOnly[nMapOnly++] = map;
166    return 1;
167}
168
169int
170AddListing(char *file, char *map)
171{
172    if (nListed >= szListing)
173    {
174        if (szListing < 1)
175            szListing = 10;
176        else
177            szListing *= 2;
178        list = uTypedRealloc(list, szListing, Listing);
179        if (!list)
180        {
181            WSGO("Couldn't allocate list of files and maps\n");
182            ACTION("Exiting\n");
183            exit(1);
184        }
185    }
186
187    list[nListed].file = file;
188    list[nListed].map = map;
189    nListed++;
190    if (file != NULL)
191        nFilesListed++;
192    return 1;
193}
194
195/***====================================================================***/
196
197static void
198ListFile(FILE * outFile, char *fileName, XkbFile * map)
199{
200    register unsigned flags;
201    char *mapName;
202
203    flags = map->flags;
204    if ((flags & XkbLC_Hidden) && (!(verboseLevel & WantHiddenMaps)))
205        return;
206    if ((flags & XkbLC_Partial) && (!(verboseLevel & WantPartialMaps)))
207        return;
208    if (verboseLevel & WantLongListing)
209    {
210        fprintf(outFile, (flags & XkbLC_Hidden) ? "h" : "-");
211        fprintf(outFile, (flags & XkbLC_Default) ? "d" : "-");
212        fprintf(outFile, (flags & XkbLC_Partial) ? "p" : "-");
213        fprintf(outFile, "----- ");
214        if (map->type == XkmSymbolsIndex)
215        {
216            fprintf(outFile, (flags & XkbLC_AlphanumericKeys) ? "a" : "-");
217            fprintf(outFile, (flags & XkbLC_ModifierKeys) ? "m" : "-");
218            fprintf(outFile, (flags & XkbLC_KeypadKeys) ? "k" : "-");
219            fprintf(outFile, (flags & XkbLC_FunctionKeys) ? "f" : "-");
220            fprintf(outFile, (flags & XkbLC_AlternateGroup) ? "g" : "-");
221            fprintf(outFile, "--- ");
222        }
223        else
224            fprintf(outFile, "-------- ");
225    }
226    mapName = map->name;
227    if ((!(verboseLevel & WantFullNames)) && ((flags & XkbLC_Default) != 0))
228        mapName = NULL;
229    if (dirsToStrip > 0)
230    {
231        char *tmp, *last;
232        int i;
233        for (i = 0, tmp = last = fileName; (i < dirsToStrip) && tmp; i++)
234        {
235            last = tmp;
236            tmp = strchr(tmp, '/');
237            if (tmp != NULL)
238                tmp++;
239        }
240        fileName = (tmp ? tmp : last);
241    }
242    if (mapName)
243        fprintf(outFile, "%s(%s)\n", fileName, mapName);
244    else
245        fprintf(outFile, "%s\n", fileName);
246    return;
247}
248
249/***====================================================================***/
250
251static int
252AddDirectory(char *head, char *ptrn, char *rest, char *map)
253{
254#ifdef WIN32
255    HANDLE dirh;
256    WIN32_FIND_DATA file;
257#else
258    DIR *dirp;
259    struct dirent *file;
260#endif
261    int nMatch;
262
263    if (map == NULL)
264    {
265        char *tmp = ptrn;
266        if ((rest == NULL) && (ptrn != NULL) && (strchr(ptrn, '/') == NULL))
267        {
268            tmp = ptrn;
269            map = strchr(ptrn, '(');
270        }
271        else if ((rest == NULL) && (ptrn == NULL) &&
272                 (head != NULL) && (strchr(head, '/') == NULL))
273        {
274            tmp = head;
275            map = strchr(head, '(');
276        }
277        if (map != NULL)
278        {
279            tmp = strchr(tmp, ')');
280            if ((tmp == NULL) || (tmp[1] != '\0'))
281            {
282                ERROR("File and map must have the format file(map)\n");
283                return 0;
284            }
285            *map = '\0';
286            map++;
287            *tmp = '\0';
288        }
289    }
290#ifdef WIN32
291    if ((dirh = FindFirstFile("*.*", &file)) == INVALID_HANDLE_VALUE)
292        return 0;
293#else
294    if ((dirp = opendir((head ? head : "."))) == NULL)
295        return 0;
296#endif
297    nMatch = 0;
298#ifdef WIN32
299    do
300#else
301    while ((file = readdir(dirp)) != NULL)
302#endif
303    {
304        char *tmp, *filename;
305        struct stat sbuf;
306        size_t tmpsize;
307
308        filename = FileName(file);
309        if (!filename || filename[0] == '.')
310            continue;
311        if (ptrn && (!XkbNameMatchesPattern(filename, ptrn)))
312            continue;
313        tmpsize = (head ? strlen(head) : 0) + strlen(filename) + 2;
314        tmp = uAlloc(tmpsize);
315        if (!tmp)
316            continue;
317        snprintf(tmp, tmpsize, "%s%s%s",
318                 (head ? head : ""), (head ? "/" : ""), filename);
319        if (stat(tmp, &sbuf) < 0)
320        {
321            uFree(tmp);
322            continue;
323        }
324        if (((rest != NULL) && (!S_ISDIR(sbuf.st_mode))) ||
325            ((map != NULL) && (S_ISDIR(sbuf.st_mode))))
326        {
327            uFree(tmp);
328            continue;
329        }
330        if (S_ISDIR(sbuf.st_mode))
331        {
332            if ((rest != NULL) || (verboseLevel & ListRecursive))
333                nMatch += AddDirectory(tmp, rest, NULL, map);
334        }
335        else
336            nMatch += AddListing(tmp, map);
337    }
338#ifdef WIN32
339    while (FindNextFile(dirh, &file));
340#endif
341    return nMatch;
342}
343
344/***====================================================================***/
345
346Bool
347AddMatchingFiles(char *head_in)
348{
349    char *str, *head, *ptrn, *rest = NULL;
350
351    if (head_in == NULL)
352        return 0;
353    ptrn = NULL;
354    for (str = head_in; (*str != '\0') && (*str != '?') && (*str != '*');
355         str++)
356    {
357        if ((str != head_in) && (*str == '/'))
358            ptrn = str;
359    }
360    if (*str == '\0')
361    {                           /* no wildcards */
362        head = head_in;
363        ptrn = NULL;
364        rest = NULL;
365    }
366    else if (ptrn == NULL)
367    {                           /* no slash before the first wildcard */
368        head = NULL;
369        ptrn = head_in;
370    }
371    else
372    {                           /* slash followed by wildcard */
373        head = head_in;
374        *ptrn = '\0';
375        ptrn++;
376    }
377    if (ptrn)
378    {
379        rest = strchr(ptrn, '/');
380        if (rest != NULL)
381        {
382            *rest = '\0';
383            rest++;
384        }
385    }
386    if (((rest && ptrn)
387         && ((strchr(ptrn, '(') != NULL) || (strchr(ptrn, ')') != NULL)))
388        || (head
389            && ((strchr(head, '(') != NULL) || (strchr(head, ')') != NULL))))
390    {
391        ERROR("Files/maps to list must have the form file(map)\n");
392        ACTION("Illegal specifier ignored\n");
393        return 0;
394    }
395    return AddDirectory(head, ptrn, rest, NULL);
396}
397
398/***====================================================================***/
399
400static Bool
401MapMatches(char *mapToConsider, char *ptrn)
402{
403    int i;
404
405    if (ptrn != NULL)
406        return XkbNameMatchesPattern(mapToConsider, ptrn);
407    if (nMapOnly < 1)
408        return True;
409    for (i = 0; i < nMapOnly; i++)
410    {
411        if (XkbNameMatchesPattern(mapToConsider, mapOnly[i]))
412            return True;
413    }
414    return False;
415}
416
417int
418GenerateListing(char *out_name)
419{
420    int i;
421    FILE *inputFile, *outFile;
422    XkbFile *rtrn, *mapToUse;
423    unsigned oldWarningLevel;
424    char *mapName;
425
426    if (nFilesListed < 1)
427    {
428        ERROR("Must specify at least one file or pattern to list\n");
429        return 0;
430    }
431    if ((!out_name) || ((out_name[0] == '-') && (out_name[1] == '\0')))
432        outFile = stdout;
433    else if ((outFile = fopen(out_name, "w")) == NULL)
434    {
435        ERROR("Cannot open \"%s\" to write keyboard description\n",
436               out_name);
437        ACTION("Exiting\n");
438        return 0;
439    }
440#ifdef DEBUG
441    if (warningLevel > 9)
442        fprintf(stderr, "should list:\n");
443#endif
444    for (i = 0; i < nListed; i++)
445    {
446#ifdef DEBUG
447        if (warningLevel > 9)
448        {
449            fprintf(stderr, "%s(%s)\n",
450                    (list[i].file ? list[i].file : "*"),
451                    (list[i].map ? list[i].map : "*"));
452        }
453#endif
454        oldWarningLevel = warningLevel;
455        warningLevel = 0;
456        if (list[i].file)
457        {
458            struct stat sbuf;
459
460            if (stat(list[i].file, &sbuf) < 0)
461            {
462                if (oldWarningLevel > 5)
463                    WARN("Couldn't open \"%s\"\n", list[i].file);
464                continue;
465            }
466            if (S_ISDIR(sbuf.st_mode))
467            {
468                if (verboseLevel & ListRecursive)
469                    AddDirectory(list[i].file, NULL, NULL, NULL);
470                continue;
471            }
472
473            inputFile = fopen(list[i].file, "r");
474            if (!inputFile)
475            {
476                if (oldWarningLevel > 5)
477                    WARN("Couldn't open \"%s\"\n", list[i].file);
478                continue;
479            }
480            setScanState(list[i].file, 1);
481            if (XKBParseFile(inputFile, &rtrn) && (rtrn != NULL))
482            {
483                mapName = list[i].map;
484                mapToUse = rtrn;
485                for (; mapToUse; mapToUse = (XkbFile *) mapToUse->common.next)
486                {
487                    if (!MapMatches(mapToUse->name, mapName))
488                        continue;
489                    ListFile(outFile, list[i].file, mapToUse);
490                }
491            }
492            fclose(inputFile);
493        }
494        warningLevel = oldWarningLevel;
495    }
496    return 1;
497}
498