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