maprules.c revision 54cef2dd
1/************************************************************
2 Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#elif defined(HAVE_CONFIG_H)
30#include <config.h>
31#endif
32
33#include <stdio.h>
34#include <ctype.h>
35#include <stdlib.h>
36
37#define X_INCLUDE_STRING_H
38#define XOS_USE_NO_LOCKING
39#include <X11/Xos_r.h>
40
41
42#include <X11/Xproto.h>
43#include <X11/Xlib.h>
44#include <X11/Xos.h>
45#include <X11/Xfuncs.h>
46#include <X11/Xatom.h>
47#include <X11/keysym.h>
48#include <X11/XKBlib.h>
49#include <X11/extensions/XKBgeom.h>
50#include "XKMformat.h"
51#include "XKBfileInt.h"
52#include "XKBrules.h"
53
54
55#ifdef DEBUG
56#define PR_DEBUG(s)		fprintf(stderr,s)
57#define PR_DEBUG1(s,a)		fprintf(stderr,s,a)
58#define PR_DEBUG2(s,a,b)	fprintf(stderr,s,a,b)
59#else
60#define PR_DEBUG(s)
61#define PR_DEBUG1(s,a)
62#define PR_DEBUG2(s,a,b)
63#endif
64
65/***====================================================================***/
66
67#define DFLT_LINE_SIZE	128
68
69typedef struct {
70    int         line_num;
71    int         sz_line;
72    int         num_line;
73    char        buf[DFLT_LINE_SIZE];
74    char *      line;
75} InputLine;
76
77static void
78InitInputLine(InputLine *line)
79{
80    line->line_num = 1;
81    line->num_line = 0;
82    line->sz_line = DFLT_LINE_SIZE;
83    line->line = line->buf;
84    return;
85}
86
87static void
88FreeInputLine(InputLine *line)
89{
90    if (line->line != line->buf)
91        _XkbFree(line->line);
92    line->line_num = 1;
93    line->num_line = 0;
94    line->sz_line = DFLT_LINE_SIZE;
95    line->line = line->buf;
96    return;
97}
98
99static int
100InputLineAddChar(InputLine *line, int ch)
101{
102    if (line->num_line >= line->sz_line) {
103        if (line->line == line->buf) {
104            line->line = (char *) _XkbAlloc(line->sz_line * 2);
105            memcpy(line->line, line->buf, line->sz_line);
106        }
107        else {
108            line->line =
109                (char *) _XkbRealloc((char *) line->line, line->sz_line * 2);
110        }
111        line->sz_line *= 2;
112    }
113    line->line[line->num_line++] = ch;
114    return ch;
115}
116
117#define	ADD_CHAR(l,c)	((l)->num_line<(l)->sz_line?\
118				(int)((l)->line[(l)->num_line++]= (c)):\
119				InputLineAddChar(l,c))
120
121#ifdef HAVE_UNLOCKED_STDIO
122#undef getc
123#define getc(x) getc_unlocked(x)
124#else
125#define flockfile(x) do {} while (0)
126#define funlockfile(x) do {} while (0)
127#endif
128
129static Bool
130GetInputLine(FILE *file, InputLine *line, Bool checkbang)
131{
132    int ch;
133    Bool endOfFile, spacePending, slashPending, inComment;
134
135    endOfFile = False;
136    flockfile(file);
137    while ((!endOfFile) && (line->num_line == 0)) {
138        spacePending = slashPending = inComment = False;
139        while (((ch = getc(file)) != '\n') && (ch != EOF)) {
140            if (ch == '\\') {
141                if ((ch = getc(file)) == EOF)
142                    break;
143                if (ch == '\n') {
144                    inComment = False;
145                    ch = ' ';
146                    line->line_num++;
147                }
148            }
149            if (inComment)
150                continue;
151            if (ch == '/') {
152                if (slashPending) {
153                    inComment = True;
154                    slashPending = False;
155                }
156                else {
157                    slashPending = True;
158                }
159                continue;
160            }
161            else if (slashPending) {
162                if (spacePending) {
163                    ADD_CHAR(line, ' ');
164                    spacePending = False;
165                }
166                ADD_CHAR(line, '/');
167                slashPending = False;
168            }
169            if (isspace(ch)) {
170                while (isspace(ch) && (ch != '\n') && (ch != EOF)) {
171                    ch = getc(file);
172                }
173                if (ch == EOF)
174                    break;
175                if ((ch != '\n') && (line->num_line > 0))
176                    spacePending = True;
177                ungetc(ch, file);
178            }
179            else {
180                if (spacePending) {
181                    ADD_CHAR(line, ' ');
182                    spacePending = False;
183                }
184                if (checkbang && ch == '!') {
185                    if (line->num_line != 0) {
186                        PR_DEBUG("The '!' legal only at start of line\n");
187                        PR_DEBUG("Line containing '!' ignored\n");
188                        line->num_line = 0;
189                        inComment = 0;
190                        break;
191                    }
192
193                }
194                ADD_CHAR(line, ch);
195            }
196        }
197        if (ch == EOF)
198            endOfFile = True;
199/*	else line->num_line++;*/
200    }
201    funlockfile(file);
202    if ((line->num_line == 0) && (endOfFile))
203        return False;
204    ADD_CHAR(line, '\0');
205    return True;
206}
207
208/***====================================================================***/
209
210#define	MODEL		0
211#define	LAYOUT		1
212#define	VARIANT		2
213#define	OPTION		3
214#define	KEYCODES	4
215#define SYMBOLS		5
216#define	TYPES		6
217#define	COMPAT		7
218#define	GEOMETRY	8
219#define	KEYMAP		9
220#define	MAX_WORDS	10
221
222#define	PART_MASK	0x000F
223#define	COMPONENT_MASK	0x03F0
224
225static const char *cname[MAX_WORDS] = {
226    "model", "layout", "variant", "option",
227    "keycodes", "symbols", "types", "compat", "geometry", "keymap"
228};
229
230typedef struct _RemapSpec {
231    int number;
232    int num_remap;
233    struct {
234        int word;
235        int index;
236    } remap[MAX_WORDS];
237} RemapSpec;
238
239typedef struct _FileSpec {
240    char *name[MAX_WORDS];
241    struct _FileSpec *pending;
242} FileSpec;
243
244typedef struct {
245    char *model;
246    char *layout[XkbNumKbdGroups + 1];
247    char *variant[XkbNumKbdGroups + 1];
248    char *options;
249} XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
250
251#define NDX_BUFF_SIZE	4
252
253/***====================================================================***/
254
255static char *
256get_index(char *str, int *ndx)
257{
258    char ndx_buf[NDX_BUFF_SIZE];
259
260    char *end;
261
262    if (*str != '[') {
263        *ndx = 0;
264        return str;
265    }
266    str++;
267    end = strchr(str, ']');
268    if (end == NULL) {
269        *ndx = -1;
270        return str - 1;
271    }
272    if ((end - str) >= NDX_BUFF_SIZE) {
273        *ndx = -1;
274        return end + 1;
275    }
276    strncpy(ndx_buf, str, end - str);
277    ndx_buf[end - str] = '\0';
278    *ndx = atoi(ndx_buf);
279    return end + 1;
280}
281
282static void
283SetUpRemap(InputLine *line, RemapSpec *remap)
284{
285    char *tok, *str;
286    unsigned present, l_ndx_present, v_ndx_present;
287    register int i;
288    int len, ndx;
289    _Xstrtokparams strtok_buf;
290
291#ifdef DEBUG
292    Bool found;
293#endif
294
295    l_ndx_present = v_ndx_present = present = 0;
296    str = &line->line[1];
297    len = remap->number;
298    bzero((char *) remap, sizeof(RemapSpec));
299    remap->number = len;
300    while ((tok = _XStrtok(str, " ", strtok_buf)) != NULL) {
301#ifdef DEBUG
302        found = False;
303#endif
304        str = NULL;
305        if (strcmp(tok, "=") == 0)
306            continue;
307        for (i = 0; i < MAX_WORDS; i++) {
308            len = strlen(cname[i]);
309            if (strncmp(cname[i], tok, len) == 0) {
310                if (strlen(tok) > len) {
311                    char *end = get_index(tok + len, &ndx);
312
313                    if ((i != LAYOUT && i != VARIANT) ||
314                        *end != '\0' || ndx == -1)
315                        break;
316                    if (ndx < 1 || ndx > XkbNumKbdGroups) {
317                        PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
318                        PR_DEBUG1("Index must be in range 1..%d\n",
319                                  XkbNumKbdGroups);
320                        break;
321                    }
322                }
323                else {
324                    ndx = 0;
325                }
326#ifdef DEBUG
327                found = True;
328#endif
329                if (present & (1 << i)) {
330                    if ((i == LAYOUT && l_ndx_present & (1 << ndx)) ||
331                        (i == VARIANT && v_ndx_present & (1 << ndx))) {
332                        PR_DEBUG1("Component \"%s\" listed twice\n", tok);
333                        PR_DEBUG("Second definition ignored\n");
334                        break;
335                    }
336                }
337                present |= (1 << i);
338                if (i == LAYOUT)
339                    l_ndx_present |= 1 << ndx;
340                if (i == VARIANT)
341                    v_ndx_present |= 1 << ndx;
342                remap->remap[remap->num_remap].word = i;
343                remap->remap[remap->num_remap++].index = ndx;
344                break;
345            }
346        }
347#ifdef DEBUG
348        if (!found) {
349            fprintf(stderr, "Unknown component \"%s\" ignored\n", tok);
350        }
351#endif
352    }
353    if ((present & PART_MASK) == 0) {
354#ifdef DEBUG
355        unsigned mask = PART_MASK;
356
357        fprintf(stderr, "Mapping needs at least one of ");
358        for (i = 0; (i < MAX_WORDS); i++) {
359            if ((1L << i) & mask) {
360                mask &= ~(1L << i);
361                if (mask)
362                    fprintf(stderr, "\"%s,\" ", cname[i]);
363                else
364                    fprintf(stderr, "or \"%s\"\n", cname[i]);
365            }
366        }
367        fprintf(stderr, "Illegal mapping ignored\n");
368#endif
369        remap->num_remap = 0;
370        return;
371    }
372    if ((present & COMPONENT_MASK) == 0) {
373        PR_DEBUG("Mapping needs at least one component\n");
374        PR_DEBUG("Illegal mapping ignored\n");
375        remap->num_remap = 0;
376        return;
377    }
378    if (((present & COMPONENT_MASK) & (1 << KEYMAP)) &&
379        ((present & COMPONENT_MASK) != (1 << KEYMAP))) {
380        PR_DEBUG("Keymap cannot appear with other components\n");
381        PR_DEBUG("Illegal mapping ignored\n");
382        remap->num_remap = 0;
383        return;
384    }
385    remap->number++;
386    return;
387}
388
389static Bool
390MatchOneOf(char *wanted, char *vals_defined)
391{
392    char *str, *next;
393    int want_len = strlen(wanted);
394
395    for (str = vals_defined, next = NULL; str != NULL; str = next) {
396        int len;
397
398        next = strchr(str, ',');
399        if (next) {
400            len = next - str;
401            next++;
402        }
403        else {
404            len = strlen(str);
405        }
406        if ((len == want_len) && (strncmp(wanted, str, len) == 0))
407            return True;
408    }
409    return False;
410}
411
412/***====================================================================***/
413
414static Bool
415CheckLine(InputLine *    line,
416          RemapSpec *    remap,
417          XkbRF_RulePtr  rule,
418          XkbRF_GroupPtr group)
419{
420    char *str, *tok;
421    register int nread, i;
422    FileSpec tmp;
423    _Xstrtokparams strtok_buf;
424    Bool append = False;
425
426    if (line->line[0] == '!') {
427        if (line->line[1] == '$' ||
428            (line->line[1] == ' ' && line->line[2] == '$')) {
429            char *gname = strchr(line->line, '$');
430            char *words = strchr(gname, ' ');
431
432            if (!words)
433                return False;
434            *words++ = '\0';
435            for (; *words; words++) {
436                if (*words != '=' && *words != ' ')
437                    break;
438            }
439            if (*words == '\0')
440                return False;
441            group->name = _XkbDupString(gname);
442            group->words = _XkbDupString(words);
443            for (i = 1, words = group->words; *words; words++) {
444                if (*words == ' ') {
445                    *words++ = '\0';
446                    i++;
447                }
448            }
449            group->number = i;
450            return True;
451        }
452        else {
453            SetUpRemap(line, remap);
454            return False;
455        }
456    }
457
458    if (remap->num_remap == 0) {
459        PR_DEBUG("Must have a mapping before first line of data\n");
460        PR_DEBUG("Illegal line of data ignored\n");
461        return False;
462    }
463    bzero((char *) &tmp, sizeof(FileSpec));
464    str = line->line;
465    for (nread = 0; (tok = _XStrtok(str, " ", strtok_buf)) != NULL; nread++) {
466        str = NULL;
467        if (strcmp(tok, "=") == 0) {
468            nread--;
469            continue;
470        }
471        if (nread > remap->num_remap) {
472            PR_DEBUG("Too many words on a line\n");
473            PR_DEBUG1("Extra word \"%s\" ignored\n", tok);
474            continue;
475        }
476        tmp.name[remap->remap[nread].word] = tok;
477        if (*tok == '+' || *tok == '|')
478            append = True;
479    }
480    if (nread < remap->num_remap) {
481        PR_DEBUG1("Too few words on a line: %s\n", line->line);
482        PR_DEBUG("line ignored\n");
483        return False;
484    }
485
486    rule->flags = 0;
487    rule->number = remap->number;
488    if (tmp.name[OPTION])
489        rule->flags |= XkbRF_Option;
490    else if (append)
491        rule->flags |= XkbRF_Append;
492    else
493        rule->flags |= XkbRF_Normal;
494    rule->model = _XkbDupString(tmp.name[MODEL]);
495    rule->layout = _XkbDupString(tmp.name[LAYOUT]);
496    rule->variant = _XkbDupString(tmp.name[VARIANT]);
497    rule->option = _XkbDupString(tmp.name[OPTION]);
498
499    rule->keycodes = _XkbDupString(tmp.name[KEYCODES]);
500    rule->symbols = _XkbDupString(tmp.name[SYMBOLS]);
501    rule->types = _XkbDupString(tmp.name[TYPES]);
502    rule->compat = _XkbDupString(tmp.name[COMPAT]);
503    rule->geometry = _XkbDupString(tmp.name[GEOMETRY]);
504    rule->keymap = _XkbDupString(tmp.name[KEYMAP]);
505
506    rule->layout_num = rule->variant_num = 0;
507    for (i = 0; i < nread; i++) {
508        if (remap->remap[i].index) {
509            if (remap->remap[i].word == LAYOUT)
510                rule->layout_num = remap->remap[i].index;
511            if (remap->remap[i].word == VARIANT)
512                rule->variant_num = remap->remap[i].index;
513        }
514    }
515    return True;
516}
517
518static char *
519_Concat(char *str1, char *str2)
520{
521    int len;
522
523    if ((!str1) || (!str2))
524        return str1;
525    len = strlen(str1) + strlen(str2) + 1;
526    str1 = _XkbTypedRealloc(str1, len, char);
527    if (str1)
528        strcat(str1, str2);
529    return str1;
530}
531
532static void
533squeeze_spaces(char *p1)
534{
535    char *p2;
536
537    for (p2 = p1; *p2; p2++) {
538        *p1 = *p2;
539        if (*p1 != ' ')
540            p1++;
541    }
542    *p1 = '\0';
543}
544
545static Bool
546MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
547{
548
549    bzero((char *) mdefs, sizeof(XkbRF_MultiDefsRec));
550    mdefs->model = defs->model;
551    mdefs->options = _XkbDupString(defs->options);
552    if (mdefs->options)
553        squeeze_spaces(mdefs->options);
554
555    if (defs->layout) {
556        if (!strchr(defs->layout, ',')) {
557            mdefs->layout[0] = defs->layout;
558        }
559        else {
560            char *p;
561
562            int i;
563
564            mdefs->layout[1] = _XkbDupString(defs->layout);
565            if (mdefs->layout[1] == NULL)
566                return False;
567            squeeze_spaces(mdefs->layout[1]);
568            p = mdefs->layout[1];
569            for (i = 2; i <= XkbNumKbdGroups; i++) {
570                if ((p = strchr(p, ','))) {
571                    *p++ = '\0';
572                    mdefs->layout[i] = p;
573                }
574                else {
575                    break;
576                }
577            }
578            if (p && (p = strchr(p, ',')))
579                *p = '\0';
580        }
581    }
582
583    if (defs->variant) {
584        if (!strchr(defs->variant, ',')) {
585            mdefs->variant[0] = defs->variant;
586        }
587        else {
588            char *p;
589
590            int i;
591
592            mdefs->variant[1] = _XkbDupString(defs->variant);
593            if (mdefs->variant[1] == NULL)
594                return False;
595            squeeze_spaces(mdefs->variant[1]);
596            p = mdefs->variant[1];
597            for (i = 2; i <= XkbNumKbdGroups; i++) {
598                if ((p = strchr(p, ','))) {
599                    *p++ = '\0';
600                    mdefs->variant[i] = p;
601                }
602                else {
603                    break;
604                }
605            }
606            if (p && (p = strchr(p, ',')))
607                *p = '\0';
608        }
609    }
610    return True;
611}
612
613static void
614FreeMultiDefs(XkbRF_MultiDefsPtr defs)
615{
616    if (defs->options)
617        _XkbFree(defs->options);
618    if (defs->layout[1])
619        _XkbFree(defs->layout[1]);
620    if (defs->variant[1])
621        _XkbFree(defs->variant[1]);
622}
623
624static void
625Apply(char *src, char **dst)
626{
627    if (src) {
628        if (*src == '+' || *src == '|') {
629            *dst = _Concat(*dst, src);
630        }
631        else {
632            if (*dst == NULL)
633                *dst = _XkbDupString(src);
634        }
635    }
636}
637
638static void
639XkbRF_ApplyRule(XkbRF_RulePtr rule, XkbComponentNamesPtr names)
640{
641    rule->flags &= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
642
643    Apply(rule->keycodes, &names->keycodes);
644    Apply(rule->symbols,  &names->symbols);
645    Apply(rule->types,    &names->types);
646    Apply(rule->compat,   &names->compat);
647    Apply(rule->geometry, &names->geometry);
648    Apply(rule->keymap,   &names->keymap);
649}
650
651static Bool
652CheckGroup(XkbRF_RulesPtr rules, char *group_name, char *name)
653{
654    int i;
655    char *p;
656    XkbRF_GroupPtr group;
657
658    for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
659        if (!strcmp(group->name, group_name)) {
660            break;
661        }
662    }
663    if (i == rules->num_groups)
664        return False;
665    for (i = 0, p = group->words; i < group->number; i++, p += strlen(p) + 1) {
666        if (!strcmp(p, name)) {
667            return True;
668        }
669    }
670    return False;
671}
672
673static int
674XkbRF_CheckApplyRule(XkbRF_RulePtr        rule,
675                     XkbRF_MultiDefsPtr   mdefs,
676                     XkbComponentNamesPtr names,
677                     XkbRF_RulesPtr       rules)
678{
679    Bool pending = False;
680
681    if (rule->model != NULL) {
682        if (mdefs->model == NULL)
683            return 0;
684        if (strcmp(rule->model, "*") == 0) {
685            pending = True;
686        }
687        else {
688            if (rule->model[0] == '$') {
689                if (!CheckGroup(rules, rule->model, mdefs->model))
690                    return 0;
691            }
692            else {
693                if (strcmp(rule->model, mdefs->model) != 0)
694                    return 0;
695            }
696        }
697    }
698    if (rule->option != NULL) {
699        if (mdefs->options == NULL)
700            return 0;
701        if ((!MatchOneOf(rule->option, mdefs->options)))
702            return 0;
703    }
704
705    if (rule->layout != NULL) {
706        if (mdefs->layout[rule->layout_num] == NULL ||
707            *mdefs->layout[rule->layout_num] == '\0')
708            return 0;
709        if (strcmp(rule->layout, "*") == 0) {
710            pending = True;
711        }
712        else {
713            if (rule->layout[0] == '$') {
714                if (!CheckGroup(rules, rule->layout,
715                                mdefs->layout[rule->layout_num]))
716                    return 0;
717            }
718            else {
719                if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
720                    return 0;
721            }
722        }
723    }
724    if (rule->variant != NULL) {
725        if (mdefs->variant[rule->variant_num] == NULL ||
726            *mdefs->variant[rule->variant_num] == '\0')
727            return 0;
728        if (strcmp(rule->variant, "*") == 0) {
729            pending = True;
730        }
731        else {
732            if (rule->variant[0] == '$') {
733                if (!CheckGroup(rules, rule->variant,
734                                mdefs->variant[rule->variant_num]))
735                    return 0;
736            }
737            else {
738                if (strcmp(rule->variant,
739                           mdefs->variant[rule->variant_num]) != 0)
740                    return 0;
741            }
742        }
743    }
744    if (pending) {
745        rule->flags |= XkbRF_PendingMatch;
746        return rule->number;
747    }
748    /* exact match, apply it now */
749    XkbRF_ApplyRule(rule, names);
750    return rule->number;
751}
752
753static void
754XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
755{
756    register int i;
757    XkbRF_RulePtr rule;
758
759    for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
760        rule->flags &= ~XkbRF_PendingMatch;
761    }
762}
763
764static void
765XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules, XkbComponentNamesPtr names)
766{
767    int i;
768    XkbRF_RulePtr rule;
769
770    for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
771        if ((rule->flags & XkbRF_PendingMatch) == 0)
772            continue;
773        XkbRF_ApplyRule(rule, names);
774    }
775}
776
777static void
778XkbRF_CheckApplyRules(XkbRF_RulesPtr       rules,
779                      XkbRF_MultiDefsPtr   mdefs,
780                      XkbComponentNamesPtr names,
781                      int                  flags)
782{
783    int i;
784    XkbRF_RulePtr rule;
785    int skip;
786
787    for (rule = rules->rules, i = 0; i < rules->num_rules; rule++, i++) {
788        if ((rule->flags & flags) != flags)
789            continue;
790        skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
791        if (skip && !(flags & XkbRF_Option)) {
792            for (; (i < rules->num_rules) && (rule->number == skip);
793                 rule++, i++);
794            rule--;
795            i--;
796        }
797    }
798}
799
800/***====================================================================***/
801
802static char *
803XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
804{
805    char *str, *outstr, *orig, *var;
806    int len, ndx;
807
808    orig = name;
809    str = index(name, '%');
810    if (str == NULL)
811        return name;
812    len = strlen(name);
813    while (str != NULL) {
814        char pfx = str[1];
815        int extra_len = 0;
816
817        if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
818            extra_len = 1;
819            str++;
820        }
821        else if (pfx == '(') {
822            extra_len = 2;
823            str++;
824        }
825        var = str + 1;
826        str = get_index(var + 1, &ndx);
827        if (ndx == -1) {
828            str = index(str, '%');
829            continue;
830        }
831        if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
832            len += strlen(mdefs->layout[ndx]) + extra_len;
833        else if ((*var == 'm') && mdefs->model)
834            len += strlen(mdefs->model) + extra_len;
835        else if ((*var == 'v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
836            len += strlen(mdefs->variant[ndx]) + extra_len;
837        if ((pfx == '(') && (*str == ')')) {
838            str++;
839        }
840        str = index(&str[0], '%');
841    }
842    name = (char *) _XkbAlloc(len + 1);
843    str = orig;
844    outstr = name;
845    while (*str != '\0') {
846        if (str[0] == '%') {
847            char pfx, sfx;
848
849            str++;
850            pfx = str[0];
851            sfx = '\0';
852            if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
853                str++;
854            }
855            else if (pfx == '(') {
856                sfx = ')';
857                str++;
858            }
859            else
860                pfx = '\0';
861
862            var = str;
863            str = get_index(var + 1, &ndx);
864            if (ndx == -1) {
865                continue;
866            }
867            if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
868                if (pfx)
869                    *outstr++ = pfx;
870                strcpy(outstr, mdefs->layout[ndx]);
871                outstr += strlen(mdefs->layout[ndx]);
872                if (sfx)
873                    *outstr++ = sfx;
874            }
875            else if ((*var == 'm') && (mdefs->model)) {
876                if (pfx)
877                    *outstr++ = pfx;
878                strcpy(outstr, mdefs->model);
879                outstr += strlen(mdefs->model);
880                if (sfx)
881                    *outstr++ = sfx;
882            }
883            else if ((*var == 'v') && mdefs->variant[ndx] &&
884                     *mdefs->variant[ndx]) {
885                if (pfx)
886                    *outstr++ = pfx;
887                strcpy(outstr, mdefs->variant[ndx]);
888                outstr += strlen(mdefs->variant[ndx]);
889                if (sfx)
890                    *outstr++ = sfx;
891            }
892            if ((pfx == '(') && (*str == ')'))
893                str++;
894        }
895        else {
896            *outstr++ = *str++;
897        }
898    }
899    *outstr++ = '\0';
900    if (orig != name)
901        _XkbFree(orig);
902    return name;
903}
904
905/***====================================================================***/
906
907Bool
908XkbRF_GetComponents(XkbRF_RulesPtr       rules,
909                    XkbRF_VarDefsPtr     defs,
910                    XkbComponentNamesPtr names)
911{
912    XkbRF_MultiDefsRec mdefs;
913
914    MakeMultiDefs(&mdefs, defs);
915
916    bzero((char *) names, sizeof(XkbComponentNamesRec));
917    XkbRF_ClearPartialMatches(rules);
918    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
919    XkbRF_ApplyPartialMatches(rules, names);
920    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
921    XkbRF_ApplyPartialMatches(rules, names);
922    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
923    XkbRF_ApplyPartialMatches(rules, names);
924
925    if (names->keycodes)
926        names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs);
927    if (names->symbols)
928        names->symbols  = XkbRF_SubstituteVars(names->symbols, &mdefs);
929    if (names->types)
930        names->types    = XkbRF_SubstituteVars(names->types, &mdefs);
931    if (names->compat)
932        names->compat   = XkbRF_SubstituteVars(names->compat, &mdefs);
933    if (names->geometry)
934        names->geometry = XkbRF_SubstituteVars(names->geometry, &mdefs);
935    if (names->keymap)
936        names->keymap   = XkbRF_SubstituteVars(names->keymap, &mdefs);
937
938    FreeMultiDefs(&mdefs);
939    return (names->keycodes && names->symbols && names->types &&
940            names->compat && names->geometry) || names->keymap;
941}
942
943XkbRF_RulePtr
944XkbRF_AddRule(XkbRF_RulesPtr rules)
945{
946    if (rules->sz_rules < 1) {
947        rules->sz_rules = 16;
948        rules->num_rules = 0;
949        rules->rules = _XkbTypedCalloc(rules->sz_rules, XkbRF_RuleRec);
950    }
951    else if (rules->num_rules >= rules->sz_rules) {
952        rules->sz_rules *= 2;
953        rules->rules = _XkbTypedRealloc(rules->rules, rules->sz_rules,
954                                        XkbRF_RuleRec);
955    }
956    if (!rules->rules) {
957        rules->sz_rules = rules->num_rules = 0;
958#ifdef DEBUG
959        fprintf(stderr, "Allocation failure in XkbRF_AddRule\n");
960#endif
961        return NULL;
962    }
963    bzero((char *) &rules->rules[rules->num_rules], sizeof(XkbRF_RuleRec));
964    return &rules->rules[rules->num_rules++];
965}
966
967XkbRF_GroupPtr
968XkbRF_AddGroup(XkbRF_RulesPtr rules)
969{
970    if (rules->sz_groups < 1) {
971        rules->sz_groups = 16;
972        rules->num_groups = 0;
973        rules->groups = _XkbTypedCalloc(rules->sz_groups, XkbRF_GroupRec);
974    }
975    else if (rules->num_groups >= rules->sz_groups) {
976        rules->sz_groups *= 2;
977        rules->groups = _XkbTypedRealloc(rules->groups, rules->sz_groups,
978                                         XkbRF_GroupRec);
979    }
980    if (!rules->groups) {
981        rules->sz_groups = rules->num_groups = 0;
982        return NULL;
983    }
984
985    bzero((char *) &rules->groups[rules->num_groups], sizeof(XkbRF_GroupRec));
986    return &rules->groups[rules->num_groups++];
987}
988
989Bool
990XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
991{
992    InputLine line;
993    RemapSpec remap;
994    XkbRF_RuleRec trule, *rule;
995    XkbRF_GroupRec tgroup, *group;
996
997    if (!(rules && file))
998        return False;
999    bzero((char *) &remap, sizeof(RemapSpec));
1000    bzero((char *) &tgroup, sizeof(XkbRF_GroupRec));
1001    InitInputLine(&line);
1002    while (GetInputLine(file, &line, True)) {
1003        if (CheckLine(&line, &remap, &trule, &tgroup)) {
1004            if (tgroup.number) {
1005                if ((group = XkbRF_AddGroup(rules)) != NULL) {
1006                    *group = tgroup;
1007                    bzero((char *) &tgroup, sizeof(XkbRF_GroupRec));
1008                }
1009            }
1010            else {
1011                if ((rule = XkbRF_AddRule(rules)) != NULL) {
1012                    *rule = trule;
1013                    bzero((char *) &trule, sizeof(XkbRF_RuleRec));
1014                }
1015            }
1016        }
1017        line.num_line = 0;
1018    }
1019    FreeInputLine(&line);
1020    return True;
1021}
1022
1023Bool
1024XkbRF_LoadRulesByName(char *base, char *locale, XkbRF_RulesPtr rules)
1025{
1026    FILE *file;
1027    char buf[PATH_MAX];
1028    Bool ok;
1029
1030    if ((!base) || (!rules))
1031        return False;
1032    if (locale) {
1033        if (strlen(base) + strlen(locale) + 2 > PATH_MAX)
1034            return False;
1035        snprintf(buf, sizeof(buf), "%s-%s", base, locale);
1036    }
1037    else {
1038        if (strlen(base) + 1 > PATH_MAX)
1039            return False;
1040        strcpy(buf, base);
1041    }
1042
1043    file = fopen(buf, "r");
1044    if ((!file) && (locale)) {  /* fallback if locale was specified */
1045        strcpy(buf, base);
1046        file = fopen(buf, "r");
1047    }
1048    if (!file)
1049        return False;
1050    ok = XkbRF_LoadRules(file, rules);
1051    fclose(file);
1052    return ok;
1053}
1054
1055/***====================================================================***/
1056
1057#define HEAD_NONE	0
1058#define HEAD_MODEL	1
1059#define HEAD_LAYOUT	2
1060#define HEAD_VARIANT	3
1061#define HEAD_OPTION	4
1062#define	HEAD_EXTRA	5
1063
1064XkbRF_VarDescPtr
1065XkbRF_AddVarDesc(XkbRF_DescribeVarsPtr vars)
1066{
1067    if (vars->sz_desc < 1) {
1068        vars->sz_desc = 16;
1069        vars->num_desc = 0;
1070        vars->desc = _XkbTypedCalloc(vars->sz_desc, XkbRF_VarDescRec);
1071    }
1072    else if (vars->num_desc >= vars->sz_desc) {
1073        vars->sz_desc *= 2;
1074        vars->desc =
1075            _XkbTypedRealloc(vars->desc, vars->sz_desc, XkbRF_VarDescRec);
1076    }
1077    if (!vars->desc) {
1078        vars->sz_desc = vars->num_desc = 0;
1079        PR_DEBUG("Allocation failure in XkbRF_AddVarDesc\n");
1080        return NULL;
1081    }
1082    vars->desc[vars->num_desc].name = NULL;
1083    vars->desc[vars->num_desc].desc = NULL;
1084    return &vars->desc[vars->num_desc++];
1085}
1086
1087XkbRF_VarDescPtr
1088XkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars, XkbRF_VarDescPtr from)
1089{
1090    XkbRF_VarDescPtr nd;
1091
1092    if ((nd = XkbRF_AddVarDesc(vars)) != NULL) {
1093        nd->name = _XkbDupString(from->name);
1094        nd->desc = _XkbDupString(from->desc);
1095    }
1096    return nd;
1097}
1098
1099XkbRF_DescribeVarsPtr
1100XkbRF_AddVarToDescribe(XkbRF_RulesPtr rules, char *name)
1101{
1102    if (rules->sz_extra < 1) {
1103        rules->num_extra = 0;
1104        rules->sz_extra = 1;
1105        rules->extra_names = _XkbTypedCalloc(rules->sz_extra, char *);
1106
1107        rules->extra = _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
1108    }
1109    else if (rules->num_extra >= rules->sz_extra) {
1110        rules->sz_extra *= 2;
1111        rules->extra_names =
1112            _XkbTypedRealloc(rules->extra_names, rules->sz_extra, char *);
1113        rules->extra =
1114            _XkbTypedRealloc(rules->extra, rules->sz_extra,
1115                             XkbRF_DescribeVarsRec);
1116    }
1117    if ((!rules->extra_names) || (!rules->extra)) {
1118        PR_DEBUG("allocation error in extra parts\n");
1119        rules->sz_extra = rules->num_extra = 0;
1120        rules->extra_names = NULL;
1121        rules->extra = NULL;
1122        return NULL;
1123    }
1124    rules->extra_names[rules->num_extra] = _XkbDupString(name);
1125    bzero(&rules->extra[rules->num_extra], sizeof(XkbRF_DescribeVarsRec));
1126    return &rules->extra[rules->num_extra++];
1127}
1128
1129Bool
1130XkbRF_LoadDescriptions(FILE *file, XkbRF_RulesPtr rules)
1131{
1132    InputLine line;
1133    XkbRF_VarDescRec tmp;
1134    char *tok;
1135    int len, headingtype, extra_ndx = 0;
1136
1137    bzero((char *) &tmp, sizeof(XkbRF_VarDescRec));
1138    headingtype = HEAD_NONE;
1139    InitInputLine(&line);
1140    for (; GetInputLine(file, &line, False); line.num_line = 0) {
1141        if (line.line[0] == '!') {
1142            tok = strtok(&(line.line[1]), " \t");
1143            if (strcmp(tok, "model") == 0)
1144                headingtype = HEAD_MODEL;
1145            else if (_XkbStrCaseCmp(tok, "layout") == 0)
1146                headingtype = HEAD_LAYOUT;
1147            else if (_XkbStrCaseCmp(tok, "variant") == 0)
1148                headingtype = HEAD_VARIANT;
1149            else if (_XkbStrCaseCmp(tok, "option") == 0)
1150                headingtype = HEAD_OPTION;
1151            else {
1152                int i;
1153
1154                headingtype = HEAD_EXTRA;
1155                extra_ndx = -1;
1156                for (i = 0; (i < rules->num_extra) && (extra_ndx < 0); i++) {
1157                    if (_XkbStrCaseCmp(tok, rules->extra_names[i]))
1158                        extra_ndx = i;
1159                }
1160                if (extra_ndx < 0) {
1161                    XkbRF_DescribeVarsPtr var;
1162
1163                    PR_DEBUG1("Extra heading \"%s\" encountered\n", tok);
1164                    var = XkbRF_AddVarToDescribe(rules, tok);
1165                    if (var)
1166                        extra_ndx = var - rules->extra;
1167                    else
1168                        headingtype = HEAD_NONE;
1169                }
1170            }
1171            continue;
1172        }
1173
1174        if (headingtype == HEAD_NONE) {
1175            PR_DEBUG("Must have a heading before first line of data\n");
1176            PR_DEBUG("Illegal line of data ignored\n");
1177            continue;
1178        }
1179
1180        len = strlen(line.line);
1181        if ((tmp.name = strtok(line.line, " \t")) == NULL) {
1182            PR_DEBUG("Huh? No token on line\n");
1183            PR_DEBUG("Illegal line of data ignored\n");
1184            continue;
1185        }
1186        if (strlen(tmp.name) == len) {
1187            PR_DEBUG("No description found\n");
1188            PR_DEBUG("Illegal line of data ignored\n");
1189            continue;
1190        }
1191
1192        tok = line.line + strlen(tmp.name) + 1;
1193        while ((*tok != '\n') && isspace(*tok))
1194            tok++;
1195        if (*tok == '\0') {
1196            PR_DEBUG("No description found\n");
1197            PR_DEBUG("Illegal line of data ignored\n");
1198            continue;
1199        }
1200        tmp.desc = tok;
1201        switch (headingtype) {
1202        case HEAD_MODEL:
1203            XkbRF_AddVarDescCopy(&rules->models, &tmp);
1204            break;
1205        case HEAD_LAYOUT:
1206            XkbRF_AddVarDescCopy(&rules->layouts, &tmp);
1207            break;
1208        case HEAD_VARIANT:
1209            XkbRF_AddVarDescCopy(&rules->variants, &tmp);
1210            break;
1211        case HEAD_OPTION:
1212            XkbRF_AddVarDescCopy(&rules->options, &tmp);
1213            break;
1214        case HEAD_EXTRA:
1215            XkbRF_AddVarDescCopy(&rules->extra[extra_ndx], &tmp);
1216            break;
1217        }
1218    }
1219    FreeInputLine(&line);
1220    if ((rules->models.num_desc == 0) && (rules->layouts.num_desc == 0) &&
1221        (rules->variants.num_desc == 0) && (rules->options.num_desc == 0) &&
1222        (rules->num_extra == 0)) {
1223        return False;
1224    }
1225    return True;
1226}
1227
1228Bool
1229XkbRF_LoadDescriptionsByName(char *base, char *locale, XkbRF_RulesPtr rules)
1230{
1231    FILE *file;
1232    char buf[PATH_MAX];
1233    Bool ok;
1234
1235    if ((!base) || (!rules))
1236        return False;
1237    if (locale) {
1238        if (strlen(base) + strlen(locale) + 6 > PATH_MAX)
1239            return False;
1240        snprintf(buf, sizeof(buf), "%s-%s.lst", base, locale);
1241    }
1242    else {
1243        if (strlen(base) + 5 > PATH_MAX)
1244            return False;
1245        snprintf(buf, sizeof(buf), "%s.lst", base);
1246    }
1247
1248    file = fopen(buf, "r");
1249    if ((!file) && (locale)) {  /* fallback if locale was specified */
1250        snprintf(buf, sizeof(buf), "%s.lst", base);
1251
1252        file = fopen(buf, "r");
1253    }
1254    if (!file)
1255        return False;
1256    ok = XkbRF_LoadDescriptions(file, rules);
1257    fclose(file);
1258    return ok;
1259}
1260
1261/***====================================================================***/
1262
1263XkbRF_RulesPtr
1264XkbRF_Load(char *base, char *locale, Bool wantDesc, Bool wantRules)
1265{
1266    XkbRF_RulesPtr rules;
1267
1268    if ((!base) || ((!wantDesc) && (!wantRules)))
1269        return NULL;
1270    if ((rules = _XkbTypedCalloc(1, XkbRF_RulesRec)) == NULL)
1271        return NULL;
1272    if (wantDesc && (!XkbRF_LoadDescriptionsByName(base, locale, rules))) {
1273        XkbRF_Free(rules, True);
1274        return NULL;
1275    }
1276    if (wantRules && (!XkbRF_LoadRulesByName(base, locale, rules))) {
1277        XkbRF_Free(rules, True);
1278        return NULL;
1279    }
1280    return rules;
1281}
1282
1283XkbRF_RulesPtr
1284XkbRF_Create(int szRules, int szExtra)
1285{
1286    XkbRF_RulesPtr rules;
1287
1288    if ((rules = _XkbTypedCalloc(1, XkbRF_RulesRec)) == NULL)
1289        return NULL;
1290    if (szRules > 0) {
1291        rules->sz_rules = szRules;
1292        rules->rules = _XkbTypedCalloc(rules->sz_rules, XkbRF_RuleRec);
1293        if (!rules->rules) {
1294            _XkbFree(rules);
1295            return NULL;
1296        }
1297    }
1298    if (szExtra > 0) {
1299        rules->sz_extra = szExtra;
1300        rules->extra = _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
1301        if (!rules->extra) {
1302            if (rules->rules)
1303                _XkbFree(rules->rules);
1304            _XkbFree(rules);
1305            return NULL;
1306        }
1307    }
1308    return rules;
1309}
1310
1311/***====================================================================***/
1312
1313static void
1314XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
1315{
1316    register int i;
1317
1318    for (i = 0; i < var->num_desc; i++) {
1319        if (var->desc[i].name)
1320            _XkbFree(var->desc[i].name);
1321        if (var->desc[i].desc)
1322            _XkbFree(var->desc[i].desc);
1323        var->desc[i].name = var->desc[i].desc = NULL;
1324    }
1325    if (var->desc)
1326        _XkbFree(var->desc);
1327    var->desc = NULL;
1328    return;
1329}
1330
1331void
1332XkbRF_Free(XkbRF_RulesPtr rules, Bool freeRules)
1333{
1334    int i;
1335    XkbRF_RulePtr rule;
1336    XkbRF_GroupPtr group;
1337
1338    if (!rules)
1339        return;
1340    XkbRF_ClearVarDescriptions(&rules->models);
1341    XkbRF_ClearVarDescriptions(&rules->layouts);
1342    XkbRF_ClearVarDescriptions(&rules->variants);
1343    XkbRF_ClearVarDescriptions(&rules->options);
1344    if (rules->extra) {
1345        for (i = 0; i < rules->num_extra; i++) {
1346            XkbRF_ClearVarDescriptions(&rules->extra[i]);
1347        }
1348        _XkbFree(rules->extra);
1349        rules->num_extra = rules->sz_extra = 0;
1350        rules->extra = NULL;
1351    }
1352    if (rules->rules) {
1353        for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
1354            if (rule->model)
1355                _XkbFree(rule->model);
1356            if (rule->layout)
1357                _XkbFree(rule->layout);
1358            if (rule->variant)
1359                _XkbFree(rule->variant);
1360            if (rule->option)
1361                _XkbFree(rule->option);
1362            if (rule->keycodes)
1363                _XkbFree(rule->keycodes);
1364            if (rule->symbols)
1365                _XkbFree(rule->symbols);
1366            if (rule->types)
1367                _XkbFree(rule->types);
1368            if (rule->compat)
1369                _XkbFree(rule->compat);
1370            if (rule->geometry)
1371                _XkbFree(rule->geometry);
1372            if (rule->keymap)
1373                _XkbFree(rule->keymap);
1374            bzero((char *) rule, sizeof(XkbRF_RuleRec));
1375        }
1376        _XkbFree(rules->rules);
1377        rules->num_rules = rules->sz_rules = 0;
1378        rules->rules = NULL;
1379    }
1380
1381    if (rules->groups) {
1382        for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
1383            if (group->name)
1384                _XkbFree(group->name);
1385            if (group->words)
1386                _XkbFree(group->words);
1387        }
1388        _XkbFree(rules->groups);
1389        rules->num_groups = 0;
1390        rules->groups = NULL;
1391    }
1392    if (freeRules)
1393        _XkbFree(rules);
1394    return;
1395}
1396
1397
1398Bool
1399XkbRF_GetNamesProp(Display * dpy, char **rf_rtrn, XkbRF_VarDefsPtr vd_rtrn)
1400{
1401    Atom rules_atom, actual_type;
1402    int fmt;
1403    unsigned long nitems, bytes_after;
1404    unsigned char *data;
1405    char *out, *end;
1406    Status rtrn;
1407
1408    rules_atom = XInternAtom(dpy, _XKB_RF_NAMES_PROP_ATOM, True);
1409    if (rules_atom == None)     /* property cannot exist */
1410        return False;
1411    rtrn = XGetWindowProperty(dpy, DefaultRootWindow(dpy), rules_atom,
1412                              0L, _XKB_RF_NAMES_PROP_MAXLEN, False,
1413                              XA_STRING, &actual_type,
1414                              &fmt, &nitems, &bytes_after,
1415                              (unsigned char **) &data);
1416    if (rtrn != Success)
1417        return False;
1418    if (rf_rtrn)
1419        *rf_rtrn = NULL;
1420    (void) bzero((char *) vd_rtrn, sizeof(XkbRF_VarDefsRec));
1421    if ((bytes_after > 0) || (actual_type != XA_STRING) || (fmt != 8)) {
1422        if (data)
1423            XFree(data);
1424        return (fmt == 0 ? True : False);
1425    }
1426
1427    out = (char *) data;
1428    end = out + nitems;
1429    if (out && (*out) && rf_rtrn)
1430        *rf_rtrn = _XkbDupString(out);
1431    out += strlen(out) + 1;
1432
1433    if (out < end) {
1434        if (*out)
1435            vd_rtrn->model = _XkbDupString(out);
1436        out += strlen(out) + 1;
1437    }
1438
1439    if (out < end) {
1440        if (*out)
1441            vd_rtrn->layout = _XkbDupString(out);
1442        out += strlen(out) + 1;
1443    }
1444
1445    if (out < end) {
1446        if (*out)
1447            vd_rtrn->variant = _XkbDupString(out);
1448        out += strlen(out) + 1;
1449    }
1450
1451    if (out < end) {
1452        if (*out)
1453            vd_rtrn->options = _XkbDupString(out);
1454        out += strlen(out) + 1;
1455    }
1456
1457    XFree(data);
1458    return True;
1459}
1460
1461Bool
1462XkbRF_SetNamesProp(Display *dpy, char *rules_file, XkbRF_VarDefsPtr var_defs)
1463{
1464    int len, out;
1465    Atom name;
1466    char *pval;
1467
1468    len = (rules_file ? strlen(rules_file) : 0);
1469    len += (var_defs->model ? strlen(var_defs->model) : 0);
1470    len += (var_defs->layout ? strlen(var_defs->layout) : 0);
1471    len += (var_defs->variant ? strlen(var_defs->variant) : 0);
1472    len += (var_defs->options ? strlen(var_defs->options) : 0);
1473    if (len < 1)
1474        return True;
1475
1476    len += 5;                   /* trailing NULs */
1477
1478    name = XInternAtom(dpy, _XKB_RF_NAMES_PROP_ATOM, False);
1479    if (name == None) {         /* should never happen */
1480        _XkbLibError(_XkbErrXReqFailure, "XkbRF_SetNamesProp", X_InternAtom);
1481        return False;
1482    }
1483    pval = (char *) _XkbAlloc(len);
1484    if (!pval) {
1485        _XkbLibError(_XkbErrBadAlloc, "XkbRF_SetNamesProp", len);
1486        return False;
1487    }
1488    out = 0;
1489    if (rules_file) {
1490        strcpy(&pval[out], rules_file);
1491        out += strlen(rules_file);
1492    }
1493    pval[out++] = '\0';
1494    if (var_defs->model) {
1495        strcpy(&pval[out], var_defs->model);
1496        out += strlen(var_defs->model);
1497    }
1498    pval[out++] = '\0';
1499    if (var_defs->layout) {
1500        strcpy(&pval[out], var_defs->layout);
1501        out += strlen(var_defs->layout);
1502    }
1503    pval[out++] = '\0';
1504    if (var_defs->variant) {
1505        strcpy(&pval[out], var_defs->variant);
1506        out += strlen(var_defs->variant);
1507    }
1508    pval[out++] = '\0';
1509    if (var_defs->options) {
1510        strcpy(&pval[out], var_defs->options);
1511        out += strlen(var_defs->options);
1512    }
1513    pval[out++] = '\0';
1514    if (out != len) {
1515        _XkbLibError(_XkbErrBadLength, "XkbRF_SetNamesProp", out);
1516        _XkbFree(pval);
1517        return False;
1518    }
1519
1520    XChangeProperty(dpy, DefaultRootWindow(dpy), name, XA_STRING, 8,
1521                    PropModeReplace, (unsigned char *) pval, len);
1522    _XkbFree(pval);
1523    return True;
1524}
1525
1526