1 /************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
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.
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.
25 ********************************************************/
29 #include <X11/keysym.h>
31 /* for symlink attack security fix -- Branden Robinson */
33 #include <sys/types.h>
41 #define DEBUG_VAR debugFlags
45 #include "parseutils.h"
48 #include <X11/extensions/XKBgeom.h>
61 #define lowbit(x) ((x) & (-(x)))
63 /***====================================================================***/
65 #define WANT_DEFAULT 0
66 #define WANT_XKM_FILE 1
68 #define WANT_XKB_FILE 3
69 #define WANT_X_SERVER 4
70 #define WANT_LISTING 5
72 #define INPUT_UNKNOWN 0
76 unsigned int debugFlags;
78 static const char *fileTypeExt[] = {
86 static unsigned inputFormat, outputFormat;
88 static char *inputFile;
89 static char *inputMap;
90 static char *outputFile;
91 static char *inDpyName;
92 static char *outDpyName;
93 static Display *inDpy;
94 static Display *outDpy;
95 static Bool showImplicit = False;
96 static Bool synch = False;
97 static Bool computeDflts = False;
98 static Bool xkblist = False;
99 unsigned warningLevel = 5;
100 unsigned verboseLevel = 0;
101 unsigned dirsToStrip = 0;
102 unsigned optionalParts = 0;
103 static char *preErrorMsg = NULL;
104 static char *postErrorMsg = NULL;
105 static char *errorPrefix = NULL;
106 static unsigned int device_id = XkbUseCoreKbd;
108 /***====================================================================***/
110 #define M(m) fprintf(stderr,(m))
111 #define M1(m,a) fprintf(stderr,(m),(a))
114 Usage(int argc, char *argv[])
117 M1("Usage: %s [options] input-file [ output-file ]\n", argv[0]);
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");
125 M("-a Show all actions\n");
126 M("-C Create a C header file\n");
129 M("-d [flags] Report debugging information\n");
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");
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");
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");
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");
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");
164 M("-R[<DIR>] Specifies the root directory for\n");
165 M(" relative path names\n");
166 M("-synch Force synchronization\n");
169 M("-v [<flags>] Set level of detail for listing.\n");
170 M(" flags are as for the -l option\n");
172 M("-w [<lvl>] Set warning level (0=none, 10=all)\n");
175 M("-xkb Create an XKB source (.xkb) file\n");
176 M("-xkm Create a compiled key map (.xkm) file\n");
181 /***====================================================================***/
184 setVerboseFlags(char *str)
191 verboseLevel |= WantFullNames;
194 verboseLevel |= WantHiddenMaps;
197 verboseLevel |= WantLongListing;
200 verboseLevel |= WantPartialMaps;
203 verboseLevel |= ListRecursive;
206 if (warningLevel > 4)
208 WARN1("Unknown verbose option \"%c\"\n", (unsigned int) *str);
218 parseArgs(int argc, char *argv[])
223 tmp = strlen("xkblist");
224 if ((i >= tmp) && (strcmp(&argv[0][i - tmp], "xkblist") == 0))
228 for (i = 1; i < argc; i++)
231 if ((argv[i][0] != '-') || (uStringEqual(argv[i], "-")))
235 if (inputFile == NULL)
237 else if (outputFile == NULL)
238 outputFile = argv[i];
239 else if (warningLevel > 0)
241 WARN("Too many file names on command line\n");
243 ("Compiling %s, writing to %s, ignoring %s\n",
244 inputFile, outputFile, argv[i]);
247 else if (!AddMatchingFiles(argv[i]))
250 else if ((strcmp(argv[i], "-?") == 0)
251 || (strcmp(argv[i], "-help") == 0))
256 else if (strcmp(argv[i], "-version") == 0)
258 printf("xkbcomp %s\n", PACKAGE_VERSION);
260 } else if ((strcmp(argv[i], "-a") == 0) && (!xkblist))
264 else if ((strcmp(argv[i], "-C") == 0) && (!xkblist))
266 if ((outputFormat != WANT_DEFAULT)
267 && (outputFormat != WANT_C_HDR))
269 if (warningLevel > 0)
271 WARN("Multiple output file formats specified\n");
272 ACTION1("\"%s\" flag ignored\n", argv[i]);
276 outputFormat = WANT_C_HDR;
279 else if (strcmp(argv[i], "-d") == 0)
281 if ((i >= (argc - 1)) || (!isdigit(argv[i + 1][0])))
287 if (sscanf(argv[++i], "%i", &itmp) == 1)
290 INFO1("Setting debug flags to %d\n", debugFlags);
293 else if ((strcmp(argv[i], "-dflts") == 0) && (!xkblist))
297 else if (strcmp(argv[i], "-em1") == 0)
301 if (warningLevel > 0)
303 WARN("No pre-error message specified\n");
304 ACTION("Trailing \"-em1\" option ignored\n");
307 else if (preErrorMsg != NULL)
309 if (warningLevel > 0)
311 WARN("Multiple pre-error messsages specified\n");
312 ACTION2("Compiling %s, ignoring %s\n",
313 preErrorMsg, argv[i]);
317 preErrorMsg = argv[i];
319 else if (strcmp(argv[i], "-emp") == 0)
323 if (warningLevel > 0)
325 WARN("No error prefix specified\n");
326 ACTION("Trailing \"-emp\" option ignored\n");
329 else if (errorPrefix != NULL)
331 if (warningLevel > 0)
333 WARN("Multiple error prefixes specified\n");
334 ACTION2("Compiling %s, ignoring %s\n",
335 errorPrefix, argv[i]);
339 errorPrefix = argv[i];
341 else if (strcmp(argv[i], "-eml") == 0)
345 if (warningLevel > 0)
347 WARN("No post-error message specified\n");
348 ACTION("Trailing \"-eml\" option ignored\n");
351 else if (postErrorMsg != NULL)
353 if (warningLevel > 0)
355 WARN("Multiple post-error messages specified\n");
356 ACTION2("Compiling %s, ignoring %s\n",
357 postErrorMsg, argv[i]);
361 postErrorMsg = argv[i];
363 else if ((strncmp(argv[i], "-I", 2) == 0) && (!xkblist))
365 if (!XkbAddDirectoryToPath(&argv[i][2]))
371 else if ((strncmp(argv[i], "-i", 2) == 0) && (!xkblist))
375 if (warningLevel > 0)
376 WARN("No device ID specified\n");
378 device_id = atoi(argv[i]);
380 else if ((strncmp(argv[i], "-l", 2) == 0) && (!xkblist))
382 if (outputFormat != WANT_DEFAULT)
384 if (warningLevel > 0)
386 WARN("Multiple output file formats specified\n");
387 ACTION1("\"%s\" flag ignored\n", argv[i]);
392 if (argv[i][2] != '\0')
393 setVerboseFlags(&argv[i][2]);
395 if ((inputFile) && (!AddMatchingFiles(inputFile)))
399 if ((outputFile) && (!AddMatchingFiles(outputFile)))
405 else if ((strcmp(argv[i], "-m") == 0)
406 || (strcmp(argv[i], "-map") == 0))
410 if (warningLevel > 0)
412 WARN("No map name specified\n");
413 ACTION1("Trailing \"%s\" option ignored\n", argv[i - 1]);
418 if (!AddMapOnly(argv[i]))
421 else if (inputMap != NULL)
423 if (warningLevel > 0)
425 WARN("Multiple map names specified\n");
426 ACTION2("Compiling %s, ignoring %s\n", inputMap, argv[i]);
432 else if ((strcmp(argv[i], "-merge") == 0) && (!xkblist))
436 else if (strcmp(argv[i], "-o") == 0)
440 if (warningLevel > 0)
442 WARN("No output file specified\n");
443 ACTION("Trailing \"-o\" option ignored\n");
446 else if (outputFile != NULL)
448 if (warningLevel > 0)
450 WARN("Multiple output files specified\n");
451 ACTION2("Compiling %s, ignoring %s\n", outputFile,
456 outputFile = argv[i];
458 else if (((strcmp(argv[i], "-opt") == 0)
459 || (strcmp(argv[i], "optional") == 0)) && (!xkblist))
463 if (warningLevel > 0)
465 WARN("No optional components specified\n");
466 ACTION1("Trailing \"%s\" option ignored\n", argv[i - 1]);
472 for (tmp2 = argv[i]; (*tmp2 != '\0'); tmp2++)
478 optionalParts |= XkmCompatMapMask;
482 optionalParts |= XkmGeometryMask;
486 optionalParts |= XkmKeyNamesMask;
490 optionalParts |= XkmSymbolsMask;
494 optionalParts |= XkmTypesMask;
497 if (warningLevel > 0)
500 ("Illegal component for %s option\n",
503 ("Ignoring unknown specifier \"%c\"\n",
504 (unsigned int) *tmp2);
511 else if (strncmp(argv[i], "-p", 2) == 0)
513 if (isdigit(argv[i][2]))
515 if (sscanf(&argv[i][2], "%i", &itmp) == 1)
518 else if ((i < (argc - 1)) && (isdigit(argv[i + 1][0])))
520 if (sscanf(argv[++i], "%i", &itmp) == 1)
527 if (warningLevel > 5)
528 INFO1("Setting path count to %d\n", dirsToStrip);
530 else if (strncmp(argv[i], "-R", 2) == 0)
532 if (argv[i][2] == '\0')
534 if (warningLevel > 0)
536 WARN("No root directory specified\n");
537 ACTION("Ignoring -R option\n");
540 else if (rootDir != NULL)
542 if (warningLevel > 0)
544 WARN("Multiple root directories specified\n");
545 ACTION2("Using %s, ignoring %s\n", rootDir, argv[i]);
550 rootDir = &argv[i][2];
551 if (warningLevel > 8)
553 WARN1("Changing root directory to \"%s\"\n", rootDir);
555 if ((chdir(rootDir) < 0) && (warningLevel > 0))
557 WARN1("Couldn't change directory to \"%s\"\n", rootDir);
558 ACTION("Root directory (-R) option ignored\n");
563 else if ((strcmp(argv[i], "-synch") == 0)
564 || (strcmp(argv[i], "-s") == 0))
568 else if (strncmp(argv[i], "-v", 2) == 0)
571 if (argv[i][2] != '\0')
573 else if ((i < (argc - 1)) && (argv[i + 1][0] != '-'))
578 setVerboseFlags(str);
580 else if (strncmp(argv[i], "-w", 2) == 0)
582 if ((i >= (argc - 1)) || (!isdigit(argv[i + 1][0])))
585 if (isdigit(argv[i][1]))
586 if (sscanf(&argv[i][1], "%i", &itmp) == 1)
591 if (sscanf(argv[++i], "%i", &itmp) == 1)
595 else if ((strcmp(argv[i], "-xkb") == 0) && (!xkblist))
597 if ((outputFormat != WANT_DEFAULT)
598 && (outputFormat != WANT_XKB_FILE))
600 if (warningLevel > 0)
602 WARN("Multiple output file formats specified\n");
603 ACTION1("\"%s\" flag ignored\n", argv[i]);
607 outputFormat = WANT_XKB_FILE;
609 else if ((strcmp(argv[i], "-xkm") == 0) && (!xkblist))
611 if ((outputFormat != WANT_DEFAULT)
612 && (outputFormat != WANT_XKM_FILE))
614 if (warningLevel > 0)
616 WARN("Multiple output file formats specified\n");
617 ACTION1("\"%s\" flag ignored\n", argv[i]);
621 outputFormat = WANT_XKM_FILE;
625 ERROR1("Unknown flag \"%s\" on command line\n", argv[i]);
631 inputFormat = INPUT_XKB;
632 else if (inputFile == NULL)
634 ERROR("No input file specified\n");
637 else if (uStringEqual(inputFile, "-"))
639 inputFormat = INPUT_XKB;
642 else if (strchr(inputFile, ':') == NULL)
645 else if ((strchr(inputFile, ':') == NULL) || (strlen(inputFile) > 2 &&
646 isalpha(inputFile[0]) &&
648 && strchr(inputFile + 2,
653 len = strlen(inputFile);
654 if (inputFile[len - 1] == ')')
657 if ((tmpstr = strchr(inputFile, '(')) != NULL)
660 inputFile[len - 1] = '\0';
664 WARN("Empty map in filename\n");
667 else if (inputMap == NULL)
669 inputMap = uStringDup(tmpstr);
673 WARN("Map specified in filename and with -m flag\n");
674 ACTION1("map from name (\"%s\") ignored\n", tmpstr);
679 ERROR1("Illegal name \"%s\" for input file\n", inputFile);
683 if ((len > 4) && (strcmp(&inputFile[len - 4], ".xkm") == 0))
685 inputFormat = INPUT_XKM;
690 file = fopen(inputFile, "r");
694 inputFormat = INPUT_XKM;
696 inputFormat = INPUT_XKB;
701 fprintf(stderr, "Cannot open \"%s\" for reading\n",
709 inDpyName = inputFile;
711 inputFormat = INPUT_XKM;
714 if (outputFormat == WANT_DEFAULT)
717 outputFormat = WANT_LISTING;
718 else if (inputFormat == INPUT_XKB)
719 outputFormat = WANT_XKM_FILE;
721 outputFormat = WANT_XKB_FILE;
723 if ((outputFormat == WANT_LISTING) && (inputFormat != INPUT_XKB))
726 ERROR("Cannot generate a listing from a .xkm file (yet)\n");
728 ERROR("Cannot generate a listing from an X connection (yet)\n");
733 if (outputFile == NULL)
734 outputFile = uStringDup("-");
735 else if (strchr(outputFile, ':') != NULL)
737 ERROR("Cannot write a listing to an X connection\n");
741 else if ((!outputFile) && (inputFile) && uStringEqual(inputFile, "-"))
743 int len = strlen("stdin") + strlen(fileTypeExt[outputFormat]) + 2;
744 outputFile = uTypedCalloc(len, char);
745 if (outputFile == NULL)
747 WSGO("Cannot allocate space for output file name\n");
751 sprintf(outputFile, "stdin.%s", fileTypeExt[outputFormat]);
753 else if ((outputFile == NULL) && (inputFile != NULL))
758 if (inputMap == NULL)
760 base = strrchr(inputFile, '/');
769 len = strlen(base) + strlen(fileTypeExt[outputFormat]) + 2;
770 outputFile = uTypedCalloc(len, char);
771 if (outputFile == NULL)
773 WSGO("Cannot allocate space for output file name\n");
777 ext = strrchr(base, '.');
779 sprintf(outputFile, "%s.%s", base, fileTypeExt[outputFormat]);
782 strcpy(outputFile, base);
783 strcpy(&outputFile[ext - base + 1], fileTypeExt[outputFormat]);
786 else if (outputFile == NULL)
789 char *ch, *name, buf[128];
790 if (inDpyName[0] == ':')
791 snprintf(name = buf, sizeof(buf), "server%s", inDpyName);
795 len = strlen(name) + strlen(fileTypeExt[outputFormat]) + 2;
796 outputFile = uTypedCalloc(len, char);
797 if (outputFile == NULL)
799 WSGO("Cannot allocate space for output file name\n");
803 strcpy(outputFile, name);
804 for (ch = outputFile; (*ch) != '\0'; ch++)
812 strcpy(ch, fileTypeExt[outputFormat]);
815 else if (strlen(outputFile) > 2 &&
816 isalpha(outputFile[0]) &&
817 outputFile[1] == ':' && strchr(outputFile + 2, ':') == NULL)
821 else if (strchr(outputFile, ':') != NULL)
823 outDpyName = outputFile;
825 outputFormat = WANT_X_SERVER;
831 GetDisplay(char *program, char *dpyName)
836 mjr = XkbMajorVersion;
837 mnr = XkbMinorVersion;
838 dpy = XkbOpenDisplay(dpyName, NULL, NULL, &mjr, &mnr, &error);
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",
849 case XkbOD_ConnectionRefused:
850 ERROR1("Cannot open display \"%s\"\n", dpyName);
852 case XkbOD_NonXkbServer:
853 ERROR1("XKB extension not present on %s\n", dpyName);
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",
862 WSGO1("Unknown error %d from XkbOpenDisplay\n", error);
866 XSynchronize(dpy, True);
870 /***====================================================================***/
877 main(int argc, char *argv[])
879 FILE *file; /* input file (or stdin) */
887 uSetEntryFile(NullString);
888 uSetDebugFile(NullString);
889 uSetErrorFile(NullString);
891 XkbInitIncludePath();
892 if (!parseArgs(argc, argv))
895 if (debugFlags & 0x2)
899 uSetPreErrorMessage(preErrorMsg);
901 uSetErrorPrefix(errorPrefix);
903 uSetPostErrorMessage(postErrorMsg);
906 XkbAddDefaultDirectoriesToPath();
910 gotSome = GenerateListing(outputFile);
911 if ((warningLevel > 7) && (!gotSome))
915 if (inputFile != NULL)
917 if (uStringEqual(inputFile, "-"))
924 file = fopen(inputFile, "r");
927 else if (inDpyName != NULL)
929 inDpy = GetDisplay(argv[0], inDpyName);
936 if (outDpyName != NULL)
938 outDpy = GetDisplay(argv[0], outDpyName);
945 if ((inDpy == NULL) && (outDpy == NULL))
948 mjr = XkbMajorVersion;
949 mnr = XkbMinorVersion;
950 if (!XkbLibraryVersion(&mjr, &mnr))
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",
963 setScanState(inputFile, 1);
964 if ((inputFormat == INPUT_XKB) /* parse .xkb file */
965 && (XKBParseFile(file, &rtrn) && (rtrn != NULL)))
969 if (inputMap != NULL) /* map specified on cmdline? */
972 && (!uStringEqual(mapToUse->name, inputMap)))
974 mapToUse = (XkbFile *) mapToUse->common.next;
978 FATAL2("No map named \"%s\" in \"%s\"\n",
979 inputMap, inputFile);
983 else if (rtrn->common.next != NULL)
985 /* look for map with XkbLC_Default flag. */
987 for (; mapToUse; mapToUse = (XkbFile *) mapToUse->common.next)
989 if (mapToUse->flags & XkbLC_Default)
995 if (warningLevel > 4)
998 ("No map specified, but \"%s\" has several\n",
1001 ("Using the first defined map, \"%s\"\n",
1006 bzero((char *) &result, sizeof(result));
1007 result.type = mapToUse->type;
1008 if ((result.xkb = XkbAllocKeyboard()) == NULL)
1010 WSGO("Cannot allocate keyboard description\n");
1013 switch (mapToUse->type)
1015 case XkmSemanticsFile:
1018 ok = CompileKeymap(mapToUse, &result, MergeReplace);
1020 case XkmKeyNamesIndex:
1021 ok = CompileKeycodes(mapToUse, &result, MergeReplace);
1024 ok = CompileKeyTypes(mapToUse, &result, MergeReplace);
1026 case XkmSymbolsIndex:
1027 /* if it's just symbols, invent key names */
1028 result.xkb->flags |= AutoKeyNames;
1031 case XkmCompatMapIndex:
1032 ok = CompileCompatMap(mapToUse, &result, MergeReplace, NULL);
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);
1041 WSGO1("Unknown file type %d\n", mapToUse->type);
1045 result.xkb->device_spec = device_id;
1047 else if (inputFormat == INPUT_XKM) /* parse xkm file */
1050 bzero((char *) &result, sizeof(result));
1051 if ((result.xkb = XkbAllocKeyboard()) == NULL)
1053 WSGO("Cannot allocate keyboard description\n");
1056 tmp = XkmReadFile(file, 0, XkmKeymapLegal, &result);
1057 if (tmp == XkmKeymapLegal)
1059 ERROR1("Cannot read XKM file \"%s\"\n", inputFile);
1062 result.xkb->device_spec = device_id;
1066 INFO1("Errors encountered in %s; not compiled.\n", inputFile);
1070 else if (inDpy != NULL)
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)
1087 if (warningLevel > 3)
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");
1098 ok = (ComputeKbdDefaults(result.xkb) == Success);
1104 fprintf(stderr, "Cannot open \"%s\" to compile\n", inputFile);
1110 if ((inDpy != outDpy) &&
1111 (XkbChangeKbdDisplay(outDpy, &result) != Success))
1113 WSGO2("Error converting keyboard display from %s to %s\n",
1114 inDpyName, outDpyName);
1117 if (outputFile != NULL)
1119 if (uStringEqual(outputFile, "-"))
1120 outputFile = "stdout";
1124 * fix to prevent symlink attack (e.g.,
1125 * ln -s /etc/passwd /var/tmp/server-0.xkm)
1128 * this patch may have POSIX, Linux, or GNU libc bias
1129 * -- Branden Robinson
1133 const char *openMode = "w";
1136 switch (outputFormat)
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)
1154 ("Cannot open \"%s\" to write keyboard description\n",
1156 ACTION("Exiting\n");
1160 out = fdopen(outputFileFd, openMode);
1162 close(outputFileFd);
1163 out = fopen(outputFile, "wb");
1169 ("Cannot open \"%s\" to write keyboard description\n",
1171 ACTION("Exiting\n");
1176 switch (outputFormat)
1179 ok = XkbWriteXKMFile(out, &result);
1182 ok = XkbWriteXKBFile(out, &result, showImplicit, NULL, NULL);
1185 ok = XkbWriteCFile(out, outputFile, &result);
1188 if (!(ok = XkbWriteToServer(&result)))
1190 ERROR2("%s in %s\n", _XkbErrMessages[_XkbErrCode],
1191 _XkbErrLocation ? _XkbErrLocation : "unknown");
1192 ACTION1("Couldn't write keyboard description to %s\n",
1197 WSGO1("Unknown output format %d\n", outputFormat);
1198 ACTION("No output file created\n");
1202 if (outputFormat != WANT_X_SERVER)
1206 ERROR1("Cannot close \"%s\" properly (not enough space?)\n",
1212 ERROR2("%s in %s\n", _XkbErrMessages[_XkbErrCode],
1213 _XkbErrLocation ? _XkbErrLocation : "unknown");
1217 ACTION1("Output file \"%s\" removed\n", outputFile);
1223 XCloseDisplay(inDpy);
1226 XCloseDisplay(outDpy);