1f46a6179Smrg/************************************************************ 2f46a6179Smrg Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. 3f46a6179Smrg 4f46a6179Smrg Permission to use, copy, modify, and distribute this 5f46a6179Smrg software and its documentation for any purpose and without 6f46a6179Smrg fee is hereby granted, provided that the above copyright 7f46a6179Smrg notice appear in all copies and that both that copyright 8f46a6179Smrg notice and this permission notice appear in supporting 9bfe6082cSmrg documentation, and that the name of Silicon Graphics not be 10bfe6082cSmrg used in advertising or publicity pertaining to distribution 11f46a6179Smrg of the software without specific prior written permission. 12bfe6082cSmrg Silicon Graphics makes no representation about the suitability 13f46a6179Smrg of this software for any purpose. It is provided "as is" 14f46a6179Smrg without any express or implied warranty. 15bfe6082cSmrg 16bfe6082cSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 17bfe6082cSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 18f46a6179Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 19bfe6082cSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 20bfe6082cSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21bfe6082cSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 22f46a6179Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 23f46a6179Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE. 24f46a6179Smrg 25f46a6179Smrg ********************************************************/ 26f46a6179Smrg 27f46a6179Smrg#include <X11/Xos.h> 28f46a6179Smrg#include "xkbcomp.h" 29f46a6179Smrg#include "tokens.h" 30f46a6179Smrg#include "expr.h" 31f46a6179Smrg#include "vmod.h" 32f46a6179Smrg#include "misc.h" 33f46a6179Smrg#include "indicators.h" 34f46a6179Smrg#include "action.h" 3534345a63Smrg#include "compat.h" 36f46a6179Smrg 3734345a63Smrgtypedef struct _SymInterpInfo 3834345a63Smrg{ 3934345a63Smrg CommonInfo defs; 4034345a63Smrg XkbSymInterpretRec interp; 41f46a6179Smrg} SymInterpInfo; 42f46a6179Smrg 43f46a6179Smrg#define _SI_VirtualMod (1<<0) 44f46a6179Smrg#define _SI_Action (1<<1) 45f46a6179Smrg#define _SI_AutoRepeat (1<<2) 46f46a6179Smrg#define _SI_LockingKey (1<<3) 47f46a6179Smrg#define _SI_LevelOneOnly (1<<4) 48f46a6179Smrg 4934345a63Smrgtypedef struct _GroupCompatInfo 5034345a63Smrg{ 5134345a63Smrg unsigned char fileID; 5234345a63Smrg unsigned char merge; 531d8c7986Smrg Bool defined; 5434345a63Smrg unsigned char real_mods; 5534345a63Smrg unsigned short vmods; 56f46a6179Smrg} GroupCompatInfo; 57f46a6179Smrg 5834345a63Smrgtypedef struct _CompatInfo 5934345a63Smrg{ 6034345a63Smrg char *name; 6134345a63Smrg unsigned fileID; 6234345a63Smrg int errorCount; 6334345a63Smrg int nInterps; 6434345a63Smrg SymInterpInfo *interps; 6534345a63Smrg SymInterpInfo dflt; 6634345a63Smrg LEDInfo ledDflt; 6734345a63Smrg GroupCompatInfo groupCompat[XkbNumKbdGroups]; 6834345a63Smrg LEDInfo *leds; 6934345a63Smrg VModInfo vmods; 7034345a63Smrg ActionInfo *act; 7134345a63Smrg XkbDescPtr xkb; 72f46a6179Smrg} CompatInfo; 73f46a6179Smrg 74f46a6179Smrg/***====================================================================***/ 75f46a6179Smrg 76f46a6179Smrg#define ReportSINotArray(si,f,i) \ 77f46a6179Smrg ReportNotArray("symbol interpretation",(f),siText((si),(i))) 78f46a6179Smrg#define ReportSIBadType(si,f,w,i) \ 79f46a6179Smrg ReportBadType("symbol interpretation",(f),siText((si),(i)),(w)) 80f46a6179Smrg 81f46a6179Smrg/***====================================================================***/ 82f46a6179Smrg 83f46a6179Smrgstatic char * 846930ead5SmrgsiText(const SymInterpInfo *si, const CompatInfo *info) 85f46a6179Smrg{ 8634345a63Smrg static char buf[128]; 87f46a6179Smrg 8834345a63Smrg if (si == &info->dflt) 8934345a63Smrg { 9034345a63Smrg snprintf(buf, sizeof(buf), "default"); 91f46a6179Smrg } 9234345a63Smrg else 9334345a63Smrg { 94bfe6082cSmrg snprintf(buf, sizeof(buf), "%s+%s(%s)", 9534345a63Smrg XkbKeysymText(si->interp.sym, XkbMessage), 9634345a63Smrg XkbSIMatchText(si->interp.match, XkbMessage), 9734345a63Smrg XkbModMaskText(si->interp.mods, XkbMessage)); 98f46a6179Smrg } 99f46a6179Smrg return buf; 100f46a6179Smrg} 101f46a6179Smrg 102f46a6179Smrgstatic void 10334345a63SmrgInitCompatInfo(CompatInfo * info, XkbDescPtr xkb) 104f46a6179Smrg{ 10534345a63Smrg info->xkb = xkb; 10634345a63Smrg info->name = NULL; 10734345a63Smrg info->fileID = 0; 10834345a63Smrg info->errorCount = 0; 10934345a63Smrg info->nInterps = 0; 11034345a63Smrg info->interps = NULL; 11134345a63Smrg info->act = NULL; 11234345a63Smrg info->dflt.defs.fileID = info->fileID; 11334345a63Smrg info->dflt.defs.defined = 0; 11434345a63Smrg info->dflt.defs.merge = MergeOverride; 11534345a63Smrg info->dflt.interp.flags = 0; 11634345a63Smrg info->dflt.interp.virtual_mod = XkbNoModifier; 11734345a63Smrg info->dflt.interp.act.type = XkbSA_NoAction; 1186930ead5Smrg for (int i = 0; i < XkbAnyActionDataSize; i++) 11934345a63Smrg { 12034345a63Smrg info->dflt.interp.act.data[i] = 0; 12134345a63Smrg } 12234345a63Smrg ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt); 12334345a63Smrg info->ledDflt.defs.fileID = info->fileID; 12434345a63Smrg info->ledDflt.defs.defined = 0; 12534345a63Smrg info->ledDflt.defs.merge = MergeOverride; 1266930ead5Smrg bzero(&info->groupCompat[0], XkbNumKbdGroups * sizeof(GroupCompatInfo)); 12734345a63Smrg info->leds = NULL; 12834345a63Smrg InitVModInfo(&info->vmods, xkb); 129f46a6179Smrg return; 130f46a6179Smrg} 131f46a6179Smrg 132f46a6179Smrgstatic void 13334345a63SmrgClearCompatInfo(CompatInfo * info, XkbDescPtr xkb) 134f46a6179Smrg{ 1356930ead5Smrg free(info->name); 13634345a63Smrg info->name = NULL; 13734345a63Smrg info->dflt.defs.defined = 0; 13834345a63Smrg info->dflt.defs.merge = MergeAugment; 13934345a63Smrg info->dflt.interp.flags = 0; 14034345a63Smrg info->dflt.interp.virtual_mod = XkbNoModifier; 14134345a63Smrg info->dflt.interp.act.type = XkbSA_NoAction; 1426930ead5Smrg for (int i = 0; i < XkbAnyActionDataSize; i++) 14334345a63Smrg { 14434345a63Smrg info->dflt.interp.act.data[i] = 0; 14534345a63Smrg } 14634345a63Smrg ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt); 14734345a63Smrg info->nInterps = 0; 14834345a63Smrg info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs); 1496930ead5Smrg bzero(&info->groupCompat[0], XkbNumKbdGroups * sizeof(GroupCompatInfo)); 15034345a63Smrg info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs); 151f46a6179Smrg /* 3/30/94 (ef) -- XXX! Should free action info here */ 15234345a63Smrg ClearVModInfo(&info->vmods, xkb); 153f46a6179Smrg return; 154f46a6179Smrg} 155f46a6179Smrg 156f46a6179Smrgstatic SymInterpInfo * 15734345a63SmrgNextInterp(CompatInfo * info) 158f46a6179Smrg{ 15934345a63Smrg SymInterpInfo *si; 160f46a6179Smrg 1616930ead5Smrg si = calloc(1, sizeof(SymInterpInfo)); 16234345a63Smrg if (si) 16334345a63Smrg { 16434345a63Smrg info->interps = 16534345a63Smrg (SymInterpInfo *) AddCommonInfo(&info->interps->defs, 16634345a63Smrg (CommonInfo *) si); 16734345a63Smrg info->nInterps++; 168f46a6179Smrg } 169f46a6179Smrg return si; 170f46a6179Smrg} 171f46a6179Smrg 172f46a6179Smrgstatic SymInterpInfo * 1736930ead5SmrgFindMatchingInterp(CompatInfo *info, const SymInterpInfo *new) 174f46a6179Smrg{ 17534345a63Smrg SymInterpInfo *old; 17634345a63Smrg 17734345a63Smrg for (old = info->interps; old != NULL; 17834345a63Smrg old = (SymInterpInfo *) old->defs.next) 17934345a63Smrg { 18034345a63Smrg if ((old->interp.sym == new->interp.sym) && 18134345a63Smrg (old->interp.mods == new->interp.mods) && 18234345a63Smrg (old->interp.match == new->interp.match)) 18334345a63Smrg { 18434345a63Smrg return old; 18534345a63Smrg } 186f46a6179Smrg } 187f46a6179Smrg return NULL; 188f46a6179Smrg} 189f46a6179Smrg 190f46a6179Smrgstatic Bool 19134345a63SmrgAddInterp(CompatInfo * info, SymInterpInfo * new) 192f46a6179Smrg{ 19334345a63Smrg SymInterpInfo *old; 19434345a63Smrg 19534345a63Smrg old = FindMatchingInterp(info, new); 19634345a63Smrg if (old != NULL) 19734345a63Smrg { 1986930ead5Smrg unsigned collide = 0; 1996930ead5Smrg 20034345a63Smrg if (new->defs.merge == MergeReplace) 20134345a63Smrg { 20234345a63Smrg SymInterpInfo *next = (SymInterpInfo *) old->defs.next; 20334345a63Smrg if (((old->defs.fileID == new->defs.fileID) 20434345a63Smrg && (warningLevel > 0)) || (warningLevel > 9)) 20534345a63Smrg { 206bfe6082cSmrg WARN("Multiple definitions for \"%s\"\n", siText(new, info)); 20734345a63Smrg ACTION("Earlier interpretation ignored\n"); 20834345a63Smrg } 20934345a63Smrg *old = *new; 21034345a63Smrg old->defs.next = &next->defs; 21134345a63Smrg return True; 21234345a63Smrg } 21334345a63Smrg if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide)) 21434345a63Smrg { 21534345a63Smrg old->interp.virtual_mod = new->interp.virtual_mod; 21634345a63Smrg old->defs.defined |= _SI_VirtualMod; 21734345a63Smrg } 21834345a63Smrg if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide)) 21934345a63Smrg { 22034345a63Smrg old->interp.act = new->interp.act; 22134345a63Smrg old->defs.defined |= _SI_Action; 22234345a63Smrg } 22334345a63Smrg if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide)) 22434345a63Smrg { 22534345a63Smrg old->interp.flags &= ~XkbSI_AutoRepeat; 22634345a63Smrg old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat); 22734345a63Smrg old->defs.defined |= _SI_AutoRepeat; 22834345a63Smrg } 22934345a63Smrg if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide)) 23034345a63Smrg { 23134345a63Smrg old->interp.flags &= ~XkbSI_LockingKey; 23234345a63Smrg old->interp.flags |= (new->interp.flags & XkbSI_LockingKey); 23334345a63Smrg old->defs.defined |= _SI_LockingKey; 23434345a63Smrg } 23534345a63Smrg if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide)) 23634345a63Smrg { 23734345a63Smrg old->interp.match &= ~XkbSI_LevelOneOnly; 23834345a63Smrg old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly); 23934345a63Smrg old->defs.defined |= _SI_LevelOneOnly; 24034345a63Smrg } 241a57d84feSmrg if (collide && (warningLevel > 0)) 24234345a63Smrg { 243bfe6082cSmrg WARN("Multiple interpretations of \"%s\"\n", siText(new, info)); 244bfe6082cSmrg ACTION("Using %s definition for duplicate fields\n", 24534345a63Smrg (new->defs.merge != MergeAugment ? "last" : "first")); 24634345a63Smrg } 24734345a63Smrg return True; 24834345a63Smrg } 24934345a63Smrg old = new; 25034345a63Smrg if ((new = NextInterp(info)) == NULL) 25134345a63Smrg return False; 25234345a63Smrg *new = *old; 25334345a63Smrg new->defs.next = NULL; 254f46a6179Smrg return True; 255f46a6179Smrg} 256f46a6179Smrg 257f46a6179Smrgstatic Bool 2586930ead5SmrgAddGroupCompat(CompatInfo *info, unsigned group, const GroupCompatInfo *newGC) 259f46a6179Smrg{ 26034345a63Smrg GroupCompatInfo *gc; 26134345a63Smrg unsigned merge; 26234345a63Smrg 26334345a63Smrg merge = newGC->merge; 26434345a63Smrg gc = &info->groupCompat[group]; 26534345a63Smrg if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods))) 26634345a63Smrg { 26734345a63Smrg return True; 26834345a63Smrg } 269c82dfdfbSmrg if (((gc->defined && gc->fileID == newGC->fileID) && (warningLevel > 0)) 27034345a63Smrg || (warningLevel > 9)) 27134345a63Smrg { 272bfe6082cSmrg WARN("Compat map for group %d redefined\n", group + 1); 273bfe6082cSmrg ACTION("Using %s definition\n", 27434345a63Smrg (merge == MergeAugment ? "old" : "new")); 27534345a63Smrg } 2761d8c7986Smrg if(newGC->defined && (merge != MergeAugment || !gc->defined)) 2771d8c7986Smrg *gc = *newGC; 278f46a6179Smrg return True; 279f46a6179Smrg} 280f46a6179Smrg 281f46a6179Smrg/***====================================================================***/ 282f46a6179Smrg 283f46a6179Smrgstatic Bool 2846930ead5SmrgResolveStateAndPredicate(const ExprDef *expr, 2856930ead5Smrg unsigned *pred_rtrn, unsigned *mods_rtrn, 2866930ead5Smrg const CompatInfo *info) 287f46a6179Smrg{ 28834345a63Smrg ExprResult result; 28934345a63Smrg 29034345a63Smrg if (expr == NULL) 29134345a63Smrg { 29234345a63Smrg *pred_rtrn = XkbSI_AnyOfOrNone; 29334345a63Smrg *mods_rtrn = ~0; 29434345a63Smrg return True; 29534345a63Smrg } 29634345a63Smrg 29734345a63Smrg *pred_rtrn = XkbSI_Exactly; 29834345a63Smrg if (expr->op == ExprActionDecl) 29934345a63Smrg { 30034345a63Smrg char *pred_txt = 30134345a63Smrg XkbAtomText(NULL, expr->value.action.name, XkbMessage); 30234345a63Smrg if (uStrCaseCmp(pred_txt, "noneof") == 0) 30334345a63Smrg *pred_rtrn = XkbSI_NoneOf; 30434345a63Smrg else if (uStrCaseCmp(pred_txt, "anyofornone") == 0) 30534345a63Smrg *pred_rtrn = XkbSI_AnyOfOrNone; 30634345a63Smrg else if (uStrCaseCmp(pred_txt, "anyof") == 0) 30734345a63Smrg *pred_rtrn = XkbSI_AnyOf; 30834345a63Smrg else if (uStrCaseCmp(pred_txt, "allof") == 0) 30934345a63Smrg *pred_rtrn = XkbSI_AllOf; 31034345a63Smrg else if (uStrCaseCmp(pred_txt, "exactly") == 0) 31134345a63Smrg *pred_rtrn = XkbSI_Exactly; 31234345a63Smrg else 31334345a63Smrg { 314bfe6082cSmrg ERROR("Illegal modifier predicate \"%s\"\n", pred_txt); 31534345a63Smrg ACTION("Ignored\n"); 31634345a63Smrg return False; 31734345a63Smrg } 31834345a63Smrg expr = expr->value.action.args; 31934345a63Smrg } 32034345a63Smrg else if (expr->op == ExprIdent) 32134345a63Smrg { 32234345a63Smrg char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage); 32334345a63Smrg if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0)) 32434345a63Smrg { 32534345a63Smrg *pred_rtrn = XkbSI_AnyOf; 32634345a63Smrg *mods_rtrn = 0xff; 32734345a63Smrg return True; 32834345a63Smrg } 32934345a63Smrg } 33034345a63Smrg 33134345a63Smrg if (ExprResolveModMask(expr, &result, NULL, NULL)) 33234345a63Smrg { 33334345a63Smrg *mods_rtrn = result.uval; 33434345a63Smrg return True; 335f46a6179Smrg } 336f46a6179Smrg return False; 337f46a6179Smrg} 338f46a6179Smrg 339f46a6179Smrg/***====================================================================***/ 340f46a6179Smrg 341f46a6179Smrgstatic void 34234345a63SmrgMergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge) 343f46a6179Smrg{ 3446930ead5Smrg LEDInfo *next; 34534345a63Smrg GroupCompatInfo *gcm; 3466930ead5Smrg int i; 34734345a63Smrg 34834345a63Smrg if (from->errorCount > 0) 34934345a63Smrg { 35034345a63Smrg into->errorCount += from->errorCount; 35134345a63Smrg return; 35234345a63Smrg } 35334345a63Smrg if (into->name == NULL) 35434345a63Smrg { 35534345a63Smrg into->name = from->name; 35634345a63Smrg from->name = NULL; 35734345a63Smrg } 3586930ead5Smrg for (SymInterpInfo *si = from->interps; si; 3596930ead5Smrg si = (SymInterpInfo *) si->defs.next) 36034345a63Smrg { 36134345a63Smrg if (merge != MergeDefault) 36234345a63Smrg si->defs.merge = merge; 36334345a63Smrg if (!AddInterp(into, si)) 36434345a63Smrg into->errorCount++; 36534345a63Smrg } 36634345a63Smrg for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++) 36734345a63Smrg { 36834345a63Smrg if (merge != MergeDefault) 36934345a63Smrg gcm->merge = merge; 37034345a63Smrg if (!AddGroupCompat(into, i, gcm)) 37134345a63Smrg into->errorCount++; 37234345a63Smrg } 3736930ead5Smrg for (LEDInfo *led = from->leds; led != NULL; led = next) 37434345a63Smrg { 3756930ead5Smrg LEDInfo *rtrn; 3766930ead5Smrg 37734345a63Smrg next = (LEDInfo *) led->defs.next; 37834345a63Smrg if (merge != MergeDefault) 37934345a63Smrg led->defs.merge = merge; 38034345a63Smrg rtrn = AddIndicatorMap(into->leds, led); 38134345a63Smrg if (rtrn != NULL) 38234345a63Smrg into->leds = rtrn; 38334345a63Smrg else 38434345a63Smrg into->errorCount++; 385f46a6179Smrg } 386f46a6179Smrg return; 387f46a6179Smrg} 388f46a6179Smrg 3896930ead5Smrgtypedef void (*FileHandler) (const XkbFile * /* rtrn */ , 39034345a63Smrg XkbDescPtr /* xkb */ , 39134345a63Smrg unsigned /* merge */ , 39234345a63Smrg CompatInfo * /* info */ 39334345a63Smrg ); 394f46a6179Smrg 395f46a6179Smrgstatic Bool 3966930ead5SmrgHandleIncludeCompatMap(IncludeStmt *stmt, 39734345a63Smrg XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr) 398f46a6179Smrg{ 39934345a63Smrg unsigned newMerge; 40034345a63Smrg XkbFile *rtrn; 40134345a63Smrg CompatInfo included; 40234345a63Smrg Bool haveSelf; 40334345a63Smrg 40434345a63Smrg haveSelf = False; 40534345a63Smrg if ((stmt->file == NULL) && (stmt->map == NULL)) 40634345a63Smrg { 40734345a63Smrg haveSelf = True; 40834345a63Smrg included = *info; 40934345a63Smrg bzero(info, sizeof(CompatInfo)); 41034345a63Smrg } 41134345a63Smrg else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge)) 41234345a63Smrg { 41334345a63Smrg InitCompatInfo(&included, xkb); 41434345a63Smrg included.fileID = rtrn->id; 41534345a63Smrg included.dflt = info->dflt; 41634345a63Smrg included.dflt.defs.fileID = rtrn->id; 41734345a63Smrg included.dflt.defs.merge = newMerge; 41834345a63Smrg included.ledDflt.defs.fileID = rtrn->id; 41934345a63Smrg included.ledDflt.defs.merge = newMerge; 42034345a63Smrg included.act = info->act; 42134345a63Smrg (*hndlr) (rtrn, xkb, MergeOverride, &included); 42234345a63Smrg if (stmt->stmt != NULL) 42334345a63Smrg { 4246930ead5Smrg free(included.name); 42534345a63Smrg included.name = stmt->stmt; 42634345a63Smrg stmt->stmt = NULL; 42734345a63Smrg } 42834345a63Smrg } 42934345a63Smrg else 43034345a63Smrg { 43134345a63Smrg info->errorCount += 10; 43234345a63Smrg return False; 43334345a63Smrg } 43434345a63Smrg if ((stmt->next != NULL) && (included.errorCount < 1)) 43534345a63Smrg { 43634345a63Smrg IncludeStmt *next; 43734345a63Smrg unsigned op; 43834345a63Smrg CompatInfo next_incl; 43934345a63Smrg 44034345a63Smrg for (next = stmt->next; next != NULL; next = next->next) 44134345a63Smrg { 44234345a63Smrg if ((next->file == NULL) && (next->map == NULL)) 44334345a63Smrg { 44434345a63Smrg haveSelf = True; 44534345a63Smrg MergeIncludedCompatMaps(&included, info, next->merge); 44634345a63Smrg ClearCompatInfo(info, xkb); 44734345a63Smrg } 44834345a63Smrg else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op)) 44934345a63Smrg { 45034345a63Smrg InitCompatInfo(&next_incl, xkb); 45134345a63Smrg next_incl.fileID = rtrn->id; 45234345a63Smrg next_incl.dflt = info->dflt; 45334345a63Smrg next_incl.dflt.defs.fileID = rtrn->id; 45434345a63Smrg next_incl.dflt.defs.merge = op; 45534345a63Smrg next_incl.ledDflt.defs.fileID = rtrn->id; 45634345a63Smrg next_incl.ledDflt.defs.merge = op; 45734345a63Smrg next_incl.act = info->act; 45834345a63Smrg (*hndlr) (rtrn, xkb, MergeOverride, &next_incl); 45934345a63Smrg MergeIncludedCompatMaps(&included, &next_incl, op); 46034345a63Smrg ClearCompatInfo(&next_incl, xkb); 46134345a63Smrg } 46234345a63Smrg else 46334345a63Smrg { 46434345a63Smrg info->errorCount += 10; 46534345a63Smrg return False; 46634345a63Smrg } 46734345a63Smrg } 468f46a6179Smrg } 469f46a6179Smrg if (haveSelf) 47034345a63Smrg *info = included; 47134345a63Smrg else 47234345a63Smrg { 47334345a63Smrg MergeIncludedCompatMaps(info, &included, newMerge); 47434345a63Smrg ClearCompatInfo(&included, xkb); 475f46a6179Smrg } 47634345a63Smrg return (info->errorCount == 0); 477f46a6179Smrg} 478f46a6179Smrg 479f46a6179Smrgstatic LookupEntry useModMapValues[] = { 48034345a63Smrg {"levelone", 1}, 48134345a63Smrg {"level1", 1}, 48234345a63Smrg {"anylevel", 0}, 48334345a63Smrg {"any", 0}, 48434345a63Smrg {NULL, 0} 485f46a6179Smrg}; 486f46a6179Smrg 487f46a6179Smrgstatic int 4886930ead5SmrgSetInterpField(SymInterpInfo *si, XkbDescPtr xkb, const char *field, 4896930ead5Smrg const ExprDef *arrayNdx, const ExprDef *value, 4906930ead5Smrg const CompatInfo *info) 491f46a6179Smrg{ 49234345a63Smrg int ok = 1; 49334345a63Smrg ExprResult tmp; 49434345a63Smrg 49534345a63Smrg if (uStrCaseCmp(field, "action") == 0) 49634345a63Smrg { 49734345a63Smrg if (arrayNdx != NULL) 49834345a63Smrg return ReportSINotArray(si, field, info); 49934345a63Smrg ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge, 50034345a63Smrg info->act); 50134345a63Smrg if (ok) 50234345a63Smrg si->defs.defined |= _SI_Action; 50334345a63Smrg } 50434345a63Smrg else if ((uStrCaseCmp(field, "virtualmodifier") == 0) || 50534345a63Smrg (uStrCaseCmp(field, "virtualmod") == 0)) 50634345a63Smrg { 50734345a63Smrg if (arrayNdx != NULL) 50834345a63Smrg return ReportSINotArray(si, field, info); 50934345a63Smrg ok = ResolveVirtualModifier(value, &tmp, &info->vmods); 51034345a63Smrg if (ok) 51134345a63Smrg { 51234345a63Smrg si->interp.virtual_mod = tmp.uval; 51334345a63Smrg si->defs.defined |= _SI_VirtualMod; 51434345a63Smrg } 51534345a63Smrg else 51634345a63Smrg return ReportSIBadType(si, field, "virtual modifier", info); 51734345a63Smrg } 51834345a63Smrg else if (uStrCaseCmp(field, "repeat") == 0) 51934345a63Smrg { 52034345a63Smrg if (arrayNdx != NULL) 52134345a63Smrg return ReportSINotArray(si, field, info); 52234345a63Smrg ok = ExprResolveBoolean(value, &tmp, NULL, NULL); 52334345a63Smrg if (ok) 52434345a63Smrg { 52534345a63Smrg if (tmp.uval) 52634345a63Smrg si->interp.flags |= XkbSI_AutoRepeat; 52734345a63Smrg else 52834345a63Smrg si->interp.flags &= ~XkbSI_AutoRepeat; 52934345a63Smrg si->defs.defined |= _SI_AutoRepeat; 53034345a63Smrg } 53134345a63Smrg else 53234345a63Smrg return ReportSIBadType(si, field, "boolean", info); 53334345a63Smrg } 53434345a63Smrg else if (uStrCaseCmp(field, "locking") == 0) 53534345a63Smrg { 53634345a63Smrg if (arrayNdx != NULL) 53734345a63Smrg return ReportSINotArray(si, field, info); 53834345a63Smrg ok = ExprResolveBoolean(value, &tmp, NULL, NULL); 53934345a63Smrg if (ok) 54034345a63Smrg { 54134345a63Smrg if (tmp.uval) 54234345a63Smrg si->interp.flags |= XkbSI_LockingKey; 54334345a63Smrg else 54434345a63Smrg si->interp.flags &= ~XkbSI_LockingKey; 54534345a63Smrg si->defs.defined |= _SI_LockingKey; 54634345a63Smrg } 54734345a63Smrg else 54834345a63Smrg return ReportSIBadType(si, field, "boolean", info); 54934345a63Smrg } 55034345a63Smrg else if ((uStrCaseCmp(field, "usemodmap") == 0) || 55134345a63Smrg (uStrCaseCmp(field, "usemodmapmods") == 0)) 55234345a63Smrg { 55334345a63Smrg if (arrayNdx != NULL) 55434345a63Smrg return ReportSINotArray(si, field, info); 55534345a63Smrg ok = ExprResolveEnum(value, &tmp, useModMapValues); 55634345a63Smrg if (ok) 55734345a63Smrg { 55834345a63Smrg if (tmp.uval) 55934345a63Smrg si->interp.match |= XkbSI_LevelOneOnly; 56034345a63Smrg else 56134345a63Smrg si->interp.match &= ~XkbSI_LevelOneOnly; 56234345a63Smrg si->defs.defined |= _SI_LevelOneOnly; 56334345a63Smrg } 56434345a63Smrg else 56534345a63Smrg return ReportSIBadType(si, field, "level specification", info); 56634345a63Smrg } 56734345a63Smrg else 56834345a63Smrg { 56934345a63Smrg ok = ReportBadField("symbol interpretation", field, siText(si, info)); 570f46a6179Smrg } 571f46a6179Smrg return ok; 572f46a6179Smrg} 573f46a6179Smrg 57434345a63SmrgLookupEntry groupNames[] = { 57534345a63Smrg {"group1", 0x01} 57634345a63Smrg , 57734345a63Smrg {"group2", 0x02} 57834345a63Smrg , 57934345a63Smrg {"group3", 0x04} 58034345a63Smrg , 58134345a63Smrg {"group4", 0x08} 58234345a63Smrg , 58334345a63Smrg {"group5", 0x10} 58434345a63Smrg , 58534345a63Smrg {"group6", 0x20} 58634345a63Smrg , 58734345a63Smrg {"group7", 0x40} 58834345a63Smrg , 58934345a63Smrg {"group8", 0x80} 59034345a63Smrg , 59134345a63Smrg {"none", 0x00} 59234345a63Smrg , 59334345a63Smrg {"all", 0xff} 59434345a63Smrg , 59534345a63Smrg {NULL, 0} 596f46a6179Smrg}; 597f46a6179Smrg 598f46a6179Smrgstatic int 5996930ead5SmrgHandleInterpVar(const VarDef *stmt, XkbDescPtr xkb, CompatInfo *info) 600f46a6179Smrg{ 60134345a63Smrg ExprResult elem, field; 60234345a63Smrg ExprDef *ndx; 60334345a63Smrg 60434345a63Smrg if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0) 60534345a63Smrg return 0; /* internal error, already reported */ 60634345a63Smrg if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0)) 60734345a63Smrg return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value, 60834345a63Smrg info); 60934345a63Smrg if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0)) 61034345a63Smrg { 61134345a63Smrg return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx, 61234345a63Smrg stmt->value); 61334345a63Smrg } 61434345a63Smrg return SetActionField(xkb, elem.str, field.str, ndx, stmt->value, 61534345a63Smrg &info->act); 616f46a6179Smrg} 617f46a6179Smrg 618f46a6179Smrgstatic int 6196930ead5SmrgHandleInterpBody(const VarDef *def, XkbDescPtr xkb, SymInterpInfo *si, 6206930ead5Smrg CompatInfo *info) 621f46a6179Smrg{ 62234345a63Smrg int ok = 1; 62334345a63Smrg ExprResult tmp, field; 62434345a63Smrg ExprDef *arrayNdx; 62534345a63Smrg 62634345a63Smrg for (; def != NULL; def = (VarDef *) def->common.next) 62734345a63Smrg { 62834345a63Smrg if ((def->name) && (def->name->type == ExprFieldRef)) 62934345a63Smrg { 63034345a63Smrg ok = HandleInterpVar(def, xkb, info); 63134345a63Smrg continue; 63234345a63Smrg } 63334345a63Smrg ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx); 63434345a63Smrg if (ok) 63534345a63Smrg ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value, 63634345a63Smrg info); 637f46a6179Smrg } 638f46a6179Smrg return ok; 639f46a6179Smrg} 640f46a6179Smrg 641f46a6179Smrgstatic int 6426930ead5SmrgHandleInterpDef(const InterpDef *def, XkbDescPtr xkb, unsigned merge, 6436930ead5Smrg CompatInfo *info) 644f46a6179Smrg{ 64534345a63Smrg unsigned pred, mods; 64634345a63Smrg SymInterpInfo si; 64734345a63Smrg 64834345a63Smrg if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) 64934345a63Smrg { 65034345a63Smrg ERROR("Couldn't determine matching modifiers\n"); 65134345a63Smrg ACTION("Symbol interpretation ignored\n"); 652690143ccSmrg return True; 65334345a63Smrg } 654690143ccSmrg if (def->ignore) 655690143ccSmrg { 656690143ccSmrg ERROR("Couldn't lookup keysym\n"); 657690143ccSmrg ACTION("Symbol interpretation ignored\n"); 658690143ccSmrg return True; 659690143ccSmrg } 660690143ccSmrg 66134345a63Smrg if (def->merge != MergeDefault) 66234345a63Smrg merge = def->merge; 66334345a63Smrg 66434345a63Smrg si = info->dflt; 66534345a63Smrg si.defs.merge = merge; 66634345a63Smrg si.interp.sym = def->sym; 66734345a63Smrg si.interp.match = pred & XkbSI_OpMask; 66834345a63Smrg si.interp.mods = mods; 66934345a63Smrg if (!HandleInterpBody(def->def, xkb, &si, info)) 67034345a63Smrg { 67134345a63Smrg info->errorCount++; 67234345a63Smrg return False; 67334345a63Smrg } 67434345a63Smrg 67534345a63Smrg if (!AddInterp(info, &si)) 67634345a63Smrg { 67734345a63Smrg info->errorCount++; 67834345a63Smrg return False; 679f46a6179Smrg } 680f46a6179Smrg return True; 681f46a6179Smrg} 682f46a6179Smrg 683f46a6179Smrgstatic int 6846930ead5SmrgHandleGroupCompatDef(const GroupCompatDef *def, 6856930ead5Smrg XkbDescPtr xkb, unsigned merge, CompatInfo *info) 686f46a6179Smrg{ 68734345a63Smrg ExprResult val; 68834345a63Smrg GroupCompatInfo tmp; 68934345a63Smrg 69034345a63Smrg if (def->merge != MergeDefault) 69134345a63Smrg merge = def->merge; 69234345a63Smrg if (!XkbIsLegalGroup(def->group - 1)) 69334345a63Smrg { 694bfe6082cSmrg ERROR("Keyboard group must be in the range 1..%d\n", 69534345a63Smrg XkbNumKbdGroups + 1); 696bfe6082cSmrg ACTION("Compatibility map for illegal group %d ignored\n", 69734345a63Smrg def->group); 69834345a63Smrg return False; 69934345a63Smrg } 70034345a63Smrg tmp.fileID = info->fileID; 70134345a63Smrg tmp.merge = merge; 70234345a63Smrg if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb)) 70334345a63Smrg { 70434345a63Smrg ERROR("Expected a modifier mask in group compatibility definition\n"); 705bfe6082cSmrg ACTION("Ignoring illegal compatibility map for group %d\n", 70634345a63Smrg def->group); 70734345a63Smrg return False; 70834345a63Smrg } 70934345a63Smrg tmp.real_mods = val.uval & 0xff; 71034345a63Smrg tmp.vmods = (val.uval >> 8) & 0xffff; 7111d8c7986Smrg tmp.defined = True; 71234345a63Smrg return AddGroupCompat(info, def->group - 1, &tmp); 713f46a6179Smrg} 714f46a6179Smrg 715f46a6179Smrgstatic void 7166930ead5SmrgHandleCompatMapFile(const XkbFile *file, 7176930ead5Smrg XkbDescPtr xkb, unsigned merge, CompatInfo *info) 718f46a6179Smrg{ 71934345a63Smrg ParseCommon *stmt; 72034345a63Smrg 72134345a63Smrg if (merge == MergeDefault) 72234345a63Smrg merge = MergeAugment; 72334345a63Smrg info->name = uStringDup(file->name); 72434345a63Smrg stmt = file->defs; 72534345a63Smrg while (stmt) 72634345a63Smrg { 72734345a63Smrg switch (stmt->stmtType) 72834345a63Smrg { 72934345a63Smrg case StmtInclude: 73034345a63Smrg if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info, 73134345a63Smrg HandleCompatMapFile)) 73234345a63Smrg info->errorCount++; 73334345a63Smrg break; 73434345a63Smrg case StmtInterpDef: 73534345a63Smrg if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info)) 73634345a63Smrg info->errorCount++; 73734345a63Smrg break; 73834345a63Smrg case StmtGroupCompatDef: 73934345a63Smrg if (!HandleGroupCompatDef 74034345a63Smrg ((GroupCompatDef *) stmt, xkb, merge, info)) 74134345a63Smrg info->errorCount++; 74234345a63Smrg break; 74334345a63Smrg case StmtIndicatorMapDef: 74434345a63Smrg { 74534345a63Smrg LEDInfo *rtrn; 74634345a63Smrg rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb, 74734345a63Smrg &info->ledDflt, info->leds, merge); 74834345a63Smrg if (rtrn != NULL) 74934345a63Smrg info->leds = rtrn; 75034345a63Smrg else 75134345a63Smrg info->errorCount++; 75234345a63Smrg } 75334345a63Smrg break; 75434345a63Smrg case StmtVarDef: 75534345a63Smrg if (!HandleInterpVar((VarDef *) stmt, xkb, info)) 75634345a63Smrg info->errorCount++; 75734345a63Smrg break; 75834345a63Smrg case StmtVModDef: 75934345a63Smrg if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods)) 76034345a63Smrg info->errorCount++; 76134345a63Smrg break; 76234345a63Smrg case StmtKeycodeDef: 76334345a63Smrg ERROR("Interpretation files may not include other types\n"); 76434345a63Smrg ACTION("Ignoring definition of key name\n"); 76534345a63Smrg info->errorCount++; 76634345a63Smrg break; 76734345a63Smrg default: 768bfe6082cSmrg WSGO("Unexpected statement type %d in HandleCompatMapFile\n", 76934345a63Smrg stmt->stmtType); 77034345a63Smrg break; 77134345a63Smrg } 77234345a63Smrg stmt = stmt->next; 77334345a63Smrg if (info->errorCount > 10) 77434345a63Smrg { 775f46a6179Smrg#ifdef NOISY 77634345a63Smrg ERROR("Too many errors\n"); 777f46a6179Smrg#endif 778bfe6082cSmrg ACTION("Abandoning compatibility map \"%s\"\n", file->topName); 77934345a63Smrg break; 78034345a63Smrg } 781f46a6179Smrg } 782f46a6179Smrg return; 783f46a6179Smrg} 784f46a6179Smrg 785f46a6179Smrgstatic void 7866930ead5SmrgCopyInterps(const CompatInfo *info, 78734345a63Smrg XkbCompatMapPtr compat, Bool needSymbol, unsigned pred) 788f46a6179Smrg{ 7896930ead5Smrg for (SymInterpInfo *si = info->interps; si; 7906930ead5Smrg si = (SymInterpInfo *) si->defs.next) 79134345a63Smrg { 79234345a63Smrg if (((si->interp.match & XkbSI_OpMask) != pred) || 79334345a63Smrg (needSymbol && (si->interp.sym == NoSymbol)) || 79434345a63Smrg ((!needSymbol) && (si->interp.sym != NoSymbol))) 79534345a63Smrg continue; 79634345a63Smrg if (compat->num_si >= compat->size_si) 79734345a63Smrg { 79834345a63Smrg WSGO("No room to merge symbol interpretations\n"); 79934345a63Smrg ACTION("Symbol interpretations lost\n"); 80034345a63Smrg return; 80134345a63Smrg } 80234345a63Smrg compat->sym_interpret[compat->num_si++] = si->interp; 803f46a6179Smrg } 804f46a6179Smrg return; 805f46a6179Smrg} 806f46a6179Smrg 807f46a6179SmrgBool 8086930ead5SmrgCompileCompatMap(const XkbFile *file, 8096930ead5Smrg XkbFileInfo *result, unsigned merge, LEDInfo **unboundLEDs) 810f46a6179Smrg{ 81134345a63Smrg CompatInfo info; 81234345a63Smrg XkbDescPtr xkb; 81334345a63Smrg 81434345a63Smrg xkb = result->xkb; 81534345a63Smrg InitCompatInfo(&info, xkb); 81634345a63Smrg info.dflt.defs.merge = merge; 81734345a63Smrg info.ledDflt.defs.merge = merge; 81834345a63Smrg HandleCompatMapFile(file, xkb, merge, &info); 81934345a63Smrg 82034345a63Smrg if (info.errorCount == 0) 82134345a63Smrg { 8226930ead5Smrg int size, i; 8236930ead5Smrg GroupCompatInfo *gcm; 8246930ead5Smrg 82534345a63Smrg if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) != 82634345a63Smrg Success) 82734345a63Smrg { 82834345a63Smrg WSGO("Couldn't allocate compatibility map\n"); 82934345a63Smrg ACTION("Exiting\n"); 83034345a63Smrg return False; 83134345a63Smrg } 83234345a63Smrg if (info.name != NULL) 83334345a63Smrg { 83434345a63Smrg if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success) 83534345a63Smrg xkb->names->compat = 83634345a63Smrg XkbInternAtom(xkb->dpy, info.name, False); 83734345a63Smrg else 83834345a63Smrg { 83934345a63Smrg WSGO("Couldn't allocate space for compat name\n"); 840bfe6082cSmrg ACTION("Name \"%s\" (from %s) NOT assigned\n", 84134345a63Smrg scanFile, info.name); 84234345a63Smrg } 84334345a63Smrg } 84434345a63Smrg size = info.nInterps * sizeof(XkbSymInterpretRec); 84534345a63Smrg if (size > 0) 84634345a63Smrg { 84734345a63Smrg CopyInterps(&info, xkb->compat, True, XkbSI_Exactly); 84834345a63Smrg CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf); 84934345a63Smrg CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf); 85034345a63Smrg CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone); 85134345a63Smrg CopyInterps(&info, xkb->compat, False, XkbSI_Exactly); 85234345a63Smrg CopyInterps(&info, xkb->compat, False, 85334345a63Smrg XkbSI_AllOf | XkbSI_NoneOf); 85434345a63Smrg CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf); 85534345a63Smrg CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone); 85634345a63Smrg } 85734345a63Smrg for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups; 85834345a63Smrg i++, gcm++) 85934345a63Smrg { 86034345a63Smrg if ((gcm->fileID != 0) || (gcm->real_mods != 0) 86134345a63Smrg || (gcm->vmods != 0)) 86234345a63Smrg { 86334345a63Smrg xkb->compat->groups[i].mask = gcm->real_mods; 86434345a63Smrg xkb->compat->groups[i].real_mods = gcm->real_mods; 86534345a63Smrg xkb->compat->groups[i].vmods = gcm->vmods; 86634345a63Smrg } 86734345a63Smrg } 86834345a63Smrg if (info.leds != NULL) 86934345a63Smrg { 87034345a63Smrg if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs)) 87134345a63Smrg info.errorCount++; 87234345a63Smrg info.leds = NULL; 87334345a63Smrg } 87434345a63Smrg ClearCompatInfo(&info, xkb); 87534345a63Smrg return True; 87634345a63Smrg } 8776930ead5Smrg free(info.interps); 878f46a6179Smrg return False; 879f46a6179Smrg} 880