2006-11-25 13:07:29 -07:00
|
|
|
/* $Xorg: keytypes.c,v 1.3 2000/08/17 19:54:32 cpqbld Exp $ */
|
|
|
|
/************************************************************
|
|
|
|
Copyright (c) 1994 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/programs/xkbcomp/keytypes.c,v 1.4 2001/01/17 23:45:44 dawes Exp $ */
|
|
|
|
|
|
|
|
#include "xkbcomp.h"
|
|
|
|
#include "tokens.h"
|
|
|
|
#include "expr.h"
|
|
|
|
#include "vmod.h"
|
|
|
|
#include "action.h"
|
|
|
|
#include "misc.h"
|
|
|
|
|
|
|
|
typedef struct _PreserveInfo {
|
|
|
|
CommonInfo defs;
|
|
|
|
short matchingMapIndex;
|
|
|
|
unsigned char indexMods;
|
|
|
|
unsigned char preMods;
|
|
|
|
unsigned short indexVMods;
|
|
|
|
unsigned short preVMods;
|
|
|
|
} PreserveInfo;
|
|
|
|
|
|
|
|
#define _KT_Name (1<<0)
|
|
|
|
#define _KT_Mask (1<<1)
|
|
|
|
#define _KT_Map (1<<2)
|
|
|
|
#define _KT_Preserve (1<<3)
|
|
|
|
#define _KT_LevelNames (1<<4)
|
|
|
|
|
|
|
|
typedef struct _KeyTypeInfo {
|
|
|
|
CommonInfo defs;
|
|
|
|
Display * dpy;
|
|
|
|
Atom name;
|
|
|
|
int fileID;
|
|
|
|
unsigned mask;
|
|
|
|
unsigned vmask;
|
|
|
|
Bool groupInfo;
|
|
|
|
int numLevels;
|
|
|
|
int nEntries;
|
|
|
|
int szEntries;
|
|
|
|
XkbKTMapEntryPtr entries;
|
|
|
|
PreserveInfo * preserve;
|
|
|
|
int szNames;
|
|
|
|
Atom * lvlNames;
|
|
|
|
} KeyTypeInfo;
|
|
|
|
|
|
|
|
typedef struct _KeyTypesInfo {
|
|
|
|
Display * dpy;
|
|
|
|
char * name;
|
|
|
|
int errorCount;
|
|
|
|
int fileID;
|
|
|
|
unsigned stdPresent;
|
|
|
|
int nTypes;
|
|
|
|
KeyTypeInfo * types;
|
|
|
|
KeyTypeInfo dflt;
|
|
|
|
VModInfo vmods;
|
|
|
|
} KeyTypesInfo;
|
|
|
|
|
|
|
|
Atom tok_ONE_LEVEL;
|
|
|
|
Atom tok_TWO_LEVEL;
|
|
|
|
Atom tok_ALPHABETIC;
|
|
|
|
Atom tok_KEYPAD;
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
#define ReportTypeShouldBeArray(t,f) \
|
|
|
|
ReportShouldBeArray("key type",(f),TypeTxt(t))
|
|
|
|
#define ReportTypeBadType(t,f,w) \
|
|
|
|
ReportBadType("key type",(f),TypeTxt(t),(w))
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
extern Bool AddMapEntry(
|
|
|
|
XkbDescPtr /* xkb */,
|
|
|
|
KeyTypeInfo * /* type */,
|
|
|
|
XkbKTMapEntryPtr /* new */,
|
|
|
|
Bool /* clobber */,
|
|
|
|
Bool /* report */
|
|
|
|
);
|
|
|
|
|
|
|
|
extern Bool AddPreserve(
|
|
|
|
XkbDescPtr /* xkb */,
|
|
|
|
KeyTypeInfo * /* type */,
|
|
|
|
PreserveInfo * /* new */,
|
|
|
|
Bool /* clobber */,
|
|
|
|
Bool /* report */
|
|
|
|
);
|
|
|
|
|
|
|
|
extern Bool AddLevelName(
|
|
|
|
KeyTypeInfo * /* type */,
|
|
|
|
unsigned /* level */,
|
|
|
|
Atom /* name */,
|
|
|
|
Bool /* clobber */,
|
|
|
|
Bool /* report */
|
|
|
|
);
|
|
|
|
|
|
|
|
#define MapEntryTxt(t,x,e) \
|
|
|
|
XkbVModMaskText((t)->dpy,(x),(e)->mods.real_mods,(e)->mods.vmods,XkbMessage)
|
|
|
|
#define PreserveIndexTxt(t,x,p) \
|
|
|
|
XkbVModMaskText((t)->dpy,(x),(p)->indexMods,(p)->indexVMods,XkbMessage)
|
|
|
|
#define PreserveTxt(t,x,p) \
|
|
|
|
XkbVModMaskText((t)->dpy,(x),(p)->preMods,(p)->preVMods,XkbMessage)
|
|
|
|
#define TypeTxt(t) XkbAtomText((t)->dpy,(t)->name,XkbMessage)
|
|
|
|
#define TypeMaskTxt(t,x) \
|
|
|
|
XkbVModMaskText((t)->dpy,(x),(t)->mask,(t)->vmask,XkbMessage)
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
static void
|
|
|
|
InitKeyTypesInfo(KeyTypesInfo *info,XkbDescPtr xkb,KeyTypesInfo *from)
|
|
|
|
{
|
|
|
|
tok_ONE_LEVEL= XkbInternAtom(NULL,"ONE_LEVEL",False);
|
|
|
|
tok_TWO_LEVEL= XkbInternAtom(NULL,"TWO_LEVEL",False);
|
|
|
|
tok_ALPHABETIC= XkbInternAtom(NULL,"ALPHABETIC",False);
|
|
|
|
tok_KEYPAD= XkbInternAtom(NULL,"KEYPAD",False);
|
|
|
|
info->dpy= NULL;
|
|
|
|
info->name= uStringDup("default");
|
|
|
|
info->errorCount= 0;
|
|
|
|
info->stdPresent= 0;
|
|
|
|
info->nTypes= 0;
|
|
|
|
info->types= NULL;
|
|
|
|
info->dflt.defs.defined= 0;
|
|
|
|
info->dflt.defs.fileID= 0;
|
|
|
|
info->dflt.defs.merge= MergeOverride;
|
|
|
|
info->dflt.defs.next= NULL;
|
|
|
|
info->dflt.name= None;
|
|
|
|
info->dflt.mask= 0;
|
|
|
|
info->dflt.vmask= 0;
|
|
|
|
info->dflt.groupInfo= False;
|
|
|
|
info->dflt.numLevels= 1;
|
|
|
|
info->dflt.nEntries= info->dflt.szEntries= 0;
|
|
|
|
info->dflt.entries= NULL;
|
|
|
|
info->dflt.szNames= 0;
|
|
|
|
info->dflt.lvlNames= NULL;
|
|
|
|
info->dflt.preserve= NULL;
|
|
|
|
InitVModInfo(&info->vmods,xkb);
|
|
|
|
if (from!=NULL) {
|
|
|
|
info->dpy= from->dpy;
|
|
|
|
info->dflt= from->dflt;
|
|
|
|
if (from->dflt.entries) {
|
|
|
|
info->dflt.entries= uTypedCalloc(from->dflt.szEntries,
|
|
|
|
XkbKTMapEntryRec);
|
|
|
|
if (info->dflt.entries) {
|
|
|
|
unsigned sz = from->dflt.nEntries*sizeof(XkbKTMapEntryRec);
|
|
|
|
memcpy(info->dflt.entries,from->dflt.entries,sz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (from->dflt.lvlNames) {
|
|
|
|
info->dflt.lvlNames= uTypedCalloc(from->dflt.szNames,Atom);
|
|
|
|
if (info->dflt.lvlNames) {
|
|
|
|
register unsigned sz = from->dflt.szNames*sizeof(Atom);
|
|
|
|
memcpy(info->dflt.lvlNames,from->dflt.lvlNames,sz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (from->dflt.preserve) {
|
|
|
|
PreserveInfo *old,*new,*last;
|
|
|
|
last= NULL;
|
|
|
|
old= from->dflt.preserve;
|
|
|
|
for (;old;old=(PreserveInfo *)old->defs.next) {
|
|
|
|
new= uTypedAlloc(PreserveInfo);
|
|
|
|
if (!new)
|
|
|
|
return;
|
|
|
|
*new= *old;
|
|
|
|
new->defs.next= NULL;
|
|
|
|
if (last) last->defs.next= (CommonInfo *)new;
|
|
|
|
else info->dflt.preserve= new;
|
|
|
|
last= new;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FreeKeyTypeInfo(KeyTypeInfo *type)
|
|
|
|
{
|
|
|
|
if (type->entries!=NULL) {
|
|
|
|
uFree(type->entries);
|
|
|
|
type->entries= NULL;
|
|
|
|
}
|
|
|
|
if (type->lvlNames!=NULL) {
|
|
|
|
uFree(type->lvlNames);
|
|
|
|
type->lvlNames= NULL;
|
|
|
|
}
|
|
|
|
if (type->preserve!=NULL) {
|
|
|
|
ClearCommonInfo(&type->preserve->defs);
|
|
|
|
type->preserve= NULL;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
FreeKeyTypesInfo(KeyTypesInfo *info)
|
|
|
|
{
|
|
|
|
info->dpy= NULL;
|
|
|
|
if (info->name)
|
|
|
|
uFree(info->name);
|
|
|
|
info->name= NULL;
|
|
|
|
if (info->types) {
|
|
|
|
register KeyTypeInfo *type;
|
|
|
|
for (type= info->types;type;type=(KeyTypeInfo *)type->defs.next) {
|
|
|
|
FreeKeyTypeInfo(type);
|
|
|
|
}
|
|
|
|
info->types= (KeyTypeInfo *)ClearCommonInfo(&info->types->defs);
|
|
|
|
}
|
|
|
|
FreeKeyTypeInfo(&info->dflt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static KeyTypeInfo *
|
|
|
|
NextKeyType(KeyTypesInfo *info)
|
|
|
|
{
|
|
|
|
KeyTypeInfo * type;
|
|
|
|
|
|
|
|
type= uTypedAlloc(KeyTypeInfo);
|
|
|
|
if (type!=NULL) {
|
|
|
|
bzero(type,sizeof(KeyTypeInfo));
|
|
|
|
type->defs.fileID= info->fileID;
|
|
|
|
type->dpy= info->dpy;
|
|
|
|
info->types= (KeyTypeInfo *)AddCommonInfo(&info->types->defs,
|
|
|
|
(CommonInfo *)type);
|
|
|
|
info->nTypes++;
|
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
static KeyTypeInfo *
|
|
|
|
FindMatchingKeyType(KeyTypesInfo *info,KeyTypeInfo *new)
|
|
|
|
{
|
|
|
|
KeyTypeInfo *old;
|
|
|
|
|
|
|
|
for (old=info->types;old;old=(KeyTypeInfo *)old->defs.next) {
|
|
|
|
if (old->name==new->name)
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
2008-04-20 10:32:06 -06:00
|
|
|
ReportTypeBadWidth(const char *type, int has, int needs)
|
2006-11-25 13:07:29 -07:00
|
|
|
{
|
|
|
|
ERROR3("Key type \"%s\" has %d levels, must have %d\n",type,has,needs);
|
|
|
|
ACTION("Illegal type definition ignored\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
AddKeyType(XkbDescPtr xkb,KeyTypesInfo *info,KeyTypeInfo *new)
|
|
|
|
{
|
|
|
|
KeyTypeInfo * old;
|
|
|
|
|
|
|
|
if (new->name==tok_ONE_LEVEL) {
|
|
|
|
if (new->numLevels>1)
|
|
|
|
return ReportTypeBadWidth("ONE_LEVEL",new->numLevels,1);
|
|
|
|
info->stdPresent|= XkbOneLevelMask;
|
|
|
|
}
|
|
|
|
else if (new->name==tok_TWO_LEVEL) {
|
|
|
|
if (new->numLevels>2)
|
|
|
|
return ReportTypeBadWidth("TWO_LEVEL",new->numLevels,2);
|
|
|
|
else if (new->numLevels<2)
|
|
|
|
new->numLevels= 2;
|
|
|
|
info->stdPresent|= XkbTwoLevelMask;
|
|
|
|
}
|
|
|
|
else if (new->name==tok_ALPHABETIC) {
|
|
|
|
if (new->numLevels>2)
|
|
|
|
return ReportTypeBadWidth("ALPHABETIC",new->numLevels,2);
|
|
|
|
else if (new->numLevels<2)
|
|
|
|
new->numLevels= 2;
|
|
|
|
info->stdPresent|= XkbAlphabeticMask;
|
|
|
|
}
|
|
|
|
else if (new->name==tok_KEYPAD) {
|
|
|
|
if (new->numLevels>2)
|
|
|
|
return ReportTypeBadWidth("KEYPAD",new->numLevels,2);
|
|
|
|
else if (new->numLevels<2)
|
|
|
|
new->numLevels= 2;
|
|
|
|
info->stdPresent|= XkbKeypadMask;
|
|
|
|
}
|
|
|
|
|
|
|
|
old= FindMatchingKeyType(info,new);
|
|
|
|
if (old!=NULL) {
|
|
|
|
Bool report;
|
|
|
|
if ((new->defs.merge==MergeReplace)||(new->defs.merge==MergeOverride)) {
|
|
|
|
KeyTypeInfo *next= (KeyTypeInfo *)old->defs.next;
|
|
|
|
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
|
|
|
|
(warningLevel>9)) {
|
|
|
|
WARN1("Multiple definitions of the %s key type\n",
|
|
|
|
XkbAtomGetString(NULL,new->name));
|
|
|
|
ACTION("Earlier definition ignored\n");
|
|
|
|
}
|
|
|
|
FreeKeyTypeInfo(old);
|
|
|
|
*old= *new;
|
|
|
|
new->szEntries= new->nEntries= 0;
|
|
|
|
new->entries= NULL;
|
|
|
|
new->preserve= NULL;
|
|
|
|
new->lvlNames= NULL;
|
|
|
|
old->defs.next= &next->defs;
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
report= (old->defs.fileID==new->defs.fileID)&&(warningLevel>0);
|
|
|
|
if (report) {
|
|
|
|
WARN1("Multiple definitions of the %s key type\n",
|
|
|
|
XkbAtomGetString(NULL,new->name));
|
|
|
|
ACTION("Later definition ignored\n");
|
|
|
|
}
|
|
|
|
FreeKeyTypeInfo(new);
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
old= NextKeyType(info);
|
|
|
|
if (old==NULL)
|
|
|
|
return False;
|
|
|
|
*old= *new;
|
|
|
|
old->defs.next= NULL;
|
|
|
|
new->nEntries= new->szEntries= 0;
|
|
|
|
new->entries= NULL;
|
|
|
|
new->szNames= 0;
|
|
|
|
new->lvlNames= NULL;
|
|
|
|
new->preserve= NULL;
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
static void
|
|
|
|
MergeIncludedKeyTypes( KeyTypesInfo * into,
|
|
|
|
KeyTypesInfo * from,
|
|
|
|
unsigned merge,
|
|
|
|
XkbDescPtr xkb)
|
|
|
|
{
|
|
|
|
KeyTypeInfo * type;
|
|
|
|
|
|
|
|
if (from->errorCount>0) {
|
|
|
|
into->errorCount+= from->errorCount;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (into->name==NULL) {
|
|
|
|
into->name= from->name;
|
|
|
|
from->name= NULL;
|
|
|
|
}
|
|
|
|
for (type=from->types;type;type=(KeyTypeInfo *)type->defs.next) {
|
|
|
|
if (merge!=MergeDefault)
|
|
|
|
type->defs.merge= merge;
|
|
|
|
if (!AddKeyType(xkb,into,type))
|
|
|
|
into->errorCount++;
|
|
|
|
}
|
|
|
|
into->stdPresent|= from->stdPresent;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef void (*FileHandler)(
|
|
|
|
XkbFile * /* file */,
|
|
|
|
XkbDescPtr /* xkb */,
|
|
|
|
unsigned /* merge */,
|
|
|
|
KeyTypesInfo * /* included */
|
|
|
|
);
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
HandleIncludeKeyTypes( IncludeStmt * stmt,
|
|
|
|
XkbDescPtr xkb,
|
|
|
|
KeyTypesInfo * info,
|
|
|
|
FileHandler hndlr)
|
|
|
|
{
|
|
|
|
unsigned newMerge;
|
|
|
|
XkbFile * rtrn;
|
|
|
|
KeyTypesInfo included;
|
|
|
|
Bool haveSelf;
|
|
|
|
|
|
|
|
haveSelf= False;
|
|
|
|
if ((stmt->file==NULL)&&(stmt->map==NULL)) {
|
|
|
|
haveSelf= True;
|
|
|
|
included= *info;
|
|
|
|
bzero(info,sizeof(KeyTypesInfo));
|
|
|
|
}
|
|
|
|
else if (ProcessIncludeFile(stmt,XkmTypesIndex,&rtrn,&newMerge)) {
|
|
|
|
InitKeyTypesInfo(&included,xkb,info);
|
|
|
|
included.fileID= included.dflt.defs.fileID= rtrn->id;
|
|
|
|
included.dflt.defs.merge= newMerge;
|
|
|
|
|
|
|
|
(*hndlr)(rtrn,xkb,newMerge,&included);
|
|
|
|
if (stmt->stmt!=NULL) {
|
|
|
|
if (included.name!=NULL)
|
|
|
|
uFree(included.name);
|
|
|
|
included.name= stmt->stmt;
|
|
|
|
stmt->stmt= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
info->errorCount+= 10;
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
if ((stmt->next!=NULL)&&(included.errorCount<1)) {
|
|
|
|
IncludeStmt * next;
|
|
|
|
unsigned op;
|
|
|
|
KeyTypesInfo next_incl;
|
|
|
|
|
|
|
|
for (next=stmt->next;next!=NULL;next=next->next) {
|
|
|
|
if ((next->file==NULL)&&(next->map==NULL)) {
|
|
|
|
haveSelf= True;
|
|
|
|
MergeIncludedKeyTypes(&included,info,next->merge,xkb);
|
|
|
|
FreeKeyTypesInfo(info);
|
|
|
|
}
|
|
|
|
else if (ProcessIncludeFile(next,XkmTypesIndex,&rtrn,&op)) {
|
|
|
|
InitKeyTypesInfo(&next_incl,xkb,&included);
|
|
|
|
next_incl.fileID= next_incl.dflt.defs.fileID= rtrn->id;
|
|
|
|
next_incl.dflt.defs.merge= op;
|
|
|
|
(*hndlr)(rtrn,xkb,op,&next_incl);
|
|
|
|
MergeIncludedKeyTypes(&included,&next_incl,op,xkb);
|
|
|
|
FreeKeyTypesInfo(&next_incl);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
info->errorCount+= 10;
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (haveSelf)
|
|
|
|
*info= included;
|
|
|
|
else {
|
|
|
|
MergeIncludedKeyTypes(info,&included,newMerge,xkb);
|
|
|
|
FreeKeyTypesInfo(&included);
|
|
|
|
}
|
|
|
|
return (info->errorCount==0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
static XkbKTMapEntryPtr
|
|
|
|
FindMatchingMapEntry(KeyTypeInfo *type,unsigned mask,unsigned vmask)
|
|
|
|
{
|
|
|
|
register int i;
|
|
|
|
XkbKTMapEntryPtr entry;
|
|
|
|
|
|
|
|
for (i=0,entry=type->entries;i<type->nEntries;i++,entry++) {
|
|
|
|
if ((entry->mods.real_mods==mask)&&(entry->mods.vmods==vmask))
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DeleteLevel1MapEntries(KeyTypeInfo *type)
|
|
|
|
{
|
|
|
|
register int i,n;
|
|
|
|
|
|
|
|
for (i=0;i<type->nEntries;i++) {
|
|
|
|
if (type->entries[i].level==0) {
|
|
|
|
for (n=i;n<type->nEntries-1;n++) {
|
|
|
|
type->entries[n]= type->entries[n+1];
|
|
|
|
}
|
|
|
|
type->nEntries--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static XkbKTMapEntryPtr
|
|
|
|
NextMapEntry(KeyTypeInfo *type)
|
|
|
|
{
|
|
|
|
if (type->entries==NULL) {
|
|
|
|
type->entries= uTypedCalloc(2,XkbKTMapEntryRec);
|
|
|
|
if (type->entries==NULL) {
|
|
|
|
ERROR1("Couldn't allocate map entries for %s\n",TypeTxt(type));
|
|
|
|
ACTION("Map entries lost\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
type->szEntries= 2;
|
|
|
|
type->nEntries= 0;
|
|
|
|
}
|
|
|
|
else if (type->nEntries>=type->szEntries) {
|
|
|
|
type->szEntries*=2;
|
|
|
|
type->entries= uTypedRecalloc(type->entries,
|
|
|
|
type->nEntries,type->szEntries,
|
|
|
|
XkbKTMapEntryRec);
|
|
|
|
if (type->entries==NULL) {
|
|
|
|
ERROR1("Couldn't reallocate map entries for %s\n",TypeTxt(type));
|
|
|
|
ACTION("Map entries lost\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &type->entries[type->nEntries++];
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
AddPreserve( XkbDescPtr xkb,
|
|
|
|
KeyTypeInfo * type,
|
|
|
|
PreserveInfo * new,
|
|
|
|
Bool clobber,
|
|
|
|
Bool report)
|
|
|
|
{
|
|
|
|
PreserveInfo *old;
|
|
|
|
|
|
|
|
old= type->preserve;
|
|
|
|
while (old!=NULL) {
|
|
|
|
if ((old->indexMods!=new->indexMods)||
|
|
|
|
(old->indexVMods!=new->indexVMods)) {
|
|
|
|
old= (PreserveInfo *)old->defs.next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((old->preMods==new->preMods)&&(old->preVMods==new->preVMods)) {
|
|
|
|
if (warningLevel>9) {
|
|
|
|
WARN2("Identical definitions for preserve[%s] in %s\n",
|
|
|
|
PreserveIndexTxt(type,xkb,old),TypeTxt(type));
|
|
|
|
ACTION("Ignored\n");
|
|
|
|
}
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
if (report && (warningLevel>0)) {
|
|
|
|
char *str;
|
|
|
|
WARN2("Multiple definitions for preserve[%s] in %s\n",
|
|
|
|
PreserveIndexTxt(type,xkb,old),TypeTxt(type));
|
|
|
|
|
|
|
|
if (clobber) str= PreserveTxt(type,xkb,new);
|
|
|
|
else str= PreserveTxt(type,xkb,old);
|
|
|
|
ACTION1("Using %s, ",str);
|
|
|
|
if (clobber) str= PreserveTxt(type,xkb,old);
|
|
|
|
else str= PreserveTxt(type,xkb,new);
|
|
|
|
INFO1("ignoring %s\n",str);
|
|
|
|
}
|
|
|
|
if (clobber) {
|
|
|
|
old->preMods= new->preMods;
|
|
|
|
old->preVMods= new->preVMods;
|
|
|
|
}
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
old= uTypedAlloc(PreserveInfo);
|
|
|
|
if (!old) {
|
|
|
|
WSGO1("Couldn't allocate preserve in %s\n",TypeTxt(type));
|
|
|
|
ACTION1("Preserve[%s] lost\n",PreserveIndexTxt(type,xkb,old));
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
*old= *new;
|
|
|
|
old->matchingMapIndex= -1;
|
|
|
|
type->preserve=(PreserveInfo*)AddCommonInfo(&type->preserve->defs,&old->defs);
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
AddMapEntry( XkbDescPtr xkb,
|
|
|
|
KeyTypeInfo * type,
|
|
|
|
XkbKTMapEntryPtr new,
|
|
|
|
Bool clobber,
|
|
|
|
Bool report)
|
|
|
|
{
|
|
|
|
XkbKTMapEntryPtr old;
|
|
|
|
|
|
|
|
if ((old=FindMatchingMapEntry(type,new->mods.real_mods,new->mods.vmods))) {
|
|
|
|
if (report&&(old->level!=new->level)) {
|
|
|
|
unsigned use,ignore;
|
|
|
|
if (clobber) {
|
|
|
|
use= new->level+1;
|
|
|
|
ignore= old->level+1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
use= old->level+1;
|
|
|
|
ignore= new->level+1;
|
|
|
|
}
|
|
|
|
WARN2("Multiple map entries for %s in %s\n",
|
|
|
|
MapEntryTxt(type,xkb,new),TypeTxt(type));
|
|
|
|
ACTION2("Using %d, ignoring %d\n",use,ignore);
|
|
|
|
}
|
|
|
|
else if (warningLevel>9) {
|
|
|
|
WARN3("Multiple occurences of map[%s]= %d in %s\n",
|
|
|
|
MapEntryTxt(type,xkb,new),new->level+1,TypeTxt(type));
|
|
|
|
ACTION("Ignored\n");
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
if (clobber)
|
|
|
|
old->level= new->level;
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
if ((old=NextMapEntry(type))==NULL)
|
|
|
|
return False; /* allocation failure, already reported */
|
|
|
|
if (new->level>=type->numLevels)
|
|
|
|
type->numLevels= new->level+1;
|
|
|
|
if (new->mods.vmods==0) old->active= True;
|
|
|
|
else old->active= False;
|
|
|
|
old->mods.mask= new->mods.real_mods;
|
|
|
|
old->mods.real_mods= new->mods.real_mods;
|
|
|
|
old->mods.vmods= new->mods.vmods;
|
|
|
|
old->level= new->level;
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LookupEntry lnames[] = {
|
|
|
|
{ "level1", 1 },
|
|
|
|
{ "level2", 2 },
|
|
|
|
{ "level3", 3 },
|
|
|
|
{ "level4", 4 },
|
|
|
|
{ "level5", 5 },
|
|
|
|
{ "level6", 6 },
|
|
|
|
{ "level7", 7 },
|
|
|
|
{ "level8", 8 },
|
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
SetMapEntry( KeyTypeInfo * type,
|
|
|
|
XkbDescPtr xkb,
|
|
|
|
ExprDef * arrayNdx,
|
|
|
|
ExprDef * value)
|
|
|
|
{
|
|
|
|
ExprResult rtrn;
|
|
|
|
XkbKTMapEntryRec entry;
|
|
|
|
|
|
|
|
if (arrayNdx==NULL)
|
|
|
|
return ReportTypeShouldBeArray(type,"map entry");
|
|
|
|
if (!ExprResolveModMask(arrayNdx,&rtrn,LookupVModMask,(XPointer)xkb))
|
|
|
|
return ReportTypeBadType(type,"map entry","modifier mask");
|
|
|
|
entry.mods.real_mods= rtrn.uval&0xff;
|
|
|
|
entry.mods.vmods= (rtrn.uval>>8)&0xffff;
|
|
|
|
if ((entry.mods.real_mods&(~type->mask))||
|
|
|
|
((entry.mods.vmods&(~type->vmask))!=0)) {
|
|
|
|
if (warningLevel>0) {
|
|
|
|
WARN1("Map entry for unused modifiers in %s\n",TypeTxt(type));
|
|
|
|
ACTION1("Using %s instead of ",XkbVModMaskText(type->dpy,xkb,
|
|
|
|
entry.mods.real_mods&type->mask,
|
|
|
|
entry.mods.vmods&type->vmask,
|
|
|
|
XkbMessage));
|
|
|
|
INFO1("%s\n",MapEntryTxt(type,xkb,&entry));
|
|
|
|
}
|
|
|
|
entry.mods.real_mods&= type->mask;
|
|
|
|
entry.mods.vmods&= type->vmask;
|
|
|
|
}
|
|
|
|
if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)lnames)) {
|
|
|
|
ERROR("Level specifications in a key type must be integer\n");
|
|
|
|
ACTION("Ignoring malformed level specification\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
if ((rtrn.ival<1)||(rtrn.ival>XkbMaxShiftLevel+1)) {
|
|
|
|
ERROR3("Shift level %d out of range (1..%d) in key type %s\n",
|
|
|
|
XkbMaxShiftLevel+1,
|
|
|
|
rtrn.ival,TypeTxt(type));
|
|
|
|
ACTION1("Ignoring illegal definition of map[%s]\n",
|
|
|
|
MapEntryTxt(type,xkb,&entry));
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
entry.level= rtrn.ival-1;
|
|
|
|
return AddMapEntry(xkb,type,&entry,True,True);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
SetPreserve( KeyTypeInfo * type,
|
|
|
|
XkbDescPtr xkb,
|
|
|
|
ExprDef * arrayNdx,
|
|
|
|
ExprDef * value)
|
|
|
|
{
|
|
|
|
ExprResult rtrn;
|
|
|
|
PreserveInfo new;
|
|
|
|
|
|
|
|
if (arrayNdx==NULL)
|
|
|
|
return ReportTypeShouldBeArray(type,"preserve entry");
|
|
|
|
if (!ExprResolveModMask(arrayNdx,&rtrn,LookupVModMask,(XPointer)xkb))
|
|
|
|
return ReportTypeBadType(type,"preserve entry","modifier mask");
|
|
|
|
new.defs= type->defs;
|
|
|
|
new.defs.next= NULL;
|
|
|
|
new.indexMods= rtrn.uval&0xff;
|
|
|
|
new.indexVMods= (rtrn.uval>>8)&0xffff;
|
|
|
|
if ((new.indexMods&(~type->mask))||(new.indexVMods&(~type->vmask))) {
|
|
|
|
if (warningLevel>0) {
|
|
|
|
WARN1("Preserve for modifiers not used by the %s type\n",
|
|
|
|
TypeTxt(type));
|
|
|
|
ACTION1("Index %s converted to ",PreserveIndexTxt(type,xkb,&new));
|
|
|
|
}
|
|
|
|
new.indexMods&= type->mask;
|
|
|
|
new.indexVMods&= type->vmask;
|
|
|
|
if (warningLevel>0)
|
|
|
|
INFO1("%s\n",PreserveIndexTxt(type,xkb,&new));
|
|
|
|
}
|
|
|
|
if (!ExprResolveModMask(value,&rtrn,LookupVModMask,(XPointer)xkb)) {
|
|
|
|
ERROR("Preserve value in a key type is not a modifier mask\n");
|
|
|
|
ACTION2("Ignoring preserve[%s] in type %s\n",
|
|
|
|
PreserveIndexTxt(type,xkb,&new),
|
|
|
|
TypeTxt(type));
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
new.preMods= rtrn.uval&0xff;
|
|
|
|
new.preVMods= (rtrn.uval>>16)&0xffff;
|
|
|
|
if ((new.preMods&(~new.indexMods))||(new.preVMods&&(~new.indexVMods))) {
|
|
|
|
if (warningLevel>0) {
|
|
|
|
WARN2("Illegal value for preserve[%s] in type %s\n",
|
|
|
|
PreserveTxt(type,xkb,&new),
|
|
|
|
TypeTxt(type));
|
|
|
|
ACTION1("Converted %s to ",PreserveIndexTxt(type,xkb,&new));
|
|
|
|
}
|
|
|
|
new.preMods&= new.indexMods;
|
|
|
|
new.preVMods&= new.indexVMods;
|
|
|
|
if (warningLevel>0) {
|
|
|
|
INFO1("%s\n",PreserveIndexTxt(type,xkb,&new));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return AddPreserve(xkb,type,&new,True,True);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
Bool
|
|
|
|
AddLevelName( KeyTypeInfo * type,
|
|
|
|
unsigned level,
|
|
|
|
Atom name,
|
|
|
|
Bool clobber,
|
|
|
|
Bool report)
|
|
|
|
{
|
|
|
|
if ((type->lvlNames==NULL)||(type->szNames<=level)) {
|
|
|
|
type->lvlNames=
|
|
|
|
uTypedRecalloc(type->lvlNames,type->szNames,level+1,Atom);
|
|
|
|
if (type->lvlNames==NULL) {
|
|
|
|
ERROR1("Couldn't allocate level names for type %s\n",TypeTxt(type));
|
|
|
|
ACTION("Level names lost\n");
|
|
|
|
type->szNames= 0;
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
type->szNames= level+1;
|
|
|
|
}
|
|
|
|
else if (type->lvlNames[level]==name) {
|
|
|
|
if (warningLevel>9) {
|
|
|
|
WARN2("Duplicate names for level %d of key type %s\n",level+1,
|
|
|
|
TypeTxt(type));
|
|
|
|
ACTION("Ignored\n");
|
|
|
|
}
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
else if (type->lvlNames[level]!=None) {
|
|
|
|
if (warningLevel>0) {
|
|
|
|
char *old,*new;
|
|
|
|
old= XkbAtomText(type->dpy,type->lvlNames[level],XkbMessage);
|
|
|
|
new= XkbAtomText(type->dpy,name,XkbMessage);
|
|
|
|
WARN2("Multiple names for level %d of key type %s\n",level+1,
|
|
|
|
TypeTxt(type));
|
|
|
|
if (clobber)
|
|
|
|
ACTION2("Using %s, ignoring %s\n",new,old);
|
|
|
|
else ACTION2("Using %s, ignoring %s\n",old,new);
|
|
|
|
}
|
|
|
|
if (!clobber)
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
if (level>=type->numLevels)
|
|
|
|
type->numLevels= level+1;
|
|
|
|
type->lvlNames[level]= name;
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
SetLevelName(KeyTypeInfo *type,ExprDef *arrayNdx,ExprDef *value)
|
|
|
|
{
|
|
|
|
ExprResult rtrn;
|
|
|
|
unsigned level;
|
|
|
|
|
|
|
|
if (arrayNdx==NULL)
|
|
|
|
return ReportTypeShouldBeArray(type,"level name");
|
|
|
|
if (!ExprResolveInteger(arrayNdx,&rtrn,SimpleLookup,(XPointer)lnames))
|
|
|
|
return ReportTypeBadType(type,"level name","integer");
|
|
|
|
if ((rtrn.ival<1)||(rtrn.ival>XkbMaxShiftLevel+1)) {
|
|
|
|
ERROR3("Level name %d out of range (1..%d) in key type %s\n",
|
|
|
|
rtrn.ival,
|
|
|
|
XkbMaxShiftLevel+1,
|
|
|
|
XkbAtomText(type->dpy,type->name,XkbMessage));
|
|
|
|
ACTION("Ignoring illegal level name definition\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
level= rtrn.ival-1;
|
|
|
|
if (!ExprResolveString(value,&rtrn,NULL,NULL)) {
|
|
|
|
ERROR2("Non-string name for level %d in key type %s\n",level+1,
|
|
|
|
XkbAtomText(type->dpy,type->name,XkbMessage));
|
|
|
|
ACTION("Ignoring illegal level name definition\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
return
|
|
|
|
AddLevelName(type,level,XkbInternAtom(NULL,rtrn.str,False),True,True);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
SetKeyTypeField( KeyTypeInfo * type,
|
|
|
|
XkbDescPtr xkb,
|
|
|
|
char * field,
|
|
|
|
ExprDef * arrayNdx,
|
|
|
|
ExprDef * value,
|
|
|
|
KeyTypesInfo * info)
|
|
|
|
{
|
|
|
|
ExprResult tmp;
|
|
|
|
|
|
|
|
if (uStrCaseCmp(field,"modifiers")==0) {
|
|
|
|
unsigned mods,vmods;
|
|
|
|
if (arrayNdx!=NULL) {
|
|
|
|
WARN("The modifiers field of a key type is not an array\n");
|
|
|
|
ACTION("Illegal array subscript ignored\n");
|
|
|
|
}
|
|
|
|
if (!ExprResolveModMask(value,&tmp,LookupVModMask,(XPointer)xkb)) {
|
|
|
|
ERROR("Key type mask field must be a modifier mask\n");
|
|
|
|
ACTION("Key type definition ignored\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
mods= tmp.uval&0xff;
|
|
|
|
vmods= (tmp.uval>>8)&0xffff;
|
|
|
|
if (type->defs.defined&_KT_Mask) {
|
|
|
|
WARN1("Multiple modifier mask definitions for key type %s\n",
|
|
|
|
XkbAtomText(type->dpy,type->name,XkbMessage));
|
|
|
|
ACTION1("Using %s, ",TypeMaskTxt(type,xkb));
|
|
|
|
INFO1("ignoring %s\n",XkbVModMaskText(type->dpy,xkb,mods,
|
|
|
|
vmods,
|
|
|
|
XkbMessage));
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
type->mask= mods;
|
|
|
|
type->vmask= vmods;
|
|
|
|
type->defs.defined|= _KT_Mask;
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
else if (uStrCaseCmp(field,"map")==0) {
|
|
|
|
type->defs.defined|= _KT_Map;
|
|
|
|
return SetMapEntry(type,xkb,arrayNdx,value);
|
|
|
|
}
|
|
|
|
else if (uStrCaseCmp(field,"preserve")==0) {
|
|
|
|
type->defs.defined|= _KT_Preserve;
|
|
|
|
return SetPreserve(type,xkb,arrayNdx,value);
|
|
|
|
}
|
|
|
|
else if ((uStrCaseCmp(field,"levelname")==0)||
|
|
|
|
(uStrCaseCmp(field,"level_name")==0)) {
|
|
|
|
type->defs.defined|= _KT_LevelNames;
|
|
|
|
return SetLevelName(type,arrayNdx,value);
|
|
|
|
}
|
|
|
|
ERROR2("Unknown field %s in key type %s\n",field,TypeTxt(type));
|
|
|
|
ACTION("Definition ignored\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
HandleKeyTypeVar(VarDef *stmt,XkbDescPtr xkb,KeyTypesInfo *info)
|
|
|
|
{
|
|
|
|
ExprResult elem,field;
|
|
|
|
ExprDef * arrayNdx;
|
|
|
|
|
|
|
|
if (!ExprResolveLhs(stmt->name,&elem,&field,&arrayNdx))
|
|
|
|
return False; /* internal error, already reported */
|
|
|
|
if (elem.str&&(uStrCaseCmp(elem.str,"type")==0))
|
|
|
|
return SetKeyTypeField(&info->dflt,xkb,field.str,arrayNdx,stmt->value,
|
|
|
|
info);
|
|
|
|
if (elem.str!=NULL) {
|
|
|
|
ERROR1("Default for unknown element %s\n",uStringText(elem.str));
|
|
|
|
ACTION1("Value for field %s ignored\n",uStringText(field.str));
|
|
|
|
}
|
|
|
|
else if (field.str!=NULL) {
|
|
|
|
ERROR1("Default defined for unknown field %s\n",uStringText(field.str));
|
|
|
|
ACTION("Ignored\n");
|
|
|
|
}
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
HandleKeyTypeBody( VarDef * def,
|
|
|
|
XkbDescPtr xkb,
|
|
|
|
KeyTypeInfo * type,
|
|
|
|
KeyTypesInfo * info)
|
|
|
|
{
|
|
|
|
int ok= 1;
|
|
|
|
ExprResult tmp,field;
|
|
|
|
ExprDef * arrayNdx;
|
|
|
|
|
|
|
|
for (;def!=NULL;def= (VarDef *)def->common.next) {
|
|
|
|
if ((def->name)&&(def->name->type==ExprFieldRef)) {
|
|
|
|
ok= HandleKeyTypeVar(def,xkb,info);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ok= ExprResolveLhs(def->name,&tmp,&field,&arrayNdx);
|
|
|
|
if (ok)
|
|
|
|
ok= SetKeyTypeField(type,xkb,field.str,arrayNdx,def->value,info);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
HandleKeyTypeDef( KeyTypeDef * def,
|
|
|
|
XkbDescPtr xkb,
|
|
|
|
unsigned merge,
|
|
|
|
KeyTypesInfo * info)
|
|
|
|
{
|
|
|
|
register int i;
|
|
|
|
KeyTypeInfo type;
|
|
|
|
|
|
|
|
if (def->merge!=MergeDefault)
|
|
|
|
merge= def->merge;
|
|
|
|
|
|
|
|
type.defs.defined= 0;
|
|
|
|
type.defs.fileID= info->fileID;
|
|
|
|
type.defs.merge= merge;
|
|
|
|
type.defs.next= 0;
|
|
|
|
type.dpy= info->dpy;
|
|
|
|
type.name= def->name;
|
|
|
|
type.mask= info->dflt.mask;
|
|
|
|
type.vmask= info->dflt.vmask;
|
|
|
|
type.groupInfo= info->dflt.groupInfo;
|
|
|
|
type.numLevels= 1;
|
|
|
|
type.nEntries= type.szEntries= 0;
|
|
|
|
type.entries= NULL;
|
|
|
|
type.szNames= 0;
|
|
|
|
type.lvlNames= NULL;
|
|
|
|
type.preserve= NULL;
|
|
|
|
|
|
|
|
if (!HandleKeyTypeBody(def->body,xkb,&type,info)) {
|
|
|
|
info->errorCount++;
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now copy any appropriate map, preserve or level names from the */
|
|
|
|
/* default type */
|
|
|
|
for (i=0;i<info->dflt.nEntries;i++) {
|
|
|
|
XkbKTMapEntryPtr dflt;
|
|
|
|
dflt= &info->dflt.entries[i];
|
|
|
|
if (((dflt->mods.real_mods&type.mask)==dflt->mods.real_mods)&&
|
|
|
|
((dflt->mods.vmods&type.vmask)==dflt->mods.vmods)) {
|
|
|
|
AddMapEntry(xkb,&type,dflt,False,False);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (info->dflt.preserve) {
|
|
|
|
PreserveInfo *dflt= info->dflt.preserve;
|
|
|
|
while (dflt) {
|
|
|
|
if (((dflt->indexMods&type.mask)==dflt->indexMods)&&
|
|
|
|
((dflt->indexVMods&type.vmask)==dflt->indexVMods)) {
|
|
|
|
AddPreserve(xkb,&type,dflt,False,False);
|
|
|
|
}
|
|
|
|
dflt= (PreserveInfo *)dflt->defs.next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i=0;i<info->dflt.szNames;i++) {
|
|
|
|
if ((i<type.numLevels)&&(info->dflt.lvlNames[i]!=None)) {
|
|
|
|
AddLevelName(&type,i,info->dflt.lvlNames[i],False,False);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!AddKeyType(xkb,info,&type)) {
|
|
|
|
info->errorCount++;
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
HandleKeyTypesFile( XkbFile * file,
|
|
|
|
XkbDescPtr xkb,
|
|
|
|
unsigned merge,
|
|
|
|
KeyTypesInfo * info)
|
|
|
|
{
|
|
|
|
ParseCommon *stmt;
|
|
|
|
|
|
|
|
info->name= uStringDup(file->name);
|
|
|
|
stmt= file->defs;
|
|
|
|
while (stmt) {
|
|
|
|
switch (stmt->stmtType) {
|
|
|
|
case StmtInclude:
|
|
|
|
if (!HandleIncludeKeyTypes((IncludeStmt *)stmt,xkb,info,
|
|
|
|
HandleKeyTypesFile))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtKeyTypeDef:
|
|
|
|
if (!HandleKeyTypeDef((KeyTypeDef *)stmt,xkb,merge,info))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtVarDef:
|
|
|
|
if (!HandleKeyTypeVar((VarDef *)stmt,xkb,info))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtVModDef:
|
|
|
|
if (!HandleVModDef((VModDef *)stmt,merge,&info->vmods))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtKeyAliasDef:
|
|
|
|
ERROR("Key type files may not include other declarations\n");
|
|
|
|
ACTION("Ignoring definition of key alias\n");
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtKeycodeDef:
|
|
|
|
ERROR("Key type files may not include other declarations\n");
|
|
|
|
ACTION("Ignoring definition of key name\n");
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtInterpDef:
|
|
|
|
ERROR("Key type files may not include other declarations\n");
|
|
|
|
ACTION("Ignoring definition of symbol interpretation\n");
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WSGO1("Unexpected statement type %d in HandleKeyTypesFile\n",
|
|
|
|
stmt->stmtType);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
stmt= stmt->next;
|
|
|
|
if (info->errorCount>10) {
|
|
|
|
#ifdef NOISY
|
|
|
|
ERROR("Too many errors\n");
|
|
|
|
#endif
|
|
|
|
ACTION1("Abandoning keytypes file \"%s\"\n",file->topName);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
CopyDefToKeyType(XkbDescPtr xkb,XkbKeyTypePtr type,KeyTypeInfo *def)
|
|
|
|
{
|
|
|
|
register int i;
|
|
|
|
PreserveInfo *pre;
|
|
|
|
|
|
|
|
for (pre=def->preserve;pre!=NULL;pre=(PreserveInfo *)pre->defs.next) {
|
|
|
|
XkbKTMapEntryPtr match;
|
|
|
|
XkbKTMapEntryRec tmp;
|
|
|
|
tmp.mods.real_mods= pre->indexMods;
|
|
|
|
tmp.mods.vmods= pre->indexVMods;
|
|
|
|
tmp.level= 0;
|
|
|
|
AddMapEntry(xkb,def,&tmp,False,False);
|
|
|
|
match= FindMatchingMapEntry(def,pre->indexMods,pre->indexVMods);
|
|
|
|
if (!match) {
|
|
|
|
WSGO("Couldn't find matching entry for preserve\n");
|
|
|
|
ACTION("Aborting\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
pre->matchingMapIndex= match-def->entries;
|
|
|
|
}
|
|
|
|
type->mods.real_mods= def->mask;
|
|
|
|
type->mods.vmods= def->vmask;
|
|
|
|
type->num_levels= def->numLevels;
|
|
|
|
type->map_count= def->nEntries;
|
|
|
|
type->map= def->entries;
|
|
|
|
if (def->preserve) {
|
|
|
|
type->preserve= uTypedCalloc(type->map_count,XkbModsRec);
|
|
|
|
if (!type->preserve) {
|
|
|
|
WARN("Couldn't allocate preserve array in CopyDefToKeyType\n");
|
|
|
|
ACTION1("Preserve setting for type %s lost\n",
|
|
|
|
XkbAtomText(def->dpy,def->name,XkbMessage));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pre= def->preserve;
|
|
|
|
for (;pre!=NULL;pre=(PreserveInfo *)pre->defs.next) {
|
|
|
|
int ndx= pre->matchingMapIndex;
|
|
|
|
type->preserve[ndx].mask= pre->preMods;
|
|
|
|
type->preserve[ndx].real_mods= pre->preMods;
|
|
|
|
type->preserve[ndx].vmods= pre->preVMods;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else type->preserve= NULL;
|
|
|
|
type->name= (Atom)def->name;
|
|
|
|
if (def->szNames>0) {
|
|
|
|
type->level_names= uTypedCalloc(def->numLevels,Atom);
|
|
|
|
|
|
|
|
/* assert def->szNames<=def->numLevels */
|
|
|
|
for (i=0;i<def->szNames;i++) {
|
|
|
|
type->level_names[i]= (Atom)def->lvlNames[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
type->level_names= NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->nEntries= def->szEntries= 0;
|
|
|
|
def->entries= NULL;
|
|
|
|
return XkbComputeEffectiveMap(xkb,type,NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
CompileKeyTypes(XkbFile *file,XkbFileInfo *result,unsigned merge)
|
|
|
|
{
|
|
|
|
KeyTypesInfo info;
|
|
|
|
XkbDescPtr xkb;
|
|
|
|
|
|
|
|
xkb= result->xkb;
|
|
|
|
InitKeyTypesInfo(&info,xkb,NULL);
|
|
|
|
info.fileID= file->id;
|
|
|
|
HandleKeyTypesFile(file,xkb,merge,&info);
|
|
|
|
|
|
|
|
if (info.errorCount==0) {
|
|
|
|
register int i;
|
|
|
|
register KeyTypeInfo *def;
|
|
|
|
register XkbKeyTypePtr type,next;
|
|
|
|
|
|
|
|
if (info.name!=None) {
|
|
|
|
if (XkbAllocNames(xkb,XkbTypesNameMask,0,0)==Success)
|
|
|
|
xkb->names->types= XkbInternAtom(xkb->dpy,info.name,False);
|
|
|
|
else {
|
|
|
|
WSGO("Couldn't allocate space for types name\n");
|
|
|
|
ACTION2("Name \"%s\" (from %s) NOT assigned\n",scanFile,
|
|
|
|
info.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i= info.nTypes;
|
|
|
|
if ((info.stdPresent&XkbOneLevelMask)==0)
|
|
|
|
i++;
|
|
|
|
if ((info.stdPresent&XkbTwoLevelMask)==0)
|
|
|
|
i++;
|
|
|
|
if ((info.stdPresent&XkbKeypadMask)==0)
|
|
|
|
i++;
|
|
|
|
if ((info.stdPresent&XkbAlphabeticMask)==0)
|
|
|
|
i++;
|
|
|
|
if (XkbAllocClientMap(xkb,XkbKeyTypesMask,i)!=Success) {
|
|
|
|
WSGO("Couldn't allocate client map\n");
|
|
|
|
ACTION("Exiting\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
xkb->map->num_types= i;
|
|
|
|
if (XkbAllRequiredTypes&(~info.stdPresent)) {
|
|
|
|
unsigned missing,keypadVMod;
|
|
|
|
|
|
|
|
missing= XkbAllRequiredTypes&(~info.stdPresent);
|
|
|
|
keypadVMod= FindKeypadVMod(xkb);
|
|
|
|
if (XkbInitCanonicalKeyTypes(xkb,missing,keypadVMod)!=Success) {
|
|
|
|
WSGO("Couldn't initialize canonical key types\n");
|
|
|
|
ACTION("Exiting\n");
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
if (missing&XkbOneLevelMask)
|
|
|
|
xkb->map->types[XkbOneLevelIndex].name= tok_ONE_LEVEL;
|
|
|
|
if (missing&XkbTwoLevelMask)
|
|
|
|
xkb->map->types[XkbTwoLevelIndex].name= tok_TWO_LEVEL;
|
|
|
|
if (missing&XkbAlphabeticMask)
|
|
|
|
xkb->map->types[XkbAlphabeticIndex].name= tok_ALPHABETIC;
|
|
|
|
if (missing&XkbKeypadMask)
|
|
|
|
xkb->map->types[XkbKeypadIndex].name= tok_KEYPAD;
|
|
|
|
}
|
|
|
|
next= &xkb->map->types[XkbLastRequiredType+1];
|
|
|
|
for (i=0,def=info.types;i<info.nTypes;i++) {
|
|
|
|
if (def->name==tok_ONE_LEVEL)
|
|
|
|
type= &xkb->map->types[XkbOneLevelIndex];
|
|
|
|
else if (def->name==tok_TWO_LEVEL)
|
|
|
|
type= &xkb->map->types[XkbTwoLevelIndex];
|
|
|
|
else if (def->name==tok_ALPHABETIC)
|
|
|
|
type= &xkb->map->types[XkbAlphabeticIndex];
|
|
|
|
else if (def->name==tok_KEYPAD)
|
|
|
|
type= &xkb->map->types[XkbKeypadIndex];
|
|
|
|
else type= next++;
|
|
|
|
DeleteLevel1MapEntries(def);
|
|
|
|
if (!CopyDefToKeyType(xkb,type,def))
|
|
|
|
return False;
|
|
|
|
def= (KeyTypeInfo *)def->defs.next;
|
|
|
|
}
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|