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