setxkbmap.c revision b8414663
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 9bda5b58fSmrg documentation, and that the name of Silicon Graphics not be 10bda5b58fSmrg used in advertising or publicity pertaining to distribution 117d5e3a19Smrg of the software without specific prior written permission. 12bda5b58fSmrg 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. 15bda5b58fSmrg 16bda5b58fSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 17bda5b58fSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 187d5e3a19Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 19bda5b58fSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 20bda5b58fSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21bda5b58fSmrg 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 27b8414663Smrg#ifdef HAVE_CONFIG_H 28b8414663Smrg#include "config.h" 29b8414663Smrg#endif 307d5e3a19Smrg#include <stdio.h> 317d5e3a19Smrg#include <stdlib.h> 327d5e3a19Smrg#include <locale.h> 337d5e3a19Smrg#include <limits.h> 347d5e3a19Smrg#include <ctype.h> 357d5e3a19Smrg#include <X11/Xlib.h> 367d5e3a19Smrg#include <X11/Xos.h> 377d5e3a19Smrg#include <X11/XKBlib.h> 387d5e3a19Smrg#include <X11/extensions/XKBfile.h> 397d5e3a19Smrg#include <X11/extensions/XKBconfig.h> 407d5e3a19Smrg#include <X11/extensions/XKBrules.h> 417d5e3a19Smrg 427d5e3a19Smrg#ifndef PATH_MAX 437d5e3a19Smrg#ifdef MAXPATHLEN 447d5e3a19Smrg#define PATH_MAX MAXPATHLEN 457d5e3a19Smrg#else 467d5e3a19Smrg#define PATH_MAX 1024 477d5e3a19Smrg#endif 487d5e3a19Smrg#endif 497d5e3a19Smrg 507d5e3a19Smrg#ifndef DFLT_XKB_CONFIG_ROOT 51bda5b58fSmrg#define DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb" 527d5e3a19Smrg#endif 537d5e3a19Smrg#ifndef DFLT_XKB_RULES_FILE 54bda5b58fSmrg#define DFLT_XKB_RULES_FILE "base" 557d5e3a19Smrg#endif 567d5e3a19Smrg#ifndef DFLT_XKB_LAYOUT 57bda5b58fSmrg#define DFLT_XKB_LAYOUT "us" 587d5e3a19Smrg#endif 597d5e3a19Smrg#ifndef DFLT_XKB_MODEL 60bda5b58fSmrg#define DFLT_XKB_MODEL "pc105" 617d5e3a19Smrg#endif 627d5e3a19Smrg 63bda5b58fSmrg/* Constants to state how a value was obtained. The order of these 641568b75bSmrg * is important, the bigger the higher the priority. 651568b75bSmrg * e.g. FROM_CONFIG overrides FROM_SERVER */ 66bda5b58fSmrgenum source { 67bda5b58fSmrg UNDEFINED = 0, 68bda5b58fSmrg FROM_SERVER, /* Retrieved from server at runtime. */ 69bda5b58fSmrg FROM_RULES, /* Xkb rules file. */ 70bda5b58fSmrg FROM_CONFIG, /* Command-line specified config file. */ 71bda5b58fSmrg FROM_CMD_LINE, /* Specified at the cmdline. */ 72bda5b58fSmrg NUM_SOURCES 73bda5b58fSmrg}; 747d5e3a19Smrg 757d5e3a19Smrg/***====================================================================***/ 761568b75bSmrgstatic Bool print = False; 77765486e8Smrgstatic Bool query = False; 781568b75bSmrgstatic Bool synch = False; 791568b75bSmrgstatic int verbose = 5; 801568b75bSmrg 811568b75bSmrgstatic Display *dpy; 821568b75bSmrg 831568b75bSmrg/** 841568b75bSmrg * human-readable versions of FROM_CONFIG, FROM_SERVER, etc. Used for error 851568b75bSmrg * reporting. 861568b75bSmrg */ 87bda5b58fSmrgstatic const char *srcName[NUM_SOURCES] = { 881568b75bSmrg "undefined", "X server", "rules file", "config file", "command line" 897d5e3a19Smrg}; 907d5e3a19Smrg 91bda5b58fSmrgstruct setting { 92bda5b58fSmrg char const *name; /* Human-readable setting name. Used for error reporting. */ 93bda5b58fSmrg char *value; /* Holds the value. */ 94bda5b58fSmrg enum source src; /* Holds the source. */ 95bda5b58fSmrg}; 96bda5b58fSmrg 97bda5b58fSmrgtypedef struct setting setting_t; 98bda5b58fSmrg 99bda5b58fSmrgstruct settings { 100bda5b58fSmrg setting_t rules; /* Rules file */ 101bda5b58fSmrg setting_t config; /* Config file (if used) */ 102bda5b58fSmrg setting_t display; /* X display name */ 103bda5b58fSmrg setting_t locale; /* Machine's locale */ 104bda5b58fSmrg setting_t model; 105bda5b58fSmrg setting_t layout; 106bda5b58fSmrg setting_t variant; 107bda5b58fSmrg setting_t keycodes; 108bda5b58fSmrg setting_t types; 109bda5b58fSmrg setting_t compat; 110bda5b58fSmrg setting_t symbols; 111bda5b58fSmrg setting_t geometry; 112bda5b58fSmrg setting_t keymap; 113bda5b58fSmrg}; 114bda5b58fSmrg 115bda5b58fSmrgtypedef struct settings settings_t; 116bda5b58fSmrg 117bda5b58fSmrgstatic settings_t settings = { 118bda5b58fSmrg { "rules file", NULL, UNDEFINED }, 119bda5b58fSmrg { "config file", NULL, UNDEFINED }, 120bda5b58fSmrg { "X display", NULL, UNDEFINED }, 121bda5b58fSmrg { "locale", NULL, UNDEFINED }, 122bda5b58fSmrg { "keyboard model", NULL, UNDEFINED }, 123bda5b58fSmrg { "keyboard layout", NULL, UNDEFINED }, 124bda5b58fSmrg { "layout variant", NULL, UNDEFINED }, 125bda5b58fSmrg { "keycodes", NULL, UNDEFINED }, 126bda5b58fSmrg { "types", NULL, UNDEFINED }, 127bda5b58fSmrg { "compatibility map", NULL, UNDEFINED }, 128bda5b58fSmrg { "symbols", NULL, UNDEFINED }, 129bda5b58fSmrg { "geometry", NULL, UNDEFINED }, 130bda5b58fSmrg { "keymap", NULL, UNDEFINED } 1317d5e3a19Smrg}; 1327d5e3a19Smrg 1331568b75bSmrgstatic XkbConfigRtrnRec cfgResult; 1347d5e3a19Smrg 1351568b75bSmrgstatic XkbRF_VarDefsRec rdefs; 1367d5e3a19Smrg 1371568b75bSmrgstatic Bool clearOptions = False; 1387d5e3a19Smrg 139bda5b58fSmrgstruct list { 140bda5b58fSmrg char **item; /* Array of items. */ 141bda5b58fSmrg int sz; /* Size of array. */ 142bda5b58fSmrg int num; /* Number of used elements. */ 143bda5b58fSmrg}; 144bda5b58fSmrg 145bda5b58fSmrgtypedef struct list list_t; 146bda5b58fSmrg 147bda5b58fSmrgstatic list_t options = { NULL, 0, 0 }; 148bda5b58fSmrg 149bda5b58fSmrgstatic list_t inclPath = { NULL, 0, 0 }; 1507d5e3a19Smrg 1511568b75bSmrgstatic XkbDescPtr xkb = NULL; 1527d5e3a19Smrg 1531568b75bSmrgstatic int deviceSpec = XkbUseCoreKbd; 1547d5e3a19Smrg 1557d5e3a19Smrg/***====================================================================***/ 1567d5e3a19Smrg 157bda5b58fSmrg#define streq(s1,s2) (strcmp(s1,s2)==0) 158bda5b58fSmrg#define strpfx(s1,s2) (strncmp(s1,s2,strlen(s2))==0) 159bda5b58fSmrg 160bda5b58fSmrg#define MSG(s) printf(s) 161bda5b58fSmrg#define MSG1(s,a) printf(s,a) 162bda5b58fSmrg#define MSG2(s,a,b) printf(s,a,b) 163bda5b58fSmrg#define MSG3(s,a,b,c) printf(s,a,b,c) 1647d5e3a19Smrg 165bda5b58fSmrg#define VMSG(l,s) if (verbose>(l)) printf(s) 166bda5b58fSmrg#define VMSG1(l,s,a) if (verbose>(l)) printf(s,a) 167bda5b58fSmrg#define VMSG2(l,s,a,b) if (verbose>(l)) printf(s,a,b) 168bda5b58fSmrg#define VMSG3(l,s,a,b,c) if (verbose>(l)) printf(s,a,b,c) 1697d5e3a19Smrg 170bda5b58fSmrg#define ERR(s) fprintf(stderr,s) 171bda5b58fSmrg#define ERR1(s,a) fprintf(stderr,s,a) 172bda5b58fSmrg#define ERR2(s,a,b) fprintf(stderr,s,a,b) 173bda5b58fSmrg#define ERR3(s,a,b,c) fprintf(stderr,s,a,b,c) 1747d5e3a19Smrg 175bda5b58fSmrg#define OOM(ptr) do { if ((ptr) == NULL) { ERR("Out of memory.\n"); exit(-1); } } while (0) 1767d5e3a19Smrg 1777d5e3a19Smrg/***====================================================================***/ 1787d5e3a19Smrg 179bda5b58fSmrgBool addToList(list_t *list, const char *newVal); 1801568b75bSmrgvoid usage(int argc, char **argv); 1811568b75bSmrgvoid dumpNames(Bool wantRules, Bool wantCNames); 182bda5b58fSmrgvoid trySetString(setting_t * setting, char *newVal, enum source src); 183bda5b58fSmrgBool setOptString(int *arg, int argc, char **argv, setting_t *setting, enum source src); 1841568b75bSmrgint parseArgs(int argc, char **argv); 1851568b75bSmrgBool getDisplay(int argc, char **argv); 1861568b75bSmrgBool getServerValues(void); 187bda5b58fSmrgFILE *findFileInPath(char *name); 188bda5b58fSmrgBool addStringToOptions(char *opt_str, list_t *opts); 189bda5b58fSmrgchar *stringFromOptions(char *orig, list_t *newOpts); 1901568b75bSmrgBool applyConfig(char *name); 191bda5b58fSmrgXkbRF_RulesPtr tryLoadRules(char *name, char *locale, Bool wantDesc, Bool wantRules); 1921568b75bSmrgBool applyRules(void); 1931568b75bSmrgBool applyComponentNames(void); 1941568b75bSmrgvoid printKeymap(void); 1957d5e3a19Smrg 1967d5e3a19Smrg/***====================================================================***/ 1977d5e3a19Smrg 198bda5b58fSmrg/* 199bda5b58fSmrg If newVal is NULL or empty string, the list is cleared. 200bda5b58fSmrg Otherwise newVal is added to the end of the list (if it is not present in the list yet). 201bda5b58fSmrg*/ 202bda5b58fSmrg 2037d5e3a19SmrgBool 204bda5b58fSmrgaddToList(list_t *list, const char *newVal) 2057d5e3a19Smrg{ 2061568b75bSmrg register int i; 2071568b75bSmrg 2081568b75bSmrg if ((!newVal) || (!newVal[0])) 2091568b75bSmrg { 210bda5b58fSmrg list->num = 0; 2111568b75bSmrg return True; 2121568b75bSmrg } 213bda5b58fSmrg for (i = 0; i < list->num; i++) 2141568b75bSmrg { 215bda5b58fSmrg if (streq(list->item[i], newVal)) 2161568b75bSmrg return True; 2171568b75bSmrg } 218bda5b58fSmrg if ((list->item == NULL) || (list->sz < 1)) 2191568b75bSmrg { 220bda5b58fSmrg list->num = 0; 221bda5b58fSmrg list->sz = 4; 222bda5b58fSmrg list->item = (char **) calloc(list->sz, sizeof(char *)); 223bda5b58fSmrg OOM(list->item); 2241568b75bSmrg } 225bda5b58fSmrg else if (list->num >= list->sz) 2261568b75bSmrg { 227bda5b58fSmrg list->sz *= 2; 228bda5b58fSmrg list->item = (char **) realloc(list->item, (list->sz) * sizeof(char *)); 229bda5b58fSmrg OOM(list->item); 2301568b75bSmrg } 231bda5b58fSmrg list->item[list->num] = strdup(newVal); 232bda5b58fSmrg OOM(list->item[list->num]); 233bda5b58fSmrg list->num += 1; 2347d5e3a19Smrg return True; 2357d5e3a19Smrg} 2367d5e3a19Smrg 2377d5e3a19Smrg/***====================================================================***/ 2387d5e3a19Smrg 2397d5e3a19Smrgvoid 2401568b75bSmrgusage(int argc, char **argv) 2417d5e3a19Smrg{ 242bda5b58fSmrg MSG1( 243bda5b58fSmrg "Usage: %s [options] [<layout> [<variant> [<option> ... ]]]\n" 244bda5b58fSmrg "Options:\n" 245bda5b58fSmrg " -?, -help Print this message\n" 246bda5b58fSmrg " -compat <name> Specifies compatibility map component name\n" 247bda5b58fSmrg " -config <file> Specifies configuration file to use\n" 248bda5b58fSmrg " -device <deviceid> Specifies the device ID to use\n" 249bda5b58fSmrg " -display <dpy> Specifies display to use\n" 250bda5b58fSmrg " -geometry <name> Specifies geometry component name\n" 251b8414663Smrg " -I <dir> Add <dir> to list of directories to be used\n" 252bda5b58fSmrg " -keycodes <name> Specifies keycodes component name\n" 253bda5b58fSmrg " -keymap <name> Specifies name of keymap to load\n" 254bda5b58fSmrg " -layout <name> Specifies layout used to choose component names\n" 255bda5b58fSmrg " -model <name> Specifies model used to choose component names\n" 256bda5b58fSmrg " -option <name> Adds an option used to choose component names\n" 257bda5b58fSmrg " -print Print a complete xkb_keymap description and exit\n" 258bda5b58fSmrg " -query Print the current layout settings and exit\n" 259bda5b58fSmrg " -rules <name> Name of rules file to use\n" 260bda5b58fSmrg " -symbols <name> Specifies symbols component name\n" 261bda5b58fSmrg " -synch Synchronize request with X server\n" 262bda5b58fSmrg " -types <name> Specifies types component name\n" 263b8414663Smrg " -v[erbose] [<lvl>] Sets verbosity (1..10); higher values yield more messages\n" 264b8414663Smrg " -version Print the program's version number\n" 265bda5b58fSmrg " -variant <name> Specifies layout variant used to choose component names\n", 266bda5b58fSmrg argv[0] 267bda5b58fSmrg ); 2687d5e3a19Smrg} 2697d5e3a19Smrg 2707d5e3a19Smrgvoid 2711568b75bSmrgdumpNames(Bool wantRules, Bool wantCNames) 2727d5e3a19Smrg{ 2731568b75bSmrg if (wantRules) 2741568b75bSmrg { 275bda5b58fSmrg if (settings.rules.value) 276bda5b58fSmrg MSG1("rules: %s\n", settings.rules.value); 277bda5b58fSmrg if (settings.model.value) 278bda5b58fSmrg MSG1("model: %s\n", settings.model.value); 279bda5b58fSmrg if (settings.layout.value) 280bda5b58fSmrg MSG1("layout: %s\n", settings.layout.value); 281bda5b58fSmrg if (settings.variant.value) 282bda5b58fSmrg MSG1("variant: %s\n", settings.variant.value); 283bda5b58fSmrg if (options.item) 2841568b75bSmrg { 285bda5b58fSmrg char *opt_str = stringFromOptions(NULL, &options); 2861568b75bSmrg MSG1("options: %s\n", opt_str); 2871568b75bSmrg free(opt_str); 2881568b75bSmrg } 2891568b75bSmrg } 2901568b75bSmrg if (wantCNames) 2911568b75bSmrg { 292bda5b58fSmrg if (settings.keymap.value) 293bda5b58fSmrg MSG1("keymap: %s\n", settings.keymap.value); 294bda5b58fSmrg if (settings.keycodes.value) 295bda5b58fSmrg MSG1("keycodes: %s\n", settings.keycodes.value); 296bda5b58fSmrg if (settings.types.value) 297bda5b58fSmrg MSG1("types: %s\n", settings.types.value); 298bda5b58fSmrg if (settings.compat.value) 299bda5b58fSmrg MSG1("compat: %s\n", settings.compat.value); 300bda5b58fSmrg if (settings.symbols.value) 301bda5b58fSmrg MSG1("symbols: %s\n", settings.symbols.value); 302bda5b58fSmrg if (settings.geometry.value) 303bda5b58fSmrg MSG1("geometry: %s\n", settings.geometry.value); 3047d5e3a19Smrg } 3057d5e3a19Smrg return; 3067d5e3a19Smrg} 3077d5e3a19Smrg 3087d5e3a19Smrg/***====================================================================***/ 3097d5e3a19Smrg 3101568b75bSmrg/** 3111568b75bSmrg * Set the given string (obtained from src) in the svValue/svSrc globals. 3121568b75bSmrg * If the given item is already set, it is overridden if the original source 3131568b75bSmrg * is less significant than the given one. 3141568b75bSmrg * 3151568b75bSmrg * @param which What value is it (one of RULES_NDX, CONFIG_NDX, ...) 3161568b75bSmrg */ 3177d5e3a19Smrgvoid 318bda5b58fSmrgtrySetString(setting_t *setting, char *newVal, enum source src) 3197d5e3a19Smrg{ 320bda5b58fSmrg if (setting->value != NULL) 3211568b75bSmrg { 322bda5b58fSmrg if (setting->src == src) 3231568b75bSmrg { 3241568b75bSmrg VMSG2(0, "Warning! More than one %s from %s\n", 325bda5b58fSmrg setting->name, srcName[src]); 3261568b75bSmrg VMSG2(0, " Using \"%s\", ignoring \"%s\"\n", 327bda5b58fSmrg setting->value, newVal); 3281568b75bSmrg return; 3291568b75bSmrg } 330bda5b58fSmrg else if (setting->src > src) 3311568b75bSmrg { 332bda5b58fSmrg VMSG1(5, "Warning! Multiple definitions of %s\n", setting->name); 3331568b75bSmrg VMSG2(5, " Using %s, ignoring %s\n", 334bda5b58fSmrg srcName[setting->src], srcName[src]); 3351568b75bSmrg return; 3361568b75bSmrg } 3371568b75bSmrg } 338bda5b58fSmrg setting->src = src; 339bda5b58fSmrg setting->value = newVal; 3407d5e3a19Smrg return; 3417d5e3a19Smrg} 3427d5e3a19Smrg 3437d5e3a19SmrgBool 344bda5b58fSmrgsetOptString(int *arg, int argc, char **argv, setting_t *setting, enum source src) 3457d5e3a19Smrg{ 3461568b75bSmrg int ndx; 3471568b75bSmrg char *opt; 3481568b75bSmrg 3491568b75bSmrg ndx = *arg; 3501568b75bSmrg opt = argv[ndx]; 3511568b75bSmrg if (ndx >= argc - 1) 3521568b75bSmrg { 353bda5b58fSmrg VMSG1(0, "No %s specified on the command line\n", setting->name); 3541568b75bSmrg VMSG1(0, "Trailing %s option ignored\n", opt); 3551568b75bSmrg return True; 3567d5e3a19Smrg } 3577d5e3a19Smrg ndx++; 3581568b75bSmrg *arg = ndx; 359bda5b58fSmrg if (setting->value != NULL) 3601568b75bSmrg { 361bda5b58fSmrg if (setting->src == src) 3621568b75bSmrg { 363bda5b58fSmrg VMSG2(0, "More than one %s on %s\n", setting->name, srcName[src]); 364bda5b58fSmrg VMSG2(0, "Using \"%s\", ignoring \"%s\"\n", setting->value, 3651568b75bSmrg argv[ndx]); 3661568b75bSmrg return True; 3671568b75bSmrg } 368bda5b58fSmrg else if (setting->src > src) 3691568b75bSmrg { 370bda5b58fSmrg VMSG1(5, "Multiple definitions of %s\n", setting->name); 371bda5b58fSmrg VMSG2(5, "Using %s, ignoring %s\n", srcName[setting->src], 3721568b75bSmrg srcName[src]); 3731568b75bSmrg return True; 3741568b75bSmrg } 3751568b75bSmrg } 376bda5b58fSmrg setting->src = src; 377bda5b58fSmrg setting->value = argv[ndx]; 3787d5e3a19Smrg return True; 3797d5e3a19Smrg} 3807d5e3a19Smrg 3817d5e3a19Smrg/***====================================================================***/ 3827d5e3a19Smrg 3831568b75bSmrg/** 3841568b75bSmrg * Parse commandline arguments. 3851568b75bSmrg * Return True on success or False if an unrecognized option has been 3861568b75bSmrg * specified. 3871568b75bSmrg */ 3887d5e3a19Smrgint 3891568b75bSmrgparseArgs(int argc, char **argv) 3907d5e3a19Smrg{ 3911568b75bSmrg int i; 3921568b75bSmrg Bool ok; 3931568b75bSmrg unsigned present; 3941568b75bSmrg 3951568b75bSmrg ok = True; 396bda5b58fSmrg addToList(&inclPath, "."); 397bda5b58fSmrg addToList(&inclPath, DFLT_XKB_CONFIG_ROOT); 3981568b75bSmrg for (i = 1; (i < argc) && ok; i++) 3991568b75bSmrg { 4001568b75bSmrg if (argv[i][0] != '-') 4011568b75bSmrg { 4021568b75bSmrg /* Allow a call like "setxkbmap us" to work. Layout is default, 4031568b75bSmrg if -layout is given, then try parsing variant, then options */ 404bda5b58fSmrg if (!settings.layout.src) 405bda5b58fSmrg trySetString(&settings.layout, argv[i], FROM_CMD_LINE); 406bda5b58fSmrg else if (!settings.variant.src) 407bda5b58fSmrg trySetString(&settings.variant, argv[i], FROM_CMD_LINE); 4081568b75bSmrg else 409bda5b58fSmrg ok = addToList(&options, argv[i]); 4101568b75bSmrg } 4111568b75bSmrg else if (streq(argv[i], "-compat")) 412bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.compat, FROM_CMD_LINE); 4131568b75bSmrg else if (streq(argv[i], "-config")) 414bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.config, FROM_CMD_LINE); 4151568b75bSmrg else if (streq(argv[i], "-device")) 416bda5b58fSmrg { 417bda5b58fSmrg if ( ++i < argc ) { 418bda5b58fSmrg deviceSpec = atoi(argv[i]); /* only allow device IDs, not names */ 419bda5b58fSmrg } else { 420bda5b58fSmrg usage(argc, argv); 421bda5b58fSmrg exit(-1); 422bda5b58fSmrg } 423bda5b58fSmrg } 4241568b75bSmrg else if (streq(argv[i], "-display")) 425bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.display, FROM_CMD_LINE); 4261568b75bSmrg else if (streq(argv[i], "-geometry")) 427bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.geometry, FROM_CMD_LINE); 4281568b75bSmrg else if (streq(argv[i], "-help") || streq(argv[i], "-?")) 4291568b75bSmrg { 4301568b75bSmrg usage(argc, argv); 4311568b75bSmrg exit(0); 4321568b75bSmrg } 433bda5b58fSmrg else if (streq(argv[i], "-I")) /* space between -I and path */ 434bda5b58fSmrg { 435bda5b58fSmrg if ( ++i < argc ) 436bda5b58fSmrg ok = addToList(&inclPath, argv[i]); 437bda5b58fSmrg else 438bda5b58fSmrg VMSG(0, "No directory specified on the command line\n" 439bda5b58fSmrg "Trailing -I option ignored\n"); 440bda5b58fSmrg } 441bda5b58fSmrg else if (strpfx(argv[i], "-I")) /* no space between -I and path */ 442bda5b58fSmrg ok = addToList(&inclPath, &argv[i][2]); 4431568b75bSmrg else if (streq(argv[i], "-keycodes")) 444bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.keycodes, FROM_CMD_LINE); 4451568b75bSmrg else if (streq(argv[i], "-keymap")) 446bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.keymap, FROM_CMD_LINE); 4471568b75bSmrg else if (streq(argv[i], "-layout")) 448bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.layout, FROM_CMD_LINE); 4491568b75bSmrg else if (streq(argv[i], "-model")) 450bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.model, FROM_CMD_LINE); 4511568b75bSmrg else if (streq(argv[i], "-option")) 4521568b75bSmrg { 4531568b75bSmrg if ((i == argc - 1) || (argv[i + 1][0] == '\0') 4541568b75bSmrg || (argv[i + 1][0] == '-')) 4551568b75bSmrg { 4561568b75bSmrg clearOptions = True; 457bda5b58fSmrg ok = addToList(&options, ""); 4581568b75bSmrg if (i < argc - 1 && argv[i + 1][0] == '\0') 4591568b75bSmrg i++; 4601568b75bSmrg } 4611568b75bSmrg else 4621568b75bSmrg { 463bda5b58fSmrg ok = addToList(&options, argv[++i]); 4641568b75bSmrg } 4651568b75bSmrg } 4661568b75bSmrg else if (streq(argv[i], "-print")) 4671568b75bSmrg print = True; 468765486e8Smrg else if (streq(argv[i], "-query")) 469765486e8Smrg query = True; 4701568b75bSmrg else if (streq(argv[i], "-rules")) 471bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.rules, FROM_CMD_LINE); 4721568b75bSmrg else if (streq(argv[i], "-symbols")) 473bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.symbols, FROM_CMD_LINE); 4741568b75bSmrg else if (streq(argv[i], "-synch")) 4751568b75bSmrg synch = True; 4761568b75bSmrg else if (streq(argv[i], "-types")) 477bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.types, FROM_CMD_LINE); 478b8414663Smrg else if (streq(argv[i], "-version")) 479b8414663Smrg { 480b8414663Smrg MSG1("setxkbmap %s\n", PACKAGE_VERSION); 481b8414663Smrg exit(0); 482b8414663Smrg } 4831568b75bSmrg else if (streq(argv[i], "-verbose") || (streq(argv[i], "-v"))) 4841568b75bSmrg { 4851568b75bSmrg if ((i < argc - 1) && (isdigit(argv[i + 1][0]))) 4861568b75bSmrg verbose = atoi(argv[++i]); 4871568b75bSmrg else 4881568b75bSmrg verbose++; 4891568b75bSmrg if (verbose < 0) 4901568b75bSmrg { 4911568b75bSmrg ERR1("Illegal verbose level %d. Reset to 0\n", verbose); 4921568b75bSmrg verbose = 0; 4931568b75bSmrg } 4941568b75bSmrg else if (verbose > 10) 4951568b75bSmrg { 4961568b75bSmrg ERR1("Illegal verbose level %d. Reset to 10\n", verbose); 4971568b75bSmrg verbose = 10; 4981568b75bSmrg } 4991568b75bSmrg VMSG1(7, "Setting verbose level to %d\n", verbose); 5001568b75bSmrg } 5011568b75bSmrg else if (streq(argv[i], "-variant")) 502bda5b58fSmrg ok = setOptString(&i, argc, argv, &settings.variant, FROM_CMD_LINE); 5031568b75bSmrg else 5041568b75bSmrg { 5051568b75bSmrg ERR1("Error! Option \"%s\" not recognized\n", argv[i]); 5061568b75bSmrg ok = False; 5071568b75bSmrg } 5081568b75bSmrg } 5091568b75bSmrg 5101568b75bSmrg present = 0; 511bda5b58fSmrg if (settings.types.value) 5121568b75bSmrg present++; 513bda5b58fSmrg if (settings.compat.value) 5141568b75bSmrg present++; 515bda5b58fSmrg if (settings.symbols.value) 5161568b75bSmrg present++; 517bda5b58fSmrg if (settings.keycodes.value) 5181568b75bSmrg present++; 519bda5b58fSmrg if (settings.geometry.value) 5201568b75bSmrg present++; 521bda5b58fSmrg if (settings.config.value) 5221568b75bSmrg present++; 523bda5b58fSmrg if (settings.model.value) 5241568b75bSmrg present++; 525bda5b58fSmrg if (settings.layout.value) 5261568b75bSmrg present++; 527bda5b58fSmrg if (settings.variant.value) 5281568b75bSmrg present++; 529bda5b58fSmrg if (settings.keymap.value && present) 5301568b75bSmrg { 5311568b75bSmrg ERR("No other components can be specified when a keymap is present\n"); 5321568b75bSmrg return False; 5337d5e3a19Smrg } 5347d5e3a19Smrg return ok; 5357d5e3a19Smrg} 5367d5e3a19Smrg 5371568b75bSmrg/** 5381568b75bSmrg * Open a connection to the display and print error if it fails. 5391568b75bSmrg * 5401568b75bSmrg * @return True on success or False otherwise. 5411568b75bSmrg */ 5427d5e3a19SmrgBool 5431568b75bSmrggetDisplay(int argc, char **argv) 5447d5e3a19Smrg{ 5451568b75bSmrg int major, minor, why; 5461568b75bSmrg 5471568b75bSmrg major = XkbMajorVersion; 5481568b75bSmrg minor = XkbMinorVersion; 5491568b75bSmrg dpy = 550bda5b58fSmrg XkbOpenDisplay(settings.display.value, NULL, NULL, &major, &minor, 5511568b75bSmrg &why); 5521568b75bSmrg if (!dpy) 5531568b75bSmrg { 554bda5b58fSmrg if (settings.display.value == NULL) 555bda5b58fSmrg settings.display.value = getenv("DISPLAY"); 556bda5b58fSmrg if (settings.display.value == NULL) 557bda5b58fSmrg settings.display.value = "default display"; 5581568b75bSmrg switch (why) 5591568b75bSmrg { 5601568b75bSmrg case XkbOD_BadLibraryVersion: 5611568b75bSmrg ERR3("%s was compiled with XKB version %d.%02d\n", argv[0], 5621568b75bSmrg XkbMajorVersion, XkbMinorVersion); 5631568b75bSmrg ERR2("Xlib supports incompatible version %d.%02d\n", 5641568b75bSmrg major, minor); 5651568b75bSmrg break; 5661568b75bSmrg case XkbOD_ConnectionRefused: 567bda5b58fSmrg ERR1("Cannot open display \"%s\"\n", settings.display.value); 5681568b75bSmrg break; 5691568b75bSmrg case XkbOD_NonXkbServer: 570bda5b58fSmrg ERR1("XKB extension not present on %s\n", settings.display.value); 5711568b75bSmrg break; 5721568b75bSmrg case XkbOD_BadServerVersion: 5731568b75bSmrg ERR3("%s was compiled with XKB version %d.%02d\n", argv[0], 5741568b75bSmrg XkbMajorVersion, XkbMinorVersion); 5751568b75bSmrg ERR3("Server %s uses incompatible version %d.%02d\n", 576bda5b58fSmrg settings.display.value, major, minor); 5771568b75bSmrg break; 5781568b75bSmrg default: 5791568b75bSmrg ERR1("Unknown error %d from XkbOpenDisplay\n", why); 5801568b75bSmrg break; 5811568b75bSmrg } 5821568b75bSmrg return False; 5837d5e3a19Smrg } 5847d5e3a19Smrg if (synch) 5851568b75bSmrg XSynchronize(dpy, True); 5867d5e3a19Smrg return True; 5877d5e3a19Smrg} 5887d5e3a19Smrg 5897d5e3a19Smrg/***====================================================================***/ 5907d5e3a19Smrg 5911568b75bSmrg/** 592765486e8Smrg * Retrieve xkb values from the XKB_RULES_NAMES property and store their 5931568b75bSmrg * contents in svValues. 5941568b75bSmrg * If the property cannot be read, the built-in defaults are used. 5951568b75bSmrg * 5961568b75bSmrg * @return True. 5971568b75bSmrg */ 5987d5e3a19SmrgBool 5997d5e3a19SmrggetServerValues(void) 6007d5e3a19Smrg{ 6011568b75bSmrg XkbRF_VarDefsRec vd; 6021568b75bSmrg char *tmp = NULL; 6037d5e3a19Smrg 6041568b75bSmrg if (!XkbRF_GetNamesProp(dpy, &tmp, &vd) || !tmp) 6051568b75bSmrg { 6061568b75bSmrg VMSG1(3, "Couldn't interpret %s property\n", _XKB_RF_NAMES_PROP_ATOM); 6077d5e3a19Smrg tmp = DFLT_XKB_RULES_FILE; 6087d5e3a19Smrg vd.model = DFLT_XKB_MODEL; 6097d5e3a19Smrg vd.layout = DFLT_XKB_LAYOUT; 6107d5e3a19Smrg vd.variant = NULL; 6117d5e3a19Smrg vd.options = NULL; 6121568b75bSmrg VMSG3(3, "Use defaults: rules - '%s' model - '%s' layout - '%s'\n", 6131568b75bSmrg tmp, vd.model, vd.layout); 6147d5e3a19Smrg } 6157d5e3a19Smrg if (tmp) 616bda5b58fSmrg trySetString(&settings.rules, tmp, FROM_SERVER); 6177d5e3a19Smrg if (vd.model) 618bda5b58fSmrg trySetString(&settings.model, vd.model, FROM_SERVER); 6197d5e3a19Smrg if (vd.layout) 620bda5b58fSmrg trySetString(&settings.layout, vd.layout, FROM_SERVER); 6217d5e3a19Smrg if (vd.variant) 622bda5b58fSmrg trySetString(&settings.variant, vd.variant, FROM_SERVER); 6231568b75bSmrg if ((vd.options) && (!clearOptions)) 6241568b75bSmrg { 625bda5b58fSmrg addStringToOptions(vd.options, &options); 6261568b75bSmrg XFree(vd.options); 6277d5e3a19Smrg } 6287d5e3a19Smrg return True; 6297d5e3a19Smrg} 6307d5e3a19Smrg 6317d5e3a19Smrg/***====================================================================***/ 6327d5e3a19Smrg 6337d5e3a19SmrgFILE * 634bda5b58fSmrgfindFileInPath(char *name) 6357d5e3a19Smrg{ 6361568b75bSmrg register int i; 6371568b75bSmrg char buf[PATH_MAX]; 6381568b75bSmrg FILE *fp; 6391568b75bSmrg 6401568b75bSmrg if (name[0] == '/') 6411568b75bSmrg { 6421568b75bSmrg fp = fopen(name, "r"); 6431568b75bSmrg if ((verbose > 7) || ((!fp) && (verbose > 0))) 6441568b75bSmrg MSG2("%s file %s\n", (fp ? "Found" : "Didn't find"), name); 6451568b75bSmrg return fp; 6461568b75bSmrg } 647bda5b58fSmrg for (i = 0; (i < inclPath.num); i++) 6481568b75bSmrg { 649bda5b58fSmrg if (snprintf(buf, PATH_MAX, "%s/%s", inclPath.item[i], name) >= 6501568b75bSmrg PATH_MAX) 6511568b75bSmrg { 652bda5b58fSmrg VMSG2(0, "Path too long (%s/%s). Ignored.\n", inclPath.item[i], 653bda5b58fSmrg name); 6541568b75bSmrg continue; 6551568b75bSmrg } 656bda5b58fSmrg fp = fopen(buf, "r"); 6571568b75bSmrg if ((verbose > 7) || ((!fp) && (verbose > 5))) 6581568b75bSmrg MSG2("%s file %s\n", (fp ? "Found" : "Didn't find"), buf); 6591568b75bSmrg if (fp != NULL) 6601568b75bSmrg return fp; 6617d5e3a19Smrg } 6627d5e3a19Smrg return NULL; 6637d5e3a19Smrg} 6647d5e3a19Smrg 6657d5e3a19Smrg/***====================================================================***/ 6667d5e3a19Smrg 6677d5e3a19SmrgBool 668bda5b58fSmrgaddStringToOptions(char *opt_str, list_t *opts) 6697d5e3a19Smrg{ 6701568b75bSmrg char *tmp, *str, *next; 6711568b75bSmrg Bool ok = True; 6727d5e3a19Smrg 673bda5b58fSmrg str = strdup(opt_str); 674bda5b58fSmrg OOM(str); 675bda5b58fSmrg for (tmp = str; (tmp && *tmp != '\0') && ok; tmp = next) 6761568b75bSmrg { 6771568b75bSmrg next = strchr(str, ','); 6781568b75bSmrg if (next) 6791568b75bSmrg { 6801568b75bSmrg *next = '\0'; 6811568b75bSmrg next++; 6821568b75bSmrg } 683bda5b58fSmrg ok = addToList(opts, tmp) && ok; 6847d5e3a19Smrg } 6857d5e3a19Smrg free(str); 6867d5e3a19Smrg return ok; 6877d5e3a19Smrg} 6887d5e3a19Smrg 6897d5e3a19Smrg/***====================================================================***/ 6907d5e3a19Smrg 6917d5e3a19Smrgchar * 692bda5b58fSmrgstringFromOptions(char *orig, list_t *newOpts) 6937d5e3a19Smrg{ 694b8414663Smrg size_t len; 695b8414663Smrg int i, nOut; 6961568b75bSmrg 6971568b75bSmrg if (orig) 6981568b75bSmrg len = strlen(orig) + 1; 6991568b75bSmrg else 7001568b75bSmrg len = 0; 701bda5b58fSmrg for (i = 0; i < newOpts->num; i++) 7021568b75bSmrg { 703bda5b58fSmrg if (newOpts->item[i]) 704bda5b58fSmrg len += strlen(newOpts->item[i]) + 1; 7051568b75bSmrg } 7061568b75bSmrg if (len < 1) 7071568b75bSmrg return NULL; 7081568b75bSmrg if (orig) 7091568b75bSmrg { 7101568b75bSmrg orig = (char *) realloc(orig, len); 711bda5b58fSmrg OOM(orig); 7121568b75bSmrg nOut = 1; 7131568b75bSmrg } 7141568b75bSmrg else 7151568b75bSmrg { 7161568b75bSmrg orig = (char *) calloc(len, 1); 717bda5b58fSmrg OOM(orig); 7181568b75bSmrg nOut = 0; 7191568b75bSmrg } 720bda5b58fSmrg for (i = 0; i < newOpts->num; i++) 7211568b75bSmrg { 722bda5b58fSmrg if (!newOpts->item[i]) 7231568b75bSmrg continue; 7241568b75bSmrg if (nOut > 0) 7251568b75bSmrg { 7261568b75bSmrg strcat(orig, ","); 727bda5b58fSmrg strcat(orig, newOpts->item[i]); 7281568b75bSmrg } 7291568b75bSmrg else 730bda5b58fSmrg strcpy(orig, newOpts->item[i]); 7311568b75bSmrg nOut++; 7327d5e3a19Smrg } 7337d5e3a19Smrg return orig; 7347d5e3a19Smrg} 7357d5e3a19Smrg 7367d5e3a19Smrg/***====================================================================***/ 7377d5e3a19Smrg 7387d5e3a19SmrgBool 7397d5e3a19SmrgapplyConfig(char *name) 7407d5e3a19Smrg{ 7411568b75bSmrg FILE *fp; 7421568b75bSmrg Bool ok; 7431568b75bSmrg 744bda5b58fSmrg if ((fp = findFileInPath(name)) == NULL) 7451568b75bSmrg return False; 7461568b75bSmrg ok = XkbCFParse(fp, XkbCFDflts, NULL, &cfgResult); 7477d5e3a19Smrg fclose(fp); 7481568b75bSmrg if (!ok) 7491568b75bSmrg { 7501568b75bSmrg ERR1("Couldn't find configuration file \"%s\"\n", name); 7511568b75bSmrg return False; 7527d5e3a19Smrg } 7531568b75bSmrg if (cfgResult.rules_file) 7541568b75bSmrg { 755bda5b58fSmrg trySetString(&settings.rules, cfgResult.rules_file, FROM_CONFIG); 7561568b75bSmrg cfgResult.rules_file = NULL; 7577d5e3a19Smrg } 7581568b75bSmrg if (cfgResult.model) 7591568b75bSmrg { 760bda5b58fSmrg trySetString(&settings.model, cfgResult.model, FROM_CONFIG); 7611568b75bSmrg cfgResult.model = NULL; 7627d5e3a19Smrg } 7631568b75bSmrg if (cfgResult.layout) 7641568b75bSmrg { 765bda5b58fSmrg trySetString(&settings.layout, cfgResult.layout, FROM_CONFIG); 7661568b75bSmrg cfgResult.layout = NULL; 7677d5e3a19Smrg } 7681568b75bSmrg if (cfgResult.variant) 7691568b75bSmrg { 770bda5b58fSmrg trySetString(&settings.variant, cfgResult.variant, FROM_CONFIG); 7711568b75bSmrg cfgResult.variant = NULL; 7727d5e3a19Smrg } 7731568b75bSmrg if (cfgResult.options) 7741568b75bSmrg { 775bda5b58fSmrg addStringToOptions(cfgResult.options, &options); 7761568b75bSmrg cfgResult.options = NULL; 7777d5e3a19Smrg } 7781568b75bSmrg if (cfgResult.keymap) 7791568b75bSmrg { 780bda5b58fSmrg trySetString(&settings.keymap, cfgResult.keymap, FROM_CONFIG); 7811568b75bSmrg cfgResult.keymap = NULL; 7827d5e3a19Smrg } 7831568b75bSmrg if (cfgResult.keycodes) 7841568b75bSmrg { 785bda5b58fSmrg trySetString(&settings.keycodes, cfgResult.keycodes, FROM_CONFIG); 7861568b75bSmrg cfgResult.keycodes = NULL; 7877d5e3a19Smrg } 7881568b75bSmrg if (cfgResult.geometry) 7891568b75bSmrg { 790bda5b58fSmrg trySetString(&settings.geometry, cfgResult.geometry, FROM_CONFIG); 7911568b75bSmrg cfgResult.geometry = NULL; 7927d5e3a19Smrg } 7931568b75bSmrg if (cfgResult.symbols) 7941568b75bSmrg { 795bda5b58fSmrg trySetString(&settings.symbols, cfgResult.symbols, FROM_CONFIG); 7961568b75bSmrg cfgResult.symbols = NULL; 7977d5e3a19Smrg } 7981568b75bSmrg if (cfgResult.types) 7991568b75bSmrg { 800bda5b58fSmrg trySetString(&settings.types, cfgResult.types, FROM_CONFIG); 8011568b75bSmrg cfgResult.types = NULL; 8027d5e3a19Smrg } 8031568b75bSmrg if (cfgResult.compat) 8041568b75bSmrg { 805bda5b58fSmrg trySetString(&settings.compat, cfgResult.compat, FROM_CONFIG); 8061568b75bSmrg cfgResult.compat = NULL; 8077d5e3a19Smrg } 8081568b75bSmrg if (verbose > 5) 8091568b75bSmrg { 8101568b75bSmrg MSG("After config file:\n"); 8111568b75bSmrg dumpNames(True, True); 8127d5e3a19Smrg } 8137d5e3a19Smrg return True; 8147d5e3a19Smrg} 8157d5e3a19Smrg 816bda5b58fSmrgXkbRF_RulesPtr 817bda5b58fSmrgtryLoadRules(char *name, char *locale, Bool wantDesc, Bool wantRules) 818bda5b58fSmrg{ 819bda5b58fSmrg XkbRF_RulesPtr rules = NULL; 820bda5b58fSmrg VMSG1(7, "Trying to load rules file %s...\n", name); 821bda5b58fSmrg rules = XkbRF_Load(name, locale, wantDesc, wantRules); 822bda5b58fSmrg if (rules) 823bda5b58fSmrg { 824bda5b58fSmrg VMSG(7, "Success.\n"); 825bda5b58fSmrg } 826bda5b58fSmrg return rules; 827bda5b58fSmrg} 828bda5b58fSmrg 8291568b75bSmrg/** 8301568b75bSmrg * If any of model, layout, variant or options is specified, then compile the 8311568b75bSmrg * options into the 8321568b75bSmrg * 8331568b75bSmrg * @return True on success or false otherwise. 8341568b75bSmrg */ 8357d5e3a19SmrgBool 8367d5e3a19SmrgapplyRules(void) 8377d5e3a19Smrg{ 8381568b75bSmrg int i; 8391568b75bSmrg char *rfName; 840b8414663Smrg XkbRF_RulesPtr rules = NULL; 8417d5e3a19Smrg 842bda5b58fSmrg if (settings.model.src || settings.layout.src || settings.variant.src 843bda5b58fSmrg || options.item) 8441568b75bSmrg { 8451568b75bSmrg char buf[PATH_MAX]; 8461568b75bSmrg XkbComponentNamesRec rnames; 8477d5e3a19Smrg 848bda5b58fSmrg if (settings.variant.src < settings.layout.src) 849bda5b58fSmrg settings.variant.value = NULL; 8507d5e3a19Smrg 851bda5b58fSmrg rdefs.model = settings.model.value; 852bda5b58fSmrg rdefs.layout = settings.layout.value; 853bda5b58fSmrg rdefs.variant = settings.variant.value; 854bda5b58fSmrg if (options.item) 8551568b75bSmrg rdefs.options = 856bda5b58fSmrg stringFromOptions(rdefs.options, &options); 8571568b75bSmrg 858bda5b58fSmrg if (settings.rules.src) 859bda5b58fSmrg rfName = settings.rules.value; 8601568b75bSmrg else 8611568b75bSmrg rfName = DFLT_XKB_RULES_FILE; 8621568b75bSmrg 8631568b75bSmrg if (rfName[0] == '/') 8641568b75bSmrg { 865bda5b58fSmrg rules = tryLoadRules(rfName, settings.locale.value, True, True); 8661568b75bSmrg } 8671568b75bSmrg else 8681568b75bSmrg { 8691568b75bSmrg /* try to load rules files from all include paths until the first 8701568b75bSmrg * we succeed with */ 871bda5b58fSmrg for (i = 0; (i < inclPath.num) && (!rules); i++) 8721568b75bSmrg { 873bda5b58fSmrg if (snprintf(buf, PATH_MAX, "%s/rules/%s", 874bda5b58fSmrg inclPath.item[i], rfName) >= PATH_MAX) 8751568b75bSmrg { 8761568b75bSmrg VMSG2(0, "Path too long (%s/rules/%s). Ignored.\n", 877bda5b58fSmrg inclPath.item[i], rfName); 8781568b75bSmrg continue; 8791568b75bSmrg } 880bda5b58fSmrg rules = tryLoadRules(buf, settings.locale.value, True, True); 8811568b75bSmrg } 8821568b75bSmrg } 8831568b75bSmrg if (!rules) 8841568b75bSmrg { 885bda5b58fSmrg ERR1("Couldn't find rules file (%s) \n", rfName); 8861568b75bSmrg return False; 8871568b75bSmrg } 8881568b75bSmrg /* Let the rules file to the magic, then update the svValues with 8891568b75bSmrg * those returned after processing the rules */ 8901568b75bSmrg XkbRF_GetComponents(rules, &rdefs, &rnames); 8911568b75bSmrg if (rnames.keycodes) 8921568b75bSmrg { 893bda5b58fSmrg trySetString(&settings.keycodes, rnames.keycodes, FROM_RULES); 8941568b75bSmrg rnames.keycodes = NULL; 8951568b75bSmrg } 8961568b75bSmrg if (rnames.symbols) 8971568b75bSmrg { 898bda5b58fSmrg trySetString(&settings.symbols, rnames.symbols, FROM_RULES); 8991568b75bSmrg rnames.symbols = NULL; 9001568b75bSmrg } 9011568b75bSmrg if (rnames.types) 9021568b75bSmrg { 903bda5b58fSmrg trySetString(&settings.types, rnames.types, FROM_RULES); 9041568b75bSmrg rnames.types = NULL; 9051568b75bSmrg } 9061568b75bSmrg if (rnames.compat) 9071568b75bSmrg { 908bda5b58fSmrg trySetString(&settings.compat, rnames.compat, FROM_RULES); 9091568b75bSmrg rnames.compat = NULL; 9101568b75bSmrg } 9111568b75bSmrg if (rnames.geometry) 9121568b75bSmrg { 913bda5b58fSmrg trySetString(&settings.geometry, rnames.geometry, FROM_RULES); 9141568b75bSmrg rnames.geometry = NULL; 9151568b75bSmrg } 9161568b75bSmrg if (rnames.keymap) 9171568b75bSmrg { 918bda5b58fSmrg trySetString(&settings.keymap, rnames.keymap, FROM_RULES); 9191568b75bSmrg rnames.keymap = NULL; 9201568b75bSmrg } 9211568b75bSmrg if (verbose > 6) 9221568b75bSmrg { 923bda5b58fSmrg MSG1("Applied rules from %s:\n", rfName); 9241568b75bSmrg dumpNames(True, False); 9251568b75bSmrg } 9261568b75bSmrg } 9271568b75bSmrg else if (verbose > 6) 9281568b75bSmrg { 9291568b75bSmrg MSG("No rules variables specified. Rules file ignored\n"); 9307d5e3a19Smrg } 9317d5e3a19Smrg return True; 9327d5e3a19Smrg} 9337d5e3a19Smrg 9347d5e3a19Smrg/* Primitive sanity check - filter out 'map names' (inside parenthesis) */ 9357d5e3a19Smrg/* that can confuse xkbcomp parser */ 9361568b75bSmrgstatic Bool 937bda5b58fSmrgcheckName(char *name, const char *string) 9387d5e3a19Smrg{ 9391568b75bSmrg char *i = name, *opar = NULL; 9401568b75bSmrg Bool ret = True; 9411568b75bSmrg 9421568b75bSmrg if (!name) 9431568b75bSmrg return True; 9441568b75bSmrg 9451568b75bSmrg while (*i) 9461568b75bSmrg { 9471568b75bSmrg if (opar == NULL) 9481568b75bSmrg { 9491568b75bSmrg if (*i == '(') 9501568b75bSmrg opar = i; 9511568b75bSmrg } 9521568b75bSmrg else 9531568b75bSmrg { 9541568b75bSmrg if ((*i == '(') || (*i == '|') || (*i == '+')) 9551568b75bSmrg { 9561568b75bSmrg ret = False; 9571568b75bSmrg break; 9581568b75bSmrg } 9591568b75bSmrg if (*i == ')') 9601568b75bSmrg opar = NULL; 9611568b75bSmrg } 9621568b75bSmrg i++; 9631568b75bSmrg } 9641568b75bSmrg if (opar) 9651568b75bSmrg ret = False; 9661568b75bSmrg if (!ret) 9671568b75bSmrg { 9681568b75bSmrg char c; 9691568b75bSmrg int n = 1; 9701568b75bSmrg for (i = opar + 1; *i && n; i++) 9711568b75bSmrg { 9721568b75bSmrg if (*i == '(') 9731568b75bSmrg n++; 9741568b75bSmrg if (*i == ')') 9751568b75bSmrg n--; 9761568b75bSmrg } 9771568b75bSmrg if (*i) 9781568b75bSmrg i++; 9791568b75bSmrg c = *i; 9801568b75bSmrg *i = '\0'; 9811568b75bSmrg ERR1("Illegal map name '%s' ", opar); 9821568b75bSmrg *i = c; 9831568b75bSmrg ERR2("in %s name '%s'\n", string, name); 9841568b75bSmrg } 9851568b75bSmrg return ret; 9867d5e3a19Smrg} 9877d5e3a19Smrg 9887d5e3a19Smrgvoid 9897d5e3a19SmrgprintKeymap(void) 9907d5e3a19Smrg{ 9917d5e3a19Smrg MSG("xkb_keymap {\n"); 992bda5b58fSmrg if (settings.keycodes.value) 993bda5b58fSmrg MSG1("\txkb_keycodes { include \"%s\"\t};\n", settings.keycodes.value); 994bda5b58fSmrg if (settings.types.value) 995bda5b58fSmrg MSG1("\txkb_types { include \"%s\"\t};\n", settings.types.value); 996bda5b58fSmrg if (settings.compat.value) 997bda5b58fSmrg MSG1("\txkb_compat { include \"%s\"\t};\n", settings.compat.value); 998bda5b58fSmrg if (settings.symbols.value) 999bda5b58fSmrg MSG1("\txkb_symbols { include \"%s\"\t};\n", settings.symbols.value); 1000bda5b58fSmrg if (settings.geometry.value) 1001bda5b58fSmrg MSG1("\txkb_geometry { include \"%s\"\t};\n", settings.geometry.value); 10027d5e3a19Smrg MSG("};\n"); 10037d5e3a19Smrg} 10047d5e3a19Smrg 10057d5e3a19SmrgBool 10067d5e3a19SmrgapplyComponentNames(void) 10077d5e3a19Smrg{ 1008bda5b58fSmrg if (!checkName(settings.types.value, "types")) 10091568b75bSmrg return False; 1010bda5b58fSmrg if (!checkName(settings.compat.value, "compat")) 10111568b75bSmrg return False; 1012bda5b58fSmrg if (!checkName(settings.symbols.value, "symbols")) 10131568b75bSmrg return False; 1014bda5b58fSmrg if (!checkName(settings.keycodes.value, "keycodes")) 10151568b75bSmrg return False; 1016bda5b58fSmrg if (!checkName(settings.geometry.value, "geometry")) 10171568b75bSmrg return False; 1018bda5b58fSmrg if (!checkName(settings.keymap.value, "keymap")) 10191568b75bSmrg return False; 10201568b75bSmrg 10211568b75bSmrg if (verbose > 5) 10221568b75bSmrg { 10231568b75bSmrg MSG("Trying to build keymap using the following components:\n"); 10241568b75bSmrg dumpNames(False, True); 10251568b75bSmrg } 10261568b75bSmrg /* Upload the new description to the server. */ 1027765486e8Smrg if (dpy && !print && !query) 10281568b75bSmrg { 1029b8414663Smrg XkbComponentNamesRec cmdNames = { 1030b8414663Smrg .keymap = settings.keymap.value, 1031b8414663Smrg .keycodes = settings.keycodes.value, 1032b8414663Smrg .types = settings.types.value, 1033b8414663Smrg .compat = settings.compat.value, 1034b8414663Smrg .symbols = settings.symbols.value, 1035b8414663Smrg .geometry = settings.geometry.value 1036b8414663Smrg }; 1037b8414663Smrg 10381568b75bSmrg xkb = XkbGetKeyboardByName(dpy, deviceSpec, &cmdNames, 10391568b75bSmrg XkbGBN_AllComponentsMask, 10401568b75bSmrg XkbGBN_AllComponentsMask & 10411568b75bSmrg (~XkbGBN_GeometryMask), True); 10421568b75bSmrg if (!xkb) 10431568b75bSmrg { 10441568b75bSmrg ERR("Error loading new keyboard description\n"); 10451568b75bSmrg return False; 10461568b75bSmrg } 10471568b75bSmrg /* update the XKB root property */ 1048bda5b58fSmrg if (settings.rules.value && (rdefs.model || rdefs.layout)) 10491568b75bSmrg { 1050bda5b58fSmrg if (!XkbRF_SetNamesProp(dpy, settings.rules.value, &rdefs)) 10511568b75bSmrg { 10521568b75bSmrg VMSG(0, "Error updating the XKB names property\n"); 10531568b75bSmrg } 10541568b75bSmrg } 10551568b75bSmrg } 10561568b75bSmrg if (print) 10571568b75bSmrg { 10587d5e3a19Smrg printKeymap(); 10597d5e3a19Smrg } 1060765486e8Smrg if (query) 1061765486e8Smrg { 1062bda5b58fSmrg dumpNames(True, False); 1063765486e8Smrg } 10647d5e3a19Smrg return True; 10657d5e3a19Smrg} 10667d5e3a19Smrg 10677d5e3a19Smrg 10687d5e3a19Smrgint 10691568b75bSmrgmain(int argc, char **argv) 10707d5e3a19Smrg{ 10711568b75bSmrg if ((!parseArgs(argc, argv)) || (!getDisplay(argc, argv))) 10721568b75bSmrg exit(-1); 1073bda5b58fSmrg settings.locale.value = setlocale(LC_ALL, settings.locale.value); 1074bda5b58fSmrg settings.locale.src = FROM_SERVER; 1075bda5b58fSmrg VMSG1(7, "locale is %s\n", settings.locale.value); 10767d5e3a19Smrg if (dpy) 10777d5e3a19Smrg getServerValues(); 1078bda5b58fSmrg if (settings.config.value && (!applyConfig(settings.config.value))) 10791568b75bSmrg exit(-3); 10807d5e3a19Smrg if (!applyRules()) 10811568b75bSmrg exit(-4); 10827d5e3a19Smrg if (!applyComponentNames()) 10831568b75bSmrg exit(-5); 10847d5e3a19Smrg if (dpy) 10851568b75bSmrg XCloseDisplay(dpy); 10867d5e3a19Smrg exit(0); 10877d5e3a19Smrg} 1088