1333 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1333 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
| /* $Xorg: maprules.c,v 1.4 2000/08/17 19:46:43 cpqbld Exp $ */
 | |
| /************************************************************
 | |
|  Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc.
 | |
| 
 | |
|  Permission to use, copy, modify, and distribute this
 | |
|  software and its documentation for any purpose and without
 | |
|  fee is hereby granted, provided that the above copyright
 | |
|  notice appear in all copies and that both that copyright
 | |
|  notice and this permission notice appear in supporting
 | |
|  documentation, and that the name of Silicon Graphics not be 
 | |
|  used in advertising or publicity pertaining to distribution 
 | |
|  of the software without specific prior written permission.
 | |
|  Silicon Graphics makes no representation about the suitability 
 | |
|  of this software for any purpose. It is provided "as is"
 | |
|  without any express or implied warranty.
 | |
|  
 | |
|  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 
 | |
|  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 
 | |
|  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
 | |
|  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
 | |
|  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 
 | |
|  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
 | |
|  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
 | |
|  THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
|  ********************************************************/
 | |
| /* $XFree86: xc/lib/xkbfile/maprules.c,v 3.17 2002/11/26 01:43:25 dawes Exp $ */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <ctype.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #define X_INCLUDE_STRING_H
 | |
| #define XOS_USE_NO_LOCKING
 | |
| #include <X11/Xos_r.h>
 | |
| 
 | |
| #define NEED_EVENTS
 | |
| #include <X11/Xproto.h>
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xos.h>
 | |
| #include <X11/Xfuncs.h>
 | |
| #include <X11/Xatom.h>
 | |
| #include <X11/keysym.h>
 | |
| #include "misc.h"
 | |
| #include "inputstr.h"
 | |
| #include "dix.h"
 | |
| #include <X11/extensions/XKBstr.h>
 | |
| #define XKBSRV_NEED_FILE_FUNCS
 | |
| #include <X11/extensions/XKBsrv.h>
 | |
| 
 | |
| #ifdef DEBUG
 | |
| #define PR_DEBUG(s)		fprintf(stderr,s)
 | |
| #define PR_DEBUG1(s,a)		fprintf(stderr,s,a)
 | |
| #define PR_DEBUG2(s,a,b)	fprintf(stderr,s,a,b)
 | |
| #else
 | |
| #define PR_DEBUG(s)
 | |
| #define PR_DEBUG1(s,a)
 | |
| #define PR_DEBUG2(s,a,b)
 | |
| #endif
 | |
| 
 | |
| #ifdef NEED_STRCASECMP
 | |
| extern int _XkbStrCaseCmp(char *s1, char *s2);
 | |
| #else
 | |
| #define _XkbStrCaseCmp strcasecmp
 | |
| #endif
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| #define DFLT_LINE_SIZE	128
 | |
| 
 | |
| typedef struct {
 | |
| 	int	line_num;
 | |
| 	int	sz_line;
 | |
| 	int	num_line;
 | |
| 	char	buf[DFLT_LINE_SIZE];
 | |
| 	char *	line;
 | |
| } InputLine;
 | |
| 
 | |
| static void
 | |
| InitInputLine(InputLine *line)
 | |
| {
 | |
|     line->line_num= 1;
 | |
|     line->num_line= 0;
 | |
|     line->sz_line= DFLT_LINE_SIZE;
 | |
|     line->line=	line->buf;
 | |
|     return;
 | |
| }
 | |
| 
 | |
| static void
 | |
| FreeInputLine(InputLine *line)
 | |
| {
 | |
|     if (line->line!=line->buf)
 | |
| 	_XkbFree(line->line);
 | |
|     line->line_num= 1;
 | |
|     line->num_line= 0;
 | |
|     line->sz_line= DFLT_LINE_SIZE;
 | |
|     line->line= line->buf;
 | |
|     return;
 | |
| }
 | |
| 
 | |
| static int
 | |
| InputLineAddChar(InputLine *line,int ch)
 | |
| {
 | |
|     if (line->num_line>=line->sz_line) {
 | |
| 	if (line->line==line->buf) {
 | |
| 	    line->line= (char *)_XkbAlloc(line->sz_line*2);
 | |
| 	    memcpy(line->line,line->buf,line->sz_line);
 | |
| 	}
 | |
| 	else {
 | |
| 	    line->line=(char *)_XkbRealloc((char *)line->line,line->sz_line*2);
 | |
| 	}
 | |
| 	line->sz_line*= 2;
 | |
|     }
 | |
|     line->line[line->num_line++]= ch;
 | |
|     return ch;
 | |
| }
 | |
| 
 | |
| #define	ADD_CHAR(l,c)	((l)->num_line<(l)->sz_line?\
 | |
| 				(int)((l)->line[(l)->num_line++]= (c)):\
 | |
| 				InputLineAddChar(l,c))
 | |
| 
 | |
| static Bool
 | |
| GetInputLine(FILE *file,InputLine *line,Bool checkbang)
 | |
| {
 | |
| int	ch;
 | |
| Bool	endOfFile,spacePending,slashPending,inComment;
 | |
| 
 | |
|      endOfFile= False;
 | |
|      while ((!endOfFile)&&(line->num_line==0)) {
 | |
| 	spacePending= slashPending= inComment= False;
 | |
| 	while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
 | |
| 	    if (ch=='\\') {
 | |
| 		if ((ch=getc(file))==EOF)
 | |
| 		    break;
 | |
| 		if (ch=='\n') {
 | |
| 		    inComment= False;
 | |
| 		    ch= ' ';
 | |
| 		    line->line_num++;
 | |
| 		}
 | |
| 	    }
 | |
| 	    if (inComment)
 | |
| 		continue;
 | |
| 	    if (ch=='/') {
 | |
| 		if (slashPending) {
 | |
| 		    inComment= True;
 | |
| 		    slashPending= False;
 | |
| 		}
 | |
| 		else {
 | |
| 		    slashPending= True;
 | |
| 		}
 | |
| 		continue;
 | |
| 	    }
 | |
| 	    else if (slashPending) {
 | |
| 		if (spacePending) {
 | |
| 		    ADD_CHAR(line,' ');
 | |
| 		    spacePending= False;
 | |
| 		}
 | |
| 		ADD_CHAR(line,'/');
 | |
| 		slashPending= False;
 | |
| 	    }
 | |
| 	    if (isspace(ch)) {
 | |
| 		while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
 | |
| 		    ch= getc(file);
 | |
| 		}
 | |
| 		if (ch==EOF)
 | |
| 		    break;
 | |
| 		if ((ch!='\n')&&(line->num_line>0))
 | |
| 		    spacePending= True;
 | |
| 		ungetc(ch,file);
 | |
| 	    }
 | |
| 	    else {
 | |
| 		if (spacePending) {
 | |
| 		    ADD_CHAR(line,' ');
 | |
| 		    spacePending= False;
 | |
| 		}
 | |
| 		if (checkbang && ch=='!') {
 | |
| 		    if (line->num_line!=0) {
 | |
| 			PR_DEBUG("The '!' legal only at start of line\n");
 | |
| 			PR_DEBUG("Line containing '!' ignored\n");
 | |
| 			line->num_line= 0;
 | |
| 			inComment= 0;
 | |
| 			break;
 | |
| 		    }
 | |
| 
 | |
| 		}
 | |
| 		ADD_CHAR(line,ch);
 | |
| 	    }
 | |
| 	}
 | |
| 	if (ch==EOF)
 | |
| 	     endOfFile= True;
 | |
| /*	else line->num_line++;*/
 | |
|      }
 | |
|      if ((line->num_line==0)&&(endOfFile))
 | |
| 	return False;
 | |
|       ADD_CHAR(line,'\0');
 | |
|       return True;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| #define	MODEL		0
 | |
| #define	LAYOUT		1
 | |
| #define	VARIANT		2
 | |
| #define	OPTION		3
 | |
| #define	KEYCODES	4
 | |
| #define SYMBOLS		5
 | |
| #define	TYPES		6
 | |
| #define	COMPAT		7
 | |
| #define	GEOMETRY	8
 | |
| #define	KEYMAP		9
 | |
| #define	MAX_WORDS	10
 | |
| 
 | |
| #define	PART_MASK	0x000F
 | |
| #define	COMPONENT_MASK	0x03F0
 | |
| 
 | |
| static	char *	cname[MAX_WORDS] = {
 | |
| 	"model", "layout", "variant", "option", 
 | |
| 	"keycodes", "symbols", "types", "compat", "geometry", "keymap"
 | |
| };
 | |
| 
 | |
| typedef	struct _RemapSpec {
 | |
| 	int			number;
 | |
| 	int			num_remap;
 | |
| 	struct	{
 | |
| 		int	word;
 | |
| 		int	index;
 | |
|                 }		remap[MAX_WORDS];
 | |
| } RemapSpec;
 | |
| 
 | |
| typedef struct _FileSpec {
 | |
| 	char *			name[MAX_WORDS];
 | |
| 	struct _FileSpec *	pending;
 | |
| } FileSpec;
 | |
| 
 | |
| typedef struct {
 | |
| 	char *			model;
 | |
| 	char *			layout[XkbNumKbdGroups+1];
 | |
| 	char *			variant[XkbNumKbdGroups+1];
 | |
| 	char *			options;
 | |
| } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
 | |
| 
 | |
| #define NDX_BUFF_SIZE	4
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static char*
 | |
| get_index(char *str, int *ndx)
 | |
| {
 | |
|    char ndx_buf[NDX_BUFF_SIZE];
 | |
|    char *end;
 | |
| 
 | |
|    if (*str != '[') {
 | |
|        *ndx = 0;
 | |
|        return str;
 | |
|    }
 | |
|    str++;
 | |
|    end = strchr(str, ']');
 | |
|    if (end == NULL) {
 | |
|        *ndx = -1;
 | |
|        return str - 1;
 | |
|    }
 | |
|    if ( (end - str) >= NDX_BUFF_SIZE) {
 | |
|        *ndx = -1;
 | |
|        return end + 1;
 | |
|    }
 | |
|    strncpy(ndx_buf, str, end - str);
 | |
|    ndx_buf[end - str] = '\0';
 | |
|    *ndx = atoi(ndx_buf);
 | |
|    return end + 1;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetUpRemap(InputLine *line,RemapSpec *remap)
 | |
| {
 | |
| char *		tok,*str;
 | |
| unsigned	present, l_ndx_present, v_ndx_present;
 | |
| register int	i;
 | |
| int		len, ndx;
 | |
| _Xstrtokparams	strtok_buf;
 | |
| #ifdef DEBUG
 | |
| Bool		found;
 | |
| #endif
 | |
| 
 | |
| 
 | |
|    l_ndx_present = v_ndx_present = present= 0;
 | |
|    str= &line->line[1];
 | |
|    len = remap->number;
 | |
|    bzero((char *)remap,sizeof(RemapSpec));
 | |
|    remap->number = len;
 | |
|    while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
 | |
| #ifdef DEBUG
 | |
| 	found= False;
 | |
| #endif
 | |
| 	str= NULL;
 | |
| 	if (strcmp(tok,"=")==0)
 | |
| 	    continue;
 | |
| 	for (i=0;i<MAX_WORDS;i++) {
 | |
|             len = strlen(cname[i]);
 | |
| 	    if (strncmp(cname[i],tok,len)==0) {
 | |
| 		if(strlen(tok) > len) {
 | |
| 		    char *end = get_index(tok+len, &ndx);
 | |
| 		    if ((i != LAYOUT && i != VARIANT) ||
 | |
| 			*end != '\0' || ndx == -1)
 | |
| 		        break;
 | |
| 		     if (ndx < 1 || ndx > XkbNumKbdGroups) {
 | |
| 		        PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
 | |
| 		        PR_DEBUG1("Index must be in range 1..%d\n",
 | |
| 				   XkbNumKbdGroups);
 | |
| 			break;
 | |
| 		     }
 | |
|                 } else {
 | |
| 		    ndx = 0;
 | |
|                 }
 | |
| #ifdef DEBUG
 | |
| 		found= True;
 | |
| #endif
 | |
| 		if (present&(1<<i)) {
 | |
| 		    if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
 | |
| 			(i == VARIANT && v_ndx_present&(1<<ndx)) ) {
 | |
| 		        PR_DEBUG1("Component \"%s\" listed twice\n",tok);
 | |
| 		        PR_DEBUG("Second definition ignored\n");
 | |
| 		        break;
 | |
| 		    }
 | |
| 		}
 | |
| 		present |= (1<<i);
 | |
|                 if (i == LAYOUT)
 | |
|                     l_ndx_present |= 1 << ndx;
 | |
|                 if (i == VARIANT)
 | |
|                     v_ndx_present |= 1 << ndx;
 | |
| 		remap->remap[remap->num_remap].word= i;
 | |
| 		remap->remap[remap->num_remap++].index= ndx;
 | |
| 		break;
 | |
| 	    }
 | |
| 	}
 | |
| #ifdef DEBUG
 | |
| 	if (!found) {
 | |
| 	    fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
 | |
| 	}
 | |
| #endif
 | |
|    }
 | |
|    if ((present&PART_MASK)==0) {
 | |
| #ifdef DEBUG
 | |
| 	unsigned mask= PART_MASK;
 | |
| 	fprintf(stderr,"Mapping needs at least one of ");
 | |
| 	for (i=0; (i<MAX_WORDS); i++) {
 | |
| 	    if ((1L<<i)&mask) {
 | |
| 		mask&= ~(1L<<i);
 | |
| 		if (mask)	fprintf(stderr,"\"%s,\" ",cname[i]);
 | |
| 		else		fprintf(stderr,"or \"%s\"\n",cname[i]);
 | |
| 	    }
 | |
| 	}
 | |
| 	fprintf(stderr,"Illegal mapping ignored\n");
 | |
| #endif
 | |
| 	remap->num_remap= 0;
 | |
| 	return;
 | |
|    }
 | |
|    if ((present&COMPONENT_MASK)==0) {
 | |
| 	PR_DEBUG("Mapping needs at least one component\n");
 | |
| 	PR_DEBUG("Illegal mapping ignored\n");
 | |
| 	remap->num_remap= 0;
 | |
| 	return;
 | |
|    }
 | |
|    if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
 | |
| 				((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
 | |
| 	PR_DEBUG("Keymap cannot appear with other components\n");
 | |
| 	PR_DEBUG("Illegal mapping ignored\n");
 | |
| 	remap->num_remap= 0;
 | |
| 	return;
 | |
|    }
 | |
|    remap->number++;
 | |
|    return;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| MatchOneOf(char *wanted,char *vals_defined)
 | |
| {
 | |
| char	*str,*next;
 | |
| int	want_len= strlen(wanted);
 | |
| 
 | |
|     for (str=vals_defined,next=NULL;str!=NULL;str=next) {
 | |
| 	int len;
 | |
| 	next= strchr(str,',');
 | |
| 	if (next) {
 | |
| 	    len= next-str;
 | |
| 	    next++;
 | |
| 	}
 | |
| 	else {
 | |
| 	    len= strlen(str);
 | |
| 	}
 | |
| 	if ((len==want_len)&&(strncmp(wanted,str,len)==0))
 | |
| 	    return True;
 | |
|     }
 | |
|     return False;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static Bool
 | |
| CheckLine(	InputLine *		line,
 | |
| 		RemapSpec *		remap,
 | |
| 		XkbRF_RulePtr		rule,
 | |
| 		XkbRF_GroupPtr		group)
 | |
| {
 | |
| char *		str,*tok;
 | |
| register int	nread, i;
 | |
| FileSpec	tmp;
 | |
| _Xstrtokparams	strtok_buf;
 | |
| Bool 		append = False;
 | |
| 
 | |
|     if (line->line[0]=='!') {
 | |
|         if (line->line[1] == '$' ||
 | |
|             (line->line[1] == ' ' && line->line[2] == '$')) {
 | |
|             char *gname = strchr(line->line, '$');
 | |
|             char *words = strchr(gname, ' ');
 | |
|             if(!words)
 | |
|                 return False;
 | |
|             *words++ = '\0';
 | |
|             for (; *words; words++) {
 | |
|                 if (*words != '=' && *words != ' ')
 | |
|                     break;
 | |
|             }
 | |
|             if (*words == '\0')
 | |
|                 return False;
 | |
|             group->name = _XkbDupString(gname);
 | |
|             group->words = _XkbDupString(words);
 | |
|             for (i = 1, words = group->words; *words; words++) {
 | |
|                  if ( *words == ' ') {
 | |
|                      *words++ = '\0';
 | |
|                      i++;
 | |
|                  }
 | |
|             }
 | |
|             group->number = i;
 | |
|             return True;
 | |
|         } else {
 | |
| 	    SetUpRemap(line,remap);
 | |
| 	    return False;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (remap->num_remap==0) {
 | |
| 	PR_DEBUG("Must have a mapping before first line of data\n");
 | |
| 	PR_DEBUG("Illegal line of data ignored\n");
 | |
| 	return False;
 | |
|     }
 | |
|     bzero((char *)&tmp,sizeof(FileSpec));
 | |
|     str= line->line;
 | |
|     for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
 | |
| 	str= NULL;
 | |
| 	if (strcmp(tok,"=")==0) {
 | |
| 	    nread--;
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (nread>remap->num_remap) {
 | |
| 	    PR_DEBUG("Too many words on a line\n");
 | |
| 	    PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
 | |
| 	    continue;
 | |
| 	}
 | |
| 	tmp.name[remap->remap[nread].word]= tok;
 | |
| 	if (*tok == '+' || *tok == '|')
 | |
| 	    append = True;
 | |
|     }
 | |
|     if (nread<remap->num_remap) {
 | |
| 	PR_DEBUG1("Too few words on a line: %s\n", line->line);
 | |
| 	PR_DEBUG("line ignored\n");
 | |
| 	return False;
 | |
|     }
 | |
| 
 | |
|     rule->flags= 0;
 | |
|     rule->number = remap->number;
 | |
|     if (tmp.name[OPTION])
 | |
| 	 rule->flags|= XkbRF_Option;
 | |
|     else if (append)
 | |
| 	 rule->flags|= XkbRF_Append;
 | |
|     else
 | |
| 	 rule->flags|= XkbRF_Normal;
 | |
|     rule->model= _XkbDupString(tmp.name[MODEL]);
 | |
|     rule->layout= _XkbDupString(tmp.name[LAYOUT]);
 | |
|     rule->variant= _XkbDupString(tmp.name[VARIANT]);
 | |
|     rule->option= _XkbDupString(tmp.name[OPTION]);
 | |
| 
 | |
|     rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
 | |
|     rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
 | |
|     rule->types= _XkbDupString(tmp.name[TYPES]);
 | |
|     rule->compat= _XkbDupString(tmp.name[COMPAT]);
 | |
|     rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
 | |
|     rule->keymap= _XkbDupString(tmp.name[KEYMAP]);
 | |
| 
 | |
|     rule->layout_num = rule->variant_num = 0;
 | |
|     for (i = 0; i < nread; i++) {
 | |
|         if (remap->remap[i].index) {
 | |
| 	    if (remap->remap[i].word == LAYOUT)
 | |
| 	        rule->layout_num = remap->remap[i].index;
 | |
| 	    if (remap->remap[i].word == VARIANT)
 | |
| 	        rule->variant_num = remap->remap[i].index;
 | |
|         }
 | |
|     }
 | |
|     return True;
 | |
| }
 | |
| 
 | |
| static char *
 | |
| _Concat(char *str1,char *str2)
 | |
| {
 | |
| int len;
 | |
| 
 | |
|     if ((!str1)||(!str2))
 | |
| 	return str1;
 | |
|     len= strlen(str1)+strlen(str2)+1;
 | |
|     str1= _XkbTypedRealloc(str1,len,char);
 | |
|     if (str1)
 | |
| 	strcat(str1,str2);
 | |
|     return str1;
 | |
| }
 | |
| 
 | |
| static void
 | |
| squeeze_spaces(char *p1)
 | |
| {
 | |
|    char *p2;
 | |
|    for (p2 = p1; *p2; p2++) {
 | |
|        *p1 = *p2;
 | |
|        if (*p1 != ' ') p1++;
 | |
|    }
 | |
|    *p1 = '\0';
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
 | |
| {
 | |
| 
 | |
|    bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec));
 | |
|    mdefs->model = defs->model;
 | |
|    mdefs->options = _XkbDupString(defs->options);
 | |
|    if (mdefs->options) squeeze_spaces(mdefs->options); 
 | |
| 
 | |
|    if (defs->layout) {
 | |
|        if (!strchr(defs->layout, ',')) {
 | |
|            mdefs->layout[0] = defs->layout;
 | |
|        } else {
 | |
|            char *p;
 | |
|            int i;
 | |
|            mdefs->layout[1] = _XkbDupString(defs->layout);
 | |
| 	   if (mdefs->layout[1] == NULL)
 | |
| 	      return False;
 | |
|            squeeze_spaces(mdefs->layout[1]);
 | |
|            p = mdefs->layout[1];
 | |
|            for (i = 2; i <= XkbNumKbdGroups; i++) {
 | |
|               if ((p = strchr(p, ','))) {
 | |
|                  *p++ = '\0';
 | |
|                  mdefs->layout[i] = p;
 | |
|               } else {
 | |
|                  break;
 | |
|               }
 | |
|            }
 | |
|            if (p && (p = strchr(p, ',')))
 | |
|               *p = '\0';
 | |
|        }
 | |
|    }
 | |
| 
 | |
|    if (defs->variant) {
 | |
|        if (!strchr(defs->variant, ',')) {
 | |
|            mdefs->variant[0] = defs->variant;
 | |
|        } else {
 | |
|            char *p;
 | |
|            int i;
 | |
|            mdefs->variant[1] = _XkbDupString(defs->variant);
 | |
| 	   if (mdefs->variant[1] == NULL)
 | |
| 	      return False;
 | |
|            squeeze_spaces(mdefs->variant[1]);
 | |
|            p = mdefs->variant[1];
 | |
|            for (i = 2; i <= XkbNumKbdGroups; i++) {
 | |
|               if ((p = strchr(p, ','))) {
 | |
|                  *p++ = '\0';
 | |
|                  mdefs->variant[i] = p;
 | |
|               } else {
 | |
|                  break;
 | |
|               }
 | |
|            }
 | |
|            if (p && (p = strchr(p, ',')))
 | |
|               *p = '\0';
 | |
|        }
 | |
|    }
 | |
|    return True;
 | |
| }
 | |
| 
 | |
| static void
 | |
| FreeMultiDefs(XkbRF_MultiDefsPtr defs)
 | |
| {
 | |
|   if (defs->options) _XkbFree(defs->options);
 | |
|   if (defs->layout[1])  _XkbFree(defs->layout[1]);
 | |
|   if (defs->variant[1])  _XkbFree(defs->variant[1]);
 | |
| }
 | |
| 
 | |
| static void
 | |
| Apply(char *src, char **dst)
 | |
| {
 | |
|     if (src) {
 | |
|         if (*src == '+' || *src == '!') {
 | |
| 	    *dst= _Concat(*dst, src);
 | |
|         } else {
 | |
|             if (*dst == NULL)
 | |
| 	        *dst= _XkbDupString(src);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| XkbRF_ApplyRule(	XkbRF_RulePtr 		rule,
 | |
| 			XkbComponentNamesPtr	names)
 | |
| {
 | |
|     rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
 | |
| 
 | |
|     Apply(rule->keycodes, &names->keycodes);
 | |
|     Apply(rule->symbols,  &names->symbols);
 | |
|     Apply(rule->types,    &names->types);
 | |
|     Apply(rule->compat,   &names->compat);
 | |
|     Apply(rule->geometry, &names->geometry);
 | |
|     Apply(rule->keymap,   &names->keymap);
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| CheckGroup(	XkbRF_RulesPtr          rules,
 | |
| 		char * 			group_name,
 | |
| 		char * 			name)
 | |
| {
 | |
|    int i;
 | |
|    char *p;
 | |
|    XkbRF_GroupPtr group;
 | |
| 
 | |
|    for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
 | |
|        if (! strcmp(group->name, group_name)) {
 | |
|            break;
 | |
|        }
 | |
|    }
 | |
|    if (i == rules->num_groups)
 | |
|        return False;
 | |
|    for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
 | |
|        if (! strcmp(p, name)) {
 | |
|            return True;
 | |
|        }
 | |
|    }
 | |
|    return False;
 | |
| }
 | |
| 
 | |
| static int
 | |
| XkbRF_CheckApplyRule(	XkbRF_RulePtr 		rule,
 | |
| 			XkbRF_MultiDefsPtr	mdefs,
 | |
| 			XkbComponentNamesPtr	names,
 | |
| 			XkbRF_RulesPtr          rules)
 | |
| {
 | |
|     Bool pending = False;
 | |
| 
 | |
|     if (rule->model != NULL) {
 | |
|         if(mdefs->model == NULL)
 | |
|             return 0;
 | |
|         if (strcmp(rule->model, "*") == 0) {
 | |
|             pending = True;
 | |
|         } else {
 | |
|             if (rule->model[0] == '$') {
 | |
|                if (!CheckGroup(rules, rule->model, mdefs->model))
 | |
|                   return 0;
 | |
|             } else {
 | |
| 	       if (strcmp(rule->model, mdefs->model) != 0)
 | |
| 	          return 0;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     if (rule->option != NULL) {
 | |
| 	if (mdefs->options == NULL)
 | |
| 	    return 0;
 | |
| 	if ((!MatchOneOf(rule->option,mdefs->options)))
 | |
| 	    return 0;
 | |
|     }
 | |
| 
 | |
|     if (rule->layout != NULL) {
 | |
| 	if(mdefs->layout[rule->layout_num] == NULL ||
 | |
| 	   *mdefs->layout[rule->layout_num] == '\0')
 | |
| 	    return 0;
 | |
|         if (strcmp(rule->layout, "*") == 0) {
 | |
|             pending = True;
 | |
|         } else {
 | |
|             if (rule->layout[0] == '$') {
 | |
|                if (!CheckGroup(rules, rule->layout,
 | |
|                                mdefs->layout[rule->layout_num]))
 | |
|                   return 0;
 | |
| 	    } else {
 | |
| 	       if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
 | |
| 	           return 0;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     if (rule->variant != NULL) {
 | |
| 	if (mdefs->variant[rule->variant_num] == NULL ||
 | |
| 	    *mdefs->variant[rule->variant_num] == '\0')
 | |
| 	    return 0;
 | |
|         if (strcmp(rule->variant, "*") == 0) {
 | |
|             pending = True;
 | |
|         } else {
 | |
|             if (rule->variant[0] == '$') {
 | |
|                if (!CheckGroup(rules, rule->variant,
 | |
|                                mdefs->variant[rule->variant_num]))
 | |
|                   return 0;
 | |
|             } else {
 | |
| 	       if (strcmp(rule->variant,
 | |
|                           mdefs->variant[rule->variant_num]) != 0)
 | |
| 	           return 0;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     if (pending) {
 | |
|         rule->flags|= XkbRF_PendingMatch;
 | |
| 	return rule->number;
 | |
|     }
 | |
|     /* exact match, apply it now */
 | |
|     XkbRF_ApplyRule(rule,names);
 | |
|     return rule->number;
 | |
| }
 | |
| 
 | |
| static void
 | |
| XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
 | |
| {
 | |
| register int 	i;
 | |
| XkbRF_RulePtr	rule;
 | |
| 
 | |
|     for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
 | |
| 	rule->flags&= ~XkbRF_PendingMatch;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)
 | |
| {
 | |
| int		i;
 | |
| XkbRF_RulePtr	rule;
 | |
| 
 | |
|     for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
 | |
| 	if ((rule->flags&XkbRF_PendingMatch)==0)
 | |
| 	    continue;
 | |
| 	XkbRF_ApplyRule(rule,names);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| XkbRF_CheckApplyRules(	XkbRF_RulesPtr 		rules,
 | |
| 			XkbRF_MultiDefsPtr	mdefs,
 | |
| 			XkbComponentNamesPtr	names,
 | |
| 			int			flags)
 | |
| {
 | |
| int		i;
 | |
| XkbRF_RulePtr	rule;
 | |
| int		skip;
 | |
| 
 | |
|     for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
 | |
| 	if ((rule->flags & flags) != flags)
 | |
| 	    continue;
 | |
| 	skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
 | |
| 	if (skip && !(flags & XkbRF_Option)) {
 | |
| 	    for ( ;(i < rules->num_rules) && (rule->number == skip);
 | |
| 		  rule++, i++);
 | |
| 	    rule--; i--;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static char *
 | |
| XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
 | |
| {
 | |
| char 	*str, *outstr, *orig, *var;
 | |
| int	len, ndx;
 | |
| 
 | |
|     orig= name;
 | |
|     str= index(name,'%');
 | |
|     if (str==NULL)
 | |
| 	return name;
 | |
|     len= strlen(name);
 | |
|     while (str!=NULL) {
 | |
| 	char pfx= str[1];
 | |
| 	int   extra_len= 0;
 | |
| 	if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
 | |
| 	    extra_len= 1;
 | |
| 	    str++;
 | |
| 	}
 | |
| 	else if (pfx=='(') {
 | |
| 	    extra_len= 2;
 | |
| 	    str++;
 | |
| 	}
 | |
| 	var = str + 1;
 | |
| 	str = get_index(var + 1, &ndx);
 | |
| 	if (ndx == -1) {
 | |
| 	    str = index(str,'%');
 | |
| 	    continue;
 | |
|         }
 | |
| 	if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
 | |
| 	    len+= strlen(mdefs->layout[ndx])+extra_len;
 | |
| 	else if ((*var=='m')&&mdefs->model)
 | |
| 	    len+= strlen(mdefs->model)+extra_len;
 | |
| 	else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
 | |
| 	    len+= strlen(mdefs->variant[ndx])+extra_len;
 | |
| 	if ((pfx=='(')&&(*str==')')) {
 | |
| 	    str++;
 | |
| 	}
 | |
| 	str= index(&str[0],'%');
 | |
|     }
 | |
|     name= (char *)_XkbAlloc(len+1);
 | |
|     str= orig;
 | |
|     outstr= name;
 | |
|     while (*str!='\0') {
 | |
| 	if (str[0]=='%') {
 | |
| 	    char pfx,sfx;
 | |
| 	    str++;
 | |
| 	    pfx= str[0];
 | |
| 	    sfx= '\0';
 | |
| 	    if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
 | |
| 		str++;
 | |
| 	    }
 | |
| 	    else if (pfx=='(') {
 | |
| 		sfx= ')';
 | |
| 		str++;
 | |
| 	    }
 | |
| 	    else pfx= '\0';
 | |
| 
 | |
| 	    var = str;
 | |
| 	    str = get_index(var + 1, &ndx);
 | |
| 	    if (ndx == -1) {
 | |
| 	        continue;
 | |
|             }
 | |
| 	    if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
 | |
| 		if (pfx) *outstr++= pfx;
 | |
| 		strcpy(outstr,mdefs->layout[ndx]);
 | |
| 		outstr+= strlen(mdefs->layout[ndx]);
 | |
| 		if (sfx) *outstr++= sfx;
 | |
| 	    }
 | |
| 	    else if ((*var=='m')&&(mdefs->model)) {
 | |
| 		if (pfx) *outstr++= pfx;
 | |
| 		strcpy(outstr,mdefs->model);
 | |
| 		outstr+= strlen(mdefs->model);
 | |
| 		if (sfx) *outstr++= sfx;
 | |
| 	    }
 | |
| 	    else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
 | |
| 		if (pfx) *outstr++= pfx;
 | |
| 		strcpy(outstr,mdefs->variant[ndx]);
 | |
| 		outstr+= strlen(mdefs->variant[ndx]);
 | |
| 		if (sfx) *outstr++= sfx;
 | |
| 	    }
 | |
| 	    if ((pfx=='(')&&(*str==')'))
 | |
| 		str++;
 | |
| 	}
 | |
| 	else {
 | |
| 	    *outstr++= *str++;
 | |
| 	}
 | |
|     }
 | |
|     *outstr++= '\0';
 | |
|     if (orig!=name)
 | |
| 	_XkbFree(orig);
 | |
|     return name;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| Bool
 | |
| XkbRF_GetComponents(	XkbRF_RulesPtr		rules,
 | |
| 			XkbRF_VarDefsPtr	defs,
 | |
| 			XkbComponentNamesPtr	names)
 | |
| {
 | |
|     XkbRF_MultiDefsRec mdefs;
 | |
| 
 | |
|     MakeMultiDefs(&mdefs, defs);
 | |
| 
 | |
|     bzero((char *)names,sizeof(XkbComponentNamesRec));
 | |
|     XkbRF_ClearPartialMatches(rules);
 | |
|     XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
 | |
|     XkbRF_ApplyPartialMatches(rules, names);
 | |
|     XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
 | |
|     XkbRF_ApplyPartialMatches(rules, names);
 | |
|     XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
 | |
| 
 | |
|     if (names->keycodes)
 | |
| 	names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
 | |
|     if (names->symbols)	
 | |
| 	names->symbols=	XkbRF_SubstituteVars(names->symbols, &mdefs);
 | |
|     if (names->types)
 | |
| 	names->types= XkbRF_SubstituteVars(names->types, &mdefs);
 | |
|     if (names->compat)
 | |
| 	names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
 | |
|     if (names->geometry)
 | |
| 	names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
 | |
|     if (names->keymap)	
 | |
| 	names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
 | |
| 
 | |
|     FreeMultiDefs(&mdefs);
 | |
|     return (names->keycodes && names->symbols && names->types &&
 | |
| 		names->compat && names->geometry ) || names->keymap;
 | |
| }
 | |
| 
 | |
| XkbRF_RulePtr
 | |
| XkbRF_AddRule(XkbRF_RulesPtr	rules)
 | |
| {
 | |
|     if (rules->sz_rules<1) {
 | |
| 	rules->sz_rules= 16;
 | |
| 	rules->num_rules= 0;
 | |
| 	rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
 | |
|     }
 | |
|     else if (rules->num_rules>=rules->sz_rules) {
 | |
| 	rules->sz_rules*= 2;
 | |
| 	rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
 | |
| 							XkbRF_RuleRec);
 | |
|     }
 | |
|     if (!rules->rules) {
 | |
| 	rules->sz_rules= rules->num_rules= 0;
 | |
| #ifdef DEBUG
 | |
| 	fprintf(stderr,"Allocation failure in XkbRF_AddRule\n");
 | |
| #endif
 | |
| 	return NULL;
 | |
|     }
 | |
|     bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
 | |
|     return &rules->rules[rules->num_rules++];
 | |
| }
 | |
| 
 | |
| XkbRF_GroupPtr
 | |
| XkbRF_AddGroup(XkbRF_RulesPtr	rules)
 | |
| {
 | |
|     if (rules->sz_groups<1) {
 | |
| 	rules->sz_groups= 16;
 | |
| 	rules->num_groups= 0;
 | |
| 	rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
 | |
|     }
 | |
|     else if (rules->num_groups >= rules->sz_groups) {
 | |
| 	rules->sz_groups *= 2;
 | |
| 	rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
 | |
| 							XkbRF_GroupRec);
 | |
|     }
 | |
|     if (!rules->groups) {
 | |
| 	rules->sz_groups= rules->num_groups= 0;
 | |
| 	return NULL;
 | |
|     }
 | |
| 
 | |
|     bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
 | |
|     return &rules->groups[rules->num_groups++];
 | |
| }
 | |
| 
 | |
| Bool
 | |
| XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
 | |
| {
 | |
| InputLine	line;
 | |
| RemapSpec	remap;
 | |
| XkbRF_RuleRec	trule,*rule;
 | |
| XkbRF_GroupRec  tgroup,*group;
 | |
| 
 | |
|     if (!(rules && file))
 | |
| 	return False;
 | |
|     bzero((char *)&remap,sizeof(RemapSpec));
 | |
|     bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
 | |
|     InitInputLine(&line);
 | |
|     while (GetInputLine(file,&line,True)) {
 | |
| 	if (CheckLine(&line,&remap,&trule,&tgroup)) {
 | |
|             if (tgroup.number) {
 | |
| 	        if ((group= XkbRF_AddGroup(rules))!=NULL) {
 | |
| 		    *group= tgroup;
 | |
| 		    bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
 | |
| 	        }
 | |
| 	    } else {
 | |
| 	        if ((rule= XkbRF_AddRule(rules))!=NULL) {
 | |
| 		    *rule= trule;
 | |
| 		    bzero((char *)&trule,sizeof(XkbRF_RuleRec));
 | |
| 	        }
 | |
| 	    }
 | |
| 	}
 | |
| 	line.num_line= 0;
 | |
|     }
 | |
|     FreeInputLine(&line);
 | |
|     return True;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules)
 | |
| {
 | |
| FILE *		file;
 | |
| char		buf[PATH_MAX];
 | |
| Bool		ok;
 | |
| 
 | |
|     if ((!base)||(!rules))
 | |
| 	return False;
 | |
|     if (locale) {
 | |
| 	if (strlen(base)+strlen(locale)+2 > PATH_MAX)
 | |
| 	    return False;
 | |
| 	sprintf(buf,"%s-%s", base, locale);
 | |
|     }
 | |
|     else {
 | |
| 	if (strlen(base)+1 > PATH_MAX)
 | |
| 	    return False;
 | |
| 	strcpy(buf,base);
 | |
|     }
 | |
| 
 | |
|     file= fopen(buf, "r");
 | |
|     if ((!file)&&(locale)) { /* fallback if locale was specified */
 | |
| 	strcpy(buf,base);
 | |
| 	file= fopen(buf, "r");
 | |
|     }
 | |
|     if (!file)
 | |
| 	return False;
 | |
|     ok= XkbRF_LoadRules(file,rules);
 | |
|     fclose(file);
 | |
|     return ok;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| #define HEAD_NONE	0
 | |
| #define HEAD_MODEL	1
 | |
| #define HEAD_LAYOUT	2
 | |
| #define HEAD_VARIANT	3
 | |
| #define HEAD_OPTION	4
 | |
| #define	HEAD_EXTRA	5
 | |
| 
 | |
| XkbRF_VarDescPtr
 | |
| XkbRF_AddVarDesc(XkbRF_DescribeVarsPtr	vars)
 | |
| {
 | |
|     if (vars->sz_desc<1) {
 | |
| 	vars->sz_desc= 16;
 | |
| 	vars->num_desc= 0;
 | |
| 	vars->desc= _XkbTypedCalloc(vars->sz_desc,XkbRF_VarDescRec);
 | |
|     }
 | |
|     else if (vars->num_desc>=vars->sz_desc) {
 | |
| 	vars->sz_desc*= 2;
 | |
| 	vars->desc= _XkbTypedRealloc(vars->desc,vars->sz_desc,XkbRF_VarDescRec);
 | |
|     }
 | |
|     if (!vars->desc) {
 | |
| 	vars->sz_desc= vars->num_desc= 0;
 | |
| 	PR_DEBUG("Allocation failure in XkbRF_AddVarDesc\n");
 | |
| 	return NULL;
 | |
|     }
 | |
|     vars->desc[vars->num_desc].name= NULL;
 | |
|     vars->desc[vars->num_desc].desc= NULL;
 | |
|     return &vars->desc[vars->num_desc++];
 | |
| }
 | |
| 
 | |
| XkbRF_VarDescPtr
 | |
| XkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from)
 | |
| {
 | |
| XkbRF_VarDescPtr	nd;
 | |
| 
 | |
|     if ((nd=XkbRF_AddVarDesc(vars))!=NULL) {
 | |
| 	nd->name= _XkbDupString(from->name);
 | |
| 	nd->desc= _XkbDupString(from->desc);
 | |
|     }
 | |
|     return nd;
 | |
| }
 | |
| 
 | |
| XkbRF_DescribeVarsPtr 
 | |
| XkbRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name)
 | |
| {
 | |
|     if (rules->sz_extra<1) {
 | |
| 	rules->num_extra= 0;
 | |
| 	rules->sz_extra= 1;
 | |
| 	rules->extra_names= _XkbTypedCalloc(rules->sz_extra,char *);
 | |
| 	rules->extra= _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
 | |
|     }
 | |
|     else if (rules->num_extra>=rules->sz_extra) {
 | |
| 	rules->sz_extra*= 2;
 | |
| 	rules->extra_names= _XkbTypedRealloc(rules->extra_names,rules->sz_extra,
 | |
| 								char *);
 | |
| 	rules->extra=_XkbTypedRealloc(rules->extra, rules->sz_extra,
 | |
| 							XkbRF_DescribeVarsRec);
 | |
|     }
 | |
|     if ((!rules->extra_names)||(!rules->extra)) {
 | |
| 	PR_DEBUG("allocation error in extra parts\n");
 | |
| 	rules->sz_extra= rules->num_extra= 0;
 | |
| 	rules->extra_names= NULL;
 | |
| 	rules->extra= NULL;
 | |
| 	return NULL;
 | |
|     }
 | |
|     rules->extra_names[rules->num_extra]= _XkbDupString(name);
 | |
|     bzero(&rules->extra[rules->num_extra],sizeof(XkbRF_DescribeVarsRec));
 | |
|     return &rules->extra[rules->num_extra++];
 | |
| }
 | |
| 
 | |
| Bool
 | |
| XkbRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules)
 | |
| {
 | |
| InputLine		line;
 | |
| XkbRF_VarDescRec	tmp;
 | |
| char			*tok;
 | |
| int			len,headingtype,extra_ndx = 0;
 | |
| 
 | |
|     bzero((char *)&tmp, sizeof(XkbRF_VarDescRec));
 | |
|     headingtype = HEAD_NONE;
 | |
|     InitInputLine(&line);
 | |
|     for ( ; GetInputLine(file,&line,False); line.num_line= 0) {
 | |
| 	if (line.line[0]=='!') {
 | |
| 	    tok = strtok(&(line.line[1]), " \t");
 | |
| 	    if (_XkbStrCaseCmp(tolower(tok),"model") == 0)
 | |
| 		headingtype = HEAD_MODEL;
 | |
| 	    else if (_XkbStrCaseCmp(tok,"layout") == 0)
 | |
| 		headingtype = HEAD_LAYOUT;
 | |
| 	    else if (_XkbStrCaseCmp(tok,"variant") == 0)
 | |
| 		headingtype = HEAD_VARIANT;
 | |
| 	    else if (_XkbStrCaseCmp(tok,"option") == 0)
 | |
| 		headingtype = HEAD_OPTION;
 | |
| 	    else {
 | |
| 		int i;
 | |
| 		headingtype = HEAD_EXTRA;
 | |
| 		extra_ndx= -1;
 | |
| 		for (i=0;(i<rules->num_extra)&&(extra_ndx<0);i++) {
 | |
| 		    if (!_XkbStrCaseCmp(tok,rules->extra_names[i]))
 | |
| 			extra_ndx= i;
 | |
| 		}
 | |
| 		if (extra_ndx<0) {
 | |
| 		    XkbRF_DescribeVarsPtr	var;
 | |
| 		    PR_DEBUG1("Extra heading \"%s\" encountered\n",tok);
 | |
| 		    var= XkbRF_AddVarToDescribe(rules,tok);
 | |
| 		    if (var)
 | |
| 			 extra_ndx= var-rules->extra;
 | |
| 		    else headingtype= HEAD_NONE;
 | |
| 		}
 | |
| 	    }
 | |
| 	    continue;
 | |
| 	}
 | |
| 
 | |
| 	if (headingtype == HEAD_NONE) {
 | |
| 	    PR_DEBUG("Must have a heading before first line of data\n");
 | |
| 	    PR_DEBUG("Illegal line of data ignored\n");
 | |
| 	    continue;
 | |
| 	}
 | |
| 
 | |
| 	len = strlen(line.line);
 | |
| 	if ((tmp.name= strtok(line.line, " \t")) == NULL) {
 | |
| 	    PR_DEBUG("Huh? No token on line\n");
 | |
| 	    PR_DEBUG("Illegal line of data ignored\n");
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (strlen(tmp.name) == len) {
 | |
| 	    PR_DEBUG("No description found\n");
 | |
| 	    PR_DEBUG("Illegal line of data ignored\n");
 | |
| 	    continue;
 | |
| 	}
 | |
| 
 | |
| 	tok = line.line + strlen(tmp.name) + 1;
 | |
| 	while ((*tok!='\n')&&isspace(*tok))
 | |
| 		tok++;
 | |
| 	if (*tok == '\0') {
 | |
| 	    PR_DEBUG("No description found\n");
 | |
| 	    PR_DEBUG("Illegal line of data ignored\n");
 | |
| 	    continue;
 | |
| 	}
 | |
| 	tmp.desc= tok;
 | |
| 	switch (headingtype) {
 | |
| 	    case HEAD_MODEL:
 | |
| 		XkbRF_AddVarDescCopy(&rules->models,&tmp);
 | |
| 		break;
 | |
| 	    case HEAD_LAYOUT:
 | |
| 		XkbRF_AddVarDescCopy(&rules->layouts,&tmp);
 | |
| 		break;
 | |
| 	    case HEAD_VARIANT:
 | |
| 		XkbRF_AddVarDescCopy(&rules->variants,&tmp);
 | |
| 		break;
 | |
| 	    case HEAD_OPTION:
 | |
| 		XkbRF_AddVarDescCopy(&rules->options,&tmp);
 | |
| 		break;
 | |
| 	    case HEAD_EXTRA:
 | |
| 		XkbRF_AddVarDescCopy(&rules->extra[extra_ndx],&tmp);
 | |
| 		break;
 | |
| 	}
 | |
|     }
 | |
|     FreeInputLine(&line);
 | |
|     if ((rules->models.num_desc==0) && (rules->layouts.num_desc==0) &&
 | |
| 	(rules->variants.num_desc==0) && (rules->options.num_desc==0) &&
 | |
| 	(rules->num_extra==0)) {
 | |
| 	return False;
 | |
|     }
 | |
|     return True;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| XkbRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules)
 | |
| {
 | |
| FILE *		file;
 | |
| char		buf[PATH_MAX];
 | |
| Bool		ok;
 | |
| 
 | |
|     if ((!base)||(!rules))
 | |
| 	return False;
 | |
|     if (locale) {
 | |
| 	if (strlen(base)+strlen(locale)+6 > PATH_MAX)
 | |
| 	    return False;
 | |
| 	sprintf(buf,"%s-%s.lst", base, locale);
 | |
|     }
 | |
|     else {
 | |
| 	if (strlen(base)+5 > PATH_MAX)
 | |
| 	    return False;
 | |
| 	sprintf(buf,"%s.lst", base);
 | |
|     }
 | |
| 
 | |
|     file= fopen(buf, "r");
 | |
|     if ((!file)&&(locale)) { /* fallback if locale was specified */
 | |
| 	sprintf(buf,"%s.lst", base);
 | |
| 
 | |
| 	file= fopen(buf, "r");
 | |
|     }
 | |
|     if (!file)
 | |
| 	return False;
 | |
|     ok= XkbRF_LoadDescriptions(file,rules);
 | |
|     fclose(file);
 | |
|     return ok;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| XkbRF_RulesPtr
 | |
| XkbRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules)
 | |
| {
 | |
| XkbRF_RulesPtr	rules;
 | |
| 
 | |
|     if ((!base)||((!wantDesc)&&(!wantRules)))
 | |
| 	return NULL;
 | |
|     if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
 | |
| 	return NULL;
 | |
|     if (wantDesc&&(!XkbRF_LoadDescriptionsByName(base,locale,rules))) {
 | |
| 	XkbRF_Free(rules,True);
 | |
| 	return NULL;
 | |
|     }
 | |
|     if (wantRules&&(!XkbRF_LoadRulesByName(base,locale,rules))) {
 | |
| 	XkbRF_Free(rules,True);
 | |
| 	return NULL;
 | |
|     }
 | |
|     return rules;
 | |
| }
 | |
| 
 | |
| XkbRF_RulesPtr
 | |
| XkbRF_Create(int szRules,int szExtra) 
 | |
| {
 | |
| XkbRF_RulesPtr rules;
 | |
| 
 | |
|     if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
 | |
| 	return NULL;
 | |
|     if (szRules>0) {
 | |
| 	rules->sz_rules= szRules; 
 | |
| 	rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
 | |
| 	if (!rules->rules) {
 | |
| 	    _XkbFree(rules);
 | |
| 	    return NULL;
 | |
| 	}
 | |
|     }
 | |
|     if (szExtra>0) {
 | |
| 	rules->sz_extra= szExtra; 
 | |
| 	rules->extra= _XkbTypedCalloc(rules->sz_extra,XkbRF_DescribeVarsRec);
 | |
| 	if (!rules->extra) {
 | |
| 	    if (rules->rules)
 | |
| 		_XkbFree(rules->rules);
 | |
| 	    _XkbFree(rules);
 | |
| 	    return NULL;
 | |
| 	}
 | |
|     }
 | |
|     return rules;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static void
 | |
| XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
 | |
| {
 | |
| register int i;
 | |
|     
 | |
|     for (i=0;i<var->num_desc;i++) {
 | |
| 	if (var->desc[i].name)
 | |
| 	    _XkbFree(var->desc[i].name);
 | |
| 	if (var->desc[i].desc)
 | |
| 	    _XkbFree(var->desc[i].desc);
 | |
| 	var->desc[i].name= var->desc[i].desc= NULL;
 | |
|     }
 | |
|     if (var->desc)
 | |
| 	_XkbFree(var->desc);
 | |
|     var->desc= NULL;
 | |
|     return;
 | |
| }
 | |
| 
 | |
| void
 | |
| XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
 | |
| {
 | |
| int		i;
 | |
| XkbRF_RulePtr	rule;
 | |
| XkbRF_GroupPtr	group;
 | |
| 
 | |
|     if (!rules)
 | |
| 	return;
 | |
|     XkbRF_ClearVarDescriptions(&rules->models);
 | |
|     XkbRF_ClearVarDescriptions(&rules->layouts);
 | |
|     XkbRF_ClearVarDescriptions(&rules->variants);
 | |
|     XkbRF_ClearVarDescriptions(&rules->options);
 | |
|     if (rules->extra) {
 | |
| 	for (i = 0; i < rules->num_extra; i++) {
 | |
| 	    XkbRF_ClearVarDescriptions(&rules->extra[i]);
 | |
| 	}
 | |
| 	_XkbFree(rules->extra);
 | |
| 	rules->num_extra= rules->sz_extra= 0;
 | |
| 	rules->extra= NULL;
 | |
|     }
 | |
|     if (rules->rules) {
 | |
| 	for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
 | |
| 	    if (rule->model)	_XkbFree(rule->model);
 | |
| 	    if (rule->layout)	_XkbFree(rule->layout);
 | |
| 	    if (rule->variant)	_XkbFree(rule->variant);
 | |
| 	    if (rule->option)	_XkbFree(rule->option);
 | |
| 	    if (rule->keycodes)	_XkbFree(rule->keycodes);
 | |
| 	    if (rule->symbols)	_XkbFree(rule->symbols);
 | |
| 	    if (rule->types)	_XkbFree(rule->types);
 | |
| 	    if (rule->compat)	_XkbFree(rule->compat);
 | |
| 	    if (rule->geometry)	_XkbFree(rule->geometry);
 | |
| 	    if (rule->keymap)	_XkbFree(rule->keymap);
 | |
| 	    bzero((char *)rule,sizeof(XkbRF_RuleRec));
 | |
| 	}
 | |
| 	_XkbFree(rules->rules);
 | |
| 	rules->num_rules= rules->sz_rules= 0;
 | |
| 	rules->rules= NULL;
 | |
|     }
 | |
| 
 | |
|     if (rules->groups) {
 | |
| 	for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
 | |
| 	    if (group->name)	_XkbFree(group->name);
 | |
| 	    if (group->words)	_XkbFree(group->words);
 | |
| 	}
 | |
| 	_XkbFree(rules->groups);
 | |
| 	rules->num_groups= 0;
 | |
| 	rules->groups= NULL;
 | |
|     }
 | |
|     if (freeRules)
 | |
| 	_XkbFree(rules);
 | |
|     return;
 | |
| }
 |