#include "xkbcomp.h"
#include "misc.h"
#include "alias.h"
#include "keycodes.h"
#include <X11/extensions/XKBgeom.h>
static void
HandleCollision(AliasInfo * old, AliasInfo * new)
{
if (strncmp(new->real, old->real, XkbKeyNameLength) == 0)
{
if (((new->def.fileID == old->def.fileID) && (warningLevel > 0)) ||
(warningLevel > 9))
{
WARN2("Alias of %s for %s declared more than once\n",
XkbKeyNameText(new->alias, XkbMessage),
XkbKeyNameText(new->real, XkbMessage));
ACTION("First definition ignored\n");
}
}
else
{
char *use, *ignore;
if (new->def.merge == MergeAugment)
{
use = old->real;
ignore = new->real;
}
else
{
use = new->real;
ignore = old->real;
}
if (((old->def.fileID == new->def.fileID) && (warningLevel > 0)) ||
(warningLevel > 9))
{
WARN1("Multiple definitions for alias %s\n",
XkbKeyNameText(old->alias, XkbMessage));
ACTION2("Using %s, ignoring %s\n",
XkbKeyNameText(use, XkbMessage),
XkbKeyNameText(ignore, XkbMessage));
}
if (use != old->real)
memcpy(old->real, use, XkbKeyNameLength);
}
old->def.fileID = new->def.fileID;
old->def.merge = new->def.merge;
return;
}
static void
InitAliasInfo(AliasInfo * info,
unsigned merge, unsigned file_id, char *alias, char *real)
{
bzero(info, sizeof(AliasInfo));
info->def.merge = merge;
info->def.fileID = file_id;
strncpy(info->alias, alias, XkbKeyNameLength);
strncpy(info->real, real, XkbKeyNameLength);
return;
}
int
HandleAliasDef(KeyAliasDef * def,
unsigned merge, unsigned file_id, AliasInfo ** info_in)
{
AliasInfo *info;
for (info = *info_in; info != NULL; info = (AliasInfo *) info->def.next)
{
if (strncmp(info->alias, def->alias, XkbKeyNameLength) == 0)
{
AliasInfo new;
InitAliasInfo(&new, merge, file_id, def->alias, def->real);
HandleCollision(info, &new);
return True;
}
}
info = uTypedCalloc(1, AliasInfo);
if (info == NULL)
{
WSGO("Allocation failure in HandleAliasDef\n");
return False;
}
info->def.fileID = file_id;
info->def.merge = merge;
info->def.next = (CommonInfo *) * info_in;
memcpy(info->alias, def->alias, XkbKeyNameLength);
memcpy(info->real, def->real, XkbKeyNameLength);
*info_in = (AliasInfo *) AddCommonInfo(&(*info_in)->def, &info->def);
return True;
}
void
ClearAliases(AliasInfo ** info_in)
{
if ((info_in) && (*info_in))
ClearCommonInfo(&(*info_in)->def);
return;
}
Bool
MergeAliases(AliasInfo ** into, AliasInfo ** merge, unsigned how_merge)
{
AliasInfo *tmp;
KeyAliasDef def;
if ((*merge) == NULL)
return True;
if ((*into) == NULL)
{
*into = *merge;
*merge = NULL;
return True;
}
bzero((char *) &def, sizeof(KeyAliasDef));
for (tmp = *merge; tmp != NULL; tmp = (AliasInfo *) tmp->def.next)
{
if (how_merge == MergeDefault)
def.merge = tmp->def.merge;
else
def.merge = how_merge;
memcpy(def.alias, tmp->alias, XkbKeyNameLength);
memcpy(def.real, tmp->real, XkbKeyNameLength);
if (!HandleAliasDef(&def, def.merge, tmp->def.fileID, into))
return False;
}
return True;
}
int
ApplyAliases(XkbDescPtr xkb, Bool toGeom, AliasInfo ** info_in)
{
register int i;
XkbKeyAliasPtr old, a;
AliasInfo *info;
int nNew, nOld;
Status status;
if (*info_in == NULL)
return True;
if (toGeom)
{
nOld = (xkb->geom ? xkb->geom->num_key_aliases : 0);
old = (xkb->geom ? xkb->geom->key_aliases : NULL);
}
else
{
nOld = (xkb->names ? xkb->names->num_key_aliases : 0);
old = (xkb->names ? xkb->names->key_aliases : NULL);
}
for (nNew = 0, info = *info_in; info != NULL;
info = (AliasInfo *) info->def.next)
{
unsigned long lname;
unsigned int kc;
lname = KeyNameToLong(info->real);
if (!FindNamedKey(xkb, lname, &kc, False, CreateKeyNames(xkb), 0))
{
if (warningLevel > 4)
{
WARN2("Attempt to alias %s to non-existent key %s\n",
XkbKeyNameText(info->alias, XkbMessage),
XkbKeyNameText(info->real, XkbMessage));
ACTION("Ignored\n");
}
info->alias[0] = '\0';
continue;
}
lname = KeyNameToLong(info->alias);
if (FindNamedKey(xkb, lname, &kc, False, False, 0))
{
if (warningLevel > 4)
{
WARN("Attempt to create alias with the name of a real key\n");
ACTION2("Alias \"%s = %s\" ignored\n",
XkbKeyNameText(info->alias, XkbMessage),
XkbKeyNameText(info->real, XkbMessage));
}
info->alias[0] = '\0';
continue;
}
nNew++;
if (old)
{
for (i = 0, a = old; i < nOld; i++, a++)
{
if (strncmp(a->alias, info->alias, XkbKeyNameLength) == 0)
{
AliasInfo old;
InitAliasInfo(&old, MergeAugment, 0, a->alias, a->real);
HandleCollision(&old, info);
memcpy(old.real, a->real, XkbKeyNameLength);
info->alias[0] = '\0';
nNew--;
break;
}
}
}
}
if (nNew == 0)
{
ClearCommonInfo(&(*info_in)->def);
*info_in = NULL;
return True;
}
status = Success;
if (toGeom)
{
if (!xkb->geom)
{
XkbGeometrySizesRec sizes;
bzero((char *) &sizes, sizeof(XkbGeometrySizesRec));
sizes.which = XkbGeomKeyAliasesMask;
sizes.num_key_aliases = nOld + nNew;
status = XkbAllocGeometry(xkb, &sizes);
}
else
{
status = XkbAllocGeomKeyAliases(xkb->geom, nOld + nNew);
}
if (xkb->geom)
old = xkb->geom->key_aliases;
}
else
{
status = XkbAllocNames(xkb, XkbKeyAliasesMask, 0, nOld + nNew);
if (xkb->names)
old = xkb->names->key_aliases;
}
if (status != Success)
{
WSGO("Allocation failure in ApplyAliases\n");
return False;
}
if (toGeom)
a = &xkb->geom->key_aliases[nOld];
else
a = &xkb->names->key_aliases[nOld];
for (info = *info_in; info != NULL; info = (AliasInfo *) info->def.next)
{
if (info->alias[0] != '\0')
{
strncpy(a->alias, info->alias, XkbKeyNameLength);
strncpy(a->real, info->real, XkbKeyNameLength);
a++;
}
}
#ifdef DEBUG
if ((a - old) != (nOld + nNew))
{
WSGO2("Expected %d aliases total but created %d\n", nOld + nNew,
a - old);
}
#endif
if (toGeom)
xkb->geom->num_key_aliases += nNew;
ClearCommonInfo(&(*info_in)->def);
*info_in = NULL;
return True;
}