xkbcomp.c revision 1d8c7986
1/************************************************************ 2 Copyright (c) 1994 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#include <stdio.h> 28#include <ctype.h> 29#include <X11/keysym.h> 30 31/* for symlink attack security fix -- Branden Robinson */ 32#include <sys/stat.h> 33#include <sys/types.h> 34#include <unistd.h> 35/* end BR */ 36 37#if defined(sgi) 38#include <malloc.h> 39#endif 40 41#define DEBUG_VAR debugFlags 42#include "xkbcomp.h" 43#include <stdlib.h> 44#include "xkbpath.h" 45#include "parseutils.h" 46#include "misc.h" 47#include "tokens.h" 48#include <X11/extensions/XKBgeom.h> 49 50#ifdef __UNIXOS2__ 51#define chdir _chdir2 52#endif 53 54#ifdef WIN32 55#define S_IRGRP 0 56#define S_IWGRP 0 57#define S_IROTH 0 58#define S_IWOTH 0 59#endif 60 61#define lowbit(x) ((x) & (-(x))) 62 63/***====================================================================***/ 64 65#define WANT_DEFAULT 0 66#define WANT_XKM_FILE 1 67#define WANT_C_HDR 2 68#define WANT_XKB_FILE 3 69#define WANT_X_SERVER 4 70#define WANT_LISTING 5 71 72#define INPUT_UNKNOWN 0 73#define INPUT_XKB 1 74#define INPUT_XKM 2 75 76unsigned int debugFlags; 77 78static const char *fileTypeExt[] = { 79 "XXX", 80 "xkm", 81 "h", 82 "xkb", 83 "dir" 84}; 85 86static unsigned inputFormat, outputFormat; 87char *rootDir; 88static char *inputFile; 89static char *inputMap; 90static char *outputFile; 91static char *inDpyName; 92static char *outDpyName; 93static Display *inDpy; 94static Display *outDpy; 95static Bool showImplicit = False; 96static Bool synch = False; 97static Bool computeDflts = False; 98static Bool xkblist = False; 99unsigned warningLevel = 5; 100unsigned verboseLevel = 0; 101unsigned dirsToStrip = 0; 102unsigned optionalParts = 0; 103static char *preErrorMsg = NULL; 104static char *postErrorMsg = NULL; 105static char *errorPrefix = NULL; 106static unsigned int device_id = XkbUseCoreKbd; 107 108/***====================================================================***/ 109 110#define M(m) fprintf(stderr,(m)) 111#define M1(m,a) fprintf(stderr,(m),(a)) 112 113static void 114Usage(int argc, char *argv[]) 115{ 116 if (!xkblist) 117 M1("Usage: %s [options] input-file [ output-file ]\n", argv[0]); 118 else 119 M1("Usage: %s [options] file[(map)] ...\n", argv[0]); 120 M("Legal options:\n"); 121 M("-?,-help Print this message\n"); 122 M("-version Print the version number\n"); 123 if (!xkblist) 124 { 125 M("-a Show all actions\n"); 126 M("-C Create a C header file\n"); 127 } 128#ifdef DEBUG 129 M("-d [flags] Report debugging information\n"); 130#endif 131 M("-em1 <msg> Print <msg> before printing first error message\n"); 132 M("-emp <msg> Print <msg> at the start of each message line\n"); 133 M("-eml <msg> If there were any errors, print <msg> before exiting\n"); 134 if (!xkblist) 135 { 136 M("-dflts Compute defaults for missing parts\n"); 137 M("-I[<dir>] Specifies a top level directory for include\n"); 138 M(" directives. Multiple directories are legal.\n"); 139 M("-l [flags] List matching maps in the specified files\n"); 140 M(" f: list fully specified names\n"); 141 M(" h: also list hidden maps\n"); 142 M(" l: long listing (show flags)\n"); 143 M(" p: also list partial maps\n"); 144 M(" R: recursively list subdirectories\n"); 145 M(" default is all options off\n"); 146 } 147 M("-i <deviceid> Specifies device ID (not name) to compile for\n"); 148 M("-m[ap] <map> Specifies map to compile\n"); 149 M("-o <file> Specifies output file name\n"); 150 if (!xkblist) 151 { 152 M("-opt[ional] <parts> Specifies optional components of keymap\n"); 153 M(" Errors in optional parts are not fatal\n"); 154 M(" <parts> can be any combination of:\n"); 155 M(" c: compat map g: geometry\n"); 156 M(" k: keycodes s: symbols\n"); 157 M(" t: types\n"); 158 } 159 if (xkblist) 160 { 161 M("-p <count> Specifies the number of slashes to be stripped\n"); 162 M(" from the front of the map name on output\n"); 163 } 164 M("-R[<DIR>] Specifies the root directory for\n"); 165 M(" relative path names\n"); 166 M("-synch Force synchronization\n"); 167 if (xkblist) 168 { 169 M("-v [<flags>] Set level of detail for listing.\n"); 170 M(" flags are as for the -l option\n"); 171 } 172 M("-w [<lvl>] Set warning level (0=none, 10=all)\n"); 173 if (!xkblist) 174 { 175 M("-xkb Create an XKB source (.xkb) file\n"); 176 M("-xkm Create a compiled key map (.xkm) file\n"); 177 } 178 return; 179} 180 181/***====================================================================***/ 182 183static void 184setVerboseFlags(char *str) 185{ 186 for (; *str; str++) 187 { 188 switch (*str) 189 { 190 case 'f': 191 verboseLevel |= WantFullNames; 192 break; 193 case 'h': 194 verboseLevel |= WantHiddenMaps; 195 break; 196 case 'l': 197 verboseLevel |= WantLongListing; 198 break; 199 case 'p': 200 verboseLevel |= WantPartialMaps; 201 break; 202 case 'R': 203 verboseLevel |= ListRecursive; 204 break; 205 default: 206 if (warningLevel > 4) 207 { 208 WARN1("Unknown verbose option \"%c\"\n", (unsigned int) *str); 209 ACTION("Ignored\n"); 210 } 211 break; 212 } 213 } 214 return; 215} 216 217static Bool 218parseArgs(int argc, char *argv[]) 219{ 220 register int i, tmp; 221 222 i = strlen(argv[0]); 223 tmp = strlen("xkblist"); 224 if ((i >= tmp) && (strcmp(&argv[0][i - tmp], "xkblist") == 0)) 225 { 226 xkblist = True; 227 } 228 for (i = 1; i < argc; i++) 229 { 230 int itmp; 231 if ((argv[i][0] != '-') || (uStringEqual(argv[i], "-"))) 232 { 233 if (!xkblist) 234 { 235 if (inputFile == NULL) 236 inputFile = argv[i]; 237 else if (outputFile == NULL) 238 outputFile = argv[i]; 239 else if (warningLevel > 0) 240 { 241 WARN("Too many file names on command line\n"); 242 ACTION3 243 ("Compiling %s, writing to %s, ignoring %s\n", 244 inputFile, outputFile, argv[i]); 245 } 246 } 247 else if (!AddMatchingFiles(argv[i])) 248 return False; 249 } 250 else if ((strcmp(argv[i], "-?") == 0) 251 || (strcmp(argv[i], "-help") == 0)) 252 { 253 Usage(argc, argv); 254 exit(0); 255 } 256 else if (strcmp(argv[i], "-version") == 0) 257 { 258 printf("xkbcomp %s\n", PACKAGE_VERSION); 259 exit(0); 260 } else if ((strcmp(argv[i], "-a") == 0) && (!xkblist)) 261 { 262 showImplicit = True; 263 } 264 else if ((strcmp(argv[i], "-C") == 0) && (!xkblist)) 265 { 266 if ((outputFormat != WANT_DEFAULT) 267 && (outputFormat != WANT_C_HDR)) 268 { 269 if (warningLevel > 0) 270 { 271 WARN("Multiple output file formats specified\n"); 272 ACTION1("\"%s\" flag ignored\n", argv[i]); 273 } 274 } 275 else 276 outputFormat = WANT_C_HDR; 277 } 278#ifdef DEBUG 279 else if (strcmp(argv[i], "-d") == 0) 280 { 281 if ((i >= (argc - 1)) || (!isdigit(argv[i + 1][0]))) 282 { 283 debugFlags = 1; 284 } 285 else 286 { 287 if (sscanf(argv[++i], "%i", &itmp) == 1) 288 debugFlags = itmp; 289 } 290 INFO1("Setting debug flags to %d\n", debugFlags); 291 } 292#endif 293 else if ((strcmp(argv[i], "-dflts") == 0) && (!xkblist)) 294 { 295 computeDflts = True; 296 } 297 else if (strcmp(argv[i], "-em1") == 0) 298 { 299 if (++i >= argc) 300 { 301 if (warningLevel > 0) 302 { 303 WARN("No pre-error message specified\n"); 304 ACTION("Trailing \"-em1\" option ignored\n"); 305 } 306 } 307 else if (preErrorMsg != NULL) 308 { 309 if (warningLevel > 0) 310 { 311 WARN("Multiple pre-error messsages specified\n"); 312 ACTION2("Compiling %s, ignoring %s\n", 313 preErrorMsg, argv[i]); 314 } 315 } 316 else 317 preErrorMsg = argv[i]; 318 } 319 else if (strcmp(argv[i], "-emp") == 0) 320 { 321 if (++i >= argc) 322 { 323 if (warningLevel > 0) 324 { 325 WARN("No error prefix specified\n"); 326 ACTION("Trailing \"-emp\" option ignored\n"); 327 } 328 } 329 else if (errorPrefix != NULL) 330 { 331 if (warningLevel > 0) 332 { 333 WARN("Multiple error prefixes specified\n"); 334 ACTION2("Compiling %s, ignoring %s\n", 335 errorPrefix, argv[i]); 336 } 337 } 338 else 339 errorPrefix = argv[i]; 340 } 341 else if (strcmp(argv[i], "-eml") == 0) 342 { 343 if (++i >= argc) 344 { 345 if (warningLevel > 0) 346 { 347 WARN("No post-error message specified\n"); 348 ACTION("Trailing \"-eml\" option ignored\n"); 349 } 350 } 351 else if (postErrorMsg != NULL) 352 { 353 if (warningLevel > 0) 354 { 355 WARN("Multiple post-error messages specified\n"); 356 ACTION2("Compiling %s, ignoring %s\n", 357 postErrorMsg, argv[i]); 358 } 359 } 360 else 361 postErrorMsg = argv[i]; 362 } 363 else if ((strncmp(argv[i], "-I", 2) == 0) && (!xkblist)) 364 { 365 if (!XkbAddDirectoryToPath(&argv[i][2])) 366 { 367 ACTION("Exiting\n"); 368 exit(1); 369 } 370 } 371 else if ((strncmp(argv[i], "-i", 2) == 0) && (!xkblist)) 372 { 373 if (++i >= argc) 374 { 375 if (warningLevel > 0) 376 WARN("No device ID specified\n"); 377 } 378 device_id = atoi(argv[i]); 379 } 380 else if ((strncmp(argv[i], "-l", 2) == 0) && (!xkblist)) 381 { 382 if (outputFormat != WANT_DEFAULT) 383 { 384 if (warningLevel > 0) 385 { 386 WARN("Multiple output file formats specified\n"); 387 ACTION1("\"%s\" flag ignored\n", argv[i]); 388 } 389 } 390 else 391 { 392 if (argv[i][2] != '\0') 393 setVerboseFlags(&argv[i][2]); 394 xkblist = True; 395 if ((inputFile) && (!AddMatchingFiles(inputFile))) 396 return False; 397 else 398 inputFile = NULL; 399 if ((outputFile) && (!AddMatchingFiles(outputFile))) 400 return False; 401 else 402 outputFile = NULL; 403 } 404 } 405 else if ((strcmp(argv[i], "-m") == 0) 406 || (strcmp(argv[i], "-map") == 0)) 407 { 408 if (++i >= argc) 409 { 410 if (warningLevel > 0) 411 { 412 WARN("No map name specified\n"); 413 ACTION1("Trailing \"%s\" option ignored\n", argv[i - 1]); 414 } 415 } 416 else if (xkblist) 417 { 418 if (!AddMapOnly(argv[i])) 419 return False; 420 } 421 else if (inputMap != NULL) 422 { 423 if (warningLevel > 0) 424 { 425 WARN("Multiple map names specified\n"); 426 ACTION2("Compiling %s, ignoring %s\n", inputMap, argv[i]); 427 } 428 } 429 else 430 inputMap = argv[i]; 431 } 432 else if ((strcmp(argv[i], "-merge") == 0) && (!xkblist)) 433 { 434 /* Ignored */ 435 } 436 else if (strcmp(argv[i], "-o") == 0) 437 { 438 if (++i >= argc) 439 { 440 if (warningLevel > 0) 441 { 442 WARN("No output file specified\n"); 443 ACTION("Trailing \"-o\" option ignored\n"); 444 } 445 } 446 else if (outputFile != NULL) 447 { 448 if (warningLevel > 0) 449 { 450 WARN("Multiple output files specified\n"); 451 ACTION2("Compiling %s, ignoring %s\n", outputFile, 452 argv[i]); 453 } 454 } 455 else 456 outputFile = argv[i]; 457 } 458 else if (((strcmp(argv[i], "-opt") == 0) 459 || (strcmp(argv[i], "optional") == 0)) && (!xkblist)) 460 { 461 if (++i >= argc) 462 { 463 if (warningLevel > 0) 464 { 465 WARN("No optional components specified\n"); 466 ACTION1("Trailing \"%s\" option ignored\n", argv[i - 1]); 467 } 468 } 469 else 470 { 471 char *tmp2; 472 for (tmp2 = argv[i]; (*tmp2 != '\0'); tmp2++) 473 { 474 switch (*tmp2) 475 { 476 case 'c': 477 case 'C': 478 optionalParts |= XkmCompatMapMask; 479 break; 480 case 'g': 481 case 'G': 482 optionalParts |= XkmGeometryMask; 483 break; 484 case 'k': 485 case 'K': 486 optionalParts |= XkmKeyNamesMask; 487 break; 488 case 's': 489 case 'S': 490 optionalParts |= XkmSymbolsMask; 491 break; 492 case 't': 493 case 'T': 494 optionalParts |= XkmTypesMask; 495 break; 496 default: 497 if (warningLevel > 0) 498 { 499 WARN1 500 ("Illegal component for %s option\n", 501 argv[i - 1]); 502 ACTION1 503 ("Ignoring unknown specifier \"%c\"\n", 504 (unsigned int) *tmp2); 505 } 506 break; 507 } 508 } 509 } 510 } 511 else if (strncmp(argv[i], "-p", 2) == 0) 512 { 513 if (isdigit(argv[i][2])) 514 { 515 if (sscanf(&argv[i][2], "%i", &itmp) == 1) 516 dirsToStrip = itmp; 517 } 518 else if ((i < (argc - 1)) && (isdigit(argv[i + 1][0]))) 519 { 520 if (sscanf(argv[++i], "%i", &itmp) == 1) 521 dirsToStrip = itmp; 522 } 523 else 524 { 525 dirsToStrip = 0; 526 } 527 if (warningLevel > 5) 528 INFO1("Setting path count to %d\n", dirsToStrip); 529 } 530 else if (strncmp(argv[i], "-R", 2) == 0) 531 { 532 if (argv[i][2] == '\0') 533 { 534 if (warningLevel > 0) 535 { 536 WARN("No root directory specified\n"); 537 ACTION("Ignoring -R option\n"); 538 } 539 } 540 else if (rootDir != NULL) 541 { 542 if (warningLevel > 0) 543 { 544 WARN("Multiple root directories specified\n"); 545 ACTION2("Using %s, ignoring %s\n", rootDir, argv[i]); 546 } 547 } 548 else 549 { 550 rootDir = &argv[i][2]; 551 if (warningLevel > 8) 552 { 553 WARN1("Changing root directory to \"%s\"\n", rootDir); 554 } 555 if ((chdir(rootDir) < 0) && (warningLevel > 0)) 556 { 557 WARN1("Couldn't change directory to \"%s\"\n", rootDir); 558 ACTION("Root directory (-R) option ignored\n"); 559 rootDir = NULL; 560 } 561 } 562 } 563 else if ((strcmp(argv[i], "-synch") == 0) 564 || (strcmp(argv[i], "-s") == 0)) 565 { 566 synch = True; 567 } 568 else if (strncmp(argv[i], "-v", 2) == 0) 569 { 570 char *str; 571 if (argv[i][2] != '\0') 572 str = &argv[i][2]; 573 else if ((i < (argc - 1)) && (argv[i + 1][0] != '-')) 574 str = argv[++i]; 575 else 576 str = NULL; 577 if (str) 578 setVerboseFlags(str); 579 } 580 else if (strncmp(argv[i], "-w", 2) == 0) 581 { 582 if ((i >= (argc - 1)) || (!isdigit(argv[i + 1][0]))) 583 { 584 warningLevel = 0; 585 if (isdigit(argv[i][1])) 586 if (sscanf(&argv[i][1], "%i", &itmp) == 1) 587 warningLevel = itmp; 588 } 589 else 590 { 591 if (sscanf(argv[++i], "%i", &itmp) == 1) 592 warningLevel = itmp; 593 } 594 } 595 else if ((strcmp(argv[i], "-xkb") == 0) && (!xkblist)) 596 { 597 if ((outputFormat != WANT_DEFAULT) 598 && (outputFormat != WANT_XKB_FILE)) 599 { 600 if (warningLevel > 0) 601 { 602 WARN("Multiple output file formats specified\n"); 603 ACTION1("\"%s\" flag ignored\n", argv[i]); 604 } 605 } 606 else 607 outputFormat = WANT_XKB_FILE; 608 } 609 else if ((strcmp(argv[i], "-xkm") == 0) && (!xkblist)) 610 { 611 if ((outputFormat != WANT_DEFAULT) 612 && (outputFormat != WANT_XKM_FILE)) 613 { 614 if (warningLevel > 0) 615 { 616 WARN("Multiple output file formats specified\n"); 617 ACTION1("\"%s\" flag ignored\n", argv[i]); 618 } 619 } 620 else 621 outputFormat = WANT_XKM_FILE; 622 } 623 else 624 { 625 ERROR1("Unknown flag \"%s\" on command line\n", argv[i]); 626 Usage(argc, argv); 627 return False; 628 } 629 } 630 if (xkblist) 631 inputFormat = INPUT_XKB; 632 else if (inputFile == NULL) 633 { 634 ERROR("No input file specified\n"); 635 return False; 636 } 637 else if (uStringEqual(inputFile, "-")) 638 { 639 inputFormat = INPUT_XKB; 640 } 641#ifndef WIN32 642 else if (strchr(inputFile, ':') == NULL) 643 { 644#else 645 else if ((strchr(inputFile, ':') == NULL) || (strlen(inputFile) > 2 && 646 isalpha(inputFile[0]) && 647 inputFile[1] == ':' 648 && strchr(inputFile + 2, 649 ':') == NULL)) 650 { 651#endif 652 int len; 653 len = strlen(inputFile); 654 if (inputFile[len - 1] == ')') 655 { 656 char *tmpstr; 657 if ((tmpstr = strchr(inputFile, '(')) != NULL) 658 { 659 *tmpstr = '\0'; 660 inputFile[len - 1] = '\0'; 661 tmpstr++; 662 if (*tmpstr == '\0') 663 { 664 WARN("Empty map in filename\n"); 665 ACTION("Ignored\n"); 666 } 667 else if (inputMap == NULL) 668 { 669 inputMap = uStringDup(tmpstr); 670 } 671 else 672 { 673 WARN("Map specified in filename and with -m flag\n"); 674 ACTION1("map from name (\"%s\") ignored\n", tmpstr); 675 } 676 } 677 else 678 { 679 ERROR1("Illegal name \"%s\" for input file\n", inputFile); 680 return False; 681 } 682 } 683 if ((len > 4) && (strcmp(&inputFile[len - 4], ".xkm") == 0)) 684 { 685 inputFormat = INPUT_XKM; 686 } 687 else 688 { 689 FILE *file; 690 file = fopen(inputFile, "r"); 691 if (file) 692 { 693 if (XkmProbe(file)) 694 inputFormat = INPUT_XKM; 695 else 696 inputFormat = INPUT_XKB; 697 fclose(file); 698 } 699 else 700 { 701 fprintf(stderr, "Cannot open \"%s\" for reading\n", 702 inputFile); 703 return False; 704 } 705 } 706 } 707 else 708 { 709 inDpyName = inputFile; 710 inputFile = NULL; 711 inputFormat = INPUT_XKM; 712 } 713 714 if (outputFormat == WANT_DEFAULT) 715 { 716 if (xkblist) 717 outputFormat = WANT_LISTING; 718 else if (inputFormat == INPUT_XKB) 719 outputFormat = WANT_XKM_FILE; 720 else 721 outputFormat = WANT_XKB_FILE; 722 } 723 if ((outputFormat == WANT_LISTING) && (inputFormat != INPUT_XKB)) 724 { 725 if (inputFile) 726 ERROR("Cannot generate a listing from a .xkm file (yet)\n"); 727 else 728 ERROR("Cannot generate a listing from an X connection (yet)\n"); 729 return False; 730 } 731 if (xkblist) 732 { 733 if (outputFile == NULL) 734 outputFile = uStringDup("-"); 735 else if (strchr(outputFile, ':') != NULL) 736 { 737 ERROR("Cannot write a listing to an X connection\n"); 738 return False; 739 } 740 } 741 else if ((!outputFile) && (inputFile) && uStringEqual(inputFile, "-")) 742 { 743 int len = strlen("stdin") + strlen(fileTypeExt[outputFormat]) + 2; 744 outputFile = uTypedCalloc(len, char); 745 if (outputFile == NULL) 746 { 747 WSGO("Cannot allocate space for output file name\n"); 748 ACTION("Exiting\n"); 749 exit(1); 750 } 751 sprintf(outputFile, "stdin.%s", fileTypeExt[outputFormat]); 752 } 753 else if ((outputFile == NULL) && (inputFile != NULL)) 754 { 755 int len; 756 char *base, *ext; 757 758 if (inputMap == NULL) 759 { 760 base = strrchr(inputFile, '/'); 761 if (base == NULL) 762 base = inputFile; 763 else 764 base++; 765 } 766 else 767 base = inputMap; 768 769 len = strlen(base) + strlen(fileTypeExt[outputFormat]) + 2; 770 outputFile = uTypedCalloc(len, char); 771 if (outputFile == NULL) 772 { 773 WSGO("Cannot allocate space for output file name\n"); 774 ACTION("Exiting\n"); 775 exit(1); 776 } 777 ext = strrchr(base, '.'); 778 if (ext == NULL) 779 sprintf(outputFile, "%s.%s", base, fileTypeExt[outputFormat]); 780 else 781 { 782 strcpy(outputFile, base); 783 strcpy(&outputFile[ext - base + 1], fileTypeExt[outputFormat]); 784 } 785 } 786 else if (outputFile == NULL) 787 { 788 int len; 789 char *ch, *name, buf[128]; 790 if (inDpyName[0] == ':') 791 snprintf(name = buf, sizeof(buf), "server%s", inDpyName); 792 else 793 name = inDpyName; 794 795 len = strlen(name) + strlen(fileTypeExt[outputFormat]) + 2; 796 outputFile = uTypedCalloc(len, char); 797 if (outputFile == NULL) 798 { 799 WSGO("Cannot allocate space for output file name\n"); 800 ACTION("Exiting\n"); 801 exit(1); 802 } 803 strcpy(outputFile, name); 804 for (ch = outputFile; (*ch) != '\0'; ch++) 805 { 806 if (*ch == ':') 807 *ch = '-'; 808 else if (*ch == '.') 809 *ch = '_'; 810 } 811 *ch++ = '.'; 812 strcpy(ch, fileTypeExt[outputFormat]); 813 } 814#ifdef WIN32 815 else if (strlen(outputFile) > 2 && 816 isalpha(outputFile[0]) && 817 outputFile[1] == ':' && strchr(outputFile + 2, ':') == NULL) 818 { 819 } 820#endif 821 else if (strchr(outputFile, ':') != NULL) 822 { 823 outDpyName = outputFile; 824 outputFile = NULL; 825 outputFormat = WANT_X_SERVER; 826 } 827 return True; 828} 829 830static Display * 831GetDisplay(char *program, char *dpyName) 832{ 833 int mjr, mnr, error; 834 Display *dpy; 835 836 mjr = XkbMajorVersion; 837 mnr = XkbMinorVersion; 838 dpy = XkbOpenDisplay(dpyName, NULL, NULL, &mjr, &mnr, &error); 839 if (dpy == NULL) 840 { 841 switch (error) 842 { 843 case XkbOD_BadLibraryVersion: 844 INFO3("%s was compiled with XKB version %d.%02d\n", 845 program, XkbMajorVersion, XkbMinorVersion); 846 ERROR2("X library supports incompatible version %d.%02d\n", 847 mjr, mnr); 848 break; 849 case XkbOD_ConnectionRefused: 850 ERROR1("Cannot open display \"%s\"\n", dpyName); 851 break; 852 case XkbOD_NonXkbServer: 853 ERROR1("XKB extension not present on %s\n", dpyName); 854 break; 855 case XkbOD_BadServerVersion: 856 INFO3("%s was compiled with XKB version %d.%02d\n", 857 program, XkbMajorVersion, XkbMinorVersion); 858 ERROR3("Server %s uses incompatible version %d.%02d\n", 859 dpyName, mjr, mnr); 860 break; 861 default: 862 WSGO1("Unknown error %d from XkbOpenDisplay\n", error); 863 } 864 } 865 else if (synch) 866 XSynchronize(dpy, True); 867 return dpy; 868} 869 870/***====================================================================***/ 871 872#ifdef DEBUG 873extern int yydebug; 874#endif 875 876int 877main(int argc, char *argv[]) 878{ 879 FILE *file; /* input file (or stdin) */ 880 XkbFile *rtrn; 881 XkbFile *mapToUse; 882 int ok; 883 XkbFileInfo result; 884 Status status; 885 886 yyin = stdin; 887 uSetEntryFile(NullString); 888 uSetDebugFile(NullString); 889 uSetErrorFile(NullString); 890 891 XkbInitIncludePath(); 892 if (!parseArgs(argc, argv)) 893 exit(1); 894#ifdef DEBUG 895 if (debugFlags & 0x2) 896 yydebug = 1; 897#endif 898 if (preErrorMsg) 899 uSetPreErrorMessage(preErrorMsg); 900 if (errorPrefix) 901 uSetErrorPrefix(errorPrefix); 902 if (postErrorMsg) 903 uSetPostErrorMessage(postErrorMsg); 904 file = NULL; 905 XkbInitAtoms(NULL); 906 XkbAddDefaultDirectoriesToPath(); 907 if (xkblist) 908 { 909 Bool gotSome; 910 gotSome = GenerateListing(outputFile); 911 if ((warningLevel > 7) && (!gotSome)) 912 return -1; 913 return 0; 914 } 915 if (inputFile != NULL) 916 { 917 if (uStringEqual(inputFile, "-")) 918 { 919 file = stdin; 920 inputFile = "stdin"; 921 } 922 else 923 { 924 file = fopen(inputFile, "r"); 925 } 926 } 927 else if (inDpyName != NULL) 928 { 929 inDpy = GetDisplay(argv[0], inDpyName); 930 if (!inDpy) 931 { 932 ACTION("Exiting\n"); 933 exit(1); 934 } 935 } 936 if (outDpyName != NULL) 937 { 938 outDpy = GetDisplay(argv[0], outDpyName); 939 if (!outDpy) 940 { 941 ACTION("Exiting\n"); 942 exit(1); 943 } 944 } 945 if ((inDpy == NULL) && (outDpy == NULL)) 946 { 947 int mjr, mnr; 948 mjr = XkbMajorVersion; 949 mnr = XkbMinorVersion; 950 if (!XkbLibraryVersion(&mjr, &mnr)) 951 { 952 INFO3("%s was compiled with XKB version %d.%02d\n", 953 argv[0], XkbMajorVersion, XkbMinorVersion); 954 ERROR2("X library supports incompatible version %d.%02d\n", 955 mjr, mnr); 956 ACTION("Exiting\n"); 957 exit(1); 958 } 959 } 960 if (file) 961 { 962 ok = True; 963 setScanState(inputFile, 1); 964 if ((inputFormat == INPUT_XKB) /* parse .xkb file */ 965 && (XKBParseFile(file, &rtrn) && (rtrn != NULL))) 966 { 967 fclose(file); 968 mapToUse = rtrn; 969 if (inputMap != NULL) /* map specified on cmdline? */ 970 { 971 while ((mapToUse) 972 && (!uStringEqual(mapToUse->name, inputMap))) 973 { 974 mapToUse = (XkbFile *) mapToUse->common.next; 975 } 976 if (!mapToUse) 977 { 978 FATAL2("No map named \"%s\" in \"%s\"\n", 979 inputMap, inputFile); 980 /* NOTREACHED */ 981 } 982 } 983 else if (rtrn->common.next != NULL) 984 { 985 /* look for map with XkbLC_Default flag. */ 986 mapToUse = rtrn; 987 for (; mapToUse; mapToUse = (XkbFile *) mapToUse->common.next) 988 { 989 if (mapToUse->flags & XkbLC_Default) 990 break; 991 } 992 if (!mapToUse) 993 { 994 mapToUse = rtrn; 995 if (warningLevel > 4) 996 { 997 WARN1 998 ("No map specified, but \"%s\" has several\n", 999 inputFile); 1000 ACTION1 1001 ("Using the first defined map, \"%s\"\n", 1002 mapToUse->name); 1003 } 1004 } 1005 } 1006 bzero((char *) &result, sizeof(result)); 1007 result.type = mapToUse->type; 1008 if ((result.xkb = XkbAllocKeyboard()) == NULL) 1009 { 1010 WSGO("Cannot allocate keyboard description\n"); 1011 /* NOTREACHED */ 1012 } 1013 switch (mapToUse->type) 1014 { 1015 case XkmSemanticsFile: 1016 case XkmLayoutFile: 1017 case XkmKeymapFile: 1018 ok = CompileKeymap(mapToUse, &result, MergeReplace); 1019 break; 1020 case XkmKeyNamesIndex: 1021 ok = CompileKeycodes(mapToUse, &result, MergeReplace); 1022 break; 1023 case XkmTypesIndex: 1024 ok = CompileKeyTypes(mapToUse, &result, MergeReplace); 1025 break; 1026 case XkmSymbolsIndex: 1027 /* if it's just symbols, invent key names */ 1028 result.xkb->flags |= AutoKeyNames; 1029 ok = False; 1030 break; 1031 case XkmCompatMapIndex: 1032 ok = CompileCompatMap(mapToUse, &result, MergeReplace, NULL); 1033 break; 1034 case XkmGeometryFile: 1035 case XkmGeometryIndex: 1036 /* if it's just a geometry, invent key names */ 1037 result.xkb->flags |= AutoKeyNames; 1038 ok = CompileGeometry(mapToUse, &result, MergeReplace); 1039 break; 1040 default: 1041 WSGO1("Unknown file type %d\n", mapToUse->type); 1042 ok = False; 1043 break; 1044 } 1045 result.xkb->device_spec = device_id; 1046 } 1047 else if (inputFormat == INPUT_XKM) /* parse xkm file */ 1048 { 1049 unsigned tmp; 1050 bzero((char *) &result, sizeof(result)); 1051 if ((result.xkb = XkbAllocKeyboard()) == NULL) 1052 { 1053 WSGO("Cannot allocate keyboard description\n"); 1054 /* NOTREACHED */ 1055 } 1056 tmp = XkmReadFile(file, 0, XkmKeymapLegal, &result); 1057 if (tmp == XkmKeymapLegal) 1058 { 1059 ERROR1("Cannot read XKM file \"%s\"\n", inputFile); 1060 ok = False; 1061 } 1062 result.xkb->device_spec = device_id; 1063 } 1064 else 1065 { 1066 INFO1("Errors encountered in %s; not compiled.\n", inputFile); 1067 ok = False; 1068 } 1069 } 1070 else if (inDpy != NULL) 1071 { 1072 bzero((char *) &result, sizeof(result)); 1073 result.type = XkmKeymapFile; 1074 result.xkb = XkbGetMap(inDpy, XkbAllMapComponentsMask, device_id); 1075 if (result.xkb == NULL) 1076 WSGO("Cannot load keyboard description\n"); 1077 if (XkbGetIndicatorMap(inDpy, ~0, result.xkb) != Success) 1078 WSGO("Could not load indicator map\n"); 1079 if (XkbGetControls(inDpy, XkbAllControlsMask, result.xkb) != Success) 1080 WSGO("Could not load keyboard controls\n"); 1081 if (XkbGetCompatMap(inDpy, XkbAllCompatMask, result.xkb) != Success) 1082 WSGO("Could not load compatibility map\n"); 1083 if (XkbGetNames(inDpy, XkbAllNamesMask, result.xkb) != Success) 1084 WSGO("Could not load names\n"); 1085 if ((status = XkbGetGeometry(inDpy, result.xkb)) != Success) 1086 { 1087 if (warningLevel > 3) 1088 { 1089 char buf[100]; 1090 buf[0] = '\0'; 1091 XGetErrorText(inDpy, status, buf, 100); 1092 WARN1("Could not load keyboard geometry for %s\n", inDpyName); 1093 ACTION1("%s\n", buf); 1094 ACTION("Resulting keymap file will not describe geometry\n"); 1095 } 1096 } 1097 if (computeDflts) 1098 ok = (ComputeKbdDefaults(result.xkb) == Success); 1099 else 1100 ok = True; 1101 } 1102 else 1103 { 1104 fprintf(stderr, "Cannot open \"%s\" to compile\n", inputFile); 1105 ok = 0; 1106 } 1107 if (ok) 1108 { 1109 FILE *out = stdout; 1110 if ((inDpy != outDpy) && 1111 (XkbChangeKbdDisplay(outDpy, &result) != Success)) 1112 { 1113 WSGO2("Error converting keyboard display from %s to %s\n", 1114 inDpyName, outDpyName); 1115 exit(1); 1116 } 1117 if (outputFile != NULL) 1118 { 1119 if (uStringEqual(outputFile, "-")) 1120 outputFile = "stdout"; 1121 else 1122 { 1123 /* 1124 * fix to prevent symlink attack (e.g., 1125 * ln -s /etc/passwd /var/tmp/server-0.xkm) 1126 */ 1127 /* 1128 * this patch may have POSIX, Linux, or GNU libc bias 1129 * -- Branden Robinson 1130 */ 1131 int outputFileFd; 1132 int binMode = 0; 1133 const char *openMode = "w"; 1134 unlink(outputFile); 1135#ifdef O_BINARY 1136 switch (outputFormat) 1137 { 1138 case WANT_XKM_FILE: 1139 binMode = O_BINARY; 1140 openMode = "wb"; 1141 break; 1142 default: 1143 binMode = 0; 1144 break; 1145 } 1146#endif 1147 outputFileFd = 1148 open(outputFile, O_WRONLY | O_CREAT | O_EXCL, 1149 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH 1150 | S_IWOTH | binMode); 1151 if (outputFileFd < 0) 1152 { 1153 ERROR1 1154 ("Cannot open \"%s\" to write keyboard description\n", 1155 outputFile); 1156 ACTION("Exiting\n"); 1157 exit(1); 1158 } 1159#ifndef WIN32 1160 out = fdopen(outputFileFd, openMode); 1161#else 1162 close(outputFileFd); 1163 out = fopen(outputFile, "wb"); 1164#endif 1165 /* end BR */ 1166 if (out == NULL) 1167 { 1168 ERROR1 1169 ("Cannot open \"%s\" to write keyboard description\n", 1170 outputFile); 1171 ACTION("Exiting\n"); 1172 exit(1); 1173 } 1174 } 1175 } 1176 switch (outputFormat) 1177 { 1178 case WANT_XKM_FILE: 1179 ok = XkbWriteXKMFile(out, &result); 1180 break; 1181 case WANT_XKB_FILE: 1182 ok = XkbWriteXKBFile(out, &result, showImplicit, NULL, NULL); 1183 break; 1184 case WANT_C_HDR: 1185 ok = XkbWriteCFile(out, outputFile, &result); 1186 break; 1187 case WANT_X_SERVER: 1188 if (!(ok = XkbWriteToServer(&result))) 1189 { 1190 ERROR2("%s in %s\n", _XkbErrMessages[_XkbErrCode], 1191 _XkbErrLocation ? _XkbErrLocation : "unknown"); 1192 ACTION1("Couldn't write keyboard description to %s\n", 1193 outDpyName); 1194 } 1195 break; 1196 default: 1197 WSGO1("Unknown output format %d\n", outputFormat); 1198 ACTION("No output file created\n"); 1199 ok = False; 1200 break; 1201 } 1202 if (outputFormat != WANT_X_SERVER) 1203 { 1204 if (fclose(out)) 1205 { 1206 ERROR1("Cannot close \"%s\" properly (not enough space?)\n", 1207 outputFile); 1208 ok= False; 1209 } 1210 else if (!ok) 1211 { 1212 ERROR2("%s in %s\n", _XkbErrMessages[_XkbErrCode], 1213 _XkbErrLocation ? _XkbErrLocation : "unknown"); 1214 } 1215 if (!ok) 1216 { 1217 ACTION1("Output file \"%s\" removed\n", outputFile); 1218 unlink(outputFile); 1219 } 1220 } 1221 } 1222 if (inDpy) 1223 XCloseDisplay(inDpy); 1224 inDpy = NULL; 1225 if (outDpy) 1226 XCloseDisplay(outDpy); 1227 uFinishUp(); 1228 return (ok == 0); 1229} 1230