maprules.c revision 4642e01f
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#define NEED_EVENTS
4005b261ecSmrg#include <X11/Xproto.h>
4105b261ecSmrg#include <X11/X.h>
4205b261ecSmrg#include <X11/Xos.h>
4305b261ecSmrg#include <X11/Xfuncs.h>
4405b261ecSmrg#include <X11/Xatom.h>
4505b261ecSmrg#include <X11/keysym.h>
4605b261ecSmrg#include "misc.h"
4705b261ecSmrg#include "inputstr.h"
4805b261ecSmrg#include "dix.h"
494642e01fSmrg#include "os.h"
504642e01fSmrg#include "xkbstr.h"
5105b261ecSmrg#define XKBSRV_NEED_FILE_FUNCS
5205b261ecSmrg#include <xkbsrv.h>
5305b261ecSmrg
5405b261ecSmrg/***====================================================================***/
5505b261ecSmrg
5605b261ecSmrg#define DFLT_LINE_SIZE	128
5705b261ecSmrg
5805b261ecSmrgtypedef struct {
5905b261ecSmrg	int	line_num;
6005b261ecSmrg	int	sz_line;
6105b261ecSmrg	int	num_line;
6205b261ecSmrg	char	buf[DFLT_LINE_SIZE];
6305b261ecSmrg	char *	line;
6405b261ecSmrg} InputLine;
6505b261ecSmrg
6605b261ecSmrgstatic void
6705b261ecSmrgInitInputLine(InputLine *line)
6805b261ecSmrg{
6905b261ecSmrg    line->line_num= 1;
7005b261ecSmrg    line->num_line= 0;
7105b261ecSmrg    line->sz_line= DFLT_LINE_SIZE;
7205b261ecSmrg    line->line=	line->buf;
7305b261ecSmrg    return;
7405b261ecSmrg}
7505b261ecSmrg
7605b261ecSmrgstatic void
7705b261ecSmrgFreeInputLine(InputLine *line)
7805b261ecSmrg{
7905b261ecSmrg    if (line->line!=line->buf)
8005b261ecSmrg	_XkbFree(line->line);
8105b261ecSmrg    line->line_num= 1;
8205b261ecSmrg    line->num_line= 0;
8305b261ecSmrg    line->sz_line= DFLT_LINE_SIZE;
8405b261ecSmrg    line->line= line->buf;
8505b261ecSmrg    return;
8605b261ecSmrg}
8705b261ecSmrg
8805b261ecSmrgstatic int
8905b261ecSmrgInputLineAddChar(InputLine *line,int ch)
9005b261ecSmrg{
9105b261ecSmrg    if (line->num_line>=line->sz_line) {
9205b261ecSmrg	if (line->line==line->buf) {
9305b261ecSmrg	    line->line= (char *)_XkbAlloc(line->sz_line*2);
9405b261ecSmrg	    memcpy(line->line,line->buf,line->sz_line);
9505b261ecSmrg	}
9605b261ecSmrg	else {
9705b261ecSmrg	    line->line=(char *)_XkbRealloc((char *)line->line,line->sz_line*2);
9805b261ecSmrg	}
9905b261ecSmrg	line->sz_line*= 2;
10005b261ecSmrg    }
10105b261ecSmrg    line->line[line->num_line++]= ch;
10205b261ecSmrg    return ch;
10305b261ecSmrg}
10405b261ecSmrg
10505b261ecSmrg#define	ADD_CHAR(l,c)	((l)->num_line<(l)->sz_line?\
10605b261ecSmrg				(int)((l)->line[(l)->num_line++]= (c)):\
10705b261ecSmrg				InputLineAddChar(l,c))
10805b261ecSmrg
10905b261ecSmrgstatic Bool
11005b261ecSmrgGetInputLine(FILE *file,InputLine *line,Bool checkbang)
11105b261ecSmrg{
11205b261ecSmrgint	ch;
11305b261ecSmrgBool	endOfFile,spacePending,slashPending,inComment;
11405b261ecSmrg
11505b261ecSmrg     endOfFile= False;
11605b261ecSmrg     while ((!endOfFile)&&(line->num_line==0)) {
11705b261ecSmrg	spacePending= slashPending= inComment= False;
11805b261ecSmrg	while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
11905b261ecSmrg	    if (ch=='\\') {
12005b261ecSmrg		if ((ch=getc(file))==EOF)
12105b261ecSmrg		    break;
12205b261ecSmrg		if (ch=='\n') {
12305b261ecSmrg		    inComment= False;
12405b261ecSmrg		    ch= ' ';
12505b261ecSmrg		    line->line_num++;
12605b261ecSmrg		}
12705b261ecSmrg	    }
12805b261ecSmrg	    if (inComment)
12905b261ecSmrg		continue;
13005b261ecSmrg	    if (ch=='/') {
13105b261ecSmrg		if (slashPending) {
13205b261ecSmrg		    inComment= True;
13305b261ecSmrg		    slashPending= False;
13405b261ecSmrg		}
13505b261ecSmrg		else {
13605b261ecSmrg		    slashPending= True;
13705b261ecSmrg		}
13805b261ecSmrg		continue;
13905b261ecSmrg	    }
14005b261ecSmrg	    else if (slashPending) {
14105b261ecSmrg		if (spacePending) {
14205b261ecSmrg		    ADD_CHAR(line,' ');
14305b261ecSmrg		    spacePending= False;
14405b261ecSmrg		}
14505b261ecSmrg		ADD_CHAR(line,'/');
14605b261ecSmrg		slashPending= False;
14705b261ecSmrg	    }
14805b261ecSmrg	    if (isspace(ch)) {
14905b261ecSmrg		while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
15005b261ecSmrg		    ch= getc(file);
15105b261ecSmrg		}
15205b261ecSmrg		if (ch==EOF)
15305b261ecSmrg		    break;
15405b261ecSmrg		if ((ch!='\n')&&(line->num_line>0))
15505b261ecSmrg		    spacePending= True;
15605b261ecSmrg		ungetc(ch,file);
15705b261ecSmrg	    }
15805b261ecSmrg	    else {
15905b261ecSmrg		if (spacePending) {
16005b261ecSmrg		    ADD_CHAR(line,' ');
16105b261ecSmrg		    spacePending= False;
16205b261ecSmrg		}
16305b261ecSmrg		if (checkbang && ch=='!') {
16405b261ecSmrg		    if (line->num_line!=0) {
1654642e01fSmrg			DebugF("The '!' legal only at start of line\n");
1664642e01fSmrg			DebugF("Line containing '!' ignored\n");
16705b261ecSmrg			line->num_line= 0;
16805b261ecSmrg			inComment= 0;
16905b261ecSmrg			break;
17005b261ecSmrg		    }
17105b261ecSmrg
17205b261ecSmrg		}
17305b261ecSmrg		ADD_CHAR(line,ch);
17405b261ecSmrg	    }
17505b261ecSmrg	}
17605b261ecSmrg	if (ch==EOF)
17705b261ecSmrg	     endOfFile= True;
17805b261ecSmrg/*	else line->num_line++;*/
17905b261ecSmrg     }
18005b261ecSmrg     if ((line->num_line==0)&&(endOfFile))
18105b261ecSmrg	return False;
18205b261ecSmrg      ADD_CHAR(line,'\0');
18305b261ecSmrg      return True;
18405b261ecSmrg}
18505b261ecSmrg
18605b261ecSmrg/***====================================================================***/
18705b261ecSmrg
18805b261ecSmrg#define	MODEL		0
18905b261ecSmrg#define	LAYOUT		1
19005b261ecSmrg#define	VARIANT		2
19105b261ecSmrg#define	OPTION		3
19205b261ecSmrg#define	KEYCODES	4
19305b261ecSmrg#define SYMBOLS		5
19405b261ecSmrg#define	TYPES		6
19505b261ecSmrg#define	COMPAT		7
19605b261ecSmrg#define	GEOMETRY	8
19705b261ecSmrg#define	KEYMAP		9
19805b261ecSmrg#define	MAX_WORDS	10
19905b261ecSmrg
20005b261ecSmrg#define	PART_MASK	0x000F
20105b261ecSmrg#define	COMPONENT_MASK	0x03F0
20205b261ecSmrg
20305b261ecSmrgstatic	char *	cname[MAX_WORDS] = {
20405b261ecSmrg	"model", "layout", "variant", "option",
20505b261ecSmrg	"keycodes", "symbols", "types", "compat", "geometry", "keymap"
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;
27305b261ecSmrg   bzero((char *)remap,sizeof(RemapSpec));
27405b261ecSmrg   remap->number = len;
27505b261ecSmrg   while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
27605b261ecSmrg	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                }
29705b261ecSmrg		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   if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
34105b261ecSmrg				((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
3424642e01fSmrg	DebugF("Keymap cannot appear with other components\n");
3434642e01fSmrg	DebugF("Illegal mapping ignored\n");
34405b261ecSmrg	remap->num_remap= 0;
34505b261ecSmrg	return;
34605b261ecSmrg   }
34705b261ecSmrg   remap->number++;
34805b261ecSmrg   return;
34905b261ecSmrg}
35005b261ecSmrg
35105b261ecSmrgstatic Bool
35205b261ecSmrgMatchOneOf(char *wanted,char *vals_defined)
35305b261ecSmrg{
35405b261ecSmrgchar	*str,*next;
35505b261ecSmrgint	want_len= strlen(wanted);
35605b261ecSmrg
35705b261ecSmrg    for (str=vals_defined,next=NULL;str!=NULL;str=next) {
35805b261ecSmrg	int len;
35905b261ecSmrg	next= strchr(str,',');
36005b261ecSmrg	if (next) {
36105b261ecSmrg	    len= next-str;
36205b261ecSmrg	    next++;
36305b261ecSmrg	}
36405b261ecSmrg	else {
36505b261ecSmrg	    len= strlen(str);
36605b261ecSmrg	}
36705b261ecSmrg	if ((len==want_len)&&(strncmp(wanted,str,len)==0))
36805b261ecSmrg	    return True;
36905b261ecSmrg    }
37005b261ecSmrg    return False;
37105b261ecSmrg}
37205b261ecSmrg
37305b261ecSmrg/***====================================================================***/
37405b261ecSmrg
37505b261ecSmrgstatic Bool
37605b261ecSmrgCheckLine(	InputLine *		line,
37705b261ecSmrg		RemapSpec *		remap,
37805b261ecSmrg		XkbRF_RulePtr		rule,
37905b261ecSmrg		XkbRF_GroupPtr		group)
38005b261ecSmrg{
38105b261ecSmrgchar *		str,*tok;
38205b261ecSmrgregister int	nread, i;
38305b261ecSmrgFileSpec	tmp;
38405b261ecSmrg_Xstrtokparams	strtok_buf;
38505b261ecSmrgBool 		append = False;
38605b261ecSmrg
38705b261ecSmrg    if (line->line[0]=='!') {
38805b261ecSmrg        if (line->line[1] == '$' ||
38905b261ecSmrg            (line->line[1] == ' ' && line->line[2] == '$')) {
39005b261ecSmrg            char *gname = strchr(line->line, '$');
39105b261ecSmrg            char *words = strchr(gname, ' ');
39205b261ecSmrg            if(!words)
39305b261ecSmrg                return False;
39405b261ecSmrg            *words++ = '\0';
39505b261ecSmrg            for (; *words; words++) {
39605b261ecSmrg                if (*words != '=' && *words != ' ')
39705b261ecSmrg                    break;
39805b261ecSmrg            }
39905b261ecSmrg            if (*words == '\0')
40005b261ecSmrg                return False;
40105b261ecSmrg            group->name = _XkbDupString(gname);
40205b261ecSmrg            group->words = _XkbDupString(words);
40305b261ecSmrg            for (i = 1, words = group->words; *words; words++) {
40405b261ecSmrg                 if ( *words == ' ') {
40505b261ecSmrg                     *words++ = '\0';
40605b261ecSmrg                     i++;
40705b261ecSmrg                 }
40805b261ecSmrg            }
40905b261ecSmrg            group->number = i;
41005b261ecSmrg            return True;
41105b261ecSmrg        } else {
41205b261ecSmrg	    SetUpRemap(line,remap);
41305b261ecSmrg	    return False;
41405b261ecSmrg        }
41505b261ecSmrg    }
41605b261ecSmrg
41705b261ecSmrg    if (remap->num_remap==0) {
4184642e01fSmrg	DebugF("Must have a mapping before first line of data\n");
4194642e01fSmrg	DebugF("Illegal line of data ignored\n");
42005b261ecSmrg	return False;
42105b261ecSmrg    }
42205b261ecSmrg    bzero((char *)&tmp,sizeof(FileSpec));
42305b261ecSmrg    str= line->line;
42405b261ecSmrg    for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
42505b261ecSmrg	str= NULL;
42605b261ecSmrg	if (strcmp(tok,"=")==0) {
42705b261ecSmrg	    nread--;
42805b261ecSmrg	    continue;
42905b261ecSmrg	}
43005b261ecSmrg	if (nread>remap->num_remap) {
4314642e01fSmrg	    DebugF("Too many words on a line\n");
4324642e01fSmrg	    DebugF("Extra word \"%s\" ignored\n",tok);
43305b261ecSmrg	    continue;
43405b261ecSmrg	}
43505b261ecSmrg	tmp.name[remap->remap[nread].word]= tok;
43605b261ecSmrg	if (*tok == '+' || *tok == '|')
43705b261ecSmrg	    append = True;
43805b261ecSmrg    }
43905b261ecSmrg    if (nread<remap->num_remap) {
4404642e01fSmrg	DebugF("Too few words on a line: %s\n", line->line);
4414642e01fSmrg	DebugF("line ignored\n");
44205b261ecSmrg	return False;
44305b261ecSmrg    }
44405b261ecSmrg
44505b261ecSmrg    rule->flags= 0;
44605b261ecSmrg    rule->number = remap->number;
44705b261ecSmrg    if (tmp.name[OPTION])
44805b261ecSmrg	 rule->flags|= XkbRF_Option;
44905b261ecSmrg    else if (append)
45005b261ecSmrg	 rule->flags|= XkbRF_Append;
45105b261ecSmrg    else
45205b261ecSmrg	 rule->flags|= XkbRF_Normal;
45305b261ecSmrg    rule->model= _XkbDupString(tmp.name[MODEL]);
45405b261ecSmrg    rule->layout= _XkbDupString(tmp.name[LAYOUT]);
45505b261ecSmrg    rule->variant= _XkbDupString(tmp.name[VARIANT]);
45605b261ecSmrg    rule->option= _XkbDupString(tmp.name[OPTION]);
45705b261ecSmrg
45805b261ecSmrg    rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
45905b261ecSmrg    rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
46005b261ecSmrg    rule->types= _XkbDupString(tmp.name[TYPES]);
46105b261ecSmrg    rule->compat= _XkbDupString(tmp.name[COMPAT]);
46205b261ecSmrg    rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
4634642e01fSmrg    rule->keymap= NULL;
46405b261ecSmrg
46505b261ecSmrg    rule->layout_num = rule->variant_num = 0;
46605b261ecSmrg    for (i = 0; i < nread; i++) {
46705b261ecSmrg        if (remap->remap[i].index) {
46805b261ecSmrg	    if (remap->remap[i].word == LAYOUT)
46905b261ecSmrg	        rule->layout_num = remap->remap[i].index;
47005b261ecSmrg	    if (remap->remap[i].word == VARIANT)
47105b261ecSmrg	        rule->variant_num = remap->remap[i].index;
47205b261ecSmrg        }
47305b261ecSmrg    }
47405b261ecSmrg    return True;
47505b261ecSmrg}
47605b261ecSmrg
47705b261ecSmrgstatic char *
47805b261ecSmrg_Concat(char *str1,char *str2)
47905b261ecSmrg{
48005b261ecSmrgint len;
48105b261ecSmrg
48205b261ecSmrg    if ((!str1)||(!str2))
48305b261ecSmrg	return str1;
48405b261ecSmrg    len= strlen(str1)+strlen(str2)+1;
48505b261ecSmrg    str1= _XkbTypedRealloc(str1,len,char);
48605b261ecSmrg    if (str1)
48705b261ecSmrg	strcat(str1,str2);
48805b261ecSmrg    return str1;
48905b261ecSmrg}
49005b261ecSmrg
49105b261ecSmrgstatic void
49205b261ecSmrgsqueeze_spaces(char *p1)
49305b261ecSmrg{
49405b261ecSmrg   char *p2;
49505b261ecSmrg   for (p2 = p1; *p2; p2++) {
49605b261ecSmrg       *p1 = *p2;
49705b261ecSmrg       if (*p1 != ' ') p1++;
49805b261ecSmrg   }
49905b261ecSmrg   *p1 = '\0';
50005b261ecSmrg}
50105b261ecSmrg
50205b261ecSmrgstatic Bool
50305b261ecSmrgMakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
50405b261ecSmrg{
50505b261ecSmrg
50605b261ecSmrg   bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec));
50705b261ecSmrg   mdefs->model = defs->model;
50805b261ecSmrg   mdefs->options = _XkbDupString(defs->options);
50905b261ecSmrg   if (mdefs->options) squeeze_spaces(mdefs->options);
51005b261ecSmrg
51105b261ecSmrg   if (defs->layout) {
51205b261ecSmrg       if (!strchr(defs->layout, ',')) {
51305b261ecSmrg           mdefs->layout[0] = defs->layout;
51405b261ecSmrg       } else {
51505b261ecSmrg           char *p;
51605b261ecSmrg           int i;
51705b261ecSmrg           mdefs->layout[1] = _XkbDupString(defs->layout);
51805b261ecSmrg	   if (mdefs->layout[1] == NULL)
51905b261ecSmrg	      return False;
52005b261ecSmrg           squeeze_spaces(mdefs->layout[1]);
52105b261ecSmrg           p = mdefs->layout[1];
52205b261ecSmrg           for (i = 2; i <= XkbNumKbdGroups; i++) {
52305b261ecSmrg              if ((p = strchr(p, ','))) {
52405b261ecSmrg                 *p++ = '\0';
52505b261ecSmrg                 mdefs->layout[i] = p;
52605b261ecSmrg              } else {
52705b261ecSmrg                 break;
52805b261ecSmrg              }
52905b261ecSmrg           }
53005b261ecSmrg           if (p && (p = strchr(p, ',')))
53105b261ecSmrg              *p = '\0';
53205b261ecSmrg       }
53305b261ecSmrg   }
53405b261ecSmrg
53505b261ecSmrg   if (defs->variant) {
53605b261ecSmrg       if (!strchr(defs->variant, ',')) {
53705b261ecSmrg           mdefs->variant[0] = defs->variant;
53805b261ecSmrg       } else {
53905b261ecSmrg           char *p;
54005b261ecSmrg           int i;
54105b261ecSmrg           mdefs->variant[1] = _XkbDupString(defs->variant);
54205b261ecSmrg	   if (mdefs->variant[1] == NULL)
54305b261ecSmrg	      return False;
54405b261ecSmrg           squeeze_spaces(mdefs->variant[1]);
54505b261ecSmrg           p = mdefs->variant[1];
54605b261ecSmrg           for (i = 2; i <= XkbNumKbdGroups; i++) {
54705b261ecSmrg              if ((p = strchr(p, ','))) {
54805b261ecSmrg                 *p++ = '\0';
54905b261ecSmrg                 mdefs->variant[i] = p;
55005b261ecSmrg              } else {
55105b261ecSmrg                 break;
55205b261ecSmrg              }
55305b261ecSmrg           }
55405b261ecSmrg           if (p && (p = strchr(p, ',')))
55505b261ecSmrg              *p = '\0';
55605b261ecSmrg       }
55705b261ecSmrg   }
55805b261ecSmrg   return True;
55905b261ecSmrg}
56005b261ecSmrg
56105b261ecSmrgstatic void
56205b261ecSmrgFreeMultiDefs(XkbRF_MultiDefsPtr defs)
56305b261ecSmrg{
56405b261ecSmrg  if (defs->options) _XkbFree(defs->options);
56505b261ecSmrg  if (defs->layout[1])  _XkbFree(defs->layout[1]);
56605b261ecSmrg  if (defs->variant[1])  _XkbFree(defs->variant[1]);
56705b261ecSmrg}
56805b261ecSmrg
56905b261ecSmrgstatic void
57005b261ecSmrgApply(char *src, char **dst)
57105b261ecSmrg{
57205b261ecSmrg    if (src) {
57305b261ecSmrg        if (*src == '+' || *src == '!') {
57405b261ecSmrg	    *dst= _Concat(*dst, src);
57505b261ecSmrg        } else {
57605b261ecSmrg            if (*dst == NULL)
57705b261ecSmrg	        *dst= _XkbDupString(src);
57805b261ecSmrg        }
57905b261ecSmrg    }
58005b261ecSmrg}
58105b261ecSmrg
58205b261ecSmrgstatic void
58305b261ecSmrgXkbRF_ApplyRule(	XkbRF_RulePtr 		rule,
58405b261ecSmrg			XkbComponentNamesPtr	names)
58505b261ecSmrg{
58605b261ecSmrg    rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
58705b261ecSmrg
58805b261ecSmrg    Apply(rule->keycodes, &names->keycodes);
58905b261ecSmrg    Apply(rule->symbols,  &names->symbols);
59005b261ecSmrg    Apply(rule->types,    &names->types);
59105b261ecSmrg    Apply(rule->compat,   &names->compat);
59205b261ecSmrg    Apply(rule->geometry, &names->geometry);
59305b261ecSmrg}
59405b261ecSmrg
59505b261ecSmrgstatic Bool
59605b261ecSmrgCheckGroup(	XkbRF_RulesPtr          rules,
59705b261ecSmrg		char * 			group_name,
59805b261ecSmrg		char * 			name)
59905b261ecSmrg{
60005b261ecSmrg   int i;
60105b261ecSmrg   char *p;
60205b261ecSmrg   XkbRF_GroupPtr group;
60305b261ecSmrg
60405b261ecSmrg   for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
60505b261ecSmrg       if (! strcmp(group->name, group_name)) {
60605b261ecSmrg           break;
60705b261ecSmrg       }
60805b261ecSmrg   }
60905b261ecSmrg   if (i == rules->num_groups)
61005b261ecSmrg       return False;
61105b261ecSmrg   for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
61205b261ecSmrg       if (! strcmp(p, name)) {
61305b261ecSmrg           return True;
61405b261ecSmrg       }
61505b261ecSmrg   }
61605b261ecSmrg   return False;
61705b261ecSmrg}
61805b261ecSmrg
61905b261ecSmrgstatic int
62005b261ecSmrgXkbRF_CheckApplyRule(	XkbRF_RulePtr 		rule,
62105b261ecSmrg			XkbRF_MultiDefsPtr	mdefs,
62205b261ecSmrg			XkbComponentNamesPtr	names,
62305b261ecSmrg			XkbRF_RulesPtr          rules)
62405b261ecSmrg{
62505b261ecSmrg    Bool pending = False;
62605b261ecSmrg
62705b261ecSmrg    if (rule->model != NULL) {
62805b261ecSmrg        if(mdefs->model == NULL)
62905b261ecSmrg            return 0;
63005b261ecSmrg        if (strcmp(rule->model, "*") == 0) {
63105b261ecSmrg            pending = True;
63205b261ecSmrg        } else {
63305b261ecSmrg            if (rule->model[0] == '$') {
63405b261ecSmrg               if (!CheckGroup(rules, rule->model, mdefs->model))
63505b261ecSmrg                  return 0;
63605b261ecSmrg            } else {
63705b261ecSmrg	       if (strcmp(rule->model, mdefs->model) != 0)
63805b261ecSmrg	          return 0;
63905b261ecSmrg	    }
64005b261ecSmrg	}
64105b261ecSmrg    }
64205b261ecSmrg    if (rule->option != NULL) {
64305b261ecSmrg	if (mdefs->options == NULL)
64405b261ecSmrg	    return 0;
64505b261ecSmrg	if ((!MatchOneOf(rule->option,mdefs->options)))
64605b261ecSmrg	    return 0;
64705b261ecSmrg    }
64805b261ecSmrg
64905b261ecSmrg    if (rule->layout != NULL) {
65005b261ecSmrg	if(mdefs->layout[rule->layout_num] == NULL ||
65105b261ecSmrg	   *mdefs->layout[rule->layout_num] == '\0')
65205b261ecSmrg	    return 0;
65305b261ecSmrg        if (strcmp(rule->layout, "*") == 0) {
65405b261ecSmrg            pending = True;
65505b261ecSmrg        } else {
65605b261ecSmrg            if (rule->layout[0] == '$') {
65705b261ecSmrg               if (!CheckGroup(rules, rule->layout,
65805b261ecSmrg                               mdefs->layout[rule->layout_num]))
65905b261ecSmrg                  return 0;
66005b261ecSmrg	    } else {
66105b261ecSmrg	       if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
66205b261ecSmrg	           return 0;
66305b261ecSmrg	    }
66405b261ecSmrg	}
66505b261ecSmrg    }
66605b261ecSmrg    if (rule->variant != NULL) {
66705b261ecSmrg	if (mdefs->variant[rule->variant_num] == NULL ||
66805b261ecSmrg	    *mdefs->variant[rule->variant_num] == '\0')
66905b261ecSmrg	    return 0;
67005b261ecSmrg        if (strcmp(rule->variant, "*") == 0) {
67105b261ecSmrg            pending = True;
67205b261ecSmrg        } else {
67305b261ecSmrg            if (rule->variant[0] == '$') {
67405b261ecSmrg               if (!CheckGroup(rules, rule->variant,
67505b261ecSmrg                               mdefs->variant[rule->variant_num]))
67605b261ecSmrg                  return 0;
67705b261ecSmrg            } else {
67805b261ecSmrg	       if (strcmp(rule->variant,
67905b261ecSmrg                          mdefs->variant[rule->variant_num]) != 0)
68005b261ecSmrg	           return 0;
68105b261ecSmrg	    }
68205b261ecSmrg	}
68305b261ecSmrg    }
68405b261ecSmrg    if (pending) {
68505b261ecSmrg        rule->flags|= XkbRF_PendingMatch;
68605b261ecSmrg	return rule->number;
68705b261ecSmrg    }
68805b261ecSmrg    /* exact match, apply it now */
68905b261ecSmrg    XkbRF_ApplyRule(rule,names);
69005b261ecSmrg    return rule->number;
69105b261ecSmrg}
69205b261ecSmrg
69305b261ecSmrgstatic void
69405b261ecSmrgXkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
69505b261ecSmrg{
69605b261ecSmrgregister int 	i;
69705b261ecSmrgXkbRF_RulePtr	rule;
69805b261ecSmrg
69905b261ecSmrg    for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
70005b261ecSmrg	rule->flags&= ~XkbRF_PendingMatch;
70105b261ecSmrg    }
70205b261ecSmrg}
70305b261ecSmrg
70405b261ecSmrgstatic void
70505b261ecSmrgXkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)
70605b261ecSmrg{
70705b261ecSmrgint		i;
70805b261ecSmrgXkbRF_RulePtr	rule;
70905b261ecSmrg
71005b261ecSmrg    for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
71105b261ecSmrg	if ((rule->flags&XkbRF_PendingMatch)==0)
71205b261ecSmrg	    continue;
71305b261ecSmrg	XkbRF_ApplyRule(rule,names);
71405b261ecSmrg    }
71505b261ecSmrg}
71605b261ecSmrg
71705b261ecSmrgstatic void
71805b261ecSmrgXkbRF_CheckApplyRules(	XkbRF_RulesPtr 		rules,
71905b261ecSmrg			XkbRF_MultiDefsPtr	mdefs,
72005b261ecSmrg			XkbComponentNamesPtr	names,
72105b261ecSmrg			int			flags)
72205b261ecSmrg{
72305b261ecSmrgint		i;
72405b261ecSmrgXkbRF_RulePtr	rule;
72505b261ecSmrgint		skip;
72605b261ecSmrg
72705b261ecSmrg    for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
72805b261ecSmrg	if ((rule->flags & flags) != flags)
72905b261ecSmrg	    continue;
73005b261ecSmrg	skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
73105b261ecSmrg	if (skip && !(flags & XkbRF_Option)) {
73205b261ecSmrg	    for ( ;(i < rules->num_rules) && (rule->number == skip);
73305b261ecSmrg		  rule++, i++);
73405b261ecSmrg	    rule--; i--;
73505b261ecSmrg	}
73605b261ecSmrg    }
73705b261ecSmrg}
73805b261ecSmrg
73905b261ecSmrg/***====================================================================***/
74005b261ecSmrg
74105b261ecSmrgstatic char *
74205b261ecSmrgXkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
74305b261ecSmrg{
74405b261ecSmrgchar 	*str, *outstr, *orig, *var;
74505b261ecSmrgint	len, ndx;
74605b261ecSmrg
74705b261ecSmrg    orig= name;
74805b261ecSmrg    str= index(name,'%');
74905b261ecSmrg    if (str==NULL)
75005b261ecSmrg	return name;
75105b261ecSmrg    len= strlen(name);
75205b261ecSmrg    while (str!=NULL) {
75305b261ecSmrg	char pfx= str[1];
75405b261ecSmrg	int   extra_len= 0;
75505b261ecSmrg	if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
75605b261ecSmrg	    extra_len= 1;
75705b261ecSmrg	    str++;
75805b261ecSmrg	}
75905b261ecSmrg	else if (pfx=='(') {
76005b261ecSmrg	    extra_len= 2;
76105b261ecSmrg	    str++;
76205b261ecSmrg	}
76305b261ecSmrg	var = str + 1;
76405b261ecSmrg	str = get_index(var + 1, &ndx);
76505b261ecSmrg	if (ndx == -1) {
76605b261ecSmrg	    str = index(str,'%');
76705b261ecSmrg	    continue;
76805b261ecSmrg        }
76905b261ecSmrg	if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
77005b261ecSmrg	    len+= strlen(mdefs->layout[ndx])+extra_len;
77105b261ecSmrg	else if ((*var=='m')&&mdefs->model)
77205b261ecSmrg	    len+= strlen(mdefs->model)+extra_len;
77305b261ecSmrg	else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
77405b261ecSmrg	    len+= strlen(mdefs->variant[ndx])+extra_len;
77505b261ecSmrg	if ((pfx=='(')&&(*str==')')) {
77605b261ecSmrg	    str++;
77705b261ecSmrg	}
77805b261ecSmrg	str= index(&str[0],'%');
77905b261ecSmrg    }
78005b261ecSmrg    name= (char *)_XkbAlloc(len+1);
78105b261ecSmrg    str= orig;
78205b261ecSmrg    outstr= name;
78305b261ecSmrg    while (*str!='\0') {
78405b261ecSmrg	if (str[0]=='%') {
78505b261ecSmrg	    char pfx,sfx;
78605b261ecSmrg	    str++;
78705b261ecSmrg	    pfx= str[0];
78805b261ecSmrg	    sfx= '\0';
78905b261ecSmrg	    if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
79005b261ecSmrg		str++;
79105b261ecSmrg	    }
79205b261ecSmrg	    else if (pfx=='(') {
79305b261ecSmrg		sfx= ')';
79405b261ecSmrg		str++;
79505b261ecSmrg	    }
79605b261ecSmrg	    else pfx= '\0';
79705b261ecSmrg
79805b261ecSmrg	    var = str;
79905b261ecSmrg	    str = get_index(var + 1, &ndx);
80005b261ecSmrg	    if (ndx == -1) {
80105b261ecSmrg	        continue;
80205b261ecSmrg            }
80305b261ecSmrg	    if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
80405b261ecSmrg		if (pfx) *outstr++= pfx;
80505b261ecSmrg		strcpy(outstr,mdefs->layout[ndx]);
80605b261ecSmrg		outstr+= strlen(mdefs->layout[ndx]);
80705b261ecSmrg		if (sfx) *outstr++= sfx;
80805b261ecSmrg	    }
80905b261ecSmrg	    else if ((*var=='m')&&(mdefs->model)) {
81005b261ecSmrg		if (pfx) *outstr++= pfx;
81105b261ecSmrg		strcpy(outstr,mdefs->model);
81205b261ecSmrg		outstr+= strlen(mdefs->model);
81305b261ecSmrg		if (sfx) *outstr++= sfx;
81405b261ecSmrg	    }
81505b261ecSmrg	    else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
81605b261ecSmrg		if (pfx) *outstr++= pfx;
81705b261ecSmrg		strcpy(outstr,mdefs->variant[ndx]);
81805b261ecSmrg		outstr+= strlen(mdefs->variant[ndx]);
81905b261ecSmrg		if (sfx) *outstr++= sfx;
82005b261ecSmrg	    }
82105b261ecSmrg	    if ((pfx=='(')&&(*str==')'))
82205b261ecSmrg		str++;
82305b261ecSmrg	}
82405b261ecSmrg	else {
82505b261ecSmrg	    *outstr++= *str++;
82605b261ecSmrg	}
82705b261ecSmrg    }
82805b261ecSmrg    *outstr++= '\0';
82905b261ecSmrg    if (orig!=name)
83005b261ecSmrg	_XkbFree(orig);
83105b261ecSmrg    return name;
83205b261ecSmrg}
83305b261ecSmrg
83405b261ecSmrg/***====================================================================***/
83505b261ecSmrg
83605b261ecSmrgBool
83705b261ecSmrgXkbRF_GetComponents(	XkbRF_RulesPtr		rules,
83805b261ecSmrg			XkbRF_VarDefsPtr	defs,
83905b261ecSmrg			XkbComponentNamesPtr	names)
84005b261ecSmrg{
84105b261ecSmrg    XkbRF_MultiDefsRec mdefs;
84205b261ecSmrg
84305b261ecSmrg    MakeMultiDefs(&mdefs, defs);
84405b261ecSmrg
84505b261ecSmrg    bzero((char *)names,sizeof(XkbComponentNamesRec));
84605b261ecSmrg    XkbRF_ClearPartialMatches(rules);
84705b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
84805b261ecSmrg    XkbRF_ApplyPartialMatches(rules, names);
84905b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
85005b261ecSmrg    XkbRF_ApplyPartialMatches(rules, names);
85105b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
85205b261ecSmrg
85305b261ecSmrg    if (names->keycodes)
85405b261ecSmrg	names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
85505b261ecSmrg    if (names->symbols)
85605b261ecSmrg	names->symbols=	XkbRF_SubstituteVars(names->symbols, &mdefs);
85705b261ecSmrg    if (names->types)
85805b261ecSmrg	names->types= XkbRF_SubstituteVars(names->types, &mdefs);
85905b261ecSmrg    if (names->compat)
86005b261ecSmrg	names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
86105b261ecSmrg    if (names->geometry)
86205b261ecSmrg	names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
86305b261ecSmrg    if (names->keymap)
86405b261ecSmrg	names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
86505b261ecSmrg
86605b261ecSmrg    FreeMultiDefs(&mdefs);
86705b261ecSmrg    return (names->keycodes && names->symbols && names->types &&
86805b261ecSmrg		names->compat && names->geometry ) || names->keymap;
86905b261ecSmrg}
87005b261ecSmrg
87105b261ecSmrgXkbRF_RulePtr
87205b261ecSmrgXkbRF_AddRule(XkbRF_RulesPtr	rules)
87305b261ecSmrg{
87405b261ecSmrg    if (rules->sz_rules<1) {
87505b261ecSmrg	rules->sz_rules= 16;
87605b261ecSmrg	rules->num_rules= 0;
87705b261ecSmrg	rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
87805b261ecSmrg    }
87905b261ecSmrg    else if (rules->num_rules>=rules->sz_rules) {
88005b261ecSmrg	rules->sz_rules*= 2;
88105b261ecSmrg	rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
88205b261ecSmrg							XkbRF_RuleRec);
88305b261ecSmrg    }
88405b261ecSmrg    if (!rules->rules) {
88505b261ecSmrg	rules->sz_rules= rules->num_rules= 0;
8864642e01fSmrg	DebugF("Allocation failure in XkbRF_AddRule\n");
88705b261ecSmrg	return NULL;
88805b261ecSmrg    }
88905b261ecSmrg    bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
89005b261ecSmrg    return &rules->rules[rules->num_rules++];
89105b261ecSmrg}
89205b261ecSmrg
89305b261ecSmrgXkbRF_GroupPtr
89405b261ecSmrgXkbRF_AddGroup(XkbRF_RulesPtr	rules)
89505b261ecSmrg{
89605b261ecSmrg    if (rules->sz_groups<1) {
89705b261ecSmrg	rules->sz_groups= 16;
89805b261ecSmrg	rules->num_groups= 0;
89905b261ecSmrg	rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
90005b261ecSmrg    }
90105b261ecSmrg    else if (rules->num_groups >= rules->sz_groups) {
90205b261ecSmrg	rules->sz_groups *= 2;
90305b261ecSmrg	rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
90405b261ecSmrg							XkbRF_GroupRec);
90505b261ecSmrg    }
90605b261ecSmrg    if (!rules->groups) {
90705b261ecSmrg	rules->sz_groups= rules->num_groups= 0;
90805b261ecSmrg	return NULL;
90905b261ecSmrg    }
91005b261ecSmrg
91105b261ecSmrg    bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
91205b261ecSmrg    return &rules->groups[rules->num_groups++];
91305b261ecSmrg}
91405b261ecSmrg
91505b261ecSmrgBool
91605b261ecSmrgXkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
91705b261ecSmrg{
91805b261ecSmrgInputLine	line;
91905b261ecSmrgRemapSpec	remap;
92005b261ecSmrgXkbRF_RuleRec	trule,*rule;
92105b261ecSmrgXkbRF_GroupRec  tgroup,*group;
92205b261ecSmrg
92305b261ecSmrg    if (!(rules && file))
92405b261ecSmrg	return False;
92505b261ecSmrg    bzero((char *)&remap,sizeof(RemapSpec));
92605b261ecSmrg    bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
92705b261ecSmrg    InitInputLine(&line);
92805b261ecSmrg    while (GetInputLine(file,&line,True)) {
92905b261ecSmrg	if (CheckLine(&line,&remap,&trule,&tgroup)) {
93005b261ecSmrg            if (tgroup.number) {
93105b261ecSmrg	        if ((group= XkbRF_AddGroup(rules))!=NULL) {
93205b261ecSmrg		    *group= tgroup;
93305b261ecSmrg		    bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
93405b261ecSmrg	        }
93505b261ecSmrg	    } else {
93605b261ecSmrg	        if ((rule= XkbRF_AddRule(rules))!=NULL) {
93705b261ecSmrg		    *rule= trule;
93805b261ecSmrg		    bzero((char *)&trule,sizeof(XkbRF_RuleRec));
93905b261ecSmrg	        }
94005b261ecSmrg	    }
94105b261ecSmrg	}
94205b261ecSmrg	line.num_line= 0;
94305b261ecSmrg    }
94405b261ecSmrg    FreeInputLine(&line);
94505b261ecSmrg    return True;
94605b261ecSmrg}
94705b261ecSmrg
94805b261ecSmrgBool
94905b261ecSmrgXkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules)
95005b261ecSmrg{
95105b261ecSmrgFILE *		file;
95205b261ecSmrgchar		buf[PATH_MAX];
95305b261ecSmrgBool		ok;
95405b261ecSmrg
95505b261ecSmrg    if ((!base)||(!rules))
95605b261ecSmrg	return False;
95705b261ecSmrg    if (locale) {
95805b261ecSmrg	if (strlen(base)+strlen(locale)+2 > PATH_MAX)
95905b261ecSmrg	    return False;
96005b261ecSmrg	sprintf(buf,"%s-%s", base, locale);
96105b261ecSmrg    }
96205b261ecSmrg    else {
96305b261ecSmrg	if (strlen(base)+1 > PATH_MAX)
96405b261ecSmrg	    return False;
96505b261ecSmrg	strcpy(buf,base);
96605b261ecSmrg    }
96705b261ecSmrg
96805b261ecSmrg    file= fopen(buf, "r");
96905b261ecSmrg    if ((!file)&&(locale)) { /* fallback if locale was specified */
97005b261ecSmrg	strcpy(buf,base);
97105b261ecSmrg	file= fopen(buf, "r");
97205b261ecSmrg    }
97305b261ecSmrg    if (!file)
97405b261ecSmrg	return False;
97505b261ecSmrg    ok= XkbRF_LoadRules(file,rules);
97605b261ecSmrg    fclose(file);
97705b261ecSmrg    return ok;
97805b261ecSmrg}
97905b261ecSmrg
98005b261ecSmrg/***====================================================================***/
98105b261ecSmrg
98205b261ecSmrg#define HEAD_NONE	0
98305b261ecSmrg#define HEAD_MODEL	1
98405b261ecSmrg#define HEAD_LAYOUT	2
98505b261ecSmrg#define HEAD_VARIANT	3
98605b261ecSmrg#define HEAD_OPTION	4
98705b261ecSmrg#define	HEAD_EXTRA	5
98805b261ecSmrg
98905b261ecSmrgXkbRF_VarDescPtr
99005b261ecSmrgXkbRF_AddVarDesc(XkbRF_DescribeVarsPtr	vars)
99105b261ecSmrg{
99205b261ecSmrg    if (vars->sz_desc<1) {
99305b261ecSmrg	vars->sz_desc= 16;
99405b261ecSmrg	vars->num_desc= 0;
99505b261ecSmrg	vars->desc= _XkbTypedCalloc(vars->sz_desc,XkbRF_VarDescRec);
99605b261ecSmrg    }
99705b261ecSmrg    else if (vars->num_desc>=vars->sz_desc) {
99805b261ecSmrg	vars->sz_desc*= 2;
99905b261ecSmrg	vars->desc= _XkbTypedRealloc(vars->desc,vars->sz_desc,XkbRF_VarDescRec);
100005b261ecSmrg    }
100105b261ecSmrg    if (!vars->desc) {
100205b261ecSmrg	vars->sz_desc= vars->num_desc= 0;
10034642e01fSmrg	DebugF("Allocation failure in XkbRF_AddVarDesc\n");
100405b261ecSmrg	return NULL;
100505b261ecSmrg    }
100605b261ecSmrg    vars->desc[vars->num_desc].name= NULL;
100705b261ecSmrg    vars->desc[vars->num_desc].desc= NULL;
100805b261ecSmrg    return &vars->desc[vars->num_desc++];
100905b261ecSmrg}
101005b261ecSmrg
101105b261ecSmrgXkbRF_VarDescPtr
101205b261ecSmrgXkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from)
101305b261ecSmrg{
101405b261ecSmrgXkbRF_VarDescPtr	nd;
101505b261ecSmrg
101605b261ecSmrg    if ((nd=XkbRF_AddVarDesc(vars))!=NULL) {
101705b261ecSmrg	nd->name= _XkbDupString(from->name);
101805b261ecSmrg	nd->desc= _XkbDupString(from->desc);
101905b261ecSmrg    }
102005b261ecSmrg    return nd;
102105b261ecSmrg}
102205b261ecSmrg
102305b261ecSmrgXkbRF_DescribeVarsPtr
102405b261ecSmrgXkbRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name)
102505b261ecSmrg{
102605b261ecSmrg    if (rules->sz_extra<1) {
102705b261ecSmrg	rules->num_extra= 0;
102805b261ecSmrg	rules->sz_extra= 1;
102905b261ecSmrg	rules->extra_names= _XkbTypedCalloc(rules->sz_extra,char *);
103005b261ecSmrg	rules->extra= _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
103105b261ecSmrg    }
103205b261ecSmrg    else if (rules->num_extra>=rules->sz_extra) {
103305b261ecSmrg	rules->sz_extra*= 2;
103405b261ecSmrg	rules->extra_names= _XkbTypedRealloc(rules->extra_names,rules->sz_extra,
103505b261ecSmrg								char *);
103605b261ecSmrg	rules->extra=_XkbTypedRealloc(rules->extra, rules->sz_extra,
103705b261ecSmrg							XkbRF_DescribeVarsRec);
103805b261ecSmrg    }
103905b261ecSmrg    if ((!rules->extra_names)||(!rules->extra)) {
10404642e01fSmrg	DebugF("allocation error in extra parts\n");
104105b261ecSmrg	rules->sz_extra= rules->num_extra= 0;
104205b261ecSmrg	rules->extra_names= NULL;
104305b261ecSmrg	rules->extra= NULL;
104405b261ecSmrg	return NULL;
104505b261ecSmrg    }
104605b261ecSmrg    rules->extra_names[rules->num_extra]= _XkbDupString(name);
104705b261ecSmrg    bzero(&rules->extra[rules->num_extra],sizeof(XkbRF_DescribeVarsRec));
104805b261ecSmrg    return &rules->extra[rules->num_extra++];
104905b261ecSmrg}
105005b261ecSmrg
105105b261ecSmrgBool
105205b261ecSmrgXkbRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules)
105305b261ecSmrg{
105405b261ecSmrgInputLine		line;
105505b261ecSmrgXkbRF_VarDescRec	tmp;
105605b261ecSmrgchar			*tok;
105705b261ecSmrgint			len,headingtype,extra_ndx = 0;
105805b261ecSmrg
105905b261ecSmrg    bzero((char *)&tmp, sizeof(XkbRF_VarDescRec));
106005b261ecSmrg    headingtype = HEAD_NONE;
106105b261ecSmrg    InitInputLine(&line);
106205b261ecSmrg    for ( ; GetInputLine(file,&line,False); line.num_line= 0) {
106305b261ecSmrg	if (line.line[0]=='!') {
106405b261ecSmrg	    tok = strtok(&(line.line[1]), " \t");
106505b261ecSmrg	    if (strcasecmp(tok,"model") == 0)
106605b261ecSmrg		headingtype = HEAD_MODEL;
106705b261ecSmrg	    else if (strcasecmp(tok,"layout") == 0)
106805b261ecSmrg		headingtype = HEAD_LAYOUT;
106905b261ecSmrg	    else if (strcasecmp(tok,"variant") == 0)
107005b261ecSmrg		headingtype = HEAD_VARIANT;
107105b261ecSmrg	    else if (strcasecmp(tok,"option") == 0)
107205b261ecSmrg		headingtype = HEAD_OPTION;
107305b261ecSmrg	    else {
107405b261ecSmrg		int i;
107505b261ecSmrg		headingtype = HEAD_EXTRA;
107605b261ecSmrg		extra_ndx= -1;
107705b261ecSmrg		for (i=0;(i<rules->num_extra)&&(extra_ndx<0);i++) {
107805b261ecSmrg		    if (!strcasecmp(tok,rules->extra_names[i]))
107905b261ecSmrg			extra_ndx= i;
108005b261ecSmrg		}
108105b261ecSmrg		if (extra_ndx<0) {
108205b261ecSmrg		    XkbRF_DescribeVarsPtr	var;
10834642e01fSmrg		    DebugF("Extra heading \"%s\" encountered\n",tok);
108405b261ecSmrg		    var= XkbRF_AddVarToDescribe(rules,tok);
108505b261ecSmrg		    if (var)
108605b261ecSmrg			 extra_ndx= var-rules->extra;
108705b261ecSmrg		    else headingtype= HEAD_NONE;
108805b261ecSmrg		}
108905b261ecSmrg	    }
109005b261ecSmrg	    continue;
109105b261ecSmrg	}
109205b261ecSmrg
109305b261ecSmrg	if (headingtype == HEAD_NONE) {
10944642e01fSmrg	    DebugF("Must have a heading before first line of data\n");
10954642e01fSmrg	    DebugF("Illegal line of data ignored\n");
109605b261ecSmrg	    continue;
109705b261ecSmrg	}
109805b261ecSmrg
109905b261ecSmrg	len = strlen(line.line);
110005b261ecSmrg	if ((tmp.name= strtok(line.line, " \t")) == NULL) {
11014642e01fSmrg	    DebugF("Huh? No token on line\n");
11024642e01fSmrg	    DebugF("Illegal line of data ignored\n");
110305b261ecSmrg	    continue;
110405b261ecSmrg	}
110505b261ecSmrg	if (strlen(tmp.name) == len) {
11064642e01fSmrg	    DebugF("No description found\n");
11074642e01fSmrg	    DebugF("Illegal line of data ignored\n");
110805b261ecSmrg	    continue;
110905b261ecSmrg	}
111005b261ecSmrg
111105b261ecSmrg	tok = line.line + strlen(tmp.name) + 1;
111205b261ecSmrg	while ((*tok!='\n')&&isspace(*tok))
111305b261ecSmrg		tok++;
111405b261ecSmrg	if (*tok == '\0') {
11154642e01fSmrg	    DebugF("No description found\n");
11164642e01fSmrg	    DebugF("Illegal line of data ignored\n");
111705b261ecSmrg	    continue;
111805b261ecSmrg	}
111905b261ecSmrg	tmp.desc= tok;
112005b261ecSmrg	switch (headingtype) {
112105b261ecSmrg	    case HEAD_MODEL:
112205b261ecSmrg		XkbRF_AddVarDescCopy(&rules->models,&tmp);
112305b261ecSmrg		break;
112405b261ecSmrg	    case HEAD_LAYOUT:
112505b261ecSmrg		XkbRF_AddVarDescCopy(&rules->layouts,&tmp);
112605b261ecSmrg		break;
112705b261ecSmrg	    case HEAD_VARIANT:
112805b261ecSmrg		XkbRF_AddVarDescCopy(&rules->variants,&tmp);
112905b261ecSmrg		break;
113005b261ecSmrg	    case HEAD_OPTION:
113105b261ecSmrg		XkbRF_AddVarDescCopy(&rules->options,&tmp);
113205b261ecSmrg		break;
113305b261ecSmrg	    case HEAD_EXTRA:
113405b261ecSmrg		XkbRF_AddVarDescCopy(&rules->extra[extra_ndx],&tmp);
113505b261ecSmrg		break;
113605b261ecSmrg	}
113705b261ecSmrg    }
113805b261ecSmrg    FreeInputLine(&line);
113905b261ecSmrg    if ((rules->models.num_desc==0) && (rules->layouts.num_desc==0) &&
114005b261ecSmrg	(rules->variants.num_desc==0) && (rules->options.num_desc==0) &&
114105b261ecSmrg	(rules->num_extra==0)) {
114205b261ecSmrg	return False;
114305b261ecSmrg    }
114405b261ecSmrg    return True;
114505b261ecSmrg}
114605b261ecSmrg
114705b261ecSmrgBool
114805b261ecSmrgXkbRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules)
114905b261ecSmrg{
115005b261ecSmrgFILE *		file;
115105b261ecSmrgchar		buf[PATH_MAX];
115205b261ecSmrgBool		ok;
115305b261ecSmrg
115405b261ecSmrg    if ((!base)||(!rules))
115505b261ecSmrg	return False;
115605b261ecSmrg    if (locale) {
115705b261ecSmrg	if (strlen(base)+strlen(locale)+6 > PATH_MAX)
115805b261ecSmrg	    return False;
115905b261ecSmrg	sprintf(buf,"%s-%s.lst", base, locale);
116005b261ecSmrg    }
116105b261ecSmrg    else {
116205b261ecSmrg	if (strlen(base)+5 > PATH_MAX)
116305b261ecSmrg	    return False;
116405b261ecSmrg	sprintf(buf,"%s.lst", base);
116505b261ecSmrg    }
116605b261ecSmrg
116705b261ecSmrg    file= fopen(buf, "r");
116805b261ecSmrg    if ((!file)&&(locale)) { /* fallback if locale was specified */
116905b261ecSmrg	sprintf(buf,"%s.lst", base);
117005b261ecSmrg
117105b261ecSmrg	file= fopen(buf, "r");
117205b261ecSmrg    }
117305b261ecSmrg    if (!file)
117405b261ecSmrg	return False;
117505b261ecSmrg    ok= XkbRF_LoadDescriptions(file,rules);
117605b261ecSmrg    fclose(file);
117705b261ecSmrg    return ok;
117805b261ecSmrg}
117905b261ecSmrg
118005b261ecSmrg/***====================================================================***/
118105b261ecSmrg
118205b261ecSmrgXkbRF_RulesPtr
118305b261ecSmrgXkbRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules)
118405b261ecSmrg{
118505b261ecSmrgXkbRF_RulesPtr	rules;
118605b261ecSmrg
118705b261ecSmrg    if ((!base)||((!wantDesc)&&(!wantRules)))
118805b261ecSmrg	return NULL;
118905b261ecSmrg    if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
119005b261ecSmrg	return NULL;
119105b261ecSmrg    if (wantDesc&&(!XkbRF_LoadDescriptionsByName(base,locale,rules))) {
119205b261ecSmrg	XkbRF_Free(rules,True);
119305b261ecSmrg	return NULL;
119405b261ecSmrg    }
119505b261ecSmrg    if (wantRules&&(!XkbRF_LoadRulesByName(base,locale,rules))) {
119605b261ecSmrg	XkbRF_Free(rules,True);
119705b261ecSmrg	return NULL;
119805b261ecSmrg    }
119905b261ecSmrg    return rules;
120005b261ecSmrg}
120105b261ecSmrg
120205b261ecSmrgXkbRF_RulesPtr
120305b261ecSmrgXkbRF_Create(int szRules,int szExtra)
120405b261ecSmrg{
120505b261ecSmrgXkbRF_RulesPtr rules;
120605b261ecSmrg
120705b261ecSmrg    if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
120805b261ecSmrg	return NULL;
120905b261ecSmrg    if (szRules>0) {
121005b261ecSmrg	rules->sz_rules= szRules;
121105b261ecSmrg	rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
121205b261ecSmrg	if (!rules->rules) {
121305b261ecSmrg	    _XkbFree(rules);
121405b261ecSmrg	    return NULL;
121505b261ecSmrg	}
121605b261ecSmrg    }
121705b261ecSmrg    if (szExtra>0) {
121805b261ecSmrg	rules->sz_extra= szExtra;
121905b261ecSmrg	rules->extra= _XkbTypedCalloc(rules->sz_extra,XkbRF_DescribeVarsRec);
122005b261ecSmrg	if (!rules->extra) {
122105b261ecSmrg	    if (rules->rules)
122205b261ecSmrg		_XkbFree(rules->rules);
122305b261ecSmrg	    _XkbFree(rules);
122405b261ecSmrg	    return NULL;
122505b261ecSmrg	}
122605b261ecSmrg    }
122705b261ecSmrg    return rules;
122805b261ecSmrg}
122905b261ecSmrg
123005b261ecSmrg/***====================================================================***/
123105b261ecSmrg
123205b261ecSmrgstatic void
123305b261ecSmrgXkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
123405b261ecSmrg{
123505b261ecSmrgregister int i;
123605b261ecSmrg
123705b261ecSmrg    for (i=0;i<var->num_desc;i++) {
123805b261ecSmrg	if (var->desc[i].name)
123905b261ecSmrg	    _XkbFree(var->desc[i].name);
124005b261ecSmrg	if (var->desc[i].desc)
124105b261ecSmrg	    _XkbFree(var->desc[i].desc);
124205b261ecSmrg	var->desc[i].name= var->desc[i].desc= NULL;
124305b261ecSmrg    }
124405b261ecSmrg    if (var->desc)
124505b261ecSmrg	_XkbFree(var->desc);
124605b261ecSmrg    var->desc= NULL;
124705b261ecSmrg    return;
124805b261ecSmrg}
124905b261ecSmrg
125005b261ecSmrgvoid
125105b261ecSmrgXkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
125205b261ecSmrg{
125305b261ecSmrgint		i;
125405b261ecSmrgXkbRF_RulePtr	rule;
125505b261ecSmrgXkbRF_GroupPtr	group;
125605b261ecSmrg
125705b261ecSmrg    if (!rules)
125805b261ecSmrg	return;
125905b261ecSmrg    XkbRF_ClearVarDescriptions(&rules->models);
126005b261ecSmrg    XkbRF_ClearVarDescriptions(&rules->layouts);
126105b261ecSmrg    XkbRF_ClearVarDescriptions(&rules->variants);
126205b261ecSmrg    XkbRF_ClearVarDescriptions(&rules->options);
126305b261ecSmrg    if (rules->extra) {
126405b261ecSmrg	for (i = 0; i < rules->num_extra; i++) {
126505b261ecSmrg	    XkbRF_ClearVarDescriptions(&rules->extra[i]);
126605b261ecSmrg	}
126705b261ecSmrg	_XkbFree(rules->extra);
126805b261ecSmrg	rules->num_extra= rules->sz_extra= 0;
126905b261ecSmrg	rules->extra= NULL;
127005b261ecSmrg    }
127105b261ecSmrg    if (rules->rules) {
127205b261ecSmrg	for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
127305b261ecSmrg	    if (rule->model)	_XkbFree(rule->model);
127405b261ecSmrg	    if (rule->layout)	_XkbFree(rule->layout);
127505b261ecSmrg	    if (rule->variant)	_XkbFree(rule->variant);
127605b261ecSmrg	    if (rule->option)	_XkbFree(rule->option);
127705b261ecSmrg	    if (rule->keycodes)	_XkbFree(rule->keycodes);
127805b261ecSmrg	    if (rule->symbols)	_XkbFree(rule->symbols);
127905b261ecSmrg	    if (rule->types)	_XkbFree(rule->types);
128005b261ecSmrg	    if (rule->compat)	_XkbFree(rule->compat);
128105b261ecSmrg	    if (rule->geometry)	_XkbFree(rule->geometry);
128205b261ecSmrg	    bzero((char *)rule,sizeof(XkbRF_RuleRec));
128305b261ecSmrg	}
128405b261ecSmrg	_XkbFree(rules->rules);
128505b261ecSmrg	rules->num_rules= rules->sz_rules= 0;
128605b261ecSmrg	rules->rules= NULL;
128705b261ecSmrg    }
128805b261ecSmrg
128905b261ecSmrg    if (rules->groups) {
129005b261ecSmrg	for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
129105b261ecSmrg	    if (group->name)	_XkbFree(group->name);
129205b261ecSmrg	    if (group->words)	_XkbFree(group->words);
129305b261ecSmrg	}
129405b261ecSmrg	_XkbFree(rules->groups);
129505b261ecSmrg	rules->num_groups= 0;
129605b261ecSmrg	rules->groups= NULL;
129705b261ecSmrg    }
129805b261ecSmrg    if (freeRules)
129905b261ecSmrg	_XkbFree(rules);
130005b261ecSmrg    return;
130105b261ecSmrg}
1302