xkbcomp: Lazy keysym parsing (avoid XStringToKeysym)
[profile/ivi/libxkbcommon.git] / src / malloc.c
1 /************************************************************
2 Copyright (c) 1993 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 "xkballoc.h"
28 #include "X11/extensions/XKBcommon.h"
29 #include "XKBcommonint.h"
30
31 int
32 XkbcAllocClientMap(XkbcDescPtr xkb, unsigned which, unsigned nTotalTypes)
33 {
34     int i;
35     XkbClientMapPtr map;
36
37     if (!xkb || ((nTotalTypes > 0) && (nTotalTypes < XkbNumRequiredTypes)))
38         return BadValue;
39
40     if ((which & XkbKeySymsMask) &&
41         ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
42          (!XkbIsLegalKeycode(xkb->max_key_code)) ||
43          (xkb->max_key_code < xkb->min_key_code))) {
44 #ifdef DEBUG
45         fprintf(stderr, "bad keycode (%d,%d) in XkbAllocClientMap\n",
46                 xkb->min_key_code, xkb->max_key_code);
47 #endif
48         return BadValue;
49     }
50
51     if (!xkb->map) {
52         map = _XkbTypedCalloc(1, XkbClientMapRec);
53         if (!map)
54             return BadAlloc;
55         xkb->map = map;
56     }
57     else
58         map = xkb->map;
59
60     if ((which & XkbKeyTypesMask) && (nTotalTypes > 0)) {
61         if (!map->types) {
62             map->types = _XkbTypedCalloc(nTotalTypes, XkbKeyTypeRec);
63             if (!map->types)
64                 return BadAlloc;
65
66             map->num_types = 0;
67             map->size_types = nTotalTypes;
68         }
69         else if (map->size_types < nTotalTypes) {
70             XkbKeyTypeRec *prev_types = map->types;
71
72             map->types = _XkbTypedRealloc(map->types, nTotalTypes,
73                                           XkbKeyTypeRec);
74             if (!map->types) {
75                 _XkbFree(prev_types);
76                 map->num_types = map->size_types = 0;
77                 return BadAlloc;
78             }
79
80             map->size_types = nTotalTypes;
81             bzero(&map->types[map->num_types],
82                   (map->size_types - map->num_types) * sizeof(XkbKeyTypeRec));
83         }
84     }
85
86     if (which & XkbKeySymsMask) {
87         int nKeys = XkbNumKeys(xkb);
88
89         if (!map->syms) {
90             map->size_syms = (nKeys * 15) / 10;
91             map->syms = _XkbTypedCalloc(map->size_syms, KeySym);
92             if (!map->syms) {
93                 map->size_syms = 0;
94                 return BadAlloc;
95             }
96             map->num_syms = 1;
97             map->syms[0] = NoSymbol;
98         }
99
100         if (!map->key_sym_map) {
101             i = xkb->max_key_code + 1;
102             map->key_sym_map = _XkbTypedCalloc(i, XkbSymMapRec);
103             if (!map->key_sym_map)
104                 return BadAlloc;
105         }
106     }
107
108     if (which & XkbModifierMapMask) {
109         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
110             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
111             (xkb->max_key_code < xkb->min_key_code))
112             return BadMatch;
113
114         if (!map->modmap) {
115             i = xkb->max_key_code + 1;
116             map->modmap = _XkbTypedCalloc(i, unsigned char);
117             if (!map->modmap)
118                 return BadAlloc;
119         }
120     }
121
122     return Success;
123 }
124
125 int
126 XkbcAllocServerMap(XkbcDescPtr xkb, unsigned which, unsigned nNewActions)
127 {
128     int i;
129     XkbcServerMapPtr map;
130
131     if (!xkb)
132         return BadMatch;
133
134     if (!xkb->server) {
135         map = _XkbTypedCalloc(1, XkbcServerMapRec);
136         if (!map)
137             return BadAlloc;
138
139         for (i = 0; i < XkbNumVirtualMods; i++)
140             map->vmods[i] = XkbNoModifierMask;
141
142         xkb->server = map;
143     }
144     else
145         map = xkb->server;
146
147     if (which & XkbExplicitComponentsMask) {
148         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
149             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
150             (xkb->max_key_code < xkb->min_key_code))
151             return BadMatch;
152
153         if (!map->explicit) {
154             i = xkb->max_key_code + 1;
155             map->explicit = _XkbTypedCalloc(i, unsigned char);
156             if (!map->explicit)
157                 return BadAlloc;
158         }
159     }
160
161     if (which&XkbKeyActionsMask) {
162         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
163             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
164             (xkb->max_key_code < xkb->min_key_code))
165             return BadMatch;
166
167         if (nNewActions < 1)
168             nNewActions = 1;
169
170         if (!map->acts) {
171             map->acts = _XkbTypedCalloc(nNewActions + 1, XkbcAction);
172             if (!map->acts)
173                 return BadAlloc;
174             map->num_acts = 1;
175             map->size_acts = nNewActions + 1;
176         }
177         else if ((map->size_acts - map->num_acts) < nNewActions) {
178             unsigned need;
179             XkbcAction *prev_acts = map->acts;
180
181             need = map->num_acts + nNewActions;
182             map->acts = _XkbTypedRealloc(map->acts, need, XkbcAction);
183             if (!map->acts) {
184                 _XkbFree(prev_acts);
185                 map->num_acts = map->size_acts = 0;
186                 return BadAlloc;
187             }
188
189             map->size_acts = need;
190             bzero(&map->acts[map->num_acts],
191                   (map->size_acts - map->num_acts) * sizeof(XkbcAction));
192         }
193
194         if (!map->key_acts) {
195             i = xkb->max_key_code + 1;
196             map->key_acts = _XkbTypedCalloc(i, unsigned short);
197             if (!map->key_acts)
198                 return BadAlloc;
199         }
200     }
201
202     if (which & XkbKeyBehaviorsMask) {
203         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
204             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
205             (xkb->max_key_code < xkb->min_key_code))
206             return BadMatch;
207
208         if (!map->behaviors) {
209             i = xkb->max_key_code + 1;
210             map->behaviors = _XkbTypedCalloc(i, XkbBehavior);
211             if (!map->behaviors)
212                 return BadAlloc;
213         }
214     }
215
216     if (which & XkbVirtualModMapMask) {
217         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
218             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
219             (xkb->max_key_code < xkb->min_key_code))
220             return BadMatch;
221
222         if (!map->vmodmap) {
223             i = xkb->max_key_code + 1;
224             map->vmodmap = _XkbTypedCalloc(i, unsigned short);
225             if (!map->vmodmap)
226                 return BadAlloc;
227         }
228     }
229
230     return Success;
231 }
232
233 int
234 XkbcCopyKeyType(XkbKeyTypePtr from, XkbKeyTypePtr into)
235 {
236     if (!from || !into)
237         return BadMatch;
238
239     if (into->map) {
240         _XkbFree(into->map);
241         into->map = NULL;
242     }
243     if (into->preserve) {
244        _XkbFree(into->preserve);
245        into->preserve= NULL;
246     }
247     if (into->level_names) {
248         _XkbFree(into->level_names);
249         into->level_names = NULL;
250     }
251
252     *into = *from;
253
254     if (from->map && (into->map_count > 0)) {
255         into->map = _XkbTypedCalloc(into->map_count, XkbKTMapEntryRec);
256         if (!into->map)
257             return BadAlloc;
258         memcpy(into->map, from->map,
259                into->map_count * sizeof(XkbKTMapEntryRec));
260     }
261
262     if (from->preserve && (into->map_count > 0)) {
263         into->preserve = _XkbTypedCalloc(into->map_count, XkbModsRec);
264         if (!into->preserve)
265             return BadAlloc;
266         memcpy(into->preserve, from->preserve,
267                into->map_count * sizeof(XkbModsRec));
268     }
269
270     if (from->level_names && (into->num_levels > 0)) {
271         into->level_names = _XkbTypedCalloc(into->num_levels, Atom);
272         if (!into->level_names)
273             return BadAlloc;
274         memcpy(into->level_names, from->level_names,
275                into->num_levels * sizeof(Atom));
276     }
277
278     return Success;
279 }
280
281 int
282 XkbcCopyKeyTypes(XkbKeyTypePtr from, XkbKeyTypePtr into, int num_types)
283 {
284     int i, rtrn;
285
286     if (!from || !into || (num_types < 0))
287         return BadMatch;
288
289     for (i = 0; i < num_types; i++) {
290         if ((rtrn = XkbcCopyKeyType(from++, into++)) != Success)
291             return rtrn;
292     }
293
294     return Success;
295 }
296
297 int
298 XkbcResizeKeyType(XkbcDescPtr xkb, int type_ndx, int map_count,
299                   Bool want_preserve, int new_num_lvls)
300 {
301     XkbKeyTypePtr type;
302     KeyCode matchingKeys[XkbMaxKeyCount], nMatchingKeys;
303
304     if ((type_ndx < 0) || (type_ndx >= xkb->map->num_types) ||
305         (map_count < 0)|| (new_num_lvls < 1))
306         return BadValue;
307
308     switch (type_ndx) {
309     case XkbOneLevelIndex:
310         if (new_num_lvls != 1)
311             return BadMatch;
312     case XkbTwoLevelIndex:
313     case XkbAlphabeticIndex:
314     case XkbKeypadIndex:
315         if (new_num_lvls != 2)
316             return BadMatch;
317     }
318
319     type = &xkb->map->types[type_ndx];
320
321     if (map_count == 0) {
322         if (type->map)
323             _XkbFree(type->map);
324         type->map = NULL;
325
326         if (type->preserve)
327             _XkbFree(type->preserve);
328         type->preserve = NULL;
329
330         type->map_count = 0;
331     }
332     else {
333         XkbKTMapEntryRec *prev_map = type->map;
334
335         if ((map_count > type->map_count) || !type->map)
336             type->map = _XkbTypedRealloc(type->map, map_count,
337                                          XkbKTMapEntryRec);
338         if (!type->map) {
339             if (prev_map)
340                 _XkbFree(prev_map);
341             return BadAlloc;
342         }
343
344         if (want_preserve) {
345             XkbModsRec *prev_preserve = type->preserve;
346
347             if ((map_count > type->map_count) || !type->preserve)
348                 type->preserve = _XkbTypedRealloc(type->preserve, map_count,
349                                                   XkbModsRec);
350             if (!type->preserve) {
351                 if (prev_preserve)
352                     _XkbFree(prev_preserve);
353                 return BadAlloc;
354             }
355         }
356         else if (type->preserve) {
357             _XkbFree(type->preserve);
358             type->preserve = NULL;
359         }
360
361         type->map_count = map_count;
362     }
363
364     if ((new_num_lvls > type->num_levels) || !type->level_names) {
365         Atom *prev_level_names = type->level_names;
366
367         type->level_names = _XkbTypedRealloc(type->level_names, new_num_lvls,
368                                              Atom);
369         if (!type->level_names) {
370             if (prev_level_names)
371                 _XkbFree(prev_level_names);
372             return BadAlloc;
373         }
374     }
375
376     /*
377      * Here's the theory:
378      *    If the width of the type changed, we might have to resize the symbol
379      * maps for any keys that use the type for one or more groups.  This is
380      * expensive, so we'll try to cull out any keys that are obviously okay:
381      * In any case:
382      *    - keys that have a group width <= the old width are okay (because
383      *      they could not possibly have been associated with the old type)
384      * If the key type increased in size:
385      *    - keys that already have a group width >= to the new width are okay
386      *    + keys that have a group width >= the old width but < the new width
387      *      might have to be enlarged.
388      * If the key type decreased in size:
389      *    - keys that have a group width > the old width don't have to be
390      *      resized (because they must have some other wider type associated
391      *      with some group).
392      *    + keys that have a group width == the old width might have to be
393      *      shrunk.
394      * The possibilities marked with '+' require us to examine the key types
395      * associated with each group for the key.
396      */
397     bzero(matchingKeys, XkbMaxKeyCount * sizeof(KeyCode));
398     nMatchingKeys = 0;
399     if (new_num_lvls > type->num_levels) {
400         int nTotal;
401         KeySym *newSyms;
402         int width, match, nResize = 0;
403         int i, g, nSyms;
404
405         for (nTotal = 1, i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
406             width = XkbKeyGroupsWidth(xkb, i);
407             if (width < type->num_levels)
408                 continue;
409
410             for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
411                  (g >= 0) && !match; g--) {
412                 if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
413                     matchingKeys[nMatchingKeys++] = i;
414                     match = 1;
415                 }
416             }
417
418             if (!match || (width >= new_num_lvls))
419                 nTotal += XkbKeyNumSyms(xkb, i);
420             else {
421                 nTotal += XkbKeyNumGroups(xkb, i) * new_num_lvls;
422                 nResize++;
423             }
424         }
425
426         if (nResize > 0) {
427             int nextMatch;
428
429             xkb->map->size_syms = (nTotal * 12) / 10;
430             newSyms = _XkbTypedCalloc(xkb->map->size_syms, KeySym);
431             if (!newSyms)
432                 return BadAlloc;
433             nextMatch = 0;
434             nSyms = 1;
435
436             for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
437                 if (matchingKeys[nextMatch] == i) {
438                     KeySym *pOld;
439
440                     nextMatch++;
441                     width = XkbKeyGroupsWidth(xkb, i);
442                     pOld = XkbKeySymsPtr(xkb, i);
443                     for (g = XkbKeyNumGroups(xkb, i) - 1; g >= 0; g--)
444                         memcpy(&newSyms[nSyms+(new_num_lvls * g)],
445                                &pOld[width * g], width * sizeof(KeySym));
446                     xkb->map->key_sym_map[i].offset = nSyms;
447                     nSyms += XkbKeyNumGroups(xkb, i) * new_num_lvls;
448                 }
449                 else {
450                     memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
451                            XkbKeyNumSyms(xkb, i) * sizeof(KeySym));
452                     xkb->map->key_sym_map[i].offset = nSyms;
453                     nSyms += XkbKeyNumSyms(xkb,i);
454                 }
455             }
456
457             type->num_levels = new_num_lvls;
458             _XkbFree(xkb->map->syms);
459             xkb->map->syms = newSyms;
460             xkb->map->num_syms = nSyms;
461
462             return Success;
463         }
464     }
465     else if (new_num_lvls < type->num_levels) {
466         int width,match;
467         int g, i;
468
469         for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
470             width = XkbKeyGroupsWidth(xkb, i);
471             if (width < type->num_levels)
472                 continue;
473
474             for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
475                  (g >= 0) && !match; g--) {
476                 if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
477                     matchingKeys[nMatchingKeys++] = i;
478                     match = 1;
479                 }
480             }
481         }
482     }
483
484     if (nMatchingKeys > 0) {
485         int key, firstClear;
486         int i, g;
487
488         if (new_num_lvls > type->num_levels)
489              firstClear = type->num_levels;
490         else
491             firstClear = new_num_lvls;
492
493         for (i = 0; i < nMatchingKeys; i++) {
494             KeySym *pSyms;
495             int width, nClear;
496
497             key = matchingKeys[i];
498             width = XkbKeyGroupsWidth(xkb, key);
499             nClear = width - firstClear;
500             pSyms = XkbKeySymsPtr(xkb, key);
501             for (g = XkbKeyNumGroups(xkb, key) - 1; g >= 0; g--) {
502                 if (XkbKeyKeyTypeIndex(xkb, key, g) == type_ndx) {
503                     if (nClear>0)
504                         bzero(&pSyms[g * width + firstClear],
505                               nClear * sizeof(KeySym));
506                 }
507             }
508         }
509     }
510
511     type->num_levels = new_num_lvls;
512
513     return Success;
514 }
515
516 KeySym *
517 XkbcResizeKeySyms(XkbcDescPtr xkb, int key, int needed)
518 {
519     int i, nSyms, nKeySyms;
520     unsigned nOldSyms;
521     KeySym *newSyms;
522
523     if (needed == 0) {
524         xkb->map->key_sym_map[key].offset = 0;
525         return xkb->map->syms;
526     }
527
528     nOldSyms = XkbKeyNumSyms(xkb, key);
529     if (nOldSyms >= (unsigned)needed)
530         return XkbKeySymsPtr(xkb, key);
531
532     if (xkb->map->size_syms - xkb->map->num_syms >= (unsigned)needed) {
533         if (nOldSyms > 0)
534             memcpy(&xkb->map->syms[xkb->map->num_syms],
535                    XkbKeySymsPtr(xkb, key), nOldSyms * sizeof(KeySym));
536
537         if ((needed - nOldSyms) > 0)
538             bzero(&xkb->map->syms[xkb->map->num_syms + XkbKeyNumSyms(xkb, key)],
539                   (needed - nOldSyms) * sizeof(KeySym));
540
541         xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
542         xkb->map->num_syms += needed;
543
544         return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
545     }
546
547     xkb->map->size_syms += (needed > 32 ? needed : 32);
548     newSyms = _XkbTypedCalloc(xkb->map->size_syms, KeySym);
549     if (!newSyms)
550         return NULL;
551
552     newSyms[0] = NoSymbol;
553     nSyms = 1;
554     for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
555         int nCopy;
556
557         nCopy = nKeySyms = XkbKeyNumSyms(xkb, i);
558         if ((nKeySyms == 0) && (i != key))
559             continue;
560
561         if (i == key)
562             nKeySyms = needed;
563         if (nCopy != 0)
564            memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
565                   nCopy * sizeof(KeySym));
566         if (nKeySyms > nCopy)
567             bzero(&newSyms[nSyms+nCopy], (nKeySyms - nCopy) * sizeof(KeySym));
568
569         xkb->map->key_sym_map[i].offset = nSyms;
570         nSyms += nKeySyms;
571     }
572
573     _XkbFree(xkb->map->syms);
574     xkb->map->syms = newSyms;
575     xkb->map->num_syms = nSyms;
576
577     return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
578 }
579
580 static unsigned
581 _ExtendRange(unsigned int old_flags, unsigned int flag, KeyCode newKC,
582              KeyCode *old_min, unsigned char *old_num)
583 {
584     if ((old_flags & flag) == 0) {
585         old_flags |= flag;
586         *old_min = newKC;
587         *old_num = 1;
588     }
589     else {
590         int last = (*old_min) + (*old_num) - 1;
591
592         if (newKC < *old_min) {
593             *old_min = newKC;
594             *old_num = last - newKC + 1;
595         }
596         else if (newKC > last) {
597             *old_num = newKC - (*old_min) + 1;
598         }
599     }
600
601     return old_flags;
602 }
603
604 int
605 XkbcChangeKeycodeRange(XkbcDescPtr xkb, int minKC, int maxKC,
606                        XkbChangesPtr changes)
607 {
608     int tmp;
609
610     if (!xkb || (minKC < XkbMinLegalKeyCode) || (maxKC > XkbMaxLegalKeyCode))
611         return BadValue;
612
613     if (minKC > maxKC)
614         return BadMatch;
615
616     if (minKC < xkb->min_key_code) {
617         if (changes)
618             changes->map.min_key_code = minKC;
619         tmp = xkb->min_key_code - minKC;
620
621         if (xkb->map)  {
622             if (xkb->map->key_sym_map) {
623                 bzero(&xkb->map->key_sym_map[minKC],
624                       tmp * sizeof(XkbSymMapRec));
625                 if (changes)
626                     changes->map.changed = _ExtendRange(changes->map.changed,
627                                                 XkbKeySymsMask, minKC,
628                                                 &changes->map.first_key_sym,
629                                                 &changes->map.num_key_syms);
630             }
631
632             if (xkb->map->modmap) {
633                 bzero(&xkb->map->modmap[minKC], tmp);
634                 if (changes)
635                     changes->map.changed = _ExtendRange(changes->map.changed,
636                                                 XkbModifierMapMask, minKC,
637                                                 &changes->map.first_modmap_key,
638                                                 &changes->map.num_modmap_keys);
639             }
640         }
641
642         if (xkb->server) {
643             if (xkb->server->behaviors) {
644                 bzero(&xkb->server->behaviors[minKC],
645                       tmp * sizeof(XkbBehavior));
646                 if (changes)
647                     changes->map.changed = _ExtendRange(changes->map.changed,
648                                                 XkbKeyBehaviorsMask, minKC,
649                                                 &changes->map.first_key_behavior,
650                                                 &changes->map.num_key_behaviors);
651             }
652
653             if (xkb->server->key_acts) {
654                 bzero(&xkb->server->key_acts[minKC],
655                       tmp * sizeof(unsigned short));
656                 if (changes)
657                     changes->map.changed = _ExtendRange(changes->map.changed,
658                                                 XkbKeyActionsMask, minKC,
659                                                 &changes->map.first_key_act,
660                                                 &changes->map.num_key_acts);
661             }
662
663             if (xkb->server->vmodmap) {
664                 bzero(&xkb->server->vmodmap[minKC],
665                       tmp * sizeof(unsigned short));
666                 if (changes)
667                     changes->map.changed = _ExtendRange(changes->map.changed,
668                                                 XkbVirtualModMapMask, minKC,
669                                                 &changes->map.first_modmap_key,
670                                                 &changes->map.num_vmodmap_keys);
671             }
672         }
673
674         if (xkb->names && xkb->names->keys) {
675             bzero(&xkb->names->keys[minKC], tmp * sizeof(XkbKeyNameRec));
676             if (changes)
677                 changes->names.changed = _ExtendRange(changes->names.changed,
678                                                 XkbKeyNamesMask, minKC,
679                                                 &changes->names.first_key,
680                                                 &changes->names.num_keys);
681         }
682
683         xkb->min_key_code = minKC;
684     }
685
686     if (maxKC > xkb->max_key_code) {
687         if (changes)
688             changes->map.max_key_code = maxKC;
689         tmp = maxKC-xkb->max_key_code;
690
691         if (xkb->map) {
692             if (xkb->map->key_sym_map) {
693                 XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
694
695                 xkb->map->key_sym_map = _XkbTypedRealloc(xkb->map->key_sym_map,
696                                                          maxKC + 1,
697                                                          XkbSymMapRec);
698                 if (!xkb->map->key_sym_map) {
699                     _XkbFree(prev_key_sym_map);
700                     return BadAlloc;
701                 }
702
703                 bzero(&xkb->map->key_sym_map[xkb->max_key_code],
704                       tmp * sizeof(XkbSymMapRec));
705                 if (changes)
706                     changes->map.changed = _ExtendRange(changes->map.changed,
707                                                     XkbKeySymsMask, maxKC,
708                                                     &changes->map.first_key_sym,
709                                                     &changes->map.num_key_syms);
710             }
711
712             if (xkb->map->modmap) {
713                 unsigned char *prev_modmap = xkb->map->modmap;
714
715                 xkb->map->modmap = _XkbTypedRealloc(xkb->map->modmap,
716                                                     maxKC + 1, unsigned char);
717                 if (!xkb->map->modmap) {
718                     _XkbFree(prev_modmap);
719                     return BadAlloc;
720                 }
721
722                 bzero(&xkb->map->modmap[xkb->max_key_code], tmp);
723                 if (changes)
724                     changes->map.changed = _ExtendRange(changes->map.changed,
725                                                     XkbModifierMapMask, maxKC,
726                                                     &changes->map.first_modmap_key,
727                                                     &changes->map.num_modmap_keys);
728             }
729         }
730
731         if (xkb->server) {
732             if (xkb->server->behaviors) {
733                 XkbBehavior *prev_behaviors = xkb->server->behaviors;
734
735                 xkb->server->behaviors = _XkbTypedRealloc(xkb->server->behaviors,
736                                                           maxKC + 1,
737                                                           XkbBehavior);
738                 if (!xkb->server->behaviors) {
739                     _XkbFree(prev_behaviors);
740                     return BadAlloc;
741                 }
742
743                 bzero(&xkb->server->behaviors[xkb->max_key_code],
744                       tmp * sizeof(XkbBehavior));
745                 if (changes)
746                     changes->map.changed = _ExtendRange(changes->map.changed,
747                                                 XkbKeyBehaviorsMask, maxKC,
748                                                 &changes->map.first_key_behavior,
749                                                 &changes->map.num_key_behaviors);
750             }
751
752             if (xkb->server->key_acts) {
753                 unsigned short *prev_key_acts = xkb->server->key_acts;
754
755                 xkb->server->key_acts = _XkbTypedRealloc(xkb->server->key_acts,
756                                                          maxKC + 1,
757                                                          unsigned short);
758                 if (!xkb->server->key_acts) {
759                     _XkbFree(prev_key_acts);
760                     return BadAlloc;
761                 }
762
763                 bzero(&xkb->server->key_acts[xkb->max_key_code],
764                       tmp * sizeof(unsigned short));
765                 if (changes)
766                     changes->map.changed = _ExtendRange(changes->map.changed,
767                                                 XkbKeyActionsMask, maxKC,
768                                                 &changes->map.first_key_act,
769                                                 &changes->map.num_key_acts);
770             }
771
772             if (xkb->server->vmodmap) {
773                 unsigned short *prev_vmodmap = xkb->server->vmodmap;
774
775                 xkb->server->vmodmap = _XkbTypedRealloc(xkb->server->vmodmap,
776                                                         maxKC + 1,
777                                                         unsigned short);
778                 if (!xkb->server->vmodmap) {
779                     _XkbFree(prev_vmodmap);
780                     return BadAlloc;
781                 }
782
783                 bzero(&xkb->server->vmodmap[xkb->max_key_code],
784                       tmp * sizeof(unsigned short));
785                 if (changes)
786                     changes->map.changed = _ExtendRange(changes->map.changed,
787                                                 XkbVirtualModMapMask, maxKC,
788                                                 &changes->map.first_modmap_key,
789                                                 &changes->map.num_vmodmap_keys);
790             }
791         }
792
793         if (xkb->names && xkb->names->keys ) {
794             XkbKeyNameRec *prev_keys = xkb->names->keys;
795
796             xkb->names->keys = _XkbTypedRealloc(xkb->names->keys, maxKC + 1,
797                                                 XkbKeyNameRec);
798             if (!xkb->names->keys) {
799                 _XkbFree(prev_keys);
800                 return BadAlloc;
801             }
802
803             bzero(&xkb->names->keys[xkb->max_key_code],
804                   tmp * sizeof(XkbKeyNameRec));
805             if (changes)
806                 changes->names.changed = _ExtendRange(changes->names.changed,
807                                                 XkbKeyNamesMask, maxKC,
808                                                 &changes->names.first_key,
809                                                 &changes->names.num_keys);
810         }
811
812         xkb->max_key_code = maxKC;
813     }
814
815     return Success;
816 }
817
818 XkbcAction *
819 XkbcResizeKeyActions(XkbcDescPtr xkb, int key, int needed)
820 {
821     int i, nActs;
822     XkbcAction *newActs;
823
824     if (needed == 0) {
825         xkb->server->key_acts[key] = 0;
826         return NULL;
827     }
828
829     if (XkbKeyHasActions(xkb, key) &&
830         (XkbKeyNumSyms(xkb, key) >= (unsigned)needed))
831         return XkbKeyActionsPtr(xkb, key);
832
833     if (xkb->server->size_acts - xkb->server->num_acts >= (unsigned)needed) {
834         xkb->server->key_acts[key] = xkb->server->num_acts;
835         xkb->server->num_acts += needed;
836
837         return &xkb->server->acts[xkb->server->key_acts[key]];
838     }
839
840     xkb->server->size_acts = xkb->server->num_acts + needed + 8;
841     newActs = _XkbTypedCalloc(xkb->server->size_acts, XkbcAction);
842     if (!newActs)
843         return NULL;
844     newActs[0].type = XkbSA_NoAction;
845     nActs = 1;
846
847     for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
848         int nKeyActs, nCopy;
849
850         if ((xkb->server->key_acts[i] == 0) && (i != key))
851             continue;
852
853         nCopy = nKeyActs = XkbKeyNumActions(xkb, i);
854         if (i == key) {
855             nKeyActs= needed;
856             if (needed < nCopy)
857                 nCopy = needed;
858         }
859
860         if (nCopy > 0)
861             memcpy(&newActs[nActs], XkbKeyActionsPtr(xkb, i),
862                    nCopy * sizeof(XkbcAction));
863         if (nCopy < nKeyActs)
864             bzero(&newActs[nActs + nCopy],
865                   (nKeyActs - nCopy) * sizeof(XkbcAction));
866
867         xkb->server->key_acts[i] = nActs;
868         nActs += nKeyActs;
869     }
870
871     _XkbFree(xkb->server->acts);
872     xkb->server->acts = newActs;
873     xkb->server->num_acts = nActs;
874
875     return &xkb->server->acts[xkb->server->key_acts[key]];
876 }
877
878 void
879 XkbcFreeClientMap(XkbcDescPtr xkb, unsigned what, Bool freeMap)
880 {
881     XkbClientMapPtr map;
882
883     if (!xkb || !xkb->map)
884         return;
885
886     if (freeMap)
887         what = XkbAllClientInfoMask;
888     map = xkb->map;
889
890     if (what & XkbKeyTypesMask) {
891         if (map->types) {
892             if (map->num_types > 0) {
893                 int i;
894                 XkbKeyTypePtr type;
895
896                 for (i = 0, type = map->types; i < map->num_types; i++, type++) {
897                     if (type->map) {
898                         _XkbFree(type->map);
899                         type->map = NULL;
900                     }
901                     if (type->preserve) {
902                         _XkbFree(type->preserve);
903                         type->preserve = NULL;
904                     }
905                     type->map_count = 0;
906                     if (type->level_names) {
907                         _XkbFree(type->level_names);
908                         type->level_names = NULL;
909                     }
910                 }
911             }
912             _XkbFree(map->types);
913             map->num_types = map->size_types = 0;
914             map->types = NULL;
915         }
916     }
917
918     if (what & XkbKeySymsMask) {
919         if (map->key_sym_map) {
920             _XkbFree(map->key_sym_map);
921             map->key_sym_map = NULL;
922         }
923         if (map->syms) {
924             _XkbFree(map->syms);
925             map->size_syms = map->num_syms = 0;
926             map->syms = NULL;
927         }
928     }
929
930     if ((what & XkbModifierMapMask) && map->modmap) {
931         _XkbFree(map->modmap);
932         map->modmap = NULL;
933     }
934
935     if (freeMap) {
936         _XkbFree(xkb->map);
937         xkb->map = NULL;
938     }
939 }
940
941 void
942 XkbcFreeServerMap(XkbcDescPtr xkb, unsigned what, Bool freeMap)
943 {
944     XkbcServerMapPtr map;
945
946     if (!xkb || !xkb->server)
947         return;
948
949     if (freeMap)
950         what = XkbAllServerInfoMask;
951     map = xkb->server;
952
953     if ((what & XkbExplicitComponentsMask) && map->explicit) {
954         _XkbFree(map->explicit);
955         map->explicit = NULL;
956     }
957
958     if (what & XkbKeyActionsMask) {
959         if (map->key_acts) {
960             _XkbFree(map->key_acts);
961             map->key_acts = NULL;
962         }
963         if (map->acts) {
964             _XkbFree(map->acts);
965             map->num_acts = map->size_acts = 0;
966             map->acts = NULL;
967         }
968     }
969
970     if ((what & XkbKeyBehaviorsMask) && map->behaviors) {
971         _XkbFree(map->behaviors);
972         map->behaviors = NULL;
973     }
974
975     if ((what & XkbVirtualModMapMask) && map->vmodmap) {
976         _XkbFree(map->vmodmap);
977         map->vmodmap = NULL;
978     }
979
980     if (freeMap) {
981         _XkbFree(xkb->server);
982         xkb->server = NULL;
983     }
984 }