diff options
Diffstat (limited to 'xkb/maprules.c')
-rw-r--r-- | xkb/maprules.c | 1382 |
1 files changed, 1382 insertions, 0 deletions
diff --git a/xkb/maprules.c b/xkb/maprules.c new file mode 100644 index 000000000..559dc9c7f --- /dev/null +++ b/xkb/maprules.c @@ -0,0 +1,1382 @@ +/* $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. + + ********************************************************/ + +#include <stdio.h> +#include <ctype.h> +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#endif + + +#define X_INCLUDE_STRING_H +#define XOS_USE_NO_LOCKING +#include <X11/Xos_r.h> + +#ifndef XKB_IN_SERVER + +#include <X11/Xproto.h> +#include <X11/Xlib.h> +#include <X11/Xos.h> +#include <X11/Xfuncs.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include <X11/XKBlib.h> +#include <X11/extensions/XKBgeom.h> +#include "XKMformat.h" +#include "XKBfileInt.h" +#include "XKBrules.h" + +#else + +#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 "XKBstr.h" +#define XKBSRV_NEED_FILE_FUNCS +#include "XKBsrv.h" + +#endif + +#ifdef DEBUG +#define PR_DEBUG(s) fprintf(stderr,s) +#define PR_DEBUG1(s,a) fprintf(stderr,s,a) +#else +#define PR_DEBUG(s) +#define PR_DEBUG1(s,a) +#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 +#if NeedFunctionPrototypes +InitInputLine(InputLine *line) +#else +InitInputLine(line) + InputLine * line; +#endif +{ + line->line_num= 1; + line->num_line= 0; + line->sz_line= DFLT_LINE_SIZE; + line->line= line->buf; + return; +} + +static void +#if NeedFunctionPrototypes +FreeInputLine(InputLine *line) +#else +FreeInputLine(line) + InputLine *line; +#endif +{ + 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 +#if NeedFunctionPrototypes +InputLineAddChar(InputLine *line,int ch) +#else +InputLineAddChar(line,ch) + InputLine * line; + int ch; +#endif +{ + 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 +#if NeedFunctionPrototypes +GetInputLine(FILE *file,InputLine *line,Bool checkbang) +#else +GetInputLine(file,line,checkbang) + FILE * file; + InputLine * line; + Bool checkbang; +#endif +{ +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 num_remap; + int remap[MAX_WORDS]; +} RemapSpec; + +typedef struct _FileSpec { + char * name[MAX_WORDS]; + struct _FileSpec * pending; +} FileSpec; + +/***====================================================================***/ + +static void +#if NeedFunctionPrototypes +SetUpRemap(InputLine *line,RemapSpec *remap) +#else +SetUpRemap(line,remap) + InputLine * line; + RemapSpec * remap; +#endif +{ +char * tok,*str; +unsigned present; +register int i; +#ifdef DEBUG +Bool found; +#endif +_Xstrtokparams strtok_buf; + + present= 0; + str= &line->line[1]; + bzero((char *)remap,sizeof(RemapSpec)); + 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++) { + if (strcmp(cname[i],tok)==0) { +#ifdef DEBUG + found= True; +#endif + if (present&(1<<i)) { + PR_DEBUG1("Component \"%s\" listed twice\n",tok); + PR_DEBUG("Second definition ignored\n"); + break; + } + present|= (1<<i); + remap->remap[remap->num_remap++]= i; + 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 one of "); + for (i=0;(i<MAX_WORDS)&mask;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&PART_MASK)&(1<<OPTION))&& + ((present&PART_MASK)!=(1<<OPTION))) { + PR_DEBUG("Options cannot appear with other parts\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; + } + return; +} + +static Bool +#if NeedFunctionPrototypes +MatchOneOf(char *wanted,char *vals_defined) +#else +MatchOneOf(wanted,vals_defined) + char * wanted; + char * vals_defined; +#endif +{ +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 +#if NeedFunctionPrototypes +CheckLine( InputLine * line, + RemapSpec * remap, + XkbRF_RulePtr rule) +#else +CheckLine(line,remap,rule) + InputLine * line; + RemapSpec * remap; + XkbRF_RulePtr rule; +#endif +{ +char * str,*tok; +register int nread; +FileSpec tmp; +_Xstrtokparams strtok_buf; + + if (line->line[0]=='!') { + 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]]= tok; + } + if (nread<remap->num_remap) { + PR_DEBUG("Too few words on a line\n"); + PR_DEBUG("line ignored\n"); + return False; + } + if ((tmp.name[MODEL]!=NULL)&&(strcmp(tmp.name[MODEL],"*")==0)) + tmp.name[MODEL]= NULL; + if ((tmp.name[LAYOUT]!=NULL)&&(strcmp(tmp.name[LAYOUT],"*")==0)) + tmp.name[LAYOUT]= NULL; + if ((tmp.name[VARIANT]!=NULL)&&(strcmp(tmp.name[VARIANT],"*")==0)) + tmp.name[VARIANT]= NULL; + + rule->flags= 0; + if (tmp.name[OPTION]) + rule->flags|= XkbRF_Delayed|XkbRF_Append; + 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]); + return True; +} + +static char * +#if NeedFunctionPrototypes +_Concat(char *str1,char *str2) +#else +_Concat(str1,str2) + char * str1; + char * str2; +#endif +{ +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; +} + +Bool +#if NeedFunctionPrototypes +XkbRF_ApplyRule( XkbRF_RulePtr rule, + XkbComponentNamesPtr names) +#else +XkbRF_ApplyRule(rule,names) + XkbRF_RulePtr rule; + XkbComponentNamesPtr names; +#endif +{ + rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */ + if ((rule->flags&XkbRF_Append)==0) { + if ((names->keycodes==NULL)&&(rule->keycodes!=NULL)) + names->keycodes= _XkbDupString(rule->keycodes); + + if ((names->symbols==NULL)&&(rule->symbols!=NULL)) + names->symbols= _XkbDupString(rule->symbols); + + if ((names->types==NULL)&&(rule->types!=NULL)) + names->types= _XkbDupString(rule->types); + + if ((names->compat==NULL)&&(rule->compat!=NULL)) + names->compat= _XkbDupString(rule->compat); + + if ((names->geometry==NULL)&&(rule->geometry!=NULL)) + names->geometry= _XkbDupString(rule->geometry); + + if ((names->keymap==NULL)&&(rule->keymap!=NULL)) + names->keymap= _XkbDupString(rule->keymap); + } + else { + if (rule->keycodes) + names->keycodes= _Concat(names->keycodes,rule->keycodes); + if (rule->symbols) + names->symbols= _Concat(names->symbols,rule->symbols); + if (rule->types) + names->types= _Concat(names->types,rule->types); + if (rule->compat) + names->compat= _Concat(names->compat,rule->compat); + if (rule->geometry) + names->geometry= _Concat(names->geometry,rule->geometry); + if (rule->keymap) + names->keymap= _Concat(names->keymap,rule->keymap); + } + return (names->keycodes && names->symbols && names->types && + names->compat && names->geometry ) || names->keymap; +} + +#define CHECK_MATCH(r,d) ((((r)[0]=='?')&&((r)[1]=='\0'))||(strcmp(r,d)==0)) + +Bool +#if NeedFunctionPrototypes +XkbRF_CheckApplyRule( XkbRF_RulePtr rule, + XkbRF_VarDefsPtr defs, + XkbComponentNamesPtr names) +#else +XkbRF_CheckApplyRule(rule,defs,names) + XkbRF_RulePtr rule; + XkbRF_VarDefsPtr defs; + XkbComponentNamesPtr names; +#endif +{ + if (rule->model!=NULL) { + if ((!defs->model)||(!CHECK_MATCH(rule->model,defs->model))) + return False; + } + if (rule->layout!=NULL) { + if ((!defs->layout)||(!CHECK_MATCH(rule->layout,defs->layout))) + return False; + } + if (rule->variant!=NULL) { + if ((!defs->variant)||(!CHECK_MATCH(rule->variant,defs->variant))) + return False; + } + if (rule->option!=NULL) { + if ((!defs->options)||(!MatchOneOf(rule->option,defs->options))) + return False; + } + + if ((!rule->option)&& + ((!rule->model)||(!rule->layout)||(!rule->variant))) { + /* partial map -- partial maps are applied in the order they */ + /* appear, but all partial maps come before any options. */ + rule->flags|= XkbRF_PendingMatch; + return False; + } + /* exact match, apply it now */ + return XkbRF_ApplyRule(rule,names); +} + +void +#if NeedFunctionPrototypes +XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules) +#else +XkbRF_ClearPartialMatches(rules) + XkbRF_RulesPtr rules; +#endif +{ +register int i; +XkbRF_RulePtr rule; + + for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { + rule->flags&= ~XkbRF_PendingMatch; + } +} + +Bool +#if NeedFunctionPrototypes +XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names) +#else +XkbRF_ApplyPartialMatches(rules,names) + XkbRF_RulesPtr rules; + XkbComponentNamesPtr names; +#endif +{ +int i; +XkbRF_RulePtr rule; +Bool complete; + + complete= False; + for (rule=rules->rules,i=0;(i<rules->num_rules)&&(!complete);i++,rule++) { + if ((rule->flags&XkbRF_PendingMatch)==0) + continue; + complete= XkbRF_ApplyRule(rule,names); + } + return complete; +} + +void +#if NeedFunctionPrototypes +XkbRF_CheckApplyDelayedRules( XkbRF_RulesPtr rules, + XkbRF_VarDefsPtr defs, + XkbComponentNamesPtr names) +#else +XkbRF_CheckApplyDelayedRules(rules,defs,names) + XkbRF_RulesPtr rules; + XkbRF_VarDefsPtr defs; + XkbComponentNamesPtr names; +#endif +{ +int i; +XkbRF_RulePtr rule; + + for (rule=rules->rules,i=0;(i<rules->num_rules);i++,rule++) { + if ((rule->flags&XkbRF_Delayed)==0) + continue; + XkbRF_CheckApplyRule(rule,defs,names); + } + return; +} + +Bool +#if NeedFunctionPrototypes +XkbRF_CheckApplyRules( XkbRF_RulesPtr rules, + XkbRF_VarDefsPtr defs, + XkbComponentNamesPtr names) +#else +XkbRF_CheckApplyRules(rules,defs,names) + XkbRF_RulesPtr rules; + XkbRF_VarDefsPtr defs; + XkbComponentNamesPtr names; +#endif +{ +int i; +XkbRF_RulePtr rule; +Bool complete; + + complete= False; + for (rule=rules->rules,i=0;(i<rules->num_rules)&&(!complete);i++,rule++) { + if ((rule->flags&XkbRF_Delayed)!=0) + continue; + complete= XkbRF_CheckApplyRule(rule,defs,names); + } + return complete; +} + +/***====================================================================***/ + +char * +#if NeedFunctionPrototypes +XkbRF_SubstituteVars(char *name,XkbRF_VarDefsPtr defs) +#else +XkbRF_SubstituteVars(name,defs) + char * name; + XkbRF_VarDefsPtr defs; +#endif +{ +char *str,*outstr,*orig; +int len; + + 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++; + } + + if ((str[1]=='l')&&defs->layout) + len+= strlen(defs->layout)+extra_len; + else if ((str[1]=='m')&&defs->model) + len+= strlen(defs->model)+extra_len; + else if ((str[1]=='v')&&defs->variant) + len+= strlen(defs->variant)+extra_len; + if ((pfx=='(')&&(str[2]==')')) { + str++; + } + str= index(&str[1],'%'); + } + 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'; + + if ((str[0]=='l')&&(defs->layout)) { + if (pfx) *outstr++= pfx; + strcpy(outstr,defs->layout); + outstr+= strlen(defs->layout); + if (sfx) *outstr++= sfx; + } + else if ((str[0]=='m')&&(defs->model)) { + if (pfx) *outstr++= pfx; + strcpy(outstr,defs->model); + outstr+= strlen(defs->model); + if (sfx) *outstr++= sfx; + } + else if ((str[0]=='v')&&(defs->variant)) { + if (pfx) *outstr++= pfx; + strcpy(outstr,defs->variant); + outstr+= strlen(defs->variant); + if (sfx) *outstr++= sfx; + } + str++; + if ((pfx=='(')&&(str[0]==')')) + str++; + } + else { + *outstr++= *str++; + } + } + *outstr++= '\0'; + if (orig!=name) + _XkbFree(orig); + return name; +} + +/***====================================================================***/ + +Bool +#if NeedFunctionPrototypes +XkbRF_GetComponents( XkbRF_RulesPtr rules, + XkbRF_VarDefsPtr defs, + XkbComponentNamesPtr names) +#else +XkbRF_GetComponents(rules,defs,names) + XkbRF_RulesPtr rules; + XkbRF_VarDefsPtr defs; + XkbComponentNamesPtr names; +#endif +{ +Bool complete; + + bzero((char *)names,sizeof(XkbComponentNamesRec)); + XkbRF_ClearPartialMatches(rules); + complete= XkbRF_CheckApplyRules(rules,defs,names); + if (!complete) + complete= XkbRF_ApplyPartialMatches(rules,names); + XkbRF_CheckApplyDelayedRules(rules,defs,names); + if (names->keycodes) + names->keycodes= XkbRF_SubstituteVars(names->keycodes,defs); + if (names->symbols) + names->symbols= XkbRF_SubstituteVars(names->symbols,defs); + if (names->types) + names->types= XkbRF_SubstituteVars(names->types,defs); + if (names->compat) + names->compat= XkbRF_SubstituteVars(names->compat,defs); + if (names->geometry) + names->geometry= XkbRF_SubstituteVars(names->geometry,defs); + if (names->keymap) + names->keymap= XkbRF_SubstituteVars(names->keymap,defs); + return (names->keycodes && names->symbols && names->types && + names->compat && names->geometry ) || names->keymap; +} + +XkbRF_RulePtr +#if NeedFunctionPrototypes +XkbRF_AddRule(XkbRF_RulesPtr rules) +#else +XkbRF_AddRule(rules) + XkbRF_RulesPtr rules; +#endif +{ + 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++]; +} + +Bool +#if NeedFunctionPrototypes +XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules) +#else +XkbRF_LoadRules(file,rules) + FILE * file; + XkbRF_RulesPtr rules; +#endif +{ +InputLine line; +RemapSpec remap; +XkbRF_RuleRec trule,*rule; + + if (!(rules && file)) + return False; + bzero((char *)&remap,sizeof(RemapSpec)); + InitInputLine(&line); + while (GetInputLine(file,&line,True)) { + if (CheckLine(&line,&remap,&trule)) { + if ((rule= XkbRF_AddRule(rules))!=NULL) { + *rule= trule; + bzero((char *)&trule,sizeof(XkbRF_RuleRec)); + } + } + line.num_line= 0; + } + FreeInputLine(&line); + return True; +} + +Bool +#if NeedFunctionPrototypes +XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules) +#else +XkbRF_LoadRulesByName(base,locale,rules) + char * base; + char * locale; + XkbRF_RulesPtr rules; +#endif +{ +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 +#if NeedFunctionPrototypes +XkbRF_AddVarDesc(XkbRF_DescribeVarsPtr vars) +#else +XkbRF_AddVarDesc(vars) + XkbRF_DescribeVarsPtr vars; +#endif +{ + 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 +#if NeedFunctionPrototypes +XkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from) +#else +XkbRF_AddVarDescCopy(vars,from) + XkbRF_DescribeVarsPtr vars; + XkbRF_VarDescPtr from; +#endif +{ +XkbRF_VarDescPtr nd; + + if ((nd=XkbRF_AddVarDesc(vars))!=NULL) { + nd->name= _XkbDupString(from->name); + nd->desc= _XkbDupString(from->desc); + } + return nd; +} + +XkbRF_DescribeVarsPtr +#if NeedFunctionPrototypes +XkbRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name) +#else +XkbRF_AddVarToDescribe(rules,name) + XkbRF_RulesPtr rules; + char * name; +#endif +{ + 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 +#if NeedFunctionPrototypes +XkbRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules) +#else +XkbRF_LoadDescriptions(file,rules) + FILE * file; + XkbRF_RulesPtr rules; +#endif +{ +InputLine line; +XkbRF_VarDescRec tmp; +char *tok; +int len,headingtype,extra_ndx; + + 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(tok,"model")) + headingtype = HEAD_MODEL; + else if (!_XkbStrCaseCmp(tok,"layout")) + headingtype = HEAD_LAYOUT; + else if (!_XkbStrCaseCmp(tok,"variant")) + headingtype = HEAD_VARIANT; + else if (!_XkbStrCaseCmp(tok,"option")) + 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 +#if NeedFunctionPrototypes +XkbRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules) +#else +XkbRF_LoadDescriptionsByName(base,locale,rules) + char * base; + char * locale; + XkbRF_RulesPtr rules; +#endif +{ +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 +#if NeedFunctionPrototypes +XkbRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules) +#else +XkbRF_Load(base,locale,wantDesc,wantRules) + char *base; + char *locale; + Bool wantDesc; + Bool wantRules; +#endif +{ +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 +#if NeedFunctionPrototypes +XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var) +#else +XkbRF_ClearVarDescriptions(var) + XkbRF_DescribeVarsPtr var; +#endif +{ +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 +#if NeedFunctionPrototypes +XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules) +#else +XkbRF_Free(rules,freeRules) + XkbRF_RulesPtr rules; + Bool freeRules; +#endif +{ +int i; +XkbRF_RulePtr rule; + + 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 (freeRules) + _XkbFree(rules); + return; +} + +#ifndef XKB_IN_SERVER + +Bool +#if NeedFunctionPrototypes +XkbRF_GetNamesProp(Display *dpy,char **rf_rtrn,XkbRF_VarDefsPtr vd_rtrn) +#else +XkbRF_GetNamesProp(dpy,rf_rtrn,vd_rtrn) + Display * dpy; + char ** rf_rtrn; + XkbRF_VarDefsPtr vd_rtrn; +#endif +{ +Atom rules_atom,actual_type; +int fmt; +unsigned long nitems,bytes_after; +char *data,*out; +Status rtrn; + + rules_atom= XInternAtom(dpy,_XKB_RF_NAMES_PROP_ATOM,True); + if (rules_atom==None) /* property cannot exist */ + return False; + rtrn= XGetWindowProperty(dpy,DefaultRootWindow(dpy),rules_atom, + 0L,_XKB_RF_NAMES_PROP_MAXLEN,False, + XA_STRING,&actual_type, + &fmt,&nitems,&bytes_after, + (unsigned char **)&data); + if (rtrn!=Success) + return False; + if (rf_rtrn) + *rf_rtrn= NULL; + (void)bzero((char *)vd_rtrn,sizeof(XkbRF_VarDefsRec)); + if ((bytes_after>0)||(actual_type!=XA_STRING)||(fmt!=8)) { + if (data) XFree(data); + return (fmt==0?True:False); + } + + out= data; + if (out && (*out) && rf_rtrn) + *rf_rtrn= _XkbDupString(out); + out+=strlen(out)+1; + + if ((out-data)<nitems) { + if (*out) + vd_rtrn->model= _XkbDupString(out); + out+=strlen(out)+1; + } + + if ((out-data)<nitems) { + if (*out) + vd_rtrn->layout= _XkbDupString(out); + out+=strlen(out)+1; + } + + if ((out-data)<nitems) { + if (*out) + vd_rtrn->variant= _XkbDupString(out); + out+=strlen(out)+1; + } + + + if ((out-data)<nitems) { + if (*out) + vd_rtrn->options= _XkbDupString(out); + out+=strlen(out)+1; + } + XFree(data); + return True; +} + +Bool +#if NeedFunctionPrototypes +XkbRF_SetNamesProp(Display *dpy,char *rules_file,XkbRF_VarDefsPtr var_defs) +#else +XkbRF_SetNamesProp(dpy,rules_file,var_defs) + Display * dpy; + char * rules_file; + XkbRF_VarDefsPtr var_defs; +#endif +{ +int len,out; +Atom name; +char * pval; + + len= (rules_file?strlen(rules_file):0); + len+= (var_defs->model?strlen(var_defs->model):0); + len+= (var_defs->layout?strlen(var_defs->layout):0); + len+= (var_defs->variant?strlen(var_defs->variant):0); + len+= (var_defs->options?strlen(var_defs->options):0); + if (len<1) + return True; + + len+= 5; /* trailing NULs */ + + name= XInternAtom(dpy,_XKB_RF_NAMES_PROP_ATOM,False); + if (name==None) { /* should never happen */ + _XkbLibError(_XkbErrXReqFailure,"XkbRF_SetNamesProp",X_InternAtom); + return False; + } + pval= (char *)_XkbAlloc(len); + if (!pval) { + _XkbLibError(_XkbErrBadAlloc,"XkbRF_SetNamesProp",len); + return False; + } + out= 0; + if (rules_file) { + strcpy(&pval[out],rules_file); + out+= strlen(rules_file); + } + pval[out++]= '\0'; + if (var_defs->model) { + strcpy(&pval[out],var_defs->model); + out+= strlen(var_defs->model); + } + pval[out++]= '\0'; + if (var_defs->layout) { + strcpy(&pval[out],var_defs->layout); + out+= strlen(var_defs->layout); + } + pval[out++]= '\0'; + if (var_defs->variant) { + strcpy(&pval[out],var_defs->variant); + out+= strlen(var_defs->variant); + } + pval[out++]= '\0'; + if (var_defs->options) { + strcpy(&pval[out],var_defs->options); + out+= strlen(var_defs->options); + } + pval[out++]= '\0'; + if (out!=len) { + _XkbLibError(_XkbErrBadLength,"XkbRF_SetNamesProp",out); + _XkbFree(pval); + return False; + } + + XChangeProperty(dpy,DefaultRootWindow(dpy),name,XA_STRING,8,PropModeReplace, + (unsigned char *)pval,len); + _XkbFree(pval); + return True; +} + +#endif |