1/************************************************************ 2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. 3 4 Permission to use, copy, modify, and distribute this 5 software and its documentation for any purpose and without 6 fee is hereby granted, provided that the above copyright 7 notice appear in all copies and that both that copyright 8 notice and this permission notice appear in supporting 9 documentation, and that the name of Silicon Graphics not be 10 used in advertising or publicity pertaining to distribution 11 of the software without specific prior written permission. 12 Silicon Graphics makes no representation about the suitability 13 of this software for any purpose. It is provided "as is" 14 without any express or implied warranty. 15 16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 23 THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 25 ********************************************************/ 26 27#include <X11/Xos.h> 28#include "xkbcomp.h" 29#include "tokens.h" 30#include "expr.h" 31#include "vmod.h" 32#include "misc.h" 33#include "indicators.h" 34#include "action.h" 35#include "compat.h" 36 37typedef struct _SymInterpInfo 38{ 39 CommonInfo defs; 40 XkbSymInterpretRec interp; 41} SymInterpInfo; 42 43#define _SI_VirtualMod (1<<0) 44#define _SI_Action (1<<1) 45#define _SI_AutoRepeat (1<<2) 46#define _SI_LockingKey (1<<3) 47#define _SI_LevelOneOnly (1<<4) 48 49typedef struct _GroupCompatInfo 50{ 51 unsigned char fileID; 52 unsigned char merge; 53 Bool defined; 54 unsigned char real_mods; 55 unsigned short vmods; 56} GroupCompatInfo; 57 58typedef struct _CompatInfo 59{ 60 char *name; 61 unsigned fileID; 62 int errorCount; 63 int nInterps; 64 SymInterpInfo *interps; 65 SymInterpInfo dflt; 66 LEDInfo ledDflt; 67 GroupCompatInfo groupCompat[XkbNumKbdGroups]; 68 LEDInfo *leds; 69 VModInfo vmods; 70 ActionInfo *act; 71 XkbDescPtr xkb; 72} CompatInfo; 73 74/***====================================================================***/ 75 76#define ReportSINotArray(si,f,i) \ 77 ReportNotArray("symbol interpretation",(f),siText((si),(i))) 78#define ReportSIBadType(si,f,w,i) \ 79 ReportBadType("symbol interpretation",(f),siText((si),(i)),(w)) 80 81/***====================================================================***/ 82 83static char * 84siText(const SymInterpInfo *si, const CompatInfo *info) 85{ 86 static char buf[128]; 87 88 if (si == &info->dflt) 89 { 90 snprintf(buf, sizeof(buf), "default"); 91 } 92 else 93 { 94 snprintf(buf, sizeof(buf), "%s+%s(%s)", 95 XkbKeysymText(si->interp.sym, XkbMessage), 96 XkbSIMatchText(si->interp.match, XkbMessage), 97 XkbModMaskText(si->interp.mods, XkbMessage)); 98 } 99 return buf; 100} 101 102static void 103InitCompatInfo(CompatInfo * info, XkbDescPtr xkb) 104{ 105 info->xkb = xkb; 106 info->name = NULL; 107 info->fileID = 0; 108 info->errorCount = 0; 109 info->nInterps = 0; 110 info->interps = NULL; 111 info->act = NULL; 112 info->dflt.defs.fileID = info->fileID; 113 info->dflt.defs.defined = 0; 114 info->dflt.defs.merge = MergeOverride; 115 info->dflt.interp.flags = 0; 116 info->dflt.interp.virtual_mod = XkbNoModifier; 117 info->dflt.interp.act.type = XkbSA_NoAction; 118 for (int i = 0; i < XkbAnyActionDataSize; i++) 119 { 120 info->dflt.interp.act.data[i] = 0; 121 } 122 ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt); 123 info->ledDflt.defs.fileID = info->fileID; 124 info->ledDflt.defs.defined = 0; 125 info->ledDflt.defs.merge = MergeOverride; 126 bzero(&info->groupCompat[0], XkbNumKbdGroups * sizeof(GroupCompatInfo)); 127 info->leds = NULL; 128 InitVModInfo(&info->vmods, xkb); 129 return; 130} 131 132static void 133ClearCompatInfo(CompatInfo * info, XkbDescPtr xkb) 134{ 135 free(info->name); 136 info->name = NULL; 137 info->dflt.defs.defined = 0; 138 info->dflt.defs.merge = MergeAugment; 139 info->dflt.interp.flags = 0; 140 info->dflt.interp.virtual_mod = XkbNoModifier; 141 info->dflt.interp.act.type = XkbSA_NoAction; 142 for (int i = 0; i < XkbAnyActionDataSize; i++) 143 { 144 info->dflt.interp.act.data[i] = 0; 145 } 146 ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt); 147 info->nInterps = 0; 148 info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs); 149 bzero(&info->groupCompat[0], XkbNumKbdGroups * sizeof(GroupCompatInfo)); 150 info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs); 151 /* 3/30/94 (ef) -- XXX! Should free action info here */ 152 ClearVModInfo(&info->vmods, xkb); 153 return; 154} 155 156static SymInterpInfo * 157NextInterp(CompatInfo * info) 158{ 159 SymInterpInfo *si; 160 161 si = calloc(1, sizeof(SymInterpInfo)); 162 if (si) 163 { 164 info->interps = 165 (SymInterpInfo *) AddCommonInfo(&info->interps->defs, 166 (CommonInfo *) si); 167 info->nInterps++; 168 } 169 return si; 170} 171 172static SymInterpInfo * 173FindMatchingInterp(CompatInfo *info, const SymInterpInfo *new) 174{ 175 SymInterpInfo *old; 176 177 for (old = info->interps; old != NULL; 178 old = (SymInterpInfo *) old->defs.next) 179 { 180 if ((old->interp.sym == new->interp.sym) && 181 (old->interp.mods == new->interp.mods) && 182 (old->interp.match == new->interp.match)) 183 { 184 return old; 185 } 186 } 187 return NULL; 188} 189 190static Bool 191AddInterp(CompatInfo * info, SymInterpInfo * new) 192{ 193 SymInterpInfo *old; 194 195 old = FindMatchingInterp(info, new); 196 if (old != NULL) 197 { 198 unsigned collide = 0; 199 200 if (new->defs.merge == MergeReplace) 201 { 202 SymInterpInfo *next = (SymInterpInfo *) old->defs.next; 203 if (((old->defs.fileID == new->defs.fileID) 204 && (warningLevel > 0)) || (warningLevel > 9)) 205 { 206 WARN("Multiple definitions for \"%s\"\n", siText(new, info)); 207 ACTION("Earlier interpretation ignored\n"); 208 } 209 *old = *new; 210 old->defs.next = &next->defs; 211 return True; 212 } 213 if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide)) 214 { 215 old->interp.virtual_mod = new->interp.virtual_mod; 216 old->defs.defined |= _SI_VirtualMod; 217 } 218 if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide)) 219 { 220 old->interp.act = new->interp.act; 221 old->defs.defined |= _SI_Action; 222 } 223 if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide)) 224 { 225 old->interp.flags &= ~XkbSI_AutoRepeat; 226 old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat); 227 old->defs.defined |= _SI_AutoRepeat; 228 } 229 if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide)) 230 { 231 old->interp.flags &= ~XkbSI_LockingKey; 232 old->interp.flags |= (new->interp.flags & XkbSI_LockingKey); 233 old->defs.defined |= _SI_LockingKey; 234 } 235 if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide)) 236 { 237 old->interp.match &= ~XkbSI_LevelOneOnly; 238 old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly); 239 old->defs.defined |= _SI_LevelOneOnly; 240 } 241 if (collide && (warningLevel > 0)) 242 { 243 WARN("Multiple interpretations of \"%s\"\n", siText(new, info)); 244 ACTION("Using %s definition for duplicate fields\n", 245 (new->defs.merge != MergeAugment ? "last" : "first")); 246 } 247 return True; 248 } 249 old = new; 250 if ((new = NextInterp(info)) == NULL) 251 return False; 252 *new = *old; 253 new->defs.next = NULL; 254 return True; 255} 256 257static Bool 258AddGroupCompat(CompatInfo *info, unsigned group, const GroupCompatInfo *newGC) 259{ 260 GroupCompatInfo *gc; 261 unsigned merge; 262 263 merge = newGC->merge; 264 gc = &info->groupCompat[group]; 265 if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods))) 266 { 267 return True; 268 } 269 if (((gc->defined && gc->fileID == newGC->fileID) && (warningLevel > 0)) 270 || (warningLevel > 9)) 271 { 272 WARN("Compat map for group %d redefined\n", group + 1); 273 ACTION("Using %s definition\n", 274 (merge == MergeAugment ? "old" : "new")); 275 } 276 if(newGC->defined && (merge != MergeAugment || !gc->defined)) 277 *gc = *newGC; 278 return True; 279} 280 281/***====================================================================***/ 282 283static Bool 284ResolveStateAndPredicate(const ExprDef *expr, 285 unsigned *pred_rtrn, unsigned *mods_rtrn, 286 const CompatInfo *info) 287{ 288 ExprResult result; 289 290 if (expr == NULL) 291 { 292 *pred_rtrn = XkbSI_AnyOfOrNone; 293 *mods_rtrn = ~0; 294 return True; 295 } 296 297 *pred_rtrn = XkbSI_Exactly; 298 if (expr->op == ExprActionDecl) 299 { 300 char *pred_txt = 301 XkbAtomText(NULL, expr->value.action.name, XkbMessage); 302 if (uStrCaseCmp(pred_txt, "noneof") == 0) 303 *pred_rtrn = XkbSI_NoneOf; 304 else if (uStrCaseCmp(pred_txt, "anyofornone") == 0) 305 *pred_rtrn = XkbSI_AnyOfOrNone; 306 else if (uStrCaseCmp(pred_txt, "anyof") == 0) 307 *pred_rtrn = XkbSI_AnyOf; 308 else if (uStrCaseCmp(pred_txt, "allof") == 0) 309 *pred_rtrn = XkbSI_AllOf; 310 else if (uStrCaseCmp(pred_txt, "exactly") == 0) 311 *pred_rtrn = XkbSI_Exactly; 312 else 313 { 314 ERROR("Illegal modifier predicate \"%s\"\n", pred_txt); 315 ACTION("Ignored\n"); 316 return False; 317 } 318 expr = expr->value.action.args; 319 } 320 else if (expr->op == ExprIdent) 321 { 322 char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage); 323 if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0)) 324 { 325 *pred_rtrn = XkbSI_AnyOf; 326 *mods_rtrn = 0xff; 327 return True; 328 } 329 } 330 331 if (ExprResolveModMask(expr, &result, NULL, NULL)) 332 { 333 *mods_rtrn = result.uval; 334 return True; 335 } 336 return False; 337} 338 339/***====================================================================***/ 340 341static void 342MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge) 343{ 344 LEDInfo *next; 345 GroupCompatInfo *gcm; 346 int i; 347 348 if (from->errorCount > 0) 349 { 350 into->errorCount += from->errorCount; 351 return; 352 } 353 if (into->name == NULL) 354 { 355 into->name = from->name; 356 from->name = NULL; 357 } 358 for (SymInterpInfo *si = from->interps; si; 359 si = (SymInterpInfo *) si->defs.next) 360 { 361 if (merge != MergeDefault) 362 si->defs.merge = merge; 363 if (!AddInterp(into, si)) 364 into->errorCount++; 365 } 366 for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++) 367 { 368 if (merge != MergeDefault) 369 gcm->merge = merge; 370 if (!AddGroupCompat(into, i, gcm)) 371 into->errorCount++; 372 } 373 for (LEDInfo *led = from->leds; led != NULL; led = next) 374 { 375 LEDInfo *rtrn; 376 377 next = (LEDInfo *) led->defs.next; 378 if (merge != MergeDefault) 379 led->defs.merge = merge; 380 rtrn = AddIndicatorMap(into->leds, led); 381 if (rtrn != NULL) 382 into->leds = rtrn; 383 else 384 into->errorCount++; 385 } 386 return; 387} 388 389typedef void (*FileHandler) (const XkbFile * /* rtrn */ , 390 XkbDescPtr /* xkb */ , 391 unsigned /* merge */ , 392 CompatInfo * /* info */ 393 ); 394 395static Bool 396HandleIncludeCompatMap(IncludeStmt *stmt, 397 XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr) 398{ 399 unsigned newMerge; 400 XkbFile *rtrn; 401 CompatInfo included; 402 Bool haveSelf; 403 404 haveSelf = False; 405 if ((stmt->file == NULL) && (stmt->map == NULL)) 406 { 407 haveSelf = True; 408 included = *info; 409 bzero(info, sizeof(CompatInfo)); 410 } 411 else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge)) 412 { 413 InitCompatInfo(&included, xkb); 414 included.fileID = rtrn->id; 415 included.dflt = info->dflt; 416 included.dflt.defs.fileID = rtrn->id; 417 included.dflt.defs.merge = newMerge; 418 included.ledDflt.defs.fileID = rtrn->id; 419 included.ledDflt.defs.merge = newMerge; 420 included.act = info->act; 421 (*hndlr) (rtrn, xkb, MergeOverride, &included); 422 if (stmt->stmt != NULL) 423 { 424 free(included.name); 425 included.name = stmt->stmt; 426 stmt->stmt = NULL; 427 } 428 } 429 else 430 { 431 info->errorCount += 10; 432 return False; 433 } 434 if ((stmt->next != NULL) && (included.errorCount < 1)) 435 { 436 IncludeStmt *next; 437 unsigned op; 438 CompatInfo next_incl; 439 440 for (next = stmt->next; next != NULL; next = next->next) 441 { 442 if ((next->file == NULL) && (next->map == NULL)) 443 { 444 haveSelf = True; 445 MergeIncludedCompatMaps(&included, info, next->merge); 446 ClearCompatInfo(info, xkb); 447 } 448 else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op)) 449 { 450 InitCompatInfo(&next_incl, xkb); 451 next_incl.fileID = rtrn->id; 452 next_incl.dflt = info->dflt; 453 next_incl.dflt.defs.fileID = rtrn->id; 454 next_incl.dflt.defs.merge = op; 455 next_incl.ledDflt.defs.fileID = rtrn->id; 456 next_incl.ledDflt.defs.merge = op; 457 next_incl.act = info->act; 458 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl); 459 MergeIncludedCompatMaps(&included, &next_incl, op); 460 ClearCompatInfo(&next_incl, xkb); 461 } 462 else 463 { 464 info->errorCount += 10; 465 return False; 466 } 467 } 468 } 469 if (haveSelf) 470 *info = included; 471 else 472 { 473 MergeIncludedCompatMaps(info, &included, newMerge); 474 ClearCompatInfo(&included, xkb); 475 } 476 return (info->errorCount == 0); 477} 478 479static LookupEntry useModMapValues[] = { 480 {"levelone", 1}, 481 {"level1", 1}, 482 {"anylevel", 0}, 483 {"any", 0}, 484 {NULL, 0} 485}; 486 487static int 488SetInterpField(SymInterpInfo *si, XkbDescPtr xkb, const char *field, 489 const ExprDef *arrayNdx, const ExprDef *value, 490 const CompatInfo *info) 491{ 492 int ok = 1; 493 ExprResult tmp; 494 495 if (uStrCaseCmp(field, "action") == 0) 496 { 497 if (arrayNdx != NULL) 498 return ReportSINotArray(si, field, info); 499 ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge, 500 info->act); 501 if (ok) 502 si->defs.defined |= _SI_Action; 503 } 504 else if ((uStrCaseCmp(field, "virtualmodifier") == 0) || 505 (uStrCaseCmp(field, "virtualmod") == 0)) 506 { 507 if (arrayNdx != NULL) 508 return ReportSINotArray(si, field, info); 509 ok = ResolveVirtualModifier(value, &tmp, &info->vmods); 510 if (ok) 511 { 512 si->interp.virtual_mod = tmp.uval; 513 si->defs.defined |= _SI_VirtualMod; 514 } 515 else 516 return ReportSIBadType(si, field, "virtual modifier", info); 517 } 518 else if (uStrCaseCmp(field, "repeat") == 0) 519 { 520 if (arrayNdx != NULL) 521 return ReportSINotArray(si, field, info); 522 ok = ExprResolveBoolean(value, &tmp, NULL, NULL); 523 if (ok) 524 { 525 if (tmp.uval) 526 si->interp.flags |= XkbSI_AutoRepeat; 527 else 528 si->interp.flags &= ~XkbSI_AutoRepeat; 529 si->defs.defined |= _SI_AutoRepeat; 530 } 531 else 532 return ReportSIBadType(si, field, "boolean", info); 533 } 534 else if (uStrCaseCmp(field, "locking") == 0) 535 { 536 if (arrayNdx != NULL) 537 return ReportSINotArray(si, field, info); 538 ok = ExprResolveBoolean(value, &tmp, NULL, NULL); 539 if (ok) 540 { 541 if (tmp.uval) 542 si->interp.flags |= XkbSI_LockingKey; 543 else 544 si->interp.flags &= ~XkbSI_LockingKey; 545 si->defs.defined |= _SI_LockingKey; 546 } 547 else 548 return ReportSIBadType(si, field, "boolean", info); 549 } 550 else if ((uStrCaseCmp(field, "usemodmap") == 0) || 551 (uStrCaseCmp(field, "usemodmapmods") == 0)) 552 { 553 if (arrayNdx != NULL) 554 return ReportSINotArray(si, field, info); 555 ok = ExprResolveEnum(value, &tmp, useModMapValues); 556 if (ok) 557 { 558 if (tmp.uval) 559 si->interp.match |= XkbSI_LevelOneOnly; 560 else 561 si->interp.match &= ~XkbSI_LevelOneOnly; 562 si->defs.defined |= _SI_LevelOneOnly; 563 } 564 else 565 return ReportSIBadType(si, field, "level specification", info); 566 } 567 else 568 { 569 ok = ReportBadField("symbol interpretation", field, siText(si, info)); 570 } 571 return ok; 572} 573 574LookupEntry groupNames[] = { 575 {"group1", 0x01} 576 , 577 {"group2", 0x02} 578 , 579 {"group3", 0x04} 580 , 581 {"group4", 0x08} 582 , 583 {"group5", 0x10} 584 , 585 {"group6", 0x20} 586 , 587 {"group7", 0x40} 588 , 589 {"group8", 0x80} 590 , 591 {"none", 0x00} 592 , 593 {"all", 0xff} 594 , 595 {NULL, 0} 596}; 597 598static int 599HandleInterpVar(const VarDef *stmt, XkbDescPtr xkb, CompatInfo *info) 600{ 601 ExprResult elem, field; 602 ExprDef *ndx; 603 604 if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0) 605 return 0; /* internal error, already reported */ 606 if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0)) 607 return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value, 608 info); 609 if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0)) 610 { 611 return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx, 612 stmt->value); 613 } 614 return SetActionField(xkb, elem.str, field.str, ndx, stmt->value, 615 &info->act); 616} 617 618static int 619HandleInterpBody(const VarDef *def, XkbDescPtr xkb, SymInterpInfo *si, 620 CompatInfo *info) 621{ 622 int ok = 1; 623 ExprResult tmp, field; 624 ExprDef *arrayNdx; 625 626 for (; def != NULL; def = (VarDef *) def->common.next) 627 { 628 if ((def->name) && (def->name->type == ExprFieldRef)) 629 { 630 ok = HandleInterpVar(def, xkb, info); 631 continue; 632 } 633 ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx); 634 if (ok) 635 ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value, 636 info); 637 } 638 return ok; 639} 640 641static int 642HandleInterpDef(const InterpDef *def, XkbDescPtr xkb, unsigned merge, 643 CompatInfo *info) 644{ 645 unsigned pred, mods; 646 SymInterpInfo si; 647 648 if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) 649 { 650 ERROR("Couldn't determine matching modifiers\n"); 651 ACTION("Symbol interpretation ignored\n"); 652 return True; 653 } 654 if (def->ignore) 655 { 656 ERROR("Couldn't lookup keysym\n"); 657 ACTION("Symbol interpretation ignored\n"); 658 return True; 659 } 660 661 if (def->merge != MergeDefault) 662 merge = def->merge; 663 664 si = info->dflt; 665 si.defs.merge = merge; 666 si.interp.sym = def->sym; 667 si.interp.match = pred & XkbSI_OpMask; 668 si.interp.mods = mods; 669 if (!HandleInterpBody(def->def, xkb, &si, info)) 670 { 671 info->errorCount++; 672 return False; 673 } 674 675 if (!AddInterp(info, &si)) 676 { 677 info->errorCount++; 678 return False; 679 } 680 return True; 681} 682 683static int 684HandleGroupCompatDef(const GroupCompatDef *def, 685 XkbDescPtr xkb, unsigned merge, CompatInfo *info) 686{ 687 ExprResult val; 688 GroupCompatInfo tmp; 689 690 if (def->merge != MergeDefault) 691 merge = def->merge; 692 if (!XkbIsLegalGroup(def->group - 1)) 693 { 694 ERROR("Keyboard group must be in the range 1..%d\n", 695 XkbNumKbdGroups + 1); 696 ACTION("Compatibility map for illegal group %d ignored\n", 697 def->group); 698 return False; 699 } 700 tmp.fileID = info->fileID; 701 tmp.merge = merge; 702 if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb)) 703 { 704 ERROR("Expected a modifier mask in group compatibility definition\n"); 705 ACTION("Ignoring illegal compatibility map for group %d\n", 706 def->group); 707 return False; 708 } 709 tmp.real_mods = val.uval & 0xff; 710 tmp.vmods = (val.uval >> 8) & 0xffff; 711 tmp.defined = True; 712 return AddGroupCompat(info, def->group - 1, &tmp); 713} 714 715static void 716HandleCompatMapFile(const XkbFile *file, 717 XkbDescPtr xkb, unsigned merge, CompatInfo *info) 718{ 719 ParseCommon *stmt; 720 721 if (merge == MergeDefault) 722 merge = MergeAugment; 723 info->name = uStringDup(file->name); 724 stmt = file->defs; 725 while (stmt) 726 { 727 switch (stmt->stmtType) 728 { 729 case StmtInclude: 730 if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info, 731 HandleCompatMapFile)) 732 info->errorCount++; 733 break; 734 case StmtInterpDef: 735 if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info)) 736 info->errorCount++; 737 break; 738 case StmtGroupCompatDef: 739 if (!HandleGroupCompatDef 740 ((GroupCompatDef *) stmt, xkb, merge, info)) 741 info->errorCount++; 742 break; 743 case StmtIndicatorMapDef: 744 { 745 LEDInfo *rtrn; 746 rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb, 747 &info->ledDflt, info->leds, merge); 748 if (rtrn != NULL) 749 info->leds = rtrn; 750 else 751 info->errorCount++; 752 } 753 break; 754 case StmtVarDef: 755 if (!HandleInterpVar((VarDef *) stmt, xkb, info)) 756 info->errorCount++; 757 break; 758 case StmtVModDef: 759 if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods)) 760 info->errorCount++; 761 break; 762 case StmtKeycodeDef: 763 ERROR("Interpretation files may not include other types\n"); 764 ACTION("Ignoring definition of key name\n"); 765 info->errorCount++; 766 break; 767 default: 768 WSGO("Unexpected statement type %d in HandleCompatMapFile\n", 769 stmt->stmtType); 770 break; 771 } 772 stmt = stmt->next; 773 if (info->errorCount > 10) 774 { 775#ifdef NOISY 776 ERROR("Too many errors\n"); 777#endif 778 ACTION("Abandoning compatibility map \"%s\"\n", file->topName); 779 break; 780 } 781 } 782 return; 783} 784 785static void 786CopyInterps(const CompatInfo *info, 787 XkbCompatMapPtr compat, Bool needSymbol, unsigned pred) 788{ 789 for (SymInterpInfo *si = info->interps; si; 790 si = (SymInterpInfo *) si->defs.next) 791 { 792 if (((si->interp.match & XkbSI_OpMask) != pred) || 793 (needSymbol && (si->interp.sym == NoSymbol)) || 794 ((!needSymbol) && (si->interp.sym != NoSymbol))) 795 continue; 796 if (compat->num_si >= compat->size_si) 797 { 798 WSGO("No room to merge symbol interpretations\n"); 799 ACTION("Symbol interpretations lost\n"); 800 return; 801 } 802 compat->sym_interpret[compat->num_si++] = si->interp; 803 } 804 return; 805} 806 807Bool 808CompileCompatMap(const XkbFile *file, 809 XkbFileInfo *result, unsigned merge, LEDInfo **unboundLEDs) 810{ 811 CompatInfo info; 812 XkbDescPtr xkb; 813 814 xkb = result->xkb; 815 InitCompatInfo(&info, xkb); 816 info.dflt.defs.merge = merge; 817 info.ledDflt.defs.merge = merge; 818 HandleCompatMapFile(file, xkb, merge, &info); 819 820 if (info.errorCount == 0) 821 { 822 int size, i; 823 GroupCompatInfo *gcm; 824 825 if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) != 826 Success) 827 { 828 WSGO("Couldn't allocate compatibility map\n"); 829 ACTION("Exiting\n"); 830 return False; 831 } 832 if (info.name != NULL) 833 { 834 if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success) 835 xkb->names->compat = 836 XkbInternAtom(xkb->dpy, info.name, False); 837 else 838 { 839 WSGO("Couldn't allocate space for compat name\n"); 840 ACTION("Name \"%s\" (from %s) NOT assigned\n", 841 scanFile, info.name); 842 } 843 } 844 size = info.nInterps * sizeof(XkbSymInterpretRec); 845 if (size > 0) 846 { 847 CopyInterps(&info, xkb->compat, True, XkbSI_Exactly); 848 CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf); 849 CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf); 850 CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone); 851 CopyInterps(&info, xkb->compat, False, XkbSI_Exactly); 852 CopyInterps(&info, xkb->compat, False, 853 XkbSI_AllOf | XkbSI_NoneOf); 854 CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf); 855 CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone); 856 } 857 for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups; 858 i++, gcm++) 859 { 860 if ((gcm->fileID != 0) || (gcm->real_mods != 0) 861 || (gcm->vmods != 0)) 862 { 863 xkb->compat->groups[i].mask = gcm->real_mods; 864 xkb->compat->groups[i].real_mods = gcm->real_mods; 865 xkb->compat->groups[i].vmods = gcm->vmods; 866 } 867 } 868 if (info.leds != NULL) 869 { 870 if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs)) 871 info.errorCount++; 872 info.leds = NULL; 873 } 874 ClearCompatInfo(&info, xkb); 875 return True; 876 } 877 free(info.interps); 878 return False; 879} 880