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