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#define DEBUG_VAR listingDebug 80#include "xkbcomp.h" 81#include <stdlib.h> 82 83#ifdef _POSIX_SOURCE 84# include <limits.h> 85#else 86# define _POSIX_SOURCE 87# include <limits.h> 88# undef _POSIX_SOURCE 89#endif 90 91#ifndef PATH_MAX 92#ifdef WIN32 93#define PATH_MAX 512 94#else 95#include <sys/param.h> 96#endif 97#ifndef PATH_MAX 98#ifdef MAXPATHLEN 99#define PATH_MAX MAXPATHLEN 100#else 101#define PATH_MAX 1024 102#endif 103#endif 104#endif 105 106#ifdef WIN32 107# define WIN32_LEAN_AND_MEAN 108# include <X11/Xwindows.h> 109# define FileName(file) file.cFileName 110# undef TEXT 111# undef ALTERNATE 112#else 113# include <dirent.h> 114# define FileName(file) file->d_name 115#endif 116 117#include "xkbpath.h" 118#include "parseutils.h" 119#include "misc.h" 120#include "tokens.h" 121#include <X11/extensions/XKBgeom.h> 122 123#define lowbit(x) ((x) & (-(x))) 124 125#ifdef DEBUG 126unsigned int listingDebug; 127#endif 128 129static int szListing = 0; 130static int nListed = 0; 131static int nFilesListed = 0; 132 133typedef struct _Listing 134{ 135 char *file; 136 char *map; 137} Listing; 138 139static int szMapOnly; 140static int nMapOnly; 141static char **mapOnly; 142 143static Listing *list = NULL; 144 145/***====================================================================***/ 146 147int 148AddMapOnly(char *map) 149{ 150 if (nMapOnly >= szMapOnly) 151 { 152 if (szMapOnly < 1) 153 szMapOnly = 5; 154 else 155 szMapOnly *= 2; 156 mapOnly = reallocarray(list, szMapOnly, sizeof(char *)); 157 if (!mapOnly) 158 { 159 WSGO("Couldn't allocate list of maps\n"); 160 return 0; 161 } 162 } 163 mapOnly[nMapOnly++] = map; 164 return 1; 165} 166 167static int 168AddListing(char *file, char *map) 169{ 170 if (nListed >= szListing) 171 { 172 if (szListing < 1) 173 szListing = 10; 174 else 175 szListing *= 2; 176 list = reallocarray(list, szListing, sizeof(Listing)); 177 if (!list) 178 { 179 WSGO("Couldn't allocate list of files and maps\n"); 180 ACTION("Exiting\n"); 181 exit(1); 182 } 183 } 184 185 list[nListed].file = file; 186 list[nListed].map = map; 187 nListed++; 188 if (file != NULL) 189 nFilesListed++; 190 return 1; 191} 192 193/***====================================================================***/ 194 195static void 196ListFile(FILE *outFile, const char *fileName, XkbFile *map) 197{ 198 unsigned flags; 199 const char *mapName; 200 201 flags = map->flags; 202 if ((flags & XkbLC_Hidden) && (!(verboseLevel & WantHiddenMaps))) 203 return; 204 if ((flags & XkbLC_Partial) && (!(verboseLevel & WantPartialMaps))) 205 return; 206 if (verboseLevel & WantLongListing) 207 { 208 fprintf(outFile, (flags & XkbLC_Hidden) ? "h" : "-"); 209 fprintf(outFile, (flags & XkbLC_Default) ? "d" : "-"); 210 fprintf(outFile, (flags & XkbLC_Partial) ? "p" : "-"); 211 fprintf(outFile, "----- "); 212 if (map->type == XkmSymbolsIndex) 213 { 214 fprintf(outFile, (flags & XkbLC_AlphanumericKeys) ? "a" : "-"); 215 fprintf(outFile, (flags & XkbLC_ModifierKeys) ? "m" : "-"); 216 fprintf(outFile, (flags & XkbLC_KeypadKeys) ? "k" : "-"); 217 fprintf(outFile, (flags & XkbLC_FunctionKeys) ? "f" : "-"); 218 fprintf(outFile, (flags & XkbLC_AlternateGroup) ? "g" : "-"); 219 fprintf(outFile, "--- "); 220 } 221 else 222 fprintf(outFile, "-------- "); 223 } 224 mapName = map->name; 225 if ((!(verboseLevel & WantFullNames)) && ((flags & XkbLC_Default) != 0)) 226 mapName = NULL; 227 if (dirsToStrip > 0) 228 { 229 const char *tmp, *last; 230 int i; 231 for (i = 0, tmp = last = fileName; (i < dirsToStrip) && tmp; i++) 232 { 233 last = tmp; 234 tmp = strchr(tmp, '/'); 235 if (tmp != NULL) 236 tmp++; 237 } 238 fileName = (tmp ? tmp : last); 239 } 240 if (mapName) 241 fprintf(outFile, "%s(%s)\n", fileName, mapName); 242 else 243 fprintf(outFile, "%s\n", fileName); 244 return; 245} 246 247/***====================================================================***/ 248 249static int 250AddDirectory(char *head, char *ptrn, char *rest, char *map) 251{ 252#ifdef WIN32 253 HANDLE dirh; 254 WIN32_FIND_DATA file; 255#else 256 DIR *dirp; 257 struct dirent *file; 258#endif 259 int nMatch; 260 261 if (map == NULL) 262 { 263 char *tmp = ptrn; 264 if ((rest == NULL) && (ptrn != NULL) && (strchr(ptrn, '/') == NULL)) 265 { 266 tmp = ptrn; 267 map = strchr(ptrn, '('); 268 } 269 else if ((rest == NULL) && (ptrn == NULL) && 270 (head != NULL) && (strchr(head, '/') == NULL)) 271 { 272 tmp = head; 273 map = strchr(head, '('); 274 } 275 if (map != NULL) 276 { 277 tmp = strchr(tmp, ')'); 278 if ((tmp == NULL) || (tmp[1] != '\0')) 279 { 280 ERROR("File and map must have the format file(map)\n"); 281 return 0; 282 } 283 *map = '\0'; 284 map++; 285 *tmp = '\0'; 286 } 287 } 288#ifdef WIN32 289 if ((dirh = FindFirstFile("*.*", &file)) == INVALID_HANDLE_VALUE) 290 return 0; 291#else 292 if ((dirp = opendir((head ? head : "."))) == NULL) 293 return 0; 294#endif 295 nMatch = 0; 296#ifdef WIN32 297 do 298#else 299 while ((file = readdir(dirp)) != NULL) 300#endif 301 { 302 char *tmp, *filename; 303 struct stat sbuf; 304 305 filename = FileName(file); 306 if (!filename || filename[0] == '.') 307 continue; 308 if (ptrn && (!XkbNameMatchesPattern(filename, ptrn))) 309 continue; 310#ifdef HAVE_ASPRINTF 311 if (asprintf(&tmp, "%s%s%s", 312 (head ? head : ""), (head ? "/" : ""), filename) < 0) 313 continue; 314#else 315 size_t tmpsize = (head ? strlen(head) : 0) + strlen(filename) + 2; 316 tmp = malloc(tmpsize); 317 if (!tmp) 318 continue; 319 snprintf(tmp, tmpsize, "%s%s%s", 320 (head ? head : ""), (head ? "/" : ""), filename); 321#endif 322 if (stat(tmp, &sbuf) < 0) 323 { 324 free(tmp); 325 continue; 326 } 327 if (((rest != NULL) && (!S_ISDIR(sbuf.st_mode))) || 328 ((map != NULL) && (S_ISDIR(sbuf.st_mode)))) 329 { 330 free(tmp); 331 continue; 332 } 333 if (S_ISDIR(sbuf.st_mode)) 334 { 335 if ((rest != NULL) || (verboseLevel & ListRecursive)) 336 nMatch += AddDirectory(tmp, rest, NULL, map); 337 } 338 else 339 nMatch += AddListing(tmp, map); 340 } 341#ifdef WIN32 342 while (FindNextFile(dirh, &file)); 343#endif 344 return nMatch; 345} 346 347/***====================================================================***/ 348 349Bool 350AddMatchingFiles(char *head_in) 351{ 352 char *str, *head, *ptrn, *rest = NULL; 353 354 if (head_in == NULL) 355 return 0; 356 ptrn = NULL; 357 for (str = head_in; (*str != '\0') && (*str != '?') && (*str != '*'); 358 str++) 359 { 360 if ((str != head_in) && (*str == '/')) 361 ptrn = str; 362 } 363 if (*str == '\0') 364 { /* no wildcards */ 365 head = head_in; 366 ptrn = NULL; 367 rest = NULL; 368 } 369 else if (ptrn == NULL) 370 { /* no slash before the first wildcard */ 371 head = NULL; 372 ptrn = head_in; 373 } 374 else 375 { /* slash followed by wildcard */ 376 head = head_in; 377 *ptrn = '\0'; 378 ptrn++; 379 } 380 if (ptrn) 381 { 382 rest = strchr(ptrn, '/'); 383 if (rest != NULL) 384 { 385 *rest = '\0'; 386 rest++; 387 } 388 } 389 if (((rest && ptrn) 390 && ((strchr(ptrn, '(') != NULL) || (strchr(ptrn, ')') != NULL))) 391 || (head 392 && ((strchr(head, '(') != NULL) || (strchr(head, ')') != NULL)))) 393 { 394 ERROR("Files/maps to list must have the form file(map)\n"); 395 ACTION("Illegal specifier ignored\n"); 396 return 0; 397 } 398 return AddDirectory(head, ptrn, rest, NULL); 399} 400 401/***====================================================================***/ 402 403static Bool 404MapMatches(char *mapToConsider, char *ptrn) 405{ 406 if (ptrn != NULL) 407 return XkbNameMatchesPattern(mapToConsider, ptrn); 408 if (nMapOnly < 1) 409 return True; 410 for (int i = 0; i < nMapOnly; i++) 411 { 412 if (XkbNameMatchesPattern(mapToConsider, mapOnly[i])) 413 return True; 414 } 415 return False; 416} 417 418int 419GenerateListing(const char *out_name) 420{ 421 FILE *outFile; 422 XkbFile *rtrn; 423 424 if (nFilesListed < 1) 425 { 426 ERROR("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 ERROR("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 (int i = 0; i < nListed; i++) 443 { 444 unsigned oldWarningLevel; 445#ifdef DEBUG 446 if (warningLevel > 9) 447 { 448 fprintf(stderr, "%s(%s)\n", 449 (list[i].file ? list[i].file : "*"), 450 (list[i].map ? list[i].map : "*")); 451 } 452#endif 453 oldWarningLevel = warningLevel; 454 warningLevel = 0; 455 if (list[i].file) 456 { 457 FILE *inputFile; 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 char *mapName = list[i].map; 484 XkbFile *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 if (outFile != stdout) 497 { 498 fclose(outFile); 499 } 500 return 1; 501} 502