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
53 unsigned char real_mods;
57 typedef struct _CompatInfo
63 SymInterpInfo *interps;
66 GroupCompatInfo groupCompat[XkbNumKbdGroups];
73 /***====================================================================***/
75 #define ReportSINotArray(si,f,i) \
76 ReportNotArray("symbol interpretation",(f),siText((si),(i)))
77 #define ReportSIBadType(si,f,w,i) \
78 ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
80 /***====================================================================***/
83 siText(SymInterpInfo * si, CompatInfo * info)
87 if (si == &info->dflt)
89 snprintf(buf, sizeof(buf), "default");
93 snprintf(buf, sizeof(buf), "%s+%s(%s)",
94 XkbcKeysymText(si->interp.sym),
95 XkbcSIMatchText(si->interp.match),
96 XkbcModMaskText(si->interp.mods, False));
102 InitCompatInfo(CompatInfo * info, XkbcDescPtr xkb)
109 info->errorCount = 0;
111 info->interps = NULL;
113 info->dflt.defs.fileID = info->fileID;
114 info->dflt.defs.defined = 0;
115 info->dflt.defs.merge = MergeOverride;
116 info->dflt.interp.flags = 0;
117 info->dflt.interp.virtual_mod = XkbNoModifier;
118 info->dflt.interp.act.type = XkbSA_NoAction;
119 for (i = 0; i < XkbAnyActionDataSize; i++)
121 info->dflt.interp.act.data[i] = 0;
123 ClearIndicatorMapInfo(&info->ledDflt);
124 info->ledDflt.defs.fileID = info->fileID;
125 info->ledDflt.defs.defined = 0;
126 info->ledDflt.defs.merge = MergeOverride;
127 bzero((char *) &info->groupCompat[0],
128 XkbNumKbdGroups * sizeof(GroupCompatInfo));
130 InitVModInfo(&info->vmods, xkb);
135 ClearCompatInfo(CompatInfo * info, XkbcDescPtr xkb)
139 if (info->name != NULL)
142 info->dflt.defs.defined = 0;
143 info->dflt.defs.merge = MergeAugment;
144 info->dflt.interp.flags = 0;
145 info->dflt.interp.virtual_mod = XkbNoModifier;
146 info->dflt.interp.act.type = XkbSA_NoAction;
147 for (i = 0; i < XkbAnyActionDataSize; i++)
149 info->dflt.interp.act.data[i] = 0;
151 ClearIndicatorMapInfo(&info->ledDflt);
153 info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
154 bzero((char *) &info->groupCompat[0],
155 XkbNumKbdGroups * sizeof(GroupCompatInfo));
156 info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
157 /* 3/30/94 (ef) -- XXX! Should free action info here */
158 ClearVModInfo(&info->vmods, xkb);
162 static SymInterpInfo *
163 NextInterp(CompatInfo * info)
167 si = uTypedAlloc(SymInterpInfo);
170 bzero((char *) si, sizeof(SymInterpInfo));
172 (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
179 static SymInterpInfo *
180 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
184 for (old = info->interps; old != NULL;
185 old = (SymInterpInfo *) old->defs.next)
187 if ((old->interp.sym == new->interp.sym) &&
188 (old->interp.mods == new->interp.mods) &&
189 (old->interp.match == new->interp.match))
198 AddInterp(CompatInfo * info, SymInterpInfo * new)
204 old = FindMatchingInterp(info, new);
207 if (new->defs.merge == MergeReplace)
209 SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
210 if (((old->defs.fileID == new->defs.fileID)
211 && (warningLevel > 0)) || (warningLevel > 9))
213 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
214 ACTION("Earlier interpretation ignored\n");
217 old->defs.next = &next->defs;
220 if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
222 old->interp.virtual_mod = new->interp.virtual_mod;
223 old->defs.defined |= _SI_VirtualMod;
225 if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
227 old->interp.act = new->interp.act;
228 old->defs.defined |= _SI_Action;
230 if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
232 old->interp.flags &= ~XkbSI_AutoRepeat;
233 old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
234 old->defs.defined |= _SI_AutoRepeat;
236 if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
238 old->interp.flags &= ~XkbSI_LockingKey;
239 old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
240 old->defs.defined |= _SI_LockingKey;
242 if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
244 old->interp.match &= ~XkbSI_LevelOneOnly;
245 old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
246 old->defs.defined |= _SI_LevelOneOnly;
250 WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
251 ACTION("Using %s definition for duplicate fields\n",
252 (new->defs.merge != MergeAugment ? "last" : "first"));
257 if ((new = NextInterp(info)) == NULL)
260 new->defs.next = NULL;
265 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
270 merge = newGC->merge;
271 gc = &info->groupCompat[group];
272 if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
276 if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
277 || (warningLevel > 9))
279 WARN("Compat map for group %d redefined\n", group + 1);
280 ACTION("Using %s definition\n",
281 (merge == MergeAugment ? "old" : "new"));
283 if (merge != MergeAugment)
288 /***====================================================================***/
291 ResolveStateAndPredicate(ExprDef * expr,
293 unsigned *mods_rtrn, CompatInfo * info)
299 *pred_rtrn = XkbSI_AnyOfOrNone;
304 *pred_rtrn = XkbSI_Exactly;
305 if (expr->op == ExprActionDecl)
307 char *pred_txt = XkbcAtomText(expr->value.action.name);
308 if (uStrCaseCmp(pred_txt, "noneof") == 0)
309 *pred_rtrn = XkbSI_NoneOf;
310 else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
311 *pred_rtrn = XkbSI_AnyOfOrNone;
312 else if (uStrCaseCmp(pred_txt, "anyof") == 0)
313 *pred_rtrn = XkbSI_AnyOf;
314 else if (uStrCaseCmp(pred_txt, "allof") == 0)
315 *pred_rtrn = XkbSI_AllOf;
316 else if (uStrCaseCmp(pred_txt, "exactly") == 0)
317 *pred_rtrn = XkbSI_Exactly;
320 ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
324 expr = expr->value.action.args;
326 else if (expr->op == ExprIdent)
328 char *pred_txt = XkbcAtomText(expr->value.str);
329 if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
331 *pred_rtrn = XkbSI_AnyOf;
337 if (ExprResolveModMask(expr, &result, NULL, NULL))
339 *mods_rtrn = result.uval;
345 /***====================================================================***/
348 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
351 LEDInfo *led, *rtrn, *next;
352 GroupCompatInfo *gcm;
355 if (from->errorCount > 0)
357 into->errorCount += from->errorCount;
360 if (into->name == NULL)
362 into->name = from->name;
365 for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
367 if (merge != MergeDefault)
368 si->defs.merge = merge;
369 if (!AddInterp(into, si))
372 for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
374 if (merge != MergeDefault)
376 if (!AddGroupCompat(into, i, gcm))
379 for (led = from->leds; led != NULL; led = next)
381 next = (LEDInfo *) led->defs.next;
382 if (merge != MergeDefault)
383 led->defs.merge = merge;
384 rtrn = AddIndicatorMap(into->leds, led);
393 typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
394 XkbcDescPtr /* xkb */ ,
395 unsigned /* merge */ ,
396 CompatInfo * /* info */
400 HandleIncludeCompatMap(IncludeStmt * stmt,
401 XkbcDescPtr xkb, CompatInfo * info, FileHandler hndlr)
409 if ((stmt->file == NULL) && (stmt->map == NULL))
413 bzero(info, sizeof(CompatInfo));
415 else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
417 InitCompatInfo(&included, xkb);
418 included.fileID = rtrn->id;
419 included.dflt = info->dflt;
420 included.dflt.defs.fileID = rtrn->id;
421 included.dflt.defs.merge = newMerge;
422 included.ledDflt.defs.fileID = rtrn->id;
423 included.ledDflt.defs.merge = newMerge;
424 included.act = info->act;
425 (*hndlr) (rtrn, xkb, MergeOverride, &included);
426 if (stmt->stmt != NULL)
428 if (included.name != NULL)
429 uFree(included.name);
430 included.name = stmt->stmt;
436 info->errorCount += 10;
439 if ((stmt->next != NULL) && (included.errorCount < 1))
443 CompatInfo next_incl;
445 for (next = stmt->next; next != NULL; next = next->next)
447 if ((next->file == NULL) && (next->map == NULL))
450 MergeIncludedCompatMaps(&included, info, next->merge);
451 ClearCompatInfo(info, xkb);
453 else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
455 InitCompatInfo(&next_incl, xkb);
456 next_incl.fileID = rtrn->id;
457 next_incl.dflt = info->dflt;
458 next_incl.dflt.defs.fileID = rtrn->id;
459 next_incl.dflt.defs.merge = op;
460 next_incl.ledDflt.defs.fileID = rtrn->id;
461 next_incl.ledDflt.defs.merge = op;
462 next_incl.act = info->act;
463 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
464 MergeIncludedCompatMaps(&included, &next_incl, op);
465 ClearCompatInfo(&next_incl, xkb);
469 info->errorCount += 10;
478 MergeIncludedCompatMaps(info, &included, newMerge);
479 ClearCompatInfo(&included, xkb);
481 return (info->errorCount == 0);
484 static LookupEntry useModMapValues[] = {
493 SetInterpField(SymInterpInfo * si,
496 ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
501 if (uStrCaseCmp(field, "action") == 0)
503 if (arrayNdx != NULL)
504 return ReportSINotArray(si, field, info);
505 ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
508 si->defs.defined |= _SI_Action;
510 else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
511 (uStrCaseCmp(field, "virtualmod") == 0))
513 if (arrayNdx != NULL)
514 return ReportSINotArray(si, field, info);
515 ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
518 si->interp.virtual_mod = tmp.uval;
519 si->defs.defined |= _SI_VirtualMod;
522 return ReportSIBadType(si, field, "virtual modifier", info);
524 else if (uStrCaseCmp(field, "repeat") == 0)
526 if (arrayNdx != NULL)
527 return ReportSINotArray(si, field, info);
528 ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
532 si->interp.flags |= XkbSI_AutoRepeat;
534 si->interp.flags &= ~XkbSI_AutoRepeat;
535 si->defs.defined |= _SI_AutoRepeat;
538 return ReportSIBadType(si, field, "boolean", info);
540 else if (uStrCaseCmp(field, "locking") == 0)
542 if (arrayNdx != NULL)
543 return ReportSINotArray(si, field, info);
544 ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
548 si->interp.flags |= XkbSI_LockingKey;
550 si->interp.flags &= ~XkbSI_LockingKey;
551 si->defs.defined |= _SI_LockingKey;
554 return ReportSIBadType(si, field, "boolean", info);
556 else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
557 (uStrCaseCmp(field, "usemodmapmods") == 0))
559 if (arrayNdx != NULL)
560 return ReportSINotArray(si, field, info);
561 ok = ExprResolveEnum(value, &tmp, useModMapValues);
565 si->interp.match |= XkbSI_LevelOneOnly;
567 si->interp.match &= ~XkbSI_LevelOneOnly;
568 si->defs.defined |= _SI_LevelOneOnly;
571 return ReportSIBadType(si, field, "level specification", info);
575 ok = ReportBadField("symbol interpretation", field, siText(si, info));
580 LookupEntry groupNames[] = {
605 HandleInterpVar(VarDef * stmt, XkbcDescPtr xkb, CompatInfo * info)
607 ExprResult elem, field;
610 if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
611 return 0; /* internal error, already reported */
612 if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
613 return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
615 if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
617 return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
620 return SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
625 HandleInterpBody(VarDef * def, XkbcDescPtr xkb, SymInterpInfo * si,
629 ExprResult tmp, field;
632 for (; def != NULL; def = (VarDef *) def->common.next)
634 if ((def->name) && (def->name->type == ExprFieldRef))
636 ok = HandleInterpVar(def, xkb, info);
639 ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
641 ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
648 HandleInterpDef(InterpDef * def, XkbcDescPtr xkb, unsigned merge,
654 if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
656 ERROR("Couldn't determine matching modifiers\n");
657 ACTION("Symbol interpretation ignored\n");
660 if (def->merge != MergeDefault)
664 si.defs.merge = merge;
665 si.interp.sym = def->sym;
666 si.interp.match = pred & XkbSI_OpMask;
667 si.interp.mods = mods;
668 if (!HandleInterpBody(def->def, xkb, &si, info))
674 if (!AddInterp(info, &si))
683 HandleGroupCompatDef(GroupCompatDef * def,
684 XkbcDescPtr xkb, unsigned merge, CompatInfo * info)
689 if (def->merge != MergeDefault)
691 if (!XkbIsLegalGroup(def->group - 1))
693 ERROR("Keyboard group must be in the range 1..%d\n",
694 XkbNumKbdGroups + 1);
695 ACTION("Compatibility map for illegal group %d ignored\n",
699 tmp.fileID = info->fileID;
701 if (!ExprResolveModMask(def->def, &val, LookupVModMask, (char *) xkb))
703 ERROR("Expected a modifier mask in group compatibility definition\n");
704 ACTION("Ignoring illegal compatibility map for group %d\n",
708 tmp.real_mods = val.uval & 0xff;
709 tmp.vmods = (val.uval >> 8) & 0xffff;
710 return AddGroupCompat(info, def->group - 1, &tmp);
714 HandleCompatMapFile(XkbFile * file,
715 XkbcDescPtr xkb, unsigned merge, CompatInfo * info)
719 if (merge == MergeDefault)
720 merge = MergeAugment;
721 info->name = uStringDup(file->name);
725 switch (stmt->stmtType)
728 if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
729 HandleCompatMapFile))
733 if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
736 case StmtGroupCompatDef:
737 if (!HandleGroupCompatDef
738 ((GroupCompatDef *) stmt, xkb, merge, info))
741 case StmtIndicatorMapDef:
744 rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
745 &info->ledDflt, info->leds, merge);
753 if (!HandleInterpVar((VarDef *) stmt, xkb, info))
757 if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
761 ERROR("Interpretation files may not include other types\n");
762 ACTION("Ignoring definition of key name\n");
766 WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
771 if (info->errorCount > 10)
774 ERROR("Too many errors\n");
776 ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
784 CopyInterps(CompatInfo * info,
785 XkbCompatMapPtr compat, Bool needSymbol, unsigned pred)
789 for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
791 if (((si->interp.match & XkbSI_OpMask) != pred) ||
792 (needSymbol && (si->interp.sym == NoSymbol)) ||
793 ((!needSymbol) && (si->interp.sym != NoSymbol)))
795 if (compat->num_si >= compat->size_si)
797 WSGO("No room to merge symbol interpretations\n");
798 ACTION("Symbol interpretations lost\n");
801 compat->sym_interpret[compat->num_si++] = si->interp;
807 CompileCompatMap(XkbFile *file, XkbcDescPtr xkb, unsigned merge,
808 LEDInfoPtr *unboundLEDs)
812 GroupCompatInfo *gcm;
814 InitCompatInfo(&info, xkb);
815 info.dflt.defs.merge = merge;
816 info.ledDflt.defs.merge = merge;
817 HandleCompatMapFile(file, xkb, merge, &info);
819 if (info.errorCount == 0)
822 if (XkbcAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
825 WSGO("Couldn't allocate compatibility map\n");
829 if (info.name != NULL)
831 if (XkbcAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
833 XkbcInternAtom(info.name, False);
836 WSGO("Couldn't allocate space for compat name\n");
837 ACTION("Name \"%s\" (from %s) NOT assigned\n",
838 scanFile, info.name);
841 size = info.nInterps * sizeof(XkbSymInterpretRec);
844 CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
845 CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
846 CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
847 CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
848 CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
849 CopyInterps(&info, xkb->compat, False,
850 XkbSI_AllOf | XkbSI_NoneOf);
851 CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
852 CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
854 for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
857 if ((gcm->fileID != 0) || (gcm->real_mods != 0)
858 || (gcm->vmods != 0))
860 xkb->compat->groups[i].mask = gcm->real_mods;
861 xkb->compat->groups[i].real_mods = gcm->real_mods;
862 xkb->compat->groups[i].vmods = gcm->vmods;
865 if (info.leds != NULL)
867 if (!CopyIndicatorMapDefs(xkb, info.leds, unboundLEDs))
871 ClearCompatInfo(&info, xkb);
874 if (info.interps != NULL)