diff options
Diffstat (limited to 'xkbcomp/xkbcomp.c')
-rw-r--r-- | xkbcomp/xkbcomp.c | 986 |
1 files changed, 986 insertions, 0 deletions
diff --git a/xkbcomp/xkbcomp.c b/xkbcomp/xkbcomp.c new file mode 100644 index 000000000..111a7b371 --- /dev/null +++ b/xkbcomp/xkbcomp.c @@ -0,0 +1,986 @@ +/* $Xorg: xkbcomp.c,v 1.4 2000/08/17 19:54:33 cpqbld Exp $ */ +/************************************************************ + Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. + + Permission to use, copy, modify, and distribute this + software and its documentation for any purpose and without + fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright + notice and this permission notice appear in supporting + documentation, and that the name of Silicon Graphics not be + used in advertising or publicity pertaining to distribution + of the software without specific prior written permission. + Silicon Graphics makes no representation about the suitability + of this software for any purpose. It is provided "as is" + without any express or implied warranty. + + SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL + DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH + THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ********************************************************/ +/* $XFree86: xc/programs/xkbcomp/xkbcomp.c,v 3.20 2003/09/24 02:43:38 dawes Exp $ */ + +#include <stdio.h> +#include <ctype.h> +#include <X11/keysym.h> + +/* for symlink attack security fix -- Branden Robinson */ +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +/* end BR */ + +#if defined(sgi) +#include <malloc.h> +#endif + +#define DEBUG_VAR_NOT_LOCAL +#define DEBUG_VAR debugFlags +#include "xkbcomp.h" +#include <stdlib.h> +#include "xkbpath.h" +#include "parseutils.h" +#include "misc.h" +#include "tokens.h" +#include <X11/extensions/XKBgeom.h> + +#ifdef __UNIXOS2__ +#define chdir _chdir2 +#endif + +#ifdef WIN32 +#define S_IRGRP 0 +#define S_IWGRP 0 +#define S_IROTH 0 +#define S_IWOTH 0 +#endif + +#define lowbit(x) ((x) & (-(x))) + +/***====================================================================***/ + +#define WANT_DEFAULT 0 +#define WANT_XKM_FILE 1 +#define WANT_C_HDR 2 +#define WANT_XKB_FILE 3 +#define WANT_X_SERVER 4 +#define WANT_LISTING 5 + +#define INPUT_UNKNOWN 0 +#define INPUT_XKB 1 +#define INPUT_XKM 2 + +static const char *fileTypeExt[] = { + "XXX", + "xkm", + "h", + "xkb", + "dir" +}; + +static unsigned inputFormat,outputFormat; + char * rootDir; +static char * inputFile; +static char * inputMap; +static char * outputFile; +static char * inDpyName; +static char * outDpyName; +static Display * inDpy; +static Display * outDpy; +static Bool showImplicit= False; +static Bool synch= False; +static Bool computeDflts= False; +static Bool xkblist= False; + unsigned warningLevel= 5; + unsigned verboseLevel= 0; + unsigned dirsToStrip= 0; + unsigned optionalParts= 0; +static char * preErrorMsg= NULL; +static char * postErrorMsg= NULL; +static char * errorPrefix= NULL; +static unsigned int device_id = XkbUseCoreKbd; + +/***====================================================================***/ + +#define M(m) fprintf(stderr,(m)) +#define M1(m,a) fprintf(stderr,(m),(a)) + +static void +Usage(int argc,char *argv[]) +{ + if (!xkblist) + M1("Usage: %s [options] input-file [ output-file ]\n",argv[0]); + else M1("Usage: %s [options] file[(map)] ...\n",argv[0]); + M("Legal options:\n"); + M("-?,-help Print this message\n"); + if (!xkblist) { + M("-a Show all actions\n"); + M("-C Create a C header file\n"); + } +#ifdef DEBUG + M("-d [flags] Report debugging information\n"); +#endif + M("-em1 <msg> Print <msg> before printing first error message\n"); + M("-emp <msg> Print <msg> at the start of each message line\n"); + M("-eml <msg> If there were any errors, print <msg> before exiting\n"); + if (!xkblist) { + M("-dflts Compute defaults for missing parts\n"); + M("-I[<dir>] Specifies a top level directory for include\n"); + M(" directives. Multiple directories are legal.\n"); + M("-l [flags] List matching maps in the specified files\n"); + M(" f: list fully specified names\n"); + M(" h: also list hidden maps\n"); + M(" l: long listing (show flags)\n"); + M(" p: also list partial maps\n"); + M(" R: recursively list subdirectories\n"); + M(" default is all options off\n"); + } + M("-i <deviceid> Specifies device ID (not name) to compile for\n"); + M("-m[ap] <map> Specifies map to compile\n"); + M("-o <file> Specifies output file name\n"); + if (!xkblist) { + M("-opt[ional] <parts> Specifies optional components of keymap\n"); + M(" Errors in optional parts are not fatal\n"); + M(" <parts> can be any combination of:\n"); + M(" c: compat map g: geometry\n"); + M(" k: keycodes s: symbols\n"); + M(" t: types\n"); + } + if (xkblist) { + M("-p <count> Specifies the number of slashes to be stripped\n"); + M(" from the front of the map name on output\n"); + } + M("-R[<DIR>] Specifies the root directory for\n"); + M(" relative path names\n"); + M("-synch Force synchronization\n"); + if (xkblist) { + M("-v [<flags>] Set level of detail for listing.\n"); + M(" flags are as for the -l option\n"); + } + M("-w [<lvl>] Set warning level (0=none, 10=all)\n"); + if (!xkblist) { + M("-xkb Create an XKB source (.xkb) file\n"); + M("-xkm Create a compiled key map (.xkm) file\n"); + } + return; +} + +/***====================================================================***/ + +static void +setVerboseFlags(char *str) +{ + for (;*str;str++) { + switch (*str) { + case 'f': verboseLevel|= WantFullNames; break; + case 'h': verboseLevel|= WantHiddenMaps; break; + case 'l': verboseLevel|= WantLongListing; break; + case 'p': verboseLevel|= WantPartialMaps; break; + case 'R': verboseLevel|= ListRecursive; break; + default: + if (warningLevel>4) { + WARN1("Unknown verbose option \"%c\"\n",(unsigned int)*str); + ACTION("Ignored\n"); + } + break; + } + } + return; +} + +static Bool +parseArgs(int argc,char *argv[]) +{ +register int i,tmp; + + i= strlen(argv[0]); + tmp= strlen("xkblist"); + if ((i>=tmp)&&(strcmp(&argv[0][i-tmp],"xkblist")==0)) { + xkblist= True; + } + for (i=1;i<argc;i++) { + int itmp; + if ((argv[i][0]!='-')||(uStringEqual(argv[i],"-"))) { + if (!xkblist) { + if (inputFile==NULL) + inputFile= argv[i]; + else if (outputFile==NULL) + outputFile= argv[i]; + else if (warningLevel>0) { + WARN("Too many file names on command line\n"); + ACTION3("Compiling %s, writing to %s, ignoring %s\n", + inputFile,outputFile,argv[i]); + } + } + else if (!AddMatchingFiles(argv[i])) + return False; + } + else if ((strcmp(argv[i],"-?")==0)||(strcmp(argv[i],"-help")==0)) { + Usage(argc,argv); + exit(0); + } + else if ((strcmp(argv[i],"-a")==0)&&(!xkblist)) { + showImplicit= True; + } + else if ((strcmp(argv[i],"-C")==0)&&(!xkblist)) { + if ((outputFormat!=WANT_DEFAULT)&&(outputFormat!=WANT_C_HDR)) { + if (warningLevel>0) { + WARN("Multiple output file formats specified\n"); + ACTION1("\"%s\" flag ignored\n",argv[i]); + } + } + else outputFormat= WANT_C_HDR; + } +#ifdef DEBUG + else if (strcmp(argv[i],"-d")==0) { + if ((i>=(argc-1))||(!isdigit(argv[i+1][0]))) { + debugFlags= 1; + } + else { + if (sscanf(argv[++i],"%i",&itmp) == 1) + debugFlags = itmp; + } + INFO1("Setting debug flags to %d\n",debugFlags); + } +#endif + else if ((strcmp(argv[i],"-dflts")==0)&&(!xkblist)) { + computeDflts= True; + } + else if (strcmp(argv[i],"-em1")==0) { + if (++i>=argc) { + if (warningLevel>0) { + WARN("No pre-error message specified\n"); + ACTION("Trailing \"-em1\" option ignored\n"); + } + } + else if (preErrorMsg!=NULL) { + if (warningLevel>0) { + WARN("Multiple pre-error messsages specified\n"); + ACTION2("Compiling %s, ignoring %s\n",preErrorMsg,argv[i]); + } + } + else preErrorMsg= argv[i]; + } + else if (strcmp(argv[i],"-emp")==0) { + if (++i>=argc) { + if (warningLevel>0) { + WARN("No error prefix specified\n"); + ACTION("Trailing \"-emp\" option ignored\n"); + } + } + else if (errorPrefix!=NULL) { + if (warningLevel>0) { + WARN("Multiple error prefixes specified\n"); + ACTION2("Compiling %s, ignoring %s\n",errorPrefix,argv[i]); + } + } + else errorPrefix= argv[i]; + } + else if (strcmp(argv[i],"-eml")==0) { + if (++i>=argc) { + if (warningLevel>0) { + WARN("No post-error message specified\n"); + ACTION("Trailing \"-eml\" option ignored\n"); + } + } + else if (postErrorMsg!=NULL) { + if (warningLevel>0) { + WARN("Multiple post-error messages specified\n"); + ACTION2("Compiling %s, ignoring %s\n",postErrorMsg,argv[i]); + } + } + else postErrorMsg= argv[i]; + } + else if ((strncmp(argv[i],"-I",2)==0)&&(!xkblist)) { + if (!XkbAddDirectoryToPath(&argv[i][2])) { + ACTION("Exiting\n"); + exit(1); + } + } + else if ((strncmp(argv[i], "-i", 2) == 0) && (!xkblist)) { + if (++i >= argc) { + if (warningLevel > 0) + WARN("No device ID specified\n"); + } + device_id = atoi(argv[i]); + } + else if ((strncmp(argv[i],"-l",2)==0)&&(!xkblist)) { + if (outputFormat!=WANT_DEFAULT) { + if (warningLevel>0) { + WARN("Multiple output file formats specified\n"); + ACTION1("\"%s\" flag ignored\n",argv[i]); + } + } + else { + if (argv[i][2]!='\0') + setVerboseFlags(&argv[i][2]); + xkblist= True; + if ((inputFile)&&(!AddMatchingFiles(inputFile))) + return False; + else inputFile= NULL; + if ((outputFile)&&(!AddMatchingFiles(outputFile))) + return False; + else outputFile= NULL; + } + } + else if ((strcmp(argv[i],"-m")==0)||(strcmp(argv[i],"-map")==0)) { + if (++i>=argc) { + if (warningLevel>0) { + WARN("No map name specified\n"); + ACTION1("Trailing \"%s\" option ignored\n",argv[i-1]); + } + } + else if (xkblist) { + if (!AddMapOnly(argv[i])) + return False; + } + else if (inputMap!=NULL) { + if (warningLevel>0) { + WARN("Multiple map names specified\n"); + ACTION2("Compiling %s, ignoring %s\n",inputMap,argv[i]); + } + } + else inputMap= argv[i]; + } + else if ((strcmp(argv[i],"-merge")==0)&&(!xkblist)) { + /* Ignored */ + } + else if (strcmp(argv[i],"-o")==0) { + if (++i>=argc) { + if (warningLevel>0) { + WARN("No output file specified\n"); + ACTION("Trailing \"-o\" option ignored\n"); + } + } + else if (outputFile!=NULL) { + if (warningLevel>0) { + WARN("Multiple output files specified\n"); + ACTION2("Compiling %s, ignoring %s\n",outputFile,argv[i]); + } + } + else outputFile= argv[i]; + } + else if (((strcmp(argv[i],"-opt")==0)||(strcmp(argv[i],"optional")==0)) + &&(!xkblist)) { + if (++i>=argc) { + if (warningLevel>0) { + WARN("No optional components specified\n"); + ACTION1("Trailing \"%s\" option ignored\n",argv[i-1]); + } + } + else { + char *tmp2; + for (tmp2=argv[i];(*tmp2!='\0');tmp2++) { + switch (*tmp2) { + case 'c': case 'C': + optionalParts|= XkmCompatMapMask; + break; + case 'g': case 'G': + optionalParts|= XkmGeometryMask; + break; + case 'k': case 'K': + optionalParts|= XkmKeyNamesMask; + break; + case 's': case 'S': + optionalParts|= XkmSymbolsMask; + break; + case 't': case 'T': + optionalParts|= XkmTypesMask; + break; + default: + if (warningLevel>0) { + WARN1("Illegal component for %s option\n", + argv[i-1]); + ACTION1("Ignoring unknown specifier \"%c\"\n", + (unsigned int)*tmp2); + } + break; + } + } + } + } + else if (strncmp(argv[i],"-p",2)==0) { + if (isdigit(argv[i][2])) { + if (sscanf(&argv[i][2],"%i",&itmp) == 1) + dirsToStrip = itmp; + } + else if ((i<(argc-1))&&(isdigit(argv[i+1][0]))) { + if (sscanf(argv[++i],"%i",&itmp) == 1) + dirsToStrip = itmp; + } + else { + dirsToStrip= 0; + } + if (warningLevel>5) + INFO1("Setting path count to %d\n",dirsToStrip); + } + else if (strncmp(argv[i],"-R",2)==0) { + if (argv[i][2]=='\0') { + if (warningLevel>0) { + WARN("No root directory specified\n"); + ACTION("Ignoring -R option\n"); + } + } + else if (rootDir!=NULL) { + if (warningLevel>0) { + WARN("Multiple root directories specified\n"); + ACTION2("Using %s, ignoring %s\n",rootDir,argv[i]); + } + } + else { + rootDir= &argv[i][2]; + if (warningLevel>8) { + WARN1("Changing root directory to \"%s\"\n",rootDir); + } + if ((chdir(rootDir)<0) && (warningLevel>0)) { + WARN1("Couldn't change directory to \"%s\"\n",rootDir); + ACTION("Root directory (-R) option ignored\n"); + rootDir= NULL; + } + } + } + else if ((strcmp(argv[i],"-synch")==0)||(strcmp(argv[i],"-s")==0)) { + synch= True; + } + else if (strncmp(argv[i],"-v",2)==0) { + char *str; + if (argv[i][2]!='\0') + str= &argv[i][2]; + else if ((i<(argc-1))&&(argv[i+1][0]!='-')) + str= argv[++i]; + else str= NULL; + if (str) + setVerboseFlags(str); + } + else if (strncmp(argv[i],"-w",2)==0) { + if ((i>=(argc-1))||(!isdigit(argv[i+1][0]))) { + warningLevel = 0; + if (isdigit(argv[i][1])) + if (sscanf(&argv[i][1],"%i",&itmp) == 1) + warningLevel = itmp; + } + else { + if (sscanf(argv[++i],"%i",&itmp) == 1) + warningLevel = itmp; + } + } + else if ((strcmp(argv[i],"-xkb")==0)&&(!xkblist)) { + if ((outputFormat!=WANT_DEFAULT)&&(outputFormat!=WANT_XKB_FILE)) { + if (warningLevel>0) { + WARN("Multiple output file formats specified\n"); + ACTION1("\"%s\" flag ignored\n",argv[i]); + } + } + else outputFormat= WANT_XKB_FILE; + } + else if ((strcmp(argv[i],"-xkm")==0)&&(!xkblist)) { + if ((outputFormat!=WANT_DEFAULT)&&(outputFormat!=WANT_XKM_FILE)) { + if (warningLevel>0) { + WARN("Multiple output file formats specified\n"); + ACTION1("\"%s\" flag ignored\n",argv[i]); + } + } + else outputFormat= WANT_XKM_FILE; + } + else { + ERROR1("Unknown flag \"%s\" on command line\n",argv[i]); + Usage(argc,argv); + return False; + } + } + if (xkblist) + inputFormat= INPUT_XKB; + else if (inputFile==NULL) { + ERROR("No input file specified\n"); + return False; + } + else if (uStringEqual(inputFile,"-")) { + inputFormat= INPUT_XKB; + } +#ifndef WIN32 + else if (strchr(inputFile,':')==0) { +#else + else if ((strchr(inputFile,':')==0) || ( + strlen(inputFile) > 2 && + isalpha(inputFile[0]) && + inputFile[1] == ':' && strchr(inputFile + 2,':')==NULL)) { +#endif + int len; + len= strlen(inputFile); + if (inputFile[len-1]==')') { + char *tmp; + if ((tmp=strchr(inputFile,'('))!=0) { + *tmp= '\0'; inputFile[len-1]= '\0'; + tmp++; + if (*tmp=='\0') { + WARN("Empty map in filename\n"); + ACTION("Ignored\n"); + } + else if (inputMap==NULL) { + inputMap= uStringDup(tmp); + } + else { + WARN("Map specified in filename and with -m flag\n"); + ACTION1("map from name (\"%s\") ignored\n",tmp); + } + } + else { + ERROR1("Illegal name \"%s\" for input file\n",inputFile); + return False; + } + } + if ((len>4)&&(strcmp(&inputFile[len-4],".xkm")==0)) { + inputFormat= INPUT_XKM; + } + else { + FILE *file; + file= fopen(inputFile,"r"); + if (file) { + if (XkmProbe(file)) inputFormat= INPUT_XKM; + else inputFormat= INPUT_XKB; + fclose(file); + } + else { + fprintf(stderr,"Cannot open \"%s\" for reading\n",inputFile); + return False; + } + } + } + else { + inDpyName= inputFile; + inputFile= NULL; + inputFormat= INPUT_XKM; + } + + if (outputFormat==WANT_DEFAULT) { + if (xkblist) outputFormat= WANT_LISTING; + else if (inputFormat==INPUT_XKB) outputFormat= WANT_XKM_FILE; + else outputFormat= WANT_XKB_FILE; + } + if ((outputFormat==WANT_LISTING)&&(inputFormat!=INPUT_XKB)) { + if (inputFile) + ERROR("Cannot generate a listing from a .xkm file (yet)\n"); + else ERROR("Cannot generate a listing from an X connection (yet)\n"); + return False; + } + if (xkblist) { + if (outputFile==NULL) outputFile= uStringDup("-"); + else if (strchr(outputFile,':')!=NULL) { + ERROR("Cannot write a listing to an X connection\n"); + return False; + } + } + else if ((!outputFile) && (inputFile) && uStringEqual(inputFile,"-")) { + int len= strlen("stdin")+strlen(fileTypeExt[outputFormat])+2; + outputFile= uTypedCalloc(len,char); + if (outputFile==NULL) { + WSGO("Cannot allocate space for output file name\n"); + ACTION("Exiting\n"); + exit(1); + } + sprintf(outputFile,"stdin.%s",fileTypeExt[outputFormat]); + } + else if ((outputFile==NULL)&&(inputFile!=NULL)) { + int len; + char *base,*ext; + + if (inputMap==NULL) { + base= strrchr(inputFile,'/'); + if (base==NULL) base= inputFile; + else base++; + } + else base= inputMap; + + len= strlen(base)+strlen(fileTypeExt[outputFormat])+2; + outputFile= uTypedCalloc(len,char); + if (outputFile==NULL) { + WSGO("Cannot allocate space for output file name\n"); + ACTION("Exiting\n"); + exit(1); + } + ext= strrchr(base,'.'); + if (ext==NULL) + sprintf(outputFile,"%s.%s",base,fileTypeExt[outputFormat]); + else { + strcpy(outputFile,base); + strcpy(&outputFile[ext-base+1],fileTypeExt[outputFormat]); + } + } + else if (outputFile==NULL) { + int len; + char *ch,*name,buf[128]; + if (inDpyName[0]==':') + sprintf(name=buf,"server%s",inDpyName); + else name= inDpyName; + + len= strlen(name)+strlen(fileTypeExt[outputFormat])+2; + outputFile= uTypedCalloc(len,char); + if (outputFile==NULL) { + WSGO("Cannot allocate space for output file name\n"); + ACTION("Exiting\n"); + exit(1); + } + strcpy(outputFile,name); + for (ch=outputFile;(*ch)!='\0';ch++) { + if (*ch==':') *ch= '-'; + else if (*ch=='.') *ch= '_'; + } + *ch++= '.'; + strcpy(ch,fileTypeExt[outputFormat]); + } +#ifdef WIN32 + else if (strlen(outputFile) > 2 && + isalpha(outputFile[0]) && + outputFile[1] == ':' && strchr(outputFile + 2,':')==NULL) { + } +#endif + else if (strchr(outputFile,':')!=NULL) { + outDpyName= outputFile; + outputFile= NULL; + outputFormat= WANT_X_SERVER; + } + return True; +} + +static Display * +GetDisplay(char *program,char *dpyName) +{ +int mjr,mnr,error; +Display *dpy; + + mjr= XkbMajorVersion; + mnr= XkbMinorVersion; + dpy= XkbOpenDisplay(dpyName,NULL,NULL,&mjr,&mnr,&error); + if (dpy==NULL) { + switch (error) { + case XkbOD_BadLibraryVersion: + INFO3("%s was compiled with XKB version %d.%02d\n", + program,XkbMajorVersion,XkbMinorVersion); + ERROR2("X library supports incompatible version %d.%02d\n", + mjr,mnr); + break; + case XkbOD_ConnectionRefused: + ERROR1("Cannot open display \"%s\"\n",dpyName); + break; + case XkbOD_NonXkbServer: + ERROR1("XKB extension not present on %s\n",dpyName); + break; + case XkbOD_BadServerVersion: + INFO3("%s was compiled with XKB version %d.%02d\n", + program,XkbMajorVersion,XkbMinorVersion); + ERROR3("Server %s uses incompatible version %d.%02d\n", + dpyName,mjr,mnr); + break; + default: + WSGO1("Unknown error %d from XkbOpenDisplay\n",error); + } + } + else if (synch) + XSynchronize(dpy,True); + return dpy; +} + +/***====================================================================***/ + +extern int yydebug; + +int +main(int argc,char *argv[]) +{ +FILE * file; +XkbFile * rtrn; +XkbFile * mapToUse; +int ok; +XkbFileInfo result; +Status status; + + yyin = stdin; + uSetEntryFile(NullString); + uSetDebugFile(NullString); + uSetErrorFile(NullString); + + XkbInitIncludePath(); + if (!parseArgs(argc,argv)) + exit(1); +#ifdef DEBUG + if (debugFlags&0x2) + yydebug= 1; +#endif + if (preErrorMsg) + uSetPreErrorMessage(preErrorMsg); + if (errorPrefix) + uSetErrorPrefix(errorPrefix); + if (postErrorMsg) + uSetPostErrorMessage(postErrorMsg); + file= NULL; + XkbInitAtoms(NULL); + XkbAddDefaultDirectoriesToPath(); + if (xkblist) { + Bool gotSome; + gotSome= GenerateListing(outputFile); + if ((warningLevel>7)&&(!gotSome)) + return -1; + return 0; + } + if (inputFile!=NULL) { + if (uStringEqual(inputFile,"-")) { + file= stdin; + inputFile= "stdin"; + } + else { + file= fopen(inputFile,"r"); + } + } + else if (inDpyName!=NULL) { + inDpy= GetDisplay(argv[0],inDpyName); + if (!inDpy) { + ACTION("Exiting\n"); + exit(1); + } + } + if (outDpyName!=NULL) { + outDpy= GetDisplay(argv[0],outDpyName); + if (!outDpy) { + ACTION("Exiting\n"); + exit(1); + } + } + if ((inDpy==NULL) && (outDpy==NULL)) { + int mjr,mnr; + mjr= XkbMajorVersion; + mnr= XkbMinorVersion; + if (!XkbLibraryVersion(&mjr,&mnr)) { + INFO3("%s was compiled with XKB version %d.%02d\n", + argv[0],XkbMajorVersion,XkbMinorVersion); + ERROR2("X library supports incompatible version %d.%02d\n", + mjr,mnr); + ACTION("Exiting\n"); + exit(1); + } + } + if (file) { + ok= True; + setScanState(inputFile,1); + if ((inputFormat==INPUT_XKB)&&(XKBParseFile(file,&rtrn)&&(rtrn!=NULL))){ + fclose(file); + mapToUse= rtrn; + if (inputMap!=NULL) { + while ((mapToUse)&&(!uStringEqual(mapToUse->name,inputMap))) { + mapToUse= (XkbFile *)mapToUse->common.next; + } + if (!mapToUse) { + FATAL2("No map named \"%s\" in \"%s\"\n",inputMap, + inputFile); + /* NOTREACHED */ + } + } + else if (rtrn->common.next!=NULL) { + mapToUse= rtrn; + for (;mapToUse;mapToUse= (XkbFile*)mapToUse->common.next) { + if (mapToUse->flags&XkbLC_Default) + break; + } + if (!mapToUse) { + mapToUse= rtrn; + if (warningLevel>4) { + WARN1("No map specified, but \"%s\" has several\n", + inputFile); + ACTION1("Using the first defined map, \"%s\"\n", + mapToUse->name); + } + } + } + bzero((char *)&result,sizeof(result)); + result.type= mapToUse->type; + if ((result.xkb= XkbAllocKeyboard())==NULL) { + WSGO("Cannot allocate keyboard description\n"); + /* NOTREACHED */ + } + switch (mapToUse->type) { + case XkmSemanticsFile: + case XkmLayoutFile: + case XkmKeymapFile: + ok= CompileKeymap(mapToUse,&result,MergeReplace); + break; + case XkmKeyNamesIndex: + ok= CompileKeycodes(mapToUse,&result,MergeReplace); + break; + case XkmTypesIndex: + ok= CompileKeyTypes(mapToUse,&result,MergeReplace); + break; + case XkmSymbolsIndex: + /* if it's just symbols, invent key names */ + result.xkb->flags|= AutoKeyNames; + ok= False; + break; + case XkmCompatMapIndex: + ok= CompileCompatMap(mapToUse,&result,MergeReplace,NULL); + break; + case XkmGeometryFile: + case XkmGeometryIndex: + /* if it's just a geometry, invent key names */ + result.xkb->flags|= AutoKeyNames; + ok= CompileGeometry(mapToUse,&result,MergeReplace); + break; + default: + WSGO1("Unknown file type %d\n",mapToUse->type); + ok= False; + break; + } + } + else if (inputFormat==INPUT_XKM) { + unsigned tmp; + bzero((char *)&result,sizeof(result)); + if ((result.xkb= XkbAllocKeyboard())==NULL) { + WSGO("Cannot allocate keyboard description\n"); + /* NOTREACHED */ + } + tmp= XkmReadFile(file,0,XkmKeymapLegal,&result); + if (tmp==XkmKeymapLegal) { + ERROR1("Cannot read XKM file \"%s\"\n",inputFile); + ok= False; + } + } + else { + INFO1("Errors encountered in %s; not compiled.\n",inputFile); + ok= False; + } + } + else if (inDpy!=NULL) { + bzero((char *)&result,sizeof(result)); + result.type= XkmKeymapFile; + result.xkb= XkbGetMap(inDpy,XkbAllMapComponentsMask,device_id); + if (result.xkb==NULL) + WSGO("Cannot load keyboard description\n"); + if (XkbGetIndicatorMap(inDpy,~0,result.xkb)!=Success) + WSGO("Could not load indicator map\n"); + if (XkbGetControls(inDpy,XkbAllControlsMask,result.xkb)!=Success) + WSGO("Could not load keyboard controls\n"); + if (XkbGetCompatMap(inDpy,XkbAllCompatMask,result.xkb)!=Success) + WSGO("Could not load compatibility map\n"); + if (XkbGetNames(inDpy,XkbAllNamesMask,result.xkb)!=Success) + WSGO("Could not load names\n"); + if ((status=XkbGetGeometry(inDpy,result.xkb))!=Success) { + if (warningLevel>3) { + char buf[100]; + buf[0]= '\0'; + XGetErrorText(inDpy,status,buf,100); + WARN1("Could not load keyboard geometry for %s\n",inDpyName); + ACTION1("%s\n",buf); + ACTION("Resulting keymap file will not describe geometry\n"); + } + } + if (computeDflts) + ok= (ComputeKbdDefaults(result.xkb)==Success); + else ok= True; + } + else { + fprintf(stderr,"Cannot open \"%s\" to compile\n",inputFile); + ok= 0; + } + if (ok) { + FILE *out = stdout; + if ((inDpy!=outDpy)&& + (XkbChangeKbdDisplay(outDpy,&result)!=Success)) { + WSGO2("Error converting keyboard display from %s to %s\n", + inDpyName,outDpyName); + exit(1); + } + if (outputFile!=NULL) { + if (uStringEqual(outputFile,"-")) + outputFile= "stdout"; + else { + /* + * fix to prevent symlink attack (e.g., + * ln -s /etc/passwd /var/tmp/server-0.xkm) + */ + /* + * this patch may have POSIX, Linux, or GNU libc bias + * -- Branden Robinson + */ + int outputFileFd; + int binMode = 0; + const char *openMode = "w"; + unlink(outputFile); +#ifdef O_BINARY + switch (outputFormat) { + case WANT_XKM_FILE: + binMode = O_BINARY; + openMode = "wb"; + break; + default: + binMode = 0; + break; + } +#endif + outputFileFd= open(outputFile, O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH|binMode); + if (outputFileFd<0) { + ERROR1("Cannot open \"%s\" to write keyboard description\n", + outputFile); + ACTION("Exiting\n"); + exit(1); + } +#ifndef WIN32 + out= fdopen(outputFileFd, openMode); +#else + close(outputFileFd); + out= fopen(outputFile, "wb"); +#endif + /* end BR */ + if (out==NULL) { + ERROR1("Cannot open \"%s\" to write keyboard description\n", + outputFile); + ACTION("Exiting\n"); + exit(1); + } + } + } + switch (outputFormat) { + case WANT_XKM_FILE: + ok= XkbWriteXKMFile(out,&result); + break; + case WANT_XKB_FILE: + ok= XkbWriteXKBFile(out,&result,showImplicit,NULL,NULL); + break; + case WANT_C_HDR: + ok= XkbWriteCFile(out,outputFile,&result); + break; + case WANT_X_SERVER: + if (!(ok= XkbWriteToServer(&result))) { + ERROR2("%s in %s\n",_XkbErrMessages[_XkbErrCode], + _XkbErrLocation?_XkbErrLocation:"unknown"); + ACTION1("Couldn't write keyboard description to %s\n", + outDpyName); + } + break; + default: + WSGO1("Unknown output format %d\n",outputFormat); + ACTION("No output file created\n"); + ok= False; + break; + } + if (outputFormat!=WANT_X_SERVER) { + fclose(out); + if (!ok) { + ERROR2("%s in %s\n",_XkbErrMessages[_XkbErrCode], + _XkbErrLocation?_XkbErrLocation:"unknown"); + ACTION1("Output file \"%s\" removed\n",outputFile); + unlink(outputFile); + } + } + } + if (inDpy) + XCloseDisplay(inDpy); + inDpy= NULL; + if (outDpy) + XCloseDisplay(outDpy); + uFinishUp(); + return (ok==0); +} |