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