Remove all non-public API from XKBcommon.h header
[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(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(XkbcDescPtr xkb,
337                XkbAnyAction * 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(XkbcDescPtr 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         register char *valStr;
376         valStr = XkbcAtomGetString(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(XkbcDescPtr xkb,
395                    XkbAnyAction * action,
396                    unsigned field, ExprDef * array_ndx, ExprDef * value)
397 {
398     XkbcModAction *act;
399     unsigned rtrn;
400     unsigned t1, t2;
401
402     act = (XkbcModAction *) 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(XkbcDescPtr xkb,
440                XkbAnyAction * action,
441                unsigned field, ExprDef * array_ndx, ExprDef * value)
442 {
443     XkbcModAction *act;
444     unsigned t1, t2;
445
446     act = (XkbcModAction *) 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(XkbcDescPtr xkb,
515                     XkbAnyAction * action,
516                     unsigned field, ExprDef * array_ndx, ExprDef * value)
517 {
518     XkbGroupAction *act;
519     unsigned rtrn;
520     unsigned t1;
521     int t2;
522
523     act = (XkbGroupAction *) 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             XkbSASetGroup(act, t2);
551             return True;
552         }
553         return False;
554     }
555     return ReportIllegal(action->type, field);
556 }
557
558 static Bool
559 HandleLockGroup(XkbcDescPtr xkb,
560                 XkbAnyAction * action,
561                 unsigned field, ExprDef * array_ndx, ExprDef * value)
562 {
563     XkbGroupAction *act;
564     unsigned t1;
565     int t2;
566
567     act = (XkbGroupAction *) 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             XkbSASetGroup(act, t2);
577             return True;
578         }
579         return False;
580     }
581     return ReportIllegal(action->type, field);
582 }
583
584 static Bool
585 HandleMovePtr(XkbcDescPtr xkb,
586               XkbAnyAction * action,
587               unsigned field, ExprDef * array_ndx, ExprDef * value)
588 {
589     ExprResult rtrn;
590     XkbcPtrAction *act;
591     Bool absolute;
592
593     act = (XkbcPtrAction *) 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(XkbcDescPtr xkb,
651              XkbAnyAction * action,
652              unsigned field, ExprDef * array_ndx, ExprDef * value)
653 {
654     ExprResult rtrn;
655     XkbPtrBtnAction *act;
656
657     act = (XkbPtrBtnAction *) 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(XkbcDescPtr xkb,
713                  XkbAnyAction * action,
714                  unsigned field, ExprDef * array_ndx, ExprDef * value)
715 {
716     ExprResult rtrn;
717     XkbPtrDfltAction *act;
718
719     act = (XkbPtrDfltAction *) 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             XkbSASetPtrDfltValue(act, -rtrn.ival);
763         else
764             XkbSASetPtrDfltValue(act, 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(XkbcDescPtr xkb,
786               XkbAnyAction * action,
787               unsigned field, ExprDef * array_ndx, ExprDef * value)
788 {
789     ExprResult rtrn;
790     XkbcISOAction *act;
791     unsigned flags, mods;
792     int group;
793
794     act = (XkbcISOAction *) 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             XkbSASetGroup(act, 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(XkbcDescPtr xkb,
833                    XkbAnyAction * action,
834                    unsigned field, ExprDef * array_ndx, ExprDef * value)
835 {
836     ExprResult rtrn;
837     XkbSwitchScreenAction *act;
838
839     act = (XkbSwitchScreenAction *) 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             XkbSASetScreen(act, -rtrn.ival);
866         else
867             XkbSASetScreen(act, 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(XkbcDescPtr xkb,
925                       XkbAnyAction * action,
926                       unsigned field, ExprDef * array_ndx, ExprDef * value)
927 {
928     ExprResult rtrn;
929     XkbcCtrlsAction *act;
930
931     act = (XkbcCtrlsAction *) 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(XkbcDescPtr xkb,
957                     XkbAnyAction * action,
958                     unsigned field, ExprDef * array_ndx, ExprDef * value)
959 {
960     ExprResult rtrn;
961     XkbMessageAction *act;
962
963     act = (XkbMessageAction *) 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(XkbcDescPtr xkb,
1035                   XkbAnyAction * action,
1036                   unsigned field, ExprDef * array_ndx, ExprDef * value)
1037 {
1038     ExprResult rtrn;
1039     XkbcRedirectKeyAction *act;
1040     unsigned t1, t2;
1041     unsigned long tmp;
1042
1043     if (array_ndx != NULL)
1044         return ReportActionNotArray(action->type, field);
1045
1046     act = (XkbcRedirectKeyAction *) action;
1047     switch (field)
1048     {
1049     case F_Keycode:
1050         if (!ExprResolveKeyName(value, &rtrn, NULL, NULL))
1051             return ReportMismatch(action->type, field, "key name");
1052         tmp = KeyNameToLong(rtrn.keyName.name);
1053         if (!FindNamedKey(xkb, tmp, &t1, True, CreateKeyNames(xkb), 0))
1054         {
1055             return ReportNotFound(action->type, field, "Key",
1056                                   XkbcKeyNameText(rtrn.keyName.name));
1057         }
1058         act->new_key = t1;
1059         return True;
1060     case F_ModsToClear:
1061     case F_Modifiers:
1062         t1 = 0;
1063         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
1064         {
1065             act->mods_mask |= (t2 & 0xff);
1066             if (field == F_Modifiers)
1067                 act->mods |= (t2 & 0xff);
1068             else
1069                 act->mods &= ~(t2 & 0xff);
1070
1071             t2 = (t2 >> 8) & 0xffff;
1072             act->vmods_mask |= t2;
1073             if (field == F_Modifiers)
1074                 act->vmods |= t2;
1075             else
1076                 act->vmods &= ~t2;
1077             return True;
1078         }
1079         return True;
1080     }
1081     return ReportIllegal(action->type, field);
1082 }
1083
1084 static Bool
1085 HandleDeviceBtn(XkbcDescPtr xkb,
1086                 XkbAnyAction * action,
1087                 unsigned field, ExprDef * array_ndx, ExprDef * value)
1088 {
1089     ExprResult rtrn;
1090     XkbDeviceBtnAction *act;
1091
1092     act = (XkbDeviceBtnAction *) action;
1093     if (field == F_Button)
1094     {
1095         if (array_ndx != NULL)
1096             return ReportActionNotArray(action->type, field);
1097         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1098             return ReportMismatch(action->type, field,
1099                                   "integer (range 1..255)");
1100         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1101         {
1102             ERROR("Button must specify default or be in the range 1..255\n");
1103             ACTION("Illegal button value %d ignored\n", rtrn.ival);
1104             return False;
1105         }
1106         act->button = rtrn.ival;
1107         return True;
1108     }
1109     else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
1110     {
1111         if (array_ndx != NULL)
1112             return ReportActionNotArray(action->type, field);
1113         if (!ExprResolveEnum(value, &rtrn, lockWhich))
1114             return ReportMismatch(action->type, field, "lock or unlock");
1115         act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
1116         act->flags |= rtrn.ival;
1117         return True;
1118     }
1119     else if (field == F_Count)
1120     {
1121         if (array_ndx != NULL)
1122             return ReportActionNotArray(action->type, field);
1123         if (!ExprResolveInteger
1124             (value, &rtrn, SimpleLookup, (char *) btnNames))
1125             return ReportMismatch(action->type, field, "integer");
1126         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1127         {
1128             ERROR("The count field must have a value in the range 0..255\n");
1129             ACTION("Illegal count %d ignored\n", rtrn.ival);
1130             return False;
1131         }
1132         act->count = rtrn.ival;
1133         return True;
1134     }
1135     else if (field == F_Device)
1136     {
1137         if (array_ndx != NULL)
1138             return ReportActionNotArray(action->type, field);
1139         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1140             return ReportMismatch(action->type, field,
1141                                   "integer (range 1..255)");
1142         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1143         {
1144             ERROR("Device must specify default or be in the range 1..255\n");
1145             ACTION("Illegal device value %d ignored\n", rtrn.ival);
1146             return False;
1147         }
1148         act->device = rtrn.ival;
1149         return True;
1150     }
1151     return ReportIllegal(action->type, field);
1152 }
1153
1154 static Bool
1155 HandleDeviceValuator(XkbcDescPtr xkb,
1156                      XkbAnyAction * action,
1157                      unsigned field, ExprDef * array_ndx, ExprDef * value)
1158 {
1159 #if 0
1160     ExprResult rtrn;
1161     XkbDeviceValuatorAction *act;
1162
1163     act = (XkbDeviceValuatorAction *) action;
1164     /*  XXX - Not yet implemented */
1165 #endif
1166     return False;
1167 }
1168
1169 static Bool
1170 HandlePrivate(XkbcDescPtr xkb,
1171               XkbAnyAction * action,
1172               unsigned field, ExprDef * array_ndx, ExprDef * value)
1173 {
1174     ExprResult rtrn;
1175
1176     switch (field)
1177     {
1178     case F_Type:
1179         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1180             return ReportMismatch(PrivateAction, field, "integer");
1181         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1182         {
1183             ERROR("Private action type must be in the range 0..255\n");
1184             ACTION("Illegal type %d ignored\n", rtrn.ival);
1185             return False;
1186         }
1187         action->type = rtrn.uval;
1188         return True;
1189     case F_Data:
1190         if (array_ndx == NULL)
1191         {
1192             if (!ExprResolveString(value, &rtrn, NULL, NULL))
1193                 return ReportMismatch(action->type, field, "string");
1194             else
1195             {
1196                 int len = strlen(rtrn.str);
1197                 if ((len < 1) || (len > 7))
1198                 {
1199                     WARN("A private action has 7 data bytes\n");
1200                     ACTION("Extra %d bytes ignored\n", len - 6);
1201                     return False;
1202                 }
1203                 strncpy((char *) action->data, rtrn.str, 7);
1204             }
1205             return True;
1206         }
1207         else
1208         {
1209             unsigned ndx;
1210             if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1211             {
1212                 ERROR("Array subscript must be integer\n");
1213                 ACTION("Illegal subscript ignored\n");
1214                 return False;
1215             }
1216             ndx = rtrn.uval;
1217             if (ndx > 6)
1218             {
1219                 ERROR("The data for a private action is 7 bytes long\n");
1220                 ACTION("Attempt to use data[%d] ignored\n", ndx);
1221                 return False;
1222             }
1223             if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1224                 return ReportMismatch(action->type, field, "integer");
1225             if ((rtrn.ival < 0) || (rtrn.ival > 255))
1226             {
1227                 ERROR("All data for a private action must be 0..255\n");
1228                 ACTION("Illegal datum %d ignored\n", rtrn.ival);
1229                 return False;
1230             }
1231             action->data[ndx] = rtrn.uval;
1232             return True;
1233         }
1234     }
1235     return ReportIllegal(PrivateAction, field);
1236 }
1237
1238 typedef Bool(*actionHandler) (XkbcDescPtr /* xkb */ ,
1239                               XkbAnyAction * /* action */ ,
1240                               unsigned /* field */ ,
1241                               ExprDef * /* array_ndx */ ,
1242                               ExprDef * /* value */
1243     );
1244
1245 static actionHandler handleAction[XkbSA_NumActions + 1] = {
1246     HandleNoAction /* NoAction     */ ,
1247     HandleSetLatchMods /* SetMods      */ ,
1248     HandleSetLatchMods /* LatchMods    */ ,
1249     HandleLockMods /* LockMods     */ ,
1250     HandleSetLatchGroup /* SetGroup     */ ,
1251     HandleSetLatchGroup /* LatchGroup   */ ,
1252     HandleLockGroup /* LockGroup    */ ,
1253     HandleMovePtr /* MovePtr      */ ,
1254     HandlePtrBtn /* PtrBtn       */ ,
1255     HandlePtrBtn /* LockPtrBtn   */ ,
1256     HandleSetPtrDflt /* SetPtrDflt   */ ,
1257     HandleISOLock /* ISOLock      */ ,
1258     HandleNoAction /* Terminate    */ ,
1259     HandleSwitchScreen /* SwitchScreen */ ,
1260     HandleSetLockControls /* SetControls  */ ,
1261     HandleSetLockControls /* LockControls */ ,
1262     HandleActionMessage /* ActionMessage */ ,
1263     HandleRedirectKey /* RedirectKey  */ ,
1264     HandleDeviceBtn /* DeviceBtn    */ ,
1265     HandleDeviceBtn /* LockDeviceBtn */ ,
1266     HandleDeviceValuator /* DeviceValuatr */ ,
1267     HandlePrivate               /* Private      */
1268 };
1269
1270 /***====================================================================***/
1271
1272 static void
1273 ApplyActionFactoryDefaults(XkbcAction * action)
1274 {
1275     if (action->type == XkbSA_SetPtrDflt)
1276     {                           /* increment default button */
1277         action->dflt.affect = XkbSA_AffectDfltBtn;
1278         action->dflt.flags = 0;
1279         XkbSASetPtrDfltValue(&action->dflt, 1);
1280     }
1281     else if (action->type == XkbSA_ISOLock)
1282     {
1283         action->iso.real_mods = LockMask;
1284     }
1285     return;
1286 }
1287
1288
1289 int
1290 HandleActionDef(ExprDef * def,
1291                 XkbcDescPtr xkb,
1292                 XkbAnyAction * action, unsigned mergeMode, ActionInfo * info)
1293 {
1294     ExprDef *arg;
1295     register char *str;
1296     unsigned tmp, hndlrType;
1297
1298     if (!actionsInitialized)
1299         ActionsInit();
1300
1301     if (def->op != ExprActionDecl)
1302     {
1303         ERROR("Expected an action definition, found %s\n",
1304                exprOpText(def->op));
1305         return False;
1306     }
1307     str = XkbcAtomGetString(def->value.action.name);
1308     if (!str)
1309     {
1310         WSGO("Missing name in action definition!!\n");
1311         return False;
1312     }
1313     if (!stringToAction(str, &tmp))
1314     {
1315         ERROR("Unknown action %s\n", str);
1316         return False;
1317     }
1318     action->type = hndlrType = tmp;
1319     if (action->type != XkbSA_NoAction)
1320     {
1321         ApplyActionFactoryDefaults((XkbcAction *) action);
1322         while (info)
1323         {
1324             if ((info->action == XkbSA_NoAction)
1325                 || (info->action == hndlrType))
1326             {
1327                 if (!(*handleAction[hndlrType]) (xkb, action,
1328                                                  info->field,
1329                                                  info->array_ndx,
1330                                                  info->value))
1331                 {
1332                     return False;
1333                 }
1334             }
1335             info = info->next;
1336         }
1337     }
1338     for (arg = def->value.action.args; arg != NULL;
1339          arg = (ExprDef *) arg->common.next)
1340     {
1341         ExprDef *field, *value, *arrayRtrn;
1342         ExprResult elemRtrn, fieldRtrn;
1343         unsigned fieldNdx;
1344
1345         if (arg->op == OpAssign)
1346         {
1347             field = arg->value.binary.left;
1348             value = arg->value.binary.right;
1349         }
1350         else
1351         {
1352             if ((arg->op == OpNot) || (arg->op == OpInvert))
1353             {
1354                 field = arg->value.child;
1355                 value = &constFalse;
1356             }
1357             else
1358             {
1359                 field = arg;
1360                 value = &constTrue;
1361             }
1362         }
1363         if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
1364             return False;       /* internal error -- already reported */
1365
1366         if (elemRtrn.str != NULL)
1367         {
1368             ERROR("Cannot change defaults in an action definition\n");
1369             ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str,
1370                     fieldRtrn.str);
1371             return False;
1372         }
1373         if (!stringToField(fieldRtrn.str, &fieldNdx))
1374         {
1375             ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str));
1376             return False;
1377         }
1378         if (!(*handleAction[hndlrType])
1379             (xkb, action, fieldNdx, arrayRtrn, value))
1380         {
1381             return False;
1382         }
1383     }
1384     return True;
1385 }
1386
1387 /***====================================================================***/
1388
1389 int
1390 SetActionField(XkbcDescPtr xkb,
1391                char *elem,
1392                char *field,
1393                ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
1394 {
1395     ActionInfo *new, *old;
1396
1397     if (!actionsInitialized)
1398         ActionsInit();
1399
1400     new = uTypedAlloc(ActionInfo);
1401     if (new == NULL)
1402     {
1403         WSGO("Couldn't allocate space for action default\n");
1404         return False;
1405     }
1406     if (uStrCaseCmp(elem, "action") == 0)
1407         new->action = XkbSA_NoAction;
1408     else
1409     {
1410         if (!stringToAction(elem, &new->action))
1411             return False;
1412         if (new->action == XkbSA_NoAction)
1413         {
1414             ERROR("\"%s\" is not a valid field in a NoAction action\n",
1415                    field);
1416             return False;
1417         }
1418     }
1419     if (!stringToField(field, &new->field))
1420     {
1421         ERROR("\"%s\" is not a legal field name\n", field);
1422         return False;
1423     }
1424     new->array_ndx = array_ndx;
1425     new->value = value;
1426     new->next = NULL;
1427     old = *info_rtrn;
1428     while ((old) && (old->next))
1429         old = old->next;
1430     if (old == NULL)
1431         *info_rtrn = new;
1432     else
1433         old->next = new;
1434     return True;
1435 }
1436
1437 /***====================================================================***/
1438
1439 void
1440 ActionsInit(void)
1441 {
1442     if (!actionsInitialized)
1443     {
1444         bzero((char *) &constTrue, sizeof(constTrue));
1445         bzero((char *) &constFalse, sizeof(constFalse));
1446         constTrue.common.stmtType = StmtExpr;
1447         constTrue.common.next = NULL;
1448         constTrue.op = ExprIdent;
1449         constTrue.type = TypeBoolean;
1450         constTrue.value.str = XkbcInternAtom("true", False);
1451         constFalse.common.stmtType = StmtExpr;
1452         constFalse.common.next = NULL;
1453         constFalse.op = ExprIdent;
1454         constFalse.type = TypeBoolean;
1455         constFalse.value.str = XkbcInternAtom("false", False);
1456         actionsInitialized = 1;
1457     }
1458     return;
1459 }