setxkbmap.c revision 1568b75b
17d5e3a19Smrg/************************************************************ 27d5e3a19Smrg Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc. 37d5e3a19Smrg 47d5e3a19Smrg Permission to use, copy, modify, and distribute this 57d5e3a19Smrg software and its documentation for any purpose and without 67d5e3a19Smrg fee is hereby granted, provided that the above copyright 77d5e3a19Smrg notice appear in all copies and that both that copyright 87d5e3a19Smrg notice and this permission notice appear in supporting 97d5e3a19Smrg documentation, and that the name of Silicon Graphics not be 107d5e3a19Smrg used in advertising or publicity pertaining to distribution 117d5e3a19Smrg of the software without specific prior written permission. 127d5e3a19Smrg Silicon Graphics makes no representation about the suitability 137d5e3a19Smrg of this software for any purpose. It is provided "as is" 147d5e3a19Smrg without any express or implied warranty. 157d5e3a19Smrg 167d5e3a19Smrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 177d5e3a19Smrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 187d5e3a19Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 197d5e3a19Smrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 207d5e3a19Smrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 217d5e3a19Smrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 227d5e3a19Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 237d5e3a19Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE. 247d5e3a19Smrg 257d5e3a19Smrg ********************************************************/ 267d5e3a19Smrg 277d5e3a19Smrg#include <stdio.h> 287d5e3a19Smrg#include <stdlib.h> 297d5e3a19Smrg#include <locale.h> 307d5e3a19Smrg#include <limits.h> 317d5e3a19Smrg#include <ctype.h> 327d5e3a19Smrg#include <X11/Xlib.h> 337d5e3a19Smrg#include <X11/Xos.h> 347d5e3a19Smrg#include <X11/XKBlib.h> 357d5e3a19Smrg#include <X11/extensions/XKBfile.h> 367d5e3a19Smrg#include <X11/extensions/XKBconfig.h> 377d5e3a19Smrg#include <X11/extensions/XKBrules.h> 387d5e3a19Smrg 397d5e3a19Smrg#ifndef PATH_MAX 407d5e3a19Smrg#ifdef MAXPATHLEN 417d5e3a19Smrg#define PATH_MAX MAXPATHLEN 427d5e3a19Smrg#else 437d5e3a19Smrg#define PATH_MAX 1024 447d5e3a19Smrg#endif 457d5e3a19Smrg#endif 467d5e3a19Smrg 477d5e3a19Smrg#ifndef DFLT_XKB_CONFIG_ROOT 487d5e3a19Smrg#define DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb" 497d5e3a19Smrg#endif 507d5e3a19Smrg#ifndef DFLT_XKB_RULES_FILE 517d5e3a19Smrg#define DFLT_XKB_RULES_FILE __XKBDEFRULES__ 527d5e3a19Smrg#endif 537d5e3a19Smrg#ifndef DFLT_XKB_LAYOUT 547d5e3a19Smrg#define DFLT_XKB_LAYOUT "us" 557d5e3a19Smrg#endif 567d5e3a19Smrg#ifndef DFLT_XKB_MODEL 577d5e3a19Smrg#define DFLT_XKB_MODEL "pc105" 587d5e3a19Smrg#endif 597d5e3a19Smrg 601568b75bSmrg/* Values used in svSrc to state how a value was obtained. The order of these 611568b75bSmrg * is important, the bigger the higher the priority. 621568b75bSmrg * e.g. FROM_CONFIG overrides FROM_SERVER */ 637d5e3a19Smrg#define UNDEFINED 0 641568b75bSmrg#define FROM_SERVER 1 /* retrieved from server at runtime */ 651568b75bSmrg#define FROM_RULES 2 /* xkb rules file */ 661568b75bSmrg#define FROM_CONFIG 3 /* command-line specified config file */ 671568b75bSmrg#define FROM_CMD_LINE 4 /* specified at the cmdline */ 687d5e3a19Smrg#define NUM_SOURCES 5 697d5e3a19Smrg 701568b75bSmrg/* Indices used into svSrc, svNValue */ 711568b75bSmrg#define RULES_NDX 0 /* rules file */ 721568b75bSmrg#define CONFIG_NDX 1 /* config file (if used) */ 731568b75bSmrg#define DISPLAY_NDX 2 /* X display name */ 741568b75bSmrg#define LOCALE_NDX 3 /* machine's locale */ 757d5e3a19Smrg#define MODEL_NDX 4 767d5e3a19Smrg#define LAYOUT_NDX 5 777d5e3a19Smrg#define VARIANT_NDX 6 787d5e3a19Smrg#define KEYCODES_NDX 7 797d5e3a19Smrg#define TYPES_NDX 8 807d5e3a19Smrg#define COMPAT_NDX 9 817d5e3a19Smrg#define SYMBOLS_NDX 10 827d5e3a19Smrg#define GEOMETRY_NDX 11 837d5e3a19Smrg#define KEYMAP_NDX 12 847d5e3a19Smrg#define NUM_STRING_VALS 13 857d5e3a19Smrg 867d5e3a19Smrg/***====================================================================***/ 871568b75bSmrgstatic Bool print = False; 881568b75bSmrgstatic Bool synch = False; 891568b75bSmrgstatic int verbose = 5; 901568b75bSmrg 911568b75bSmrgstatic Display *dpy; 921568b75bSmrg 931568b75bSmrg/** 941568b75bSmrg * human-readable versions of FROM_CONFIG, FROM_SERVER, etc. Used for error 951568b75bSmrg * reporting. 961568b75bSmrg */ 971568b75bSmrgstatic char *srcName[NUM_SOURCES] = { 981568b75bSmrg "undefined", "X server", "rules file", "config file", "command line" 997d5e3a19Smrg}; 1007d5e3a19Smrg 1011568b75bSmrg/** 1021568b75bSmrg * human-readable versions for RULES_NDX, CONFIG_NDX, etc. Used for error 1031568b75bSmrg * reporting. 1041568b75bSmrg */ 1051568b75bSmrgstatic char *svName[NUM_STRING_VALS] = { 1061568b75bSmrg "rules file", "config file", "X display", "locale", 1071568b75bSmrg "keyboard model", "keyboard layout", "layout variant", 1081568b75bSmrg "keycodes", "types", "compatibility map", "symbols", "geometry", 1091568b75bSmrg "keymap" 1107d5e3a19Smrg}; 1111568b75bSmrg/** 1121568b75bSmrg * Holds the source for each of RULES, CONFIG, DISPLAY, etc. 1131568b75bSmrg * i.e. if svSrc[LAYOUT_NDX] == FROM_SERVER, then the layout has been fetched 1141568b75bSmrg * from the server. 1151568b75bSmrg */ 1161568b75bSmrgstatic int svSrc[NUM_STRING_VALS]; 1171568b75bSmrg/** 1181568b75bSmrg * Holds the value for each of RULES, CONFIG, DISPLAY, etc. 1191568b75bSmrg */ 1201568b75bSmrgstatic char *svValue[NUM_STRING_VALS]; 1217d5e3a19Smrg 1221568b75bSmrgstatic XkbConfigRtrnRec cfgResult; 1237d5e3a19Smrg 1241568b75bSmrgstatic XkbRF_RulesPtr rules = NULL; 1251568b75bSmrgstatic XkbRF_VarDefsRec rdefs; 1267d5e3a19Smrg 1271568b75bSmrgstatic Bool clearOptions = False; 1281568b75bSmrgstatic int szOptions = 0; 1291568b75bSmrgstatic int numOptions = 0; 1301568b75bSmrgstatic char **options = NULL; 1317d5e3a19Smrg 1321568b75bSmrgstatic int szInclPath = 0; 1331568b75bSmrgstatic int numInclPath = 0; 1341568b75bSmrgstatic char **inclPath = NULL; 1357d5e3a19Smrg 1361568b75bSmrgstatic XkbDescPtr xkb = NULL; 1377d5e3a19Smrg 1381568b75bSmrgstatic int deviceSpec = XkbUseCoreKbd; 1397d5e3a19Smrg 1407d5e3a19Smrg/***====================================================================***/ 1417d5e3a19Smrg 1427d5e3a19Smrg#define streq(s1,s2) (strcmp(s1,s2)==0) 1437d5e3a19Smrg#define strpfx(s1,s2) (strncmp(s1,s2,strlen(s2))==0) 1447d5e3a19Smrg 1457d5e3a19Smrg#define MSG(s) printf(s) 1467d5e3a19Smrg#define MSG1(s,a) printf(s,a) 1477d5e3a19Smrg#define MSG2(s,a,b) printf(s,a,b) 1487d5e3a19Smrg#define MSG3(s,a,b,c) printf(s,a,b,c) 1497d5e3a19Smrg 1507d5e3a19Smrg#define VMSG(l,s) if (verbose>(l)) printf(s) 1517d5e3a19Smrg#define VMSG1(l,s,a) if (verbose>(l)) printf(s,a) 1527d5e3a19Smrg#define VMSG2(l,s,a,b) if (verbose>(l)) printf(s,a,b) 1537d5e3a19Smrg#define VMSG3(l,s,a,b,c) if (verbose>(l)) printf(s,a,b,c) 1547d5e3a19Smrg 1557d5e3a19Smrg#define ERR(s) fprintf(stderr,s) 1567d5e3a19Smrg#define ERR1(s,a) fprintf(stderr,s,a) 1577d5e3a19Smrg#define ERR2(s,a,b) fprintf(stderr,s,a,b) 1587d5e3a19Smrg#define ERR3(s,a,b,c) fprintf(stderr,s,a,b,c) 1597d5e3a19Smrg 1607d5e3a19Smrg/***====================================================================***/ 1617d5e3a19Smrg 1621568b75bSmrgBool addToList(int *sz, int *num, char ***listIn, char *newVal); 1631568b75bSmrgvoid usage(int argc, char **argv); 1641568b75bSmrgvoid dumpNames(Bool wantRules, Bool wantCNames); 1651568b75bSmrgvoid trySetString(int which, char *newVal, int src); 1661568b75bSmrgBool setOptString(int *arg, int argc, char **argv, int which, int src); 1671568b75bSmrgint parseArgs(int argc, char **argv); 1681568b75bSmrgBool getDisplay(int argc, char **argv); 1691568b75bSmrgBool getServerValues(void); 1701568b75bSmrgFILE *findFileInPath(char *name, char *subdir); 1711568b75bSmrgBool addStringToOptions(char *opt_str, int *sz_opts, int *num_opts, 1721568b75bSmrg char ***opts); 1731568b75bSmrgchar *stringFromOptions(char *orig, int numNew, char **newOpts); 1741568b75bSmrgBool applyConfig(char *name); 1751568b75bSmrgBool applyRules(void); 1761568b75bSmrgBool applyComponentNames(void); 1771568b75bSmrgvoid printKeymap(void); 1787d5e3a19Smrg 1797d5e3a19Smrg/***====================================================================***/ 1807d5e3a19Smrg 1817d5e3a19SmrgBool 1821568b75bSmrgaddToList(int *sz, int *num, char ***listIn, char *newVal) 1837d5e3a19Smrg{ 1841568b75bSmrg register int i; 1851568b75bSmrg char **list; 1861568b75bSmrg 1871568b75bSmrg if ((!newVal) || (!newVal[0])) 1881568b75bSmrg { 1891568b75bSmrg *num = 0; 1901568b75bSmrg return True; 1911568b75bSmrg } 1921568b75bSmrg list = *listIn; 1931568b75bSmrg for (i = 0; i < *num; i++) 1941568b75bSmrg { 1951568b75bSmrg if (streq(list[i], newVal)) 1961568b75bSmrg return True; 1971568b75bSmrg } 1981568b75bSmrg if ((list == NULL) || (*sz < 1)) 1991568b75bSmrg { 2001568b75bSmrg *num = 0; 2011568b75bSmrg *sz = 4; 2021568b75bSmrg list = (char **) calloc(*sz, sizeof(char *)); 2031568b75bSmrg *listIn = list; 2041568b75bSmrg } 2051568b75bSmrg else if (*num >= *sz) 2061568b75bSmrg { 2071568b75bSmrg *sz *= 2; 2081568b75bSmrg list = (char **) realloc(list, (*sz) * sizeof(char *)); 2091568b75bSmrg *listIn = list; 2101568b75bSmrg } 2111568b75bSmrg if (!list) 2121568b75bSmrg { 2131568b75bSmrg ERR("Internal Error! Allocation failure in add to list!\n"); 2141568b75bSmrg ERR(" Exiting.\n"); 2151568b75bSmrg exit(-1); 2161568b75bSmrg } 2171568b75bSmrg list[*num] = strdup(newVal); 2181568b75bSmrg (*num) = (*num) + 1; 2197d5e3a19Smrg return True; 2207d5e3a19Smrg} 2217d5e3a19Smrg 2227d5e3a19Smrg/***====================================================================***/ 2237d5e3a19Smrg 2247d5e3a19Smrgvoid 2251568b75bSmrgusage(int argc, char **argv) 2267d5e3a19Smrg{ 2271568b75bSmrg MSG1("Usage: %s [args] [<layout> [<variant> [<option> ... ]]]\n", 2281568b75bSmrg argv[0]); 2297d5e3a19Smrg MSG("Where legal args are:\n"); 2307d5e3a19Smrg MSG("-?,-help Print this message\n"); 2317d5e3a19Smrg MSG("-compat <name> Specifies compatibility map component name\n"); 2327d5e3a19Smrg MSG("-config <file> Specifies configuration file to use\n"); 2337d5e3a19Smrg MSG("-device <deviceid> Specifies the device ID to use\n"); 2347d5e3a19Smrg MSG("-display <dpy> Specifies display to use\n"); 2357d5e3a19Smrg MSG("-geometry <name> Specifies geometry component name\n"); 2367d5e3a19Smrg MSG("-I[<dir>] Add <dir> to list of directories to be used\n"); 2377d5e3a19Smrg MSG("-keycodes <name> Specifies keycodes component name\n"); 2387d5e3a19Smrg MSG("-keymap <name> Specifies name of keymap to load\n"); 2397d5e3a19Smrg MSG("-layout <name> Specifies layout used to choose component names\n"); 2407d5e3a19Smrg MSG("-model <name> Specifies model used to choose component names\n"); 2417d5e3a19Smrg MSG("-option <name> Adds an option used to choose component names\n"); 2427d5e3a19Smrg MSG("-print Print a complete xkb_keymap description and exit\n"); 2437d5e3a19Smrg MSG("-rules <name> Name of rules file to use\n"); 2447d5e3a19Smrg MSG("-symbols <name> Specifies symbols component name\n"); 2457d5e3a19Smrg MSG("-synch Synchronize request w/X server\n"); 2467d5e3a19Smrg MSG("-types <name> Specifies types component name\n"); 2477d5e3a19Smrg MSG("-v[erbose] [<lvl>] Sets verbosity (1..10). Higher values yield\n"); 2487d5e3a19Smrg MSG(" more messages\n"); 2497d5e3a19Smrg MSG("-variant <name> Specifies layout variant used to choose component names\n"); 2507d5e3a19Smrg} 2517d5e3a19Smrg 2527d5e3a19Smrgvoid 2531568b75bSmrgdumpNames(Bool wantRules, Bool wantCNames) 2547d5e3a19Smrg{ 2551568b75bSmrg if (wantRules) 2561568b75bSmrg { 2571568b75bSmrg if (svValue[MODEL_NDX]) 2581568b75bSmrg MSG1("model: %s\n", svValue[MODEL_NDX]); 2591568b75bSmrg if (svValue[LAYOUT_NDX]) 2601568b75bSmrg MSG1("layout: %s\n", svValue[LAYOUT_NDX]); 2611568b75bSmrg if (svValue[VARIANT_NDX]) 2621568b75bSmrg MSG1("variant: %s\n", svValue[VARIANT_NDX]); 2631568b75bSmrg if (options) 2641568b75bSmrg { 2651568b75bSmrg char *opt_str = stringFromOptions(NULL, numOptions, options); 2661568b75bSmrg MSG1("options: %s\n", opt_str); 2671568b75bSmrg free(opt_str); 2681568b75bSmrg } 2691568b75bSmrg } 2701568b75bSmrg if (wantCNames) 2711568b75bSmrg { 2721568b75bSmrg if (svValue[KEYMAP_NDX]) 2731568b75bSmrg MSG1("keymap: %s\n", svValue[KEYMAP_NDX]); 2741568b75bSmrg if (svValue[KEYCODES_NDX]) 2751568b75bSmrg MSG1("keycodes: %s\n", svValue[KEYCODES_NDX]); 2761568b75bSmrg if (svValue[TYPES_NDX]) 2771568b75bSmrg MSG1("types: %s\n", svValue[TYPES_NDX]); 2781568b75bSmrg if (svValue[COMPAT_NDX]) 2791568b75bSmrg MSG1("compat: %s\n", svValue[COMPAT_NDX]); 2801568b75bSmrg if (svValue[SYMBOLS_NDX]) 2811568b75bSmrg MSG1("symbols: %s\n", svValue[SYMBOLS_NDX]); 2821568b75bSmrg if (svValue[GEOMETRY_NDX]) 2831568b75bSmrg MSG1("geometry: %s\n", svValue[GEOMETRY_NDX]); 2847d5e3a19Smrg } 2857d5e3a19Smrg return; 2867d5e3a19Smrg} 2877d5e3a19Smrg 2887d5e3a19Smrg/***====================================================================***/ 2897d5e3a19Smrg 2901568b75bSmrg/** 2911568b75bSmrg * Set the given string (obtained from src) in the svValue/svSrc globals. 2921568b75bSmrg * If the given item is already set, it is overridden if the original source 2931568b75bSmrg * is less significant than the given one. 2941568b75bSmrg * 2951568b75bSmrg * @param which What value is it (one of RULES_NDX, CONFIG_NDX, ...) 2961568b75bSmrg */ 2977d5e3a19Smrgvoid 2981568b75bSmrgtrySetString(int which, char *newVal, int src) 2997d5e3a19Smrg{ 3001568b75bSmrg if (svValue[which] != NULL) 3011568b75bSmrg { 3021568b75bSmrg if (svSrc[which] == src) 3031568b75bSmrg { 3041568b75bSmrg VMSG2(0, "Warning! More than one %s from %s\n", 3051568b75bSmrg svName[which], srcName[src]); 3061568b75bSmrg VMSG2(0, " Using \"%s\", ignoring \"%s\"\n", 3071568b75bSmrg svValue[which], newVal); 3081568b75bSmrg return; 3091568b75bSmrg } 3101568b75bSmrg else if (svSrc[which] > src) 3111568b75bSmrg { 3121568b75bSmrg VMSG1(5, "Warning! Multiple definitions of %s\n", svName[which]); 3131568b75bSmrg VMSG2(5, " Using %s, ignoring %s\n", 3141568b75bSmrg srcName[svSrc[which]], srcName[src]); 3151568b75bSmrg return; 3161568b75bSmrg } 3171568b75bSmrg } 3181568b75bSmrg svSrc[which] = src; 3191568b75bSmrg svValue[which] = newVal; 3207d5e3a19Smrg return; 3217d5e3a19Smrg} 3227d5e3a19Smrg 3237d5e3a19SmrgBool 3241568b75bSmrgsetOptString(int *arg, int argc, char **argv, int which, int src) 3257d5e3a19Smrg{ 3261568b75bSmrg int ndx; 3271568b75bSmrg char *opt; 3281568b75bSmrg 3291568b75bSmrg ndx = *arg; 3301568b75bSmrg opt = argv[ndx]; 3311568b75bSmrg if (ndx >= argc - 1) 3321568b75bSmrg { 3331568b75bSmrg VMSG1(0, "No %s specified on the command line\n", svName[which]); 3341568b75bSmrg VMSG1(0, "Trailing %s option ignored\n", opt); 3351568b75bSmrg return True; 3367d5e3a19Smrg } 3377d5e3a19Smrg ndx++; 3381568b75bSmrg *arg = ndx; 3391568b75bSmrg if (svValue[which] != NULL) 3401568b75bSmrg { 3411568b75bSmrg if (svSrc[which] == src) 3421568b75bSmrg { 3431568b75bSmrg VMSG2(0, "More than one %s on %s\n", svName[which], srcName[src]); 3441568b75bSmrg VMSG2(0, "Using \"%s\", ignoring \"%s\"\n", svValue[which], 3451568b75bSmrg argv[ndx]); 3461568b75bSmrg return True; 3471568b75bSmrg } 3481568b75bSmrg else if (svSrc[which] > src) 3491568b75bSmrg { 3501568b75bSmrg VMSG1(5, "Multiple definitions of %s\n", svName[which]); 3511568b75bSmrg VMSG2(5, "Using %s, ignoring %s\n", srcName[svSrc[which]], 3521568b75bSmrg srcName[src]); 3531568b75bSmrg return True; 3541568b75bSmrg } 3551568b75bSmrg } 3561568b75bSmrg svSrc[which] = src; 3571568b75bSmrg svValue[which] = argv[ndx]; 3587d5e3a19Smrg return True; 3597d5e3a19Smrg} 3607d5e3a19Smrg 3617d5e3a19Smrg/***====================================================================***/ 3627d5e3a19Smrg 3631568b75bSmrg/** 3641568b75bSmrg * Parse commandline arguments. 3651568b75bSmrg * Return True on success or False if an unrecognized option has been 3661568b75bSmrg * specified. 3671568b75bSmrg */ 3687d5e3a19Smrgint 3691568b75bSmrgparseArgs(int argc, char **argv) 3707d5e3a19Smrg{ 3711568b75bSmrg int i; 3721568b75bSmrg Bool ok; 3731568b75bSmrg unsigned present; 3741568b75bSmrg 3751568b75bSmrg ok = True; 3761568b75bSmrg addToList(&szInclPath, &numInclPath, &inclPath, "."); 3771568b75bSmrg addToList(&szInclPath, &numInclPath, &inclPath, DFLT_XKB_CONFIG_ROOT); 3781568b75bSmrg for (i = 1; (i < argc) && ok; i++) 3791568b75bSmrg { 3801568b75bSmrg if (argv[i][0] != '-') 3811568b75bSmrg { 3821568b75bSmrg /* Allow a call like "setxkbmap us" to work. Layout is default, 3831568b75bSmrg if -layout is given, then try parsing variant, then options */ 3841568b75bSmrg if (!svSrc[LAYOUT_NDX]) 3851568b75bSmrg trySetString(LAYOUT_NDX, argv[i], FROM_CMD_LINE); 3861568b75bSmrg else if (!svSrc[VARIANT_NDX]) 3871568b75bSmrg trySetString(VARIANT_NDX, argv[i], FROM_CMD_LINE); 3881568b75bSmrg else 3891568b75bSmrg ok = addToList(&szOptions, &numOptions, &options, argv[i]); 3901568b75bSmrg } 3911568b75bSmrg else if (streq(argv[i], "-compat")) 3921568b75bSmrg ok = setOptString(&i, argc, argv, COMPAT_NDX, FROM_CMD_LINE); 3931568b75bSmrg else if (streq(argv[i], "-config")) 3941568b75bSmrg ok = setOptString(&i, argc, argv, CONFIG_NDX, FROM_CMD_LINE); 3951568b75bSmrg else if (streq(argv[i], "-device")) 3961568b75bSmrg deviceSpec = atoi(argv[++i]); /* only allow device IDs, not names */ 3971568b75bSmrg else if (streq(argv[i], "-display")) 3981568b75bSmrg ok = setOptString(&i, argc, argv, DISPLAY_NDX, FROM_CMD_LINE); 3991568b75bSmrg else if (streq(argv[i], "-geometry")) 4001568b75bSmrg ok = setOptString(&i, argc, argv, GEOMETRY_NDX, FROM_CMD_LINE); 4011568b75bSmrg else if (streq(argv[i], "-help") || streq(argv[i], "-?")) 4021568b75bSmrg { 4031568b75bSmrg usage(argc, argv); 4041568b75bSmrg exit(0); 4051568b75bSmrg } 4061568b75bSmrg else if (strpfx(argv[i], "-I")) 4071568b75bSmrg ok = addToList(&szInclPath, &numInclPath, &inclPath, &argv[i][2]); 4081568b75bSmrg else if (streq(argv[i], "-keycodes")) 4091568b75bSmrg ok = setOptString(&i, argc, argv, KEYCODES_NDX, FROM_CMD_LINE); 4101568b75bSmrg else if (streq(argv[i], "-keymap")) 4111568b75bSmrg ok = setOptString(&i, argc, argv, KEYMAP_NDX, FROM_CMD_LINE); 4121568b75bSmrg else if (streq(argv[i], "-layout")) 4131568b75bSmrg ok = setOptString(&i, argc, argv, LAYOUT_NDX, FROM_CMD_LINE); 4141568b75bSmrg else if (streq(argv[i], "-model")) 4151568b75bSmrg ok = setOptString(&i, argc, argv, MODEL_NDX, FROM_CMD_LINE); 4161568b75bSmrg else if (streq(argv[i], "-option")) 4171568b75bSmrg { 4181568b75bSmrg if ((i == argc - 1) || (argv[i + 1][0] == '\0') 4191568b75bSmrg || (argv[i + 1][0] == '-')) 4201568b75bSmrg { 4211568b75bSmrg clearOptions = True; 4221568b75bSmrg ok = addToList(&szOptions, &numOptions, &options, ""); 4231568b75bSmrg if (i < argc - 1 && argv[i + 1][0] == '\0') 4241568b75bSmrg i++; 4251568b75bSmrg } 4261568b75bSmrg else 4271568b75bSmrg { 4281568b75bSmrg ok = addToList(&szOptions, &numOptions, &options, argv[++i]); 4291568b75bSmrg } 4301568b75bSmrg } 4311568b75bSmrg else if (streq(argv[i], "-print")) 4321568b75bSmrg print = True; 4331568b75bSmrg else if (streq(argv[i], "-rules")) 4341568b75bSmrg ok = setOptString(&i, argc, argv, RULES_NDX, FROM_CMD_LINE); 4351568b75bSmrg else if (streq(argv[i], "-symbols")) 4361568b75bSmrg ok = setOptString(&i, argc, argv, SYMBOLS_NDX, FROM_CMD_LINE); 4371568b75bSmrg else if (streq(argv[i], "-synch")) 4381568b75bSmrg synch = True; 4391568b75bSmrg else if (streq(argv[i], "-types")) 4401568b75bSmrg ok = setOptString(&i, argc, argv, TYPES_NDX, FROM_CMD_LINE); 4411568b75bSmrg else if (streq(argv[i], "-verbose") || (streq(argv[i], "-v"))) 4421568b75bSmrg { 4431568b75bSmrg if ((i < argc - 1) && (isdigit(argv[i + 1][0]))) 4441568b75bSmrg verbose = atoi(argv[++i]); 4451568b75bSmrg else 4461568b75bSmrg verbose++; 4471568b75bSmrg if (verbose < 0) 4481568b75bSmrg { 4491568b75bSmrg ERR1("Illegal verbose level %d. Reset to 0\n", verbose); 4501568b75bSmrg verbose = 0; 4511568b75bSmrg } 4521568b75bSmrg else if (verbose > 10) 4531568b75bSmrg { 4541568b75bSmrg ERR1("Illegal verbose level %d. Reset to 10\n", verbose); 4551568b75bSmrg verbose = 10; 4561568b75bSmrg } 4571568b75bSmrg VMSG1(7, "Setting verbose level to %d\n", verbose); 4581568b75bSmrg } 4591568b75bSmrg else if (streq(argv[i], "-variant")) 4601568b75bSmrg ok = setOptString(&i, argc, argv, VARIANT_NDX, FROM_CMD_LINE); 4611568b75bSmrg else 4621568b75bSmrg { 4631568b75bSmrg ERR1("Error! Option \"%s\" not recognized\n", argv[i]); 4641568b75bSmrg ok = False; 4651568b75bSmrg } 4661568b75bSmrg } 4671568b75bSmrg 4681568b75bSmrg present = 0; 4691568b75bSmrg if (svValue[TYPES_NDX]) 4701568b75bSmrg present++; 4711568b75bSmrg if (svValue[COMPAT_NDX]) 4721568b75bSmrg present++; 4731568b75bSmrg if (svValue[SYMBOLS_NDX]) 4741568b75bSmrg present++; 4751568b75bSmrg if (svValue[KEYCODES_NDX]) 4761568b75bSmrg present++; 4771568b75bSmrg if (svValue[GEOMETRY_NDX]) 4781568b75bSmrg present++; 4791568b75bSmrg if (svValue[CONFIG_NDX]) 4801568b75bSmrg present++; 4811568b75bSmrg if (svValue[MODEL_NDX]) 4821568b75bSmrg present++; 4831568b75bSmrg if (svValue[LAYOUT_NDX]) 4841568b75bSmrg present++; 4851568b75bSmrg if (svValue[VARIANT_NDX]) 4861568b75bSmrg present++; 4871568b75bSmrg if (svValue[KEYMAP_NDX] && present) 4881568b75bSmrg { 4891568b75bSmrg ERR("No other components can be specified when a keymap is present\n"); 4901568b75bSmrg return False; 4917d5e3a19Smrg } 4927d5e3a19Smrg return ok; 4937d5e3a19Smrg} 4947d5e3a19Smrg 4951568b75bSmrg/** 4961568b75bSmrg * Open a connection to the display and print error if it fails. 4971568b75bSmrg * 4981568b75bSmrg * @return True on success or False otherwise. 4991568b75bSmrg */ 5007d5e3a19SmrgBool 5011568b75bSmrggetDisplay(int argc, char **argv) 5027d5e3a19Smrg{ 5031568b75bSmrg int major, minor, why; 5041568b75bSmrg 5051568b75bSmrg major = XkbMajorVersion; 5061568b75bSmrg minor = XkbMinorVersion; 5071568b75bSmrg dpy = 5081568b75bSmrg XkbOpenDisplay(svValue[DISPLAY_NDX], NULL, NULL, &major, &minor, 5091568b75bSmrg &why); 5101568b75bSmrg if (!dpy) 5111568b75bSmrg { 5121568b75bSmrg if (svValue[DISPLAY_NDX] == NULL) 5131568b75bSmrg svValue[DISPLAY_NDX] = getenv("DISPLAY"); 5141568b75bSmrg if (svValue[DISPLAY_NDX] == NULL) 5151568b75bSmrg svValue[DISPLAY_NDX] = "default display"; 5161568b75bSmrg switch (why) 5171568b75bSmrg { 5181568b75bSmrg case XkbOD_BadLibraryVersion: 5191568b75bSmrg ERR3("%s was compiled with XKB version %d.%02d\n", argv[0], 5201568b75bSmrg XkbMajorVersion, XkbMinorVersion); 5211568b75bSmrg ERR2("Xlib supports incompatible version %d.%02d\n", 5221568b75bSmrg major, minor); 5231568b75bSmrg break; 5241568b75bSmrg case XkbOD_ConnectionRefused: 5251568b75bSmrg ERR1("Cannot open display \"%s\"\n", svValue[DISPLAY_NDX]); 5261568b75bSmrg break; 5271568b75bSmrg case XkbOD_NonXkbServer: 5281568b75bSmrg ERR1("XKB extension not present on %s\n", svValue[DISPLAY_NDX]); 5291568b75bSmrg break; 5301568b75bSmrg case XkbOD_BadServerVersion: 5311568b75bSmrg ERR3("%s was compiled with XKB version %d.%02d\n", argv[0], 5321568b75bSmrg XkbMajorVersion, XkbMinorVersion); 5331568b75bSmrg ERR3("Server %s uses incompatible version %d.%02d\n", 5341568b75bSmrg svValue[DISPLAY_NDX], major, minor); 5351568b75bSmrg break; 5361568b75bSmrg default: 5371568b75bSmrg ERR1("Unknown error %d from XkbOpenDisplay\n", why); 5381568b75bSmrg break; 5391568b75bSmrg } 5401568b75bSmrg return False; 5417d5e3a19Smrg } 5427d5e3a19Smrg if (synch) 5431568b75bSmrg XSynchronize(dpy, True); 5447d5e3a19Smrg return True; 5457d5e3a19Smrg} 5467d5e3a19Smrg 5477d5e3a19Smrg/***====================================================================***/ 5487d5e3a19Smrg 5491568b75bSmrg/** 5501568b75bSmrg * Retrieve xkb values from th the XKB_RULES_NAMES property and store their 5511568b75bSmrg * contents in svValues. 5521568b75bSmrg * If the property cannot be read, the built-in defaults are used. 5531568b75bSmrg * 5541568b75bSmrg * @return True. 5551568b75bSmrg */ 5567d5e3a19SmrgBool 5577d5e3a19SmrggetServerValues(void) 5587d5e3a19Smrg{ 5591568b75bSmrg XkbRF_VarDefsRec vd; 5601568b75bSmrg char *tmp = NULL; 5617d5e3a19Smrg 5621568b75bSmrg if (!XkbRF_GetNamesProp(dpy, &tmp, &vd) || !tmp) 5631568b75bSmrg { 5641568b75bSmrg VMSG1(3, "Couldn't interpret %s property\n", _XKB_RF_NAMES_PROP_ATOM); 5657d5e3a19Smrg tmp = DFLT_XKB_RULES_FILE; 5667d5e3a19Smrg vd.model = DFLT_XKB_MODEL; 5677d5e3a19Smrg vd.layout = DFLT_XKB_LAYOUT; 5687d5e3a19Smrg vd.variant = NULL; 5697d5e3a19Smrg vd.options = NULL; 5701568b75bSmrg VMSG3(3, "Use defaults: rules - '%s' model - '%s' layout - '%s'\n", 5711568b75bSmrg tmp, vd.model, vd.layout); 5727d5e3a19Smrg } 5737d5e3a19Smrg if (tmp) 5741568b75bSmrg trySetString(RULES_NDX, tmp, FROM_SERVER); 5757d5e3a19Smrg if (vd.model) 5761568b75bSmrg trySetString(MODEL_NDX, vd.model, FROM_SERVER); 5777d5e3a19Smrg if (vd.layout) 5781568b75bSmrg trySetString(LAYOUT_NDX, vd.layout, FROM_SERVER); 5797d5e3a19Smrg if (vd.variant) 5801568b75bSmrg trySetString(VARIANT_NDX, vd.variant, FROM_SERVER); 5811568b75bSmrg if ((vd.options) && (!clearOptions)) 5821568b75bSmrg { 5831568b75bSmrg addStringToOptions(vd.options, &szOptions, &numOptions, &options); 5841568b75bSmrg XFree(vd.options); 5857d5e3a19Smrg } 5867d5e3a19Smrg return True; 5877d5e3a19Smrg} 5887d5e3a19Smrg 5897d5e3a19Smrg/***====================================================================***/ 5907d5e3a19Smrg 5917d5e3a19SmrgFILE * 5921568b75bSmrgfindFileInPath(char *name, char *subdir) 5937d5e3a19Smrg{ 5941568b75bSmrg register int i; 5951568b75bSmrg char buf[PATH_MAX]; 5961568b75bSmrg FILE *fp; 5971568b75bSmrg 5981568b75bSmrg if (name[0] == '/') 5991568b75bSmrg { 6001568b75bSmrg fp = fopen(name, "r"); 6011568b75bSmrg if ((verbose > 7) || ((!fp) && (verbose > 0))) 6021568b75bSmrg MSG2("%s file %s\n", (fp ? "Found" : "Didn't find"), name); 6031568b75bSmrg return fp; 6041568b75bSmrg } 6051568b75bSmrg for (i = 0; (i < numInclPath); i++) 6061568b75bSmrg { 6071568b75bSmrg if ((strlen(inclPath[i]) + strlen(subdir) + strlen(name) + 2) > 6081568b75bSmrg PATH_MAX) 6091568b75bSmrg { 6101568b75bSmrg VMSG3(0, "Path too long (%s/%s%s). Ignored.\n", inclPath[i], 6111568b75bSmrg subdir, name); 6121568b75bSmrg continue; 6131568b75bSmrg } 6141568b75bSmrg sprintf(buf, "%s/%s%s", inclPath[i], subdir, name); 6151568b75bSmrg fp = fopen(name, "r"); 6161568b75bSmrg if ((verbose > 7) || ((!fp) && (verbose > 5))) 6171568b75bSmrg MSG2("%s file %s\n", (fp ? "Found" : "Didn't find"), buf); 6181568b75bSmrg if (fp != NULL) 6191568b75bSmrg return fp; 6207d5e3a19Smrg } 6217d5e3a19Smrg return NULL; 6227d5e3a19Smrg} 6237d5e3a19Smrg 6247d5e3a19Smrg/***====================================================================***/ 6257d5e3a19Smrg 6267d5e3a19SmrgBool 6271568b75bSmrgaddStringToOptions(char *opt_str, int *sz_opts, int *num_opts, char ***opts) 6287d5e3a19Smrg{ 6291568b75bSmrg char *tmp, *str, *next; 6301568b75bSmrg Bool ok = True; 6317d5e3a19Smrg 6327d5e3a19Smrg if ((str = strdup(opt_str)) == NULL) 6331568b75bSmrg return False; 6341568b75bSmrg for (tmp = str, next = NULL; (tmp && *tmp != '\0') && ok; tmp = next) 6351568b75bSmrg { 6361568b75bSmrg next = strchr(str, ','); 6371568b75bSmrg if (next) 6381568b75bSmrg { 6391568b75bSmrg *next = '\0'; 6401568b75bSmrg next++; 6411568b75bSmrg } 6421568b75bSmrg ok = addToList(sz_opts, num_opts, opts, tmp) && ok; 6437d5e3a19Smrg } 6447d5e3a19Smrg free(str); 6457d5e3a19Smrg return ok; 6467d5e3a19Smrg} 6477d5e3a19Smrg 6487d5e3a19Smrg/***====================================================================***/ 6497d5e3a19Smrg 6507d5e3a19Smrgchar * 6511568b75bSmrgstringFromOptions(char *orig, int numNew, char **newOpts) 6527d5e3a19Smrg{ 6531568b75bSmrg int len, i, nOut; 6541568b75bSmrg 6551568b75bSmrg if (orig) 6561568b75bSmrg len = strlen(orig) + 1; 6571568b75bSmrg else 6581568b75bSmrg len = 0; 6591568b75bSmrg for (i = 0; i < numNew; i++) 6601568b75bSmrg { 6611568b75bSmrg if (newOpts[i]) 6621568b75bSmrg len += strlen(newOpts[i]) + 1; 6631568b75bSmrg } 6641568b75bSmrg if (len < 1) 6651568b75bSmrg return NULL; 6661568b75bSmrg if (orig) 6671568b75bSmrg { 6681568b75bSmrg orig = (char *) realloc(orig, len); 6691568b75bSmrg if (!orig) 6701568b75bSmrg { 6711568b75bSmrg ERR("OOM in stringFromOptions\n"); 6721568b75bSmrg return NULL; 6731568b75bSmrg } 6741568b75bSmrg nOut = 1; 6751568b75bSmrg } 6761568b75bSmrg else 6771568b75bSmrg { 6781568b75bSmrg orig = (char *) calloc(len, 1); 6791568b75bSmrg if (!orig) 6801568b75bSmrg { 6811568b75bSmrg ERR("OOM in stringFromOptions\n"); 6821568b75bSmrg return NULL; 6831568b75bSmrg } 6841568b75bSmrg nOut = 0; 6851568b75bSmrg } 6861568b75bSmrg for (i = 0; i < numNew; i++) 6871568b75bSmrg { 6881568b75bSmrg if (!newOpts[i]) 6891568b75bSmrg continue; 6901568b75bSmrg if (nOut > 0) 6911568b75bSmrg { 6921568b75bSmrg strcat(orig, ","); 6931568b75bSmrg strcat(orig, newOpts[i]); 6941568b75bSmrg } 6951568b75bSmrg else 6961568b75bSmrg strcpy(orig, newOpts[i]); 6971568b75bSmrg nOut++; 6987d5e3a19Smrg } 6997d5e3a19Smrg return orig; 7007d5e3a19Smrg} 7017d5e3a19Smrg 7027d5e3a19Smrg/***====================================================================***/ 7037d5e3a19Smrg 7047d5e3a19SmrgBool 7057d5e3a19SmrgapplyConfig(char *name) 7067d5e3a19Smrg{ 7071568b75bSmrg FILE *fp; 7081568b75bSmrg Bool ok; 7091568b75bSmrg 7101568b75bSmrg if ((fp = findFileInPath(name, "")) == NULL) 7111568b75bSmrg return False; 7121568b75bSmrg ok = XkbCFParse(fp, XkbCFDflts, NULL, &cfgResult); 7137d5e3a19Smrg fclose(fp); 7141568b75bSmrg if (!ok) 7151568b75bSmrg { 7161568b75bSmrg ERR1("Couldn't find configuration file \"%s\"\n", name); 7171568b75bSmrg return False; 7187d5e3a19Smrg } 7191568b75bSmrg if (cfgResult.rules_file) 7201568b75bSmrg { 7211568b75bSmrg trySetString(RULES_NDX, cfgResult.rules_file, FROM_CONFIG); 7221568b75bSmrg cfgResult.rules_file = NULL; 7237d5e3a19Smrg } 7241568b75bSmrg if (cfgResult.model) 7251568b75bSmrg { 7261568b75bSmrg trySetString(MODEL_NDX, cfgResult.model, FROM_CONFIG); 7271568b75bSmrg cfgResult.model = NULL; 7287d5e3a19Smrg } 7291568b75bSmrg if (cfgResult.layout) 7301568b75bSmrg { 7311568b75bSmrg trySetString(LAYOUT_NDX, cfgResult.layout, FROM_CONFIG); 7321568b75bSmrg cfgResult.layout = NULL; 7337d5e3a19Smrg } 7341568b75bSmrg if (cfgResult.variant) 7351568b75bSmrg { 7361568b75bSmrg trySetString(VARIANT_NDX, cfgResult.variant, FROM_CONFIG); 7371568b75bSmrg cfgResult.variant = NULL; 7387d5e3a19Smrg } 7391568b75bSmrg if (cfgResult.options) 7401568b75bSmrg { 7411568b75bSmrg addStringToOptions(cfgResult.options, &szOptions, &numOptions, 7421568b75bSmrg &options); 7431568b75bSmrg cfgResult.options = NULL; 7447d5e3a19Smrg } 7451568b75bSmrg if (cfgResult.keymap) 7461568b75bSmrg { 7471568b75bSmrg trySetString(KEYMAP_NDX, cfgResult.keymap, FROM_CONFIG); 7481568b75bSmrg cfgResult.keymap = NULL; 7497d5e3a19Smrg } 7501568b75bSmrg if (cfgResult.keycodes) 7511568b75bSmrg { 7521568b75bSmrg trySetString(KEYCODES_NDX, cfgResult.keycodes, FROM_CONFIG); 7531568b75bSmrg cfgResult.keycodes = NULL; 7547d5e3a19Smrg } 7551568b75bSmrg if (cfgResult.geometry) 7561568b75bSmrg { 7571568b75bSmrg trySetString(GEOMETRY_NDX, cfgResult.geometry, FROM_CONFIG); 7581568b75bSmrg cfgResult.geometry = NULL; 7597d5e3a19Smrg } 7601568b75bSmrg if (cfgResult.symbols) 7611568b75bSmrg { 7621568b75bSmrg trySetString(SYMBOLS_NDX, cfgResult.symbols, FROM_CONFIG); 7631568b75bSmrg cfgResult.symbols = NULL; 7647d5e3a19Smrg } 7651568b75bSmrg if (cfgResult.types) 7661568b75bSmrg { 7671568b75bSmrg trySetString(TYPES_NDX, cfgResult.types, FROM_CONFIG); 7681568b75bSmrg cfgResult.types = NULL; 7697d5e3a19Smrg } 7701568b75bSmrg if (cfgResult.compat) 7711568b75bSmrg { 7721568b75bSmrg trySetString(COMPAT_NDX, cfgResult.compat, FROM_CONFIG); 7731568b75bSmrg cfgResult.compat = NULL; 7747d5e3a19Smrg } 7751568b75bSmrg if (verbose > 5) 7761568b75bSmrg { 7771568b75bSmrg MSG("After config file:\n"); 7781568b75bSmrg dumpNames(True, True); 7797d5e3a19Smrg } 7807d5e3a19Smrg return True; 7817d5e3a19Smrg} 7827d5e3a19Smrg 7831568b75bSmrg/** 7841568b75bSmrg * If any of model, layout, variant or options is specified, then compile the 7851568b75bSmrg * options into the 7861568b75bSmrg * 7871568b75bSmrg * @return True on success or false otherwise. 7881568b75bSmrg */ 7897d5e3a19SmrgBool 7907d5e3a19SmrgapplyRules(void) 7917d5e3a19Smrg{ 7921568b75bSmrg int i; 7931568b75bSmrg char *rfName; 7947d5e3a19Smrg 7951568b75bSmrg if (svSrc[MODEL_NDX] || svSrc[LAYOUT_NDX] || svSrc[VARIANT_NDX] 7961568b75bSmrg || options) 7971568b75bSmrg { 7981568b75bSmrg char buf[PATH_MAX]; 7991568b75bSmrg XkbComponentNamesRec rnames; 8007d5e3a19Smrg 8011568b75bSmrg if (svSrc[VARIANT_NDX] < svSrc[LAYOUT_NDX]) 8027d5e3a19Smrg svValue[VARIANT_NDX] = NULL; 8037d5e3a19Smrg 8041568b75bSmrg rdefs.model = svValue[MODEL_NDX]; 8051568b75bSmrg rdefs.layout = svValue[LAYOUT_NDX]; 8061568b75bSmrg rdefs.variant = svValue[VARIANT_NDX]; 8071568b75bSmrg if (options) 8081568b75bSmrg rdefs.options = 8091568b75bSmrg stringFromOptions(rdefs.options, numOptions, options); 8101568b75bSmrg 8111568b75bSmrg if (svSrc[RULES_NDX]) 8121568b75bSmrg rfName = svValue[RULES_NDX]; 8131568b75bSmrg else 8141568b75bSmrg rfName = DFLT_XKB_RULES_FILE; 8151568b75bSmrg 8161568b75bSmrg if (rfName[0] == '/') 8171568b75bSmrg { 8181568b75bSmrg rules = XkbRF_Load(rfName, svValue[LOCALE_NDX], True, True); 8191568b75bSmrg } 8201568b75bSmrg else 8211568b75bSmrg { 8221568b75bSmrg /* try to load rules files from all include paths until the first 8231568b75bSmrg * we succeed with */ 8241568b75bSmrg for (i = 0; (i < numInclPath) && (!rules); i++) 8251568b75bSmrg { 8261568b75bSmrg if ((strlen(inclPath[i]) + strlen(rfName) + 8) > PATH_MAX) 8271568b75bSmrg { 8281568b75bSmrg VMSG2(0, "Path too long (%s/rules/%s). Ignored.\n", 8291568b75bSmrg inclPath[i], rfName); 8301568b75bSmrg continue; 8311568b75bSmrg } 8321568b75bSmrg sprintf(buf, "%s/rules/%s", inclPath[i], svValue[RULES_NDX]); 8331568b75bSmrg rules = XkbRF_Load(buf, svValue[LOCALE_NDX], True, True); 8341568b75bSmrg } 8351568b75bSmrg } 8361568b75bSmrg if (!rules) 8371568b75bSmrg { 8381568b75bSmrg ERR1("Couldn't find rules file (%s) \n", svValue[RULES_NDX]); 8391568b75bSmrg return False; 8401568b75bSmrg } 8411568b75bSmrg /* Let the rules file to the magic, then update the svValues with 8421568b75bSmrg * those returned after processing the rules */ 8431568b75bSmrg XkbRF_GetComponents(rules, &rdefs, &rnames); 8441568b75bSmrg if (rnames.keycodes) 8451568b75bSmrg { 8461568b75bSmrg trySetString(KEYCODES_NDX, rnames.keycodes, FROM_RULES); 8471568b75bSmrg rnames.keycodes = NULL; 8481568b75bSmrg } 8491568b75bSmrg if (rnames.symbols) 8501568b75bSmrg { 8511568b75bSmrg trySetString(SYMBOLS_NDX, rnames.symbols, FROM_RULES); 8521568b75bSmrg rnames.symbols = NULL; 8531568b75bSmrg } 8541568b75bSmrg if (rnames.types) 8551568b75bSmrg { 8561568b75bSmrg trySetString(TYPES_NDX, rnames.types, FROM_RULES); 8571568b75bSmrg rnames.types = NULL; 8581568b75bSmrg } 8591568b75bSmrg if (rnames.compat) 8601568b75bSmrg { 8611568b75bSmrg trySetString(COMPAT_NDX, rnames.compat, FROM_RULES); 8621568b75bSmrg rnames.compat = NULL; 8631568b75bSmrg } 8641568b75bSmrg if (rnames.geometry) 8651568b75bSmrg { 8661568b75bSmrg trySetString(GEOMETRY_NDX, rnames.geometry, FROM_RULES); 8671568b75bSmrg rnames.geometry = NULL; 8681568b75bSmrg } 8691568b75bSmrg if (rnames.keymap) 8701568b75bSmrg { 8711568b75bSmrg trySetString(KEYMAP_NDX, rnames.keymap, FROM_RULES); 8721568b75bSmrg rnames.keymap = NULL; 8731568b75bSmrg } 8741568b75bSmrg if (verbose > 6) 8751568b75bSmrg { 8761568b75bSmrg MSG1("Applied rules from %s:\n", svValue[RULES_NDX]); 8771568b75bSmrg dumpNames(True, False); 8781568b75bSmrg } 8791568b75bSmrg } 8801568b75bSmrg else if (verbose > 6) 8811568b75bSmrg { 8821568b75bSmrg MSG("No rules variables specified. Rules file ignored\n"); 8837d5e3a19Smrg } 8847d5e3a19Smrg return True; 8857d5e3a19Smrg} 8867d5e3a19Smrg 8877d5e3a19Smrg/* Primitive sanity check - filter out 'map names' (inside parenthesis) */ 8887d5e3a19Smrg/* that can confuse xkbcomp parser */ 8891568b75bSmrgstatic Bool 8901568b75bSmrgcheckName(char *name, char *string) 8917d5e3a19Smrg{ 8921568b75bSmrg char *i = name, *opar = NULL; 8931568b75bSmrg Bool ret = True; 8941568b75bSmrg 8951568b75bSmrg if (!name) 8961568b75bSmrg return True; 8971568b75bSmrg 8981568b75bSmrg while (*i) 8991568b75bSmrg { 9001568b75bSmrg if (opar == NULL) 9011568b75bSmrg { 9021568b75bSmrg if (*i == '(') 9031568b75bSmrg opar = i; 9041568b75bSmrg } 9051568b75bSmrg else 9061568b75bSmrg { 9071568b75bSmrg if ((*i == '(') || (*i == '|') || (*i == '+')) 9081568b75bSmrg { 9091568b75bSmrg ret = False; 9101568b75bSmrg break; 9111568b75bSmrg } 9121568b75bSmrg if (*i == ')') 9131568b75bSmrg opar = NULL; 9141568b75bSmrg } 9151568b75bSmrg i++; 9161568b75bSmrg } 9171568b75bSmrg if (opar) 9181568b75bSmrg ret = False; 9191568b75bSmrg if (!ret) 9201568b75bSmrg { 9211568b75bSmrg char c; 9221568b75bSmrg int n = 1; 9231568b75bSmrg for (i = opar + 1; *i && n; i++) 9241568b75bSmrg { 9251568b75bSmrg if (*i == '(') 9261568b75bSmrg n++; 9271568b75bSmrg if (*i == ')') 9281568b75bSmrg n--; 9291568b75bSmrg } 9301568b75bSmrg if (*i) 9311568b75bSmrg i++; 9321568b75bSmrg c = *i; 9331568b75bSmrg *i = '\0'; 9341568b75bSmrg ERR1("Illegal map name '%s' ", opar); 9351568b75bSmrg *i = c; 9361568b75bSmrg ERR2("in %s name '%s'\n", string, name); 9371568b75bSmrg } 9381568b75bSmrg return ret; 9397d5e3a19Smrg} 9407d5e3a19Smrg 9417d5e3a19Smrgvoid 9427d5e3a19SmrgprintKeymap(void) 9437d5e3a19Smrg{ 9447d5e3a19Smrg MSG("xkb_keymap {\n"); 9457d5e3a19Smrg if (svValue[KEYCODES_NDX]) 9461568b75bSmrg MSG1("\txkb_keycodes { include \"%s\"\t};\n", svValue[KEYCODES_NDX]); 9477d5e3a19Smrg if (svValue[TYPES_NDX]) 9481568b75bSmrg MSG1("\txkb_types { include \"%s\"\t};\n", svValue[TYPES_NDX]); 9497d5e3a19Smrg if (svValue[COMPAT_NDX]) 9501568b75bSmrg MSG1("\txkb_compat { include \"%s\"\t};\n", svValue[COMPAT_NDX]); 9517d5e3a19Smrg if (svValue[SYMBOLS_NDX]) 9521568b75bSmrg MSG1("\txkb_symbols { include \"%s\"\t};\n", svValue[SYMBOLS_NDX]); 9537d5e3a19Smrg if (svValue[GEOMETRY_NDX]) 9541568b75bSmrg MSG1("\txkb_geometry { include \"%s\"\t};\n", svValue[GEOMETRY_NDX]); 9557d5e3a19Smrg MSG("};\n"); 9567d5e3a19Smrg} 9577d5e3a19Smrg 9587d5e3a19SmrgBool 9597d5e3a19SmrgapplyComponentNames(void) 9607d5e3a19Smrg{ 9611568b75bSmrg if (!checkName(svValue[TYPES_NDX], "types")) 9621568b75bSmrg return False; 9631568b75bSmrg if (!checkName(svValue[COMPAT_NDX], "compat")) 9641568b75bSmrg return False; 9651568b75bSmrg if (!checkName(svValue[SYMBOLS_NDX], "symbols")) 9661568b75bSmrg return False; 9671568b75bSmrg if (!checkName(svValue[KEYCODES_NDX], "keycodes")) 9681568b75bSmrg return False; 9691568b75bSmrg if (!checkName(svValue[GEOMETRY_NDX], "geometry")) 9701568b75bSmrg return False; 9711568b75bSmrg if (!checkName(svValue[KEYMAP_NDX], "keymap")) 9721568b75bSmrg return False; 9731568b75bSmrg 9741568b75bSmrg if (verbose > 5) 9751568b75bSmrg { 9761568b75bSmrg MSG("Trying to build keymap using the following components:\n"); 9771568b75bSmrg dumpNames(False, True); 9781568b75bSmrg } 9791568b75bSmrg /* Upload the new description to the server. */ 9801568b75bSmrg if (dpy && !print) 9811568b75bSmrg { 9821568b75bSmrg XkbComponentNamesRec cmdNames; 9831568b75bSmrg cmdNames.types = svValue[TYPES_NDX]; 9841568b75bSmrg cmdNames.compat = svValue[COMPAT_NDX]; 9851568b75bSmrg cmdNames.symbols = svValue[SYMBOLS_NDX]; 9861568b75bSmrg cmdNames.keycodes = svValue[KEYCODES_NDX]; 9871568b75bSmrg cmdNames.geometry = svValue[GEOMETRY_NDX]; 9881568b75bSmrg cmdNames.keymap = svValue[KEYMAP_NDX]; 9891568b75bSmrg xkb = XkbGetKeyboardByName(dpy, deviceSpec, &cmdNames, 9901568b75bSmrg XkbGBN_AllComponentsMask, 9911568b75bSmrg XkbGBN_AllComponentsMask & 9921568b75bSmrg (~XkbGBN_GeometryMask), True); 9931568b75bSmrg if (!xkb) 9941568b75bSmrg { 9951568b75bSmrg ERR("Error loading new keyboard description\n"); 9961568b75bSmrg return False; 9971568b75bSmrg } 9981568b75bSmrg /* update the XKB root property */ 9991568b75bSmrg if (svValue[RULES_NDX] && (rdefs.model || rdefs.layout)) 10001568b75bSmrg { 10011568b75bSmrg if (!XkbRF_SetNamesProp(dpy, svValue[RULES_NDX], &rdefs)) 10021568b75bSmrg { 10031568b75bSmrg VMSG(0, "Error updating the XKB names property\n"); 10041568b75bSmrg } 10051568b75bSmrg } 10061568b75bSmrg } 10071568b75bSmrg if (print) 10081568b75bSmrg { 10097d5e3a19Smrg printKeymap(); 10107d5e3a19Smrg } 10117d5e3a19Smrg return True; 10127d5e3a19Smrg} 10137d5e3a19Smrg 10147d5e3a19Smrg 10157d5e3a19Smrgint 10161568b75bSmrgmain(int argc, char **argv) 10177d5e3a19Smrg{ 10181568b75bSmrg if ((!parseArgs(argc, argv)) || (!getDisplay(argc, argv))) 10191568b75bSmrg exit(-1); 10201568b75bSmrg svValue[LOCALE_NDX] = setlocale(LC_ALL, svValue[LOCALE_NDX]); 10211568b75bSmrg svSrc[LOCALE_NDX] = FROM_SERVER; 10221568b75bSmrg VMSG1(7, "locale is %s\n", svValue[LOCALE_NDX]); 10237d5e3a19Smrg if (dpy) 10247d5e3a19Smrg getServerValues(); 10257d5e3a19Smrg if (svValue[CONFIG_NDX] && (!applyConfig(svValue[CONFIG_NDX]))) 10261568b75bSmrg exit(-3); 10277d5e3a19Smrg if (!applyRules()) 10281568b75bSmrg exit(-4); 10297d5e3a19Smrg if (!applyComponentNames()) 10301568b75bSmrg exit(-5); 10317d5e3a19Smrg if (dpy) 10321568b75bSmrg XCloseDisplay(dpy); 10337d5e3a19Smrg exit(0); 10347d5e3a19Smrg} 1035