1 /************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
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.
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.
25 ********************************************************/
33 #include "indicators.h"
37 typedef struct _SymInterpInfo
40 XkbSymInterpretRec interp;
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)
49 typedef struct _GroupCompatInfo
54 unsigned char real_mods;
58 typedef struct _CompatInfo
64 SymInterpInfo *interps;
67 GroupCompatInfo groupCompat[XkbNumKbdGroups];
74 /***====================================================================***/
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))
81 /***====================================================================***/
84 siText(SymInterpInfo * si, CompatInfo * info)
88 if (si == &info->dflt)
90 snprintf(buf, sizeof(buf), "default");
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));
103 InitCompatInfo(CompatInfo * info, XkbDescPtr xkb)
110 info->errorCount = 0;
112 info->interps = 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++)
122 info->dflt.interp.act.data[i] = 0;
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));
131 InitVModInfo(&info->vmods, xkb);
136 ClearCompatInfo(CompatInfo * info, XkbDescPtr xkb)
140 if (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++)
150 info->dflt.interp.act.data[i] = 0;
152 ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
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);
163 static SymInterpInfo *
164 NextInterp(CompatInfo * info)
168 si = uTypedAlloc(SymInterpInfo);
171 bzero((char *) si, sizeof(SymInterpInfo));
173 (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
180 static SymInterpInfo *
181 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
185 for (old = info->interps; old != NULL;
186 old = (SymInterpInfo *) old->defs.next)
188 if ((old->interp.sym == new->interp.sym) &&
189 (old->interp.mods == new->interp.mods) &&
190 (old->interp.match == new->interp.match))
199 AddInterp(CompatInfo * info, SymInterpInfo * new)
205 old = FindMatchingInterp(info, new);
208 if (new->defs.merge == MergeReplace)
210 SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
211 if (((old->defs.fileID == new->defs.fileID)
212 && (warningLevel > 0)) || (warningLevel > 9))
214 WARN1("Multiple definitions for \"%s\"\n", siText(new, info));
215 ACTION("Earlier interpretation ignored\n");
218 old->defs.next = &next->defs;
221 if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
223 old->interp.virtual_mod = new->interp.virtual_mod;
224 old->defs.defined |= _SI_VirtualMod;
226 if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
228 old->interp.act = new->interp.act;
229 old->defs.defined |= _SI_Action;
231 if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
233 old->interp.flags &= ~XkbSI_AutoRepeat;
234 old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
235 old->defs.defined |= _SI_AutoRepeat;
237 if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
239 old->interp.flags &= ~XkbSI_LockingKey;
240 old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
241 old->defs.defined |= _SI_LockingKey;
243 if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
245 old->interp.match &= ~XkbSI_LevelOneOnly;
246 old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
247 old->defs.defined |= _SI_LevelOneOnly;
251 WARN1("Multiple interpretations of \"%s\"\n", siText(new, info));
252 ACTION1("Using %s definition for duplicate fields\n",
253 (new->defs.merge != MergeAugment ? "last" : "first"));
258 if ((new = NextInterp(info)) == NULL)
261 new->defs.next = NULL;
266 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
271 merge = newGC->merge;
272 gc = &info->groupCompat[group];
273 if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
277 if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
278 || (warningLevel > 9))
280 WARN1("Compat map for group %d redefined\n", group + 1);
281 ACTION1("Using %s definition\n",
282 (merge == MergeAugment ? "old" : "new"));
284 if(newGC->defined && (merge != MergeAugment || !gc->defined))
289 /***====================================================================***/
292 ResolveStateAndPredicate(ExprDef * expr,
294 unsigned *mods_rtrn, CompatInfo * info)
300 *pred_rtrn = XkbSI_AnyOfOrNone;
305 *pred_rtrn = XkbSI_Exactly;
306 if (expr->op == ExprActionDecl)
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;
322 ERROR1("Illegal modifier predicate \"%s\"\n", pred_txt);
326 expr = expr->value.action.args;
328 else if (expr->op == ExprIdent)
330 char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage);
331 if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
333 *pred_rtrn = XkbSI_AnyOf;
339 if (ExprResolveModMask(expr, &result, NULL, NULL))
341 *mods_rtrn = result.uval;
347 /***====================================================================***/
350 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
353 LEDInfo *led, *rtrn, *next;
354 GroupCompatInfo *gcm;
357 if (from->errorCount > 0)
359 into->errorCount += from->errorCount;
362 if (into->name == NULL)
364 into->name = from->name;
367 for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
369 if (merge != MergeDefault)
370 si->defs.merge = merge;
371 if (!AddInterp(into, si))
374 for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
376 if (merge != MergeDefault)
378 if (!AddGroupCompat(into, i, gcm))
381 for (led = from->leds; led != NULL; led = next)
383 next = (LEDInfo *) led->defs.next;
384 if (merge != MergeDefault)
385 led->defs.merge = merge;
386 rtrn = AddIndicatorMap(into->leds, led);
395 typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
396 XkbDescPtr /* xkb */ ,
397 unsigned /* merge */ ,
398 CompatInfo * /* info */
402 HandleIncludeCompatMap(IncludeStmt * stmt,
403 XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr)
411 if ((stmt->file == NULL) && (stmt->map == NULL))
415 bzero(info, sizeof(CompatInfo));
417 else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
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)
430 if (included.name != NULL)
431 uFree(included.name);
432 included.name = stmt->stmt;
438 info->errorCount += 10;
441 if ((stmt->next != NULL) && (included.errorCount < 1))
445 CompatInfo next_incl;
447 for (next = stmt->next; next != NULL; next = next->next)
449 if ((next->file == NULL) && (next->map == NULL))
452 MergeIncludedCompatMaps(&included, info, next->merge);
453 ClearCompatInfo(info, xkb);
455 else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
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);
471 info->errorCount += 10;
480 MergeIncludedCompatMaps(info, &included, newMerge);
481 ClearCompatInfo(&included, xkb);
483 return (info->errorCount == 0);
486 static LookupEntry useModMapValues[] = {
495 SetInterpField(SymInterpInfo * si,
498 ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
503 if (uStrCaseCmp(field, "action") == 0)
505 if (arrayNdx != NULL)
506 return ReportSINotArray(si, field, info);
507 ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
510 si->defs.defined |= _SI_Action;
512 else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
513 (uStrCaseCmp(field, "virtualmod") == 0))
515 if (arrayNdx != NULL)
516 return ReportSINotArray(si, field, info);
517 ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
520 si->interp.virtual_mod = tmp.uval;
521 si->defs.defined |= _SI_VirtualMod;
524 return ReportSIBadType(si, field, "virtual modifier", info);
526 else if (uStrCaseCmp(field, "repeat") == 0)
528 if (arrayNdx != NULL)
529 return ReportSINotArray(si, field, info);
530 ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
534 si->interp.flags |= XkbSI_AutoRepeat;
536 si->interp.flags &= ~XkbSI_AutoRepeat;
537 si->defs.defined |= _SI_AutoRepeat;
540 return ReportSIBadType(si, field, "boolean", info);
542 else if (uStrCaseCmp(field, "locking") == 0)
544 if (arrayNdx != NULL)
545 return ReportSINotArray(si, field, info);
546 ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
550 si->interp.flags |= XkbSI_LockingKey;
552 si->interp.flags &= ~XkbSI_LockingKey;
553 si->defs.defined |= _SI_LockingKey;
556 return ReportSIBadType(si, field, "boolean", info);
558 else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
559 (uStrCaseCmp(field, "usemodmapmods") == 0))
561 if (arrayNdx != NULL)
562 return ReportSINotArray(si, field, info);
563 ok = ExprResolveEnum(value, &tmp, useModMapValues);
567 si->interp.match |= XkbSI_LevelOneOnly;
569 si->interp.match &= ~XkbSI_LevelOneOnly;
570 si->defs.defined |= _SI_LevelOneOnly;
573 return ReportSIBadType(si, field, "level specification", info);
577 ok = ReportBadField("symbol interpretation", field, siText(si, info));
582 LookupEntry groupNames[] = {
607 HandleInterpVar(VarDef * stmt, XkbDescPtr xkb, CompatInfo * info)
609 ExprResult elem, field;
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,
617 if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
619 return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
622 return SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
627 HandleInterpBody(VarDef * def, XkbDescPtr xkb, SymInterpInfo * si,
631 ExprResult tmp, field;
634 for (; def != NULL; def = (VarDef *) def->common.next)
636 if ((def->name) && (def->name->type == ExprFieldRef))
638 ok = HandleInterpVar(def, xkb, info);
641 ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
643 ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
650 HandleInterpDef(InterpDef * def, XkbDescPtr xkb, unsigned merge,
656 if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
658 ERROR("Couldn't determine matching modifiers\n");
659 ACTION("Symbol interpretation ignored\n");
664 ERROR("Couldn't lookup keysym\n");
665 ACTION("Symbol interpretation ignored\n");
669 if (def->merge != MergeDefault)
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))
683 if (!AddInterp(info, &si))
692 HandleGroupCompatDef(GroupCompatDef * def,
693 XkbDescPtr xkb, unsigned merge, CompatInfo * info)
698 if (def->merge != MergeDefault)
700 if (!XkbIsLegalGroup(def->group - 1))
702 ERROR1("Keyboard group must be in the range 1..%d\n",
703 XkbNumKbdGroups + 1);
704 ACTION1("Compatibility map for illegal group %d ignored\n",
708 tmp.fileID = info->fileID;
710 if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb))
712 ERROR("Expected a modifier mask in group compatibility definition\n");
713 ACTION1("Ignoring illegal compatibility map for group %d\n",
717 tmp.real_mods = val.uval & 0xff;
718 tmp.vmods = (val.uval >> 8) & 0xffff;
720 return AddGroupCompat(info, def->group - 1, &tmp);
724 HandleCompatMapFile(XkbFile * file,
725 XkbDescPtr xkb, unsigned merge, CompatInfo * info)
729 if (merge == MergeDefault)
730 merge = MergeAugment;
731 info->name = uStringDup(file->name);
735 switch (stmt->stmtType)
738 if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
739 HandleCompatMapFile))
743 if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
746 case StmtGroupCompatDef:
747 if (!HandleGroupCompatDef
748 ((GroupCompatDef *) stmt, xkb, merge, info))
751 case StmtIndicatorMapDef:
754 rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
755 &info->ledDflt, info->leds, merge);
763 if (!HandleInterpVar((VarDef *) stmt, xkb, info))
767 if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
771 ERROR("Interpretation files may not include other types\n");
772 ACTION("Ignoring definition of key name\n");
776 WSGO1("Unexpected statement type %d in HandleCompatMapFile\n",
781 if (info->errorCount > 10)
784 ERROR("Too many errors\n");
786 ACTION1("Abandoning compatibility map \"%s\"\n", file->topName);
794 CopyInterps(CompatInfo * info,
795 XkbCompatMapPtr compat, Bool needSymbol, unsigned pred)
799 for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
801 if (((si->interp.match & XkbSI_OpMask) != pred) ||
802 (needSymbol && (si->interp.sym == NoSymbol)) ||
803 ((!needSymbol) && (si->interp.sym != NoSymbol)))
805 if (compat->num_si >= compat->size_si)
807 WSGO("No room to merge symbol interpretations\n");
808 ACTION("Symbol interpretations lost\n");
811 compat->sym_interpret[compat->num_si++] = si->interp;
817 CompileCompatMap(XkbFile * file,
818 XkbFileInfo * result, unsigned merge, LEDInfo ** unboundLEDs)
823 GroupCompatInfo *gcm;
826 InitCompatInfo(&info, xkb);
827 info.dflt.defs.merge = merge;
828 info.ledDflt.defs.merge = merge;
829 HandleCompatMapFile(file, xkb, merge, &info);
831 if (info.errorCount == 0)
834 if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
837 WSGO("Couldn't allocate compatibility map\n");
841 if (info.name != NULL)
843 if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
845 XkbInternAtom(xkb->dpy, info.name, False);
848 WSGO("Couldn't allocate space for compat name\n");
849 ACTION2("Name \"%s\" (from %s) NOT assigned\n",
850 scanFile, info.name);
853 size = info.nInterps * sizeof(XkbSymInterpretRec);
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);
866 for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
869 if ((gcm->fileID != 0) || (gcm->real_mods != 0)
870 || (gcm->vmods != 0))
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;
877 if (info.leds != NULL)
879 if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs))
883 ClearCompatInfo(&info, xkb);
886 if (info.interps != NULL)