inpututils.c revision 9ace9065
16747b715Smrg/*
26747b715Smrg * Copyright © 2008 Daniel Stone
36747b715Smrg *
46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
56747b715Smrg * copy of this software and associated documentation files (the "Software"),
66747b715Smrg * to deal in the Software without restriction, including without limitation
76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
96747b715Smrg * Software is furnished to do so, subject to the following conditions:
106747b715Smrg *
116747b715Smrg * The above copyright notice and this permission notice (including the next
126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
136747b715Smrg * Software.
146747b715Smrg *
156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
206747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
216747b715Smrg * DEALINGS IN THE SOFTWARE.
226747b715Smrg *
236747b715Smrg * Author: Daniel Stone <daniel@fooishbar.org>
246747b715Smrg */
256747b715Smrg
266747b715Smrg#ifdef HAVE_DIX_CONFIG_H
276747b715Smrg#include "dix-config.h"
286747b715Smrg#endif
296747b715Smrg
306747b715Smrg#include "exevents.h"
316747b715Smrg#include "exglobals.h"
326747b715Smrg#include "misc.h"
336747b715Smrg#include "input.h"
346747b715Smrg#include "inputstr.h"
356747b715Smrg#include "xace.h"
366747b715Smrg#include "xkbsrv.h"
376747b715Smrg#include "xkbstr.h"
389ace9065Smrg#include "inpututils.h"
396747b715Smrg
406747b715Smrg/* Check if a button map change is okay with the device.
416747b715Smrg * Returns -1 for BadValue, as it collides with MappingBusy. */
426747b715Smrgstatic int
436747b715Smrgcheck_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out,
446747b715Smrg                    ClientPtr client)
456747b715Smrg{
466747b715Smrg    int i, ret;
476747b715Smrg
486747b715Smrg    if (!dev || !dev->button)
496747b715Smrg    {
506747b715Smrg        client->errorValue = (dev) ? dev->id : 0;
516747b715Smrg        return BadDevice;
526747b715Smrg    }
536747b715Smrg
546747b715Smrg    ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
556747b715Smrg    if (ret != Success)
566747b715Smrg    {
576747b715Smrg        client->errorValue = dev->id;
586747b715Smrg        return ret;
596747b715Smrg    }
606747b715Smrg
616747b715Smrg    for (i = 0; i < len; i++) {
626747b715Smrg        if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1])
636747b715Smrg            return MappingBusy;
646747b715Smrg    }
656747b715Smrg
666747b715Smrg    return Success;
676747b715Smrg}
686747b715Smrg
696747b715Smrgstatic void
706747b715Smrgdo_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
716747b715Smrg{
726747b715Smrg    int i;
736747b715Smrg    xEvent core_mn;
746747b715Smrg    deviceMappingNotify xi_mn;
756747b715Smrg
766747b715Smrg    /* The map in ButtonClassRec refers to button numbers, whereas the
776747b715Smrg     * protocol is zero-indexed.  Sigh. */
786747b715Smrg    memcpy(&(dev->button->map[1]), map, len);
796747b715Smrg
806747b715Smrg    core_mn.u.u.type = MappingNotify;
816747b715Smrg    core_mn.u.mappingNotify.request = MappingPointer;
826747b715Smrg
836747b715Smrg    /* 0 is the server client. */
846747b715Smrg    for (i = 1; i < currentMaxClients; i++) {
856747b715Smrg        /* Don't send irrelevant events to naïve clients. */
866747b715Smrg        if (!clients[i] || clients[i]->clientState != ClientStateRunning)
876747b715Smrg            continue;
886747b715Smrg
896747b715Smrg        if (!XIShouldNotify(clients[i], dev))
906747b715Smrg            continue;
916747b715Smrg
926747b715Smrg        WriteEventsToClient(clients[i], 1, &core_mn);
936747b715Smrg    }
946747b715Smrg
956747b715Smrg    xi_mn.type = DeviceMappingNotify;
966747b715Smrg    xi_mn.request = MappingPointer;
976747b715Smrg    xi_mn.deviceid = dev->id;
986747b715Smrg    xi_mn.time = GetTimeInMillis();
996747b715Smrg
1006747b715Smrg    SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1);
1016747b715Smrg}
1026747b715Smrg
1036747b715Smrg/*
1046747b715Smrg * Does what it says on the box, both for core and Xi.
1056747b715Smrg *
1066747b715Smrg * Faithfully reports any errors encountered while trying to apply the map
1076747b715Smrg * to the requested device, faithfully ignores any errors encountered while
1086747b715Smrg * trying to apply the map to its master/slaves.
1096747b715Smrg */
1106747b715Smrgint
1116747b715SmrgApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
1126747b715Smrg{
1136747b715Smrg    int ret;
1146747b715Smrg
1156747b715Smrg    /* If we can't perform the change on the requested device, bail out. */
1166747b715Smrg    ret = check_butmap_change(dev, map, len, &client->errorValue, client);
1176747b715Smrg    if (ret != Success)
1186747b715Smrg        return ret;
1196747b715Smrg    do_butmap_change(dev, map, len, client);
1206747b715Smrg
1216747b715Smrg    return Success;
1226747b715Smrg}
1236747b715Smrg
1246747b715Smrg/* Check if a modifier map change is okay with the device.
1256747b715Smrg * Returns -1 for BadValue, as it collides with MappingBusy; this particular
1266747b715Smrg * caveat can be removed with LegalModifier, as we have no other reason to
1276747b715Smrg * set MappingFailed.  Sigh. */
1286747b715Smrgstatic int
1296747b715Smrgcheck_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap)
1306747b715Smrg{
1316747b715Smrg    int ret, i;
1326747b715Smrg    XkbDescPtr xkb;
1336747b715Smrg
1346747b715Smrg    ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
1356747b715Smrg    if (ret != Success)
1366747b715Smrg        return ret;
1376747b715Smrg
1386747b715Smrg    if (!dev->key)
1396747b715Smrg        return BadMatch;
1406747b715Smrg    xkb = dev->key->xkbInfo->desc;
1416747b715Smrg
1426747b715Smrg    for (i = 0; i < MAP_LENGTH; i++) {
1436747b715Smrg        if (!modmap[i])
1446747b715Smrg            continue;
1456747b715Smrg
1466747b715Smrg        /* Check that all the new modifiers fall within the advertised
1476747b715Smrg         * keycode range. */
1486747b715Smrg        if (i < xkb->min_key_code || i > xkb->max_key_code) {
1496747b715Smrg            client->errorValue = i;
1506747b715Smrg            return -1;
1516747b715Smrg        }
1526747b715Smrg
1536747b715Smrg        /* Make sure the mapping is okay with the DDX. */
1546747b715Smrg        if (!LegalModifier(i, dev)) {
1556747b715Smrg            client->errorValue = i;
1566747b715Smrg            return MappingFailed;
1576747b715Smrg        }
1586747b715Smrg
1596747b715Smrg        /* None of the new modifiers may be down while we change the
1606747b715Smrg         * map. */
1616747b715Smrg        if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
1626747b715Smrg            client->errorValue = i;
1636747b715Smrg            return MappingBusy;
1646747b715Smrg        }
1656747b715Smrg    }
1666747b715Smrg
1676747b715Smrg    /* None of the old modifiers may be down while we change the map,
1686747b715Smrg     * either. */
1696747b715Smrg    for (i = xkb->min_key_code; i < xkb->max_key_code; i++) {
1706747b715Smrg        if (!xkb->map->modmap[i])
1716747b715Smrg            continue;
1726747b715Smrg        if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
1736747b715Smrg            client->errorValue = i;
1746747b715Smrg            return MappingBusy;
1756747b715Smrg        }
1766747b715Smrg    }
1776747b715Smrg
1786747b715Smrg    return Success;
1796747b715Smrg}
1806747b715Smrg
1816747b715Smrgstatic int
1826747b715Smrgcheck_modmap_change_slave(ClientPtr client, DeviceIntPtr master,
1836747b715Smrg                          DeviceIntPtr slave, CARD8 *modmap)
1846747b715Smrg{
1856747b715Smrg    XkbDescPtr master_xkb, slave_xkb;
1866747b715Smrg    int i, j;
1876747b715Smrg
1886747b715Smrg    if (!slave->key || !master->key)
1896747b715Smrg        return 0;
1906747b715Smrg
1916747b715Smrg    master_xkb = master->key->xkbInfo->desc;
1926747b715Smrg    slave_xkb = slave->key->xkbInfo->desc;
1936747b715Smrg
1946747b715Smrg    /* Ignore devices with a clearly different keymap. */
1956747b715Smrg    if (slave_xkb->min_key_code != master_xkb->min_key_code ||
1966747b715Smrg        slave_xkb->max_key_code != master_xkb->max_key_code)
1976747b715Smrg        return 0;
1986747b715Smrg
1996747b715Smrg    for (i = 0; i < MAP_LENGTH; i++) {
2006747b715Smrg        if (!modmap[i])
2016747b715Smrg            continue;
2026747b715Smrg
2036747b715Smrg        /* If we have different symbols for any modifier on an
2046747b715Smrg         * extended keyboard, ignore the whole remap request. */
2056747b715Smrg        for (j = 0;
2066747b715Smrg             j < XkbKeyNumSyms(slave_xkb, i) &&
2076747b715Smrg              j < XkbKeyNumSyms(master_xkb, i);
2086747b715Smrg             j++)
2096747b715Smrg            if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j])
2106747b715Smrg                return 0;
2116747b715Smrg    }
2126747b715Smrg
2136747b715Smrg    if (check_modmap_change(client, slave, modmap) != Success)
2146747b715Smrg        return 0;
2156747b715Smrg
2166747b715Smrg    return 1;
2176747b715Smrg}
2186747b715Smrg
2196747b715Smrg/* Actually change the modifier map, and send notifications.  Cannot fail. */
2206747b715Smrgstatic void
2216747b715Smrgdo_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap)
2226747b715Smrg{
2236747b715Smrg    XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient);
2246747b715Smrg}
2256747b715Smrg
2266747b715Smrg/* Rebuild modmap (key -> mod) from map (mod -> key). */
2276747b715Smrgstatic int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap,
2286747b715Smrg                                       int max_keys_per_mod)
2296747b715Smrg{
2306747b715Smrg    int i, len = max_keys_per_mod * 8;
2316747b715Smrg
2326747b715Smrg    memset(modmap, 0, MAP_LENGTH);
2336747b715Smrg
2346747b715Smrg    for (i = 0; i < len; i++) {
2356747b715Smrg        if (!modkeymap[i])
2366747b715Smrg            continue;
2376747b715Smrg
2386747b715Smrg        if (modkeymap[i] >= MAP_LENGTH)
2396747b715Smrg            return BadValue;
2406747b715Smrg
2416747b715Smrg        if (modmap[modkeymap[i]])
2426747b715Smrg            return BadValue;
2436747b715Smrg
2446747b715Smrg        modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod);
2456747b715Smrg    }
2466747b715Smrg
2476747b715Smrg    return Success;
2486747b715Smrg}
2496747b715Smrg
2506747b715Smrgint
2516747b715Smrgchange_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap,
2526747b715Smrg              int max_keys_per_mod)
2536747b715Smrg{
2546747b715Smrg    int ret;
2556747b715Smrg    CARD8 modmap[MAP_LENGTH];
2566747b715Smrg    DeviceIntPtr tmp;
2576747b715Smrg
2586747b715Smrg    ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod);
2596747b715Smrg    if (ret != Success)
2606747b715Smrg        return ret;
2616747b715Smrg
2626747b715Smrg    /* If we can't perform the change on the requested device, bail out. */
2636747b715Smrg    ret = check_modmap_change(client, dev, modmap);
2646747b715Smrg    if (ret != Success)
2656747b715Smrg        return ret;
2666747b715Smrg    do_modmap_change(client, dev, modmap);
2676747b715Smrg
2686747b715Smrg    /* Change any attached masters/slaves. */
2696747b715Smrg    if (IsMaster(dev)) {
2706747b715Smrg        for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
2716747b715Smrg            if (!IsMaster(tmp) && tmp->u.master == dev)
2726747b715Smrg                if (check_modmap_change_slave(client, dev, tmp, modmap))
2736747b715Smrg                    do_modmap_change(client, tmp, modmap);
2746747b715Smrg        }
2756747b715Smrg    }
2766747b715Smrg    else if (dev->u.master && dev->u.master->u.lastSlave == dev) {
2776747b715Smrg        /* If this fails, expect the results to be weird. */
2786747b715Smrg        if (check_modmap_change(client, dev->u.master, modmap))
2796747b715Smrg            do_modmap_change(client, dev->u.master, modmap);
2806747b715Smrg    }
2816747b715Smrg
2826747b715Smrg    return Success;
2836747b715Smrg}
2846747b715Smrg
2856747b715Smrgint generate_modkeymap(ClientPtr client, DeviceIntPtr dev,
2866747b715Smrg                       KeyCode **modkeymap_out, int *max_keys_per_mod_out)
2876747b715Smrg{
2886747b715Smrg    CARD8 keys_per_mod[8];
2896747b715Smrg    int max_keys_per_mod;
2908223e2f2Smrg    KeyCode *modkeymap = NULL;
2916747b715Smrg    int i, j, ret;
2926747b715Smrg
2936747b715Smrg    ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
2946747b715Smrg    if (ret != Success)
2956747b715Smrg        return ret;
2966747b715Smrg
2976747b715Smrg    if (!dev->key)
2986747b715Smrg        return BadMatch;
2996747b715Smrg
3006747b715Smrg    /* Count the number of keys per modifier to determine how wide we
3016747b715Smrg     * should make the map. */
3026747b715Smrg    max_keys_per_mod = 0;
3036747b715Smrg    for (i = 0; i < 8; i++)
3046747b715Smrg        keys_per_mod[i] = 0;
3056747b715Smrg    for (i = 8; i < MAP_LENGTH; i++) {
3066747b715Smrg        for (j = 0; j < 8; j++) {
3076747b715Smrg            if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
3086747b715Smrg                if (++keys_per_mod[j] > max_keys_per_mod)
3096747b715Smrg                    max_keys_per_mod = keys_per_mod[j];
3106747b715Smrg            }
3116747b715Smrg        }
3126747b715Smrg    }
3136747b715Smrg
3148223e2f2Smrg    if (max_keys_per_mod != 0) {
3158223e2f2Smrg        modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode));
3168223e2f2Smrg        if (!modkeymap)
3178223e2f2Smrg            return BadAlloc;
3186747b715Smrg
3198223e2f2Smrg        for (i = 0; i < 8; i++)
3208223e2f2Smrg            keys_per_mod[i] = 0;
3216747b715Smrg
3228223e2f2Smrg        for (i = 8; i < MAP_LENGTH; i++) {
3238223e2f2Smrg            for (j = 0; j < 8; j++) {
3248223e2f2Smrg                if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
3258223e2f2Smrg                    modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i;
3268223e2f2Smrg                    keys_per_mod[j]++;
3278223e2f2Smrg                }
3286747b715Smrg            }
3296747b715Smrg        }
3306747b715Smrg    }
3316747b715Smrg
3326747b715Smrg    *max_keys_per_mod_out = max_keys_per_mod;
3336747b715Smrg    *modkeymap_out = modkeymap;
3346747b715Smrg
3356747b715Smrg    return Success;
3366747b715Smrg}
3376747b715Smrg
3386747b715Smrg/**
3396747b715Smrg * Duplicate the InputAttributes in the most obvious way.
3406747b715Smrg * No special memory handling is used to give drivers the maximum
3416747b715Smrg * flexibility with the data. Drivers should be able to call realloc on the
3426747b715Smrg * product string if needed and perform similar operations.
3436747b715Smrg */
3446747b715SmrgInputAttributes*
3456747b715SmrgDuplicateInputAttributes(InputAttributes *attrs)
3466747b715Smrg{
3476747b715Smrg    InputAttributes *new_attr;
3486747b715Smrg    int ntags = 0;
3496747b715Smrg    char **tags, **new_tags;
3506747b715Smrg
3516747b715Smrg    if (!attrs)
3526747b715Smrg        return NULL;
3536747b715Smrg
3546747b715Smrg    if (!(new_attr = calloc(1, sizeof(InputAttributes))))
3556747b715Smrg        goto unwind;
3566747b715Smrg
3576747b715Smrg    if (attrs->product && !(new_attr->product = strdup(attrs->product)))
3586747b715Smrg        goto unwind;
3596747b715Smrg    if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor)))
3606747b715Smrg        goto unwind;
3616747b715Smrg    if (attrs->device && !(new_attr->device = strdup(attrs->device)))
3626747b715Smrg        goto unwind;
3636747b715Smrg    if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
3646747b715Smrg        goto unwind;
3656747b715Smrg    if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
3666747b715Smrg        goto unwind;
3676747b715Smrg
3686747b715Smrg    new_attr->flags = attrs->flags;
3696747b715Smrg
3706747b715Smrg    if ((tags = attrs->tags))
3716747b715Smrg    {
3726747b715Smrg        while(*tags++)
3736747b715Smrg            ntags++;
3746747b715Smrg
3756747b715Smrg        new_attr->tags = calloc(ntags + 1, sizeof(char*));
3766747b715Smrg        if (!new_attr->tags)
3776747b715Smrg            goto unwind;
3786747b715Smrg
3796747b715Smrg        tags = attrs->tags;
3806747b715Smrg        new_tags = new_attr->tags;
3816747b715Smrg
3826747b715Smrg        while(*tags)
3836747b715Smrg        {
3846747b715Smrg            *new_tags = strdup(*tags);
3856747b715Smrg            if (!*new_tags)
3866747b715Smrg                goto unwind;
3876747b715Smrg
3886747b715Smrg            tags++;
3896747b715Smrg            new_tags++;
3906747b715Smrg        }
3916747b715Smrg    }
3926747b715Smrg
3936747b715Smrg    return new_attr;
3946747b715Smrg
3956747b715Smrgunwind:
3966747b715Smrg    FreeInputAttributes(new_attr);
3976747b715Smrg    return NULL;
3986747b715Smrg}
3996747b715Smrg
4006747b715Smrgvoid
4016747b715SmrgFreeInputAttributes(InputAttributes *attrs)
4026747b715Smrg{
4036747b715Smrg    char **tags;
4046747b715Smrg
4056747b715Smrg    if (!attrs)
4066747b715Smrg        return;
4076747b715Smrg
4086747b715Smrg    free(attrs->product);
4096747b715Smrg    free(attrs->vendor);
4106747b715Smrg    free(attrs->device);
4116747b715Smrg    free(attrs->pnp_id);
4126747b715Smrg    free(attrs->usb_id);
4136747b715Smrg
4146747b715Smrg    if ((tags = attrs->tags))
4156747b715Smrg        while(*tags)
4166747b715Smrg            free(*tags++);
4176747b715Smrg
4186747b715Smrg    free(attrs->tags);
4196747b715Smrg    free(attrs);
4206747b715Smrg}
4216747b715Smrg
4229ace9065Smrg/**
4239ace9065Smrg * Alloc a valuator mask large enough for num_valuators.
4249ace9065Smrg */
4259ace9065SmrgValuatorMask*
4269ace9065Smrgvaluator_mask_new(int num_valuators)
4279ace9065Smrg{
4289ace9065Smrg    /* alloc a fixed size mask for now and ignore num_valuators. in the
4299ace9065Smrg     * flying-car future, when we can dynamically alloc the masks and are
4309ace9065Smrg     * not constrained by signals, we can start using num_valuators */
4319ace9065Smrg    ValuatorMask *mask = calloc(1, sizeof(ValuatorMask));
4329ace9065Smrg    mask->last_bit = -1;
4339ace9065Smrg    return mask;
4349ace9065Smrg}
4359ace9065Smrg
4369ace9065Smrgvoid
4379ace9065Smrgvaluator_mask_free(ValuatorMask **mask)
4389ace9065Smrg{
4399ace9065Smrg    free(*mask);
4409ace9065Smrg    *mask = NULL;
4419ace9065Smrg}
4429ace9065Smrg
4439ace9065Smrg
4449ace9065Smrg/**
4459ace9065Smrg * Sets a range of valuators between first_valuator and num_valuators with
4469ace9065Smrg * the data in the valuators array. All other values are set to 0.
4479ace9065Smrg */
4489ace9065Smrgvoid
4499ace9065Smrgvaluator_mask_set_range(ValuatorMask *mask, int first_valuator, int num_valuators,
4509ace9065Smrg                        const int* valuators)
4519ace9065Smrg{
4529ace9065Smrg    int i;
4539ace9065Smrg
4549ace9065Smrg    valuator_mask_zero(mask);
4559ace9065Smrg
4569ace9065Smrg    for (i = first_valuator; i < min(first_valuator + num_valuators, MAX_VALUATORS); i++)
4579ace9065Smrg        valuator_mask_set(mask, i, valuators[i - first_valuator]);
4589ace9065Smrg}
4599ace9065Smrg
4609ace9065Smrg/**
4619ace9065Smrg * Reset mask to zero.
4629ace9065Smrg */
4639ace9065Smrgvoid
4649ace9065Smrgvaluator_mask_zero(ValuatorMask *mask)
4659ace9065Smrg{
4669ace9065Smrg    memset(mask, 0, sizeof(*mask));
4679ace9065Smrg    mask->last_bit = -1;
4689ace9065Smrg}
4699ace9065Smrg
4709ace9065Smrg/**
4719ace9065Smrg * Returns the current size of the mask (i.e. the highest number of
4729ace9065Smrg * valuators currently set + 1).
4739ace9065Smrg */
4749ace9065Smrgint
4759ace9065Smrgvaluator_mask_size(const ValuatorMask *mask)
4769ace9065Smrg{
4779ace9065Smrg    return mask->last_bit + 1;
4789ace9065Smrg}
4799ace9065Smrg
4809ace9065Smrg/**
4819ace9065Smrg * Returns the number of valuators set in the given mask.
4829ace9065Smrg */
4839ace9065Smrgint
4849ace9065Smrgvaluator_mask_num_valuators(const ValuatorMask *mask)
4859ace9065Smrg{
4869ace9065Smrg    return CountBits(mask->mask, min(mask->last_bit + 1, MAX_VALUATORS));
4879ace9065Smrg}
4889ace9065Smrg
4899ace9065Smrg/**
4909ace9065Smrg * Return true if the valuator is set in the mask, or false otherwise.
4919ace9065Smrg */
4929ace9065Smrgint
4939ace9065Smrgvaluator_mask_isset(const ValuatorMask *mask, int valuator)
4949ace9065Smrg{
4959ace9065Smrg    return mask->last_bit >= valuator && BitIsOn(mask->mask, valuator);
4969ace9065Smrg}
4979ace9065Smrg
4989ace9065Smrg/**
4999ace9065Smrg * Set the valuator to the given data.
5009ace9065Smrg */
5019ace9065Smrgvoid
5029ace9065Smrgvaluator_mask_set(ValuatorMask *mask, int valuator, int data)
5039ace9065Smrg{
5049ace9065Smrg    mask->last_bit = max(valuator, mask->last_bit);
5059ace9065Smrg    SetBit(mask->mask, valuator);
5069ace9065Smrg    mask->valuators[valuator] = data;
5079ace9065Smrg}
5089ace9065Smrg
5099ace9065Smrg/**
5109ace9065Smrg * Return the requested valuator value. If the mask bit is not set for the
5119ace9065Smrg * given valuator, the returned value is undefined.
5129ace9065Smrg */
5139ace9065Smrgint
5149ace9065Smrgvaluator_mask_get(const ValuatorMask *mask, int valuator)
5159ace9065Smrg{
5169ace9065Smrg    return mask->valuators[valuator];
5179ace9065Smrg}
5189ace9065Smrg
5199ace9065Smrg/**
5209ace9065Smrg * Remove the valuator from the mask.
5219ace9065Smrg */
5229ace9065Smrgvoid
5239ace9065Smrgvaluator_mask_unset(ValuatorMask *mask, int valuator)
5249ace9065Smrg{
5259ace9065Smrg    if (mask->last_bit >= valuator) {
5269ace9065Smrg        int i, lastbit = -1;
5279ace9065Smrg
5289ace9065Smrg        ClearBit(mask->mask, valuator);
5299ace9065Smrg        mask->valuators[valuator] = 0;
5309ace9065Smrg
5319ace9065Smrg        for (i = 0; i <= mask->last_bit; i++)
5329ace9065Smrg            if (valuator_mask_isset(mask, i))
5339ace9065Smrg                lastbit = max(lastbit, i);
5349ace9065Smrg        mask->last_bit = lastbit;
5359ace9065Smrg    }
5369ace9065Smrg}
5379ace9065Smrg
5389ace9065Smrgvoid
5399ace9065Smrgvaluator_mask_copy(ValuatorMask *dest, const ValuatorMask *src)
5409ace9065Smrg{
5419ace9065Smrg    if (src)
5429ace9065Smrg        memcpy(dest, src, sizeof(*dest));
5439ace9065Smrg    else
5449ace9065Smrg        valuator_mask_zero(dest);
5459ace9065Smrg}
5469ace9065Smrg
5479ace9065Smrgint
5489ace9065SmrgCountBits(const uint8_t *mask, int len)
5499ace9065Smrg{
5509ace9065Smrg    int i;
5519ace9065Smrg    int ret = 0;
5529ace9065Smrg
5539ace9065Smrg    for (i = 0; i < len; i++)
5549ace9065Smrg        if (BitIsOn(mask, i))
5559ace9065Smrg            ret++;
5569ace9065Smrg
5579ace9065Smrg    return ret;
5589ace9065Smrg}
559