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