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