listing.c revision 34345a63
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# 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 "xkbpath.h"
121#include "parseutils.h"
122#include "misc.h"
123#include "tokens.h"
124#include <X11/extensions/XKBgeom.h>
125
126#define	lowbit(x)	((x) & (-(x)))
127
128unsigned int listingDebug;
129
130static int szListing = 0;
131static int nListed = 0;
132static int nFilesListed = 0;
133
134typedef struct _Listing
135{
136    char *file;
137    char *map;
138} Listing;
139
140static int szMapOnly;
141static int nMapOnly;
142static char **mapOnly;
143
144static Listing *list = NULL;
145
146/***====================================================================***/
147
148int
149AddMapOnly(char *map)
150{
151    if (nMapOnly >= szMapOnly)
152    {
153        if (szMapOnly < 1)
154            szMapOnly = 5;
155        else
156            szMapOnly *= 2;
157        mapOnly = uTypedRealloc(list, szMapOnly, char *);
158        if (!mapOnly)
159        {
160            WSGO("Couldn't allocate list of maps\n");
161            return 0;
162        }
163    }
164    mapOnly[nMapOnly++] = map;
165    return 1;
166}
167
168int
169AddListing(char *file, char *map)
170{
171    if (nListed >= szListing)
172    {
173        if (szListing < 1)
174            szListing = 10;
175        else
176            szListing *= 2;
177        list = uTypedRealloc(list, szListing, Listing);
178        if (!list)
179        {
180            WSGO("Couldn't allocate list of files and maps\n");
181            ACTION("Exiting\n");
182            exit(1);
183        }
184    }
185
186    list[nListed].file = file;
187    list[nListed].map = map;
188    nListed++;
189    if (file != NULL)
190        nFilesListed++;
191    return 1;
192}
193
194/***====================================================================***/
195
196static void
197ListFile(FILE * outFile, char *fileName, XkbFile * map)
198{
199    register unsigned flags;
200    char *mapName;
201
202    flags = map->flags;
203    if ((flags & XkbLC_Hidden) && (!(verboseLevel & WantHiddenMaps)))
204        return;
205    if ((flags & XkbLC_Partial) && (!(verboseLevel & WantPartialMaps)))
206        return;
207    if (verboseLevel & WantLongListing)
208    {
209        fprintf(outFile, (flags & XkbLC_Hidden) ? "h" : "-");
210        fprintf(outFile, (flags & XkbLC_Default) ? "d" : "-");
211        fprintf(outFile, (flags & XkbLC_Partial) ? "p" : "-");
212        fprintf(outFile, "----- ");
213        if (map->type == XkmSymbolsIndex)
214        {
215            fprintf(outFile, (flags & XkbLC_AlphanumericKeys) ? "a" : "-");
216            fprintf(outFile, (flags & XkbLC_ModifierKeys) ? "m" : "-");
217            fprintf(outFile, (flags & XkbLC_KeypadKeys) ? "k" : "-");
218            fprintf(outFile, (flags & XkbLC_FunctionKeys) ? "f" : "-");
219            fprintf(outFile, (flags & XkbLC_AlternateGroup) ? "g" : "-");
220            fprintf(outFile, "--- ");
221        }
222        else
223            fprintf(outFile, "-------- ");
224    }
225    mapName = map->name;
226    if ((!(verboseLevel & WantFullNames)) && ((flags & XkbLC_Default) != 0))
227        mapName = NULL;
228    if (dirsToStrip > 0)
229    {
230        char *tmp, *last;
231        int i;
232        for (i = 0, tmp = last = fileName; (i < dirsToStrip) && tmp; i++)
233        {
234            last = tmp;
235            tmp = strchr(tmp, '/');
236            if (tmp != NULL)
237                tmp++;
238        }
239        fileName = (tmp ? tmp : last);
240    }
241    if (mapName)
242        fprintf(outFile, "%s(%s)\n", fileName, mapName);
243    else
244        fprintf(outFile, "%s\n", fileName);
245    return;
246}
247
248/***====================================================================***/
249
250static int
251AddDirectory(char *head, char *ptrn, char *rest, char *map)
252{
253#ifdef WIN32
254    HANDLE dirh;
255    WIN32_FIND_DATA file;
256#else
257    DIR *dirp;
258    struct dirent *file;
259#endif
260    int nMatch;
261
262    if (map == NULL)
263    {
264        char *tmp = ptrn;
265        if ((rest == NULL) && (ptrn != NULL) && (strchr(ptrn, '/') == NULL))
266        {
267            tmp = ptrn;
268            map = strchr(ptrn, '(');
269        }
270        else if ((rest == NULL) && (ptrn == NULL) &&
271                 (head != NULL) && (strchr(head, '/') == NULL))
272        {
273            tmp = head;
274            map = strchr(head, '(');
275        }
276        if (map != NULL)
277        {
278            tmp = strchr(tmp, ')');
279            if ((tmp == NULL) || (tmp[1] != '\0'))
280            {
281                ERROR1("File and map must have the format file(map)\n");
282                return 0;
283            }
284            *map = '\0';
285            map++;
286            *tmp = '\0';
287        }
288    }
289#ifdef WIN32
290    if ((dirh = FindFirstFile("*.*", &file)) == INVALID_HANDLE_VALUE)
291        return 0;
292#else
293    if ((dirp = opendir((head ? head : "."))) == NULL)
294        return 0;
295    nMatch = 0;
296#endif
297#ifdef WIN32
298    do
299#else
300    while ((file = readdir(dirp)) != NULL)
301#endif
302    {
303        char *tmp, *filename;
304        struct stat sbuf;
305
306        filename = FileName(file);
307        if (!filename || filename[0] == '.')
308            continue;
309        if (ptrn && (!XkbNameMatchesPattern(filename, ptrn)))
310            continue;
311        tmp =
312            (char *) uAlloc((head ? strlen(head) : 0) + strlen(filename) + 2);
313        if (!tmp)
314            continue;
315        sprintf(tmp, "%s%s%s", (head ? head : ""), (head ? "/" : ""),
316                filename);
317        if (stat(tmp, &sbuf) < 0)
318        {
319            uFree(tmp);
320            continue;
321        }
322        if (((rest != NULL) && (!S_ISDIR(sbuf.st_mode))) ||
323            ((map != NULL) && (S_ISDIR(sbuf.st_mode))))
324        {
325            uFree(tmp);
326            continue;
327        }
328        if (S_ISDIR(sbuf.st_mode))
329        {
330            if ((rest != NULL) || (verboseLevel & ListRecursive))
331                nMatch += AddDirectory(tmp, rest, NULL, map);
332        }
333        else
334            nMatch += AddListing(tmp, map);
335    }
336#ifdef WIN32
337    while (FindNextFile(dirh, &file));
338#endif
339    return nMatch;
340}
341
342/***====================================================================***/
343
344Bool
345AddMatchingFiles(char *head_in)
346{
347    char *str, *head, *ptrn, *rest = NULL;
348
349    if (head_in == NULL)
350        return 0;
351    ptrn = NULL;
352    for (str = head_in; (*str != '\0') && (*str != '?') && (*str != '*');
353         str++)
354    {
355        if ((str != head_in) && (*str == '/'))
356            ptrn = str;
357    }
358    if (*str == '\0')
359    {                           /* no wildcards */
360        head = head_in;
361        ptrn = NULL;
362        rest = NULL;
363    }
364    else if (ptrn == NULL)
365    {                           /* no slash before the first wildcard */
366        head = NULL;
367        ptrn = head_in;
368    }
369    else
370    {                           /* slash followed by wildcard */
371        head = head_in;
372        *ptrn = '\0';
373        ptrn++;
374    }
375    if (ptrn)
376    {
377        rest = strchr(ptrn, '/');
378        if (rest != NULL)
379        {
380            *rest = '\0';
381            rest++;
382        }
383    }
384    if (((rest && ptrn)
385         && ((strchr(ptrn, '(') != NULL) || (strchr(ptrn, ')') != NULL)))
386        || (head
387            && ((strchr(head, '(') != NULL) || (strchr(head, ')') != NULL))))
388    {
389        ERROR1("Files/maps to list must have the form file(map)\n");
390        ACTION("Illegal specifier ignored\n");
391        return 0;
392    }
393    return AddDirectory(head, ptrn, rest, NULL);
394}
395
396/***====================================================================***/
397
398static Bool
399MapMatches(char *mapToConsider, char *ptrn)
400{
401    int i;
402
403    if (ptrn != NULL)
404        return XkbNameMatchesPattern(mapToConsider, ptrn);
405    if (nMapOnly < 1)
406        return True;
407    for (i = 0; i < nMapOnly; i++)
408    {
409        if (XkbNameMatchesPattern(mapToConsider, mapOnly[i]))
410            return True;
411    }
412    return False;
413}
414
415int
416GenerateListing(char *out_name)
417{
418    int i;
419    FILE *inputFile, *outFile;
420    XkbFile *rtrn, *mapToUse;
421    unsigned oldWarningLevel;
422    char *mapName;
423
424    if (nFilesListed < 1)
425    {
426        ERROR1("Must specify at least one file or pattern to list\n");
427        return 0;
428    }
429    if ((!out_name) || ((out_name[0] == '-') && (out_name[1] == '\0')))
430        outFile = stdout;
431    else if ((outFile = fopen(out_name, "w")) == NULL)
432    {
433        ERROR1("Cannot open \"%s\" to write keyboard description\n",
434               out_name);
435        ACTION("Exiting\n");
436        return 0;
437    }
438#ifdef DEBUG
439    if (warningLevel > 9)
440        fprintf(stderr, "should list:\n");
441#endif
442    for (i = 0; i < nListed; i++)
443    {
444#ifdef DEBUG
445        if (warningLevel > 9)
446        {
447            fprintf(stderr, "%s(%s)\n",
448                    (list[i].file ? list[i].file : "*"),
449                    (list[i].map ? list[i].map : "*"));
450        }
451#endif
452        oldWarningLevel = warningLevel;
453        warningLevel = 0;
454        if (list[i].file)
455        {
456            struct stat sbuf;
457
458            if (stat(list[i].file, &sbuf) < 0)
459            {
460                if (oldWarningLevel > 5)
461                    WARN1("Couldn't open \"%s\"\n", list[i].file);
462                continue;
463            }
464            if (S_ISDIR(sbuf.st_mode))
465            {
466                if (verboseLevel & ListRecursive)
467                    AddDirectory(list[i].file, NULL, NULL, NULL);
468                continue;
469            }
470
471            inputFile = fopen(list[i].file, "r");
472            if (!inputFile)
473            {
474                if (oldWarningLevel > 5)
475                    WARN1("Couldn't open \"%s\"\n", list[i].file);
476                continue;
477            }
478            setScanState(list[i].file, 1);
479            if (XKBParseFile(inputFile, &rtrn) && (rtrn != NULL))
480            {
481                mapName = list[i].map;
482                mapToUse = rtrn;
483                for (; mapToUse; mapToUse = (XkbFile *) mapToUse->common.next)
484                {
485                    if (!MapMatches(mapToUse->name, mapName))
486                        continue;
487                    ListFile(outFile, list[i].file, mapToUse);
488                }
489            }
490            fclose(inputFile);
491        }
492        warningLevel = oldWarningLevel;
493    }
494    return 1;
495}
496