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