1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31
32#include <stdio.h>
33#include <X11/X.h>
34#include <X11/Xproto.h>
35#include "misc.h"
36#include "inputstr.h"
37#include <xkbsrv.h>
38#include "xkbgeom.h"
39
40/***====================================================================***/
41
42static void
43_XkbFreeGeomLeafElems(	Bool			freeAll,
44			int			first,
45			int 			count,
46			unsigned short *	num_inout,
47			unsigned short *	sz_inout,
48			char **			elems,
49			unsigned int		elem_sz)
50{
51    if ((freeAll)||(*elems==NULL)) {
52	*num_inout= *sz_inout= 0;
53	free(*elems);
54	*elems = NULL;
55	return;
56    }
57
58    if ((first>=(*num_inout))||(first<0)||(count<1))
59	return;
60
61    if (first+count>=(*num_inout)) {
62	/* truncating the array is easy */
63	(*num_inout)= first;
64    }
65    else {
66	char *	ptr;
67	int 	extra;
68	ptr= *elems;
69	extra= ((*num_inout)-(first+count))*elem_sz;
70	if (extra>0)
71	    memmove(&ptr[first*elem_sz],&ptr[(first+count)*elem_sz],extra);
72	(*num_inout)-= count;
73    }
74    return;
75}
76
77typedef void (*ContentsClearFunc)(
78		char *		/* priv */
79);
80
81static void
82_XkbFreeGeomNonLeafElems(	Bool			freeAll,
83				int			first,
84				int 			count,
85				unsigned short *	num_inout,
86				unsigned short *	sz_inout,
87				char **			elems,
88				unsigned int		elem_sz,
89				ContentsClearFunc	freeFunc)
90{
91register int i;
92register char *ptr;
93
94    if (freeAll) {
95	first= 0;
96	count= (*num_inout);
97    }
98    else if ((first>=(*num_inout))||(first<0)||(count<1))
99	return;
100    else if (first+count>(*num_inout))
101	count= (*num_inout)-first;
102    if (*elems==NULL)
103	return;
104
105    if (freeFunc) {
106	ptr= *elems;
107	ptr+= first*elem_sz;
108	for (i=0;i<count;i++) {
109	    (*freeFunc)(ptr);
110	    ptr+= elem_sz;
111	}
112    }
113    if (freeAll) {
114	(*num_inout)= (*sz_inout)= 0;
115	free(*elems);
116	*elems = NULL;
117    }
118    else if (first+count>=(*num_inout))
119	*num_inout= first;
120    else {
121	i= ((*num_inout)-(first+count))*elem_sz;
122	ptr= *elems;
123	memmove(&ptr[first*elem_sz],&ptr[(first+count)*elem_sz],i);
124	(*num_inout)-= count;
125    }
126    return;
127}
128
129/***====================================================================***/
130
131static void
132_XkbClearProperty(char *prop_in)
133{
134XkbPropertyPtr	prop= (XkbPropertyPtr)prop_in;
135
136    free(prop->name);
137    prop->name = NULL;
138    free(prop->value);
139    prop->value = NULL;
140    return;
141}
142
143void
144XkbFreeGeomProperties(	XkbGeometryPtr	geom,
145			int		first,
146			int		count,
147			Bool		freeAll)
148{
149    _XkbFreeGeomNonLeafElems(freeAll,first,count,
150				&geom->num_properties,&geom->sz_properties,
151				(char **)&geom->properties,
152				sizeof(XkbPropertyRec),_XkbClearProperty);
153    return;
154}
155
156/***====================================================================***/
157
158void
159XkbFreeGeomKeyAliases(	XkbGeometryPtr	geom,
160			int		first,
161			int		count,
162			Bool		freeAll)
163{
164    _XkbFreeGeomLeafElems(freeAll,first,count,
165				&geom->num_key_aliases,&geom->sz_key_aliases,
166				(char **)&geom->key_aliases,
167				sizeof(XkbKeyAliasRec));
168    return;
169}
170
171/***====================================================================***/
172
173static void
174_XkbClearColor(char *color_in)
175{
176XkbColorPtr	color= (XkbColorPtr)color_in;
177
178    free(color->spec);
179    return;
180}
181
182void
183XkbFreeGeomColors(XkbGeometryPtr geom,int first,int count,Bool freeAll)
184{
185    _XkbFreeGeomNonLeafElems(freeAll,first,count,
186				&geom->num_colors,&geom->sz_colors,
187				(char **)&geom->colors,
188				sizeof(XkbColorRec),_XkbClearColor);
189    return;
190}
191
192/***====================================================================***/
193
194void
195XkbFreeGeomPoints(XkbOutlinePtr outline,int first,int count,Bool freeAll)
196{
197    _XkbFreeGeomLeafElems(freeAll,first,count,
198				&outline->num_points,&outline->sz_points,
199				(char **)&outline->points,
200				sizeof(XkbPointRec));
201    return;
202}
203
204/***====================================================================***/
205
206static void
207_XkbClearOutline(char *outline_in)
208{
209XkbOutlinePtr	outline= (XkbOutlinePtr)outline_in;
210
211    if (outline->points!=NULL)
212	XkbFreeGeomPoints(outline,0,outline->num_points,TRUE);
213    return;
214}
215
216void
217XkbFreeGeomOutlines(XkbShapePtr	shape,int first,int count,Bool freeAll)
218{
219    _XkbFreeGeomNonLeafElems(freeAll,first,count,
220				&shape->num_outlines,&shape->sz_outlines,
221				(char **)&shape->outlines,
222				sizeof(XkbOutlineRec),_XkbClearOutline);
223
224    return;
225}
226
227/***====================================================================***/
228
229static void
230_XkbClearShape(char *shape_in)
231{
232XkbShapePtr	shape= (XkbShapePtr)shape_in;
233
234    if (shape->outlines)
235	XkbFreeGeomOutlines(shape,0,shape->num_outlines,TRUE);
236    return;
237}
238
239void
240XkbFreeGeomShapes(XkbGeometryPtr geom,int first,int count,Bool freeAll)
241{
242    _XkbFreeGeomNonLeafElems(freeAll,first,count,
243				&geom->num_shapes,&geom->sz_shapes,
244				(char **)&geom->shapes,
245				sizeof(XkbShapeRec),_XkbClearShape);
246    return;
247}
248
249/***====================================================================***/
250
251void
252XkbFreeGeomOverlayKeys(XkbOverlayRowPtr row,int first,int count,Bool freeAll)
253{
254    _XkbFreeGeomLeafElems(freeAll,first,count,
255				&row->num_keys,&row->sz_keys,
256				(char **)&row->keys,
257				sizeof(XkbOverlayKeyRec));
258    return;
259}
260
261/***====================================================================***/
262
263static void
264_XkbClearOverlayRow(char *row_in)
265{
266XkbOverlayRowPtr	row= (XkbOverlayRowPtr)row_in;
267
268    if (row->keys!=NULL)
269	XkbFreeGeomOverlayKeys(row,0,row->num_keys,TRUE);
270    return;
271}
272
273void
274XkbFreeGeomOverlayRows(XkbOverlayPtr overlay,int first,int count,Bool freeAll)
275{
276    _XkbFreeGeomNonLeafElems(freeAll,first,count,
277				&overlay->num_rows,&overlay->sz_rows,
278				(char **)&overlay->rows,
279				sizeof(XkbOverlayRowRec),_XkbClearOverlayRow);
280    return;
281}
282
283/***====================================================================***/
284
285static void
286_XkbClearOverlay(char *overlay_in)
287{
288XkbOverlayPtr	overlay= (XkbOverlayPtr)overlay_in;
289
290    if (overlay->rows!=NULL)
291	XkbFreeGeomOverlayRows(overlay,0,overlay->num_rows,TRUE);
292    return;
293}
294
295void
296XkbFreeGeomOverlays(XkbSectionPtr section,int first,int	count,Bool freeAll)
297{
298    _XkbFreeGeomNonLeafElems(freeAll,first,count,
299				&section->num_overlays,&section->sz_overlays,
300				(char **)&section->overlays,
301				sizeof(XkbOverlayRec),_XkbClearOverlay);
302    return;
303}
304
305/***====================================================================***/
306
307void
308XkbFreeGeomKeys(XkbRowPtr row,int first,int count,Bool freeAll)
309{
310    _XkbFreeGeomLeafElems(freeAll,first,count,
311				&row->num_keys,&row->sz_keys,
312				(char **)&row->keys,
313				sizeof(XkbKeyRec));
314    return;
315}
316
317/***====================================================================***/
318
319static void
320_XkbClearRow(char *row_in)
321{
322XkbRowPtr	row= (XkbRowPtr)row_in;
323
324    if (row->keys!=NULL)
325	XkbFreeGeomKeys(row,0,row->num_keys,TRUE);
326    return;
327}
328
329void
330XkbFreeGeomRows(XkbSectionPtr section,int first,int count,Bool freeAll)
331{
332    _XkbFreeGeomNonLeafElems(freeAll,first,count,
333				&section->num_rows,&section->sz_rows,
334				(char **)&section->rows,
335				sizeof(XkbRowRec),_XkbClearRow);
336}
337
338/***====================================================================***/
339
340static void
341_XkbClearSection(char *section_in)
342{
343XkbSectionPtr	section= (XkbSectionPtr)section_in;
344
345    if (section->rows!=NULL)
346	XkbFreeGeomRows(section,0,section->num_rows,TRUE);
347    if (section->doodads!=NULL) {
348	XkbFreeGeomDoodads(section->doodads,section->num_doodads,TRUE);
349	section->doodads= NULL;
350    }
351    return;
352}
353
354void
355XkbFreeGeomSections(XkbGeometryPtr geom,int first,int count,Bool freeAll)
356{
357    _XkbFreeGeomNonLeafElems(freeAll,first,count,
358				&geom->num_sections,&geom->sz_sections,
359				(char **)&geom->sections,
360				sizeof(XkbSectionRec),_XkbClearSection);
361    return;
362}
363
364/***====================================================================***/
365
366static void
367_XkbClearDoodad(char *doodad_in)
368{
369XkbDoodadPtr	doodad= (XkbDoodadPtr)doodad_in;
370
371    switch (doodad->any.type) {
372   	case XkbTextDoodad:
373	    {
374		free(doodad->text.text);
375		doodad->text.text = NULL;
376		free(doodad->text.font);
377		doodad->text.font = NULL;
378	    }
379	    break;
380   	case XkbLogoDoodad:
381	    {
382		free(doodad->logo.logo_name);
383		doodad->logo.logo_name = NULL;
384	    }
385	    break;
386    }
387    return;
388}
389
390void
391XkbFreeGeomDoodads(XkbDoodadPtr doodads,int nDoodads,Bool freeAll)
392{
393register int 		i;
394register XkbDoodadPtr	doodad;
395
396    if (doodads) {
397	for (i=0,doodad= doodads;i<nDoodads;i++,doodad++) {
398	    _XkbClearDoodad((char *)doodad);
399	}
400	if (freeAll)
401	    free(doodads);
402    }
403    return;
404}
405
406void
407XkbFreeGeometry(XkbGeometryPtr geom,unsigned which,Bool freeMap)
408{
409    if (geom==NULL)
410	return;
411    if (freeMap)
412	which= XkbGeomAllMask;
413    if ((which&XkbGeomPropertiesMask)&&(geom->properties!=NULL))
414	XkbFreeGeomProperties(geom,0,geom->num_properties,TRUE);
415    if ((which&XkbGeomColorsMask)&&(geom->colors!=NULL))
416	XkbFreeGeomColors(geom,0,geom->num_colors,TRUE);
417    if ((which&XkbGeomShapesMask)&&(geom->shapes!=NULL))
418	XkbFreeGeomShapes(geom,0,geom->num_shapes,TRUE);
419    if ((which&XkbGeomSectionsMask)&&(geom->sections!=NULL))
420	XkbFreeGeomSections(geom,0,geom->num_sections,TRUE);
421    if ((which&XkbGeomDoodadsMask)&&(geom->doodads!= NULL)) {
422	XkbFreeGeomDoodads(geom->doodads,geom->num_doodads,TRUE);
423	geom->doodads= NULL;
424	geom->num_doodads= geom->sz_doodads= 0;
425    }
426    if ((which&XkbGeomKeyAliasesMask)&&(geom->key_aliases!=NULL))
427	XkbFreeGeomKeyAliases(geom,0,geom->num_key_aliases,TRUE);
428    if (freeMap) {
429	free(geom->label_font);
430	geom->label_font = NULL;
431	free(geom);
432    }
433    return;
434}
435
436/***====================================================================***/
437
438static Status
439_XkbGeomAlloc(	void **		old,
440		unsigned short *	num,
441		unsigned short *	total,
442		int			num_new,
443		size_t			sz_elem)
444{
445    if (num_new<1)
446	return Success;
447    if ((*old)==NULL)
448	*num= *total= 0;
449
450    if ((*num)+num_new<=(*total))
451	return Success;
452
453    *total= (*num)+num_new;
454    if ((*old)!=NULL)
455	 (*old)= realloc((*old),(*total)*sz_elem);
456    else (*old)= calloc((*total),sz_elem);
457    if ((*old)==NULL) {
458	*total= *num= 0;
459	return BadAlloc;
460    }
461
462    if (*num>0) {
463	char *tmp= (char *)(*old);
464	memset(&tmp[sz_elem*(*num)], 0, (num_new*sz_elem));
465    }
466    return Success;
467}
468
469#define	_XkbAllocProps(g,n) _XkbGeomAlloc((void *)&(g)->properties,\
470				&(g)->num_properties,&(g)->sz_properties,\
471				(n),sizeof(XkbPropertyRec))
472#define	_XkbAllocColors(g,n) _XkbGeomAlloc((void *)&(g)->colors,\
473				&(g)->num_colors,&(g)->sz_colors,\
474				(n),sizeof(XkbColorRec))
475#define	_XkbAllocShapes(g,n) _XkbGeomAlloc((void *)&(g)->shapes,\
476				&(g)->num_shapes,&(g)->sz_shapes,\
477				(n),sizeof(XkbShapeRec))
478#define	_XkbAllocSections(g,n) _XkbGeomAlloc((void *)&(g)->sections,\
479				&(g)->num_sections,&(g)->sz_sections,\
480				(n),sizeof(XkbSectionRec))
481#define	_XkbAllocDoodads(g,n) _XkbGeomAlloc((void *)&(g)->doodads,\
482				&(g)->num_doodads,&(g)->sz_doodads,\
483				(n),sizeof(XkbDoodadRec))
484#define	_XkbAllocKeyAliases(g,n) _XkbGeomAlloc((void *)&(g)->key_aliases,\
485				&(g)->num_key_aliases,&(g)->sz_key_aliases,\
486				(n),sizeof(XkbKeyAliasRec))
487
488#define	_XkbAllocOutlines(s,n) _XkbGeomAlloc((void *)&(s)->outlines,\
489				&(s)->num_outlines,&(s)->sz_outlines,\
490				(n),sizeof(XkbOutlineRec))
491#define	_XkbAllocRows(s,n) _XkbGeomAlloc((void *)&(s)->rows,\
492				&(s)->num_rows,&(s)->sz_rows,\
493				(n),sizeof(XkbRowRec))
494#define	_XkbAllocPoints(o,n) _XkbGeomAlloc((void *)&(o)->points,\
495				&(o)->num_points,&(o)->sz_points,\
496				(n),sizeof(XkbPointRec))
497#define	_XkbAllocKeys(r,n) _XkbGeomAlloc((void *)&(r)->keys,\
498				&(r)->num_keys,&(r)->sz_keys,\
499				(n),sizeof(XkbKeyRec))
500#define	_XkbAllocOverlays(s,n) _XkbGeomAlloc((void *)&(s)->overlays,\
501				&(s)->num_overlays,&(s)->sz_overlays,\
502				(n),sizeof(XkbOverlayRec))
503#define	_XkbAllocOverlayRows(o,n) _XkbGeomAlloc((void *)&(o)->rows,\
504				&(o)->num_rows,&(o)->sz_rows,\
505				(n),sizeof(XkbOverlayRowRec))
506#define	_XkbAllocOverlayKeys(r,n) _XkbGeomAlloc((void *)&(r)->keys,\
507				&(r)->num_keys,&(r)->sz_keys,\
508				(n),sizeof(XkbOverlayKeyRec))
509
510Status
511XkbAllocGeomProps(XkbGeometryPtr geom,int nProps)
512{
513    return _XkbAllocProps(geom,nProps);
514}
515
516Status
517XkbAllocGeomColors(XkbGeometryPtr geom,int nColors)
518{
519    return _XkbAllocColors(geom,nColors);
520}
521
522Status
523XkbAllocGeomKeyAliases(XkbGeometryPtr geom,int nKeyAliases)
524{
525    return _XkbAllocKeyAliases(geom,nKeyAliases);
526}
527
528Status
529XkbAllocGeomShapes(XkbGeometryPtr geom,int nShapes)
530{
531    return _XkbAllocShapes(geom,nShapes);
532}
533
534Status
535XkbAllocGeomSections(XkbGeometryPtr geom,int nSections)
536{
537    return _XkbAllocSections(geom,nSections);
538}
539
540Status
541XkbAllocGeomOverlays(XkbSectionPtr section,int nOverlays)
542{
543    return _XkbAllocOverlays(section,nOverlays);
544}
545
546Status
547XkbAllocGeomOverlayRows(XkbOverlayPtr overlay,int nRows)
548{
549    return _XkbAllocOverlayRows(overlay,nRows);
550}
551
552Status
553XkbAllocGeomOverlayKeys(XkbOverlayRowPtr row,int nKeys)
554{
555    return _XkbAllocOverlayKeys(row,nKeys);
556}
557
558Status
559XkbAllocGeomDoodads(XkbGeometryPtr geom,int nDoodads)
560{
561    return _XkbAllocDoodads(geom,nDoodads);
562}
563
564Status
565XkbAllocGeomSectionDoodads(XkbSectionPtr section,int nDoodads)
566{
567    return _XkbAllocDoodads(section,nDoodads);
568}
569
570Status
571XkbAllocGeomOutlines(XkbShapePtr shape,int nOL)
572{
573    return _XkbAllocOutlines(shape,nOL);
574}
575
576Status
577XkbAllocGeomRows(XkbSectionPtr section,int nRows)
578{
579    return _XkbAllocRows(section,nRows);
580}
581
582Status
583XkbAllocGeomPoints(XkbOutlinePtr ol,int nPts)
584{
585    return _XkbAllocPoints(ol,nPts);
586}
587
588Status
589XkbAllocGeomKeys(XkbRowPtr row,int nKeys)
590{
591    return _XkbAllocKeys(row,nKeys);
592}
593
594Status
595XkbAllocGeometry(XkbDescPtr xkb,XkbGeometrySizesPtr sizes)
596{
597XkbGeometryPtr	geom;
598Status		rtrn;
599
600    if (xkb->geom==NULL) {
601	xkb->geom= calloc(1, sizeof(XkbGeometryRec));
602	if (!xkb->geom)
603	    return BadAlloc;
604    }
605    geom= xkb->geom;
606    if ((sizes->which&XkbGeomPropertiesMask)&&
607	((rtrn=_XkbAllocProps(geom,sizes->num_properties))!=Success)) {
608	goto BAIL;
609    }
610    if ((sizes->which&XkbGeomColorsMask)&&
611	((rtrn=_XkbAllocColors(geom,sizes->num_colors))!=Success)) {
612	goto BAIL;
613    }
614    if ((sizes->which&XkbGeomShapesMask)&&
615	((rtrn=_XkbAllocShapes(geom,sizes->num_shapes))!=Success)) {
616	goto BAIL;
617    }
618    if ((sizes->which&XkbGeomSectionsMask)&&
619	((rtrn=_XkbAllocSections(geom,sizes->num_sections))!=Success)) {
620	goto BAIL;
621    }
622    if ((sizes->which&XkbGeomDoodadsMask)&&
623	((rtrn=_XkbAllocDoodads(geom,sizes->num_doodads))!=Success)) {
624	goto BAIL;
625    }
626    if ((sizes->which&XkbGeomKeyAliasesMask)&&
627	((rtrn=_XkbAllocKeyAliases(geom,sizes->num_key_aliases))!=Success)) {
628	goto BAIL;
629    }
630    return Success;
631BAIL:
632    XkbFreeGeometry(geom,XkbGeomAllMask,TRUE);
633    xkb->geom= NULL;
634    return rtrn;
635}
636
637/***====================================================================***/
638
639XkbPropertyPtr
640XkbAddGeomProperty(XkbGeometryPtr geom,char *name,char *value)
641{
642register int i;
643register XkbPropertyPtr prop;
644
645    if ((!geom)||(!name)||(!value))
646	return NULL;
647    for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) {
648	if ((prop->name)&&(strcmp(name,prop->name)==0)) {
649	    free(prop->value);
650	    prop->value= malloc(strlen(value)+1);
651	    if (prop->value)
652		strcpy(prop->value,value);
653	    return prop;
654	}
655    }
656    if ((geom->num_properties>=geom->sz_properties)&&
657					(_XkbAllocProps(geom,1)!=Success)) {
658	return NULL;
659    }
660    prop= &geom->properties[geom->num_properties];
661    prop->name= malloc(strlen(name)+1);
662    if (!prop->name)
663	return NULL;
664    strcpy(prop->name,name);
665    prop->value= malloc(strlen(value)+1);
666    if (!prop->value) {
667	free(prop->name);
668	prop->name= NULL;
669	return NULL;
670    }
671    strcpy(prop->value,value);
672    geom->num_properties++;
673    return prop;
674}
675
676XkbKeyAliasPtr
677XkbAddGeomKeyAlias(XkbGeometryPtr geom,char *aliasStr,char *realStr)
678{
679register int i;
680register XkbKeyAliasPtr alias;
681
682    if ((!geom)||(!aliasStr)||(!realStr)||(!aliasStr[0])||(!realStr[0]))
683	return NULL;
684    for (i=0,alias=geom->key_aliases;i<geom->num_key_aliases;i++,alias++) {
685	if (strncmp(alias->alias,aliasStr,XkbKeyNameLength)==0) {
686	    memset(alias->real, 0, XkbKeyNameLength);
687	    strncpy(alias->real,realStr,XkbKeyNameLength);
688	    return alias;
689	}
690    }
691    if ((geom->num_key_aliases>=geom->sz_key_aliases)&&
692				(_XkbAllocKeyAliases(geom,1)!=Success)) {
693	return NULL;
694    }
695    alias= &geom->key_aliases[geom->num_key_aliases];
696    memset(alias, 0, sizeof(XkbKeyAliasRec));
697    strncpy(alias->alias,aliasStr,XkbKeyNameLength);
698    strncpy(alias->real,realStr,XkbKeyNameLength);
699    geom->num_key_aliases++;
700    return alias;
701}
702
703XkbColorPtr
704XkbAddGeomColor(XkbGeometryPtr geom,char *spec,unsigned int pixel)
705{
706register int i;
707register XkbColorPtr color;
708
709    if ((!geom)||(!spec))
710	return NULL;
711    for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) {
712	if ((color->spec)&&(strcmp(color->spec,spec)==0)) {
713	    color->pixel= pixel;
714	    return color;
715	}
716    }
717    if ((geom->num_colors>=geom->sz_colors)&&
718					(_XkbAllocColors(geom,1)!=Success)) {
719	return NULL;
720    }
721    color= &geom->colors[geom->num_colors];
722    color->pixel= pixel;
723    color->spec= malloc(strlen(spec)+1);
724    if (!color->spec)
725	return NULL;
726    strcpy(color->spec,spec);
727    geom->num_colors++;
728    return color;
729}
730
731XkbOutlinePtr
732XkbAddGeomOutline(XkbShapePtr shape,int sz_points)
733{
734XkbOutlinePtr	outline;
735
736    if ((!shape)||(sz_points<0))
737	return NULL;
738    if ((shape->num_outlines>=shape->sz_outlines)&&
739					(_XkbAllocOutlines(shape,1)!=Success)) {
740	return NULL;
741    }
742    outline= &shape->outlines[shape->num_outlines];
743    memset(outline, 0, sizeof(XkbOutlineRec));
744    if ((sz_points>0)&&(_XkbAllocPoints(outline,sz_points)!=Success))
745	return NULL;
746    shape->num_outlines++;
747    return outline;
748}
749
750XkbShapePtr
751XkbAddGeomShape(XkbGeometryPtr geom,Atom name,int sz_outlines)
752{
753XkbShapePtr	shape;
754register int	i;
755
756    if ((!geom)||(!name)||(sz_outlines<0))
757	return NULL;
758    if (geom->num_shapes>0) {
759	for (shape=geom->shapes,i=0;i<geom->num_shapes;i++,shape++) {
760	    if (name==shape->name)
761		return shape;
762	}
763    }
764    if ((geom->num_shapes>=geom->sz_shapes)&&
765					(_XkbAllocShapes(geom,1)!=Success))
766	return NULL;
767    shape= &geom->shapes[geom->num_shapes];
768    memset(shape, 0, sizeof(XkbShapeRec));
769    if ((sz_outlines>0)&&(_XkbAllocOutlines(shape,sz_outlines)!=Success))
770	return NULL;
771    shape->name= name;
772    shape->primary= shape->approx= NULL;
773    geom->num_shapes++;
774    return shape;
775}
776
777XkbKeyPtr
778XkbAddGeomKey(XkbRowPtr row)
779{
780XkbKeyPtr	key;
781    if (!row)
782	return NULL;
783    if ((row->num_keys>=row->sz_keys)&&(_XkbAllocKeys(row,1)!=Success))
784	return NULL;
785    key= &row->keys[row->num_keys++];
786    memset(key, 0, sizeof(XkbKeyRec));
787    return key;
788}
789
790XkbRowPtr
791XkbAddGeomRow(XkbSectionPtr section,int sz_keys)
792{
793XkbRowPtr	row;
794
795    if ((!section)||(sz_keys<0))
796	return NULL;
797    if ((section->num_rows>=section->sz_rows)&&
798    					(_XkbAllocRows(section,1)!=Success))
799	return NULL;
800    row= &section->rows[section->num_rows];
801    memset(row, 0, sizeof(XkbRowRec));
802    if ((sz_keys>0)&&(_XkbAllocKeys(row,sz_keys)!=Success))
803	return NULL;
804    section->num_rows++;
805    return row;
806}
807
808XkbSectionPtr
809XkbAddGeomSection(	XkbGeometryPtr	geom,
810			Atom		name,
811			int		sz_rows,
812			int		sz_doodads,
813			int		sz_over)
814{
815register int	i;
816XkbSectionPtr	section;
817
818    if ((!geom)||(name==None)||(sz_rows<0))
819	return NULL;
820    for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) {
821	if (section->name!=name)
822	    continue;
823	if (((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success))||
824	    ((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success))||
825	    ((sz_over>0)&&(_XkbAllocOverlays(section,sz_over)!=Success)))
826	    return NULL;
827	return section;
828    }
829    if ((geom->num_sections>=geom->sz_sections)&&
830					(_XkbAllocSections(geom,1)!=Success))
831	return NULL;
832    section= &geom->sections[geom->num_sections];
833    if ((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success))
834	return NULL;
835    if ((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success)) {
836	if (section->rows) {
837	    free(section->rows);
838	    section->rows= NULL;
839	    section->sz_rows= section->num_rows= 0;
840	}
841	return NULL;
842    }
843    section->name= name;
844    geom->num_sections++;
845    return section;
846}
847
848XkbDoodadPtr
849XkbAddGeomDoodad(XkbGeometryPtr geom,XkbSectionPtr section,Atom name)
850{
851XkbDoodadPtr	old,doodad;
852register int	i,nDoodads;
853
854    if ((!geom)||(name==None))
855	return NULL;
856    if ((section!=NULL)&&(section->num_doodads>0)) {
857	old= section->doodads;
858	nDoodads= section->num_doodads;
859    }
860    else {
861	old= geom->doodads;
862	nDoodads= geom->num_doodads;
863    }
864    for (i=0,doodad=old;i<nDoodads;i++,doodad++) {
865	if (doodad->any.name==name)
866	    return doodad;
867    }
868    if (section) {
869	if ((section->num_doodads>=geom->sz_doodads)&&
870	    (_XkbAllocDoodads(section,1)!=Success)) {
871	    return NULL;
872	}
873	doodad= &section->doodads[section->num_doodads++];
874    }
875    else {
876	if ((geom->num_doodads>=geom->sz_doodads)&&
877					(_XkbAllocDoodads(geom,1)!=Success))
878	    return NULL;
879	doodad= &geom->doodads[geom->num_doodads++];
880    }
881    memset(doodad, 0, sizeof(XkbDoodadRec));
882    doodad->any.name= name;
883    return doodad;
884}
885
886XkbOverlayKeyPtr
887XkbAddGeomOverlayKey(	XkbOverlayPtr		overlay,
888			XkbOverlayRowPtr 	row,
889			char *			over,
890			char *			under)
891{
892register int	i;
893XkbOverlayKeyPtr key;
894XkbSectionPtr	section;
895XkbRowPtr	row_under;
896Bool		found;
897
898    if ((!overlay)||(!row)||(!over)||(!under))
899	return NULL;
900    section= overlay->section_under;
901    if (row->row_under>=section->num_rows)
902	return NULL;
903    row_under= &section->rows[row->row_under];
904    for (i=0,found=FALSE;i<row_under->num_keys;i++) {
905	if (strncmp(under,row_under->keys[i].name.name,XkbKeyNameLength)==0) {
906	    found= TRUE;
907	    break;
908	}
909    }
910    if (!found)
911   	return NULL;
912    if ((row->num_keys>=row->sz_keys)&&(_XkbAllocOverlayKeys(row,1)!=Success))
913	return NULL;
914    key= &row->keys[row->num_keys];
915    strncpy(key->under.name,under,XkbKeyNameLength);
916    strncpy(key->over.name,over,XkbKeyNameLength);
917    row->num_keys++;
918    return key;
919}
920
921XkbOverlayRowPtr
922XkbAddGeomOverlayRow(XkbOverlayPtr overlay,int row_under,int sz_keys)
923{
924register int		i;
925XkbOverlayRowPtr	row;
926
927    if ((!overlay)||(sz_keys<0))
928	return NULL;
929    if (row_under>=overlay->section_under->num_rows)
930	return NULL;
931    for (i=0;i<overlay->num_rows;i++) {
932	if (overlay->rows[i].row_under==row_under) {
933	    row= &overlay->rows[i];
934	    if ((row->sz_keys<sz_keys)&&
935				(_XkbAllocOverlayKeys(row,sz_keys)!=Success)) {
936		return NULL;
937	    }
938	    return &overlay->rows[i];
939	}
940    }
941    if ((overlay->num_rows>=overlay->sz_rows)&&
942				(_XkbAllocOverlayRows(overlay,1)!=Success))
943	return NULL;
944    row= &overlay->rows[overlay->num_rows];
945    memset(row, 0, sizeof(XkbOverlayRowRec));
946    if ((sz_keys>0)&&(_XkbAllocOverlayKeys(row,sz_keys)!=Success))
947	return NULL;
948    row->row_under= row_under;
949    overlay->num_rows++;
950    return row;
951}
952
953XkbOverlayPtr
954XkbAddGeomOverlay(XkbSectionPtr section,Atom name,int sz_rows)
955{
956register int	i;
957XkbOverlayPtr	overlay;
958
959    if ((!section)||(name==None)||(sz_rows==0))
960	return NULL;
961
962    for (i=0,overlay=section->overlays;i<section->num_overlays;i++,overlay++) {
963	if (overlay->name==name) {
964	    if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success))
965		return NULL;
966	    return overlay;
967	}
968    }
969    if ((section->num_overlays>=section->sz_overlays)&&
970				(_XkbAllocOverlays(section,1)!=Success))
971	return NULL;
972    overlay= &section->overlays[section->num_overlays];
973    if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success))
974	return NULL;
975    overlay->name= name;
976    overlay->section_under= section;
977    section->num_overlays++;
978    return overlay;
979}
980