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 ********************************************************/
35 #include "indicators.h"
38 #include "parseutils.h"
40 typedef struct _SymInterpInfo
43 XkbcSymInterpretRec interp;
46 #define _SI_VirtualMod (1<<0)
47 #define _SI_Action (1<<1)
48 #define _SI_AutoRepeat (1<<2)
49 #define _SI_LockingKey (1<<3)
50 #define _SI_LevelOneOnly (1<<4)
52 typedef struct _GroupCompatInfo
56 unsigned char real_mods;
60 typedef struct _CompatInfo
66 SymInterpInfo *interps;
69 GroupCompatInfo groupCompat[XkbNumKbdGroups];
76 /***====================================================================***/
78 #define ReportSINotArray(si,f,i) \
79 ReportNotArray("symbol interpretation",(f),siText((si),(i)))
80 #define ReportSIBadType(si,f,w,i) \
81 ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
83 /***====================================================================***/
86 siText(SymInterpInfo * si, CompatInfo * info)
90 if (si == &info->dflt)
92 snprintf(buf, sizeof(buf), "default");
96 snprintf(buf, sizeof(buf), "%s+%s(%s)",
97 XkbcKeysymText(si->interp.sym),
98 XkbcSIMatchText(si->interp.match),
99 XkbcModMaskText(si->interp.mods, False));
105 InitCompatInfo(CompatInfo * info, XkbcDescPtr xkb)
112 info->errorCount = 0;
114 info->interps = NULL;
116 info->dflt.defs.fileID = info->fileID;
117 info->dflt.defs.defined = 0;
118 info->dflt.defs.merge = MergeOverride;
119 info->dflt.interp.flags = 0;
120 info->dflt.interp.virtual_mod = XkbNoModifier;
121 info->dflt.interp.act.type = XkbSA_NoAction;
122 for (i = 0; i < XkbcAnyActionDataSize; i++)
124 info->dflt.interp.act.pad[i] = 0;
126 ClearIndicatorMapInfo(&info->ledDflt);
127 info->ledDflt.defs.fileID = info->fileID;
128 info->ledDflt.defs.defined = 0;
129 info->ledDflt.defs.merge = MergeOverride;
130 bzero((char *) &info->groupCompat[0],
131 XkbNumKbdGroups * sizeof(GroupCompatInfo));
133 InitVModInfo(&info->vmods, xkb);
138 ClearCompatInfo(CompatInfo * info, XkbcDescPtr xkb)
142 if (info->name != NULL)
145 info->dflt.defs.defined = 0;
146 info->dflt.defs.merge = MergeAugment;
147 info->dflt.interp.flags = 0;
148 info->dflt.interp.virtual_mod = XkbNoModifier;
149 info->dflt.interp.act.type = XkbSA_NoAction;
150 for (i = 0; i < XkbcAnyActionDataSize; i++)
152 info->dflt.interp.act.pad[i] = 0;
154 ClearIndicatorMapInfo(&info->ledDflt);
156 info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
157 bzero((char *) &info->groupCompat[0],
158 XkbNumKbdGroups * sizeof(GroupCompatInfo));
159 info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
160 /* 3/30/94 (ef) -- XXX! Should free action info here */
161 ClearVModInfo(&info->vmods, xkb);
165 static SymInterpInfo *
166 NextInterp(CompatInfo * info)
170 si = uTypedAlloc(SymInterpInfo);
173 bzero((char *) si, sizeof(SymInterpInfo));
175 (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
182 static SymInterpInfo *
183 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
187 for (old = info->interps; old != NULL;
188 old = (SymInterpInfo *) old->defs.next)
190 if ((old->interp.sym == new->interp.sym) &&
191 (old->interp.mods == new->interp.mods) &&
192 (old->interp.match == new->interp.match))
201 AddInterp(CompatInfo * info, SymInterpInfo * new)
207 old = FindMatchingInterp(info, new);
210 if (new->defs.merge == MergeReplace)
212 SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
213 if (((old->defs.fileID == new->defs.fileID)
214 && (warningLevel > 0)) || (warningLevel > 9))
216 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
217 ACTION("Earlier interpretation ignored\n");
220 old->defs.next = &next->defs;
223 if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
225 old->interp.virtual_mod = new->interp.virtual_mod;
226 old->defs.defined |= _SI_VirtualMod;
228 if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
230 old->interp.act = new->interp.act;
231 old->defs.defined |= _SI_Action;
233 if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
235 old->interp.flags &= ~XkbSI_AutoRepeat;
236 old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
237 old->defs.defined |= _SI_AutoRepeat;
239 if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
241 old->interp.flags &= ~XkbSI_LockingKey;
242 old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
243 old->defs.defined |= _SI_LockingKey;
245 if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
247 old->interp.match &= ~XkbSI_LevelOneOnly;
248 old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
249 old->defs.defined |= _SI_LevelOneOnly;
253 WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
254 ACTION("Using %s definition for duplicate fields\n",
255 (new->defs.merge != MergeAugment ? "last" : "first"));
260 if ((new = NextInterp(info)) == NULL)
263 new->defs.next = NULL;
268 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
273 merge = newGC->merge;
274 gc = &info->groupCompat[group];
275 if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
279 if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
280 || (warningLevel > 9))
282 WARN("Compat map for group %d redefined\n", group + 1);
283 ACTION("Using %s definition\n",
284 (merge == MergeAugment ? "old" : "new"));
286 if (merge != MergeAugment)
291 /***====================================================================***/
294 ResolveStateAndPredicate(ExprDef * expr,
296 unsigned *mods_rtrn, CompatInfo * info)
302 *pred_rtrn = XkbSI_AnyOfOrNone;
307 *pred_rtrn = XkbSI_Exactly;
308 if (expr->op == ExprActionDecl)
310 char *pred_txt = XkbcAtomText(expr->value.action.name);
311 if (uStrCaseCmp(pred_txt, "noneof") == 0)
312 *pred_rtrn = XkbSI_NoneOf;
313 else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
314 *pred_rtrn = XkbSI_AnyOfOrNone;
315 else if (uStrCaseCmp(pred_txt, "anyof") == 0)
316 *pred_rtrn = XkbSI_AnyOf;
317 else if (uStrCaseCmp(pred_txt, "allof") == 0)
318 *pred_rtrn = XkbSI_AllOf;
319 else if (uStrCaseCmp(pred_txt, "exactly") == 0)
320 *pred_rtrn = XkbSI_Exactly;
323 ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
327 expr = expr->value.action.args;
329 else if (expr->op == ExprIdent)
331 char *pred_txt = XkbcAtomText(expr->value.str);
332 if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
334 *pred_rtrn = XkbSI_AnyOf;
340 if (ExprResolveModMask(expr, &result, NULL, NULL))
342 *mods_rtrn = result.uval;
348 /***====================================================================***/
351 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
354 LEDInfo *led, *rtrn, *next;
355 GroupCompatInfo *gcm;
358 if (from->errorCount > 0)
360 into->errorCount += from->errorCount;
363 if (into->name == NULL)
365 into->name = from->name;
368 for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
370 if (merge != MergeDefault)
371 si->defs.merge = merge;
372 if (!AddInterp(into, si))
375 for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
377 if (merge != MergeDefault)
379 if (!AddGroupCompat(into, i, gcm))
382 for (led = from->leds; led != NULL; led = next)
384 next = (LEDInfo *) led->defs.next;
385 if (merge != MergeDefault)
386 led->defs.merge = merge;
387 rtrn = AddIndicatorMap(into->leds, led);
396 typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
397 XkbcDescPtr /* xkb */ ,
398 unsigned /* merge */ ,
399 CompatInfo * /* info */
403 HandleIncludeCompatMap(IncludeStmt * stmt,
404 XkbcDescPtr xkb, CompatInfo * info, FileHandler hndlr)
412 if ((stmt->file == NULL) && (stmt->map == NULL))
416 bzero(info, sizeof(CompatInfo));
418 else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
420 InitCompatInfo(&included, xkb);
421 included.fileID = rtrn->id;
422 included.dflt = info->dflt;
423 included.dflt.defs.fileID = rtrn->id;
424 included.dflt.defs.merge = newMerge;
425 included.ledDflt.defs.fileID = rtrn->id;
426 included.ledDflt.defs.merge = newMerge;
427 included.act = info->act;
428 (*hndlr) (rtrn, xkb, MergeOverride, &included);
429 if (stmt->stmt != NULL)
431 if (included.name != NULL)
433 included.name = stmt->stmt;
439 info->errorCount += 10;
442 if ((stmt->next != NULL) && (included.errorCount < 1))
446 CompatInfo next_incl;
448 for (next = stmt->next; next != NULL; next = next->next)
450 if ((next->file == NULL) && (next->map == NULL))
453 MergeIncludedCompatMaps(&included, info, next->merge);
454 ClearCompatInfo(info, xkb);
456 else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
458 InitCompatInfo(&next_incl, xkb);
459 next_incl.fileID = rtrn->id;
460 next_incl.dflt = info->dflt;
461 next_incl.dflt.defs.fileID = rtrn->id;
462 next_incl.dflt.defs.merge = op;
463 next_incl.ledDflt.defs.fileID = rtrn->id;
464 next_incl.ledDflt.defs.merge = op;
465 next_incl.act = info->act;
466 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
467 MergeIncludedCompatMaps(&included, &next_incl, op);
468 ClearCompatInfo(&next_incl, xkb);
472 info->errorCount += 10;
481 MergeIncludedCompatMaps(info, &included, newMerge);
482 ClearCompatInfo(&included, xkb);
484 return (info->errorCount == 0);
487 static LookupEntry useModMapValues[] = {
496 SetInterpField(SymInterpInfo * si,
499 ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
504 if (uStrCaseCmp(field, "action") == 0)
506 if (arrayNdx != NULL)
507 return ReportSINotArray(si, field, info);
508 ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
511 si->defs.defined |= _SI_Action;
513 else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
514 (uStrCaseCmp(field, "virtualmod") == 0))
516 if (arrayNdx != NULL)
517 return ReportSINotArray(si, field, info);
518 ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
521 si->interp.virtual_mod = tmp.uval;
522 si->defs.defined |= _SI_VirtualMod;
525 return ReportSIBadType(si, field, "virtual modifier", info);
527 else if (uStrCaseCmp(field, "repeat") == 0)
529 if (arrayNdx != NULL)
530 return ReportSINotArray(si, field, info);
531 ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
535 si->interp.flags |= XkbSI_AutoRepeat;
537 si->interp.flags &= ~XkbSI_AutoRepeat;
538 si->defs.defined |= _SI_AutoRepeat;
541 return ReportSIBadType(si, field, "boolean", info);
543 else if (uStrCaseCmp(field, "locking") == 0)
545 if (arrayNdx != NULL)
546 return ReportSINotArray(si, field, info);
547 ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
551 si->interp.flags |= XkbSI_LockingKey;
553 si->interp.flags &= ~XkbSI_LockingKey;
554 si->defs.defined |= _SI_LockingKey;
557 return ReportSIBadType(si, field, "boolean", info);
559 else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
560 (uStrCaseCmp(field, "usemodmapmods") == 0))
562 if (arrayNdx != NULL)
563 return ReportSINotArray(si, field, info);
564 ok = ExprResolveEnum(value, &tmp, useModMapValues);
568 si->interp.match |= XkbSI_LevelOneOnly;
570 si->interp.match &= ~XkbSI_LevelOneOnly;
571 si->defs.defined |= _SI_LevelOneOnly;
574 return ReportSIBadType(si, field, "level specification", info);
578 ok = ReportBadField("symbol interpretation", field, siText(si, info));
583 LookupEntry groupNames[] = {
608 HandleInterpVar(VarDef * stmt, XkbcDescPtr xkb, CompatInfo * info)
610 ExprResult elem, field;
614 if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
615 ret = 0; /* internal error, already reported */
616 else if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
617 ret = SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
619 else if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
620 ret = SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
623 ret = SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
631 HandleInterpBody(VarDef * def, XkbcDescPtr xkb, SymInterpInfo * si,
635 ExprResult tmp, field;
638 for (; def != NULL; def = (VarDef *) def->common.next)
640 if ((def->name) && (def->name->type == ExprFieldRef))
642 ok = HandleInterpVar(def, xkb, info);
645 ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
647 ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
654 HandleInterpDef(InterpDef * def, XkbcDescPtr xkb, unsigned merge,
660 if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
662 ERROR("Couldn't determine matching modifiers\n");
663 ACTION("Symbol interpretation ignored\n");
666 if (def->merge != MergeDefault)
670 si.defs.merge = merge;
671 if (!LookupKeysym(def->sym, &si.interp.sym))
673 WARN("Could not resolve keysym %s\n", def->sym);
677 si.interp.match = pred & XkbSI_OpMask;
678 si.interp.mods = mods;
679 if (!HandleInterpBody(def->def, xkb, &si, info))
685 if (!AddInterp(info, &si))
694 HandleGroupCompatDef(GroupCompatDef * def,
695 XkbcDescPtr xkb, unsigned merge, CompatInfo * info)
700 if (def->merge != MergeDefault)
702 if (!XkbIsLegalGroup(def->group - 1))
704 ERROR("Keyboard group must be in the range 1..%d\n",
705 XkbNumKbdGroups + 1);
706 ACTION("Compatibility map for illegal group %d ignored\n",
710 tmp.fileID = info->fileID;
712 if (!ExprResolveModMask(def->def, &val, LookupVModMask, (char *) xkb))
714 ERROR("Expected a modifier mask in group compatibility definition\n");
715 ACTION("Ignoring illegal compatibility map for group %d\n",
719 tmp.real_mods = val.uval & 0xff;
720 tmp.vmods = (val.uval >> 8) & 0xffff;
721 return AddGroupCompat(info, def->group - 1, &tmp);
725 HandleCompatMapFile(XkbFile * file,
726 XkbcDescPtr xkb, unsigned merge, CompatInfo * info)
730 if (merge == MergeDefault)
731 merge = MergeAugment;
732 info->name = _XkbDupString(file->name);
736 switch (stmt->stmtType)
739 if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
740 HandleCompatMapFile))
744 if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
747 case StmtGroupCompatDef:
748 if (!HandleGroupCompatDef
749 ((GroupCompatDef *) stmt, xkb, merge, info))
752 case StmtIndicatorMapDef:
755 rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
756 &info->ledDflt, info->leds, merge);
764 if (!HandleInterpVar((VarDef *) stmt, xkb, info))
768 if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
772 ERROR("Interpretation files may not include other types\n");
773 ACTION("Ignoring definition of key name\n");
777 WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
782 if (info->errorCount > 10)
785 ERROR("Too many errors\n");
787 ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
795 CopyInterps(CompatInfo * info,
796 XkbcCompatMapPtr compat, Bool needSymbol, unsigned pred)
800 for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
802 if (((si->interp.match & XkbSI_OpMask) != pred) ||
803 (needSymbol && (si->interp.sym == NoSymbol)) ||
804 ((!needSymbol) && (si->interp.sym != NoSymbol)))
806 if (compat->num_si >= compat->size_si)
808 WSGO("No room to merge symbol interpretations\n");
809 ACTION("Symbol interpretations lost\n");
812 compat->sym_interpret[compat->num_si++] = si->interp;
818 CompileCompatMap(XkbFile *file, XkbcDescPtr xkb, unsigned merge,
819 LEDInfoPtr *unboundLEDs)
823 GroupCompatInfo *gcm;
825 InitCompatInfo(&info, xkb);
826 info.dflt.defs.merge = merge;
827 info.ledDflt.defs.merge = merge;
828 HandleCompatMapFile(file, xkb, merge, &info);
830 if (info.errorCount == 0)
833 if (XkbcAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
836 WSGO("Couldn't allocate compatibility map\n");
839 if (info.name != NULL)
841 if (XkbcAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
843 XkbcInternAtom(info.name, False);
846 WSGO("Couldn't allocate space for compat name\n");
847 ACTION("Name \"%s\" (from %s) NOT assigned\n",
848 scanFile, info.name);
851 size = info.nInterps * sizeof(XkbcSymInterpretRec);
854 CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
855 CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
856 CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
857 CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
858 CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
859 CopyInterps(&info, xkb->compat, False,
860 XkbSI_AllOf | XkbSI_NoneOf);
861 CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
862 CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
864 for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
867 if ((gcm->fileID != 0) || (gcm->real_mods != 0)
868 || (gcm->vmods != 0))
870 xkb->compat->groups[i].mask = gcm->real_mods;
871 xkb->compat->groups[i].real_mods = gcm->real_mods;
872 xkb->compat->groups[i].vmods = gcm->vmods;
875 if (info.leds != NULL)
877 if (!CopyIndicatorMapDefs(xkb, info.leds, unboundLEDs))
881 ClearCompatInfo(&info, xkb);
884 if (info.interps != NULL)