blob: 4aed1443d4c60a46d17022cd87580312a4e86ed9 [file] [log] [blame]
/*
Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of Silicon Graphics not be
used in advertising or publicity pertaining to distribution
of the software without specific prior written permission.
Silicon Graphics makes no representation about the suitability
of this software for any purpose. It is provided "as is"
without any express or implied warranty.
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xkbgeom.h"
#include "X11/extensions/XKBcommon.h"
#include "XKBcommonint.h"
#include <X11/extensions/XKB.h>
static void
_XkbFreeGeomLeafElems(Bool freeAll, int first, int count,
unsigned short *num_inout, unsigned short *sz_inout,
char **elems, unsigned int elem_sz)
{
if (freeAll || !(*elems)) {
*num_inout = *sz_inout = 0;
if (*elems) {
free(*elems);
*elems = NULL;
}
return;
}
if ((first >= (*num_inout)) || (first < 0) || (count < 1))
return;
if (first + count >= (*num_inout))
/* truncating the array is easy */
(*num_inout) = first;
else {
char *ptr = *elems;
int extra = ((*num_inout) - first + count) * elem_sz;
if (extra > 0)
memmove(&ptr[first * elem_sz], &ptr[(first + count) * elem_sz],
extra);
(*num_inout) -= count;
}
}
typedef void (*ContentsClearFunc)(char *priv);
static void
_XkbFreeGeomNonLeafElems(Bool freeAll, int first, int count,
unsigned short *num_inout, unsigned short *sz_inout,
char **elems, unsigned int elem_sz,
ContentsClearFunc freeFunc)
{
int i;
char *ptr;
if (freeAll) {
first = 0;
count = *num_inout;
}
else if ((first >= (*num_inout)) || (first < 0) || (count < 1))
return;
else if (first + count > (*num_inout))
count = (*num_inout) - first;
if (!(*elems))
return;
if (freeFunc) {
ptr = *elems;
ptr += first * elem_sz;
for (i = 0; i < count; i++) {
(*freeFunc)(ptr);
ptr += elem_sz;
}
}
if (freeAll) {
*num_inout = *sz_inout = 0;
if (*elems) {
free(*elems);
*elems = NULL;
}
}
else if (first + count >= (*num_inout))
*num_inout = first;
else {
i = ((*num_inout) - first + count) * elem_sz;
ptr = *elems;
memmove(&ptr[first * elem_sz], &ptr[(first + count) * elem_sz], i);
(*num_inout) -= count;
}
}
static void
_XkbClearProperty(char *prop_in)
{
struct xkb_property * prop = (struct xkb_property *)prop_in;
if (prop->name) {
free(prop->name);
prop->name = NULL;
}
if (prop->value) {
free(prop->value);
prop->value = NULL;
}
}
static void
XkbcFreeGeomProperties(struct xkb_geometry * geom, int first, int count, Bool freeAll)
{
_XkbFreeGeomNonLeafElems(freeAll, first, count,
&geom->num_properties, &geom->sz_properties,
(char **)&geom->properties,
sizeof(struct xkb_property),
_XkbClearProperty);
}
static void
XkbcFreeGeomKeyAliases(struct xkb_geometry * geom, int first, int count, Bool freeAll)
{
_XkbFreeGeomLeafElems(freeAll, first, count,
&geom->num_key_aliases, &geom->sz_key_aliases,
(char **)&geom->key_aliases,
sizeof(struct xkb_key_alias));
}
static void
_XkbClearColor(char *color_in)
{
struct xkb_color * color = (struct xkb_color *)color_in;
if (color->spec)
free(color->spec);
}
static void
XkbcFreeGeomColors(struct xkb_geometry * geom, int first, int count, Bool freeAll)
{
_XkbFreeGeomNonLeafElems(freeAll, first, count,
&geom->num_colors, &geom->sz_colors,
(char **)&geom->colors, sizeof(struct xkb_color),
_XkbClearColor);
}
static void
XkbcFreeGeomPoints(struct xkb_outline * outline, int first, int count, Bool freeAll)
{
_XkbFreeGeomLeafElems(freeAll, first, count,
&outline->num_points, &outline->sz_points,
(char **)&outline->points, sizeof(struct xkb_point));
}
static void
_XkbClearOutline(char *outline_in)
{
struct xkb_outline * outline = (struct xkb_outline *)outline_in;
if (outline->points)
XkbcFreeGeomPoints(outline, 0, outline->num_points, True);
}
static void
XkbcFreeGeomOutlines(struct xkb_shape * shape, int first, int count, Bool freeAll)
{
_XkbFreeGeomNonLeafElems(freeAll, first, count,
&shape->num_outlines, &shape->sz_outlines,
(char **)&shape->outlines, sizeof(struct xkb_outline),
_XkbClearOutline);
}
static void
_XkbClearShape(char *shape_in)
{
struct xkb_shape * shape = (struct xkb_shape *)shape_in;
if (shape->outlines)
XkbcFreeGeomOutlines(shape, 0, shape->num_outlines, True);
}
static void
XkbcFreeGeomShapes(struct xkb_geometry * geom, int first, int count, Bool freeAll)
{
_XkbFreeGeomNonLeafElems(freeAll, first, count,
&geom->num_shapes, &geom->sz_shapes,
(char **)&geom->shapes, sizeof(struct xkb_shape),
_XkbClearShape);
}
static void
XkbcFreeGeomKeys(struct xkb_row * row, int first, int count, Bool freeAll)
{
_XkbFreeGeomLeafElems(freeAll, first, count,
&row->num_keys, &row->sz_keys,
(char **)&row->keys, sizeof(struct xkb_key));
}
static void
_XkbClearRow(char *row_in)
{
struct xkb_row * row = (struct xkb_row *)row_in;
if (row->keys)
XkbcFreeGeomKeys(row, 0, row->num_keys, True);
}
static void
XkbcFreeGeomRows(struct xkb_section * section, int first, int count, Bool freeAll)
{
_XkbFreeGeomNonLeafElems(freeAll, first, count,
&section->num_rows, &section->sz_rows,
(char **)&section->rows, sizeof(struct xkb_row),
_XkbClearRow);
}
static void
_XkbClearDoodad(char *doodad_in)
{
union xkb_doodad * doodad = (union xkb_doodad *)doodad_in;
switch (doodad->any.type) {
case XkbTextDoodad:
if (doodad->text.text) {
free(doodad->text.text);
doodad->text.text = NULL;
}
if (doodad->text.font) {
free(doodad->text.font);
doodad->text.font = NULL;
}
break;
case XkbLogoDoodad:
if (doodad->logo.logo_name) {
free(doodad->logo.logo_name);
doodad->logo.logo_name = NULL;
}
break;
}
}
static void
XkbcFreeGeomDoodads(union xkb_doodad * doodads, int nDoodads, Bool freeAll)
{
int i;
union xkb_doodad * doodad;
if (doodads) {
for (i = 0, doodad = doodads; i < nDoodads; i++, doodad++)
_XkbClearDoodad((char *)doodad);
if (freeAll)
free(doodads);
}
}
static void
_XkbClearSection(char *section_in)
{
struct xkb_section * section = (struct xkb_section *)section_in;
if (section->rows)
XkbcFreeGeomRows(section, 0, section->num_rows, True);
if (section->doodads) {
XkbcFreeGeomDoodads(section->doodads, section->num_doodads, True);
section->doodads = NULL;
}
}
static void
XkbcFreeGeomSections(struct xkb_geometry * geom, int first, int count, Bool freeAll)
{
_XkbFreeGeomNonLeafElems(freeAll, first, count,
&geom->num_sections, &geom->sz_sections,
(char **)&geom->sections, sizeof(struct xkb_section),
_XkbClearSection);
}
void
XkbcFreeGeometry(struct xkb_geometry * geom, unsigned which, Bool freeMap)
{
if (!geom)
return;
if (freeMap)
which = XkbGeomAllMask;
if ((which & XkbGeomPropertiesMask) && geom->properties)
XkbcFreeGeomProperties(geom, 0, geom->num_properties, True);
if ((which & XkbGeomColorsMask) && geom->colors)
XkbcFreeGeomColors(geom, 0, geom->num_colors, True);
if ((which & XkbGeomShapesMask) && geom->shapes)
XkbcFreeGeomShapes(geom, 0, geom->num_shapes, True);
if ((which & XkbGeomSectionsMask) && geom->sections)
XkbcFreeGeomSections(geom, 0, geom->num_sections, True);
if ((which & XkbGeomDoodadsMask) && geom->doodads) {
XkbcFreeGeomDoodads(geom->doodads, geom->num_doodads, True);
geom->doodads = NULL;
geom->num_doodads = geom->sz_doodads = 0;
}
if ((which & XkbGeomKeyAliasesMask) && geom->key_aliases)
XkbcFreeGeomKeyAliases(geom, 0, geom->num_key_aliases, True);
if (freeMap) {
if (geom->label_font) {
free(geom->label_font);
geom->label_font = NULL;
}
free(geom);
}
}
static int
_XkbGeomAlloc(char **old, unsigned short *num, unsigned short *total,
int num_new, size_t sz_elem)
{
if (num_new < 1)
return Success;
if (!(*old))
*num = *total = 0;
if ((*num) + num_new <= (*total))
return Success;
*total = (*num) + num_new;
if (*old)
*old = (char *)realloc(*old, (*total) * sz_elem);
else
*old = (char *)calloc(*total, sz_elem);
if (!(*old)) {
*total = *num = 0;
return BadAlloc;
}
if (*num > 0) {
char *tmp = *old;
bzero(&tmp[sz_elem * (*num)], num_new * sz_elem);
}
return Success;
}
#define _XkbAllocProps(g, n) _XkbGeomAlloc((char **)&(g)->properties, \
&(g)->num_properties, \
&(g)->sz_properties, \
(n), sizeof(struct xkb_property))
#define _XkbAllocColors(g, n) _XkbGeomAlloc((char **)&(g)->colors, \
&(g)->num_colors, \
&(g)->sz_colors, \
(n), sizeof(struct xkb_color))
#define _XkbAllocShapes(g, n) _XkbGeomAlloc((char **)&(g)->shapes, \
&(g)->num_shapes, \
&(g)->sz_shapes, \
(n), sizeof(struct xkb_shape))
#define _XkbAllocSections(g, n) _XkbGeomAlloc((char **)&(g)->sections, \
&(g)->num_sections, \
&(g)->sz_sections, \
(n), sizeof(struct xkb_section))
#define _XkbAllocDoodads(g, n) _XkbGeomAlloc((char **)&(g)->doodads, \
&(g)->num_doodads, \
&(g)->sz_doodads, \
(n), sizeof(union xkb_doodad))
#define _XkbAllocKeyAliases(g, n) _XkbGeomAlloc((char **)&(g)->key_aliases, \
&(g)->num_key_aliases, \
&(g)->sz_key_aliases, \
(n), sizeof(struct xkb_key_alias))
#define _XkbAllocOutlines(s, n) _XkbGeomAlloc((char **)&(s)->outlines, \
&(s)->num_outlines, \
&(s)->sz_outlines, \
(n), sizeof(struct xkb_outline))
#define _XkbAllocRows(s, n) _XkbGeomAlloc((char **)&(s)->rows, \
&(s)->num_rows, \
&(s)->sz_rows, \
(n), sizeof(struct xkb_row))
#define _XkbAllocPoints(o, n) _XkbGeomAlloc((char **)&(o)->points, \
&(o)->num_points, \
&(o)->sz_points, \
(n), sizeof(struct xkb_point))
#define _XkbAllocKeys(r, n) _XkbGeomAlloc((char **)&(r)->keys, \
&(r)->num_keys, \
&(r)->sz_keys, \
(n), sizeof(struct xkb_key))
#define _XkbAllocOverlays(s, n) _XkbGeomAlloc((char **)&(s)->overlays, \
&(s)->num_overlays, \
&(s)->sz_overlays, \
(n), sizeof(struct xkb_overlay))
#define _XkbAllocOverlayRows(o, n) _XkbGeomAlloc((char **)&(o)->rows, \
&(o)->num_rows, \
&(o)->sz_rows, \
(n), sizeof(struct xkb_overlay_row))
#define _XkbAllocOverlayKeys(r, n) _XkbGeomAlloc((char **)&(r)->keys, \
&(r)->num_keys, \
&(r)->sz_keys, \
(n), sizeof(struct xkb_overlay_key))
int
XkbcAllocGeomKeyAliases(struct xkb_geometry * geom, int nKeyAliases)
{
return _XkbAllocKeyAliases(geom, nKeyAliases);
}
int
XkbcAllocGeometry(struct xkb_desc * xkb, struct xkb_geometry_sizes * sizes)
{
struct xkb_geometry * geom;
int rtrn;
if (!xkb->geom) {
xkb->geom = _XkbTypedCalloc(1, struct xkb_geometry);
if (!xkb->geom)
return BadAlloc;
}
geom = xkb->geom;
if ((sizes->which & XkbGeomPropertiesMask) &&
((rtrn = _XkbAllocProps(geom, sizes->num_properties)) != Success))
goto bail;
if ((sizes->which & XkbGeomColorsMask) &&
((rtrn = _XkbAllocColors(geom, sizes->num_colors)) != Success))
goto bail;
if ((sizes->which & XkbGeomShapesMask) &&
((rtrn = _XkbAllocShapes(geom, sizes->num_shapes)) != Success))
goto bail;
if ((sizes->which & XkbGeomSectionsMask) &&
((rtrn = _XkbAllocSections(geom, sizes->num_sections)) != Success))
goto bail;
if ((sizes->which & XkbGeomDoodadsMask) &&
((rtrn = _XkbAllocDoodads(geom, sizes->num_doodads)) != Success))
goto bail;
if ((sizes->which & XkbGeomKeyAliasesMask) &&
((rtrn = _XkbAllocKeyAliases(geom, sizes->num_key_aliases)) != Success))
goto bail;
return Success;
bail:
XkbcFreeGeometry(geom, XkbGeomAllMask, True);
xkb->geom = NULL;
return rtrn;
}
struct xkb_property *
XkbcAddGeomProperty(struct xkb_geometry * geom,const char *name,const char *value)
{
register int i;
register struct xkb_property * prop;
if ((!geom)||(!name)||(!value))
return NULL;
for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) {
if ((prop->name)&&(strcmp(name,prop->name)==0)) {
if (prop->value)
free(prop->value);
prop->value= (char *)malloc(strlen(value)+1);
if (prop->value)
strcpy(prop->value,value);
return prop;
}
}
if ((geom->num_properties>=geom->sz_properties)&&
(_XkbAllocProps(geom,1)!=Success)) {
return NULL;
}
prop= &geom->properties[geom->num_properties];
prop->name= (char *)malloc(strlen(name)+1);
if (!name)
return NULL;
strcpy(prop->name,name);
prop->value= (char *)malloc(strlen(value)+1);
if (!value) {
free(prop->name);
prop->name= NULL;
return NULL;
}
strcpy(prop->value,value);
geom->num_properties++;
return prop;
}
struct xkb_color *
XkbcAddGeomColor(struct xkb_geometry * geom,const char *spec,unsigned int pixel)
{
register int i;
register struct xkb_color * color;
if ((!geom)||(!spec))
return NULL;
for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) {
if ((color->spec)&&(strcmp(color->spec,spec)==0)) {
color->pixel= pixel;
return color;
}
}
if ((geom->num_colors>=geom->sz_colors)&&
(_XkbAllocColors(geom,1)!=Success)) {
return NULL;
}
color= &geom->colors[geom->num_colors];
color->pixel= pixel;
color->spec= (char *)malloc(strlen(spec)+1);
if (!color->spec)
return NULL;
strcpy(color->spec,spec);
geom->num_colors++;
return color;
}
struct xkb_outline *
XkbcAddGeomOutline(struct xkb_shape * shape,int sz_points)
{
struct xkb_outline * outline;
if ((!shape)||(sz_points<0))
return NULL;
if ((shape->num_outlines>=shape->sz_outlines)&&
(_XkbAllocOutlines(shape,1)!=Success)) {
return NULL;
}
outline= &shape->outlines[shape->num_outlines];
bzero(outline,sizeof(struct xkb_outline));
if ((sz_points>0)&&(_XkbAllocPoints(outline,sz_points)!=Success))
return NULL;
shape->num_outlines++;
return outline;
}
struct xkb_shape *
XkbcAddGeomShape(struct xkb_geometry * geom,uint32_t name,int sz_outlines)
{
struct xkb_shape * shape;
register int i;
if ((!geom)||(!name)||(sz_outlines<0))
return NULL;
if (geom->num_shapes>0) {
for (shape=geom->shapes,i=0;i<geom->num_shapes;i++,shape++) {
if (name==shape->name)
return shape;
}
}
if ((geom->num_shapes>=geom->sz_shapes)&&
(_XkbAllocShapes(geom,1)!=Success))
return NULL;
shape= &geom->shapes[geom->num_shapes];
bzero(shape,sizeof(struct xkb_shape));
if ((sz_outlines>0)&&(_XkbAllocOutlines(shape,sz_outlines)!=Success))
return NULL;
shape->name= name;
shape->primary= shape->approx= NULL;
geom->num_shapes++;
return shape;
}
struct xkb_key *
XkbcAddGeomKey(struct xkb_row * row)
{
struct xkb_key * key;
if (!row)
return NULL;
if ((row->num_keys>=row->sz_keys)&&(_XkbAllocKeys(row,1)!=Success))
return NULL;
key= &row->keys[row->num_keys++];
bzero(key,sizeof(struct xkb_key));
return key;
}
struct xkb_row *
XkbcAddGeomRow(struct xkb_section * section,int sz_keys)
{
struct xkb_row * row;
if ((!section)||(sz_keys<0))
return NULL;
if ((section->num_rows>=section->sz_rows)&&
(_XkbAllocRows(section,1)!=Success))
return NULL;
row= &section->rows[section->num_rows];
bzero(row,sizeof(struct xkb_row));
if ((sz_keys>0)&&(_XkbAllocKeys(row,sz_keys)!=Success))
return NULL;
section->num_rows++;
return row;
}
struct xkb_section *
XkbcAddGeomSection( struct xkb_geometry * geom,
uint32_t name,
int sz_rows,
int sz_doodads,
int sz_over)
{
register int i;
struct xkb_section * section;
if ((!geom)||(name==None)||(sz_rows<0))
return NULL;
for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) {
if (section->name!=name)
continue;
if (((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success))||
((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success))||
((sz_over>0)&&(_XkbAllocOverlays(section,sz_over)!=Success)))
return NULL;
return section;
}
if ((geom->num_sections>=geom->sz_sections)&&
(_XkbAllocSections(geom,1)!=Success))
return NULL;
section= &geom->sections[geom->num_sections];
if ((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success))
return NULL;
if ((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success)) {
if (section->rows) {
free(section->rows);
section->rows= NULL;
section->sz_rows= section->num_rows= 0;
}
return NULL;
}
section->name= name;
geom->num_sections++;
return section;
}
union xkb_doodad *
XkbcAddGeomDoodad(struct xkb_geometry * geom,struct xkb_section * section,uint32_t name)
{
union xkb_doodad *old, *doodad;
register int i,nDoodads;
if ((!geom)||(name==None))
return NULL;
if ((section!=NULL)&&(section->num_doodads>0)) {
old= section->doodads;
nDoodads= section->num_doodads;
}
else {
old= geom->doodads;
nDoodads= geom->num_doodads;
}
for (i=0,doodad=old;i<nDoodads;i++,doodad++) {
if (doodad->any.name==name)
return doodad;
}
if (section) {
if ((section->num_doodads>=geom->sz_doodads)&&
(_XkbAllocDoodads(section,1)!=Success)) {
return NULL;
}
doodad= &section->doodads[section->num_doodads++];
}
else {
if ((geom->num_doodads>=geom->sz_doodads)&&
(_XkbAllocDoodads(geom,1)!=Success))
return NULL;
doodad= &geom->doodads[geom->num_doodads++];
}
bzero(doodad,sizeof(union xkb_doodad));
doodad->any.name= name;
return doodad;
}
struct xkb_overlay_row *
XkbcAddGeomOverlayRow(struct xkb_overlay * overlay,int row_under,int sz_keys)
{
register int i;
struct xkb_overlay_row * row;
if ((!overlay)||(sz_keys<0))
return NULL;
if (row_under>=overlay->section_under->num_rows)
return NULL;
for (i=0;i<overlay->num_rows;i++) {
if (overlay->rows[i].row_under==row_under) {
row= &overlay->rows[i];
if ((row->sz_keys<sz_keys)&&
(_XkbAllocOverlayKeys(row,sz_keys)!=Success)) {
return NULL;
}
return &overlay->rows[i];
}
}
if ((overlay->num_rows>=overlay->sz_rows)&&
(_XkbAllocOverlayRows(overlay,1)!=Success))
return NULL;
row= &overlay->rows[overlay->num_rows];
bzero(row,sizeof(struct xkb_overlay_row));
if ((sz_keys>0)&&(_XkbAllocOverlayKeys(row,sz_keys)!=Success))
return NULL;
row->row_under= row_under;
overlay->num_rows++;
return row;
}
struct xkb_overlay *
XkbcAddGeomOverlay(struct xkb_section * section,uint32_t name,int sz_rows)
{
register int i;
struct xkb_overlay * overlay;
if ((!section)||(name==None)||(sz_rows==0))
return NULL;
for (i=0,overlay=section->overlays;i<section->num_overlays;i++,overlay++) {
if (overlay->name==name) {
if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success))
return NULL;
return overlay;
}
}
if ((section->num_overlays>=section->sz_overlays)&&
(_XkbAllocOverlays(section,1)!=Success))
return NULL;
overlay= &section->overlays[section->num_overlays];
if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success))
return NULL;
overlay->name= name;
overlay->section_under= section;
section->num_overlays++;
return overlay;
}