Introduce xkb_keycode_t for keycodes
[platform/upstream/libxkbcommon.git] / src / xkbcomp / action.c
1 /************************************************************
2  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4  Permission to use, copy, modify, and distribute this
5  software and its documentation for any purpose and without
6  fee is hereby granted, provided that the above copyright
7  notice appear in all copies and that both that copyright
8  notice and this permission notice appear in supporting
9  documentation, and that the name of Silicon Graphics not be
10  used in advertising or publicity pertaining to distribution
11  of the software without specific prior written permission.
12  Silicon Graphics makes no representation about the suitability
13  of this software for any purpose. It is provided "as is"
14  without any express or implied warranty.
15
16  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25  ********************************************************/
26
27 #include "xkbcomp.h"
28 #include "xkbmisc.h"
29 #include "tokens.h"
30 #include "expr.h"
31
32 #include "keycodes.h"
33 #include "vmod.h"
34 #include "misc.h"
35 #include "action.h"
36 #include "misc.h"
37
38 static Bool actionsInitialized;
39 static ExprDef constTrue;
40 static ExprDef constFalse;
41
42 /***====================================================================***/
43
44 static Bool
45 stringToAction(const char *str, unsigned *type_rtrn)
46 {
47     if (str == NULL)
48         return False;
49
50     if (uStrCaseCmp(str, "noaction") == 0)
51         *type_rtrn = XkbSA_NoAction;
52     else if (uStrCaseCmp(str, "setmods") == 0)
53         *type_rtrn = XkbSA_SetMods;
54     else if (uStrCaseCmp(str, "latchmods") == 0)
55         *type_rtrn = XkbSA_LatchMods;
56     else if (uStrCaseCmp(str, "lockmods") == 0)
57         *type_rtrn = XkbSA_LockMods;
58     else if (uStrCaseCmp(str, "setgroup") == 0)
59         *type_rtrn = XkbSA_SetGroup;
60     else if (uStrCaseCmp(str, "latchgroup") == 0)
61         *type_rtrn = XkbSA_LatchGroup;
62     else if (uStrCaseCmp(str, "lockgroup") == 0)
63         *type_rtrn = XkbSA_LockGroup;
64     else if (uStrCaseCmp(str, "moveptr") == 0)
65         *type_rtrn = XkbSA_MovePtr;
66     else if (uStrCaseCmp(str, "movepointer") == 0)
67         *type_rtrn = XkbSA_MovePtr;
68     else if (uStrCaseCmp(str, "ptrbtn") == 0)
69         *type_rtrn = XkbSA_PtrBtn;
70     else if (uStrCaseCmp(str, "pointerbutton") == 0)
71         *type_rtrn = XkbSA_PtrBtn;
72     else if (uStrCaseCmp(str, "lockptrbtn") == 0)
73         *type_rtrn = XkbSA_LockPtrBtn;
74     else if (uStrCaseCmp(str, "lockpointerbutton") == 0)
75         *type_rtrn = XkbSA_LockPtrBtn;
76     else if (uStrCaseCmp(str, "lockptrbutton") == 0)
77         *type_rtrn = XkbSA_LockPtrBtn;
78     else if (uStrCaseCmp(str, "lockpointerbtn") == 0)
79         *type_rtrn = XkbSA_LockPtrBtn;
80     else if (uStrCaseCmp(str, "setptrdflt") == 0)
81         *type_rtrn = XkbSA_SetPtrDflt;
82     else if (uStrCaseCmp(str, "setpointerdefault") == 0)
83         *type_rtrn = XkbSA_SetPtrDflt;
84     else if (uStrCaseCmp(str, "isolock") == 0)
85         *type_rtrn = XkbSA_ISOLock;
86     else if (uStrCaseCmp(str, "terminate") == 0)
87         *type_rtrn = XkbSA_Terminate;
88     else if (uStrCaseCmp(str, "terminateserver") == 0)
89         *type_rtrn = XkbSA_Terminate;
90     else if (uStrCaseCmp(str, "switchscreen") == 0)
91         *type_rtrn = XkbSA_SwitchScreen;
92     else if (uStrCaseCmp(str, "setcontrols") == 0)
93         *type_rtrn = XkbSA_SetControls;
94     else if (uStrCaseCmp(str, "lockcontrols") == 0)
95         *type_rtrn = XkbSA_LockControls;
96     else if (uStrCaseCmp(str, "actionmessage") == 0)
97         *type_rtrn = XkbSA_ActionMessage;
98     else if (uStrCaseCmp(str, "messageaction") == 0)
99         *type_rtrn = XkbSA_ActionMessage;
100     else if (uStrCaseCmp(str, "message") == 0)
101         *type_rtrn = XkbSA_ActionMessage;
102     else if (uStrCaseCmp(str, "redirect") == 0)
103         *type_rtrn = XkbSA_RedirectKey;
104     else if (uStrCaseCmp(str, "redirectkey") == 0)
105         *type_rtrn = XkbSA_RedirectKey;
106     else if (uStrCaseCmp(str, "devbtn") == 0)
107         *type_rtrn = XkbSA_DeviceBtn;
108     else if (uStrCaseCmp(str, "devicebtn") == 0)
109         *type_rtrn = XkbSA_DeviceBtn;
110     else if (uStrCaseCmp(str, "devbutton") == 0)
111         *type_rtrn = XkbSA_DeviceBtn;
112     else if (uStrCaseCmp(str, "devicebutton") == 0)
113         *type_rtrn = XkbSA_DeviceBtn;
114     else if (uStrCaseCmp(str, "lockdevbtn") == 0)
115         *type_rtrn = XkbSA_DeviceBtn;
116     else if (uStrCaseCmp(str, "lockdevicebtn") == 0)
117         *type_rtrn = XkbSA_LockDeviceBtn;
118     else if (uStrCaseCmp(str, "lockdevbutton") == 0)
119         *type_rtrn = XkbSA_LockDeviceBtn;
120     else if (uStrCaseCmp(str, "lockdevicebutton") == 0)
121         *type_rtrn = XkbSA_LockDeviceBtn;
122     else if (uStrCaseCmp(str, "devval") == 0)
123         *type_rtrn = XkbSA_DeviceValuator;
124     else if (uStrCaseCmp(str, "deviceval") == 0)
125         *type_rtrn = XkbSA_DeviceValuator;
126     else if (uStrCaseCmp(str, "devvaluator") == 0)
127         *type_rtrn = XkbSA_DeviceValuator;
128     else if (uStrCaseCmp(str, "devicevaluator") == 0)
129         *type_rtrn = XkbSA_DeviceValuator;
130     else if (uStrCaseCmp(str, "private") == 0)
131         *type_rtrn = PrivateAction;
132     else
133         return False;
134     return True;
135 }
136
137 static Bool
138 stringToField(char *str, unsigned *field_rtrn)
139 {
140
141     if (str == NULL)
142         return False;
143
144     if (uStrCaseCmp(str, "clearlocks") == 0)
145         *field_rtrn = F_ClearLocks;
146     else if (uStrCaseCmp(str, "latchtolock") == 0)
147         *field_rtrn = F_LatchToLock;
148     else if (uStrCaseCmp(str, "genkeyevent") == 0)
149         *field_rtrn = F_GenKeyEvent;
150     else if (uStrCaseCmp(str, "generatekeyevent") == 0)
151         *field_rtrn = F_GenKeyEvent;
152     else if (uStrCaseCmp(str, "report") == 0)
153         *field_rtrn = F_Report;
154     else if (uStrCaseCmp(str, "default") == 0)
155         *field_rtrn = F_Default;
156     else if (uStrCaseCmp(str, "affect") == 0)
157         *field_rtrn = F_Affect;
158     else if (uStrCaseCmp(str, "increment") == 0)
159         *field_rtrn = F_Increment;
160     else if (uStrCaseCmp(str, "mods") == 0)
161         *field_rtrn = F_Modifiers;
162     else if (uStrCaseCmp(str, "modifiers") == 0)
163         *field_rtrn = F_Modifiers;
164     else if (uStrCaseCmp(str, "group") == 0)
165         *field_rtrn = F_Group;
166     else if (uStrCaseCmp(str, "x") == 0)
167         *field_rtrn = F_X;
168     else if (uStrCaseCmp(str, "y") == 0)
169         *field_rtrn = F_Y;
170     else if (uStrCaseCmp(str, "accel") == 0)
171         *field_rtrn = F_Accel;
172     else if (uStrCaseCmp(str, "accelerate") == 0)
173         *field_rtrn = F_Accel;
174     else if (uStrCaseCmp(str, "repeat") == 0)
175         *field_rtrn = F_Accel;
176     else if (uStrCaseCmp(str, "button") == 0)
177         *field_rtrn = F_Button;
178     else if (uStrCaseCmp(str, "value") == 0)
179         *field_rtrn = F_Value;
180     else if (uStrCaseCmp(str, "controls") == 0)
181         *field_rtrn = F_Controls;
182     else if (uStrCaseCmp(str, "ctrls") == 0)
183         *field_rtrn = F_Controls;
184     else if (uStrCaseCmp(str, "type") == 0)
185         *field_rtrn = F_Type;
186     else if (uStrCaseCmp(str, "count") == 0)
187         *field_rtrn = F_Count;
188     else if (uStrCaseCmp(str, "screen") == 0)
189         *field_rtrn = F_Screen;
190     else if (uStrCaseCmp(str, "same") == 0)
191         *field_rtrn = F_Same;
192     else if (uStrCaseCmp(str, "sameserver") == 0)
193         *field_rtrn = F_Same;
194     else if (uStrCaseCmp(str, "data") == 0)
195         *field_rtrn = F_Data;
196     else if (uStrCaseCmp(str, "device") == 0)
197         *field_rtrn = F_Device;
198     else if (uStrCaseCmp(str, "dev") == 0)
199         *field_rtrn = F_Device;
200     else if (uStrCaseCmp(str, "key") == 0)
201         *field_rtrn = F_Keycode;
202     else if (uStrCaseCmp(str, "keycode") == 0)
203         *field_rtrn = F_Keycode;
204     else if (uStrCaseCmp(str, "kc") == 0)
205         *field_rtrn = F_Keycode;
206     else if (uStrCaseCmp(str, "clearmods") == 0)
207         *field_rtrn = F_ModsToClear;
208     else if (uStrCaseCmp(str, "clearmodifiers") == 0)
209         *field_rtrn = F_ModsToClear;
210     else
211         return False;
212     return True;
213 }
214
215 static char *
216 fieldText(unsigned field)
217 {
218     static char buf[32];
219
220     switch (field)
221     {
222     case F_ClearLocks:
223         strcpy(buf, "clearLocks");
224         break;
225     case F_LatchToLock:
226         strcpy(buf, "latchToLock");
227         break;
228     case F_GenKeyEvent:
229         strcpy(buf, "genKeyEvent");
230         break;
231     case F_Report:
232         strcpy(buf, "report");
233         break;
234     case F_Default:
235         strcpy(buf, "default");
236         break;
237     case F_Affect:
238         strcpy(buf, "affect");
239         break;
240     case F_Increment:
241         strcpy(buf, "increment");
242         break;
243     case F_Modifiers:
244         strcpy(buf, "modifiers");
245         break;
246     case F_Group:
247         strcpy(buf, "group");
248         break;
249     case F_X:
250         strcpy(buf, "x");
251         break;
252     case F_Y:
253         strcpy(buf, "y");
254         break;
255     case F_Accel:
256         strcpy(buf, "accel");
257         break;
258     case F_Button:
259         strcpy(buf, "button");
260         break;
261     case F_Value:
262         strcpy(buf, "value");
263         break;
264     case F_Controls:
265         strcpy(buf, "controls");
266         break;
267     case F_Type:
268         strcpy(buf, "type");
269         break;
270     case F_Count:
271         strcpy(buf, "count");
272         break;
273     case F_Screen:
274         strcpy(buf, "screen");
275         break;
276     case F_Same:
277         strcpy(buf, "sameServer");
278         break;
279     case F_Data:
280         strcpy(buf, "data");
281         break;
282     case F_Device:
283         strcpy(buf, "device");
284         break;
285     case F_Keycode:
286         strcpy(buf, "keycode");
287         break;
288     case F_ModsToClear:
289         strcpy(buf, "clearmods");
290         break;
291     default:
292         strcpy(buf, "unknown");
293         break;
294     }
295     return buf;
296 }
297
298 /***====================================================================***/
299
300 static Bool
301 ReportMismatch(unsigned action, unsigned field, const char *type)
302 {
303     ERROR("Value of %s field must be of type %s\n", fieldText(field), type);
304     ACTION("Action %s definition ignored\n", XkbcActionTypeText(action));
305     return False;
306 }
307
308 static Bool
309 ReportIllegal(unsigned action, unsigned field)
310 {
311     ERROR("Field %s is not defined for an action of type %s\n",
312            fieldText(field), XkbcActionTypeText(action));
313     ACTION("Action definition ignored\n");
314     return False;
315 }
316
317 static Bool
318 ReportActionNotArray(unsigned action, unsigned field)
319 {
320     ERROR("The %s field in the %s action is not an array\n",
321            fieldText(field), XkbcActionTypeText(action));
322     ACTION("Action definition ignored\n");
323     return False;
324 }
325
326 static Bool
327 ReportNotFound(unsigned action, unsigned field, const char *what, char *bad)
328 {
329     ERROR("%s named %s not found\n", what, bad);
330     ACTION("Ignoring the %s field of an %s action\n", fieldText(field),
331             XkbcActionTypeText(action));
332     return False;
333 }
334
335 static Bool
336 HandleNoAction(struct xkb_desc * xkb,
337                struct xkb_any_action * action,
338                unsigned field, ExprDef * array_ndx, ExprDef * value)
339 {
340     return ReportIllegal(action->type, field);
341 }
342
343 static Bool
344 CheckLatchLockFlags(unsigned action,
345                     unsigned field, ExprDef * value, unsigned *flags_inout)
346 {
347     unsigned tmp;
348     ExprResult result;
349
350     if (field == F_ClearLocks)
351         tmp = XkbSA_ClearLocks;
352     else if (field == F_LatchToLock)
353         tmp = XkbSA_LatchToLock;
354     else
355         return False;           /* WSGO! */
356     if (!ExprResolveBoolean(value, &result, NULL, NULL))
357         return ReportMismatch(action, field, "boolean");
358     if (result.uval)
359         *flags_inout |= tmp;
360     else
361         *flags_inout &= ~tmp;
362     return True;
363 }
364
365 static Bool
366 CheckModifierField(struct xkb_desc * xkb,
367                    unsigned action,
368                    ExprDef * value,
369                    unsigned *flags_inout, unsigned *mods_rtrn)
370 {
371     ExprResult rtrn;
372
373     if (value->op == ExprIdent)
374     {
375         const char *valStr;
376         valStr = XkbcAtomText(value->value.str);
377         if (valStr && ((uStrCaseCmp(valStr, "usemodmapmods") == 0) ||
378                        (uStrCaseCmp(valStr, "modmapmods") == 0)))
379         {
380
381             *mods_rtrn = 0;
382             *flags_inout |= XkbSA_UseModMapMods;
383             return True;
384         }
385     }
386     if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (char *) xkb))
387         return ReportMismatch(action, F_Modifiers, "modifier mask");
388     *mods_rtrn = rtrn.uval;
389     *flags_inout &= ~XkbSA_UseModMapMods;
390     return True;
391 }
392
393 static Bool
394 HandleSetLatchMods(struct xkb_desc * xkb,
395                    struct xkb_any_action * action,
396                    unsigned field, ExprDef * array_ndx, ExprDef * value)
397 {
398     struct xkb_mod_action *act;
399     unsigned rtrn;
400     unsigned t1, t2;
401
402     act = (struct xkb_mod_action *) action;
403     if (array_ndx != NULL)
404     {
405         switch (field)
406         {
407         case F_ClearLocks:
408         case F_LatchToLock:
409         case F_Modifiers:
410             return ReportActionNotArray(action->type, field);
411         }
412     }
413     switch (field)
414     {
415     case F_ClearLocks:
416     case F_LatchToLock:
417         rtrn = act->flags;
418         if (CheckLatchLockFlags(action->type, field, value, &rtrn))
419         {
420             act->flags = rtrn;
421             return True;
422         }
423         return False;
424     case F_Modifiers:
425         t1 = act->flags;
426         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
427         {
428             act->flags = t1;
429             act->real_mods = act->mask = (t2 & 0xff);
430             act->vmods = (t2 >> 8) & 0xffff;
431             return True;
432         }
433         return False;
434     }
435     return ReportIllegal(action->type, field);
436 }
437
438 static Bool
439 HandleLockMods(struct xkb_desc * xkb,
440                struct xkb_any_action * action,
441                unsigned field, ExprDef * array_ndx, ExprDef * value)
442 {
443     struct xkb_mod_action *act;
444     unsigned t1, t2;
445
446     act = (struct xkb_mod_action *) action;
447     if ((array_ndx != NULL) && (field == F_Modifiers))
448         return ReportActionNotArray(action->type, field);
449     switch (field)
450     {
451     case F_Modifiers:
452         t1 = act->flags;
453         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
454         {
455             act->flags = t1;
456             act->real_mods = act->mask = (t2 & 0xff);
457             act->vmods = (t2 >> 8) & 0xffff;
458             return True;
459         }
460         return False;
461     }
462     return ReportIllegal(action->type, field);
463 }
464
465 static LookupEntry groupNames[] = {
466     {"group1", 1},
467     {"group2", 2},
468     {"group3", 3},
469     {"group4", 4},
470     {"group5", 5},
471     {"group6", 6},
472     {"group7", 7},
473     {"group8", 8},
474     {NULL, 0},
475 };
476
477 static Bool
478 CheckGroupField(unsigned action,
479                 ExprDef * value, unsigned *flags_inout, int *grp_rtrn)
480 {
481     ExprDef *spec;
482     ExprResult rtrn;
483
484     if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
485     {
486         *flags_inout &= ~XkbSA_GroupAbsolute;
487         spec = value->value.child;
488     }
489     else
490     {
491         *flags_inout |= XkbSA_GroupAbsolute;
492         spec = value;
493     }
494
495     if (!ExprResolveInteger(spec, &rtrn, SimpleLookup, (char *) groupNames))
496         return ReportMismatch(action, F_Group, "integer (range 1..8)");
497     if ((rtrn.ival < 1) || (rtrn.ival > XkbNumKbdGroups))
498     {
499         ERROR("Illegal group %d (must be in the range 1..%d)\n", rtrn.ival,
500                XkbNumKbdGroups);
501         ACTION("Action %s definition ignored\n", XkbcActionTypeText(action));
502         return False;
503     }
504     if (value->op == OpNegate)
505         *grp_rtrn = -rtrn.ival;
506     else if (value->op == OpUnaryPlus)
507         *grp_rtrn = rtrn.ival;
508     else
509         *grp_rtrn = rtrn.ival - 1;
510     return True;
511 }
512
513 static Bool
514 HandleSetLatchGroup(struct xkb_desc * xkb,
515                     struct xkb_any_action * action,
516                     unsigned field, ExprDef * array_ndx, ExprDef * value)
517 {
518     struct xkb_group_action *act;
519     unsigned rtrn;
520     unsigned t1;
521     int t2;
522
523     act = (struct xkb_group_action *) action;
524     if (array_ndx != NULL)
525     {
526         switch (field)
527         {
528         case F_ClearLocks:
529         case F_LatchToLock:
530         case F_Group:
531             return ReportActionNotArray(action->type, field);
532         }
533     }
534     switch (field)
535     {
536     case F_ClearLocks:
537     case F_LatchToLock:
538         rtrn = act->flags;
539         if (CheckLatchLockFlags(action->type, field, value, &rtrn))
540         {
541             act->flags = rtrn;
542             return True;
543         }
544         return False;
545     case F_Group:
546         t1 = act->flags;
547         if (CheckGroupField(action->type, value, &t1, &t2))
548         {
549             act->flags = t1;
550             act->group = t2;
551             return True;
552         }
553         return False;
554     }
555     return ReportIllegal(action->type, field);
556 }
557
558 static Bool
559 HandleLockGroup(struct xkb_desc * xkb,
560                 struct xkb_any_action * action,
561                 unsigned field, ExprDef * array_ndx, ExprDef * value)
562 {
563     struct xkb_group_action *act;
564     unsigned t1;
565     int t2;
566
567     act = (struct xkb_group_action *) action;
568     if ((array_ndx != NULL) && (field == F_Group))
569         return ReportActionNotArray(action->type, field);
570     if (field == F_Group)
571     {
572         t1 = act->flags;
573         if (CheckGroupField(action->type, value, &t1, &t2))
574         {
575             act->flags = t1;
576             act->group = t2;
577             return True;
578         }
579         return False;
580     }
581     return ReportIllegal(action->type, field);
582 }
583
584 static Bool
585 HandleMovePtr(struct xkb_desc * xkb,
586               struct xkb_any_action * action,
587               unsigned field, ExprDef * array_ndx, ExprDef * value)
588 {
589     ExprResult rtrn;
590     struct xkb_pointer_action *act;
591     Bool absolute;
592
593     act = (struct xkb_pointer_action *) action;
594     if ((array_ndx != NULL) && ((field == F_X) || (field == F_Y)))
595         return ReportActionNotArray(action->type, field);
596
597     if ((field == F_X) || (field == F_Y))
598     {
599         if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
600             absolute = False;
601         else
602             absolute = True;
603         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
604             return ReportMismatch(action->type, field, "integer");
605         if (field == F_X)
606         {
607             if (absolute)
608                 act->flags |= XkbSA_MoveAbsoluteX;
609             act->x = rtrn.ival;
610         }
611         else
612         {
613             if (absolute)
614                 act->flags |= XkbSA_MoveAbsoluteY;
615             act->y = rtrn.ival;
616         }
617         return True;
618     }
619     else if (field == F_Accel)
620     {
621         if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
622             return ReportMismatch(action->type, field, "boolean");
623         if (rtrn.uval)
624             act->flags &= ~XkbSA_NoAcceleration;
625         else
626             act->flags |= XkbSA_NoAcceleration;
627     }
628     return ReportIllegal(action->type, field);
629 }
630
631 static LookupEntry btnNames[] = {
632     {"button1", 1},
633     {"button2", 2},
634     {"button3", 3},
635     {"button4", 4},
636     {"button5", 5},
637     {"default", 0},
638     {NULL, 0}
639 };
640
641 static LookupEntry lockWhich[] = {
642     {"both", 0},
643     {"lock", XkbSA_LockNoUnlock},
644     {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)},
645     {"unlock", XkbSA_LockNoLock},
646     {NULL, 0}
647 };
648
649 static Bool
650 HandlePtrBtn(struct xkb_desc * xkb,
651              struct xkb_any_action * action,
652              unsigned field, ExprDef * array_ndx, ExprDef * value)
653 {
654     ExprResult rtrn;
655     struct xkb_pointer_button_action *act;
656
657     act = (struct xkb_pointer_button_action *) action;
658     if (field == F_Button)
659     {
660         if (array_ndx != NULL)
661             return ReportActionNotArray(action->type, field);
662         if (!ExprResolveInteger
663             (value, &rtrn, SimpleLookup, (char *) btnNames))
664             return ReportMismatch(action->type, field,
665                                   "integer (range 1..5)");
666         if ((rtrn.ival < 0) || (rtrn.ival > 5))
667         {
668             ERROR("Button must specify default or be in the range 1..5\n");
669             ACTION("Illegal button value %d ignored\n", rtrn.ival);
670             return False;
671         }
672         act->button = rtrn.ival;
673         return True;
674     }
675     else if ((action->type == XkbSA_LockPtrBtn) && (field == F_Affect))
676     {
677         if (array_ndx != NULL)
678             return ReportActionNotArray(action->type, field);
679         if (!ExprResolveEnum(value, &rtrn, lockWhich))
680             return ReportMismatch(action->type, field, "lock or unlock");
681         act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
682         act->flags |= rtrn.ival;
683         return True;
684     }
685     else if (field == F_Count)
686     {
687         if (array_ndx != NULL)
688             return ReportActionNotArray(action->type, field);
689         if (!ExprResolveInteger
690             (value, &rtrn, SimpleLookup, (char *) btnNames))
691             return ReportMismatch(action->type, field, "integer");
692         if ((rtrn.ival < 0) || (rtrn.ival > 255))
693         {
694             ERROR("The count field must have a value in the range 0..255\n");
695             ACTION("Illegal count %d ignored\n", rtrn.ival);
696             return False;
697         }
698         act->count = rtrn.ival;
699         return True;
700     }
701     return ReportIllegal(action->type, field);
702 }
703
704 static LookupEntry ptrDflts[] = {
705     {"dfltbtn", XkbSA_AffectDfltBtn},
706     {"defaultbutton", XkbSA_AffectDfltBtn},
707     {"button", XkbSA_AffectDfltBtn},
708     {NULL, 0}
709 };
710
711 static Bool
712 HandleSetPtrDflt(struct xkb_desc * xkb,
713                  struct xkb_any_action * action,
714                  unsigned field, ExprDef * array_ndx, ExprDef * value)
715 {
716     ExprResult rtrn;
717     struct xkb_pointer_default_action *act;
718
719     act = (struct xkb_pointer_default_action *) action;
720     if (field == F_Affect)
721     {
722         if (array_ndx != NULL)
723             return ReportActionNotArray(action->type, field);
724         if (!ExprResolveEnum(value, &rtrn, ptrDflts))
725             return ReportMismatch(action->type, field, "pointer component");
726         act->affect = rtrn.uval;
727         return True;
728     }
729     else if ((field == F_Button) || (field == F_Value))
730     {
731         ExprDef *btn;
732         if (array_ndx != NULL)
733             return ReportActionNotArray(action->type, field);
734         if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
735         {
736             act->flags &= ~XkbSA_DfltBtnAbsolute;
737             btn = value->value.child;
738         }
739         else
740         {
741             act->flags |= XkbSA_DfltBtnAbsolute;
742             btn = value;
743         }
744
745         if (!ExprResolveInteger
746             (btn, &rtrn, SimpleLookup, (char *) btnNames))
747             return ReportMismatch(action->type, field,
748                                   "integer (range 1..5)");
749         if ((rtrn.ival < 0) || (rtrn.ival > 5))
750         {
751             ERROR("New default button value must be in the range 1..5\n");
752             ACTION("Illegal default button value %d ignored\n", rtrn.ival);
753             return False;
754         }
755         if (rtrn.ival == 0)
756         {
757             ERROR("Cannot set default pointer button to \"default\"\n");
758             ACTION("Illegal default button setting ignored\n");
759             return False;
760         }
761         if (value->op == OpNegate)
762             act->value = -rtrn.ival;
763         else
764             act->value = rtrn.ival;
765         return True;
766     }
767     return ReportIllegal(action->type, field);
768 }
769
770 static LookupEntry isoNames[] = {
771     {"mods", XkbSA_ISONoAffectMods},
772     {"modifiers", XkbSA_ISONoAffectMods},
773     {"group", XkbSA_ISONoAffectGroup},
774     {"groups", XkbSA_ISONoAffectGroup},
775     {"ptr", XkbSA_ISONoAffectPtr},
776     {"pointer", XkbSA_ISONoAffectPtr},
777     {"ctrls", XkbSA_ISONoAffectCtrls},
778     {"controls", XkbSA_ISONoAffectCtrls},
779     {"all", ~((unsigned) 0)},
780     {"none", 0},
781     {NULL, 0},
782 };
783
784 static Bool
785 HandleISOLock(struct xkb_desc * xkb,
786               struct xkb_any_action * action,
787               unsigned field, ExprDef * array_ndx, ExprDef * value)
788 {
789     ExprResult rtrn;
790     struct xkb_iso_action *act;
791     unsigned flags, mods;
792     int group;
793
794     act = (struct xkb_iso_action *) action;
795     switch (field)
796     {
797     case F_Modifiers:
798         if (array_ndx != NULL)
799             return ReportActionNotArray(action->type, field);
800         flags = act->flags;
801         if (CheckModifierField(xkb, action->type, value, &flags, &mods))
802         {
803             act->flags = flags & (~XkbSA_ISODfltIsGroup);
804             act->real_mods = mods & 0xff;
805             act->vmods = (mods >> 8) & 0xff;
806             return True;
807         }
808         return False;
809     case F_Group:
810         if (array_ndx != NULL)
811             return ReportActionNotArray(action->type, field);
812         flags = act->flags;
813         if (CheckGroupField(action->type, value, &flags, &group))
814         {
815             act->flags = flags | XkbSA_ISODfltIsGroup;
816             act->group = group;
817             return True;
818         }
819         return False;
820     case F_Affect:
821         if (array_ndx != NULL)
822             return ReportActionNotArray(action->type, field);
823         if (!ExprResolveMask(value, &rtrn, SimpleLookup, (char *) isoNames))
824             return ReportMismatch(action->type, field, "keyboard component");
825         act->affect = (~rtrn.uval) & XkbSA_ISOAffectMask;
826         return True;
827     }
828     return ReportIllegal(action->type, field);
829 }
830
831 static Bool
832 HandleSwitchScreen(struct xkb_desc * xkb,
833                    struct xkb_any_action * action,
834                    unsigned field, ExprDef * array_ndx, ExprDef * value)
835 {
836     ExprResult rtrn;
837     struct xkb_switch_screen_action *act;
838
839     act = (struct xkb_switch_screen_action *) action;
840     if (field == F_Screen)
841     {
842         ExprDef *scrn;
843         if (array_ndx != NULL)
844             return ReportActionNotArray(action->type, field);
845         if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
846         {
847             act->flags &= ~XkbSA_SwitchAbsolute;
848             scrn = value->value.child;
849         }
850         else
851         {
852             act->flags |= XkbSA_SwitchAbsolute;
853             scrn = value;
854         }
855
856         if (!ExprResolveInteger(scrn, &rtrn, NULL, NULL))
857             return ReportMismatch(action->type, field, "integer (0..255)");
858         if ((rtrn.ival < 0) || (rtrn.ival > 255))
859         {
860             ERROR("Screen index must be in the range 1..255\n");
861             ACTION("Illegal screen value %d ignored\n", rtrn.ival);
862             return False;
863         }
864         if (value->op == OpNegate)
865             act->screen = -rtrn.ival;
866         else
867             act->screen = rtrn.ival;
868         return True;
869     }
870     else if (field == F_Same)
871     {
872         if (array_ndx != NULL)
873             return ReportActionNotArray(action->type, field);
874         if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
875             return ReportMismatch(action->type, field, "boolean");
876         if (rtrn.uval)
877             act->flags &= ~XkbSA_SwitchApplication;
878         else
879             act->flags |= XkbSA_SwitchApplication;
880         return True;
881     }
882     return ReportIllegal(action->type, field);
883 }
884
885 LookupEntry ctrlNames[] = {
886     {"repeatkeys", XkbRepeatKeysMask}
887     ,
888     {"repeat", XkbRepeatKeysMask}
889     ,
890     {"autorepeat", XkbRepeatKeysMask}
891     ,
892     {"slowkeys", XkbSlowKeysMask}
893     ,
894     {"bouncekeys", XkbBounceKeysMask}
895     ,
896     {"stickykeys", XkbStickyKeysMask}
897     ,
898     {"mousekeys", XkbMouseKeysMask}
899     ,
900     {"mousekeysaccel", XkbMouseKeysAccelMask}
901     ,
902     {"accessxkeys", XkbAccessXKeysMask}
903     ,
904     {"accessxtimeout", XkbAccessXTimeoutMask}
905     ,
906     {"accessxfeedback", XkbAccessXFeedbackMask}
907     ,
908     {"audiblebell", XkbAudibleBellMask}
909     ,
910     {"overlay1", XkbOverlay1Mask}
911     ,
912     {"overlay2", XkbOverlay2Mask}
913     ,
914     {"ignoregrouplock", XkbIgnoreGroupLockMask}
915     ,
916     {"all", XkbAllBooleanCtrlsMask}
917     ,
918     {"none", 0}
919     ,
920     {NULL, 0}
921 };
922
923 static Bool
924 HandleSetLockControls(struct xkb_desc * xkb,
925                       struct xkb_any_action * action,
926                       unsigned field, ExprDef * array_ndx, ExprDef * value)
927 {
928     ExprResult rtrn;
929     struct xkb_controls_action *act;
930
931     act = (struct xkb_controls_action *) action;
932     if (field == F_Controls)
933     {
934         if (array_ndx != NULL)
935             return ReportActionNotArray(action->type, field);
936         if (!ExprResolveMask
937             (value, &rtrn, SimpleLookup, (char *) ctrlNames))
938             return ReportMismatch(action->type, field, "controls mask");
939         act->ctrls = rtrn.uval;
940         return True;
941     }
942     return ReportIllegal(action->type, field);
943 }
944
945 static LookupEntry evNames[] = {
946     {"press", XkbSA_MessageOnPress},
947     {"keypress", XkbSA_MessageOnPress},
948     {"release", XkbSA_MessageOnRelease},
949     {"keyrelease", XkbSA_MessageOnRelease},
950     {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease},
951     {"none", 0},
952     {NULL, 0}
953 };
954
955 static Bool
956 HandleActionMessage(struct xkb_desc * xkb,
957                     struct xkb_any_action * action,
958                     unsigned field, ExprDef * array_ndx, ExprDef * value)
959 {
960     ExprResult rtrn;
961     struct xkb_message_action *act;
962
963     act = (struct xkb_message_action *) action;
964     switch (field)
965     {
966     case F_Report:
967         if (array_ndx != NULL)
968             return ReportActionNotArray(action->type, field);
969         if (!ExprResolveMask(value, &rtrn, SimpleLookup, (char *) evNames))
970             return ReportMismatch(action->type, field, "key event mask");
971         act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
972         act->flags =
973             rtrn.uval & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
974         return True;
975     case F_GenKeyEvent:
976         if (array_ndx != NULL)
977             return ReportActionNotArray(action->type, field);
978         if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
979             return ReportMismatch(action->type, field, "boolean");
980         if (rtrn.uval)
981             act->flags |= XkbSA_MessageGenKeyEvent;
982         else
983             act->flags &= ~XkbSA_MessageGenKeyEvent;
984         return True;
985     case F_Data:
986         if (array_ndx == NULL)
987         {
988             if (!ExprResolveString(value, &rtrn, NULL, NULL))
989                 return ReportMismatch(action->type, field, "string");
990             else
991             {
992                 int len = strlen(rtrn.str);
993                 if ((len < 1) || (len > 6))
994                 {
995                     WARN("An action message can hold only 6 bytes\n");
996                     ACTION("Extra %d bytes ignored\n", len - 6);
997                 }
998                 strncpy((char *) act->message, rtrn.str, 6);
999             }
1000             return True;
1001         }
1002         else
1003         {
1004             unsigned ndx;
1005             if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1006             {
1007                 ERROR("Array subscript must be integer\n");
1008                 ACTION("Illegal subscript ignored\n");
1009                 return False;
1010             }
1011             ndx = rtrn.uval;
1012             if (ndx > 5)
1013             {
1014                 ERROR("An action message is at most 6 bytes long\n");
1015                 ACTION("Attempt to use data[%d] ignored\n", ndx);
1016                 return False;
1017             }
1018             if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1019                 return ReportMismatch(action->type, field, "integer");
1020             if ((rtrn.ival < 0) || (rtrn.ival > 255))
1021             {
1022                 ERROR("Message data must be in the range 0..255\n");
1023                 ACTION("Illegal datum %d ignored\n", rtrn.ival);
1024                 return False;
1025             }
1026             act->message[ndx] = rtrn.uval;
1027         }
1028         return True;
1029     }
1030     return ReportIllegal(action->type, field);
1031 }
1032
1033 static Bool
1034 HandleRedirectKey(struct xkb_desc * xkb,
1035                   struct xkb_any_action * action,
1036                   unsigned field, ExprDef * array_ndx, ExprDef * value)
1037 {
1038     ExprResult rtrn;
1039     struct xkb_redirect_key_action *act;
1040     unsigned t1, t2;
1041     xkb_keycode_t kc;
1042     unsigned long tmp;
1043
1044     if (array_ndx != NULL)
1045         return ReportActionNotArray(action->type, field);
1046
1047     act = (struct xkb_redirect_key_action *) action;
1048     switch (field)
1049     {
1050     case F_Keycode:
1051         if (!ExprResolveKeyName(value, &rtrn, NULL, NULL))
1052             return ReportMismatch(action->type, field, "key name");
1053         tmp = KeyNameToLong(rtrn.keyName.name);
1054         if (!FindNamedKey(xkb, tmp, &kc, True, CreateKeyNames(xkb), 0))
1055         {
1056             return ReportNotFound(action->type, field, "Key",
1057                                   XkbcKeyNameText(rtrn.keyName.name));
1058         }
1059         act->new_key = kc;
1060         return True;
1061     case F_ModsToClear:
1062     case F_Modifiers:
1063         t1 = 0;
1064         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
1065         {
1066             act->mods_mask |= (t2 & 0xff);
1067             if (field == F_Modifiers)
1068                 act->mods |= (t2 & 0xff);
1069             else
1070                 act->mods &= ~(t2 & 0xff);
1071
1072             t2 = (t2 >> 8) & 0xffff;
1073             act->vmods_mask |= t2;
1074             if (field == F_Modifiers)
1075                 act->vmods |= t2;
1076             else
1077                 act->vmods &= ~t2;
1078             return True;
1079         }
1080         return True;
1081     }
1082     return ReportIllegal(action->type, field);
1083 }
1084
1085 static Bool
1086 HandleDeviceBtn(struct xkb_desc * xkb,
1087                 struct xkb_any_action * action,
1088                 unsigned field, ExprDef * array_ndx, ExprDef * value)
1089 {
1090     ExprResult rtrn;
1091     struct xkb_device_button_action *act;
1092
1093     act = (struct xkb_device_button_action *) action;
1094     if (field == F_Button)
1095     {
1096         if (array_ndx != NULL)
1097             return ReportActionNotArray(action->type, field);
1098         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1099             return ReportMismatch(action->type, field,
1100                                   "integer (range 1..255)");
1101         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1102         {
1103             ERROR("Button must specify default or be in the range 1..255\n");
1104             ACTION("Illegal button value %d ignored\n", rtrn.ival);
1105             return False;
1106         }
1107         act->button = rtrn.ival;
1108         return True;
1109     }
1110     else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
1111     {
1112         if (array_ndx != NULL)
1113             return ReportActionNotArray(action->type, field);
1114         if (!ExprResolveEnum(value, &rtrn, lockWhich))
1115             return ReportMismatch(action->type, field, "lock or unlock");
1116         act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
1117         act->flags |= rtrn.ival;
1118         return True;
1119     }
1120     else if (field == F_Count)
1121     {
1122         if (array_ndx != NULL)
1123             return ReportActionNotArray(action->type, field);
1124         if (!ExprResolveInteger
1125             (value, &rtrn, SimpleLookup, (char *) btnNames))
1126             return ReportMismatch(action->type, field, "integer");
1127         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1128         {
1129             ERROR("The count field must have a value in the range 0..255\n");
1130             ACTION("Illegal count %d ignored\n", rtrn.ival);
1131             return False;
1132         }
1133         act->count = rtrn.ival;
1134         return True;
1135     }
1136     else if (field == F_Device)
1137     {
1138         if (array_ndx != NULL)
1139             return ReportActionNotArray(action->type, field);
1140         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1141             return ReportMismatch(action->type, field,
1142                                   "integer (range 1..255)");
1143         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1144         {
1145             ERROR("Device must specify default or be in the range 1..255\n");
1146             ACTION("Illegal device value %d ignored\n", rtrn.ival);
1147             return False;
1148         }
1149         act->device = rtrn.ival;
1150         return True;
1151     }
1152     return ReportIllegal(action->type, field);
1153 }
1154
1155 static Bool
1156 HandleDeviceValuator(struct xkb_desc * xkb,
1157                      struct xkb_any_action * action,
1158                      unsigned field, ExprDef * array_ndx, ExprDef * value)
1159 {
1160 #if 0
1161     ExprResult rtrn;
1162     struct xkb_device_valuator_action *act;
1163
1164     act = (struct xkb_device_valuator_action *) action;
1165     /*  XXX - Not yet implemented */
1166 #endif
1167     return False;
1168 }
1169
1170 static Bool
1171 HandlePrivate(struct xkb_desc * xkb,
1172               struct xkb_any_action * action,
1173               unsigned field, ExprDef * array_ndx, ExprDef * value)
1174 {
1175     ExprResult rtrn;
1176
1177     switch (field)
1178     {
1179     case F_Type:
1180         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1181             return ReportMismatch(PrivateAction, field, "integer");
1182         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1183         {
1184             ERROR("Private action type must be in the range 0..255\n");
1185             ACTION("Illegal type %d ignored\n", rtrn.ival);
1186             return False;
1187         }
1188         action->type = rtrn.uval;
1189         return True;
1190     case F_Data:
1191         if (array_ndx == NULL)
1192         {
1193             if (!ExprResolveString(value, &rtrn, NULL, NULL))
1194                 return ReportMismatch(action->type, field, "string");
1195             else
1196             {
1197                 int len = strlen(rtrn.str);
1198                 if ((len < 1) || (len > 7))
1199                 {
1200                     WARN("A private action has 7 data bytes\n");
1201                     ACTION("Extra %d bytes ignored\n", len - 6);
1202                     return False;
1203                 }
1204                 strncpy((char *) action->data, rtrn.str, sizeof action->data);
1205             }
1206             free(rtrn.str);
1207             return True;
1208         }
1209         else
1210         {
1211             unsigned ndx;
1212             if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1213             {
1214                 ERROR("Array subscript must be integer\n");
1215                 ACTION("Illegal subscript ignored\n");
1216                 return False;
1217             }
1218             ndx = rtrn.uval;
1219             if (ndx >= sizeof action->data)
1220             {
1221                 ERROR("The data for a private action is 18 bytes long\n");
1222                 ACTION("Attempt to use data[%d] ignored\n", ndx);
1223                 return False;
1224             }
1225             if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1226                 return ReportMismatch(action->type, field, "integer");
1227             if ((rtrn.ival < 0) || (rtrn.ival > 255))
1228             {
1229                 ERROR("All data for a private action must be 0..255\n");
1230                 ACTION("Illegal datum %d ignored\n", rtrn.ival);
1231                 return False;
1232             }
1233             action->data[ndx] = rtrn.uval;
1234             return True;
1235         }
1236     }
1237     return ReportIllegal(PrivateAction, field);
1238 }
1239
1240 typedef Bool(*actionHandler) (struct xkb_desc * /* xkb */ ,
1241                               struct xkb_any_action * /* action */ ,
1242                               unsigned /* field */ ,
1243                               ExprDef * /* array_ndx */ ,
1244                               ExprDef * /* value */
1245     );
1246
1247 static actionHandler handleAction[XkbSA_NumActions + 1] = {
1248     HandleNoAction /* NoAction     */ ,
1249     HandleSetLatchMods /* SetMods      */ ,
1250     HandleSetLatchMods /* LatchMods    */ ,
1251     HandleLockMods /* LockMods     */ ,
1252     HandleSetLatchGroup /* SetGroup     */ ,
1253     HandleSetLatchGroup /* LatchGroup   */ ,
1254     HandleLockGroup /* LockGroup    */ ,
1255     HandleMovePtr /* MovePtr      */ ,
1256     HandlePtrBtn /* PtrBtn       */ ,
1257     HandlePtrBtn /* LockPtrBtn   */ ,
1258     HandleSetPtrDflt /* SetPtrDflt   */ ,
1259     HandleISOLock /* ISOLock      */ ,
1260     HandleNoAction /* Terminate    */ ,
1261     HandleSwitchScreen /* SwitchScreen */ ,
1262     HandleSetLockControls /* SetControls  */ ,
1263     HandleSetLockControls /* LockControls */ ,
1264     HandleActionMessage /* ActionMessage */ ,
1265     HandleRedirectKey /* RedirectKey  */ ,
1266     HandleDeviceBtn /* DeviceBtn    */ ,
1267     HandleDeviceBtn /* LockDeviceBtn */ ,
1268     HandleDeviceValuator /* DeviceValuatr */ ,
1269     HandlePrivate               /* Private      */
1270 };
1271
1272 /***====================================================================***/
1273
1274 static void
1275 ApplyActionFactoryDefaults(union xkb_action * action)
1276 {
1277     if (action->type == XkbSA_SetPtrDflt)
1278     {                           /* increment default button */
1279         action->dflt.affect = XkbSA_AffectDfltBtn;
1280         action->dflt.flags = 0;
1281         action->dflt.value = 1;
1282     }
1283     else if (action->type == XkbSA_ISOLock)
1284     {
1285         action->iso.real_mods = LockMask;
1286     }
1287     return;
1288 }
1289
1290 static void
1291 ActionsInit(void);
1292
1293 int
1294 HandleActionDef(ExprDef * def,
1295                 struct xkb_desc * xkb,
1296                 struct xkb_any_action * action, unsigned mergeMode, ActionInfo * info)
1297 {
1298     ExprDef *arg;
1299     const char *str;
1300     unsigned tmp, hndlrType;
1301
1302     if (!actionsInitialized)
1303         ActionsInit();
1304
1305     if (def->op != ExprActionDecl)
1306     {
1307         ERROR("Expected an action definition, found %s\n",
1308                exprOpText(def->op));
1309         return False;
1310     }
1311     str = XkbcAtomText(def->value.action.name);
1312     if (!str)
1313     {
1314         WSGO("Missing name in action definition!!\n");
1315         return False;
1316     }
1317     if (!stringToAction(str, &tmp))
1318     {
1319         ERROR("Unknown action %s\n", str);
1320         return False;
1321     }
1322     action->type = hndlrType = tmp;
1323     if (action->type != XkbSA_NoAction)
1324     {
1325         ApplyActionFactoryDefaults((union xkb_action *) action);
1326         while (info)
1327         {
1328             if ((info->action == XkbSA_NoAction)
1329                 || (info->action == hndlrType))
1330             {
1331                 if (!(*handleAction[hndlrType]) (xkb, action,
1332                                                  info->field,
1333                                                  info->array_ndx,
1334                                                  info->value))
1335                 {
1336                     return False;
1337                 }
1338             }
1339             info = info->next;
1340         }
1341     }
1342     for (arg = def->value.action.args; arg != NULL;
1343          arg = (ExprDef *) arg->common.next)
1344     {
1345         ExprDef *field, *value, *arrayRtrn;
1346         ExprResult elemRtrn, fieldRtrn;
1347         unsigned fieldNdx;
1348
1349         if (arg->op == OpAssign)
1350         {
1351             field = arg->value.binary.left;
1352             value = arg->value.binary.right;
1353         }
1354         else
1355         {
1356             if ((arg->op == OpNot) || (arg->op == OpInvert))
1357             {
1358                 field = arg->value.child;
1359                 value = &constFalse;
1360             }
1361             else
1362             {
1363                 field = arg;
1364                 value = &constTrue;
1365             }
1366         }
1367         if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
1368             return False;       /* internal error -- already reported */
1369
1370         if (elemRtrn.str != NULL)
1371         {
1372             ERROR("Cannot change defaults in an action definition\n");
1373             ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str,
1374                     fieldRtrn.str);
1375             free(elemRtrn.str);
1376             free(fieldRtrn.str);
1377             return False;
1378         }
1379         if (!stringToField(fieldRtrn.str, &fieldNdx))
1380         {
1381             ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str));
1382             free(elemRtrn.str);
1383             free(fieldRtrn.str);
1384             return False;
1385         }
1386         free(elemRtrn.str);
1387         free(fieldRtrn.str);
1388         if (!(*handleAction[hndlrType])
1389             (xkb, action, fieldNdx, arrayRtrn, value))
1390         {
1391             return False;
1392         }
1393     }
1394     return True;
1395 }
1396
1397 /***====================================================================***/
1398
1399 int
1400 SetActionField(struct xkb_desc * xkb,
1401                char *elem,
1402                char *field,
1403                ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
1404 {
1405     ActionInfo *new, *old;
1406
1407     if (!actionsInitialized)
1408         ActionsInit();
1409
1410     new = uTypedAlloc(ActionInfo);
1411     if (new == NULL)
1412     {
1413         WSGO("Couldn't allocate space for action default\n");
1414         return False;
1415     }
1416     if (uStrCaseCmp(elem, "action") == 0)
1417         new->action = XkbSA_NoAction;
1418     else
1419     {
1420         if (!stringToAction(elem, &new->action))
1421         {
1422             free(new);
1423             return False;
1424         }
1425         if (new->action == XkbSA_NoAction)
1426         {
1427             ERROR("\"%s\" is not a valid field in a NoAction action\n",
1428                    field);
1429             free(new);
1430             return False;
1431         }
1432     }
1433     if (!stringToField(field, &new->field))
1434     {
1435         ERROR("\"%s\" is not a legal field name\n", field);
1436         free(new);
1437         return False;
1438     }
1439     new->array_ndx = array_ndx;
1440     new->value = value;
1441     new->next = NULL;
1442     old = *info_rtrn;
1443     while ((old) && (old->next))
1444         old = old->next;
1445     if (old == NULL)
1446         *info_rtrn = new;
1447     else
1448         old->next = new;
1449     return True;
1450 }
1451
1452 /***====================================================================***/
1453
1454 static void
1455 ActionsInit(void)
1456 {
1457     if (!actionsInitialized)
1458     {
1459         bzero((char *) &constTrue, sizeof(constTrue));
1460         bzero((char *) &constFalse, sizeof(constFalse));
1461         constTrue.common.stmtType = StmtExpr;
1462         constTrue.common.next = NULL;
1463         constTrue.op = ExprIdent;
1464         constTrue.type = TypeBoolean;
1465         constTrue.value.str = xkb_intern_atom("true");
1466         constFalse.common.stmtType = StmtExpr;
1467         constFalse.common.next = NULL;
1468         constFalse.op = ExprIdent;
1469         constFalse.type = TypeBoolean;
1470         constFalse.value.str = xkb_intern_atom("false");
1471         actionsInitialized = 1;
1472     }
1473     return;
1474 }