1f46a6179Smrg/************************************************************
2f46a6179Smrg Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3f46a6179Smrg
4f46a6179Smrg Permission to use, copy, modify, and distribute this
5f46a6179Smrg software and its documentation for any purpose and without
6f46a6179Smrg fee is hereby granted, provided that the above copyright
7f46a6179Smrg notice appear in all copies and that both that copyright
8f46a6179Smrg notice and this permission notice appear in supporting
9370d0a5eSmrg documentation, and that the name of Silicon Graphics not be
10370d0a5eSmrg used in advertising or publicity pertaining to distribution
11f46a6179Smrg of the software without specific prior written permission.
12370d0a5eSmrg Silicon Graphics makes no representation about the suitability
13f46a6179Smrg of this software for any purpose. It is provided "as is"
14f46a6179Smrg without any express or implied warranty.
15370d0a5eSmrg
16370d0a5eSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17370d0a5eSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18f46a6179Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19370d0a5eSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20370d0a5eSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21370d0a5eSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22f46a6179Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23f46a6179Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
24f46a6179Smrg
25f46a6179Smrg ********************************************************/
26f46a6179Smrg
27f46a6179Smrg#include "xkbcomp.h"
28f46a6179Smrg#include "tokens.h"
29f46a6179Smrg#include "expr.h"
30f46a6179Smrg
31f46a6179Smrg#include <ctype.h>
32f46a6179Smrg
33f46a6179Smrg/***====================================================================***/
34f46a6179Smrg
35f46a6179Smrgchar *
36f46a6179SmrgexprOpText(unsigned type)
37f46a6179Smrg{
3834345a63Smrg    static char buf[32];
3934345a63Smrg
4034345a63Smrg    switch (type)
4134345a63Smrg    {
4234345a63Smrg    case ExprValue:
4334345a63Smrg        strcpy(buf, "literal");
4434345a63Smrg        break;
4534345a63Smrg    case ExprIdent:
4634345a63Smrg        strcpy(buf, "identifier");
4734345a63Smrg        break;
4834345a63Smrg    case ExprActionDecl:
4934345a63Smrg        strcpy(buf, "action declaration");
5034345a63Smrg        break;
5134345a63Smrg    case ExprFieldRef:
5234345a63Smrg        strcpy(buf, "field reference");
5334345a63Smrg        break;
5434345a63Smrg    case ExprArrayRef:
5534345a63Smrg        strcpy(buf, "array reference");
5634345a63Smrg        break;
5734345a63Smrg    case ExprKeysymList:
5834345a63Smrg        strcpy(buf, "list of keysyms");
5934345a63Smrg        break;
6034345a63Smrg    case ExprActionList:
6134345a63Smrg        strcpy(buf, "list of actions");
6234345a63Smrg        break;
6334345a63Smrg    case OpAdd:
6434345a63Smrg        strcpy(buf, "addition");
6534345a63Smrg        break;
6634345a63Smrg    case OpSubtract:
6734345a63Smrg        strcpy(buf, "subtraction");
6834345a63Smrg        break;
6934345a63Smrg    case OpMultiply:
7034345a63Smrg        strcpy(buf, "multiplication");
7134345a63Smrg        break;
7234345a63Smrg    case OpDivide:
7334345a63Smrg        strcpy(buf, "division");
7434345a63Smrg        break;
7534345a63Smrg    case OpAssign:
7634345a63Smrg        strcpy(buf, "assignment");
7734345a63Smrg        break;
7834345a63Smrg    case OpNot:
7934345a63Smrg        strcpy(buf, "logical not");
8034345a63Smrg        break;
8134345a63Smrg    case OpNegate:
8234345a63Smrg        strcpy(buf, "arithmetic negation");
8334345a63Smrg        break;
8434345a63Smrg    case OpInvert:
8534345a63Smrg        strcpy(buf, "bitwise inversion");
8634345a63Smrg        break;
8734345a63Smrg    case OpUnaryPlus:
8834345a63Smrg        strcpy(buf, "plus sign");
8934345a63Smrg        break;
9034345a63Smrg    default:
9134345a63Smrg        snprintf(buf, sizeof(buf), "illegal(%d)", type);
9234345a63Smrg        break;
9334345a63Smrg    }
9434345a63Smrg    return buf;
95f46a6179Smrg}
96f46a6179Smrg
976ae2c069Smrgstatic char *
98f46a6179SmrgexprTypeText(unsigned type)
99f46a6179Smrg{
10034345a63Smrg    static char buf[20];
10134345a63Smrg
10234345a63Smrg    switch (type)
10334345a63Smrg    {
10434345a63Smrg    case TypeUnknown:
10534345a63Smrg        strcpy(buf, "unknown");
10634345a63Smrg        break;
10734345a63Smrg    case TypeBoolean:
10834345a63Smrg        strcpy(buf, "boolean");
10934345a63Smrg        break;
11034345a63Smrg    case TypeInt:
11134345a63Smrg        strcpy(buf, "int");
11234345a63Smrg        break;
11334345a63Smrg    case TypeString:
11434345a63Smrg        strcpy(buf, "string");
11534345a63Smrg        break;
11634345a63Smrg    case TypeAction:
11734345a63Smrg        strcpy(buf, "action");
11834345a63Smrg        break;
11934345a63Smrg    case TypeKeyName:
12034345a63Smrg        strcpy(buf, "keyname");
12134345a63Smrg        break;
12234345a63Smrg    default:
12334345a63Smrg        snprintf(buf, sizeof(buf), "illegal(%d)", type);
12434345a63Smrg        break;
12534345a63Smrg    }
12634345a63Smrg    return buf;
127f46a6179Smrg}
128f46a6179Smrg
129f46a6179Smrgint
1306ae2c069SmrgExprResolveLhs(const ExprDef *expr, ExprResult *elem_rtrn,
1316ae2c069Smrg               ExprResult *field_rtrn, ExprDef **index_rtrn)
132f46a6179Smrg{
13334345a63Smrg    switch (expr->op)
13434345a63Smrg    {
13534345a63Smrg    case ExprIdent:
13634345a63Smrg        elem_rtrn->str = NULL;
13734345a63Smrg        field_rtrn->str = XkbAtomGetString(NULL, expr->value.str);
13834345a63Smrg        *index_rtrn = NULL;
13934345a63Smrg        return True;
14034345a63Smrg    case ExprFieldRef:
14134345a63Smrg        elem_rtrn->str = XkbAtomGetString(NULL, expr->value.field.element);
14234345a63Smrg        field_rtrn->str = XkbAtomGetString(NULL, expr->value.field.field);
14334345a63Smrg        *index_rtrn = NULL;
14434345a63Smrg        return True;
14534345a63Smrg    case ExprArrayRef:
14634345a63Smrg        elem_rtrn->str = XkbAtomGetString(NULL, expr->value.array.element);
14734345a63Smrg        field_rtrn->str = XkbAtomGetString(NULL, expr->value.array.field);
14834345a63Smrg        *index_rtrn = expr->value.array.entry;
14934345a63Smrg        return True;
150f46a6179Smrg    }
151370d0a5eSmrg    WSGO("Unexpected operator %d in ResolveLhs\n", expr->op);
152f46a6179Smrg    return False;
153f46a6179Smrg}
154f46a6179Smrg
155f46a6179SmrgBool
1566ae2c069SmrgSimpleLookup(const XPointer priv,
1576ae2c069Smrg             Atom elem, Atom field, unsigned type, ExprResult *val_rtrn)
158f46a6179Smrg{
1596ae2c069Smrg    char *str;
160f46a6179Smrg
16134345a63Smrg    if ((priv == NULL) ||
16234345a63Smrg        (field == None) || (elem != None) ||
16334345a63Smrg        ((type != TypeInt) && (type != TypeFloat)))
16434345a63Smrg    {
16534345a63Smrg        return False;
166f46a6179Smrg    }
16734345a63Smrg    str = XkbAtomGetString(NULL, field);
1686ae2c069Smrg    for (const LookupEntry *entry = (const LookupEntry *) priv;
16934345a63Smrg         (entry != NULL) && (entry->name != NULL); entry++)
17034345a63Smrg    {
17134345a63Smrg        if (uStrCaseCmp(str, entry->name) == 0)
17234345a63Smrg        {
17334345a63Smrg            val_rtrn->uval = entry->result;
17434345a63Smrg            if (type == TypeFloat)
17534345a63Smrg                val_rtrn->uval *= XkbGeomPtsPerMM;
17634345a63Smrg            return True;
17734345a63Smrg        }
178f46a6179Smrg    }
179f46a6179Smrg    return False;
180f46a6179Smrg}
181f46a6179Smrg
182f46a6179SmrgBool
1836ae2c069SmrgRadioLookup(const XPointer priv,
1846ae2c069Smrg            Atom elem, Atom field, unsigned type, ExprResult *val_rtrn)
185f46a6179Smrg{
1866ae2c069Smrg    char *str;
18734345a63Smrg    int rg;
18834345a63Smrg
18934345a63Smrg    if ((field == None) || (elem != None) || (type != TypeInt))
19034345a63Smrg        return False;
19134345a63Smrg    str = XkbAtomGetString(NULL, field);
19234345a63Smrg    if (str)
19334345a63Smrg    {
19434345a63Smrg        if (uStrCasePrefix("group", str))
19534345a63Smrg            str += strlen("group");
19634345a63Smrg        else if (uStrCasePrefix("radiogroup", str))
19734345a63Smrg            str += strlen("radiogroup");
19834345a63Smrg        else if (uStrCasePrefix("rg", str))
19934345a63Smrg            str += strlen("rg");
20034345a63Smrg        else if (!isdigit(str[0]))
20134345a63Smrg            str = NULL;
202f46a6179Smrg    }
20334345a63Smrg    if ((!str) || (sscanf(str, "%i", &rg) < 1) || (rg < 1)
20434345a63Smrg        || (rg > XkbMaxRadioGroups))
20534345a63Smrg        return False;
20634345a63Smrg    val_rtrn->uval = rg;
207f46a6179Smrg    return True;
208f46a6179Smrg}
209f46a6179Smrg
2106ae2c069Smrg#if 0
2116ae2c069Smrgstatic int
21234345a63SmrgTableLookup(XPointer priv,
21334345a63Smrg            Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
214f46a6179Smrg{
21534345a63Smrg    LookupTable *tbl = (LookupTable *) priv;
2166ae2c069Smrg    char *str;
21734345a63Smrg
21834345a63Smrg    if ((priv == NULL) || (field == None) || (type != TypeInt))
21934345a63Smrg        return False;
22034345a63Smrg    str = XkbAtomGetString(NULL, elem);
22134345a63Smrg    while (tbl)
22234345a63Smrg    {
22334345a63Smrg        if (((str == NULL) && (tbl->element == NULL)) ||
22434345a63Smrg            ((str != NULL) && (tbl->element != NULL) &&
22534345a63Smrg             (uStrCaseCmp(str, tbl->element) == 0)))
22634345a63Smrg        {
22734345a63Smrg            break;
22834345a63Smrg        }
22934345a63Smrg        tbl = tbl->nextElement;
230f46a6179Smrg    }
23134345a63Smrg    if (tbl == NULL)            /* didn't find a matching element */
23234345a63Smrg        return False;
23334345a63Smrg    priv = (XPointer) tbl->entries;
23434345a63Smrg    return SimpleLookup(priv, (Atom) None, field, type, val_rtrn);
235f46a6179Smrg}
2366ae2c069Smrg#endif
237f46a6179Smrg
238f46a6179Smrgstatic LookupEntry modIndexNames[] = {
23934345a63Smrg    {"shift", ShiftMapIndex},
24034345a63Smrg    {"control", ControlMapIndex},
24134345a63Smrg    {"lock", LockMapIndex},
24234345a63Smrg    {"mod1", Mod1MapIndex},
24334345a63Smrg    {"mod2", Mod2MapIndex},
24434345a63Smrg    {"mod3", Mod3MapIndex},
24534345a63Smrg    {"mod4", Mod4MapIndex},
24634345a63Smrg    {"mod5", Mod5MapIndex},
24734345a63Smrg    {"none", XkbNoModifier},
24834345a63Smrg    {NULL, 0}
249f46a6179Smrg};
250f46a6179Smrg
2516ae2c069SmrgBool
2526ae2c069SmrgLookupModIndex(const XPointer priv,
2536ae2c069Smrg               Atom elem, Atom field, unsigned type, ExprResult *val_rtrn)
254f46a6179Smrg{
25534345a63Smrg    return SimpleLookup((XPointer) modIndexNames, elem, field, type,
25634345a63Smrg                        val_rtrn);
257f46a6179Smrg}
258f46a6179Smrg
2596ae2c069Smrgstatic int
26034345a63SmrgLookupModMask(XPointer priv,
26134345a63Smrg              Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
262f46a6179Smrg{
26334345a63Smrg    char *str;
26434345a63Smrg
26534345a63Smrg    if ((elem != None) || (type != TypeInt))
26634345a63Smrg        return False;
26734345a63Smrg    str = XkbAtomGetString(NULL, field);
26834345a63Smrg    if (str == NULL)
26934345a63Smrg        return False;
27034345a63Smrg    if (uStrCaseCmp(str, "all") == 0)
27134345a63Smrg        val_rtrn->uval = 0xff;
27234345a63Smrg    else if (uStrCaseCmp(str, "none") == 0)
27334345a63Smrg        val_rtrn->uval = 0;
27434345a63Smrg    else if (LookupModIndex(priv, elem, field, type, val_rtrn))
2756ae2c069Smrg        val_rtrn->uval = (1U << val_rtrn->uval);
27634345a63Smrg    else if (priv != NULL)
27734345a63Smrg    {
27834345a63Smrg        LookupPriv *lpriv = (LookupPriv *) priv;
27934345a63Smrg        if ((lpriv->chain == NULL) ||
28034345a63Smrg            (!(*lpriv->chain) (lpriv->chainPriv, elem, field, type,
28134345a63Smrg                               val_rtrn)))
28234345a63Smrg            return False;
283f46a6179Smrg    }
28434345a63Smrg    else
28534345a63Smrg        return False;
286f46a6179Smrg    return True;
287f46a6179Smrg}
288f46a6179Smrg
2896ae2c069Smrg#if 0
290f46a6179Smrgint
2916ae2c069SmrgExprResolveModIndex(const ExprDef *expr,
29234345a63Smrg                    ExprResult * val_rtrn,
29334345a63Smrg                    IdentLookupFunc lookup, XPointer lookupPriv)
294f46a6179Smrg{
29534345a63Smrg    int ok = 0;
296c82dfdfbSmrg    const char *bogus = NULL;
29734345a63Smrg
29834345a63Smrg    switch (expr->op)
29934345a63Smrg    {
30034345a63Smrg    case ExprValue:
30134345a63Smrg        if (expr->type != TypeInt)
30234345a63Smrg        {
303370d0a5eSmrg            ERROR
30434345a63Smrg                ("Found constant of type %s where a modifier mask was expected\n",
30534345a63Smrg                 exprTypeText(expr->type));
30634345a63Smrg            return False;
30734345a63Smrg        }
30834345a63Smrg        else if ((expr->value.ival >= XkbNumModifiers)
30934345a63Smrg                 || (expr->value.ival < 0))
31034345a63Smrg        {
311370d0a5eSmrg            ERROR("Illegal modifier index (%d, must be 0..%d)\n",
31234345a63Smrg                   expr->value.ival, XkbNumModifiers - 1);
31334345a63Smrg            return False;
31434345a63Smrg        }
31534345a63Smrg        val_rtrn->ival = expr->value.ival;
31634345a63Smrg        return True;
31734345a63Smrg    case ExprIdent:
31834345a63Smrg        if (LookupModIndex(lookupPriv, (Atom) None, expr->value.str,
31934345a63Smrg                           (unsigned) TypeInt, val_rtrn))
32034345a63Smrg        {
32134345a63Smrg            return True;
32234345a63Smrg        }
32334345a63Smrg        if (lookup)
32434345a63Smrg        {
32534345a63Smrg            ok = (*lookup) (lookupPriv,
32634345a63Smrg                            None, expr->value.str, TypeInt, val_rtrn);
32734345a63Smrg        }
32834345a63Smrg        if (!ok)
329370d0a5eSmrg            ERROR("Cannot determine modifier index for \"%s\"\n",
33034345a63Smrg                   XkbAtomText(NULL, expr->value.str, XkbMessage));
33134345a63Smrg        break;
33234345a63Smrg    case ExprFieldRef:
33334345a63Smrg        bogus = "field reference";
33434345a63Smrg        break;
33534345a63Smrg    case ExprArrayRef:
33634345a63Smrg        bogus = "array reference";
33734345a63Smrg        break;
33834345a63Smrg    case ExprActionDecl:
33934345a63Smrg        bogus = "function";
34034345a63Smrg        break;
34134345a63Smrg    case OpAdd:
34234345a63Smrg    case OpSubtract:
34334345a63Smrg    case OpMultiply:
34434345a63Smrg    case OpDivide:
34534345a63Smrg    case OpInvert:
34634345a63Smrg    case OpNegate:
34734345a63Smrg    case OpNot:
34834345a63Smrg    case OpUnaryPlus:
34934345a63Smrg        bogus = "arithmetic operations";
35034345a63Smrg        break;
35134345a63Smrg    case OpAssign:
35234345a63Smrg        bogus = "assignment";
35334345a63Smrg        break;
35434345a63Smrg    default:
355370d0a5eSmrg        WSGO("Unknown operator %d in ResolveModIndex\n", expr->op);
35634345a63Smrg        return False;
357f46a6179Smrg    }
35834345a63Smrg    if (bogus)
35934345a63Smrg    {
360370d0a5eSmrg        ERROR("Modifier index must be a name or number, %s ignored\n",
36134345a63Smrg               bogus);
36234345a63Smrg        return False;
363f46a6179Smrg    }
364f46a6179Smrg    return ok;
365f46a6179Smrg}
3666ae2c069Smrg#endif
367f46a6179Smrg
368f46a6179Smrgint
3696ae2c069SmrgExprResolveModMask(const ExprDef *expr, ExprResult *val_rtrn,
37034345a63Smrg                   IdentLookupFunc lookup, XPointer lookupPriv)
371f46a6179Smrg{
3726ae2c069Smrg    LookupPriv priv = {
3736ae2c069Smrg        .priv = NULL,
3746ae2c069Smrg        .chain = lookup,
3756ae2c069Smrg        .chainPriv = lookupPriv
3766ae2c069Smrg    };
377f46a6179Smrg
3786ae2c069Smrg    return ExprResolveMask(expr, val_rtrn, LookupModMask, (XPointer) &priv);
379f46a6179Smrg}
380f46a6179Smrg
381f46a6179Smrgint
3826ae2c069SmrgExprResolveBoolean(const ExprDef *expr, ExprResult *val_rtrn,
38334345a63Smrg                   IdentLookupFunc lookup, XPointer lookupPriv)
384f46a6179Smrg{
38534345a63Smrg    int ok = 0;
386c82dfdfbSmrg    const char *bogus = NULL;
38734345a63Smrg
38834345a63Smrg    switch (expr->op)
38934345a63Smrg    {
39034345a63Smrg    case ExprValue:
39134345a63Smrg        if (expr->type != TypeBoolean)
39234345a63Smrg        {
393370d0a5eSmrg            ERROR
39434345a63Smrg                ("Found constant of type %s where boolean was expected\n",
39534345a63Smrg                 exprTypeText(expr->type));
39634345a63Smrg            return False;
39734345a63Smrg        }
39834345a63Smrg        val_rtrn->ival = expr->value.ival;
39934345a63Smrg        return True;
40034345a63Smrg    case ExprIdent:
40134345a63Smrg        bogus = XkbAtomGetString(NULL, expr->value.str);
40234345a63Smrg        if (bogus)
40334345a63Smrg        {
40434345a63Smrg            if ((uStrCaseCmp(bogus, "true") == 0) ||
40534345a63Smrg                (uStrCaseCmp(bogus, "yes") == 0) ||
40634345a63Smrg                (uStrCaseCmp(bogus, "on") == 0))
40734345a63Smrg            {
40834345a63Smrg                val_rtrn->uval = 1;
40934345a63Smrg                return True;
41034345a63Smrg            }
41134345a63Smrg            else if ((uStrCaseCmp(bogus, "false") == 0) ||
41234345a63Smrg                     (uStrCaseCmp(bogus, "no") == 0) ||
41334345a63Smrg                     (uStrCaseCmp(bogus, "off") == 0))
41434345a63Smrg            {
41534345a63Smrg                val_rtrn->uval = 0;
41634345a63Smrg                return True;
41734345a63Smrg            }
41834345a63Smrg        }
41934345a63Smrg        if (lookup)
42034345a63Smrg        {
42134345a63Smrg            ok = (*lookup) (lookupPriv,
42234345a63Smrg                            None, expr->value.str, TypeBoolean, val_rtrn);
42334345a63Smrg        }
42434345a63Smrg        if (!ok)
425370d0a5eSmrg            ERROR("Identifier \"%s\" of type int is unknown\n",
42634345a63Smrg                   XkbAtomText(NULL, expr->value.str, XkbMessage));
42734345a63Smrg        return ok;
42834345a63Smrg    case ExprFieldRef:
42934345a63Smrg        if (lookup)
43034345a63Smrg        {
43134345a63Smrg            ok = (*lookup) (lookupPriv,
43234345a63Smrg                            expr->value.field.element,
43334345a63Smrg                            expr->value.field.field, TypeBoolean, val_rtrn);
43434345a63Smrg        }
43534345a63Smrg        if (!ok)
436370d0a5eSmrg            ERROR("Default \"%s.%s\" of type boolean is unknown\n",
43734345a63Smrg                   XkbAtomText(NULL, expr->value.field.element, XkbMessage),
43834345a63Smrg                   XkbAtomText(NULL, expr->value.field.field, XkbMessage));
43934345a63Smrg        return ok;
44034345a63Smrg    case OpInvert:
44134345a63Smrg    case OpNot:
44234345a63Smrg        ok = ExprResolveBoolean(expr, val_rtrn, lookup, lookupPriv);
44334345a63Smrg        if (ok)
44434345a63Smrg            val_rtrn->uval = !val_rtrn->uval;
44534345a63Smrg        return ok;
44634345a63Smrg    case OpAdd:
4476ae2c069Smrg        bogus = "Addition";
4486ae2c069Smrg        goto boolean;
44934345a63Smrg    case OpSubtract:
4506ae2c069Smrg        bogus = "Subtraction";
4516ae2c069Smrg        goto boolean;
45234345a63Smrg    case OpMultiply:
4536ae2c069Smrg        bogus = "Multiplication";
4546ae2c069Smrg        goto boolean;
45534345a63Smrg    case OpDivide:
4566ae2c069Smrg        bogus = "Division";
4576ae2c069Smrg        goto boolean;
45834345a63Smrg    case OpAssign:
4596ae2c069Smrg        bogus = "Assignment";
4606ae2c069Smrg        goto boolean;
46134345a63Smrg    case OpNegate:
4626ae2c069Smrg        bogus = "Negation";
4636ae2c069Smrg        goto boolean;
4646ae2c069Smrg    boolean:
465370d0a5eSmrg        ERROR("%s of boolean values not permitted\n", bogus);
46634345a63Smrg        break;
46734345a63Smrg    case OpUnaryPlus:
46834345a63Smrg        ERROR("Unary \"+\" operator not permitted for boolean values\n");
46934345a63Smrg        break;
47034345a63Smrg    default:
471370d0a5eSmrg        WSGO("Unknown operator %d in ResolveBoolean\n", expr->op);
47234345a63Smrg        break;
473f46a6179Smrg    }
474f46a6179Smrg    return False;
475f46a6179Smrg}
476f46a6179Smrg
477f46a6179Smrgint
4786ae2c069SmrgExprResolveFloat(const ExprDef *expr, ExprResult *val_rtrn,
47934345a63Smrg                 IdentLookupFunc lookup, XPointer lookupPriv)
480f46a6179Smrg{
48134345a63Smrg    int ok = 0;
48234345a63Smrg    ExprResult leftRtrn, rightRtrn;
48334345a63Smrg    ExprDef *left, *right;
48434345a63Smrg
48534345a63Smrg    switch (expr->op)
48634345a63Smrg    {
48734345a63Smrg    case ExprValue:
48834345a63Smrg        if (expr->type == TypeString)
48934345a63Smrg        {
4906ae2c069Smrg            char *str;
49134345a63Smrg            str = XkbAtomGetString(NULL, expr->value.str);
49234345a63Smrg            if ((str != NULL) && (strlen(str) == 1))
49334345a63Smrg            {
49434345a63Smrg                val_rtrn->uval = str[0] * XkbGeomPtsPerMM;
49534345a63Smrg                return True;
49634345a63Smrg            }
49734345a63Smrg        }
49834345a63Smrg        if ((expr->type != TypeInt) && (expr->type != TypeFloat))
49934345a63Smrg        {
500370d0a5eSmrg            ERROR("Found constant of type %s, expected a number\n",
50134345a63Smrg                   exprTypeText(expr->type));
50234345a63Smrg            return False;
50334345a63Smrg        }
50434345a63Smrg        val_rtrn->ival = expr->value.ival;
50534345a63Smrg        if (expr->type == TypeInt)
50634345a63Smrg            val_rtrn->ival *= XkbGeomPtsPerMM;
50734345a63Smrg        return True;
50834345a63Smrg    case ExprIdent:
50934345a63Smrg        if (lookup)
51034345a63Smrg        {
51134345a63Smrg            ok = (*lookup) (lookupPriv,
51234345a63Smrg                            None, expr->value.str, TypeFloat, val_rtrn);
51334345a63Smrg        }
51434345a63Smrg        if (!ok)
515370d0a5eSmrg            ERROR("Numeric identifier \"%s\" unknown\n",
51634345a63Smrg                   XkbAtomText(NULL, expr->value.str, XkbMessage));
51734345a63Smrg        return ok;
51834345a63Smrg    case ExprFieldRef:
51934345a63Smrg        if (lookup)
52034345a63Smrg        {
52134345a63Smrg            ok = (*lookup) (lookupPriv,
52234345a63Smrg                            expr->value.field.element,
52334345a63Smrg                            expr->value.field.field, TypeFloat, val_rtrn);
52434345a63Smrg        }
52534345a63Smrg        if (!ok)
526370d0a5eSmrg            ERROR("Numeric default \"%s.%s\" unknown\n",
52734345a63Smrg                   XkbAtomText(NULL, expr->value.field.element, XkbMessage),
52834345a63Smrg                   XkbAtomText(NULL, expr->value.field.field, XkbMessage));
52934345a63Smrg        return ok;
53034345a63Smrg    case OpAdd:
53134345a63Smrg    case OpSubtract:
53234345a63Smrg    case OpMultiply:
53334345a63Smrg    case OpDivide:
53434345a63Smrg        left = expr->value.binary.left;
53534345a63Smrg        right = expr->value.binary.right;
53634345a63Smrg        if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv) &&
53734345a63Smrg            ExprResolveFloat(right, &rightRtrn, lookup, lookupPriv))
53834345a63Smrg        {
53934345a63Smrg            switch (expr->op)
54034345a63Smrg            {
54134345a63Smrg            case OpAdd:
54234345a63Smrg                val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
54334345a63Smrg                break;
54434345a63Smrg            case OpSubtract:
54534345a63Smrg                val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
54634345a63Smrg                break;
54734345a63Smrg            case OpMultiply:
54834345a63Smrg                val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
54934345a63Smrg                break;
55034345a63Smrg            case OpDivide:
55134345a63Smrg                val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
55234345a63Smrg                break;
55334345a63Smrg            }
55434345a63Smrg            return True;
55534345a63Smrg        }
55634345a63Smrg        return False;
55734345a63Smrg    case OpAssign:
55834345a63Smrg        WSGO("Assignment operator not implemented yet\n");
55934345a63Smrg        break;
56034345a63Smrg    case OpNot:
56134345a63Smrg        left = expr->value.child;
56234345a63Smrg        if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv))
56334345a63Smrg        {
56434345a63Smrg            ERROR("The ! operator cannot be applied to a number\n");
56534345a63Smrg        }
56634345a63Smrg        return False;
56734345a63Smrg    case OpInvert:
56834345a63Smrg    case OpNegate:
56934345a63Smrg        left = expr->value.child;
57034345a63Smrg        if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv))
57134345a63Smrg        {
57234345a63Smrg            if (expr->op == OpNegate)
57334345a63Smrg                val_rtrn->ival = -leftRtrn.ival;
57434345a63Smrg            else
57534345a63Smrg                val_rtrn->ival = ~leftRtrn.ival;
57634345a63Smrg            return True;
57734345a63Smrg        }
57834345a63Smrg        return False;
57934345a63Smrg    case OpUnaryPlus:
58034345a63Smrg        left = expr->value.child;
58134345a63Smrg        return ExprResolveFloat(left, val_rtrn, lookup, lookupPriv);
58234345a63Smrg    default:
583370d0a5eSmrg        WSGO("Unknown operator %d in ResolveFloat\n", expr->op);
58434345a63Smrg        break;
585f46a6179Smrg    }
586f46a6179Smrg    return False;
587f46a6179Smrg}
588f46a6179Smrg
589f46a6179Smrgint
5906ae2c069SmrgExprResolveInteger(const ExprDef *expr, ExprResult *val_rtrn,
59134345a63Smrg                   IdentLookupFunc lookup, XPointer lookupPriv)
592f46a6179Smrg{
59334345a63Smrg    int ok = 0;
59434345a63Smrg    ExprResult leftRtrn, rightRtrn;
59534345a63Smrg    ExprDef *left, *right;
59634345a63Smrg
59734345a63Smrg    switch (expr->op)
59834345a63Smrg    {
59934345a63Smrg    case ExprValue:
60034345a63Smrg        if (expr->type == TypeString)
60134345a63Smrg        {
6026ae2c069Smrg            char *str;
60334345a63Smrg            str = XkbAtomGetString(NULL, expr->value.str);
60434345a63Smrg            if (str != NULL)
60534345a63Smrg                switch (strlen(str))
60634345a63Smrg                {
60734345a63Smrg                case 0:
60834345a63Smrg                    val_rtrn->uval = 0;
60934345a63Smrg                    return True;
61034345a63Smrg                case 1:
61134345a63Smrg                    val_rtrn->uval = str[0];
61234345a63Smrg                    return True;
61334345a63Smrg                default:
61434345a63Smrg                    break;
61534345a63Smrg                }
61634345a63Smrg        }
61734345a63Smrg        if ((expr->type != TypeInt) && (expr->type != TypeFloat))
61834345a63Smrg        {
619370d0a5eSmrg            ERROR
62034345a63Smrg                ("Found constant of type %s where an int was expected\n",
62134345a63Smrg                 exprTypeText(expr->type));
62234345a63Smrg            return False;
62334345a63Smrg        }
62434345a63Smrg        val_rtrn->ival = expr->value.ival;
62534345a63Smrg        if (expr->type == TypeFloat)
62634345a63Smrg            val_rtrn->ival /= XkbGeomPtsPerMM;
62734345a63Smrg        return True;
62834345a63Smrg    case ExprIdent:
62934345a63Smrg        if (lookup)
63034345a63Smrg        {
63134345a63Smrg            ok = (*lookup) (lookupPriv,
63234345a63Smrg                            None, expr->value.str, TypeInt, val_rtrn);
63334345a63Smrg        }
63434345a63Smrg        if (!ok)
635370d0a5eSmrg            ERROR("Identifier \"%s\" of type int is unknown\n",
63634345a63Smrg                   XkbAtomText(NULL, expr->value.str, XkbMessage));
63734345a63Smrg        return ok;
63834345a63Smrg    case ExprFieldRef:
63934345a63Smrg        if (lookup)
64034345a63Smrg        {
64134345a63Smrg            ok = (*lookup) (lookupPriv,
64234345a63Smrg                            expr->value.field.element,
64334345a63Smrg                            expr->value.field.field, TypeInt, val_rtrn);
64434345a63Smrg        }
64534345a63Smrg        if (!ok)
646370d0a5eSmrg            ERROR("Default \"%s.%s\" of type int is unknown\n",
64734345a63Smrg                   XkbAtomText(NULL, expr->value.field.element, XkbMessage),
64834345a63Smrg                   XkbAtomText(NULL, expr->value.field.field, XkbMessage));
64934345a63Smrg        return ok;
65034345a63Smrg    case OpAdd:
65134345a63Smrg    case OpSubtract:
65234345a63Smrg    case OpMultiply:
65334345a63Smrg    case OpDivide:
65434345a63Smrg        left = expr->value.binary.left;
65534345a63Smrg        right = expr->value.binary.right;
65634345a63Smrg        if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv) &&
65734345a63Smrg            ExprResolveInteger(right, &rightRtrn, lookup, lookupPriv))
65834345a63Smrg        {
65934345a63Smrg            switch (expr->op)
66034345a63Smrg            {
66134345a63Smrg            case OpAdd:
66234345a63Smrg                val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
66334345a63Smrg                break;
66434345a63Smrg            case OpSubtract:
66534345a63Smrg                val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
66634345a63Smrg                break;
66734345a63Smrg            case OpMultiply:
66834345a63Smrg                val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
66934345a63Smrg                break;
67034345a63Smrg            case OpDivide:
67134345a63Smrg                val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
67234345a63Smrg                break;
67334345a63Smrg            }
67434345a63Smrg            return True;
67534345a63Smrg        }
67634345a63Smrg        return False;
67734345a63Smrg    case OpAssign:
67834345a63Smrg        WSGO("Assignment operator not implemented yet\n");
67934345a63Smrg        break;
68034345a63Smrg    case OpNot:
68134345a63Smrg        left = expr->value.child;
68234345a63Smrg        if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
68334345a63Smrg        {
68434345a63Smrg            ERROR("The ! operator cannot be applied to an integer\n");
68534345a63Smrg        }
68634345a63Smrg        return False;
68734345a63Smrg    case OpInvert:
68834345a63Smrg    case OpNegate:
68934345a63Smrg        left = expr->value.child;
69034345a63Smrg        if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
69134345a63Smrg        {
69234345a63Smrg            if (expr->op == OpNegate)
69334345a63Smrg                val_rtrn->ival = -leftRtrn.ival;
69434345a63Smrg            else
69534345a63Smrg                val_rtrn->ival = ~leftRtrn.ival;
69634345a63Smrg            return True;
69734345a63Smrg        }
69834345a63Smrg        return False;
69934345a63Smrg    case OpUnaryPlus:
70034345a63Smrg        left = expr->value.child;
70134345a63Smrg        return ExprResolveInteger(left, val_rtrn, lookup, lookupPriv);
70234345a63Smrg    default:
703370d0a5eSmrg        WSGO("Unknown operator %d in ResolveInteger\n", expr->op);
70434345a63Smrg        break;
705f46a6179Smrg    }
706f46a6179Smrg    return False;
707f46a6179Smrg}
708f46a6179Smrg
709f46a6179Smrgint
7106ae2c069SmrgExprResolveString(const ExprDef *expr, ExprResult *val_rtrn,
71134345a63Smrg                  IdentLookupFunc lookup, XPointer lookupPriv)
712f46a6179Smrg{
71334345a63Smrg    int ok = 0;
71434345a63Smrg    ExprResult leftRtrn, rightRtrn;
71534345a63Smrg    ExprDef *left;
71634345a63Smrg    ExprDef *right;
717c82dfdfbSmrg    const char *bogus = NULL;
71834345a63Smrg
71934345a63Smrg    switch (expr->op)
72034345a63Smrg    {
72134345a63Smrg    case ExprValue:
72234345a63Smrg        if (expr->type != TypeString)
72334345a63Smrg        {
724370d0a5eSmrg            ERROR("Found constant of type %s, expected a string\n",
72534345a63Smrg                   exprTypeText(expr->type));
72634345a63Smrg            return False;
72734345a63Smrg        }
72834345a63Smrg        val_rtrn->str = XkbAtomGetString(NULL, expr->value.str);
72934345a63Smrg        if (val_rtrn->str == NULL)
73034345a63Smrg        {
731319fa471Smrg            static char empty_char = '\0';
732319fa471Smrg            val_rtrn->str = &empty_char;
73334345a63Smrg        }
73434345a63Smrg        return True;
73534345a63Smrg    case ExprIdent:
73634345a63Smrg        if (lookup)
73734345a63Smrg        {
73834345a63Smrg            ok = (*lookup) (lookupPriv,
73934345a63Smrg                            None, expr->value.str, TypeString, val_rtrn);
74034345a63Smrg        }
74134345a63Smrg        if (!ok)
742370d0a5eSmrg            ERROR("Identifier \"%s\" of type string not found\n",
74334345a63Smrg                   XkbAtomText(NULL, expr->value.str, XkbMessage));
74434345a63Smrg        return ok;
74534345a63Smrg    case ExprFieldRef:
74634345a63Smrg        if (lookup)
74734345a63Smrg        {
74834345a63Smrg            ok = (*lookup) (lookupPriv,
74934345a63Smrg                            expr->value.field.element,
75034345a63Smrg                            expr->value.field.field, TypeString, val_rtrn);
75134345a63Smrg        }
75234345a63Smrg        if (!ok)
753370d0a5eSmrg            ERROR("Default \"%s.%s\" of type string not found\n",
75434345a63Smrg                   XkbAtomText(NULL, expr->value.field.element, XkbMessage),
75534345a63Smrg                   XkbAtomText(NULL, expr->value.field.field, XkbMessage));
75634345a63Smrg        return ok;
75734345a63Smrg    case OpAdd:
75834345a63Smrg        left = expr->value.binary.left;
75934345a63Smrg        right = expr->value.binary.right;
76034345a63Smrg        if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv) &&
76134345a63Smrg            ExprResolveString(right, &rightRtrn, lookup, lookupPriv))
76234345a63Smrg        {
76334345a63Smrg            char *new;
7646ae2c069Smrg
7656ae2c069Smrg#ifdef HAVE_ASPRINTF
7666ae2c069Smrg            if (asprintf(&new, "%s%s", leftRtrn.str, rightRtrn.str) < 0)
7676ae2c069Smrg                new = NULL;
7686ae2c069Smrg#else
7696ae2c069Smrg            size_t len = strlen(leftRtrn.str) + strlen(rightRtrn.str) + 1;
7706ae2c069Smrg            new = malloc(len);
7716ae2c069Smrg#endif
77234345a63Smrg            if (new)
77334345a63Smrg            {
7746ae2c069Smrg#ifndef HAVE_ASPRINTF
775c82dfdfbSmrg                snprintf(new, len, "%s%s", leftRtrn.str, rightRtrn.str);
7766ae2c069Smrg#endif
77734345a63Smrg                val_rtrn->str = new;
77834345a63Smrg                return True;
77934345a63Smrg            }
78034345a63Smrg        }
78134345a63Smrg        return False;
78234345a63Smrg    case OpSubtract:
7836ae2c069Smrg        bogus = "Subtraction";
7846ae2c069Smrg        goto string;
78534345a63Smrg    case OpMultiply:
7866ae2c069Smrg        bogus = "Multiplication";
7876ae2c069Smrg        goto string;
78834345a63Smrg    case OpDivide:
7896ae2c069Smrg        bogus = "Division";
7906ae2c069Smrg        goto string;
79134345a63Smrg    case OpAssign:
7926ae2c069Smrg        bogus = "Assignment";
7936ae2c069Smrg        goto string;
79434345a63Smrg    case OpNegate:
7956ae2c069Smrg        bogus = "Negation";
7966ae2c069Smrg        goto string;
79734345a63Smrg    case OpInvert:
7986ae2c069Smrg        bogus = "Bitwise complement";
7996ae2c069Smrg        goto string;
8006ae2c069Smrg    string:
801370d0a5eSmrg        ERROR("%s of string values not permitted\n", bogus);
80234345a63Smrg        return False;
80334345a63Smrg    case OpNot:
80434345a63Smrg        left = expr->value.child;
80534345a63Smrg        if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
80634345a63Smrg        {
80734345a63Smrg            ERROR("The ! operator cannot be applied to a string\n");
80834345a63Smrg        }
80934345a63Smrg        return False;
81034345a63Smrg    case OpUnaryPlus:
81134345a63Smrg        left = expr->value.child;
81234345a63Smrg        if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
81334345a63Smrg        {
81434345a63Smrg            ERROR("The + operator cannot be applied to a string\n");
81534345a63Smrg        }
81634345a63Smrg        return False;
81734345a63Smrg    default:
818370d0a5eSmrg        WSGO("Unknown operator %d in ResolveString\n", expr->op);
81934345a63Smrg        break;
820f46a6179Smrg    }
821f46a6179Smrg    return False;
822f46a6179Smrg}
823f46a6179Smrg
824f46a6179Smrgint
8256ae2c069SmrgExprResolveKeyName(const ExprDef *expr, ExprResult *val_rtrn,
82634345a63Smrg                   IdentLookupFunc lookup, XPointer lookupPriv)
827f46a6179Smrg{
82834345a63Smrg    int ok = 0;
82934345a63Smrg    ExprDef *left;
83034345a63Smrg    ExprResult leftRtrn;
831c82dfdfbSmrg    const char *bogus = NULL;
83234345a63Smrg
83334345a63Smrg    switch (expr->op)
83434345a63Smrg    {
83534345a63Smrg    case ExprValue:
83634345a63Smrg        if (expr->type != TypeKeyName)
83734345a63Smrg        {
838370d0a5eSmrg            ERROR("Found constant of type %s, expected a key name\n",
83934345a63Smrg                   exprTypeText(expr->type));
84034345a63Smrg            return False;
84134345a63Smrg        }
84234345a63Smrg        memcpy(val_rtrn->keyName.name, expr->value.keyName, XkbKeyNameLength);
84334345a63Smrg        return True;
84434345a63Smrg    case ExprIdent:
84534345a63Smrg        if (lookup)
84634345a63Smrg        {
84734345a63Smrg            ok = (*lookup) (lookupPriv,
84834345a63Smrg                            None, expr->value.str, TypeString, val_rtrn);
84934345a63Smrg        }
85034345a63Smrg        if (!ok)
851370d0a5eSmrg            ERROR("Identifier \"%s\" of type string not found\n",
85234345a63Smrg                   XkbAtomText(NULL, expr->value.str, XkbMessage));
85334345a63Smrg        return ok;
85434345a63Smrg    case ExprFieldRef:
85534345a63Smrg        if (lookup)
85634345a63Smrg        {
85734345a63Smrg            ok = (*lookup) (lookupPriv,
85834345a63Smrg                            expr->value.field.element,
85934345a63Smrg                            expr->value.field.field, TypeString, val_rtrn);
86034345a63Smrg        }
86134345a63Smrg        if (!ok)
862370d0a5eSmrg            ERROR("Default \"%s.%s\" of type key name not found\n",
86334345a63Smrg                   XkbAtomText(NULL, expr->value.field.element, XkbMessage),
86434345a63Smrg                   XkbAtomText(NULL, expr->value.field.field, XkbMessage));
86534345a63Smrg        return ok;
86634345a63Smrg    case OpAdd:
8676ae2c069Smrg        bogus = "Addition";
8686ae2c069Smrg        goto keyname;
86934345a63Smrg    case OpSubtract:
8706ae2c069Smrg        bogus = "Subtraction";
8716ae2c069Smrg        goto keyname;
87234345a63Smrg    case OpMultiply:
8736ae2c069Smrg        bogus = "Multiplication";
8746ae2c069Smrg        goto keyname;
87534345a63Smrg    case OpDivide:
8766ae2c069Smrg        bogus = "Division";
8776ae2c069Smrg        goto keyname;
87834345a63Smrg    case OpAssign:
8796ae2c069Smrg        bogus = "Assignment";
8806ae2c069Smrg        goto keyname;
88134345a63Smrg    case OpNegate:
8826ae2c069Smrg        bogus = "Negation";
8836ae2c069Smrg        goto keyname;
88434345a63Smrg    case OpInvert:
8856ae2c069Smrg        bogus = "Bitwise complement";
8866ae2c069Smrg        goto keyname;
8876ae2c069Smrg    keyname:
888370d0a5eSmrg        ERROR("%s of key name values not permitted\n", bogus);
88934345a63Smrg        return False;
89034345a63Smrg    case OpNot:
89134345a63Smrg        left = expr->value.binary.left;
89234345a63Smrg        if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
89334345a63Smrg        {
89434345a63Smrg            ERROR("The ! operator cannot be applied to a key name\n");
89534345a63Smrg        }
89634345a63Smrg        return False;
89734345a63Smrg    case OpUnaryPlus:
89834345a63Smrg        left = expr->value.binary.left;
89934345a63Smrg        if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
90034345a63Smrg        {
90134345a63Smrg            ERROR("The + operator cannot be applied to a key name\n");
90234345a63Smrg        }
90334345a63Smrg        return False;
90434345a63Smrg    default:
905370d0a5eSmrg        WSGO("Unknown operator %d in ResolveKeyName\n", expr->op);
90634345a63Smrg        break;
907f46a6179Smrg    }
908f46a6179Smrg    return False;
909f46a6179Smrg}
910f46a6179Smrg
911f46a6179Smrg/***====================================================================***/
912f46a6179Smrg
913f46a6179Smrgint
9146ae2c069SmrgExprResolveEnum(const ExprDef *expr, ExprResult *val_rtrn,
9156ae2c069Smrg                const LookupEntry *values)
916f46a6179Smrg{
91734345a63Smrg    if (expr->op != ExprIdent)
91834345a63Smrg    {
919370d0a5eSmrg        ERROR("Found a %s where an enumerated value was expected\n",
92034345a63Smrg               exprOpText(expr->op));
92134345a63Smrg        return False;
922f46a6179Smrg    }
92334345a63Smrg    if (!SimpleLookup((XPointer) values, (Atom) None, expr->value.str,
92434345a63Smrg                      (unsigned) TypeInt, val_rtrn))
92534345a63Smrg    {
92634345a63Smrg        int nOut = 0;
927370d0a5eSmrg        ERROR("Illegal identifier %s (expected one of: ",
92834345a63Smrg               XkbAtomText(NULL, expr->value.str, XkbMessage));
92934345a63Smrg        while (values && values->name)
93034345a63Smrg        {
93134345a63Smrg            if (nOut != 0)
932370d0a5eSmrg                INFO(", %s", values->name);
93334345a63Smrg            else
934370d0a5eSmrg                INFO("%s", values->name);
93534345a63Smrg            values++;
93634345a63Smrg            nOut++;
93734345a63Smrg        }
93834345a63Smrg        INFO(")\n");
93934345a63Smrg        return False;
940f46a6179Smrg    }
941f46a6179Smrg    return True;
942f46a6179Smrg}
943f46a6179Smrg
944f46a6179Smrgint
9456ae2c069SmrgExprResolveMask(const ExprDef *expr, ExprResult *val_rtrn,
94634345a63Smrg                IdentLookupFunc lookup, XPointer lookupPriv)
947f46a6179Smrg{
94834345a63Smrg    int ok = 0;
94934345a63Smrg    ExprResult leftRtrn, rightRtrn;
9506ae2c069Smrg    const ExprDef *left, *right;
951c82dfdfbSmrg    const char *bogus = NULL;
95234345a63Smrg
95334345a63Smrg    switch (expr->op)
95434345a63Smrg    {
95534345a63Smrg    case ExprValue:
95634345a63Smrg        if (expr->type != TypeInt)
95734345a63Smrg        {
958370d0a5eSmrg            ERROR
95934345a63Smrg                ("Found constant of type %s where a mask was expected\n",
96034345a63Smrg                 exprTypeText(expr->type));
96134345a63Smrg            return False;
96234345a63Smrg        }
96334345a63Smrg        val_rtrn->ival = expr->value.ival;
96434345a63Smrg        return True;
96534345a63Smrg    case ExprIdent:
96634345a63Smrg        if (lookup)
96734345a63Smrg        {
96834345a63Smrg            ok = (*lookup) (lookupPriv,
96934345a63Smrg                            None, expr->value.str, TypeInt, val_rtrn);
97034345a63Smrg        }
97134345a63Smrg        if (!ok)
972370d0a5eSmrg            ERROR("Identifier \"%s\" of type int is unknown\n",
97334345a63Smrg                   XkbAtomText(NULL, expr->value.str, XkbMessage));
97434345a63Smrg        return ok;
97534345a63Smrg    case ExprFieldRef:
97634345a63Smrg        if (lookup)
97734345a63Smrg        {
97834345a63Smrg            ok = (*lookup) (lookupPriv,
97934345a63Smrg                            expr->value.field.element,
98034345a63Smrg                            expr->value.field.field, TypeInt, val_rtrn);
98134345a63Smrg        }
98234345a63Smrg        if (!ok)
983370d0a5eSmrg            ERROR("Default \"%s.%s\" of type int is unknown\n",
98434345a63Smrg                   XkbAtomText(NULL, expr->value.field.element, XkbMessage),
98534345a63Smrg                   XkbAtomText(NULL, expr->value.field.field, XkbMessage));
98634345a63Smrg        return ok;
98734345a63Smrg    case ExprArrayRef:
98834345a63Smrg        bogus = "array reference";
9896ae2c069Smrg        goto unexpected_mask;
99034345a63Smrg    case ExprActionDecl:
9916ae2c069Smrg        bogus = "function use";
9926ae2c069Smrg        goto unexpected_mask;
9936ae2c069Smrg    unexpected_mask:
994370d0a5eSmrg        ERROR("Unexpected %s in mask expression\n", bogus);
99534345a63Smrg        ACTION("Expression ignored\n");
99634345a63Smrg        return False;
99734345a63Smrg    case OpAdd:
99834345a63Smrg    case OpSubtract:
99934345a63Smrg    case OpMultiply:
100034345a63Smrg    case OpDivide:
100134345a63Smrg        left = expr->value.binary.left;
100234345a63Smrg        right = expr->value.binary.right;
100334345a63Smrg        if (ExprResolveMask(left, &leftRtrn, lookup, lookupPriv) &&
100434345a63Smrg            ExprResolveMask(right, &rightRtrn, lookup, lookupPriv))
100534345a63Smrg        {
100634345a63Smrg            switch (expr->op)
100734345a63Smrg            {
100834345a63Smrg            case OpAdd:
100934345a63Smrg                val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
101034345a63Smrg                break;
101134345a63Smrg            case OpSubtract:
101234345a63Smrg                val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
101334345a63Smrg                break;
101434345a63Smrg            case OpMultiply:
101534345a63Smrg            case OpDivide:
1016370d0a5eSmrg                ERROR("Cannot %s masks\n",
101734345a63Smrg                       expr->op == OpDivide ? "divide" : "multiply");
101834345a63Smrg                ACTION("Illegal operation ignored\n");
101934345a63Smrg                return False;
102034345a63Smrg            }
102134345a63Smrg            return True;
102234345a63Smrg        }
102334345a63Smrg        return False;
102434345a63Smrg    case OpAssign:
102534345a63Smrg        WSGO("Assignment operator not implemented yet\n");
102634345a63Smrg        break;
102734345a63Smrg    case OpInvert:
102834345a63Smrg        left = expr->value.child;
102934345a63Smrg        if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
103034345a63Smrg        {
103134345a63Smrg            val_rtrn->ival = ~leftRtrn.ival;
103234345a63Smrg            return True;
103334345a63Smrg        }
103434345a63Smrg        return False;
103534345a63Smrg    case OpUnaryPlus:
103634345a63Smrg    case OpNegate:
103734345a63Smrg    case OpNot:
103834345a63Smrg        left = expr->value.child;
103934345a63Smrg        if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
104034345a63Smrg        {
1041370d0a5eSmrg            ERROR("The %s operator cannot be used with a mask\n",
104234345a63Smrg                   (expr->op == OpNegate ? "-" : "!"));
104334345a63Smrg        }
104434345a63Smrg        return False;
104534345a63Smrg    default:
1046370d0a5eSmrg        WSGO("Unknown operator %d in ResolveMask\n", expr->op);
104734345a63Smrg        break;
1048f46a6179Smrg    }
1049f46a6179Smrg    return False;
1050f46a6179Smrg}
1051f46a6179Smrg
1052f46a6179Smrgint
10536ae2c069SmrgExprResolveKeySym(const ExprDef *expr, ExprResult *val_rtrn,
105434345a63Smrg                  IdentLookupFunc lookup, XPointer lookupPriv)
1055f46a6179Smrg{
105634345a63Smrg    int ok = 0;
105734345a63Smrg
105834345a63Smrg    if (expr->op == ExprIdent)
105934345a63Smrg    {
10606ae2c069Smrg        const char *str;
10616ae2c069Smrg        KeySym sym;
10626ae2c069Smrg
106334345a63Smrg        str = XkbAtomGetString(NULL, expr->value.str);
106434345a63Smrg        if ((str != NULL) && ((sym = XStringToKeysym(str)) != NoSymbol))
106534345a63Smrg        {
106634345a63Smrg            val_rtrn->uval = sym;
106734345a63Smrg            return True;
106834345a63Smrg        }
1069f46a6179Smrg    }
107034345a63Smrg    ok = ExprResolveInteger(expr, val_rtrn, lookup, lookupPriv);
107134345a63Smrg    if ((ok) && (val_rtrn->uval < 10))
107234345a63Smrg        val_rtrn->uval += '0';
1073f46a6179Smrg    return ok;
1074f46a6179Smrg}
1075