xkbcomp: Drop unused Display argument in Atom functions
[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     ERROR2("Value of %s field must be of type %s\n", fieldText(field), type);
303     ACTION1("Action %s definition ignored\n", XkbActionTypeText(action));
304     return False;
305 }
306
307 static Bool
308 ReportIllegal(unsigned action, unsigned field)
309 {
310     ERROR2("Field %s is not defined for an action of type %s\n",
311            fieldText(field), XkbActionTypeText(action));
312     ACTION("Action definition ignored\n");
313     return False;
314 }
315
316 static Bool
317 ReportActionNotArray(unsigned action, unsigned field)
318 {
319     ERROR2("The %s field in the %s action is not an array\n",
320            fieldText(field), XkbActionTypeText(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     ERROR2("%s named %s not found\n", what, bad);
329     ACTION2("Ignoring the %s field of an %s action\n", fieldText(field),
330             XkbActionTypeText(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         ERROR2("Illegal group %d (must be in the range 1..%d)\n", rtrn.ival,
501                XkbNumKbdGroups);
502         ACTION1("Action %s definition ignored\n", XkbActionTypeText(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             ACTION1("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             ACTION1("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             ACTION1("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             ACTION1("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                     ACTION1("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                 ACTION1("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                 ACTION1("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                                   XkbKeyNameText(rtrn.keyName.name,
1059                                                  XkbMessage));
1060         }
1061         act->new_key = t1;
1062         return True;
1063     case F_ModsToClear:
1064     case F_Modifiers:
1065         t1 = 0;
1066         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
1067         {
1068             act->mods_mask |= (t2 & 0xff);
1069             if (field == F_Modifiers)
1070                 act->mods |= (t2 & 0xff);
1071             else
1072                 act->mods &= ~(t2 & 0xff);
1073
1074             t2 = (t2 >> 8) & 0xffff;
1075             vmods = XkbSARedirectVMods(act);
1076             vmask = XkbSARedirectVModsMask(act);
1077             vmask |= t2;
1078             if (field == F_Modifiers)
1079                 vmods |= t2;
1080             else
1081                 vmods &= ~t2;
1082             XkbSARedirectSetVMods(act, vmods);
1083             XkbSARedirectSetVModsMask(act, vmask);
1084             return True;
1085         }
1086         return True;
1087     }
1088     return ReportIllegal(action->type, field);
1089 }
1090
1091 static Bool
1092 HandleDeviceBtn(XkbcDescPtr xkb,
1093                 XkbAnyAction * action,
1094                 unsigned field, ExprDef * array_ndx, ExprDef * value)
1095 {
1096     ExprResult rtrn;
1097     XkbDeviceBtnAction *act;
1098
1099     act = (XkbDeviceBtnAction *) action;
1100     if (field == F_Button)
1101     {
1102         if (array_ndx != NULL)
1103             return ReportActionNotArray(action->type, field);
1104         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1105             return ReportMismatch(action->type, field,
1106                                   "integer (range 1..255)");
1107         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1108         {
1109             ERROR("Button must specify default or be in the range 1..255\n");
1110             ACTION1("Illegal button value %d ignored\n", rtrn.ival);
1111             return False;
1112         }
1113         act->button = rtrn.ival;
1114         return True;
1115     }
1116     else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
1117     {
1118         if (array_ndx != NULL)
1119             return ReportActionNotArray(action->type, field);
1120         if (!ExprResolveEnum(value, &rtrn, lockWhich))
1121             return ReportMismatch(action->type, field, "lock or unlock");
1122         act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
1123         act->flags |= rtrn.ival;
1124         return True;
1125     }
1126     else if (field == F_Count)
1127     {
1128         if (array_ndx != NULL)
1129             return ReportActionNotArray(action->type, field);
1130         if (!ExprResolveInteger
1131             (value, &rtrn, SimpleLookup, (char *) btnNames))
1132             return ReportMismatch(action->type, field, "integer");
1133         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1134         {
1135             ERROR("The count field must have a value in the range 0..255\n");
1136             ACTION1("Illegal count %d ignored\n", rtrn.ival);
1137             return False;
1138         }
1139         act->count = rtrn.ival;
1140         return True;
1141     }
1142     else if (field == F_Device)
1143     {
1144         if (array_ndx != NULL)
1145             return ReportActionNotArray(action->type, field);
1146         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1147             return ReportMismatch(action->type, field,
1148                                   "integer (range 1..255)");
1149         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1150         {
1151             ERROR("Device must specify default or be in the range 1..255\n");
1152             ACTION1("Illegal device value %d ignored\n", rtrn.ival);
1153             return False;
1154         }
1155         act->device = rtrn.ival;
1156         return True;
1157     }
1158     return ReportIllegal(action->type, field);
1159 }
1160
1161 static Bool
1162 HandleDeviceValuator(XkbcDescPtr xkb,
1163                      XkbAnyAction * action,
1164                      unsigned field, ExprDef * array_ndx, ExprDef * value)
1165 {
1166 #if 0
1167     ExprResult rtrn;
1168     XkbDeviceValuatorAction *act;
1169
1170     act = (XkbDeviceValuatorAction *) action;
1171     /*  XXX - Not yet implemented */
1172 #endif
1173     return False;
1174 }
1175
1176 static Bool
1177 HandlePrivate(XkbcDescPtr xkb,
1178               XkbAnyAction * action,
1179               unsigned field, ExprDef * array_ndx, ExprDef * value)
1180 {
1181     ExprResult rtrn;
1182
1183     switch (field)
1184     {
1185     case F_Type:
1186         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1187             return ReportMismatch(PrivateAction, field, "integer");
1188         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1189         {
1190             ERROR("Private action type must be in the range 0..255\n");
1191             ACTION1("Illegal type %d ignored\n", rtrn.ival);
1192             return False;
1193         }
1194         action->type = rtrn.uval;
1195         return True;
1196     case F_Data:
1197         if (array_ndx == NULL)
1198         {
1199             if (!ExprResolveString(value, &rtrn, NULL, NULL))
1200                 return ReportMismatch(action->type, field, "string");
1201             else
1202             {
1203                 int len = strlen(rtrn.str);
1204                 if ((len < 1) || (len > 7))
1205                 {
1206                     WARN("A private action has 7 data bytes\n");
1207                     ACTION1("Extra %d bytes ignored\n", len - 6);
1208                     return False;
1209                 }
1210                 strncpy((char *) action->data, rtrn.str, 7);
1211             }
1212             return True;
1213         }
1214         else
1215         {
1216             unsigned ndx;
1217             if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1218             {
1219                 ERROR("Array subscript must be integer\n");
1220                 ACTION("Illegal subscript ignored\n");
1221                 return False;
1222             }
1223             ndx = rtrn.uval;
1224             if (ndx > 6)
1225             {
1226                 ERROR("The data for a private action is 7 bytes long\n");
1227                 ACTION1("Attempt to use data[%d] ignored\n", ndx);
1228                 return False;
1229             }
1230             if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1231                 return ReportMismatch(action->type, field, "integer");
1232             if ((rtrn.ival < 0) || (rtrn.ival > 255))
1233             {
1234                 ERROR("All data for a private action must be 0..255\n");
1235                 ACTION1("Illegal datum %d ignored\n", rtrn.ival);
1236                 return False;
1237             }
1238             action->data[ndx] = rtrn.uval;
1239             return True;
1240         }
1241     }
1242     return ReportIllegal(PrivateAction, field);
1243 }
1244
1245 typedef Bool(*actionHandler) (XkbcDescPtr /* xkb */ ,
1246                               XkbAnyAction * /* action */ ,
1247                               unsigned /* field */ ,
1248                               ExprDef * /* array_ndx */ ,
1249                               ExprDef * /* value */
1250     );
1251
1252 static actionHandler handleAction[XkbSA_NumActions + 1] = {
1253     HandleNoAction /* NoAction     */ ,
1254     HandleSetLatchMods /* SetMods      */ ,
1255     HandleSetLatchMods /* LatchMods    */ ,
1256     HandleLockMods /* LockMods     */ ,
1257     HandleSetLatchGroup /* SetGroup     */ ,
1258     HandleSetLatchGroup /* LatchGroup   */ ,
1259     HandleLockGroup /* LockGroup    */ ,
1260     HandleMovePtr /* MovePtr      */ ,
1261     HandlePtrBtn /* PtrBtn       */ ,
1262     HandlePtrBtn /* LockPtrBtn   */ ,
1263     HandleSetPtrDflt /* SetPtrDflt   */ ,
1264     HandleISOLock /* ISOLock      */ ,
1265     HandleNoAction /* Terminate    */ ,
1266     HandleSwitchScreen /* SwitchScreen */ ,
1267     HandleSetLockControls /* SetControls  */ ,
1268     HandleSetLockControls /* LockControls */ ,
1269     HandleActionMessage /* ActionMessage */ ,
1270     HandleRedirectKey /* RedirectKey  */ ,
1271     HandleDeviceBtn /* DeviceBtn    */ ,
1272     HandleDeviceBtn /* LockDeviceBtn */ ,
1273     HandleDeviceValuator /* DeviceValuatr */ ,
1274     HandlePrivate               /* Private      */
1275 };
1276
1277 /***====================================================================***/
1278
1279 static void
1280 ApplyActionFactoryDefaults(XkbAction * action)
1281 {
1282     if (action->type == XkbSA_SetPtrDflt)
1283     {                           /* increment default button */
1284         action->dflt.affect = XkbSA_AffectDfltBtn;
1285         action->dflt.flags = 0;
1286         XkbSASetPtrDfltValue(&action->dflt, 1);
1287     }
1288     else if (action->type == XkbSA_ISOLock)
1289     {
1290         action->iso.real_mods = LockMask;
1291     }
1292     return;
1293 }
1294
1295
1296 int
1297 HandleActionDef(ExprDef * def,
1298                 XkbcDescPtr xkb,
1299                 XkbAnyAction * action, unsigned mergeMode, ActionInfo * info)
1300 {
1301     ExprDef *arg;
1302     register char *str;
1303     unsigned tmp, hndlrType;
1304
1305     if (!actionsInitialized)
1306         ActionsInit();
1307
1308     if (def->op != ExprActionDecl)
1309     {
1310         ERROR1("Expected an action definition, found %s\n",
1311                exprOpText(def->op));
1312         return False;
1313     }
1314     str = XkbcAtomGetString(def->value.action.name);
1315     if (!str)
1316     {
1317         WSGO("Missing name in action definition!!\n");
1318         return False;
1319     }
1320     if (!stringToAction(str, &tmp))
1321     {
1322         ERROR1("Unknown action %s\n", str);
1323         return False;
1324     }
1325     action->type = hndlrType = tmp;
1326     if (action->type != XkbSA_NoAction)
1327     {
1328         ApplyActionFactoryDefaults((XkbAction *) action);
1329         while (info)
1330         {
1331             if ((info->action == XkbSA_NoAction)
1332                 || (info->action == hndlrType))
1333             {
1334                 if (!(*handleAction[hndlrType]) (xkb, action,
1335                                                  info->field,
1336                                                  info->array_ndx,
1337                                                  info->value))
1338                 {
1339                     return False;
1340                 }
1341             }
1342             info = info->next;
1343         }
1344     }
1345     for (arg = def->value.action.args; arg != NULL;
1346          arg = (ExprDef *) arg->common.next)
1347     {
1348         ExprDef *field, *value, *arrayRtrn;
1349         ExprResult elemRtrn, fieldRtrn;
1350         unsigned fieldNdx;
1351
1352         if (arg->op == OpAssign)
1353         {
1354             field = arg->value.binary.left;
1355             value = arg->value.binary.right;
1356         }
1357         else
1358         {
1359             if ((arg->op == OpNot) || (arg->op == OpInvert))
1360             {
1361                 field = arg->value.child;
1362                 value = &constFalse;
1363             }
1364             else
1365             {
1366                 field = arg;
1367                 value = &constTrue;
1368             }
1369         }
1370         if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
1371             return False;       /* internal error -- already reported */
1372
1373         if (elemRtrn.str != NULL)
1374         {
1375             ERROR("Cannot change defaults in an action definition\n");
1376             ACTION2("Ignoring attempt to change %s.%s\n", elemRtrn.str,
1377                     fieldRtrn.str);
1378             return False;
1379         }
1380         if (!stringToField(fieldRtrn.str, &fieldNdx))
1381         {
1382             ERROR1("Unknown field name %s\n", uStringText(fieldRtrn.str));
1383             return False;
1384         }
1385         if (!(*handleAction[hndlrType])
1386             (xkb, action, fieldNdx, arrayRtrn, value))
1387         {
1388             return False;
1389         }
1390     }
1391     return True;
1392 }
1393
1394 /***====================================================================***/
1395
1396 int
1397 SetActionField(XkbcDescPtr xkb,
1398                char *elem,
1399                char *field,
1400                ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
1401 {
1402     ActionInfo *new, *old;
1403
1404     if (!actionsInitialized)
1405         ActionsInit();
1406
1407     new = uTypedAlloc(ActionInfo);
1408     if (new == NULL)
1409     {
1410         WSGO("Couldn't allocate space for action default\n");
1411         return False;
1412     }
1413     if (uStrCaseCmp(elem, "action") == 0)
1414         new->action = XkbSA_NoAction;
1415     else
1416     {
1417         if (!stringToAction(elem, &new->action))
1418             return False;
1419         if (new->action == XkbSA_NoAction)
1420         {
1421             ERROR1("\"%s\" is not a valid field in a NoAction action\n",
1422                    field);
1423             return False;
1424         }
1425     }
1426     if (!stringToField(field, &new->field))
1427     {
1428         ERROR1("\"%s\" is not a legal field name\n", field);
1429         return False;
1430     }
1431     new->array_ndx = array_ndx;
1432     new->value = value;
1433     new->next = NULL;
1434     old = *info_rtrn;
1435     while ((old) && (old->next))
1436         old = old->next;
1437     if (old == NULL)
1438         *info_rtrn = new;
1439     else
1440         old->next = new;
1441     return True;
1442 }
1443
1444 /***====================================================================***/
1445
1446 void
1447 ActionsInit(void)
1448 {
1449     if (!actionsInitialized)
1450     {
1451         bzero((char *) &constTrue, sizeof(constTrue));
1452         bzero((char *) &constFalse, sizeof(constFalse));
1453         constTrue.common.stmtType = StmtExpr;
1454         constTrue.common.next = NULL;
1455         constTrue.op = ExprIdent;
1456         constTrue.type = TypeBoolean;
1457         constTrue.value.str = XkbcInternAtom("true", False);
1458         constFalse.common.stmtType = StmtExpr;
1459         constFalse.common.next = NULL;
1460         constFalse.op = ExprIdent;
1461         constFalse.type = TypeBoolean;
1462         constFalse.value.str = XkbcInternAtom("false", False);
1463         actionsInitialized = 1;
1464     }
1465     return;
1466 }