setxkbmap.c revision 765486e8
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
51765486e8Smrg#define	DFLT_XKB_RULES_FILE "base"
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;
88765486e8Smrgstatic Bool query = False;
891568b75bSmrgstatic Bool synch = False;
901568b75bSmrgstatic int verbose = 5;
911568b75bSmrg
921568b75bSmrgstatic Display *dpy;
931568b75bSmrg
941568b75bSmrg/**
951568b75bSmrg * human-readable versions of FROM_CONFIG, FROM_SERVER, etc. Used for error
961568b75bSmrg * reporting.
971568b75bSmrg */
981568b75bSmrgstatic char *srcName[NUM_SOURCES] = {
991568b75bSmrg    "undefined", "X server", "rules file", "config file", "command line"
1007d5e3a19Smrg};
1017d5e3a19Smrg
1021568b75bSmrg/**
1031568b75bSmrg * human-readable versions for RULES_NDX, CONFIG_NDX, etc. Used for error
1041568b75bSmrg * reporting.
1051568b75bSmrg */
1061568b75bSmrgstatic char *svName[NUM_STRING_VALS] = {
1071568b75bSmrg    "rules file", "config file", "X display", "locale",
1081568b75bSmrg    "keyboard model", "keyboard layout", "layout variant",
1091568b75bSmrg    "keycodes", "types", "compatibility map", "symbols", "geometry",
1101568b75bSmrg    "keymap"
1117d5e3a19Smrg};
1121568b75bSmrg/**
1131568b75bSmrg * Holds the source for each of RULES, CONFIG, DISPLAY, etc.
1141568b75bSmrg * i.e. if svSrc[LAYOUT_NDX] == FROM_SERVER, then the layout has been fetched
1151568b75bSmrg * from the server.
1161568b75bSmrg */
1171568b75bSmrgstatic int svSrc[NUM_STRING_VALS];
1181568b75bSmrg/**
1191568b75bSmrg * Holds the value for each of RULES, CONFIG, DISPLAY, etc.
1201568b75bSmrg */
1211568b75bSmrgstatic char *svValue[NUM_STRING_VALS];
1227d5e3a19Smrg
1231568b75bSmrgstatic XkbConfigRtrnRec cfgResult;
1247d5e3a19Smrg
1251568b75bSmrgstatic XkbRF_RulesPtr rules = NULL;
1261568b75bSmrgstatic XkbRF_VarDefsRec rdefs;
1277d5e3a19Smrg
1281568b75bSmrgstatic Bool clearOptions = False;
1291568b75bSmrgstatic int szOptions = 0;
1301568b75bSmrgstatic int numOptions = 0;
1311568b75bSmrgstatic char **options = NULL;
1327d5e3a19Smrg
1331568b75bSmrgstatic int szInclPath = 0;
1341568b75bSmrgstatic int numInclPath = 0;
1351568b75bSmrgstatic char **inclPath = NULL;
1367d5e3a19Smrg
1371568b75bSmrgstatic XkbDescPtr xkb = NULL;
1387d5e3a19Smrg
1391568b75bSmrgstatic int deviceSpec = XkbUseCoreKbd;
1407d5e3a19Smrg
1417d5e3a19Smrg/***====================================================================***/
1427d5e3a19Smrg
1437d5e3a19Smrg#define	streq(s1,s2)	(strcmp(s1,s2)==0)
1447d5e3a19Smrg#define	strpfx(s1,s2)	(strncmp(s1,s2,strlen(s2))==0)
1457d5e3a19Smrg
1467d5e3a19Smrg#define	MSG(s)		printf(s)
1477d5e3a19Smrg#define	MSG1(s,a)	printf(s,a)
1487d5e3a19Smrg#define	MSG2(s,a,b)	printf(s,a,b)
1497d5e3a19Smrg#define	MSG3(s,a,b,c)	printf(s,a,b,c)
1507d5e3a19Smrg
1517d5e3a19Smrg#define	VMSG(l,s)	if (verbose>(l)) printf(s)
1527d5e3a19Smrg#define	VMSG1(l,s,a)	if (verbose>(l)) printf(s,a)
1537d5e3a19Smrg#define	VMSG2(l,s,a,b)	if (verbose>(l)) printf(s,a,b)
1547d5e3a19Smrg#define	VMSG3(l,s,a,b,c) if (verbose>(l)) printf(s,a,b,c)
1557d5e3a19Smrg
1567d5e3a19Smrg#define	ERR(s)		fprintf(stderr,s)
1577d5e3a19Smrg#define	ERR1(s,a)	fprintf(stderr,s,a)
1587d5e3a19Smrg#define	ERR2(s,a,b)	fprintf(stderr,s,a,b)
1597d5e3a19Smrg#define	ERR3(s,a,b,c)	fprintf(stderr,s,a,b,c)
1607d5e3a19Smrg
1617d5e3a19Smrg/***====================================================================***/
1627d5e3a19Smrg
1631568b75bSmrgBool addToList(int *sz, int *num, char ***listIn, char *newVal);
1641568b75bSmrgvoid usage(int argc, char **argv);
1651568b75bSmrgvoid dumpNames(Bool wantRules, Bool wantCNames);
1661568b75bSmrgvoid trySetString(int which, char *newVal, int src);
1671568b75bSmrgBool setOptString(int *arg, int argc, char **argv, int which, int src);
1681568b75bSmrgint parseArgs(int argc, char **argv);
1691568b75bSmrgBool getDisplay(int argc, char **argv);
1701568b75bSmrgBool getServerValues(void);
1711568b75bSmrgFILE *findFileInPath(char *name, char *subdir);
1721568b75bSmrgBool addStringToOptions(char *opt_str, int *sz_opts, int *num_opts,
1731568b75bSmrg                        char ***opts);
1741568b75bSmrgchar *stringFromOptions(char *orig, int numNew, char **newOpts);
1751568b75bSmrgBool applyConfig(char *name);
1761568b75bSmrgBool applyRules(void);
1771568b75bSmrgBool applyComponentNames(void);
1781568b75bSmrgvoid printKeymap(void);
1797d5e3a19Smrg
1807d5e3a19Smrg/***====================================================================***/
1817d5e3a19Smrg
1827d5e3a19SmrgBool
1831568b75bSmrgaddToList(int *sz, int *num, char ***listIn, char *newVal)
1847d5e3a19Smrg{
1851568b75bSmrg    register int i;
1861568b75bSmrg    char **list;
1871568b75bSmrg
1881568b75bSmrg    if ((!newVal) || (!newVal[0]))
1891568b75bSmrg    {
1901568b75bSmrg        *num = 0;
1911568b75bSmrg        return True;
1921568b75bSmrg    }
1931568b75bSmrg    list = *listIn;
1941568b75bSmrg    for (i = 0; i < *num; i++)
1951568b75bSmrg    {
1961568b75bSmrg        if (streq(list[i], newVal))
1971568b75bSmrg            return True;
1981568b75bSmrg    }
1991568b75bSmrg    if ((list == NULL) || (*sz < 1))
2001568b75bSmrg    {
2011568b75bSmrg        *num = 0;
2021568b75bSmrg        *sz = 4;
2031568b75bSmrg        list = (char **) calloc(*sz, sizeof(char *));
2041568b75bSmrg        *listIn = list;
2051568b75bSmrg    }
2061568b75bSmrg    else if (*num >= *sz)
2071568b75bSmrg    {
2081568b75bSmrg        *sz *= 2;
2091568b75bSmrg        list = (char **) realloc(list, (*sz) * sizeof(char *));
2101568b75bSmrg        *listIn = list;
2111568b75bSmrg    }
2121568b75bSmrg    if (!list)
2131568b75bSmrg    {
2141568b75bSmrg        ERR("Internal Error! Allocation failure in add to list!\n");
2151568b75bSmrg        ERR("                Exiting.\n");
2161568b75bSmrg        exit(-1);
2171568b75bSmrg    }
2181568b75bSmrg    list[*num] = strdup(newVal);
2191568b75bSmrg    (*num) = (*num) + 1;
2207d5e3a19Smrg    return True;
2217d5e3a19Smrg}
2227d5e3a19Smrg
2237d5e3a19Smrg/***====================================================================***/
2247d5e3a19Smrg
2257d5e3a19Smrgvoid
2261568b75bSmrgusage(int argc, char **argv)
2277d5e3a19Smrg{
2281568b75bSmrg    MSG1("Usage: %s [args] [<layout> [<variant> [<option> ... ]]]\n",
2291568b75bSmrg         argv[0]);
2307d5e3a19Smrg    MSG("Where legal args are:\n");
2317d5e3a19Smrg    MSG("-?,-help            Print this message\n");
2327d5e3a19Smrg    MSG("-compat <name>      Specifies compatibility map component name\n");
2337d5e3a19Smrg    MSG("-config <file>      Specifies configuration file to use\n");
2347d5e3a19Smrg    MSG("-device <deviceid>  Specifies the device ID to use\n");
2357d5e3a19Smrg    MSG("-display <dpy>      Specifies display to use\n");
2367d5e3a19Smrg    MSG("-geometry <name>    Specifies geometry component name\n");
2377d5e3a19Smrg    MSG("-I[<dir>]           Add <dir> to list of directories to be used\n");
2387d5e3a19Smrg    MSG("-keycodes <name>    Specifies keycodes component name\n");
2397d5e3a19Smrg    MSG("-keymap <name>      Specifies name of keymap to load\n");
2407d5e3a19Smrg    MSG("-layout <name>      Specifies layout used to choose component names\n");
2417d5e3a19Smrg    MSG("-model <name>       Specifies model used to choose component names\n");
2427d5e3a19Smrg    MSG("-option <name>      Adds an option used to choose component names\n");
2437d5e3a19Smrg    MSG("-print              Print a complete xkb_keymap description and exit\n");
244765486e8Smrg    MSG("-query              Print the current layout settings and exit\n");
2457d5e3a19Smrg    MSG("-rules <name>       Name of rules file to use\n");
2467d5e3a19Smrg    MSG("-symbols <name>     Specifies symbols component name\n");
2477d5e3a19Smrg    MSG("-synch              Synchronize request w/X server\n");
2487d5e3a19Smrg    MSG("-types <name>       Specifies types component name\n");
2497d5e3a19Smrg    MSG("-v[erbose] [<lvl>]  Sets verbosity (1..10).  Higher values yield\n");
2507d5e3a19Smrg    MSG("                    more messages\n");
2517d5e3a19Smrg    MSG("-variant <name>     Specifies layout variant used to choose component names\n");
2527d5e3a19Smrg}
2537d5e3a19Smrg
2547d5e3a19Smrgvoid
2551568b75bSmrgdumpNames(Bool wantRules, Bool wantCNames)
2567d5e3a19Smrg{
2571568b75bSmrg    if (wantRules)
2581568b75bSmrg    {
259765486e8Smrg        if (svValue[RULES_NDX])
260765486e8Smrg            MSG1("rules:      %s\n", svValue[RULES_NDX]);
2611568b75bSmrg        if (svValue[MODEL_NDX])
2621568b75bSmrg            MSG1("model:      %s\n", svValue[MODEL_NDX]);
2631568b75bSmrg        if (svValue[LAYOUT_NDX])
2641568b75bSmrg            MSG1("layout:     %s\n", svValue[LAYOUT_NDX]);
2651568b75bSmrg        if (svValue[VARIANT_NDX])
2661568b75bSmrg            MSG1("variant:    %s\n", svValue[VARIANT_NDX]);
2671568b75bSmrg        if (options)
2681568b75bSmrg        {
2691568b75bSmrg            char *opt_str = stringFromOptions(NULL, numOptions, options);
2701568b75bSmrg            MSG1("options:    %s\n", opt_str);
2711568b75bSmrg            free(opt_str);
2721568b75bSmrg        }
2731568b75bSmrg    }
2741568b75bSmrg    if (wantCNames)
2751568b75bSmrg    {
2761568b75bSmrg        if (svValue[KEYMAP_NDX])
2771568b75bSmrg            MSG1("keymap:     %s\n", svValue[KEYMAP_NDX]);
2781568b75bSmrg        if (svValue[KEYCODES_NDX])
2791568b75bSmrg            MSG1("keycodes:   %s\n", svValue[KEYCODES_NDX]);
2801568b75bSmrg        if (svValue[TYPES_NDX])
2811568b75bSmrg            MSG1("types:      %s\n", svValue[TYPES_NDX]);
2821568b75bSmrg        if (svValue[COMPAT_NDX])
2831568b75bSmrg            MSG1("compat:     %s\n", svValue[COMPAT_NDX]);
2841568b75bSmrg        if (svValue[SYMBOLS_NDX])
2851568b75bSmrg            MSG1("symbols:    %s\n", svValue[SYMBOLS_NDX]);
2861568b75bSmrg        if (svValue[GEOMETRY_NDX])
2871568b75bSmrg            MSG1("geometry:   %s\n", svValue[GEOMETRY_NDX]);
2887d5e3a19Smrg    }
2897d5e3a19Smrg    return;
2907d5e3a19Smrg}
2917d5e3a19Smrg
2927d5e3a19Smrg/***====================================================================***/
2937d5e3a19Smrg
2941568b75bSmrg/**
2951568b75bSmrg * Set the given string (obtained from src) in the svValue/svSrc globals.
2961568b75bSmrg * If the given item is already set, it is overridden if the original source
2971568b75bSmrg * is less significant than the given one.
2981568b75bSmrg *
2991568b75bSmrg * @param which What value is it (one of RULES_NDX, CONFIG_NDX, ...)
3001568b75bSmrg */
3017d5e3a19Smrgvoid
3021568b75bSmrgtrySetString(int which, char *newVal, int src)
3037d5e3a19Smrg{
3041568b75bSmrg    if (svValue[which] != NULL)
3051568b75bSmrg    {
3061568b75bSmrg        if (svSrc[which] == src)
3071568b75bSmrg        {
3081568b75bSmrg            VMSG2(0, "Warning! More than one %s from %s\n",
3091568b75bSmrg                  svName[which], srcName[src]);
3101568b75bSmrg            VMSG2(0, "         Using \"%s\", ignoring \"%s\"\n",
3111568b75bSmrg                  svValue[which], newVal);
3121568b75bSmrg            return;
3131568b75bSmrg        }
3141568b75bSmrg        else if (svSrc[which] > src)
3151568b75bSmrg        {
3161568b75bSmrg            VMSG1(5, "Warning! Multiple definitions of %s\n", svName[which]);
3171568b75bSmrg            VMSG2(5, "         Using %s, ignoring %s\n",
3181568b75bSmrg                  srcName[svSrc[which]], srcName[src]);
3191568b75bSmrg            return;
3201568b75bSmrg        }
3211568b75bSmrg    }
3221568b75bSmrg    svSrc[which] = src;
3231568b75bSmrg    svValue[which] = newVal;
3247d5e3a19Smrg    return;
3257d5e3a19Smrg}
3267d5e3a19Smrg
3277d5e3a19SmrgBool
3281568b75bSmrgsetOptString(int *arg, int argc, char **argv, int which, int src)
3297d5e3a19Smrg{
3301568b75bSmrg    int ndx;
3311568b75bSmrg    char *opt;
3321568b75bSmrg
3331568b75bSmrg    ndx = *arg;
3341568b75bSmrg    opt = argv[ndx];
3351568b75bSmrg    if (ndx >= argc - 1)
3361568b75bSmrg    {
3371568b75bSmrg        VMSG1(0, "No %s specified on the command line\n", svName[which]);
3381568b75bSmrg        VMSG1(0, "Trailing %s option ignored\n", opt);
3391568b75bSmrg        return True;
3407d5e3a19Smrg    }
3417d5e3a19Smrg    ndx++;
3421568b75bSmrg    *arg = ndx;
3431568b75bSmrg    if (svValue[which] != NULL)
3441568b75bSmrg    {
3451568b75bSmrg        if (svSrc[which] == src)
3461568b75bSmrg        {
3471568b75bSmrg            VMSG2(0, "More than one %s on %s\n", svName[which], srcName[src]);
3481568b75bSmrg            VMSG2(0, "Using \"%s\", ignoring \"%s\"\n", svValue[which],
3491568b75bSmrg                  argv[ndx]);
3501568b75bSmrg            return True;
3511568b75bSmrg        }
3521568b75bSmrg        else if (svSrc[which] > src)
3531568b75bSmrg        {
3541568b75bSmrg            VMSG1(5, "Multiple definitions of %s\n", svName[which]);
3551568b75bSmrg            VMSG2(5, "Using %s, ignoring %s\n", srcName[svSrc[which]],
3561568b75bSmrg                  srcName[src]);
3571568b75bSmrg            return True;
3581568b75bSmrg        }
3591568b75bSmrg    }
3601568b75bSmrg    svSrc[which] = src;
3611568b75bSmrg    svValue[which] = argv[ndx];
3627d5e3a19Smrg    return True;
3637d5e3a19Smrg}
3647d5e3a19Smrg
3657d5e3a19Smrg/***====================================================================***/
3667d5e3a19Smrg
3671568b75bSmrg/**
3681568b75bSmrg * Parse commandline arguments.
3691568b75bSmrg * Return True on success or False if an unrecognized option has been
3701568b75bSmrg * specified.
3711568b75bSmrg */
3727d5e3a19Smrgint
3731568b75bSmrgparseArgs(int argc, char **argv)
3747d5e3a19Smrg{
3751568b75bSmrg    int i;
3761568b75bSmrg    Bool ok;
3771568b75bSmrg    unsigned present;
3781568b75bSmrg
3791568b75bSmrg    ok = True;
3801568b75bSmrg    addToList(&szInclPath, &numInclPath, &inclPath, ".");
3811568b75bSmrg    addToList(&szInclPath, &numInclPath, &inclPath, DFLT_XKB_CONFIG_ROOT);
3821568b75bSmrg    for (i = 1; (i < argc) && ok; i++)
3831568b75bSmrg    {
3841568b75bSmrg        if (argv[i][0] != '-')
3851568b75bSmrg        {
3861568b75bSmrg            /* Allow a call like "setxkbmap us" to work. Layout is default,
3871568b75bSmrg               if -layout is given, then try parsing variant, then options */
3881568b75bSmrg            if (!svSrc[LAYOUT_NDX])
3891568b75bSmrg                trySetString(LAYOUT_NDX, argv[i], FROM_CMD_LINE);
3901568b75bSmrg            else if (!svSrc[VARIANT_NDX])
3911568b75bSmrg                trySetString(VARIANT_NDX, argv[i], FROM_CMD_LINE);
3921568b75bSmrg            else
3931568b75bSmrg                ok = addToList(&szOptions, &numOptions, &options, argv[i]);
3941568b75bSmrg        }
3951568b75bSmrg        else if (streq(argv[i], "-compat"))
3961568b75bSmrg            ok = setOptString(&i, argc, argv, COMPAT_NDX, FROM_CMD_LINE);
3971568b75bSmrg        else if (streq(argv[i], "-config"))
3981568b75bSmrg            ok = setOptString(&i, argc, argv, CONFIG_NDX, FROM_CMD_LINE);
3991568b75bSmrg        else if (streq(argv[i], "-device"))
4001568b75bSmrg            deviceSpec = atoi(argv[++i]); /* only allow device IDs, not names */
4011568b75bSmrg        else if (streq(argv[i], "-display"))
4021568b75bSmrg            ok = setOptString(&i, argc, argv, DISPLAY_NDX, FROM_CMD_LINE);
4031568b75bSmrg        else if (streq(argv[i], "-geometry"))
4041568b75bSmrg            ok = setOptString(&i, argc, argv, GEOMETRY_NDX, FROM_CMD_LINE);
4051568b75bSmrg        else if (streq(argv[i], "-help") || streq(argv[i], "-?"))
4061568b75bSmrg        {
4071568b75bSmrg            usage(argc, argv);
4081568b75bSmrg            exit(0);
4091568b75bSmrg        }
4101568b75bSmrg        else if (strpfx(argv[i], "-I"))
4111568b75bSmrg            ok = addToList(&szInclPath, &numInclPath, &inclPath, &argv[i][2]);
4121568b75bSmrg        else if (streq(argv[i], "-keycodes"))
4131568b75bSmrg            ok = setOptString(&i, argc, argv, KEYCODES_NDX, FROM_CMD_LINE);
4141568b75bSmrg        else if (streq(argv[i], "-keymap"))
4151568b75bSmrg            ok = setOptString(&i, argc, argv, KEYMAP_NDX, FROM_CMD_LINE);
4161568b75bSmrg        else if (streq(argv[i], "-layout"))
4171568b75bSmrg            ok = setOptString(&i, argc, argv, LAYOUT_NDX, FROM_CMD_LINE);
4181568b75bSmrg        else if (streq(argv[i], "-model"))
4191568b75bSmrg            ok = setOptString(&i, argc, argv, MODEL_NDX, FROM_CMD_LINE);
4201568b75bSmrg        else if (streq(argv[i], "-option"))
4211568b75bSmrg        {
4221568b75bSmrg            if ((i == argc - 1) || (argv[i + 1][0] == '\0')
4231568b75bSmrg                || (argv[i + 1][0] == '-'))
4241568b75bSmrg            {
4251568b75bSmrg                clearOptions = True;
4261568b75bSmrg                ok = addToList(&szOptions, &numOptions, &options, "");
4271568b75bSmrg                if (i < argc - 1 && argv[i + 1][0] == '\0')
4281568b75bSmrg                    i++;
4291568b75bSmrg            }
4301568b75bSmrg            else
4311568b75bSmrg            {
4321568b75bSmrg                ok = addToList(&szOptions, &numOptions, &options, argv[++i]);
4331568b75bSmrg            }
4341568b75bSmrg        }
4351568b75bSmrg        else if (streq(argv[i], "-print"))
4361568b75bSmrg            print = True;
437765486e8Smrg        else if (streq(argv[i], "-query"))
438765486e8Smrg            query = True;
4391568b75bSmrg        else if (streq(argv[i], "-rules"))
4401568b75bSmrg            ok = setOptString(&i, argc, argv, RULES_NDX, FROM_CMD_LINE);
4411568b75bSmrg        else if (streq(argv[i], "-symbols"))
4421568b75bSmrg            ok = setOptString(&i, argc, argv, SYMBOLS_NDX, FROM_CMD_LINE);
4431568b75bSmrg        else if (streq(argv[i], "-synch"))
4441568b75bSmrg            synch = True;
4451568b75bSmrg        else if (streq(argv[i], "-types"))
4461568b75bSmrg            ok = setOptString(&i, argc, argv, TYPES_NDX, FROM_CMD_LINE);
4471568b75bSmrg        else if (streq(argv[i], "-verbose") || (streq(argv[i], "-v")))
4481568b75bSmrg        {
4491568b75bSmrg            if ((i < argc - 1) && (isdigit(argv[i + 1][0])))
4501568b75bSmrg                verbose = atoi(argv[++i]);
4511568b75bSmrg            else
4521568b75bSmrg                verbose++;
4531568b75bSmrg            if (verbose < 0)
4541568b75bSmrg            {
4551568b75bSmrg                ERR1("Illegal verbose level %d.  Reset to 0\n", verbose);
4561568b75bSmrg                verbose = 0;
4571568b75bSmrg            }
4581568b75bSmrg            else if (verbose > 10)
4591568b75bSmrg            {
4601568b75bSmrg                ERR1("Illegal verbose level %d.  Reset to 10\n", verbose);
4611568b75bSmrg                verbose = 10;
4621568b75bSmrg            }
4631568b75bSmrg            VMSG1(7, "Setting verbose level to %d\n", verbose);
4641568b75bSmrg        }
4651568b75bSmrg        else if (streq(argv[i], "-variant"))
4661568b75bSmrg            ok = setOptString(&i, argc, argv, VARIANT_NDX, FROM_CMD_LINE);
4671568b75bSmrg        else
4681568b75bSmrg        {
4691568b75bSmrg            ERR1("Error!   Option \"%s\" not recognized\n", argv[i]);
4701568b75bSmrg            ok = False;
4711568b75bSmrg        }
4721568b75bSmrg    }
4731568b75bSmrg
4741568b75bSmrg    present = 0;
4751568b75bSmrg    if (svValue[TYPES_NDX])
4761568b75bSmrg        present++;
4771568b75bSmrg    if (svValue[COMPAT_NDX])
4781568b75bSmrg        present++;
4791568b75bSmrg    if (svValue[SYMBOLS_NDX])
4801568b75bSmrg        present++;
4811568b75bSmrg    if (svValue[KEYCODES_NDX])
4821568b75bSmrg        present++;
4831568b75bSmrg    if (svValue[GEOMETRY_NDX])
4841568b75bSmrg        present++;
4851568b75bSmrg    if (svValue[CONFIG_NDX])
4861568b75bSmrg        present++;
4871568b75bSmrg    if (svValue[MODEL_NDX])
4881568b75bSmrg        present++;
4891568b75bSmrg    if (svValue[LAYOUT_NDX])
4901568b75bSmrg        present++;
4911568b75bSmrg    if (svValue[VARIANT_NDX])
4921568b75bSmrg        present++;
4931568b75bSmrg    if (svValue[KEYMAP_NDX] && present)
4941568b75bSmrg    {
4951568b75bSmrg        ERR("No other components can be specified when a keymap is present\n");
4961568b75bSmrg        return False;
4977d5e3a19Smrg    }
4987d5e3a19Smrg    return ok;
4997d5e3a19Smrg}
5007d5e3a19Smrg
5011568b75bSmrg/**
5021568b75bSmrg * Open a connection to the display and print error if it fails.
5031568b75bSmrg *
5041568b75bSmrg * @return True on success or False otherwise.
5051568b75bSmrg */
5067d5e3a19SmrgBool
5071568b75bSmrggetDisplay(int argc, char **argv)
5087d5e3a19Smrg{
5091568b75bSmrg    int major, minor, why;
5101568b75bSmrg
5111568b75bSmrg    major = XkbMajorVersion;
5121568b75bSmrg    minor = XkbMinorVersion;
5131568b75bSmrg    dpy =
5141568b75bSmrg        XkbOpenDisplay(svValue[DISPLAY_NDX], NULL, NULL, &major, &minor,
5151568b75bSmrg                       &why);
5161568b75bSmrg    if (!dpy)
5171568b75bSmrg    {
5181568b75bSmrg        if (svValue[DISPLAY_NDX] == NULL)
5191568b75bSmrg            svValue[DISPLAY_NDX] = getenv("DISPLAY");
5201568b75bSmrg        if (svValue[DISPLAY_NDX] == NULL)
5211568b75bSmrg            svValue[DISPLAY_NDX] = "default display";
5221568b75bSmrg        switch (why)
5231568b75bSmrg        {
5241568b75bSmrg        case XkbOD_BadLibraryVersion:
5251568b75bSmrg            ERR3("%s was compiled with XKB version %d.%02d\n", argv[0],
5261568b75bSmrg                 XkbMajorVersion, XkbMinorVersion);
5271568b75bSmrg            ERR2("Xlib supports incompatible version %d.%02d\n",
5281568b75bSmrg                 major, minor);
5291568b75bSmrg            break;
5301568b75bSmrg        case XkbOD_ConnectionRefused:
5311568b75bSmrg            ERR1("Cannot open display \"%s\"\n", svValue[DISPLAY_NDX]);
5321568b75bSmrg            break;
5331568b75bSmrg        case XkbOD_NonXkbServer:
5341568b75bSmrg            ERR1("XKB extension not present on %s\n", svValue[DISPLAY_NDX]);
5351568b75bSmrg            break;
5361568b75bSmrg        case XkbOD_BadServerVersion:
5371568b75bSmrg            ERR3("%s was compiled with XKB version %d.%02d\n", argv[0],
5381568b75bSmrg                 XkbMajorVersion, XkbMinorVersion);
5391568b75bSmrg            ERR3("Server %s uses incompatible version %d.%02d\n",
5401568b75bSmrg                 svValue[DISPLAY_NDX], major, minor);
5411568b75bSmrg            break;
5421568b75bSmrg        default:
5431568b75bSmrg            ERR1("Unknown error %d from XkbOpenDisplay\n", why);
5441568b75bSmrg            break;
5451568b75bSmrg        }
5461568b75bSmrg        return False;
5477d5e3a19Smrg    }
5487d5e3a19Smrg    if (synch)
5491568b75bSmrg        XSynchronize(dpy, True);
5507d5e3a19Smrg    return True;
5517d5e3a19Smrg}
5527d5e3a19Smrg
5537d5e3a19Smrg/***====================================================================***/
5547d5e3a19Smrg
5551568b75bSmrg/**
556765486e8Smrg * Retrieve xkb values from the XKB_RULES_NAMES property and store their
5571568b75bSmrg * contents in svValues.
5581568b75bSmrg * If the property cannot be read, the built-in defaults are used.
5591568b75bSmrg *
5601568b75bSmrg * @return True.
5611568b75bSmrg */
5627d5e3a19SmrgBool
5637d5e3a19SmrggetServerValues(void)
5647d5e3a19Smrg{
5651568b75bSmrg    XkbRF_VarDefsRec vd;
5661568b75bSmrg    char *tmp = NULL;
5677d5e3a19Smrg
5681568b75bSmrg    if (!XkbRF_GetNamesProp(dpy, &tmp, &vd) || !tmp)
5691568b75bSmrg    {
5701568b75bSmrg        VMSG1(3, "Couldn't interpret %s property\n", _XKB_RF_NAMES_PROP_ATOM);
5717d5e3a19Smrg        tmp = DFLT_XKB_RULES_FILE;
5727d5e3a19Smrg        vd.model = DFLT_XKB_MODEL;
5737d5e3a19Smrg        vd.layout = DFLT_XKB_LAYOUT;
5747d5e3a19Smrg        vd.variant = NULL;
5757d5e3a19Smrg        vd.options = NULL;
5761568b75bSmrg        VMSG3(3, "Use defaults: rules - '%s' model - '%s' layout - '%s'\n",
5771568b75bSmrg              tmp, vd.model, vd.layout);
5787d5e3a19Smrg    }
5797d5e3a19Smrg    if (tmp)
5801568b75bSmrg        trySetString(RULES_NDX, tmp, FROM_SERVER);
5817d5e3a19Smrg    if (vd.model)
5821568b75bSmrg        trySetString(MODEL_NDX, vd.model, FROM_SERVER);
5837d5e3a19Smrg    if (vd.layout)
5841568b75bSmrg        trySetString(LAYOUT_NDX, vd.layout, FROM_SERVER);
5857d5e3a19Smrg    if (vd.variant)
5861568b75bSmrg        trySetString(VARIANT_NDX, vd.variant, FROM_SERVER);
5871568b75bSmrg    if ((vd.options) && (!clearOptions))
5881568b75bSmrg    {
5891568b75bSmrg        addStringToOptions(vd.options, &szOptions, &numOptions, &options);
5901568b75bSmrg        XFree(vd.options);
5917d5e3a19Smrg    }
5927d5e3a19Smrg    return True;
5937d5e3a19Smrg}
5947d5e3a19Smrg
5957d5e3a19Smrg/***====================================================================***/
5967d5e3a19Smrg
5977d5e3a19SmrgFILE *
5981568b75bSmrgfindFileInPath(char *name, char *subdir)
5997d5e3a19Smrg{
6001568b75bSmrg    register int i;
6011568b75bSmrg    char buf[PATH_MAX];
6021568b75bSmrg    FILE *fp;
6031568b75bSmrg
6041568b75bSmrg    if (name[0] == '/')
6051568b75bSmrg    {
6061568b75bSmrg        fp = fopen(name, "r");
6071568b75bSmrg        if ((verbose > 7) || ((!fp) && (verbose > 0)))
6081568b75bSmrg            MSG2("%s file %s\n", (fp ? "Found" : "Didn't find"), name);
6091568b75bSmrg        return fp;
6101568b75bSmrg    }
6111568b75bSmrg    for (i = 0; (i < numInclPath); i++)
6121568b75bSmrg    {
6131568b75bSmrg        if ((strlen(inclPath[i]) + strlen(subdir) + strlen(name) + 2) >
6141568b75bSmrg            PATH_MAX)
6151568b75bSmrg        {
6161568b75bSmrg            VMSG3(0, "Path too long (%s/%s%s). Ignored.\n", inclPath[i],
6171568b75bSmrg                  subdir, name);
6181568b75bSmrg            continue;
6191568b75bSmrg        }
6201568b75bSmrg        sprintf(buf, "%s/%s%s", inclPath[i], subdir, name);
6211568b75bSmrg        fp = fopen(name, "r");
6221568b75bSmrg        if ((verbose > 7) || ((!fp) && (verbose > 5)))
6231568b75bSmrg            MSG2("%s file %s\n", (fp ? "Found" : "Didn't find"), buf);
6241568b75bSmrg        if (fp != NULL)
6251568b75bSmrg            return fp;
6267d5e3a19Smrg    }
6277d5e3a19Smrg    return NULL;
6287d5e3a19Smrg}
6297d5e3a19Smrg
6307d5e3a19Smrg/***====================================================================***/
6317d5e3a19Smrg
6327d5e3a19SmrgBool
6331568b75bSmrgaddStringToOptions(char *opt_str, int *sz_opts, int *num_opts, char ***opts)
6347d5e3a19Smrg{
6351568b75bSmrg    char *tmp, *str, *next;
6361568b75bSmrg    Bool ok = True;
6377d5e3a19Smrg
6387d5e3a19Smrg    if ((str = strdup(opt_str)) == NULL)
6391568b75bSmrg        return False;
6401568b75bSmrg    for (tmp = str, next = NULL; (tmp && *tmp != '\0') && ok; tmp = next)
6411568b75bSmrg    {
6421568b75bSmrg        next = strchr(str, ',');
6431568b75bSmrg        if (next)
6441568b75bSmrg        {
6451568b75bSmrg            *next = '\0';
6461568b75bSmrg            next++;
6471568b75bSmrg        }
6481568b75bSmrg        ok = addToList(sz_opts, num_opts, opts, tmp) && ok;
6497d5e3a19Smrg    }
6507d5e3a19Smrg    free(str);
6517d5e3a19Smrg    return ok;
6527d5e3a19Smrg}
6537d5e3a19Smrg
6547d5e3a19Smrg/***====================================================================***/
6557d5e3a19Smrg
6567d5e3a19Smrgchar *
6571568b75bSmrgstringFromOptions(char *orig, int numNew, char **newOpts)
6587d5e3a19Smrg{
6591568b75bSmrg    int len, i, nOut;
6601568b75bSmrg
6611568b75bSmrg    if (orig)
6621568b75bSmrg        len = strlen(orig) + 1;
6631568b75bSmrg    else
6641568b75bSmrg        len = 0;
6651568b75bSmrg    for (i = 0; i < numNew; i++)
6661568b75bSmrg    {
6671568b75bSmrg        if (newOpts[i])
6681568b75bSmrg            len += strlen(newOpts[i]) + 1;
6691568b75bSmrg    }
6701568b75bSmrg    if (len < 1)
6711568b75bSmrg        return NULL;
6721568b75bSmrg    if (orig)
6731568b75bSmrg    {
6741568b75bSmrg        orig = (char *) realloc(orig, len);
6751568b75bSmrg        if (!orig)
6761568b75bSmrg        {
6771568b75bSmrg            ERR("OOM in stringFromOptions\n");
6781568b75bSmrg            return NULL;
6791568b75bSmrg        }
6801568b75bSmrg        nOut = 1;
6811568b75bSmrg    }
6821568b75bSmrg    else
6831568b75bSmrg    {
6841568b75bSmrg        orig = (char *) calloc(len, 1);
6851568b75bSmrg        if (!orig)
6861568b75bSmrg        {
6871568b75bSmrg            ERR("OOM in stringFromOptions\n");
6881568b75bSmrg            return NULL;
6891568b75bSmrg        }
6901568b75bSmrg        nOut = 0;
6911568b75bSmrg    }
6921568b75bSmrg    for (i = 0; i < numNew; i++)
6931568b75bSmrg    {
6941568b75bSmrg        if (!newOpts[i])
6951568b75bSmrg            continue;
6961568b75bSmrg        if (nOut > 0)
6971568b75bSmrg        {
6981568b75bSmrg            strcat(orig, ",");
6991568b75bSmrg            strcat(orig, newOpts[i]);
7001568b75bSmrg        }
7011568b75bSmrg        else
7021568b75bSmrg            strcpy(orig, newOpts[i]);
7031568b75bSmrg        nOut++;
7047d5e3a19Smrg    }
7057d5e3a19Smrg    return orig;
7067d5e3a19Smrg}
7077d5e3a19Smrg
7087d5e3a19Smrg/***====================================================================***/
7097d5e3a19Smrg
7107d5e3a19SmrgBool
7117d5e3a19SmrgapplyConfig(char *name)
7127d5e3a19Smrg{
7131568b75bSmrg    FILE *fp;
7141568b75bSmrg    Bool ok;
7151568b75bSmrg
7161568b75bSmrg    if ((fp = findFileInPath(name, "")) == NULL)
7171568b75bSmrg        return False;
7181568b75bSmrg    ok = XkbCFParse(fp, XkbCFDflts, NULL, &cfgResult);
7197d5e3a19Smrg    fclose(fp);
7201568b75bSmrg    if (!ok)
7211568b75bSmrg    {
7221568b75bSmrg        ERR1("Couldn't find configuration file \"%s\"\n", name);
7231568b75bSmrg        return False;
7247d5e3a19Smrg    }
7251568b75bSmrg    if (cfgResult.rules_file)
7261568b75bSmrg    {
7271568b75bSmrg        trySetString(RULES_NDX, cfgResult.rules_file, FROM_CONFIG);
7281568b75bSmrg        cfgResult.rules_file = NULL;
7297d5e3a19Smrg    }
7301568b75bSmrg    if (cfgResult.model)
7311568b75bSmrg    {
7321568b75bSmrg        trySetString(MODEL_NDX, cfgResult.model, FROM_CONFIG);
7331568b75bSmrg        cfgResult.model = NULL;
7347d5e3a19Smrg    }
7351568b75bSmrg    if (cfgResult.layout)
7361568b75bSmrg    {
7371568b75bSmrg        trySetString(LAYOUT_NDX, cfgResult.layout, FROM_CONFIG);
7381568b75bSmrg        cfgResult.layout = NULL;
7397d5e3a19Smrg    }
7401568b75bSmrg    if (cfgResult.variant)
7411568b75bSmrg    {
7421568b75bSmrg        trySetString(VARIANT_NDX, cfgResult.variant, FROM_CONFIG);
7431568b75bSmrg        cfgResult.variant = NULL;
7447d5e3a19Smrg    }
7451568b75bSmrg    if (cfgResult.options)
7461568b75bSmrg    {
7471568b75bSmrg        addStringToOptions(cfgResult.options, &szOptions, &numOptions,
7481568b75bSmrg                           &options);
7491568b75bSmrg        cfgResult.options = NULL;
7507d5e3a19Smrg    }
7511568b75bSmrg    if (cfgResult.keymap)
7521568b75bSmrg    {
7531568b75bSmrg        trySetString(KEYMAP_NDX, cfgResult.keymap, FROM_CONFIG);
7541568b75bSmrg        cfgResult.keymap = NULL;
7557d5e3a19Smrg    }
7561568b75bSmrg    if (cfgResult.keycodes)
7571568b75bSmrg    {
7581568b75bSmrg        trySetString(KEYCODES_NDX, cfgResult.keycodes, FROM_CONFIG);
7591568b75bSmrg        cfgResult.keycodes = NULL;
7607d5e3a19Smrg    }
7611568b75bSmrg    if (cfgResult.geometry)
7621568b75bSmrg    {
7631568b75bSmrg        trySetString(GEOMETRY_NDX, cfgResult.geometry, FROM_CONFIG);
7641568b75bSmrg        cfgResult.geometry = NULL;
7657d5e3a19Smrg    }
7661568b75bSmrg    if (cfgResult.symbols)
7671568b75bSmrg    {
7681568b75bSmrg        trySetString(SYMBOLS_NDX, cfgResult.symbols, FROM_CONFIG);
7691568b75bSmrg        cfgResult.symbols = NULL;
7707d5e3a19Smrg    }
7711568b75bSmrg    if (cfgResult.types)
7721568b75bSmrg    {
7731568b75bSmrg        trySetString(TYPES_NDX, cfgResult.types, FROM_CONFIG);
7741568b75bSmrg        cfgResult.types = NULL;
7757d5e3a19Smrg    }
7761568b75bSmrg    if (cfgResult.compat)
7771568b75bSmrg    {
7781568b75bSmrg        trySetString(COMPAT_NDX, cfgResult.compat, FROM_CONFIG);
7791568b75bSmrg        cfgResult.compat = NULL;
7807d5e3a19Smrg    }
7811568b75bSmrg    if (verbose > 5)
7821568b75bSmrg    {
7831568b75bSmrg        MSG("After config file:\n");
7841568b75bSmrg        dumpNames(True, True);
7857d5e3a19Smrg    }
7867d5e3a19Smrg    return True;
7877d5e3a19Smrg}
7887d5e3a19Smrg
7891568b75bSmrg/**
7901568b75bSmrg * If any of model, layout, variant or options is specified, then compile the
7911568b75bSmrg * options into the
7921568b75bSmrg *
7931568b75bSmrg * @return True on success or false otherwise.
7941568b75bSmrg */
7957d5e3a19SmrgBool
7967d5e3a19SmrgapplyRules(void)
7977d5e3a19Smrg{
7981568b75bSmrg    int i;
7991568b75bSmrg    char *rfName;
8007d5e3a19Smrg
8011568b75bSmrg    if (svSrc[MODEL_NDX] || svSrc[LAYOUT_NDX] || svSrc[VARIANT_NDX]
8021568b75bSmrg        || options)
8031568b75bSmrg    {
8041568b75bSmrg        char buf[PATH_MAX];
8051568b75bSmrg        XkbComponentNamesRec rnames;
8067d5e3a19Smrg
8071568b75bSmrg        if (svSrc[VARIANT_NDX] < svSrc[LAYOUT_NDX])
8087d5e3a19Smrg            svValue[VARIANT_NDX] = NULL;
8097d5e3a19Smrg
8101568b75bSmrg        rdefs.model = svValue[MODEL_NDX];
8111568b75bSmrg        rdefs.layout = svValue[LAYOUT_NDX];
8121568b75bSmrg        rdefs.variant = svValue[VARIANT_NDX];
8131568b75bSmrg        if (options)
8141568b75bSmrg            rdefs.options =
8151568b75bSmrg                stringFromOptions(rdefs.options, numOptions, options);
8161568b75bSmrg
8171568b75bSmrg        if (svSrc[RULES_NDX])
8181568b75bSmrg            rfName = svValue[RULES_NDX];
8191568b75bSmrg        else
8201568b75bSmrg            rfName = DFLT_XKB_RULES_FILE;
8211568b75bSmrg
8221568b75bSmrg        if (rfName[0] == '/')
8231568b75bSmrg        {
8241568b75bSmrg            rules = XkbRF_Load(rfName, svValue[LOCALE_NDX], True, True);
8251568b75bSmrg        }
8261568b75bSmrg        else
8271568b75bSmrg        {
8281568b75bSmrg            /* try to load rules files from all include paths until the first
8291568b75bSmrg             * we succeed with */
8301568b75bSmrg            for (i = 0; (i < numInclPath) && (!rules); i++)
8311568b75bSmrg            {
8321568b75bSmrg                if ((strlen(inclPath[i]) + strlen(rfName) + 8) > PATH_MAX)
8331568b75bSmrg                {
8341568b75bSmrg                    VMSG2(0, "Path too long (%s/rules/%s). Ignored.\n",
8351568b75bSmrg                          inclPath[i], rfName);
8361568b75bSmrg                    continue;
8371568b75bSmrg                }
8381568b75bSmrg                sprintf(buf, "%s/rules/%s", inclPath[i], svValue[RULES_NDX]);
8391568b75bSmrg                rules = XkbRF_Load(buf, svValue[LOCALE_NDX], True, True);
8401568b75bSmrg            }
8411568b75bSmrg        }
8421568b75bSmrg        if (!rules)
8431568b75bSmrg        {
8441568b75bSmrg            ERR1("Couldn't find rules file (%s) \n", svValue[RULES_NDX]);
8451568b75bSmrg            return False;
8461568b75bSmrg        }
8471568b75bSmrg        /* Let the rules file to the magic, then update the svValues with
8481568b75bSmrg         * those returned after processing the rules */
8491568b75bSmrg        XkbRF_GetComponents(rules, &rdefs, &rnames);
8501568b75bSmrg        if (rnames.keycodes)
8511568b75bSmrg        {
8521568b75bSmrg            trySetString(KEYCODES_NDX, rnames.keycodes, FROM_RULES);
8531568b75bSmrg            rnames.keycodes = NULL;
8541568b75bSmrg        }
8551568b75bSmrg        if (rnames.symbols)
8561568b75bSmrg        {
8571568b75bSmrg            trySetString(SYMBOLS_NDX, rnames.symbols, FROM_RULES);
8581568b75bSmrg            rnames.symbols = NULL;
8591568b75bSmrg        }
8601568b75bSmrg        if (rnames.types)
8611568b75bSmrg        {
8621568b75bSmrg            trySetString(TYPES_NDX, rnames.types, FROM_RULES);
8631568b75bSmrg            rnames.types = NULL;
8641568b75bSmrg        }
8651568b75bSmrg        if (rnames.compat)
8661568b75bSmrg        {
8671568b75bSmrg            trySetString(COMPAT_NDX, rnames.compat, FROM_RULES);
8681568b75bSmrg            rnames.compat = NULL;
8691568b75bSmrg        }
8701568b75bSmrg        if (rnames.geometry)
8711568b75bSmrg        {
8721568b75bSmrg            trySetString(GEOMETRY_NDX, rnames.geometry, FROM_RULES);
8731568b75bSmrg            rnames.geometry = NULL;
8741568b75bSmrg        }
8751568b75bSmrg        if (rnames.keymap)
8761568b75bSmrg        {
8771568b75bSmrg            trySetString(KEYMAP_NDX, rnames.keymap, FROM_RULES);
8781568b75bSmrg            rnames.keymap = NULL;
8791568b75bSmrg        }
8801568b75bSmrg        if (verbose > 6)
8811568b75bSmrg        {
8821568b75bSmrg            MSG1("Applied rules from %s:\n", svValue[RULES_NDX]);
8831568b75bSmrg            dumpNames(True, False);
8841568b75bSmrg        }
8851568b75bSmrg    }
8861568b75bSmrg    else if (verbose > 6)
8871568b75bSmrg    {
8881568b75bSmrg        MSG("No rules variables specified.  Rules file ignored\n");
8897d5e3a19Smrg    }
8907d5e3a19Smrg    return True;
8917d5e3a19Smrg}
8927d5e3a19Smrg
8937d5e3a19Smrg/* Primitive sanity check - filter out 'map names' (inside parenthesis) */
8947d5e3a19Smrg/* that can confuse xkbcomp parser */
8951568b75bSmrgstatic Bool
8961568b75bSmrgcheckName(char *name, char *string)
8977d5e3a19Smrg{
8981568b75bSmrg    char *i = name, *opar = NULL;
8991568b75bSmrg    Bool ret = True;
9001568b75bSmrg
9011568b75bSmrg    if (!name)
9021568b75bSmrg        return True;
9031568b75bSmrg
9041568b75bSmrg    while (*i)
9051568b75bSmrg    {
9061568b75bSmrg        if (opar == NULL)
9071568b75bSmrg        {
9081568b75bSmrg            if (*i == '(')
9091568b75bSmrg                opar = i;
9101568b75bSmrg        }
9111568b75bSmrg        else
9121568b75bSmrg        {
9131568b75bSmrg            if ((*i == '(') || (*i == '|') || (*i == '+'))
9141568b75bSmrg            {
9151568b75bSmrg                ret = False;
9161568b75bSmrg                break;
9171568b75bSmrg            }
9181568b75bSmrg            if (*i == ')')
9191568b75bSmrg                opar = NULL;
9201568b75bSmrg        }
9211568b75bSmrg        i++;
9221568b75bSmrg    }
9231568b75bSmrg    if (opar)
9241568b75bSmrg        ret = False;
9251568b75bSmrg    if (!ret)
9261568b75bSmrg    {
9271568b75bSmrg        char c;
9281568b75bSmrg        int n = 1;
9291568b75bSmrg        for (i = opar + 1; *i && n; i++)
9301568b75bSmrg        {
9311568b75bSmrg            if (*i == '(')
9321568b75bSmrg                n++;
9331568b75bSmrg            if (*i == ')')
9341568b75bSmrg                n--;
9351568b75bSmrg        }
9361568b75bSmrg        if (*i)
9371568b75bSmrg            i++;
9381568b75bSmrg        c = *i;
9391568b75bSmrg        *i = '\0';
9401568b75bSmrg        ERR1("Illegal map name '%s' ", opar);
9411568b75bSmrg        *i = c;
9421568b75bSmrg        ERR2("in %s name '%s'\n", string, name);
9431568b75bSmrg    }
9441568b75bSmrg    return ret;
9457d5e3a19Smrg}
9467d5e3a19Smrg
9477d5e3a19Smrgvoid
9487d5e3a19SmrgprintKeymap(void)
9497d5e3a19Smrg{
9507d5e3a19Smrg    MSG("xkb_keymap {\n");
9517d5e3a19Smrg    if (svValue[KEYCODES_NDX])
9521568b75bSmrg        MSG1("\txkb_keycodes  { include \"%s\"\t};\n", svValue[KEYCODES_NDX]);
9537d5e3a19Smrg    if (svValue[TYPES_NDX])
9541568b75bSmrg        MSG1("\txkb_types     { include \"%s\"\t};\n", svValue[TYPES_NDX]);
9557d5e3a19Smrg    if (svValue[COMPAT_NDX])
9561568b75bSmrg        MSG1("\txkb_compat    { include \"%s\"\t};\n", svValue[COMPAT_NDX]);
9577d5e3a19Smrg    if (svValue[SYMBOLS_NDX])
9581568b75bSmrg        MSG1("\txkb_symbols   { include \"%s\"\t};\n", svValue[SYMBOLS_NDX]);
9597d5e3a19Smrg    if (svValue[GEOMETRY_NDX])
9601568b75bSmrg        MSG1("\txkb_geometry  { include \"%s\"\t};\n", svValue[GEOMETRY_NDX]);
9617d5e3a19Smrg    MSG("};\n");
9627d5e3a19Smrg}
9637d5e3a19Smrg
9647d5e3a19SmrgBool
9657d5e3a19SmrgapplyComponentNames(void)
9667d5e3a19Smrg{
9671568b75bSmrg    if (!checkName(svValue[TYPES_NDX], "types"))
9681568b75bSmrg        return False;
9691568b75bSmrg    if (!checkName(svValue[COMPAT_NDX], "compat"))
9701568b75bSmrg        return False;
9711568b75bSmrg    if (!checkName(svValue[SYMBOLS_NDX], "symbols"))
9721568b75bSmrg        return False;
9731568b75bSmrg    if (!checkName(svValue[KEYCODES_NDX], "keycodes"))
9741568b75bSmrg        return False;
9751568b75bSmrg    if (!checkName(svValue[GEOMETRY_NDX], "geometry"))
9761568b75bSmrg        return False;
9771568b75bSmrg    if (!checkName(svValue[KEYMAP_NDX], "keymap"))
9781568b75bSmrg        return False;
9791568b75bSmrg
9801568b75bSmrg    if (verbose > 5)
9811568b75bSmrg    {
9821568b75bSmrg        MSG("Trying to build keymap using the following components:\n");
9831568b75bSmrg        dumpNames(False, True);
9841568b75bSmrg    }
9851568b75bSmrg    /* Upload the new description to the server. */
986765486e8Smrg    if (dpy && !print && !query)
9871568b75bSmrg    {
9881568b75bSmrg        XkbComponentNamesRec cmdNames;
9891568b75bSmrg        cmdNames.types = svValue[TYPES_NDX];
9901568b75bSmrg        cmdNames.compat = svValue[COMPAT_NDX];
9911568b75bSmrg        cmdNames.symbols = svValue[SYMBOLS_NDX];
9921568b75bSmrg        cmdNames.keycodes = svValue[KEYCODES_NDX];
9931568b75bSmrg        cmdNames.geometry = svValue[GEOMETRY_NDX];
9941568b75bSmrg        cmdNames.keymap = svValue[KEYMAP_NDX];
9951568b75bSmrg        xkb = XkbGetKeyboardByName(dpy, deviceSpec, &cmdNames,
9961568b75bSmrg                                   XkbGBN_AllComponentsMask,
9971568b75bSmrg                                   XkbGBN_AllComponentsMask &
9981568b75bSmrg                                   (~XkbGBN_GeometryMask), True);
9991568b75bSmrg        if (!xkb)
10001568b75bSmrg        {
10011568b75bSmrg            ERR("Error loading new keyboard description\n");
10021568b75bSmrg            return False;
10031568b75bSmrg        }
10041568b75bSmrg        /* update the XKB root property */
10051568b75bSmrg        if (svValue[RULES_NDX] && (rdefs.model || rdefs.layout))
10061568b75bSmrg        {
10071568b75bSmrg            if (!XkbRF_SetNamesProp(dpy, svValue[RULES_NDX], &rdefs))
10081568b75bSmrg            {
10091568b75bSmrg                VMSG(0, "Error updating the XKB names property\n");
10101568b75bSmrg            }
10111568b75bSmrg        }
10121568b75bSmrg    }
10131568b75bSmrg    if (print)
10141568b75bSmrg    {
10157d5e3a19Smrg        printKeymap();
10167d5e3a19Smrg    }
1017765486e8Smrg    if (query)
1018765486e8Smrg    {
1019765486e8Smrg	dumpNames(True, False);
1020765486e8Smrg    }
10217d5e3a19Smrg    return True;
10227d5e3a19Smrg}
10237d5e3a19Smrg
10247d5e3a19Smrg
10257d5e3a19Smrgint
10261568b75bSmrgmain(int argc, char **argv)
10277d5e3a19Smrg{
10281568b75bSmrg    if ((!parseArgs(argc, argv)) || (!getDisplay(argc, argv)))
10291568b75bSmrg        exit(-1);
10301568b75bSmrg    svValue[LOCALE_NDX] = setlocale(LC_ALL, svValue[LOCALE_NDX]);
10311568b75bSmrg    svSrc[LOCALE_NDX] = FROM_SERVER;
10321568b75bSmrg    VMSG1(7, "locale is %s\n", svValue[LOCALE_NDX]);
10337d5e3a19Smrg    if (dpy)
10347d5e3a19Smrg        getServerValues();
10357d5e3a19Smrg    if (svValue[CONFIG_NDX] && (!applyConfig(svValue[CONFIG_NDX])))
10361568b75bSmrg        exit(-3);
10377d5e3a19Smrg    if (!applyRules())
10381568b75bSmrg        exit(-4);
10397d5e3a19Smrg    if (!applyComponentNames())
10401568b75bSmrg        exit(-5);
10417d5e3a19Smrg    if (dpy)
10421568b75bSmrg        XCloseDisplay(dpy);
10437d5e3a19Smrg    exit(0);
10447d5e3a19Smrg}
1045