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