maprules.c revision 6747b715
105b261ecSmrg/************************************************************
205b261ecSmrg Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc.
305b261ecSmrg
405b261ecSmrg Permission to use, copy, modify, and distribute this
505b261ecSmrg software and its documentation for any purpose and without
605b261ecSmrg fee is hereby granted, provided that the above copyright
705b261ecSmrg notice appear in all copies and that both that copyright
805b261ecSmrg notice and this permission notice appear in supporting
905b261ecSmrg documentation, and that the name of Silicon Graphics not be
1005b261ecSmrg used in advertising or publicity pertaining to distribution
1105b261ecSmrg of the software without specific prior written permission.
1205b261ecSmrg Silicon Graphics makes no representation about the suitability
1305b261ecSmrg of this software for any purpose. It is provided "as is"
1405b261ecSmrg without any express or implied warranty.
1505b261ecSmrg
1605b261ecSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1705b261ecSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1805b261ecSmrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
1905b261ecSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2005b261ecSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2105b261ecSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2205b261ecSmrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
2305b261ecSmrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
2405b261ecSmrg
2505b261ecSmrg ********************************************************/
2605b261ecSmrg
2705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2805b261ecSmrg#include <dix-config.h>
2905b261ecSmrg#endif
3005b261ecSmrg
3105b261ecSmrg#include <stdio.h>
3205b261ecSmrg#include <ctype.h>
3305b261ecSmrg#include <stdlib.h>
3405b261ecSmrg
3505b261ecSmrg#define X_INCLUDE_STRING_H
3605b261ecSmrg#define XOS_USE_NO_LOCKING
3705b261ecSmrg#include <X11/Xos_r.h>
3805b261ecSmrg
3905b261ecSmrg#include <X11/Xproto.h>
4005b261ecSmrg#include <X11/X.h>
4105b261ecSmrg#include <X11/Xos.h>
4205b261ecSmrg#include <X11/Xfuncs.h>
4305b261ecSmrg#include <X11/Xatom.h>
4405b261ecSmrg#include <X11/keysym.h>
4505b261ecSmrg#include "misc.h"
4605b261ecSmrg#include "inputstr.h"
4705b261ecSmrg#include "dix.h"
484642e01fSmrg#include "os.h"
494642e01fSmrg#include "xkbstr.h"
5005b261ecSmrg#define XKBSRV_NEED_FILE_FUNCS
5105b261ecSmrg#include <xkbsrv.h>
5205b261ecSmrg
5305b261ecSmrg/***====================================================================***/
5405b261ecSmrg
556747b715Smrg
566747b715Smrg
5705b261ecSmrg#define DFLT_LINE_SIZE	128
5805b261ecSmrg
5905b261ecSmrgtypedef struct {
6005b261ecSmrg	int	line_num;
6105b261ecSmrg	int	sz_line;
6205b261ecSmrg	int	num_line;
6305b261ecSmrg	char	buf[DFLT_LINE_SIZE];
6405b261ecSmrg	char *	line;
6505b261ecSmrg} InputLine;
6605b261ecSmrg
6705b261ecSmrgstatic void
6805b261ecSmrgInitInputLine(InputLine *line)
6905b261ecSmrg{
7005b261ecSmrg    line->line_num= 1;
7105b261ecSmrg    line->num_line= 0;
7205b261ecSmrg    line->sz_line= DFLT_LINE_SIZE;
7305b261ecSmrg    line->line=	line->buf;
7405b261ecSmrg    return;
7505b261ecSmrg}
7605b261ecSmrg
7705b261ecSmrgstatic void
7805b261ecSmrgFreeInputLine(InputLine *line)
7905b261ecSmrg{
8005b261ecSmrg    if (line->line!=line->buf)
816747b715Smrg	free(line->line);
8205b261ecSmrg    line->line_num= 1;
8305b261ecSmrg    line->num_line= 0;
8405b261ecSmrg    line->sz_line= DFLT_LINE_SIZE;
8505b261ecSmrg    line->line= line->buf;
8605b261ecSmrg    return;
8705b261ecSmrg}
8805b261ecSmrg
8905b261ecSmrgstatic int
9005b261ecSmrgInputLineAddChar(InputLine *line,int ch)
9105b261ecSmrg{
9205b261ecSmrg    if (line->num_line>=line->sz_line) {
9305b261ecSmrg	if (line->line==line->buf) {
946747b715Smrg	    line->line= malloc(line->sz_line*2);
9505b261ecSmrg	    memcpy(line->line,line->buf,line->sz_line);
9605b261ecSmrg	}
9705b261ecSmrg	else {
986747b715Smrg	    line->line= realloc((char *)line->line,line->sz_line*2);
9905b261ecSmrg	}
10005b261ecSmrg	line->sz_line*= 2;
10105b261ecSmrg    }
10205b261ecSmrg    line->line[line->num_line++]= ch;
10305b261ecSmrg    return ch;
10405b261ecSmrg}
10505b261ecSmrg
10605b261ecSmrg#define	ADD_CHAR(l,c)	((l)->num_line<(l)->sz_line?\
10705b261ecSmrg				(int)((l)->line[(l)->num_line++]= (c)):\
10805b261ecSmrg				InputLineAddChar(l,c))
10905b261ecSmrg
11005b261ecSmrgstatic Bool
11105b261ecSmrgGetInputLine(FILE *file,InputLine *line,Bool checkbang)
11205b261ecSmrg{
11305b261ecSmrgint	ch;
11405b261ecSmrgBool	endOfFile,spacePending,slashPending,inComment;
11505b261ecSmrg
1166747b715Smrg     endOfFile= FALSE;
11705b261ecSmrg     while ((!endOfFile)&&(line->num_line==0)) {
1186747b715Smrg	spacePending= slashPending= inComment= FALSE;
11905b261ecSmrg	while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
12005b261ecSmrg	    if (ch=='\\') {
12105b261ecSmrg		if ((ch=getc(file))==EOF)
12205b261ecSmrg		    break;
12305b261ecSmrg		if (ch=='\n') {
1246747b715Smrg		    inComment= FALSE;
12505b261ecSmrg		    ch= ' ';
12605b261ecSmrg		    line->line_num++;
12705b261ecSmrg		}
12805b261ecSmrg	    }
12905b261ecSmrg	    if (inComment)
13005b261ecSmrg		continue;
13105b261ecSmrg	    if (ch=='/') {
13205b261ecSmrg		if (slashPending) {
1336747b715Smrg		    inComment= TRUE;
1346747b715Smrg		    slashPending= FALSE;
13505b261ecSmrg		}
13605b261ecSmrg		else {
1376747b715Smrg		    slashPending= TRUE;
13805b261ecSmrg		}
13905b261ecSmrg		continue;
14005b261ecSmrg	    }
14105b261ecSmrg	    else if (slashPending) {
14205b261ecSmrg		if (spacePending) {
14305b261ecSmrg		    ADD_CHAR(line,' ');
1446747b715Smrg		    spacePending= FALSE;
14505b261ecSmrg		}
14605b261ecSmrg		ADD_CHAR(line,'/');
1476747b715Smrg		slashPending= FALSE;
14805b261ecSmrg	    }
14905b261ecSmrg	    if (isspace(ch)) {
15005b261ecSmrg		while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
15105b261ecSmrg		    ch= getc(file);
15205b261ecSmrg		}
15305b261ecSmrg		if (ch==EOF)
15405b261ecSmrg		    break;
15505b261ecSmrg		if ((ch!='\n')&&(line->num_line>0))
1566747b715Smrg		    spacePending= TRUE;
15705b261ecSmrg		ungetc(ch,file);
15805b261ecSmrg	    }
15905b261ecSmrg	    else {
16005b261ecSmrg		if (spacePending) {
16105b261ecSmrg		    ADD_CHAR(line,' ');
1626747b715Smrg		    spacePending= FALSE;
16305b261ecSmrg		}
16405b261ecSmrg		if (checkbang && ch=='!') {
16505b261ecSmrg		    if (line->num_line!=0) {
1664642e01fSmrg			DebugF("The '!' legal only at start of line\n");
1674642e01fSmrg			DebugF("Line containing '!' ignored\n");
16805b261ecSmrg			line->num_line= 0;
16905b261ecSmrg			inComment= 0;
17005b261ecSmrg			break;
17105b261ecSmrg		    }
17205b261ecSmrg
17305b261ecSmrg		}
17405b261ecSmrg		ADD_CHAR(line,ch);
17505b261ecSmrg	    }
17605b261ecSmrg	}
17705b261ecSmrg	if (ch==EOF)
1786747b715Smrg	     endOfFile= TRUE;
17905b261ecSmrg/*	else line->num_line++;*/
18005b261ecSmrg     }
18105b261ecSmrg     if ((line->num_line==0)&&(endOfFile))
1826747b715Smrg	return FALSE;
18305b261ecSmrg      ADD_CHAR(line,'\0');
1846747b715Smrg      return TRUE;
18505b261ecSmrg}
18605b261ecSmrg
18705b261ecSmrg/***====================================================================***/
18805b261ecSmrg
18905b261ecSmrg#define	MODEL		0
19005b261ecSmrg#define	LAYOUT		1
19105b261ecSmrg#define	VARIANT		2
19205b261ecSmrg#define	OPTION		3
19305b261ecSmrg#define	KEYCODES	4
19405b261ecSmrg#define SYMBOLS		5
19505b261ecSmrg#define	TYPES		6
19605b261ecSmrg#define	COMPAT		7
19705b261ecSmrg#define	GEOMETRY	8
1986747b715Smrg#define	MAX_WORDS	9
19905b261ecSmrg
20005b261ecSmrg#define	PART_MASK	0x000F
20105b261ecSmrg#define	COMPONENT_MASK	0x03F0
20205b261ecSmrg
20305b261ecSmrgstatic	char *	cname[MAX_WORDS] = {
20405b261ecSmrg	"model", "layout", "variant", "option",
2056747b715Smrg	"keycodes", "symbols", "types", "compat", "geometry"
20605b261ecSmrg};
20705b261ecSmrg
20805b261ecSmrgtypedef	struct _RemapSpec {
20905b261ecSmrg	int			number;
21005b261ecSmrg	int			num_remap;
21105b261ecSmrg	struct	{
21205b261ecSmrg		int	word;
21305b261ecSmrg		int	index;
21405b261ecSmrg                }		remap[MAX_WORDS];
21505b261ecSmrg} RemapSpec;
21605b261ecSmrg
21705b261ecSmrgtypedef struct _FileSpec {
21805b261ecSmrg	char *			name[MAX_WORDS];
21905b261ecSmrg	struct _FileSpec *	pending;
22005b261ecSmrg} FileSpec;
22105b261ecSmrg
22205b261ecSmrgtypedef struct {
22305b261ecSmrg	char *			model;
22405b261ecSmrg	char *			layout[XkbNumKbdGroups+1];
22505b261ecSmrg	char *			variant[XkbNumKbdGroups+1];
22605b261ecSmrg	char *			options;
22705b261ecSmrg} XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
22805b261ecSmrg
22905b261ecSmrg#define NDX_BUFF_SIZE	4
23005b261ecSmrg
23105b261ecSmrg/***====================================================================***/
23205b261ecSmrg
23305b261ecSmrgstatic char*
23405b261ecSmrgget_index(char *str, int *ndx)
23505b261ecSmrg{
23605b261ecSmrg   char ndx_buf[NDX_BUFF_SIZE];
23705b261ecSmrg   char *end;
23805b261ecSmrg
23905b261ecSmrg   if (*str != '[') {
24005b261ecSmrg       *ndx = 0;
24105b261ecSmrg       return str;
24205b261ecSmrg   }
24305b261ecSmrg   str++;
24405b261ecSmrg   end = strchr(str, ']');
24505b261ecSmrg   if (end == NULL) {
24605b261ecSmrg       *ndx = -1;
24705b261ecSmrg       return str - 1;
24805b261ecSmrg   }
24905b261ecSmrg   if ( (end - str) >= NDX_BUFF_SIZE) {
25005b261ecSmrg       *ndx = -1;
25105b261ecSmrg       return end + 1;
25205b261ecSmrg   }
25305b261ecSmrg   strncpy(ndx_buf, str, end - str);
25405b261ecSmrg   ndx_buf[end - str] = '\0';
25505b261ecSmrg   *ndx = atoi(ndx_buf);
25605b261ecSmrg   return end + 1;
25705b261ecSmrg}
25805b261ecSmrg
25905b261ecSmrgstatic void
26005b261ecSmrgSetUpRemap(InputLine *line,RemapSpec *remap)
26105b261ecSmrg{
26205b261ecSmrgchar *		tok,*str;
26305b261ecSmrgunsigned	present, l_ndx_present, v_ndx_present;
26405b261ecSmrgregister int	i;
26505b261ecSmrgint		len, ndx;
26605b261ecSmrg_Xstrtokparams	strtok_buf;
26705b261ecSmrgBool		found;
26805b261ecSmrg
26905b261ecSmrg
27005b261ecSmrg   l_ndx_present = v_ndx_present = present= 0;
27105b261ecSmrg   str= &line->line[1];
27205b261ecSmrg   len = remap->number;
2736747b715Smrg   memset((char *)remap, 0, sizeof(RemapSpec));
27405b261ecSmrg   remap->number = len;
27505b261ecSmrg   while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
2766747b715Smrg	found= FALSE;
27705b261ecSmrg	str= NULL;
27805b261ecSmrg	if (strcmp(tok,"=")==0)
27905b261ecSmrg	    continue;
28005b261ecSmrg	for (i=0;i<MAX_WORDS;i++) {
28105b261ecSmrg            len = strlen(cname[i]);
28205b261ecSmrg	    if (strncmp(cname[i],tok,len)==0) {
28305b261ecSmrg		if(strlen(tok) > len) {
28405b261ecSmrg		    char *end = get_index(tok+len, &ndx);
28505b261ecSmrg		    if ((i != LAYOUT && i != VARIANT) ||
28605b261ecSmrg			*end != '\0' || ndx == -1)
28705b261ecSmrg		        break;
28805b261ecSmrg		     if (ndx < 1 || ndx > XkbNumKbdGroups) {
2894642e01fSmrg		        DebugF("Illegal %s index: %d\n", cname[i], ndx);
2904642e01fSmrg		        DebugF("Index must be in range 1..%d\n",
29105b261ecSmrg				   XkbNumKbdGroups);
29205b261ecSmrg			break;
29305b261ecSmrg		     }
29405b261ecSmrg                } else {
29505b261ecSmrg		    ndx = 0;
29605b261ecSmrg                }
2976747b715Smrg		found= TRUE;
29805b261ecSmrg		if (present&(1<<i)) {
29905b261ecSmrg		    if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
30005b261ecSmrg			(i == VARIANT && v_ndx_present&(1<<ndx)) ) {
3014642e01fSmrg		        DebugF("Component \"%s\" listed twice\n",tok);
3024642e01fSmrg		        DebugF("Second definition ignored\n");
30305b261ecSmrg		        break;
30405b261ecSmrg		    }
30505b261ecSmrg		}
30605b261ecSmrg		present |= (1<<i);
30705b261ecSmrg                if (i == LAYOUT)
30805b261ecSmrg                    l_ndx_present |= 1 << ndx;
30905b261ecSmrg                if (i == VARIANT)
31005b261ecSmrg                    v_ndx_present |= 1 << ndx;
31105b261ecSmrg		remap->remap[remap->num_remap].word= i;
31205b261ecSmrg		remap->remap[remap->num_remap++].index= ndx;
31305b261ecSmrg		break;
31405b261ecSmrg	    }
31505b261ecSmrg	}
31605b261ecSmrg	if (!found) {
31705b261ecSmrg	    fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
31805b261ecSmrg	}
31905b261ecSmrg   }
32005b261ecSmrg   if ((present&PART_MASK)==0) {
32105b261ecSmrg	unsigned mask= PART_MASK;
3224642e01fSmrg	ErrorF("Mapping needs at least one of ");
32305b261ecSmrg	for (i=0; (i<MAX_WORDS); i++) {
32405b261ecSmrg	    if ((1L<<i)&mask) {
32505b261ecSmrg		mask&= ~(1L<<i);
3264642e01fSmrg		if (mask)	DebugF("\"%s,\" ",cname[i]);
3274642e01fSmrg		else		DebugF("or \"%s\"\n",cname[i]);
32805b261ecSmrg	    }
32905b261ecSmrg	}
3304642e01fSmrg	DebugF("Illegal mapping ignored\n");
33105b261ecSmrg	remap->num_remap= 0;
33205b261ecSmrg	return;
33305b261ecSmrg   }
33405b261ecSmrg   if ((present&COMPONENT_MASK)==0) {
3354642e01fSmrg	DebugF("Mapping needs at least one component\n");
3364642e01fSmrg	DebugF("Illegal mapping ignored\n");
33705b261ecSmrg	remap->num_remap= 0;
33805b261ecSmrg	return;
33905b261ecSmrg   }
34005b261ecSmrg   remap->number++;
34105b261ecSmrg   return;
34205b261ecSmrg}
34305b261ecSmrg
34405b261ecSmrgstatic Bool
34505b261ecSmrgMatchOneOf(char *wanted,char *vals_defined)
34605b261ecSmrg{
34705b261ecSmrgchar	*str,*next;
34805b261ecSmrgint	want_len= strlen(wanted);
34905b261ecSmrg
35005b261ecSmrg    for (str=vals_defined,next=NULL;str!=NULL;str=next) {
35105b261ecSmrg	int len;
35205b261ecSmrg	next= strchr(str,',');
35305b261ecSmrg	if (next) {
35405b261ecSmrg	    len= next-str;
35505b261ecSmrg	    next++;
35605b261ecSmrg	}
35705b261ecSmrg	else {
35805b261ecSmrg	    len= strlen(str);
35905b261ecSmrg	}
36005b261ecSmrg	if ((len==want_len)&&(strncmp(wanted,str,len)==0))
3616747b715Smrg	    return TRUE;
36205b261ecSmrg    }
3636747b715Smrg    return FALSE;
36405b261ecSmrg}
36505b261ecSmrg
36605b261ecSmrg/***====================================================================***/
36705b261ecSmrg
36805b261ecSmrgstatic Bool
36905b261ecSmrgCheckLine(	InputLine *		line,
37005b261ecSmrg		RemapSpec *		remap,
37105b261ecSmrg		XkbRF_RulePtr		rule,
37205b261ecSmrg		XkbRF_GroupPtr		group)
37305b261ecSmrg{
37405b261ecSmrgchar *		str,*tok;
37505b261ecSmrgregister int	nread, i;
37605b261ecSmrgFileSpec	tmp;
37705b261ecSmrg_Xstrtokparams	strtok_buf;
3786747b715SmrgBool 		append = FALSE;
37905b261ecSmrg
38005b261ecSmrg    if (line->line[0]=='!') {
38105b261ecSmrg        if (line->line[1] == '$' ||
38205b261ecSmrg            (line->line[1] == ' ' && line->line[2] == '$')) {
38305b261ecSmrg            char *gname = strchr(line->line, '$');
38405b261ecSmrg            char *words = strchr(gname, ' ');
38505b261ecSmrg            if(!words)
3866747b715Smrg                return FALSE;
38705b261ecSmrg            *words++ = '\0';
38805b261ecSmrg            for (; *words; words++) {
38905b261ecSmrg                if (*words != '=' && *words != ' ')
39005b261ecSmrg                    break;
39105b261ecSmrg            }
39205b261ecSmrg            if (*words == '\0')
3936747b715Smrg                return FALSE;
39405b261ecSmrg            group->name = _XkbDupString(gname);
39505b261ecSmrg            group->words = _XkbDupString(words);
39605b261ecSmrg            for (i = 1, words = group->words; *words; words++) {
39705b261ecSmrg                 if ( *words == ' ') {
39805b261ecSmrg                     *words++ = '\0';
39905b261ecSmrg                     i++;
40005b261ecSmrg                 }
40105b261ecSmrg            }
40205b261ecSmrg            group->number = i;
4036747b715Smrg            return TRUE;
40405b261ecSmrg        } else {
40505b261ecSmrg	    SetUpRemap(line,remap);
4066747b715Smrg	    return FALSE;
40705b261ecSmrg        }
40805b261ecSmrg    }
40905b261ecSmrg
41005b261ecSmrg    if (remap->num_remap==0) {
4114642e01fSmrg	DebugF("Must have a mapping before first line of data\n");
4124642e01fSmrg	DebugF("Illegal line of data ignored\n");
4136747b715Smrg	return FALSE;
41405b261ecSmrg    }
4156747b715Smrg    memset((char *)&tmp, 0, sizeof(FileSpec));
41605b261ecSmrg    str= line->line;
41705b261ecSmrg    for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
41805b261ecSmrg	str= NULL;
41905b261ecSmrg	if (strcmp(tok,"=")==0) {
42005b261ecSmrg	    nread--;
42105b261ecSmrg	    continue;
42205b261ecSmrg	}
42305b261ecSmrg	if (nread>remap->num_remap) {
4244642e01fSmrg	    DebugF("Too many words on a line\n");
4254642e01fSmrg	    DebugF("Extra word \"%s\" ignored\n",tok);
42605b261ecSmrg	    continue;
42705b261ecSmrg	}
42805b261ecSmrg	tmp.name[remap->remap[nread].word]= tok;
42905b261ecSmrg	if (*tok == '+' || *tok == '|')
4306747b715Smrg	    append = TRUE;
43105b261ecSmrg    }
43205b261ecSmrg    if (nread<remap->num_remap) {
4334642e01fSmrg	DebugF("Too few words on a line: %s\n", line->line);
4344642e01fSmrg	DebugF("line ignored\n");
4356747b715Smrg	return FALSE;
43605b261ecSmrg    }
43705b261ecSmrg
43805b261ecSmrg    rule->flags= 0;
43905b261ecSmrg    rule->number = remap->number;
44005b261ecSmrg    if (tmp.name[OPTION])
44105b261ecSmrg	 rule->flags|= XkbRF_Option;
44205b261ecSmrg    else if (append)
44305b261ecSmrg	 rule->flags|= XkbRF_Append;
44405b261ecSmrg    else
44505b261ecSmrg	 rule->flags|= XkbRF_Normal;
44605b261ecSmrg    rule->model= _XkbDupString(tmp.name[MODEL]);
44705b261ecSmrg    rule->layout= _XkbDupString(tmp.name[LAYOUT]);
44805b261ecSmrg    rule->variant= _XkbDupString(tmp.name[VARIANT]);
44905b261ecSmrg    rule->option= _XkbDupString(tmp.name[OPTION]);
45005b261ecSmrg
45105b261ecSmrg    rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
45205b261ecSmrg    rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
45305b261ecSmrg    rule->types= _XkbDupString(tmp.name[TYPES]);
45405b261ecSmrg    rule->compat= _XkbDupString(tmp.name[COMPAT]);
45505b261ecSmrg    rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
45605b261ecSmrg
45705b261ecSmrg    rule->layout_num = rule->variant_num = 0;
45805b261ecSmrg    for (i = 0; i < nread; i++) {
45905b261ecSmrg        if (remap->remap[i].index) {
46005b261ecSmrg	    if (remap->remap[i].word == LAYOUT)
46105b261ecSmrg	        rule->layout_num = remap->remap[i].index;
46205b261ecSmrg	    if (remap->remap[i].word == VARIANT)
46305b261ecSmrg	        rule->variant_num = remap->remap[i].index;
46405b261ecSmrg        }
46505b261ecSmrg    }
4666747b715Smrg    return TRUE;
46705b261ecSmrg}
46805b261ecSmrg
46905b261ecSmrgstatic char *
47005b261ecSmrg_Concat(char *str1,char *str2)
47105b261ecSmrg{
47205b261ecSmrgint len;
47305b261ecSmrg
47405b261ecSmrg    if ((!str1)||(!str2))
47505b261ecSmrg	return str1;
47605b261ecSmrg    len= strlen(str1)+strlen(str2)+1;
4776747b715Smrg    str1= realloc(str1,len * sizeof(char));
47805b261ecSmrg    if (str1)
47905b261ecSmrg	strcat(str1,str2);
48005b261ecSmrg    return str1;
48105b261ecSmrg}
48205b261ecSmrg
48305b261ecSmrgstatic void
48405b261ecSmrgsqueeze_spaces(char *p1)
48505b261ecSmrg{
48605b261ecSmrg   char *p2;
48705b261ecSmrg   for (p2 = p1; *p2; p2++) {
48805b261ecSmrg       *p1 = *p2;
48905b261ecSmrg       if (*p1 != ' ') p1++;
49005b261ecSmrg   }
49105b261ecSmrg   *p1 = '\0';
49205b261ecSmrg}
49305b261ecSmrg
49405b261ecSmrgstatic Bool
49505b261ecSmrgMakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
49605b261ecSmrg{
49705b261ecSmrg
4986747b715Smrg   memset((char *)mdefs, 0, sizeof(XkbRF_MultiDefsRec));
49905b261ecSmrg   mdefs->model = defs->model;
50005b261ecSmrg   mdefs->options = _XkbDupString(defs->options);
50105b261ecSmrg   if (mdefs->options) squeeze_spaces(mdefs->options);
50205b261ecSmrg
50305b261ecSmrg   if (defs->layout) {
50405b261ecSmrg       if (!strchr(defs->layout, ',')) {
50505b261ecSmrg           mdefs->layout[0] = defs->layout;
50605b261ecSmrg       } else {
50705b261ecSmrg           char *p;
50805b261ecSmrg           int i;
50905b261ecSmrg           mdefs->layout[1] = _XkbDupString(defs->layout);
51005b261ecSmrg	   if (mdefs->layout[1] == NULL)
5116747b715Smrg	      return FALSE;
51205b261ecSmrg           squeeze_spaces(mdefs->layout[1]);
51305b261ecSmrg           p = mdefs->layout[1];
51405b261ecSmrg           for (i = 2; i <= XkbNumKbdGroups; i++) {
51505b261ecSmrg              if ((p = strchr(p, ','))) {
51605b261ecSmrg                 *p++ = '\0';
51705b261ecSmrg                 mdefs->layout[i] = p;
51805b261ecSmrg              } else {
51905b261ecSmrg                 break;
52005b261ecSmrg              }
52105b261ecSmrg           }
52205b261ecSmrg           if (p && (p = strchr(p, ',')))
52305b261ecSmrg              *p = '\0';
52405b261ecSmrg       }
52505b261ecSmrg   }
52605b261ecSmrg
52705b261ecSmrg   if (defs->variant) {
52805b261ecSmrg       if (!strchr(defs->variant, ',')) {
52905b261ecSmrg           mdefs->variant[0] = defs->variant;
53005b261ecSmrg       } else {
53105b261ecSmrg           char *p;
53205b261ecSmrg           int i;
53305b261ecSmrg           mdefs->variant[1] = _XkbDupString(defs->variant);
53405b261ecSmrg	   if (mdefs->variant[1] == NULL)
5356747b715Smrg	      return FALSE;
53605b261ecSmrg           squeeze_spaces(mdefs->variant[1]);
53705b261ecSmrg           p = mdefs->variant[1];
53805b261ecSmrg           for (i = 2; i <= XkbNumKbdGroups; i++) {
53905b261ecSmrg              if ((p = strchr(p, ','))) {
54005b261ecSmrg                 *p++ = '\0';
54105b261ecSmrg                 mdefs->variant[i] = p;
54205b261ecSmrg              } else {
54305b261ecSmrg                 break;
54405b261ecSmrg              }
54505b261ecSmrg           }
54605b261ecSmrg           if (p && (p = strchr(p, ',')))
54705b261ecSmrg              *p = '\0';
54805b261ecSmrg       }
54905b261ecSmrg   }
5506747b715Smrg   return TRUE;
55105b261ecSmrg}
55205b261ecSmrg
55305b261ecSmrgstatic void
55405b261ecSmrgFreeMultiDefs(XkbRF_MultiDefsPtr defs)
55505b261ecSmrg{
5566747b715Smrg  free(defs->options);
5576747b715Smrg  free(defs->layout[1]);
5586747b715Smrg  free(defs->variant[1]);
55905b261ecSmrg}
56005b261ecSmrg
56105b261ecSmrgstatic void
56205b261ecSmrgApply(char *src, char **dst)
56305b261ecSmrg{
56405b261ecSmrg    if (src) {
56505b261ecSmrg        if (*src == '+' || *src == '!') {
56605b261ecSmrg	    *dst= _Concat(*dst, src);
56705b261ecSmrg        } else {
56805b261ecSmrg            if (*dst == NULL)
56905b261ecSmrg	        *dst= _XkbDupString(src);
57005b261ecSmrg        }
57105b261ecSmrg    }
57205b261ecSmrg}
57305b261ecSmrg
57405b261ecSmrgstatic void
57505b261ecSmrgXkbRF_ApplyRule(	XkbRF_RulePtr 		rule,
57605b261ecSmrg			XkbComponentNamesPtr	names)
57705b261ecSmrg{
57805b261ecSmrg    rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
57905b261ecSmrg
58005b261ecSmrg    Apply(rule->keycodes, &names->keycodes);
58105b261ecSmrg    Apply(rule->symbols,  &names->symbols);
58205b261ecSmrg    Apply(rule->types,    &names->types);
58305b261ecSmrg    Apply(rule->compat,   &names->compat);
58405b261ecSmrg    Apply(rule->geometry, &names->geometry);
58505b261ecSmrg}
58605b261ecSmrg
58705b261ecSmrgstatic Bool
58805b261ecSmrgCheckGroup(	XkbRF_RulesPtr          rules,
58905b261ecSmrg		char * 			group_name,
59005b261ecSmrg		char * 			name)
59105b261ecSmrg{
59205b261ecSmrg   int i;
59305b261ecSmrg   char *p;
59405b261ecSmrg   XkbRF_GroupPtr group;
59505b261ecSmrg
59605b261ecSmrg   for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
59705b261ecSmrg       if (! strcmp(group->name, group_name)) {
59805b261ecSmrg           break;
59905b261ecSmrg       }
60005b261ecSmrg   }
60105b261ecSmrg   if (i == rules->num_groups)
6026747b715Smrg       return FALSE;
60305b261ecSmrg   for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
60405b261ecSmrg       if (! strcmp(p, name)) {
6056747b715Smrg           return TRUE;
60605b261ecSmrg       }
60705b261ecSmrg   }
6086747b715Smrg   return FALSE;
60905b261ecSmrg}
61005b261ecSmrg
61105b261ecSmrgstatic int
61205b261ecSmrgXkbRF_CheckApplyRule(	XkbRF_RulePtr 		rule,
61305b261ecSmrg			XkbRF_MultiDefsPtr	mdefs,
61405b261ecSmrg			XkbComponentNamesPtr	names,
61505b261ecSmrg			XkbRF_RulesPtr          rules)
61605b261ecSmrg{
6176747b715Smrg    Bool pending = FALSE;
61805b261ecSmrg
61905b261ecSmrg    if (rule->model != NULL) {
62005b261ecSmrg        if(mdefs->model == NULL)
62105b261ecSmrg            return 0;
62205b261ecSmrg        if (strcmp(rule->model, "*") == 0) {
6236747b715Smrg            pending = TRUE;
62405b261ecSmrg        } else {
62505b261ecSmrg            if (rule->model[0] == '$') {
62605b261ecSmrg               if (!CheckGroup(rules, rule->model, mdefs->model))
62705b261ecSmrg                  return 0;
62805b261ecSmrg            } else {
62905b261ecSmrg	       if (strcmp(rule->model, mdefs->model) != 0)
63005b261ecSmrg	          return 0;
63105b261ecSmrg	    }
63205b261ecSmrg	}
63305b261ecSmrg    }
63405b261ecSmrg    if (rule->option != NULL) {
63505b261ecSmrg	if (mdefs->options == NULL)
63605b261ecSmrg	    return 0;
63705b261ecSmrg	if ((!MatchOneOf(rule->option,mdefs->options)))
63805b261ecSmrg	    return 0;
63905b261ecSmrg    }
64005b261ecSmrg
64105b261ecSmrg    if (rule->layout != NULL) {
64205b261ecSmrg	if(mdefs->layout[rule->layout_num] == NULL ||
64305b261ecSmrg	   *mdefs->layout[rule->layout_num] == '\0')
64405b261ecSmrg	    return 0;
64505b261ecSmrg        if (strcmp(rule->layout, "*") == 0) {
6466747b715Smrg            pending = TRUE;
64705b261ecSmrg        } else {
64805b261ecSmrg            if (rule->layout[0] == '$') {
64905b261ecSmrg               if (!CheckGroup(rules, rule->layout,
65005b261ecSmrg                               mdefs->layout[rule->layout_num]))
65105b261ecSmrg                  return 0;
65205b261ecSmrg	    } else {
65305b261ecSmrg	       if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
65405b261ecSmrg	           return 0;
65505b261ecSmrg	    }
65605b261ecSmrg	}
65705b261ecSmrg    }
65805b261ecSmrg    if (rule->variant != NULL) {
65905b261ecSmrg	if (mdefs->variant[rule->variant_num] == NULL ||
66005b261ecSmrg	    *mdefs->variant[rule->variant_num] == '\0')
66105b261ecSmrg	    return 0;
66205b261ecSmrg        if (strcmp(rule->variant, "*") == 0) {
6636747b715Smrg            pending = TRUE;
66405b261ecSmrg        } else {
66505b261ecSmrg            if (rule->variant[0] == '$') {
66605b261ecSmrg               if (!CheckGroup(rules, rule->variant,
66705b261ecSmrg                               mdefs->variant[rule->variant_num]))
66805b261ecSmrg                  return 0;
66905b261ecSmrg            } else {
67005b261ecSmrg	       if (strcmp(rule->variant,
67105b261ecSmrg                          mdefs->variant[rule->variant_num]) != 0)
67205b261ecSmrg	           return 0;
67305b261ecSmrg	    }
67405b261ecSmrg	}
67505b261ecSmrg    }
67605b261ecSmrg    if (pending) {
67705b261ecSmrg        rule->flags|= XkbRF_PendingMatch;
67805b261ecSmrg	return rule->number;
67905b261ecSmrg    }
68005b261ecSmrg    /* exact match, apply it now */
68105b261ecSmrg    XkbRF_ApplyRule(rule,names);
68205b261ecSmrg    return rule->number;
68305b261ecSmrg}
68405b261ecSmrg
68505b261ecSmrgstatic void
68605b261ecSmrgXkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
68705b261ecSmrg{
68805b261ecSmrgregister int 	i;
68905b261ecSmrgXkbRF_RulePtr	rule;
69005b261ecSmrg
69105b261ecSmrg    for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
69205b261ecSmrg	rule->flags&= ~XkbRF_PendingMatch;
69305b261ecSmrg    }
69405b261ecSmrg}
69505b261ecSmrg
69605b261ecSmrgstatic void
69705b261ecSmrgXkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)
69805b261ecSmrg{
69905b261ecSmrgint		i;
70005b261ecSmrgXkbRF_RulePtr	rule;
70105b261ecSmrg
70205b261ecSmrg    for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
70305b261ecSmrg	if ((rule->flags&XkbRF_PendingMatch)==0)
70405b261ecSmrg	    continue;
70505b261ecSmrg	XkbRF_ApplyRule(rule,names);
70605b261ecSmrg    }
70705b261ecSmrg}
70805b261ecSmrg
70905b261ecSmrgstatic void
71005b261ecSmrgXkbRF_CheckApplyRules(	XkbRF_RulesPtr 		rules,
71105b261ecSmrg			XkbRF_MultiDefsPtr	mdefs,
71205b261ecSmrg			XkbComponentNamesPtr	names,
71305b261ecSmrg			int			flags)
71405b261ecSmrg{
71505b261ecSmrgint		i;
71605b261ecSmrgXkbRF_RulePtr	rule;
71705b261ecSmrgint		skip;
71805b261ecSmrg
71905b261ecSmrg    for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
72005b261ecSmrg	if ((rule->flags & flags) != flags)
72105b261ecSmrg	    continue;
72205b261ecSmrg	skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
72305b261ecSmrg	if (skip && !(flags & XkbRF_Option)) {
72405b261ecSmrg	    for ( ;(i < rules->num_rules) && (rule->number == skip);
72505b261ecSmrg		  rule++, i++);
72605b261ecSmrg	    rule--; i--;
72705b261ecSmrg	}
72805b261ecSmrg    }
72905b261ecSmrg}
73005b261ecSmrg
73105b261ecSmrg/***====================================================================***/
73205b261ecSmrg
73305b261ecSmrgstatic char *
73405b261ecSmrgXkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
73505b261ecSmrg{
73605b261ecSmrgchar 	*str, *outstr, *orig, *var;
73705b261ecSmrgint	len, ndx;
73805b261ecSmrg
73905b261ecSmrg    orig= name;
74005b261ecSmrg    str= index(name,'%');
74105b261ecSmrg    if (str==NULL)
74205b261ecSmrg	return name;
74305b261ecSmrg    len= strlen(name);
74405b261ecSmrg    while (str!=NULL) {
74505b261ecSmrg	char pfx= str[1];
74605b261ecSmrg	int   extra_len= 0;
74705b261ecSmrg	if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
74805b261ecSmrg	    extra_len= 1;
74905b261ecSmrg	    str++;
75005b261ecSmrg	}
75105b261ecSmrg	else if (pfx=='(') {
75205b261ecSmrg	    extra_len= 2;
75305b261ecSmrg	    str++;
75405b261ecSmrg	}
75505b261ecSmrg	var = str + 1;
75605b261ecSmrg	str = get_index(var + 1, &ndx);
75705b261ecSmrg	if (ndx == -1) {
75805b261ecSmrg	    str = index(str,'%');
75905b261ecSmrg	    continue;
76005b261ecSmrg        }
76105b261ecSmrg	if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
76205b261ecSmrg	    len+= strlen(mdefs->layout[ndx])+extra_len;
76305b261ecSmrg	else if ((*var=='m')&&mdefs->model)
76405b261ecSmrg	    len+= strlen(mdefs->model)+extra_len;
76505b261ecSmrg	else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
76605b261ecSmrg	    len+= strlen(mdefs->variant[ndx])+extra_len;
76705b261ecSmrg	if ((pfx=='(')&&(*str==')')) {
76805b261ecSmrg	    str++;
76905b261ecSmrg	}
77005b261ecSmrg	str= index(&str[0],'%');
77105b261ecSmrg    }
7726747b715Smrg    name= malloc(len+1);
77305b261ecSmrg    str= orig;
77405b261ecSmrg    outstr= name;
77505b261ecSmrg    while (*str!='\0') {
77605b261ecSmrg	if (str[0]=='%') {
77705b261ecSmrg	    char pfx,sfx;
77805b261ecSmrg	    str++;
77905b261ecSmrg	    pfx= str[0];
78005b261ecSmrg	    sfx= '\0';
78105b261ecSmrg	    if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
78205b261ecSmrg		str++;
78305b261ecSmrg	    }
78405b261ecSmrg	    else if (pfx=='(') {
78505b261ecSmrg		sfx= ')';
78605b261ecSmrg		str++;
78705b261ecSmrg	    }
78805b261ecSmrg	    else pfx= '\0';
78905b261ecSmrg
79005b261ecSmrg	    var = str;
79105b261ecSmrg	    str = get_index(var + 1, &ndx);
79205b261ecSmrg	    if (ndx == -1) {
79305b261ecSmrg	        continue;
79405b261ecSmrg            }
79505b261ecSmrg	    if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
79605b261ecSmrg		if (pfx) *outstr++= pfx;
79705b261ecSmrg		strcpy(outstr,mdefs->layout[ndx]);
79805b261ecSmrg		outstr+= strlen(mdefs->layout[ndx]);
79905b261ecSmrg		if (sfx) *outstr++= sfx;
80005b261ecSmrg	    }
80105b261ecSmrg	    else if ((*var=='m')&&(mdefs->model)) {
80205b261ecSmrg		if (pfx) *outstr++= pfx;
80305b261ecSmrg		strcpy(outstr,mdefs->model);
80405b261ecSmrg		outstr+= strlen(mdefs->model);
80505b261ecSmrg		if (sfx) *outstr++= sfx;
80605b261ecSmrg	    }
80705b261ecSmrg	    else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
80805b261ecSmrg		if (pfx) *outstr++= pfx;
80905b261ecSmrg		strcpy(outstr,mdefs->variant[ndx]);
81005b261ecSmrg		outstr+= strlen(mdefs->variant[ndx]);
81105b261ecSmrg		if (sfx) *outstr++= sfx;
81205b261ecSmrg	    }
81305b261ecSmrg	    if ((pfx=='(')&&(*str==')'))
81405b261ecSmrg		str++;
81505b261ecSmrg	}
81605b261ecSmrg	else {
81705b261ecSmrg	    *outstr++= *str++;
81805b261ecSmrg	}
81905b261ecSmrg    }
82005b261ecSmrg    *outstr++= '\0';
82105b261ecSmrg    if (orig!=name)
8226747b715Smrg	free(orig);
82305b261ecSmrg    return name;
82405b261ecSmrg}
82505b261ecSmrg
82605b261ecSmrg/***====================================================================***/
82705b261ecSmrg
82805b261ecSmrgBool
82905b261ecSmrgXkbRF_GetComponents(	XkbRF_RulesPtr		rules,
83005b261ecSmrg			XkbRF_VarDefsPtr	defs,
83105b261ecSmrg			XkbComponentNamesPtr	names)
83205b261ecSmrg{
83305b261ecSmrg    XkbRF_MultiDefsRec mdefs;
83405b261ecSmrg
83505b261ecSmrg    MakeMultiDefs(&mdefs, defs);
83605b261ecSmrg
8376747b715Smrg    memset((char *)names, 0, sizeof(XkbComponentNamesRec));
83805b261ecSmrg    XkbRF_ClearPartialMatches(rules);
83905b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
84005b261ecSmrg    XkbRF_ApplyPartialMatches(rules, names);
84105b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
84205b261ecSmrg    XkbRF_ApplyPartialMatches(rules, names);
84305b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
84405b261ecSmrg
84505b261ecSmrg    if (names->keycodes)
84605b261ecSmrg	names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
84705b261ecSmrg    if (names->symbols)
84805b261ecSmrg	names->symbols=	XkbRF_SubstituteVars(names->symbols, &mdefs);
84905b261ecSmrg    if (names->types)
85005b261ecSmrg	names->types= XkbRF_SubstituteVars(names->types, &mdefs);
85105b261ecSmrg    if (names->compat)
85205b261ecSmrg	names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
85305b261ecSmrg    if (names->geometry)
85405b261ecSmrg	names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
85505b261ecSmrg
85605b261ecSmrg    FreeMultiDefs(&mdefs);
85705b261ecSmrg    return (names->keycodes && names->symbols && names->types &&
8586747b715Smrg		names->compat && names->geometry);
85905b261ecSmrg}
86005b261ecSmrg
8616747b715Smrgstatic XkbRF_RulePtr
86205b261ecSmrgXkbRF_AddRule(XkbRF_RulesPtr	rules)
86305b261ecSmrg{
86405b261ecSmrg    if (rules->sz_rules<1) {
86505b261ecSmrg	rules->sz_rules= 16;
86605b261ecSmrg	rules->num_rules= 0;
8676747b715Smrg	rules->rules= calloc(rules->sz_rules, sizeof(XkbRF_RuleRec));
86805b261ecSmrg    }
86905b261ecSmrg    else if (rules->num_rules>=rules->sz_rules) {
87005b261ecSmrg	rules->sz_rules*= 2;
8716747b715Smrg	rules->rules= realloc(rules->rules,
8726747b715Smrg				rules->sz_rules * sizeof(XkbRF_RuleRec));
87305b261ecSmrg    }
87405b261ecSmrg    if (!rules->rules) {
87505b261ecSmrg	rules->sz_rules= rules->num_rules= 0;
8764642e01fSmrg	DebugF("Allocation failure in XkbRF_AddRule\n");
87705b261ecSmrg	return NULL;
87805b261ecSmrg    }
8796747b715Smrg    memset((char *)&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
88005b261ecSmrg    return &rules->rules[rules->num_rules++];
88105b261ecSmrg}
88205b261ecSmrg
8836747b715Smrgstatic XkbRF_GroupPtr
88405b261ecSmrgXkbRF_AddGroup(XkbRF_RulesPtr	rules)
88505b261ecSmrg{
88605b261ecSmrg    if (rules->sz_groups<1) {
88705b261ecSmrg	rules->sz_groups= 16;
88805b261ecSmrg	rules->num_groups= 0;
8896747b715Smrg	rules->groups= calloc(rules->sz_groups, sizeof(XkbRF_GroupRec));
89005b261ecSmrg    }
89105b261ecSmrg    else if (rules->num_groups >= rules->sz_groups) {
89205b261ecSmrg	rules->sz_groups *= 2;
8936747b715Smrg	rules->groups= realloc(rules->groups,
8946747b715Smrg				rules->sz_groups * sizeof(XkbRF_GroupRec));
89505b261ecSmrg    }
89605b261ecSmrg    if (!rules->groups) {
89705b261ecSmrg	rules->sz_groups= rules->num_groups= 0;
89805b261ecSmrg	return NULL;
89905b261ecSmrg    }
90005b261ecSmrg
9016747b715Smrg    memset((char *)&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec));
90205b261ecSmrg    return &rules->groups[rules->num_groups++];
90305b261ecSmrg}
90405b261ecSmrg
90505b261ecSmrgBool
90605b261ecSmrgXkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
90705b261ecSmrg{
90805b261ecSmrgInputLine	line;
90905b261ecSmrgRemapSpec	remap;
91005b261ecSmrgXkbRF_RuleRec	trule,*rule;
91105b261ecSmrgXkbRF_GroupRec  tgroup,*group;
91205b261ecSmrg
91305b261ecSmrg    if (!(rules && file))
9146747b715Smrg	return FALSE;
9156747b715Smrg    memset((char *)&remap, 0, sizeof(RemapSpec));
9166747b715Smrg    memset((char *)&tgroup, 0, sizeof(XkbRF_GroupRec));
91705b261ecSmrg    InitInputLine(&line);
9186747b715Smrg    while (GetInputLine(file,&line,TRUE)) {
91905b261ecSmrg	if (CheckLine(&line,&remap,&trule,&tgroup)) {
92005b261ecSmrg            if (tgroup.number) {
92105b261ecSmrg	        if ((group= XkbRF_AddGroup(rules))!=NULL) {
92205b261ecSmrg		    *group= tgroup;
9236747b715Smrg		    memset((char *)&tgroup, 0, sizeof(XkbRF_GroupRec));
92405b261ecSmrg	        }
92505b261ecSmrg	    } else {
92605b261ecSmrg	        if ((rule= XkbRF_AddRule(rules))!=NULL) {
92705b261ecSmrg		    *rule= trule;
9286747b715Smrg		    memset((char *)&trule, 0, sizeof(XkbRF_RuleRec));
92905b261ecSmrg	        }
93005b261ecSmrg	    }
93105b261ecSmrg	}
93205b261ecSmrg	line.num_line= 0;
93305b261ecSmrg    }
93405b261ecSmrg    FreeInputLine(&line);
9356747b715Smrg    return TRUE;
93605b261ecSmrg}
93705b261ecSmrg
93805b261ecSmrgBool
93905b261ecSmrgXkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules)
94005b261ecSmrg{
94105b261ecSmrgFILE *		file;
94205b261ecSmrgchar		buf[PATH_MAX];
94305b261ecSmrgBool		ok;
94405b261ecSmrg
94505b261ecSmrg    if ((!base)||(!rules))
9466747b715Smrg	return FALSE;
94705b261ecSmrg    if (locale) {
94805b261ecSmrg	if (strlen(base)+strlen(locale)+2 > PATH_MAX)
9496747b715Smrg	    return FALSE;
95005b261ecSmrg	sprintf(buf,"%s-%s", base, locale);
95105b261ecSmrg    }
95205b261ecSmrg    else {
95305b261ecSmrg	if (strlen(base)+1 > PATH_MAX)
9546747b715Smrg	    return FALSE;
95505b261ecSmrg	strcpy(buf,base);
95605b261ecSmrg    }
95705b261ecSmrg
95805b261ecSmrg    file= fopen(buf, "r");
95905b261ecSmrg    if ((!file)&&(locale)) { /* fallback if locale was specified */
96005b261ecSmrg	strcpy(buf,base);
96105b261ecSmrg	file= fopen(buf, "r");
96205b261ecSmrg    }
96305b261ecSmrg    if (!file)
9646747b715Smrg	return FALSE;
96505b261ecSmrg    ok= XkbRF_LoadRules(file,rules);
96605b261ecSmrg    fclose(file);
96705b261ecSmrg    return ok;
96805b261ecSmrg}
96905b261ecSmrg
97005b261ecSmrg/***====================================================================***/
97105b261ecSmrg
97205b261ecSmrgXkbRF_RulesPtr
9736747b715SmrgXkbRF_Create(void)
97405b261ecSmrg{
9756747b715Smrg    return calloc(1, sizeof( XkbRF_RulesRec));
97605b261ecSmrg}
97705b261ecSmrg
97805b261ecSmrg/***====================================================================***/
97905b261ecSmrg
98005b261ecSmrgvoid
98105b261ecSmrgXkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
98205b261ecSmrg{
98305b261ecSmrgint		i;
98405b261ecSmrgXkbRF_RulePtr	rule;
98505b261ecSmrgXkbRF_GroupPtr	group;
98605b261ecSmrg
98705b261ecSmrg    if (!rules)
98805b261ecSmrg	return;
98905b261ecSmrg    if (rules->rules) {
99005b261ecSmrg	for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
9916747b715Smrg	    free(rule->model);
9926747b715Smrg	    free(rule->layout);
9936747b715Smrg	    free(rule->variant);
9946747b715Smrg	    free(rule->option);
9956747b715Smrg	    free(rule->keycodes);
9966747b715Smrg	    free(rule->symbols);
9976747b715Smrg	    free(rule->types);
9986747b715Smrg	    free(rule->compat);
9996747b715Smrg	    free(rule->geometry);
10006747b715Smrg	    memset((char *)rule, 0, sizeof(XkbRF_RuleRec));
100105b261ecSmrg	}
10026747b715Smrg	free(rules->rules);
100305b261ecSmrg	rules->num_rules= rules->sz_rules= 0;
100405b261ecSmrg	rules->rules= NULL;
100505b261ecSmrg    }
100605b261ecSmrg
100705b261ecSmrg    if (rules->groups) {
100805b261ecSmrg	for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
10096747b715Smrg	    free(group->name);
10106747b715Smrg	    free(group->words);
101105b261ecSmrg	}
10126747b715Smrg	free(rules->groups);
101305b261ecSmrg	rules->num_groups= 0;
101405b261ecSmrg	rules->groups= NULL;
101505b261ecSmrg    }
101605b261ecSmrg    if (freeRules)
10176747b715Smrg	free(rules);
101805b261ecSmrg    return;
101905b261ecSmrg}
1020