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