File: | keytypes.c |
Location: | line 600, column 40 |
Description: | Access to field 'indexVMods' results in a dereference of a null pointer (loaded from variable 'old') |
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 "xkbcomp.h" | ||||
28 | #include "tokens.h" | ||||
29 | #include "expr.h" | ||||
30 | #include "vmod.h" | ||||
31 | #include "action.h" | ||||
32 | #include "misc.h" | ||||
33 | |||||
34 | typedef struct _PreserveInfo | ||||
35 | { | ||||
36 | CommonInfo defs; | ||||
37 | short matchingMapIndex; | ||||
38 | unsigned char indexMods; | ||||
39 | unsigned char preMods; | ||||
40 | unsigned short indexVMods; | ||||
41 | unsigned short preVMods; | ||||
42 | } PreserveInfo; | ||||
43 | |||||
44 | #define _KT_Name(1<<0) (1<<0) | ||||
45 | #define _KT_Mask(1<<1) (1<<1) | ||||
46 | #define _KT_Map(1<<2) (1<<2) | ||||
47 | #define _KT_Preserve(1<<3) (1<<3) | ||||
48 | #define _KT_LevelNames(1<<4) (1<<4) | ||||
49 | |||||
50 | typedef struct _KeyTypeInfo | ||||
51 | { | ||||
52 | CommonInfo defs; | ||||
53 | Display *dpy; | ||||
54 | Atom name; | ||||
55 | int fileID; | ||||
56 | unsigned mask; | ||||
57 | unsigned vmask; | ||||
58 | Boolint groupInfo; | ||||
59 | int numLevels; | ||||
60 | int nEntries; | ||||
61 | int szEntries; | ||||
62 | XkbKTMapEntryPtr entries; | ||||
63 | PreserveInfo *preserve; | ||||
64 | int szNames; | ||||
65 | Atom *lvlNames; | ||||
66 | } KeyTypeInfo; | ||||
67 | |||||
68 | typedef struct _KeyTypesInfo | ||||
69 | { | ||||
70 | Display *dpy; | ||||
71 | char *name; | ||||
72 | int errorCount; | ||||
73 | int fileID; | ||||
74 | unsigned stdPresent; | ||||
75 | int nTypes; | ||||
76 | KeyTypeInfo *types; | ||||
77 | KeyTypeInfo dflt; | ||||
78 | VModInfo vmods; | ||||
79 | } KeyTypesInfo; | ||||
80 | |||||
81 | Atom tok_ONE_LEVEL; | ||||
82 | Atom tok_TWO_LEVEL; | ||||
83 | Atom tok_ALPHABETIC; | ||||
84 | Atom tok_KEYPAD; | ||||
85 | |||||
86 | /***====================================================================***/ | ||||
87 | |||||
88 | #define ReportTypeShouldBeArray(t,f)ReportShouldBeArray("key type",(f),XkbAtomText((t)->dpy,(t )->name,3)) \ | ||||
89 | ReportShouldBeArray("key type",(f),TypeTxt(t)XkbAtomText((t)->dpy,(t)->name,3)) | ||||
90 | #define ReportTypeBadType(t,f,w)ReportBadType("key type",(f),XkbAtomText((t)->dpy,(t)-> name,3),(w)) \ | ||||
91 | ReportBadType("key type",(f),TypeTxt(t)XkbAtomText((t)->dpy,(t)->name,3),(w)) | ||||
92 | |||||
93 | /***====================================================================***/ | ||||
94 | |||||
95 | extern Boolint AddMapEntry(XkbDescPtr /* xkb */ , | ||||
96 | KeyTypeInfo * /* type */ , | ||||
97 | XkbKTMapEntryPtr /* new */ , | ||||
98 | Boolint /* clobber */ , | ||||
99 | Boolint /* report */ | ||||
100 | ); | ||||
101 | |||||
102 | extern Boolint AddPreserve(XkbDescPtr /* xkb */ , | ||||
103 | KeyTypeInfo * /* type */ , | ||||
104 | PreserveInfo * /* new */ , | ||||
105 | Boolint /* clobber */ , | ||||
106 | Boolint /* report */ | ||||
107 | ); | ||||
108 | |||||
109 | extern Boolint AddLevelName(KeyTypeInfo * /* type */ , | ||||
110 | unsigned /* level */ , | ||||
111 | Atom /* name */ , | ||||
112 | Boolint /* clobber */ , | ||||
113 | Boolint /* report */ | ||||
114 | ); | ||||
115 | |||||
116 | #define MapEntryTxt(t,x,e)XkbVModMaskText((t)->dpy,(x),(e)->mods.real_mods,(e)-> mods.vmods,3) \ | ||||
117 | XkbVModMaskText((t)->dpy,(x),(e)->mods.real_mods,(e)->mods.vmods,XkbMessage3) | ||||
118 | #define PreserveIndexTxt(t,x,p)XkbVModMaskText((t)->dpy,(x),(p)->indexMods,(p)->indexVMods ,3) \ | ||||
119 | XkbVModMaskText((t)->dpy,(x),(p)->indexMods,(p)->indexVMods,XkbMessage3) | ||||
120 | #define PreserveTxt(t,x,p)XkbVModMaskText((t)->dpy,(x),(p)->preMods,(p)->preVMods ,3) \ | ||||
121 | XkbVModMaskText((t)->dpy,(x),(p)->preMods,(p)->preVMods,XkbMessage3) | ||||
122 | #define TypeTxt(t)XkbAtomText((t)->dpy,(t)->name,3) XkbAtomText((t)->dpy,(t)->name,XkbMessage3) | ||||
123 | #define TypeMaskTxt(t,x)XkbVModMaskText((t)->dpy,(x),(t)->mask,(t)->vmask,3) \ | ||||
124 | XkbVModMaskText((t)->dpy,(x),(t)->mask,(t)->vmask,XkbMessage3) | ||||
125 | |||||
126 | /***====================================================================***/ | ||||
127 | |||||
128 | static void | ||||
129 | InitKeyTypesInfo(KeyTypesInfo * info, XkbDescPtr xkb, KeyTypesInfo * from) | ||||
130 | { | ||||
131 | tok_ONE_LEVEL = XkbInternAtom(NULL((void*)0), "ONE_LEVEL", False0); | ||||
132 | tok_TWO_LEVEL = XkbInternAtom(NULL((void*)0), "TWO_LEVEL", False0); | ||||
133 | tok_ALPHABETIC = XkbInternAtom(NULL((void*)0), "ALPHABETIC", False0); | ||||
134 | tok_KEYPAD = XkbInternAtom(NULL((void*)0), "KEYPAD", False0); | ||||
135 | info->dpy = NULL((void*)0); | ||||
136 | info->name = uStringDup("default")(("default") ? strdup("default") : ((void*)0)); | ||||
137 | info->errorCount = 0; | ||||
138 | info->stdPresent = 0; | ||||
139 | info->nTypes = 0; | ||||
140 | info->types = NULL((void*)0); | ||||
141 | info->dflt.defs.defined = 0; | ||||
142 | info->dflt.defs.fileID = 0; | ||||
143 | info->dflt.defs.merge = MergeOverride2; | ||||
144 | info->dflt.defs.next = NULL((void*)0); | ||||
145 | info->dflt.name = None0L; | ||||
146 | info->dflt.mask = 0; | ||||
147 | info->dflt.vmask = 0; | ||||
148 | info->dflt.groupInfo = False0; | ||||
149 | info->dflt.numLevels = 1; | ||||
150 | info->dflt.nEntries = info->dflt.szEntries = 0; | ||||
151 | info->dflt.entries = NULL((void*)0); | ||||
152 | info->dflt.szNames = 0; | ||||
153 | info->dflt.lvlNames = NULL((void*)0); | ||||
154 | info->dflt.preserve = NULL((void*)0); | ||||
155 | InitVModInfo(&info->vmods, xkb); | ||||
156 | if (from != NULL((void*)0)) | ||||
157 | { | ||||
158 | info->dpy = from->dpy; | ||||
159 | info->dflt = from->dflt; | ||||
160 | if (from->dflt.entries) | ||||
161 | { | ||||
162 | info->dflt.entries = uTypedCalloc(from->dflt.szEntries,((XkbKTMapEntryRec *)uCalloc((unsigned)from->dflt.szEntries ,(unsigned)sizeof(XkbKTMapEntryRec))) | ||||
163 | XkbKTMapEntryRec)((XkbKTMapEntryRec *)uCalloc((unsigned)from->dflt.szEntries ,(unsigned)sizeof(XkbKTMapEntryRec))); | ||||
164 | if (info->dflt.entries) | ||||
165 | { | ||||
166 | unsigned sz = from->dflt.nEntries * sizeof(XkbKTMapEntryRec); | ||||
167 | memcpy(info->dflt.entries, from->dflt.entries, sz); | ||||
168 | } | ||||
169 | } | ||||
170 | if (from->dflt.lvlNames) | ||||
171 | { | ||||
172 | info->dflt.lvlNames = uTypedCalloc(from->dflt.szNames, Atom)((Atom *)uCalloc((unsigned)from->dflt.szNames,(unsigned)sizeof (Atom))); | ||||
173 | if (info->dflt.lvlNames) | ||||
174 | { | ||||
175 | register unsigned sz = from->dflt.szNames * sizeof(Atom); | ||||
176 | memcpy(info->dflt.lvlNames, from->dflt.lvlNames, sz); | ||||
177 | } | ||||
178 | } | ||||
179 | if (from->dflt.preserve) | ||||
180 | { | ||||
181 | PreserveInfo *old, *new, *last; | ||||
182 | last = NULL((void*)0); | ||||
183 | old = from->dflt.preserve; | ||||
184 | for (; old; old = (PreserveInfo *) old->defs.next) | ||||
185 | { | ||||
186 | new = uTypedAlloc(PreserveInfo)((PreserveInfo *)uAlloc((unsigned)sizeof(PreserveInfo))); | ||||
187 | if (!new) | ||||
188 | return; | ||||
189 | *new = *old; | ||||
190 | new->defs.next = NULL((void*)0); | ||||
191 | if (last) | ||||
192 | last->defs.next = (CommonInfo *) new; | ||||
193 | else | ||||
194 | info->dflt.preserve = new; | ||||
195 | last = new; | ||||
196 | } | ||||
197 | } | ||||
198 | } | ||||
199 | return; | ||||
200 | } | ||||
201 | |||||
202 | static void | ||||
203 | FreeKeyTypeInfo(KeyTypeInfo * type) | ||||
204 | { | ||||
205 | if (type->entries != NULL((void*)0)) | ||||
206 | { | ||||
207 | uFree(type->entries); | ||||
208 | type->entries = NULL((void*)0); | ||||
209 | } | ||||
210 | if (type->lvlNames != NULL((void*)0)) | ||||
211 | { | ||||
212 | uFree(type->lvlNames); | ||||
213 | type->lvlNames = NULL((void*)0); | ||||
214 | } | ||||
215 | if (type->preserve != NULL((void*)0)) | ||||
216 | { | ||||
217 | ClearCommonInfo(&type->preserve->defs); | ||||
218 | type->preserve = NULL((void*)0); | ||||
219 | } | ||||
220 | return; | ||||
221 | } | ||||
222 | |||||
223 | static void | ||||
224 | FreeKeyTypesInfo(KeyTypesInfo * info) | ||||
225 | { | ||||
226 | info->dpy = NULL((void*)0); | ||||
227 | if (info->name) | ||||
228 | uFree(info->name); | ||||
229 | info->name = NULL((void*)0); | ||||
230 | if (info->types) | ||||
231 | { | ||||
232 | register KeyTypeInfo *type; | ||||
233 | for (type = info->types; type; type = (KeyTypeInfo *) type->defs.next) | ||||
234 | { | ||||
235 | FreeKeyTypeInfo(type); | ||||
236 | } | ||||
237 | info->types = (KeyTypeInfo *) ClearCommonInfo(&info->types->defs); | ||||
238 | } | ||||
239 | FreeKeyTypeInfo(&info->dflt); | ||||
240 | return; | ||||
241 | } | ||||
242 | |||||
243 | static KeyTypeInfo * | ||||
244 | NextKeyType(KeyTypesInfo * info) | ||||
245 | { | ||||
246 | KeyTypeInfo *type; | ||||
247 | |||||
248 | type = uTypedAlloc(KeyTypeInfo)((KeyTypeInfo *)uAlloc((unsigned)sizeof(KeyTypeInfo))); | ||||
249 | if (type != NULL((void*)0)) | ||||
250 | { | ||||
251 | bzero(type, sizeof(KeyTypeInfo))memset(type,0,sizeof(KeyTypeInfo)); | ||||
252 | type->defs.fileID = info->fileID; | ||||
253 | type->dpy = info->dpy; | ||||
254 | info->types = (KeyTypeInfo *) AddCommonInfo(&info->types->defs, | ||||
255 | (CommonInfo *) type); | ||||
256 | info->nTypes++; | ||||
257 | } | ||||
258 | return type; | ||||
259 | } | ||||
260 | |||||
261 | static KeyTypeInfo * | ||||
262 | FindMatchingKeyType(KeyTypesInfo * info, KeyTypeInfo * new) | ||||
263 | { | ||||
264 | KeyTypeInfo *old; | ||||
265 | |||||
266 | for (old = info->types; old; old = (KeyTypeInfo *) old->defs.next) | ||||
267 | { | ||||
268 | if (old->name == new->name) | ||||
269 | return old; | ||||
270 | } | ||||
271 | return NULL((void*)0); | ||||
272 | } | ||||
273 | |||||
274 | static Boolint | ||||
275 | ReportTypeBadWidth(const char *type, int has, int needs) | ||||
276 | { | ||||
277 | ERROR3uError("Key type \"%s\" has %d levels, must have %d\n", type, has, needs); | ||||
278 | ACTIONuAction("Illegal type definition ignored\n"); | ||||
279 | return False0; | ||||
280 | } | ||||
281 | |||||
282 | static Boolint | ||||
283 | AddKeyType(XkbDescPtr xkb, KeyTypesInfo * info, KeyTypeInfo * new) | ||||
284 | { | ||||
285 | KeyTypeInfo *old; | ||||
286 | |||||
287 | if (new->name == tok_ONE_LEVEL) | ||||
288 | { | ||||
289 | if (new->numLevels > 1) | ||||
290 | return ReportTypeBadWidth("ONE_LEVEL", new->numLevels, 1); | ||||
291 | info->stdPresent |= XkbOneLevelMask(1<<0); | ||||
292 | } | ||||
293 | else if (new->name == tok_TWO_LEVEL) | ||||
294 | { | ||||
295 | if (new->numLevels > 2) | ||||
296 | return ReportTypeBadWidth("TWO_LEVEL", new->numLevels, 2); | ||||
297 | else if (new->numLevels < 2) | ||||
298 | new->numLevels = 2; | ||||
299 | info->stdPresent |= XkbTwoLevelMask(1<<1); | ||||
300 | } | ||||
301 | else if (new->name == tok_ALPHABETIC) | ||||
302 | { | ||||
303 | if (new->numLevels > 2) | ||||
304 | return ReportTypeBadWidth("ALPHABETIC", new->numLevels, 2); | ||||
305 | else if (new->numLevels < 2) | ||||
306 | new->numLevels = 2; | ||||
307 | info->stdPresent |= XkbAlphabeticMask(1<<2); | ||||
308 | } | ||||
309 | else if (new->name == tok_KEYPAD) | ||||
310 | { | ||||
311 | if (new->numLevels > 2) | ||||
312 | return ReportTypeBadWidth("KEYPAD", new->numLevels, 2); | ||||
313 | else if (new->numLevels < 2) | ||||
314 | new->numLevels = 2; | ||||
315 | info->stdPresent |= XkbKeypadMask(1<<3); | ||||
316 | } | ||||
317 | |||||
318 | old = FindMatchingKeyType(info, new); | ||||
319 | if (old != NULL((void*)0)) | ||||
320 | { | ||||
321 | Boolint report; | ||||
322 | if ((new->defs.merge == MergeReplace3) | ||||
323 | || (new->defs.merge == MergeOverride2)) | ||||
324 | { | ||||
325 | KeyTypeInfo *next = (KeyTypeInfo *) old->defs.next; | ||||
326 | if (((old->defs.fileID == new->defs.fileID) | ||||
327 | && (warningLevel > 0)) || (warningLevel > 9)) | ||||
328 | { | ||||
329 | WARN1uWarning("Multiple definitions of the %s key type\n", | ||||
330 | XkbAtomGetString(NULL((void*)0), new->name)); | ||||
331 | ACTIONuAction("Earlier definition ignored\n"); | ||||
332 | } | ||||
333 | FreeKeyTypeInfo(old); | ||||
334 | *old = *new; | ||||
335 | new->szEntries = new->nEntries = 0; | ||||
336 | new->entries = NULL((void*)0); | ||||
337 | new->preserve = NULL((void*)0); | ||||
338 | new->lvlNames = NULL((void*)0); | ||||
339 | old->defs.next = &next->defs; | ||||
340 | return True1; | ||||
341 | } | ||||
342 | report = (old->defs.fileID == new->defs.fileID) && (warningLevel > 0); | ||||
343 | if (report) | ||||
344 | { | ||||
345 | WARN1uWarning("Multiple definitions of the %s key type\n", | ||||
346 | XkbAtomGetString(NULL((void*)0), new->name)); | ||||
347 | ACTIONuAction("Later definition ignored\n"); | ||||
348 | } | ||||
349 | FreeKeyTypeInfo(new); | ||||
350 | return True1; | ||||
351 | } | ||||
352 | old = NextKeyType(info); | ||||
353 | if (old == NULL((void*)0)) | ||||
354 | return False0; | ||||
355 | *old = *new; | ||||
356 | old->defs.next = NULL((void*)0); | ||||
357 | new->nEntries = new->szEntries = 0; | ||||
358 | new->entries = NULL((void*)0); | ||||
359 | new->szNames = 0; | ||||
360 | new->lvlNames = NULL((void*)0); | ||||
361 | new->preserve = NULL((void*)0); | ||||
362 | return True1; | ||||
363 | } | ||||
364 | |||||
365 | /***====================================================================***/ | ||||
366 | |||||
367 | static void | ||||
368 | MergeIncludedKeyTypes(KeyTypesInfo * into, | ||||
369 | KeyTypesInfo * from, unsigned merge, XkbDescPtr xkb) | ||||
370 | { | ||||
371 | KeyTypeInfo *type; | ||||
372 | |||||
373 | if (from->errorCount > 0) | ||||
374 | { | ||||
375 | into->errorCount += from->errorCount; | ||||
376 | return; | ||||
377 | } | ||||
378 | if (into->name == NULL((void*)0)) | ||||
379 | { | ||||
380 | into->name = from->name; | ||||
381 | from->name = NULL((void*)0); | ||||
382 | } | ||||
383 | for (type = from->types; type; type = (KeyTypeInfo *) type->defs.next) | ||||
384 | { | ||||
385 | if (merge != MergeDefault0) | ||||
386 | type->defs.merge = merge; | ||||
387 | if (!AddKeyType(xkb, into, type)) | ||||
388 | into->errorCount++; | ||||
389 | } | ||||
390 | into->stdPresent |= from->stdPresent; | ||||
391 | return; | ||||
392 | } | ||||
393 | |||||
394 | typedef void (*FileHandler) (XkbFile * /* file */ , | ||||
395 | XkbDescPtr /* xkb */ , | ||||
396 | unsigned /* merge */ , | ||||
397 | KeyTypesInfo * /* included */ | ||||
398 | ); | ||||
399 | |||||
400 | static Boolint | ||||
401 | HandleIncludeKeyTypes(IncludeStmt * stmt, | ||||
402 | XkbDescPtr xkb, KeyTypesInfo * info, FileHandler hndlr) | ||||
403 | { | ||||
404 | unsigned newMerge; | ||||
405 | XkbFile *rtrn; | ||||
406 | KeyTypesInfo included; | ||||
407 | Boolint haveSelf; | ||||
408 | |||||
409 | haveSelf = False0; | ||||
410 | if ((stmt->file == NULL((void*)0)) && (stmt->map == NULL((void*)0))) | ||||
411 | { | ||||
412 | haveSelf = True1; | ||||
413 | included = *info; | ||||
414 | bzero(info, sizeof(KeyTypesInfo))memset(info,0,sizeof(KeyTypesInfo)); | ||||
415 | } | ||||
416 | else if (ProcessIncludeFile(stmt, XkmTypesIndex0, &rtrn, &newMerge)) | ||||
417 | { | ||||
418 | InitKeyTypesInfo(&included, xkb, info); | ||||
419 | included.fileID = included.dflt.defs.fileID = rtrn->id; | ||||
420 | included.dflt.defs.merge = newMerge; | ||||
421 | |||||
422 | (*hndlr) (rtrn, xkb, newMerge, &included); | ||||
423 | if (stmt->stmt != NULL((void*)0)) | ||||
424 | { | ||||
425 | if (included.name != NULL((void*)0)) | ||||
426 | uFree(included.name); | ||||
427 | included.name = stmt->stmt; | ||||
428 | stmt->stmt = NULL((void*)0); | ||||
429 | } | ||||
430 | } | ||||
431 | else | ||||
432 | { | ||||
433 | info->errorCount += 10; | ||||
434 | return False0; | ||||
435 | } | ||||
436 | if ((stmt->next != NULL((void*)0)) && (included.errorCount < 1)) | ||||
437 | { | ||||
438 | IncludeStmt *next; | ||||
439 | unsigned op; | ||||
440 | KeyTypesInfo next_incl; | ||||
441 | |||||
442 | for (next = stmt->next; next != NULL((void*)0); next = next->next) | ||||
443 | { | ||||
444 | if ((next->file == NULL((void*)0)) && (next->map == NULL((void*)0))) | ||||
445 | { | ||||
446 | haveSelf = True1; | ||||
447 | MergeIncludedKeyTypes(&included, info, next->merge, xkb); | ||||
448 | FreeKeyTypesInfo(info); | ||||
449 | } | ||||
450 | else if (ProcessIncludeFile(next, XkmTypesIndex0, &rtrn, &op)) | ||||
451 | { | ||||
452 | InitKeyTypesInfo(&next_incl, xkb, &included); | ||||
453 | next_incl.fileID = next_incl.dflt.defs.fileID = rtrn->id; | ||||
454 | next_incl.dflt.defs.merge = op; | ||||
455 | (*hndlr) (rtrn, xkb, op, &next_incl); | ||||
456 | MergeIncludedKeyTypes(&included, &next_incl, op, xkb); | ||||
457 | FreeKeyTypesInfo(&next_incl); | ||||
458 | } | ||||
459 | else | ||||
460 | { | ||||
461 | info->errorCount += 10; | ||||
462 | return False0; | ||||
463 | } | ||||
464 | } | ||||
465 | } | ||||
466 | if (haveSelf) | ||||
467 | *info = included; | ||||
468 | else | ||||
469 | { | ||||
470 | MergeIncludedKeyTypes(info, &included, newMerge, xkb); | ||||
471 | FreeKeyTypesInfo(&included); | ||||
472 | } | ||||
473 | return (info->errorCount == 0); | ||||
474 | } | ||||
475 | |||||
476 | /***====================================================================***/ | ||||
477 | |||||
478 | static XkbKTMapEntryPtr | ||||
479 | FindMatchingMapEntry(KeyTypeInfo * type, unsigned mask, unsigned vmask) | ||||
480 | { | ||||
481 | register int i; | ||||
482 | XkbKTMapEntryPtr entry; | ||||
483 | |||||
484 | for (i = 0, entry = type->entries; i < type->nEntries; i++, entry++) | ||||
485 | { | ||||
486 | if ((entry->mods.real_mods == mask) && (entry->mods.vmods == vmask)) | ||||
487 | return entry; | ||||
488 | } | ||||
489 | return NULL((void*)0); | ||||
490 | } | ||||
491 | |||||
492 | static void | ||||
493 | DeleteLevel1MapEntries(KeyTypeInfo * type) | ||||
494 | { | ||||
495 | register int i, n; | ||||
496 | |||||
497 | for (i = 0; i < type->nEntries; i++) | ||||
498 | { | ||||
499 | if (type->entries[i].level == 0) | ||||
500 | { | ||||
501 | for (n = i; n < type->nEntries - 1; n++) | ||||
502 | { | ||||
503 | type->entries[n] = type->entries[n + 1]; | ||||
504 | } | ||||
505 | type->nEntries--; | ||||
506 | } | ||||
507 | } | ||||
508 | return; | ||||
509 | } | ||||
510 | |||||
511 | /** | ||||
512 | * Return a pointer to the next free XkbKTMapEntry, reallocating space if | ||||
513 | * necessary. | ||||
514 | */ | ||||
515 | static XkbKTMapEntryPtr | ||||
516 | NextMapEntry(KeyTypeInfo * type) | ||||
517 | { | ||||
518 | if (type->entries == NULL((void*)0)) | ||||
519 | { | ||||
520 | type->entries = uTypedCalloc(2, XkbKTMapEntryRec)((XkbKTMapEntryRec *)uCalloc((unsigned)2,(unsigned)sizeof(XkbKTMapEntryRec ))); | ||||
521 | if (type->entries == NULL((void*)0)) | ||||
522 | { | ||||
523 | ERROR1uError("Couldn't allocate map entries for %s\n", TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
524 | ACTIONuAction("Map entries lost\n"); | ||||
525 | return NULL((void*)0); | ||||
526 | } | ||||
527 | type->szEntries = 2; | ||||
528 | type->nEntries = 0; | ||||
529 | } | ||||
530 | else if (type->nEntries >= type->szEntries) | ||||
531 | { | ||||
532 | type->szEntries *= 2; | ||||
533 | type->entries = uTypedRecalloc(type->entries,((XkbKTMapEntryRec *)uRecalloc((Opaque)type->entries,((unsigned )type->nEntries),((unsigned)type->szEntries),sizeof(XkbKTMapEntryRec ))) | ||||
534 | type->nEntries, type->szEntries,((XkbKTMapEntryRec *)uRecalloc((Opaque)type->entries,((unsigned )type->nEntries),((unsigned)type->szEntries),sizeof(XkbKTMapEntryRec ))) | ||||
535 | XkbKTMapEntryRec)((XkbKTMapEntryRec *)uRecalloc((Opaque)type->entries,((unsigned )type->nEntries),((unsigned)type->szEntries),sizeof(XkbKTMapEntryRec ))); | ||||
536 | if (type->entries == NULL((void*)0)) | ||||
537 | { | ||||
538 | ERROR1uError("Couldn't reallocate map entries for %s\n", TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
539 | ACTIONuAction("Map entries lost\n"); | ||||
540 | return NULL((void*)0); | ||||
541 | } | ||||
542 | } | ||||
543 | return &type->entries[type->nEntries++]; | ||||
544 | } | ||||
545 | |||||
546 | Boolint | ||||
547 | AddPreserve(XkbDescPtr xkb, | ||||
548 | KeyTypeInfo * type, PreserveInfo * new, Boolint clobber, Boolint report) | ||||
549 | { | ||||
550 | PreserveInfo *old; | ||||
551 | |||||
552 | old = type->preserve; | ||||
553 | while (old != NULL((void*)0)) | ||||
| |||||
| |||||
554 | { | ||||
555 | if ((old->indexMods != new->indexMods) || | ||||
556 | (old->indexVMods != new->indexVMods)) | ||||
557 | { | ||||
558 | old = (PreserveInfo *) old->defs.next; | ||||
559 | continue; | ||||
560 | } | ||||
561 | if ((old->preMods == new->preMods) | ||||
562 | && (old->preVMods == new->preVMods)) | ||||
563 | { | ||||
564 | if (warningLevel > 9) | ||||
565 | { | ||||
566 | WARN2uWarning("Identical definitions for preserve[%s] in %s\n", | ||||
567 | PreserveIndexTxt(type, xkb, old)XkbVModMaskText((type)->dpy,(xkb),(old)->indexMods,(old )->indexVMods,3), TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
568 | ACTIONuAction("Ignored\n"); | ||||
569 | } | ||||
570 | return True1; | ||||
571 | } | ||||
572 | if (report && (warningLevel > 0)) | ||||
573 | { | ||||
574 | char *str; | ||||
575 | WARN2uWarning("Multiple definitions for preserve[%s] in %s\n", | ||||
576 | PreserveIndexTxt(type, xkb, old)XkbVModMaskText((type)->dpy,(xkb),(old)->indexMods,(old )->indexVMods,3), TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
577 | |||||
578 | if (clobber) | ||||
579 | str = PreserveTxt(type, xkb, new)XkbVModMaskText((type)->dpy,(xkb),(new)->preMods,(new)-> preVMods,3); | ||||
580 | else | ||||
581 | str = PreserveTxt(type, xkb, old)XkbVModMaskText((type)->dpy,(xkb),(old)->preMods,(old)-> preVMods,3); | ||||
582 | ACTION1uAction("Using %s, ", str); | ||||
583 | if (clobber) | ||||
584 | str = PreserveTxt(type, xkb, old)XkbVModMaskText((type)->dpy,(xkb),(old)->preMods,(old)-> preVMods,3); | ||||
585 | else | ||||
586 | str = PreserveTxt(type, xkb, new)XkbVModMaskText((type)->dpy,(xkb),(new)->preMods,(new)-> preVMods,3); | ||||
587 | INFO1uInformation("ignoring %s\n", str); | ||||
588 | } | ||||
589 | if (clobber) | ||||
590 | { | ||||
591 | old->preMods = new->preMods; | ||||
592 | old->preVMods = new->preVMods; | ||||
593 | } | ||||
594 | return True1; | ||||
595 | } | ||||
596 | old = uTypedAlloc(PreserveInfo)((PreserveInfo *)uAlloc((unsigned)sizeof(PreserveInfo))); | ||||
597 | if (!old) | ||||
| |||||
| |||||
598 | { | ||||
599 | WSGO1uInternalError("Couldn't allocate preserve in %s\n", TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
600 | ACTION1uAction("Preserve[%s] lost\n", PreserveIndexTxt(type, xkb, old)XkbVModMaskText((type)->dpy,(xkb),(old)->indexMods,(old )->indexVMods,3)); | ||||
| |||||
601 | return False0; | ||||
602 | } | ||||
603 | *old = *new; | ||||
604 | old->matchingMapIndex = -1; | ||||
605 | type->preserve = | ||||
606 | (PreserveInfo *) AddCommonInfo(&type->preserve->defs, &old->defs); | ||||
607 | return True1; | ||||
608 | } | ||||
609 | |||||
610 | /** | ||||
611 | * Add a new KTMapEntry to the given key type. If an entry with the same mods | ||||
612 | * already exists, the level is updated (if clobber is TRUE). Otherwise, a new | ||||
613 | * entry is created. | ||||
614 | * | ||||
615 | * @param clobber Overwrite existing entry. | ||||
616 | * @param report True if a warning is to be printed on. | ||||
617 | */ | ||||
618 | Boolint | ||||
619 | AddMapEntry(XkbDescPtr xkb, | ||||
620 | KeyTypeInfo * type, | ||||
621 | XkbKTMapEntryPtr new, Boolint clobber, Boolint report) | ||||
622 | { | ||||
623 | XkbKTMapEntryPtr old; | ||||
624 | |||||
625 | if ((old = | ||||
626 | FindMatchingMapEntry(type, new->mods.real_mods, new->mods.vmods))) | ||||
627 | { | ||||
628 | if (report && (old->level != new->level)) | ||||
629 | { | ||||
630 | unsigned use, ignore; | ||||
631 | if (clobber) | ||||
632 | { | ||||
633 | use = new->level + 1; | ||||
634 | ignore = old->level + 1; | ||||
635 | } | ||||
636 | else | ||||
637 | { | ||||
638 | use = old->level + 1; | ||||
639 | ignore = new->level + 1; | ||||
640 | } | ||||
641 | WARN2uWarning("Multiple map entries for %s in %s\n", | ||||
642 | MapEntryTxt(type, xkb, new)XkbVModMaskText((type)->dpy,(xkb),(new)->mods.real_mods ,(new)->mods.vmods,3), TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
643 | ACTION2uAction("Using %d, ignoring %d\n", use, ignore); | ||||
644 | } | ||||
645 | else if (warningLevel > 9) | ||||
646 | { | ||||
647 | WARN3uWarning("Multiple occurences of map[%s]= %d in %s\n", | ||||
648 | MapEntryTxt(type, xkb, new)XkbVModMaskText((type)->dpy,(xkb),(new)->mods.real_mods ,(new)->mods.vmods,3), new->level + 1, TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
649 | ACTIONuAction("Ignored\n"); | ||||
650 | return True1; | ||||
651 | } | ||||
652 | if (clobber) | ||||
653 | old->level = new->level; | ||||
654 | return True1; | ||||
655 | } | ||||
656 | if ((old = NextMapEntry(type)) == NULL((void*)0)) | ||||
657 | return False0; /* allocation failure, already reported */ | ||||
658 | if (new->level >= type->numLevels) | ||||
659 | type->numLevels = new->level + 1; | ||||
660 | if (new->mods.vmods == 0) | ||||
661 | old->active = True1; | ||||
662 | else | ||||
663 | old->active = False0; | ||||
664 | old->mods.mask = new->mods.real_mods; | ||||
665 | old->mods.real_mods = new->mods.real_mods; | ||||
666 | old->mods.vmods = new->mods.vmods; | ||||
667 | old->level = new->level; | ||||
668 | return True1; | ||||
669 | } | ||||
670 | |||||
671 | static LookupEntry lnames[] = { | ||||
672 | {"level1", 1}, | ||||
673 | {"level2", 2}, | ||||
674 | {"level3", 3}, | ||||
675 | {"level4", 4}, | ||||
676 | {"level5", 5}, | ||||
677 | {"level6", 6}, | ||||
678 | {"level7", 7}, | ||||
679 | {"level8", 8}, | ||||
680 | {NULL((void*)0), 0} | ||||
681 | }; | ||||
682 | |||||
683 | static Boolint | ||||
684 | SetMapEntry(KeyTypeInfo * type, | ||||
685 | XkbDescPtr xkb, ExprDef * arrayNdx, ExprDef * value) | ||||
686 | { | ||||
687 | ExprResult rtrn; | ||||
688 | XkbKTMapEntryRec entry; | ||||
689 | |||||
690 | if (arrayNdx == NULL((void*)0)) | ||||
691 | return ReportTypeShouldBeArray(type, "map entry")ReportShouldBeArray("key type",("map entry"),XkbAtomText((type )->dpy,(type)->name,3)); | ||||
692 | if (!ExprResolveModMask(arrayNdx, &rtrn, LookupVModMask, (XPointer) xkb)) | ||||
693 | return ReportTypeBadType(type, "map entry", "modifier mask")ReportBadType("key type",("map entry"),XkbAtomText((type)-> dpy,(type)->name,3),("modifier mask")); | ||||
694 | entry.mods.real_mods = rtrn.uval & 0xff; /* modifiers < 512 */ | ||||
695 | entry.mods.vmods = (rtrn.uval >> 8) & 0xffff; /* modifiers > 512 */ | ||||
696 | if ((entry.mods.real_mods & (~type->mask)) || | ||||
697 | ((entry.mods.vmods & (~type->vmask)) != 0)) | ||||
698 | { | ||||
699 | if (warningLevel > 0) | ||||
700 | { | ||||
701 | WARN1uWarning("Map entry for unused modifiers in %s\n", TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
702 | ACTION1uAction("Using %s instead of ", | ||||
703 | XkbVModMaskText(type->dpy, xkb, | ||||
704 | entry.mods.real_mods & type->mask, | ||||
705 | entry.mods.vmods & type->vmask, | ||||
706 | XkbMessage3)); | ||||
707 | INFO1uInformation("%s\n", MapEntryTxt(type, xkb, &entry)XkbVModMaskText((type)->dpy,(xkb),(&entry)->mods.real_mods ,(&entry)->mods.vmods,3)); | ||||
708 | } | ||||
709 | entry.mods.real_mods &= type->mask; | ||||
710 | entry.mods.vmods &= type->vmask; | ||||
711 | } | ||||
712 | if (!ExprResolveInteger(value, &rtrn, SimpleLookup, (XPointer) lnames)) | ||||
713 | { | ||||
714 | ERRORuError("Level specifications in a key type must be integer\n"); | ||||
715 | ACTIONuAction("Ignoring malformed level specification\n"); | ||||
716 | return False0; | ||||
717 | } | ||||
718 | if ((rtrn.ival < 1) || (rtrn.ival > XkbMaxShiftLevel63 + 1)) | ||||
719 | { | ||||
720 | ERROR3uError("Shift level %d out of range (1..%d) in key type %s\n", | ||||
721 | XkbMaxShiftLevel63 + 1, rtrn.ival, TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
722 | ACTION1uAction("Ignoring illegal definition of map[%s]\n", | ||||
723 | MapEntryTxt(type, xkb, &entry)XkbVModMaskText((type)->dpy,(xkb),(&entry)->mods.real_mods ,(&entry)->mods.vmods,3)); | ||||
724 | return False0; | ||||
725 | } | ||||
726 | entry.level = rtrn.ival - 1; | ||||
727 | return AddMapEntry(xkb, type, &entry, True1, True1); | ||||
728 | } | ||||
729 | |||||
730 | static Boolint | ||||
731 | SetPreserve(KeyTypeInfo * type, | ||||
732 | XkbDescPtr xkb, ExprDef * arrayNdx, ExprDef * value) | ||||
733 | { | ||||
734 | ExprResult rtrn; | ||||
735 | PreserveInfo new; | ||||
736 | |||||
737 | if (arrayNdx == NULL((void*)0)) | ||||
738 | return ReportTypeShouldBeArray(type, "preserve entry")ReportShouldBeArray("key type",("preserve entry"),XkbAtomText ((type)->dpy,(type)->name,3)); | ||||
739 | if (!ExprResolveModMask(arrayNdx, &rtrn, LookupVModMask, (XPointer) xkb)) | ||||
740 | return ReportTypeBadType(type, "preserve entry", "modifier mask")ReportBadType("key type",("preserve entry"),XkbAtomText((type )->dpy,(type)->name,3),("modifier mask")); | ||||
741 | new.defs = type->defs; | ||||
742 | new.defs.next = NULL((void*)0); | ||||
743 | new.indexMods = rtrn.uval & 0xff; | ||||
744 | new.indexVMods = (rtrn.uval >> 8) & 0xffff; | ||||
745 | if ((new.indexMods & (~type->mask)) || (new.indexVMods & (~type->vmask))) | ||||
746 | { | ||||
747 | if (warningLevel > 0) | ||||
748 | { | ||||
749 | WARN1uWarning("Preserve for modifiers not used by the %s type\n", | ||||
750 | TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
751 | ACTION1uAction("Index %s converted to ", | ||||
752 | PreserveIndexTxt(type, xkb, &new)XkbVModMaskText((type)->dpy,(xkb),(&new)->indexMods ,(&new)->indexVMods,3)); | ||||
753 | } | ||||
754 | new.indexMods &= type->mask; | ||||
755 | new.indexVMods &= type->vmask; | ||||
756 | if (warningLevel > 0) | ||||
757 | INFO1uInformation("%s\n", PreserveIndexTxt(type, xkb, &new)XkbVModMaskText((type)->dpy,(xkb),(&new)->indexMods ,(&new)->indexVMods,3)); | ||||
758 | } | ||||
759 | if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb)) | ||||
760 | { | ||||
761 | ERRORuError("Preserve value in a key type is not a modifier mask\n"); | ||||
762 | ACTION2uAction("Ignoring preserve[%s] in type %s\n", | ||||
763 | PreserveIndexTxt(type, xkb, &new)XkbVModMaskText((type)->dpy,(xkb),(&new)->indexMods ,(&new)->indexVMods,3), TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
764 | return False0; | ||||
765 | } | ||||
766 | new.preMods = rtrn.uval & 0xff; | ||||
767 | new.preVMods = (rtrn.uval >> 16) & 0xffff; | ||||
768 | if ((new.preMods & (~new.indexMods)) | ||||
769 | || (new.preVMods && (~new.indexVMods))) | ||||
770 | { | ||||
771 | if (warningLevel > 0) | ||||
772 | { | ||||
773 | WARN2uWarning("Illegal value for preserve[%s] in type %s\n", | ||||
774 | PreserveTxt(type, xkb, &new)XkbVModMaskText((type)->dpy,(xkb),(&new)->preMods,( &new)->preVMods,3), TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
775 | ACTION1uAction("Converted %s to ", PreserveIndexTxt(type, xkb, &new)XkbVModMaskText((type)->dpy,(xkb),(&new)->indexMods ,(&new)->indexVMods,3)); | ||||
776 | } | ||||
777 | new.preMods &= new.indexMods; | ||||
778 | new.preVMods &= new.indexVMods; | ||||
779 | if (warningLevel > 0) | ||||
780 | { | ||||
781 | INFO1uInformation("%s\n", PreserveIndexTxt(type, xkb, &new)XkbVModMaskText((type)->dpy,(xkb),(&new)->indexMods ,(&new)->indexVMods,3)); | ||||
782 | } | ||||
783 | } | ||||
784 | return AddPreserve(xkb, type, &new, True1, True1); | ||||
785 | } | ||||
786 | |||||
787 | /***====================================================================***/ | ||||
788 | |||||
789 | Boolint | ||||
790 | AddLevelName(KeyTypeInfo * type, | ||||
791 | unsigned level, Atom name, Boolint clobber, Boolint report) | ||||
792 | { | ||||
793 | if ((type->lvlNames == NULL((void*)0)) || (type->szNames <= level)) | ||||
794 | { | ||||
795 | type->lvlNames = | ||||
796 | uTypedRecalloc(type->lvlNames, type->szNames, level + 1, Atom)((Atom *)uRecalloc((Opaque)type->lvlNames,((unsigned)type-> szNames),((unsigned)level + 1),sizeof(Atom))); | ||||
797 | if (type->lvlNames == NULL((void*)0)) | ||||
798 | { | ||||
799 | ERROR1uError("Couldn't allocate level names for type %s\n", | ||||
800 | TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
801 | ACTIONuAction("Level names lost\n"); | ||||
802 | type->szNames = 0; | ||||
803 | return False0; | ||||
804 | } | ||||
805 | type->szNames = level + 1; | ||||
806 | } | ||||
807 | else if (type->lvlNames[level] == name) | ||||
808 | { | ||||
809 | if (warningLevel > 9) | ||||
810 | { | ||||
811 | WARN2uWarning("Duplicate names for level %d of key type %s\n", | ||||
812 | level + 1, TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
813 | ACTIONuAction("Ignored\n"); | ||||
814 | } | ||||
815 | return True1; | ||||
816 | } | ||||
817 | else if (type->lvlNames[level] != None0L) | ||||
818 | { | ||||
819 | if (warningLevel > 0) | ||||
820 | { | ||||
821 | char *old, *new; | ||||
822 | old = XkbAtomText(type->dpy, type->lvlNames[level], XkbMessage3); | ||||
823 | new = XkbAtomText(type->dpy, name, XkbMessage3); | ||||
824 | WARN2uWarning("Multiple names for level %d of key type %s\n", | ||||
825 | level + 1, TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
826 | if (clobber) | ||||
827 | ACTION2uAction("Using %s, ignoring %s\n", new, old); | ||||
828 | else | ||||
829 | ACTION2uAction("Using %s, ignoring %s\n", old, new); | ||||
830 | } | ||||
831 | if (!clobber) | ||||
832 | return True1; | ||||
833 | } | ||||
834 | if (level >= type->numLevels) | ||||
835 | type->numLevels = level + 1; | ||||
836 | type->lvlNames[level] = name; | ||||
837 | return True1; | ||||
838 | } | ||||
839 | |||||
840 | static Boolint | ||||
841 | SetLevelName(KeyTypeInfo * type, ExprDef * arrayNdx, ExprDef * value) | ||||
842 | { | ||||
843 | ExprResult rtrn; | ||||
844 | unsigned level; | ||||
845 | |||||
846 | if (arrayNdx == NULL((void*)0)) | ||||
847 | return ReportTypeShouldBeArray(type, "level name")ReportShouldBeArray("key type",("level name"),XkbAtomText((type )->dpy,(type)->name,3)); | ||||
848 | if (!ExprResolveInteger(arrayNdx, &rtrn, SimpleLookup, (XPointer) lnames)) | ||||
849 | return ReportTypeBadType(type, "level name", "integer")ReportBadType("key type",("level name"),XkbAtomText((type)-> dpy,(type)->name,3),("integer")); | ||||
850 | if ((rtrn.ival < 1) || (rtrn.ival > XkbMaxShiftLevel63 + 1)) | ||||
851 | { | ||||
852 | ERROR3uError("Level name %d out of range (1..%d) in key type %s\n", | ||||
853 | rtrn.ival, | ||||
854 | XkbMaxShiftLevel63 + 1, | ||||
855 | XkbAtomText(type->dpy, type->name, XkbMessage3)); | ||||
856 | ACTIONuAction("Ignoring illegal level name definition\n"); | ||||
857 | return False0; | ||||
858 | } | ||||
859 | level = rtrn.ival - 1; | ||||
860 | if (!ExprResolveString(value, &rtrn, NULL((void*)0), NULL((void*)0))) | ||||
861 | { | ||||
862 | ERROR2uError("Non-string name for level %d in key type %s\n", level + 1, | ||||
863 | XkbAtomText(type->dpy, type->name, XkbMessage3)); | ||||
864 | ACTIONuAction("Ignoring illegal level name definition\n"); | ||||
865 | return False0; | ||||
866 | } | ||||
867 | return | ||||
868 | AddLevelName(type, level, XkbInternAtom(NULL((void*)0), rtrn.str, False0), True1, | ||||
869 | True1); | ||||
870 | } | ||||
871 | |||||
872 | /***====================================================================***/ | ||||
873 | |||||
874 | /** | ||||
875 | * Parses the fields in a type "..." { } description. | ||||
876 | * | ||||
877 | * @param field The field to parse (e.g. modifiers, map, level_name) | ||||
878 | */ | ||||
879 | static Boolint | ||||
880 | SetKeyTypeField(KeyTypeInfo * type, | ||||
881 | XkbDescPtr xkb, | ||||
882 | char *field, | ||||
883 | ExprDef * arrayNdx, ExprDef * value, KeyTypesInfo * info) | ||||
884 | { | ||||
885 | ExprResult tmp; | ||||
886 | |||||
887 | if (uStrCaseCmp(field, "modifiers")(strcasecmp(field,"modifiers")) == 0) | ||||
888 | { | ||||
889 | unsigned mods, vmods; | ||||
890 | if (arrayNdx != NULL((void*)0)) | ||||
891 | { | ||||
892 | WARNuWarning("The modifiers field of a key type is not an array\n"); | ||||
893 | ACTIONuAction("Illegal array subscript ignored\n"); | ||||
894 | } | ||||
895 | /* get modifier mask for current type */ | ||||
896 | if (!ExprResolveModMask(value, &tmp, LookupVModMask, (XPointer) xkb)) | ||||
897 | { | ||||
898 | ERRORuError("Key type mask field must be a modifier mask\n"); | ||||
899 | ACTIONuAction("Key type definition ignored\n"); | ||||
900 | return False0; | ||||
901 | } | ||||
902 | mods = tmp.uval & 0xff; /* core mods */ | ||||
903 | vmods = (tmp.uval >> 8) & 0xffff; /* xkb virtual mods */ | ||||
904 | if (type->defs.defined & _KT_Mask(1<<1)) | ||||
905 | { | ||||
906 | WARN1uWarning("Multiple modifier mask definitions for key type %s\n", | ||||
907 | XkbAtomText(type->dpy, type->name, XkbMessage3)); | ||||
908 | ACTION1uAction("Using %s, ", TypeMaskTxt(type, xkb)XkbVModMaskText((type)->dpy,(xkb),(type)->mask,(type)-> vmask,3)); | ||||
909 | INFO1uInformation("ignoring %s\n", XkbVModMaskText(type->dpy, xkb, mods, | ||||
910 | vmods, XkbMessage3)); | ||||
911 | return False0; | ||||
912 | } | ||||
913 | type->mask = mods; | ||||
914 | type->vmask = vmods; | ||||
915 | type->defs.defined |= _KT_Mask(1<<1); | ||||
916 | return True1; | ||||
917 | } | ||||
918 | else if (uStrCaseCmp(field, "map")(strcasecmp(field,"map")) == 0) | ||||
919 | { | ||||
920 | type->defs.defined |= _KT_Map(1<<2); | ||||
921 | return SetMapEntry(type, xkb, arrayNdx, value); | ||||
922 | } | ||||
923 | else if (uStrCaseCmp(field, "preserve")(strcasecmp(field,"preserve")) == 0) | ||||
924 | { | ||||
925 | type->defs.defined |= _KT_Preserve(1<<3); | ||||
926 | return SetPreserve(type, xkb, arrayNdx, value); | ||||
927 | } | ||||
928 | else if ((uStrCaseCmp(field, "levelname")(strcasecmp(field,"levelname")) == 0) || | ||||
929 | (uStrCaseCmp(field, "level_name")(strcasecmp(field,"level_name")) == 0)) | ||||
930 | { | ||||
931 | type->defs.defined |= _KT_LevelNames(1<<4); | ||||
932 | return SetLevelName(type, arrayNdx, value); | ||||
933 | } | ||||
934 | ERROR2uError("Unknown field %s in key type %s\n", field, TypeTxt(type)XkbAtomText((type)->dpy,(type)->name,3)); | ||||
935 | ACTIONuAction("Definition ignored\n"); | ||||
936 | return False0; | ||||
937 | } | ||||
938 | |||||
939 | static Boolint | ||||
940 | HandleKeyTypeVar(VarDef * stmt, XkbDescPtr xkb, KeyTypesInfo * info) | ||||
941 | { | ||||
942 | ExprResult elem, field; | ||||
943 | ExprDef *arrayNdx; | ||||
944 | |||||
945 | if (!ExprResolveLhs(stmt->name, &elem, &field, &arrayNdx)) | ||||
946 | return False0; /* internal error, already reported */ | ||||
947 | if (elem.str && (uStrCaseCmp(elem.str, "type")(strcasecmp(elem.str,"type")) == 0)) | ||||
948 | return SetKeyTypeField(&info->dflt, xkb, field.str, arrayNdx, | ||||
949 | stmt->value, info); | ||||
950 | if (elem.str != NULL((void*)0)) | ||||
951 | { | ||||
952 | ERROR1uError("Default for unknown element %s\n", uStringText(elem.str)((elem.str)==((char *)((void*)0))?"<NullString>":(elem. str))); | ||||
953 | ACTION1uAction("Value for field %s ignored\n", uStringText(field.str)((field.str)==((char *)((void*)0))?"<NullString>":(field .str))); | ||||
954 | } | ||||
955 | else if (field.str != NULL((void*)0)) | ||||
956 | { | ||||
957 | ERROR1uError("Default defined for unknown field %s\n", | ||||
958 | uStringText(field.str)((field.str)==((char *)((void*)0))?"<NullString>":(field .str))); | ||||
959 | ACTIONuAction("Ignored\n"); | ||||
960 | } | ||||
961 | return False0; | ||||
962 | } | ||||
963 | |||||
964 | static int | ||||
965 | HandleKeyTypeBody(VarDef * def, | ||||
966 | XkbDescPtr xkb, KeyTypeInfo * type, KeyTypesInfo * info) | ||||
967 | { | ||||
968 | int ok = 1; | ||||
969 | ExprResult tmp, field; | ||||
970 | ExprDef *arrayNdx; | ||||
971 | |||||
972 | for (; def != NULL((void*)0); def = (VarDef *) def->common.next) | ||||
973 | { | ||||
974 | if ((def->name) && (def->name->type == ExprFieldRef3)) | ||||
975 | { | ||||
976 | ok = HandleKeyTypeVar(def, xkb, info); | ||||
977 | continue; | ||||
978 | } | ||||
979 | ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx); | ||||
980 | if (ok) | ||||
981 | ok = SetKeyTypeField(type, xkb, field.str, arrayNdx, def->value, | ||||
982 | info); | ||||
983 | } | ||||
984 | return ok; | ||||
985 | } | ||||
986 | |||||
987 | /** | ||||
988 | * Process a type "XYZ" { } specification in the xkb_types section. | ||||
989 | * | ||||
990 | */ | ||||
991 | static int | ||||
992 | HandleKeyTypeDef(KeyTypeDef * def, | ||||
993 | XkbDescPtr xkb, unsigned merge, KeyTypesInfo * info) | ||||
994 | { | ||||
995 | register int i; | ||||
996 | KeyTypeInfo type; | ||||
997 | |||||
998 | if (def->merge != MergeDefault0) | ||||
999 | merge = def->merge; | ||||
1000 | |||||
1001 | type.defs.defined = 0; | ||||
1002 | type.defs.fileID = info->fileID; | ||||
1003 | type.defs.merge = merge; | ||||
1004 | type.defs.next = NULL((void*)0); | ||||
1005 | type.dpy = info->dpy; | ||||
1006 | type.name = def->name; | ||||
1007 | type.mask = info->dflt.mask; | ||||
1008 | type.vmask = info->dflt.vmask; | ||||
1009 | type.groupInfo = info->dflt.groupInfo; | ||||
1010 | type.numLevels = 1; | ||||
1011 | type.nEntries = type.szEntries = 0; | ||||
1012 | type.entries = NULL((void*)0); | ||||
1013 | type.szNames = 0; | ||||
1014 | type.lvlNames = NULL((void*)0); | ||||
1015 | type.preserve = NULL((void*)0); | ||||
1016 | |||||
1017 | /* Parse the actual content. */ | ||||
1018 | if (!HandleKeyTypeBody(def->body, xkb, &type, info)) | ||||
1019 | { | ||||
1020 | info->errorCount++; | ||||
1021 | return False0; | ||||
1022 | } | ||||
1023 | |||||
1024 | /* now copy any appropriate map, preserve or level names from the */ | ||||
1025 | /* default type */ | ||||
1026 | for (i = 0; i < info->dflt.nEntries; i++) | ||||
1027 | { | ||||
1028 | XkbKTMapEntryPtr dflt; | ||||
1029 | dflt = &info->dflt.entries[i]; | ||||
1030 | if (((dflt->mods.real_mods & type.mask) == dflt->mods.real_mods) && | ||||
1031 | ((dflt->mods.vmods & type.vmask) == dflt->mods.vmods)) | ||||
1032 | { | ||||
1033 | AddMapEntry(xkb, &type, dflt, False0, False0); | ||||
1034 | } | ||||
1035 | } | ||||
1036 | if (info->dflt.preserve) | ||||
1037 | { | ||||
1038 | PreserveInfo *dflt = info->dflt.preserve; | ||||
1039 | while (dflt) | ||||
1040 | { | ||||
1041 | if (((dflt->indexMods & type.mask) == dflt->indexMods) && | ||||
1042 | ((dflt->indexVMods & type.vmask) == dflt->indexVMods)) | ||||
1043 | { | ||||
1044 | AddPreserve(xkb, &type, dflt, False0, False0); | ||||
1045 | } | ||||
1046 | dflt = (PreserveInfo *) dflt->defs.next; | ||||
1047 | } | ||||
1048 | } | ||||
1049 | for (i = 0; i < info->dflt.szNames; i++) | ||||
1050 | { | ||||
1051 | if ((i < type.numLevels) && (info->dflt.lvlNames[i] != None0L)) | ||||
1052 | { | ||||
1053 | AddLevelName(&type, i, info->dflt.lvlNames[i], False0, False0); | ||||
1054 | } | ||||
1055 | } | ||||
1056 | /* Now add the new keytype to the info struct */ | ||||
1057 | if (!AddKeyType(xkb, info, &type)) | ||||
1058 | { | ||||
1059 | info->errorCount++; | ||||
1060 | return False0; | ||||
1061 | } | ||||
1062 | return True1; | ||||
1063 | } | ||||
1064 | |||||
1065 | /** | ||||
1066 | * Process an xkb_types section. | ||||
1067 | * | ||||
1068 | * @param file The parsed xkb_types section. | ||||
1069 | * @param merge Merge Strategy (e.g. MergeOverride) | ||||
1070 | * @param info Pointer to memory where the outcome will be stored. | ||||
1071 | */ | ||||
1072 | static void | ||||
1073 | HandleKeyTypesFile(XkbFile * file, | ||||
1074 | XkbDescPtr xkb, unsigned merge, KeyTypesInfo * info) | ||||
1075 | { | ||||
1076 | ParseCommon *stmt; | ||||
1077 | |||||
1078 | info->name = uStringDup(file->name)((file->name) ? strdup(file->name) : ((void*)0)); | ||||
1079 | stmt = file->defs; | ||||
1080 | while (stmt) | ||||
1081 | { | ||||
1082 | switch (stmt->stmtType) | ||||
1083 | { | ||||
1084 | case StmtInclude1: | ||||
1085 | if (!HandleIncludeKeyTypes((IncludeStmt *) stmt, xkb, info, | ||||
1086 | HandleKeyTypesFile)) | ||||
1087 | info->errorCount++; | ||||
1088 | break; | ||||
1089 | case StmtKeyTypeDef6: /* e.g. type "ONE_LEVEL" */ | ||||
1090 | if (!HandleKeyTypeDef((KeyTypeDef *) stmt, xkb, merge, info)) | ||||
1091 | info->errorCount++; | ||||
1092 | break; | ||||
1093 | case StmtVarDef5: | ||||
1094 | if (!HandleKeyTypeVar((VarDef *) stmt, xkb, info)) | ||||
1095 | info->errorCount++; | ||||
1096 | break; | ||||
1097 | case StmtVModDef8: /* virtual_modifiers NumLock, ... */ | ||||
1098 | if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods)) | ||||
1099 | info->errorCount++; | ||||
1100 | break; | ||||
1101 | case StmtKeyAliasDef3: | ||||
1102 | ERRORuError("Key type files may not include other declarations\n"); | ||||
1103 | ACTIONuAction("Ignoring definition of key alias\n"); | ||||
1104 | info->errorCount++; | ||||
1105 | break; | ||||
1106 | case StmtKeycodeDef2: | ||||
1107 | ERRORuError("Key type files may not include other declarations\n"); | ||||
1108 | ACTIONuAction("Ignoring definition of key name\n"); | ||||
1109 | info->errorCount++; | ||||
1110 | break; | ||||
1111 | case StmtInterpDef7: | ||||
1112 | ERRORuError("Key type files may not include other declarations\n"); | ||||
1113 | ACTIONuAction("Ignoring definition of symbol interpretation\n"); | ||||
1114 | info->errorCount++; | ||||
1115 | break; | ||||
1116 | default: | ||||
1117 | WSGO1uInternalError("Unexpected statement type %d in HandleKeyTypesFile\n", | ||||
1118 | stmt->stmtType); | ||||
1119 | break; | ||||
1120 | } | ||||
1121 | stmt = stmt->next; | ||||
1122 | if (info->errorCount > 10) | ||||
1123 | { | ||||
1124 | #ifdef NOISY | ||||
1125 | ERRORuError("Too many errors\n"); | ||||
1126 | #endif | ||||
1127 | ACTION1uAction("Abandoning keytypes file \"%s\"\n", file->topName); | ||||
1128 | break; | ||||
1129 | } | ||||
1130 | } | ||||
1131 | return; | ||||
1132 | } | ||||
1133 | |||||
1134 | static Boolint | ||||
1135 | CopyDefToKeyType(XkbDescPtr xkb, XkbKeyTypePtr type, KeyTypeInfo * def) | ||||
1136 | { | ||||
1137 | register int i; | ||||
1138 | PreserveInfo *pre; | ||||
1139 | |||||
1140 | for (pre = def->preserve; pre != NULL((void*)0); | ||||
1141 | pre = (PreserveInfo *) pre->defs.next) | ||||
1142 | { | ||||
1143 | XkbKTMapEntryPtr match; | ||||
1144 | XkbKTMapEntryRec tmp; | ||||
1145 | tmp.mods.real_mods = pre->indexMods; | ||||
1146 | tmp.mods.vmods = pre->indexVMods; | ||||
1147 | tmp.level = 0; | ||||
1148 | AddMapEntry(xkb, def, &tmp, False0, False0); | ||||
1149 | match = FindMatchingMapEntry(def, pre->indexMods, pre->indexVMods); | ||||
1150 | if (!match) | ||||
1151 | { | ||||
1152 | WSGOuInternalError("Couldn't find matching entry for preserve\n"); | ||||
1153 | ACTIONuAction("Aborting\n"); | ||||
1154 | return False0; | ||||
1155 | } | ||||
1156 | pre->matchingMapIndex = match - def->entries; | ||||
1157 | } | ||||
1158 | type->mods.real_mods = def->mask; | ||||
1159 | type->mods.vmods = def->vmask; | ||||
1160 | type->num_levels = def->numLevels; | ||||
1161 | type->map_count = def->nEntries; | ||||
1162 | type->map = def->entries; | ||||
1163 | if (def->preserve) | ||||
1164 | { | ||||
1165 | type->preserve = uTypedCalloc(type->map_count, XkbModsRec)((XkbModsRec *)uCalloc((unsigned)type->map_count,(unsigned )sizeof(XkbModsRec))); | ||||
1166 | if (!type->preserve) | ||||
1167 | { | ||||
1168 | WARNuWarning("Couldn't allocate preserve array in CopyDefToKeyType\n"); | ||||
1169 | ACTION1uAction("Preserve setting for type %s lost\n", | ||||
1170 | XkbAtomText(def->dpy, def->name, XkbMessage3)); | ||||
1171 | } | ||||
1172 | else | ||||
1173 | { | ||||
1174 | pre = def->preserve; | ||||
1175 | for (; pre != NULL((void*)0); pre = (PreserveInfo *) pre->defs.next) | ||||
1176 | { | ||||
1177 | int ndx = pre->matchingMapIndex; | ||||
1178 | type->preserve[ndx].mask = pre->preMods; | ||||
1179 | type->preserve[ndx].real_mods = pre->preMods; | ||||
1180 | type->preserve[ndx].vmods = pre->preVMods; | ||||
1181 | } | ||||
1182 | } | ||||
1183 | } | ||||
1184 | else | ||||
1185 | type->preserve = NULL((void*)0); | ||||
1186 | type->name = (Atom) def->name; | ||||
1187 | if (def->szNames > 0) | ||||
1188 | { | ||||
1189 | type->level_names = uTypedCalloc(def->numLevels, Atom)((Atom *)uCalloc((unsigned)def->numLevels,(unsigned)sizeof (Atom))); | ||||
1190 | |||||
1191 | /* assert def->szNames<=def->numLevels */ | ||||
1192 | for (i = 0; i < def->szNames; i++) | ||||
1193 | { | ||||
1194 | type->level_names[i] = (Atom) def->lvlNames[i]; | ||||
1195 | } | ||||
1196 | } | ||||
1197 | else | ||||
1198 | { | ||||
1199 | type->level_names = NULL((void*)0); | ||||
1200 | } | ||||
1201 | |||||
1202 | def->nEntries = def->szEntries = 0; | ||||
1203 | def->entries = NULL((void*)0); | ||||
1204 | return XkbComputeEffectiveMap(xkb, type, NULL((void*)0)); | ||||
1205 | } | ||||
1206 | |||||
1207 | Boolint | ||||
1208 | CompileKeyTypes(XkbFile * file, XkbFileInfo * result, unsigned merge) | ||||
1209 | { | ||||
1210 | KeyTypesInfo info; | ||||
1211 | XkbDescPtr xkb; | ||||
1212 | |||||
1213 | xkb = result->xkb; | ||||
1214 | InitKeyTypesInfo(&info, xkb, NULL((void*)0)); | ||||
1215 | info.fileID = file->id; | ||||
1216 | HandleKeyTypesFile(file, xkb, merge, &info); | ||||
1217 | |||||
1218 | if (info.errorCount == 0) | ||||
1219 | { | ||||
1220 | register int i; | ||||
1221 | register KeyTypeInfo *def; | ||||
1222 | register XkbKeyTypePtr type, next; | ||||
1223 | |||||
1224 | if (info.name != NULL((void*)0)) | ||||
1225 | { | ||||
1226 | if (XkbAllocNames(xkb, XkbTypesNameMask(1<<4), 0, 0) == Success0) | ||||
1227 | xkb->names->types = XkbInternAtom(xkb->dpy, info.name, False0); | ||||
1228 | else | ||||
1229 | { | ||||
1230 | WSGOuInternalError("Couldn't allocate space for types name\n"); | ||||
1231 | ACTION2uAction("Name \"%s\" (from %s) NOT assigned\n", | ||||
1232 | scanFile, info.name); | ||||
1233 | } | ||||
1234 | } | ||||
1235 | i = info.nTypes; | ||||
1236 | if ((info.stdPresent & XkbOneLevelMask(1<<0)) == 0) | ||||
1237 | i++; | ||||
1238 | if ((info.stdPresent & XkbTwoLevelMask(1<<1)) == 0) | ||||
1239 | i++; | ||||
1240 | if ((info.stdPresent & XkbKeypadMask(1<<3)) == 0) | ||||
1241 | i++; | ||||
1242 | if ((info.stdPresent & XkbAlphabeticMask(1<<2)) == 0) | ||||
1243 | i++; | ||||
1244 | if (XkbAllocClientMap(xkb, XkbKeyTypesMask(1<<0), i) != Success0) | ||||
1245 | { | ||||
1246 | WSGOuInternalError("Couldn't allocate client map\n"); | ||||
1247 | ACTIONuAction("Exiting\n"); | ||||
1248 | return False0; | ||||
1249 | } | ||||
1250 | xkb->map->num_types = i; | ||||
1251 | if (XkbAllRequiredTypes(0xf) & (~info.stdPresent)) | ||||
1252 | { | ||||
1253 | unsigned missing, keypadVMod; | ||||
1254 | |||||
1255 | missing = XkbAllRequiredTypes(0xf) & (~info.stdPresent); | ||||
1256 | keypadVMod = FindKeypadVMod(xkb); | ||||
1257 | if (XkbInitCanonicalKeyTypes(xkb, missing, keypadVMod) != Success0) | ||||
1258 | { | ||||
1259 | WSGOuInternalError("Couldn't initialize canonical key types\n"); | ||||
1260 | ACTIONuAction("Exiting\n"); | ||||
1261 | return False0; | ||||
1262 | } | ||||
1263 | if (missing & XkbOneLevelMask(1<<0)) | ||||
1264 | xkb->map->types[XkbOneLevelIndex0].name = tok_ONE_LEVEL; | ||||
1265 | if (missing & XkbTwoLevelMask(1<<1)) | ||||
1266 | xkb->map->types[XkbTwoLevelIndex1].name = tok_TWO_LEVEL; | ||||
1267 | if (missing & XkbAlphabeticMask(1<<2)) | ||||
1268 | xkb->map->types[XkbAlphabeticIndex2].name = tok_ALPHABETIC; | ||||
1269 | if (missing & XkbKeypadMask(1<<3)) | ||||
1270 | xkb->map->types[XkbKeypadIndex3].name = tok_KEYPAD; | ||||
1271 | } | ||||
1272 | next = &xkb->map->types[XkbLastRequiredType3 + 1]; | ||||
1273 | for (i = 0, def = info.types; i < info.nTypes; i++) | ||||
1274 | { | ||||
1275 | if (def->name == tok_ONE_LEVEL) | ||||
1276 | type = &xkb->map->types[XkbOneLevelIndex0]; | ||||
1277 | else if (def->name == tok_TWO_LEVEL) | ||||
1278 | type = &xkb->map->types[XkbTwoLevelIndex1]; | ||||
1279 | else if (def->name == tok_ALPHABETIC) | ||||
1280 | type = &xkb->map->types[XkbAlphabeticIndex2]; | ||||
1281 | else if (def->name == tok_KEYPAD) | ||||
1282 | type = &xkb->map->types[XkbKeypadIndex3]; | ||||
1283 | else | ||||
1284 | type = next++; | ||||
1285 | DeleteLevel1MapEntries(def); | ||||
1286 | if (!CopyDefToKeyType(xkb, type, def)) | ||||
1287 | return False0; | ||||
1288 | def = (KeyTypeInfo *) def->defs.next; | ||||
1289 | } | ||||
1290 | return True1; | ||||
1291 | } | ||||
1292 | return False0; | ||||
1293 | } |