diff options
Diffstat (limited to 'libxkbfile/src/maprules.c')
-rw-r--r-- | libxkbfile/src/maprules.c | 2972 |
1 files changed, 1485 insertions, 1487 deletions
diff --git a/libxkbfile/src/maprules.c b/libxkbfile/src/maprules.c index d7d7e8d7d..68b202d98 100644 --- a/libxkbfile/src/maprules.c +++ b/libxkbfile/src/maprules.c @@ -1,1487 +1,1485 @@ -/* $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> -#elif defined(HAVE_CONFIG_H) -#include <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> - -#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 - -#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> - -#endif - -#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 - -/***====================================================================***/ - -#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)) - -#ifdef HAVE_UNLOCKED_STDIO -#undef getc -#define getc(x) getc_unlocked(x) -#else -#define flockfile(x) do {} while (0) -#define funlockfile(x) do {} while (0) -#endif - -static Bool -GetInputLine(FILE *file,InputLine *line,Bool checkbang) -{ -int ch; -Bool endOfFile,spacePending,slashPending,inComment; - - endOfFile= False; - flockfile(file); - 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++;*/ - } - funlockfile(file); - 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); - XkbRF_ApplyPartialMatches(rules, names); - - 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 (strcmp(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; -} - -#ifndef XKB_IN_SERVER - -Bool -XkbRF_GetNamesProp(Display *dpy,char **rf_rtrn,XkbRF_VarDefsPtr vd_rtrn) -{ -Atom rules_atom,actual_type; -int fmt; -unsigned long nitems,bytes_after; -unsigned char *data; -char *out, *end; -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=(char*)data; - end=out+nitems; - if (out && (*out) && rf_rtrn) - *rf_rtrn= _XkbDupString(out); - out+=strlen(out)+1; - - if (out<end) { - if (*out) - vd_rtrn->model= _XkbDupString(out); - out+=strlen(out)+1; - } - - if (out<end) { - if (*out) - vd_rtrn->layout= _XkbDupString(out); - out+=strlen(out)+1; - } - - if (out<end) { - if (*out) - vd_rtrn->variant= _XkbDupString(out); - out+=strlen(out)+1; - } - - if (out<end) { - if (*out) - vd_rtrn->options= _XkbDupString(out); - out+=strlen(out)+1; - } - - XFree(data); - return True; -} - -Bool -XkbRF_SetNamesProp(Display *dpy,char *rules_file,XkbRF_VarDefsPtr var_defs) -{ -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 +/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#elif defined(HAVE_CONFIG_H)
+#include <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>
+
+#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
+
+#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>
+
+#endif
+
+#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
+
+/***====================================================================***/
+
+#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))
+
+#ifdef HAVE_UNLOCKED_STDIO
+#undef getc
+#define getc(x) getc_unlocked(x)
+#else
+#define flockfile(x) do {} while (0)
+#define funlockfile(x) do {} while (0)
+#endif
+
+static Bool
+GetInputLine(FILE *file,InputLine *line,Bool checkbang)
+{
+int ch;
+Bool endOfFile,spacePending,slashPending,inComment;
+
+ endOfFile= False;
+ flockfile(file);
+ 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++;*/
+ }
+ funlockfile(file);
+ 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);
+ XkbRF_ApplyPartialMatches(rules, names);
+
+ 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 (strcmp(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;
+}
+
+#ifndef XKB_IN_SERVER
+
+Bool
+XkbRF_GetNamesProp(Display *dpy,char **rf_rtrn,XkbRF_VarDefsPtr vd_rtrn)
+{
+Atom rules_atom,actual_type;
+int fmt;
+unsigned long nitems,bytes_after;
+unsigned char *data;
+char *out, *end;
+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=(char*)data;
+ end=out+nitems;
+ if (out && (*out) && rf_rtrn)
+ *rf_rtrn= _XkbDupString(out);
+ out+=strlen(out)+1;
+
+ if (out<end) {
+ if (*out)
+ vd_rtrn->model= _XkbDupString(out);
+ out+=strlen(out)+1;
+ }
+
+ if (out<end) {
+ if (*out)
+ vd_rtrn->layout= _XkbDupString(out);
+ out+=strlen(out)+1;
+ }
+
+ if (out<end) {
+ if (*out)
+ vd_rtrn->variant= _XkbDupString(out);
+ out+=strlen(out)+1;
+ }
+
+ if (out<end) {
+ if (*out)
+ vd_rtrn->options= _XkbDupString(out);
+ out+=strlen(out)+1;
+ }
+
+ XFree(data);
+ return True;
+}
+
+Bool
+XkbRF_SetNamesProp(Display *dpy,char *rules_file,XkbRF_VarDefsPtr var_defs)
+{
+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
|