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
37 typedef 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
49 typedef 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
58 typedef 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
83 static char *
siText(SymInterpInfo * si,CompatInfo * info)84 siText(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
102 static void
InitCompatInfo(CompatInfo * info,XkbDescPtr xkb)103 InitCompatInfo(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
135 static void
ClearCompatInfo(CompatInfo * info,XkbDescPtr xkb)136 ClearCompatInfo(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
163 static SymInterpInfo *
NextInterp(CompatInfo * info)164 NextInterp(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
180 static SymInterpInfo *
FindMatchingInterp(CompatInfo * info,SymInterpInfo * new)181 FindMatchingInterp(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
198 static Bool
AddInterp(CompatInfo * info,SymInterpInfo * new)199 AddInterp(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)
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
265 static Bool
AddGroupCompat(CompatInfo * info,unsigned group,GroupCompatInfo * newGC)266 AddGroupCompat(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
291 static Bool
ResolveStateAndPredicate(ExprDef * expr,unsigned * pred_rtrn,unsigned * mods_rtrn,CompatInfo * info)292 ResolveStateAndPredicate(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
349 static void
MergeIncludedCompatMaps(CompatInfo * into,CompatInfo * from,unsigned merge)350 MergeIncludedCompatMaps(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
395 typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
396 XkbDescPtr /* xkb */ ,
397 unsigned /* merge */ ,
398 CompatInfo * /* info */
399 );
400
401 static Bool
HandleIncludeCompatMap(IncludeStmt * stmt,XkbDescPtr xkb,CompatInfo * info,FileHandler hndlr)402 HandleIncludeCompatMap(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
486 static LookupEntry useModMapValues[] = {
487 {"levelone", 1},
488 {"level1", 1},
489 {"anylevel", 0},
490 {"any", 0},
491 {NULL, 0}
492 };
493
494 static int
SetInterpField(SymInterpInfo * si,XkbDescPtr xkb,const char * field,ExprDef * arrayNdx,ExprDef * value,CompatInfo * info)495 SetInterpField(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
582 LookupEntry 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
606 static int
HandleInterpVar(VarDef * stmt,XkbDescPtr xkb,CompatInfo * info)607 HandleInterpVar(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
626 static int
HandleInterpBody(VarDef * def,XkbDescPtr xkb,SymInterpInfo * si,CompatInfo * info)627 HandleInterpBody(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
649 static int
HandleInterpDef(InterpDef * def,XkbDescPtr xkb,unsigned merge,CompatInfo * info)650 HandleInterpDef(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
691 static int
HandleGroupCompatDef(GroupCompatDef * def,XkbDescPtr xkb,unsigned merge,CompatInfo * info)692 HandleGroupCompatDef(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
723 static void
HandleCompatMapFile(XkbFile * file,XkbDescPtr xkb,unsigned merge,CompatInfo * info)724 HandleCompatMapFile(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
793 static void
CopyInterps(CompatInfo * info,XkbCompatMapPtr compat,Bool needSymbol,unsigned pred)794 CopyInterps(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
816 Bool
CompileCompatMap(XkbFile * file,XkbFileInfo * result,unsigned merge,LEDInfo ** unboundLEDs)817 CompileCompatMap(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