listing.c revision 6930ead5
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 "utils.h" 74#include <stdio.h> 75#include <ctype.h> 76#include <sys/types.h> 77#include <sys/stat.h> 78#include <X11/keysym.h> 79 80#define DEBUG_VAR listingDebug 81#include "xkbcomp.h" 82#include <stdlib.h> 83 84#ifdef _POSIX_SOURCE 85# include <limits.h> 86#else 87# define _POSIX_SOURCE 88# include <limits.h> 89# undef _POSIX_SOURCE 90#endif 91 92#ifndef PATH_MAX 93#ifdef WIN32 94#define PATH_MAX 512 95#else 96#include <sys/param.h> 97#endif 98#ifndef PATH_MAX 99#ifdef MAXPATHLEN 100#define PATH_MAX MAXPATHLEN 101#else 102#define PATH_MAX 1024 103#endif 104#endif 105#endif 106 107#ifdef WIN32 108# define WIN32_LEAN_AND_MEAN 109# include <X11/Xwindows.h> 110# define FileName(file) file.cFileName 111# undef TEXT 112# undef ALTERNATE 113#else 114# include <dirent.h> 115# define FileName(file) file->d_name 116#endif 117 118#include "xkbpath.h" 119#include "parseutils.h" 120#include "misc.h" 121#include "tokens.h" 122#include <X11/extensions/XKBgeom.h> 123 124#define lowbit(x) ((x) & (-(x))) 125 126#ifdef DEBUG 127unsigned int listingDebug; 128#endif 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 = reallocarray(list, szMapOnly, sizeof(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 168static int 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 = reallocarray(list, szListing, sizeof(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, const char *fileName, XkbFile *map) 198{ 199 unsigned flags; 200 const 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 const 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 ERROR("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#endif 296 nMatch = 0; 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#ifdef HAVE_ASPRINTF 312 if (asprintf(&tmp, "%s%s%s", 313 (head ? head : ""), (head ? "/" : ""), filename) < 0) 314 continue; 315#else 316 size_t tmpsize = (head ? strlen(head) : 0) + strlen(filename) + 2; 317 tmp = malloc(tmpsize); 318 if (!tmp) 319 continue; 320 snprintf(tmp, tmpsize, "%s%s%s", 321 (head ? head : ""), (head ? "/" : ""), filename); 322#endif 323 if (stat(tmp, &sbuf) < 0) 324 { 325 free(tmp); 326 continue; 327 } 328 if (((rest != NULL) && (!S_ISDIR(sbuf.st_mode))) || 329 ((map != NULL) && (S_ISDIR(sbuf.st_mode)))) 330 { 331 free(tmp); 332 continue; 333 } 334 if (S_ISDIR(sbuf.st_mode)) 335 { 336 if ((rest != NULL) || (verboseLevel & ListRecursive)) 337 nMatch += AddDirectory(tmp, rest, NULL, map); 338 } 339 else 340 nMatch += AddListing(tmp, map); 341 } 342#ifdef WIN32 343 while (FindNextFile(dirh, &file)); 344#endif 345 return nMatch; 346} 347 348/***====================================================================***/ 349 350Bool 351AddMatchingFiles(char *head_in) 352{ 353 char *str, *head, *ptrn, *rest = NULL; 354 355 if (head_in == NULL) 356 return 0; 357 ptrn = NULL; 358 for (str = head_in; (*str != '\0') && (*str != '?') && (*str != '*'); 359 str++) 360 { 361 if ((str != head_in) && (*str == '/')) 362 ptrn = str; 363 } 364 if (*str == '\0') 365 { /* no wildcards */ 366 head = head_in; 367 ptrn = NULL; 368 rest = NULL; 369 } 370 else if (ptrn == NULL) 371 { /* no slash before the first wildcard */ 372 head = NULL; 373 ptrn = head_in; 374 } 375 else 376 { /* slash followed by wildcard */ 377 head = head_in; 378 *ptrn = '\0'; 379 ptrn++; 380 } 381 if (ptrn) 382 { 383 rest = strchr(ptrn, '/'); 384 if (rest != NULL) 385 { 386 *rest = '\0'; 387 rest++; 388 } 389 } 390 if (((rest && ptrn) 391 && ((strchr(ptrn, '(') != NULL) || (strchr(ptrn, ')') != NULL))) 392 || (head 393 && ((strchr(head, '(') != NULL) || (strchr(head, ')') != NULL)))) 394 { 395 ERROR("Files/maps to list must have the form file(map)\n"); 396 ACTION("Illegal specifier ignored\n"); 397 return 0; 398 } 399 return AddDirectory(head, ptrn, rest, NULL); 400} 401 402/***====================================================================***/ 403 404static Bool 405MapMatches(char *mapToConsider, char *ptrn) 406{ 407 if (ptrn != NULL) 408 return XkbNameMatchesPattern(mapToConsider, ptrn); 409 if (nMapOnly < 1) 410 return True; 411 for (int i = 0; i < nMapOnly; i++) 412 { 413 if (XkbNameMatchesPattern(mapToConsider, mapOnly[i])) 414 return True; 415 } 416 return False; 417} 418 419int 420GenerateListing(const char *out_name) 421{ 422 FILE *outFile; 423 XkbFile *rtrn; 424 425 if (nFilesListed < 1) 426 { 427 ERROR("Must specify at least one file or pattern to list\n"); 428 return 0; 429 } 430 if ((!out_name) || ((out_name[0] == '-') && (out_name[1] == '\0'))) 431 outFile = stdout; 432 else if ((outFile = fopen(out_name, "w")) == NULL) 433 { 434 ERROR("Cannot open \"%s\" to write keyboard description\n", 435 out_name); 436 ACTION("Exiting\n"); 437 return 0; 438 } 439#ifdef DEBUG 440 if (warningLevel > 9) 441 fprintf(stderr, "should list:\n"); 442#endif 443 for (int i = 0; i < nListed; i++) 444 { 445 unsigned oldWarningLevel; 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 FILE *inputFile; 459 struct stat sbuf; 460 461 if (stat(list[i].file, &sbuf) < 0) 462 { 463 if (oldWarningLevel > 5) 464 WARN("Couldn't open \"%s\"\n", list[i].file); 465 continue; 466 } 467 if (S_ISDIR(sbuf.st_mode)) 468 { 469 if (verboseLevel & ListRecursive) 470 AddDirectory(list[i].file, NULL, NULL, NULL); 471 continue; 472 } 473 474 inputFile = fopen(list[i].file, "r"); 475 if (!inputFile) 476 { 477 if (oldWarningLevel > 5) 478 WARN("Couldn't open \"%s\"\n", list[i].file); 479 continue; 480 } 481 setScanState(list[i].file, 1); 482 if (XKBParseFile(inputFile, &rtrn) && (rtrn != NULL)) 483 { 484 char *mapName = list[i].map; 485 XkbFile *mapToUse = rtrn; 486 for (; mapToUse; mapToUse = (XkbFile *) mapToUse->common.next) 487 { 488 if (!MapMatches(mapToUse->name, mapName)) 489 continue; 490 ListFile(outFile, list[i].file, mapToUse); 491 } 492 } 493 fclose(inputFile); 494 } 495 warningLevel = oldWarningLevel; 496 } 497 if (outFile != stdout) 498 { 499 fclose(outFile); 500 } 501 return 1; 502} 503