Add action datatypes as defined in the server
[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     XkbcModAction *act;
398     unsigned rtrn;
399     unsigned t1, t2;
400
401     act = (XkbcModAction *) 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             act->vmods = (t2 >> 8) & 0xffff;
430             return True;
431         }
432         return False;
433     }
434     return ReportIllegal(action->type, field);
435 }
436
437 static Bool
438 HandleLockMods(XkbcDescPtr xkb,
439                XkbAnyAction * action,
440                unsigned field, ExprDef * array_ndx, ExprDef * value)
441 {
442     XkbcModAction *act;
443     unsigned t1, t2;
444
445     act = (XkbcModAction *) action;
446     if ((array_ndx != NULL) && (field == F_Modifiers))
447         return ReportActionNotArray(action->type, field);
448     switch (field)
449     {
450     case F_Modifiers:
451         t1 = act->flags;
452         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
453         {
454             act->flags = t1;
455             act->real_mods = act->mask = (t2 & 0xff);
456             act->vmods = (t2 >> 8) & 0xffff;
457             return True;
458         }
459         return False;
460     }
461     return ReportIllegal(action->type, field);
462 }
463
464 static LookupEntry groupNames[] = {
465     {"group1", 1},
466     {"group2", 2},
467     {"group3", 3},
468     {"group4", 4},
469     {"group5", 5},
470     {"group6", 6},
471     {"group7", 7},
472     {"group8", 8},
473     {NULL, 0},
474 };
475
476 static Bool
477 CheckGroupField(unsigned action,
478                 ExprDef * value, unsigned *flags_inout, int *grp_rtrn)
479 {
480     ExprDef *spec;
481     ExprResult rtrn;
482
483     if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
484     {
485         *flags_inout &= ~XkbSA_GroupAbsolute;
486         spec = value->value.child;
487     }
488     else
489     {
490         *flags_inout |= XkbSA_GroupAbsolute;
491         spec = value;
492     }
493
494     if (!ExprResolveInteger(spec, &rtrn, SimpleLookup, (char *) groupNames))
495         return ReportMismatch(action, F_Group, "integer (range 1..8)");
496     if ((rtrn.ival < 1) || (rtrn.ival > XkbNumKbdGroups))
497     {
498         ERROR("Illegal group %d (must be in the range 1..%d)\n", rtrn.ival,
499                XkbNumKbdGroups);
500         ACTION("Action %s definition ignored\n", XkbcActionTypeText(action));
501         return False;
502     }
503     if (value->op == OpNegate)
504         *grp_rtrn = -rtrn.ival;
505     else if (value->op == OpUnaryPlus)
506         *grp_rtrn = rtrn.ival;
507     else
508         *grp_rtrn = rtrn.ival - 1;
509     return True;
510 }
511
512 static Bool
513 HandleSetLatchGroup(XkbcDescPtr xkb,
514                     XkbAnyAction * action,
515                     unsigned field, ExprDef * array_ndx, ExprDef * value)
516 {
517     XkbGroupAction *act;
518     unsigned rtrn;
519     unsigned t1;
520     int t2;
521
522     act = (XkbGroupAction *) action;
523     if (array_ndx != NULL)
524     {
525         switch (field)
526         {
527         case F_ClearLocks:
528         case F_LatchToLock:
529         case F_Group:
530             return ReportActionNotArray(action->type, field);
531         }
532     }
533     switch (field)
534     {
535     case F_ClearLocks:
536     case F_LatchToLock:
537         rtrn = act->flags;
538         if (CheckLatchLockFlags(action->type, field, value, &rtrn))
539         {
540             act->flags = rtrn;
541             return True;
542         }
543         return False;
544     case F_Group:
545         t1 = act->flags;
546         if (CheckGroupField(action->type, value, &t1, &t2))
547         {
548             act->flags = t1;
549             XkbSASetGroup(act, t2);
550             return True;
551         }
552         return False;
553     }
554     return ReportIllegal(action->type, field);
555 }
556
557 static Bool
558 HandleLockGroup(XkbcDescPtr xkb,
559                 XkbAnyAction * action,
560                 unsigned field, ExprDef * array_ndx, ExprDef * value)
561 {
562     XkbGroupAction *act;
563     unsigned t1;
564     int t2;
565
566     act = (XkbGroupAction *) action;
567     if ((array_ndx != NULL) && (field == F_Group))
568         return ReportActionNotArray(action->type, field);
569     if (field == F_Group)
570     {
571         t1 = act->flags;
572         if (CheckGroupField(action->type, value, &t1, &t2))
573         {
574             act->flags = t1;
575             XkbSASetGroup(act, t2);
576             return True;
577         }
578         return False;
579     }
580     return ReportIllegal(action->type, field);
581 }
582
583 static Bool
584 HandleMovePtr(XkbcDescPtr xkb,
585               XkbAnyAction * action,
586               unsigned field, ExprDef * array_ndx, ExprDef * value)
587 {
588     ExprResult rtrn;
589     XkbcPtrAction *act;
590     Bool absolute;
591
592     act = (XkbcPtrAction *) action;
593     if ((array_ndx != NULL) && ((field == F_X) || (field == F_Y)))
594         return ReportActionNotArray(action->type, field);
595
596     if ((field == F_X) || (field == F_Y))
597     {
598         if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
599             absolute = False;
600         else
601             absolute = True;
602         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
603             return ReportMismatch(action->type, field, "integer");
604         if (field == F_X)
605         {
606             if (absolute)
607                 act->flags |= XkbSA_MoveAbsoluteX;
608             act->x = rtrn.ival;
609         }
610         else
611         {
612             if (absolute)
613                 act->flags |= XkbSA_MoveAbsoluteY;
614             act->y = rtrn.ival;
615         }
616         return True;
617     }
618     else if (field == F_Accel)
619     {
620         if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
621             return ReportMismatch(action->type, field, "boolean");
622         if (rtrn.uval)
623             act->flags &= ~XkbSA_NoAcceleration;
624         else
625             act->flags |= XkbSA_NoAcceleration;
626     }
627     return ReportIllegal(action->type, field);
628 }
629
630 static LookupEntry btnNames[] = {
631     {"button1", 1},
632     {"button2", 2},
633     {"button3", 3},
634     {"button4", 4},
635     {"button5", 5},
636     {"default", 0},
637     {NULL, 0}
638 };
639
640 static LookupEntry lockWhich[] = {
641     {"both", 0},
642     {"lock", XkbSA_LockNoUnlock},
643     {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)},
644     {"unlock", XkbSA_LockNoLock},
645     {NULL, 0}
646 };
647
648 static Bool
649 HandlePtrBtn(XkbcDescPtr xkb,
650              XkbAnyAction * action,
651              unsigned field, ExprDef * array_ndx, ExprDef * value)
652 {
653     ExprResult rtrn;
654     XkbPtrBtnAction *act;
655
656     act = (XkbPtrBtnAction *) action;
657     if (field == F_Button)
658     {
659         if (array_ndx != NULL)
660             return ReportActionNotArray(action->type, field);
661         if (!ExprResolveInteger
662             (value, &rtrn, SimpleLookup, (char *) btnNames))
663             return ReportMismatch(action->type, field,
664                                   "integer (range 1..5)");
665         if ((rtrn.ival < 0) || (rtrn.ival > 5))
666         {
667             ERROR("Button must specify default or be in the range 1..5\n");
668             ACTION("Illegal button value %d ignored\n", rtrn.ival);
669             return False;
670         }
671         act->button = rtrn.ival;
672         return True;
673     }
674     else if ((action->type == XkbSA_LockPtrBtn) && (field == F_Affect))
675     {
676         if (array_ndx != NULL)
677             return ReportActionNotArray(action->type, field);
678         if (!ExprResolveEnum(value, &rtrn, lockWhich))
679             return ReportMismatch(action->type, field, "lock or unlock");
680         act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
681         act->flags |= rtrn.ival;
682         return True;
683     }
684     else if (field == F_Count)
685     {
686         if (array_ndx != NULL)
687             return ReportActionNotArray(action->type, field);
688         if (!ExprResolveInteger
689             (value, &rtrn, SimpleLookup, (char *) btnNames))
690             return ReportMismatch(action->type, field, "integer");
691         if ((rtrn.ival < 0) || (rtrn.ival > 255))
692         {
693             ERROR("The count field must have a value in the range 0..255\n");
694             ACTION("Illegal count %d ignored\n", rtrn.ival);
695             return False;
696         }
697         act->count = rtrn.ival;
698         return True;
699     }
700     return ReportIllegal(action->type, field);
701 }
702
703 static LookupEntry ptrDflts[] = {
704     {"dfltbtn", XkbSA_AffectDfltBtn},
705     {"defaultbutton", XkbSA_AffectDfltBtn},
706     {"button", XkbSA_AffectDfltBtn},
707     {NULL, 0}
708 };
709
710 static Bool
711 HandleSetPtrDflt(XkbcDescPtr xkb,
712                  XkbAnyAction * action,
713                  unsigned field, ExprDef * array_ndx, ExprDef * value)
714 {
715     ExprResult rtrn;
716     XkbPtrDfltAction *act;
717
718     act = (XkbPtrDfltAction *) action;
719     if (field == F_Affect)
720     {
721         if (array_ndx != NULL)
722             return ReportActionNotArray(action->type, field);
723         if (!ExprResolveEnum(value, &rtrn, ptrDflts))
724             return ReportMismatch(action->type, field, "pointer component");
725         act->affect = rtrn.uval;
726         return True;
727     }
728     else if ((field == F_Button) || (field == F_Value))
729     {
730         ExprDef *btn;
731         if (array_ndx != NULL)
732             return ReportActionNotArray(action->type, field);
733         if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
734         {
735             act->flags &= ~XkbSA_DfltBtnAbsolute;
736             btn = value->value.child;
737         }
738         else
739         {
740             act->flags |= XkbSA_DfltBtnAbsolute;
741             btn = value;
742         }
743
744         if (!ExprResolveInteger
745             (btn, &rtrn, SimpleLookup, (char *) btnNames))
746             return ReportMismatch(action->type, field,
747                                   "integer (range 1..5)");
748         if ((rtrn.ival < 0) || (rtrn.ival > 5))
749         {
750             ERROR("New default button value must be in the range 1..5\n");
751             ACTION("Illegal default button value %d ignored\n", rtrn.ival);
752             return False;
753         }
754         if (rtrn.ival == 0)
755         {
756             ERROR("Cannot set default pointer button to \"default\"\n");
757             ACTION("Illegal default button setting ignored\n");
758             return False;
759         }
760         if (value->op == OpNegate)
761             XkbSASetPtrDfltValue(act, -rtrn.ival);
762         else
763             XkbSASetPtrDfltValue(act, rtrn.ival);
764         return True;
765     }
766     return ReportIllegal(action->type, field);
767 }
768
769 static LookupEntry isoNames[] = {
770     {"mods", XkbSA_ISONoAffectMods},
771     {"modifiers", XkbSA_ISONoAffectMods},
772     {"group", XkbSA_ISONoAffectGroup},
773     {"groups", XkbSA_ISONoAffectGroup},
774     {"ptr", XkbSA_ISONoAffectPtr},
775     {"pointer", XkbSA_ISONoAffectPtr},
776     {"ctrls", XkbSA_ISONoAffectCtrls},
777     {"controls", XkbSA_ISONoAffectCtrls},
778     {"all", ~((unsigned) 0)},
779     {"none", 0},
780     {NULL, 0},
781 };
782
783 static Bool
784 HandleISOLock(XkbcDescPtr xkb,
785               XkbAnyAction * action,
786               unsigned field, ExprDef * array_ndx, ExprDef * value)
787 {
788     ExprResult rtrn;
789     XkbcISOAction *act;
790     unsigned flags, mods;
791     int group;
792
793     act = (XkbcISOAction *) action;
794     switch (field)
795     {
796     case F_Modifiers:
797         if (array_ndx != NULL)
798             return ReportActionNotArray(action->type, field);
799         flags = act->flags;
800         if (CheckModifierField(xkb, action->type, value, &flags, &mods))
801         {
802             act->flags = flags & (~XkbSA_ISODfltIsGroup);
803             act->real_mods = mods & 0xff;
804             act->vmods = (mods >> 8) & 0xff;
805             return True;
806         }
807         return False;
808     case F_Group:
809         if (array_ndx != NULL)
810             return ReportActionNotArray(action->type, field);
811         flags = act->flags;
812         if (CheckGroupField(action->type, value, &flags, &group))
813         {
814             act->flags = flags | XkbSA_ISODfltIsGroup;
815             XkbSASetGroup(act, group);
816             return True;
817         }
818         return False;
819     case F_Affect:
820         if (array_ndx != NULL)
821             return ReportActionNotArray(action->type, field);
822         if (!ExprResolveMask(value, &rtrn, SimpleLookup, (char *) isoNames))
823             return ReportMismatch(action->type, field, "keyboard component");
824         act->affect = (~rtrn.uval) & XkbSA_ISOAffectMask;
825         return True;
826     }
827     return ReportIllegal(action->type, field);
828 }
829
830 static Bool
831 HandleSwitchScreen(XkbcDescPtr xkb,
832                    XkbAnyAction * action,
833                    unsigned field, ExprDef * array_ndx, ExprDef * value)
834 {
835     ExprResult rtrn;
836     XkbSwitchScreenAction *act;
837
838     act = (XkbSwitchScreenAction *) action;
839     if (field == F_Screen)
840     {
841         ExprDef *scrn;
842         if (array_ndx != NULL)
843             return ReportActionNotArray(action->type, field);
844         if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
845         {
846             act->flags &= ~XkbSA_SwitchAbsolute;
847             scrn = value->value.child;
848         }
849         else
850         {
851             act->flags |= XkbSA_SwitchAbsolute;
852             scrn = value;
853         }
854
855         if (!ExprResolveInteger(scrn, &rtrn, NULL, NULL))
856             return ReportMismatch(action->type, field, "integer (0..255)");
857         if ((rtrn.ival < 0) || (rtrn.ival > 255))
858         {
859             ERROR("Screen index must be in the range 1..255\n");
860             ACTION("Illegal screen value %d ignored\n", rtrn.ival);
861             return False;
862         }
863         if (value->op == OpNegate)
864             XkbSASetScreen(act, -rtrn.ival);
865         else
866             XkbSASetScreen(act, rtrn.ival);
867         return True;
868     }
869     else if (field == F_Same)
870     {
871         if (array_ndx != NULL)
872             return ReportActionNotArray(action->type, field);
873         if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
874             return ReportMismatch(action->type, field, "boolean");
875         if (rtrn.uval)
876             act->flags &= ~XkbSA_SwitchApplication;
877         else
878             act->flags |= XkbSA_SwitchApplication;
879         return True;
880     }
881     return ReportIllegal(action->type, field);
882 }
883
884 LookupEntry ctrlNames[] = {
885     {"repeatkeys", XkbRepeatKeysMask}
886     ,
887     {"repeat", XkbRepeatKeysMask}
888     ,
889     {"autorepeat", XkbRepeatKeysMask}
890     ,
891     {"slowkeys", XkbSlowKeysMask}
892     ,
893     {"bouncekeys", XkbBounceKeysMask}
894     ,
895     {"stickykeys", XkbStickyKeysMask}
896     ,
897     {"mousekeys", XkbMouseKeysMask}
898     ,
899     {"mousekeysaccel", XkbMouseKeysAccelMask}
900     ,
901     {"accessxkeys", XkbAccessXKeysMask}
902     ,
903     {"accessxtimeout", XkbAccessXTimeoutMask}
904     ,
905     {"accessxfeedback", XkbAccessXFeedbackMask}
906     ,
907     {"audiblebell", XkbAudibleBellMask}
908     ,
909     {"overlay1", XkbOverlay1Mask}
910     ,
911     {"overlay2", XkbOverlay2Mask}
912     ,
913     {"ignoregrouplock", XkbIgnoreGroupLockMask}
914     ,
915     {"all", XkbAllBooleanCtrlsMask}
916     ,
917     {"none", 0}
918     ,
919     {NULL, 0}
920 };
921
922 static Bool
923 HandleSetLockControls(XkbcDescPtr xkb,
924                       XkbAnyAction * action,
925                       unsigned field, ExprDef * array_ndx, ExprDef * value)
926 {
927     ExprResult rtrn;
928     XkbcCtrlsAction *act;
929
930     act = (XkbcCtrlsAction *) action;
931     if (field == F_Controls)
932     {
933         if (array_ndx != NULL)
934             return ReportActionNotArray(action->type, field);
935         if (!ExprResolveMask
936             (value, &rtrn, SimpleLookup, (char *) ctrlNames))
937             return ReportMismatch(action->type, field, "controls mask");
938         act->ctrls = rtrn.uval;
939         return True;
940     }
941     return ReportIllegal(action->type, field);
942 }
943
944 static LookupEntry evNames[] = {
945     {"press", XkbSA_MessageOnPress},
946     {"keypress", XkbSA_MessageOnPress},
947     {"release", XkbSA_MessageOnRelease},
948     {"keyrelease", XkbSA_MessageOnRelease},
949     {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease},
950     {"none", 0},
951     {NULL, 0}
952 };
953
954 static Bool
955 HandleActionMessage(XkbcDescPtr xkb,
956                     XkbAnyAction * action,
957                     unsigned field, ExprDef * array_ndx, ExprDef * value)
958 {
959     ExprResult rtrn;
960     XkbMessageAction *act;
961
962     act = (XkbMessageAction *) action;
963     switch (field)
964     {
965     case F_Report:
966         if (array_ndx != NULL)
967             return ReportActionNotArray(action->type, field);
968         if (!ExprResolveMask(value, &rtrn, SimpleLookup, (char *) evNames))
969             return ReportMismatch(action->type, field, "key event mask");
970         act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
971         act->flags =
972             rtrn.uval & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
973         return True;
974     case F_GenKeyEvent:
975         if (array_ndx != NULL)
976             return ReportActionNotArray(action->type, field);
977         if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
978             return ReportMismatch(action->type, field, "boolean");
979         if (rtrn.uval)
980             act->flags |= XkbSA_MessageGenKeyEvent;
981         else
982             act->flags &= ~XkbSA_MessageGenKeyEvent;
983         return True;
984     case F_Data:
985         if (array_ndx == NULL)
986         {
987             if (!ExprResolveString(value, &rtrn, NULL, NULL))
988                 return ReportMismatch(action->type, field, "string");
989             else
990             {
991                 int len = strlen(rtrn.str);
992                 if ((len < 1) || (len > 6))
993                 {
994                     WARN("An action message can hold only 6 bytes\n");
995                     ACTION("Extra %d bytes ignored\n", len - 6);
996                 }
997                 strncpy((char *) act->message, rtrn.str, 6);
998             }
999             return True;
1000         }
1001         else
1002         {
1003             unsigned ndx;
1004             if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1005             {
1006                 ERROR("Array subscript must be integer\n");
1007                 ACTION("Illegal subscript ignored\n");
1008                 return False;
1009             }
1010             ndx = rtrn.uval;
1011             if (ndx > 5)
1012             {
1013                 ERROR("An action message is at most 6 bytes long\n");
1014                 ACTION("Attempt to use data[%d] ignored\n", ndx);
1015                 return False;
1016             }
1017             if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1018                 return ReportMismatch(action->type, field, "integer");
1019             if ((rtrn.ival < 0) || (rtrn.ival > 255))
1020             {
1021                 ERROR("Message data must be in the range 0..255\n");
1022                 ACTION("Illegal datum %d ignored\n", rtrn.ival);
1023                 return False;
1024             }
1025             act->message[ndx] = rtrn.uval;
1026         }
1027         return True;
1028     }
1029     return ReportIllegal(action->type, field);
1030 }
1031
1032 static Bool
1033 HandleRedirectKey(XkbcDescPtr xkb,
1034                   XkbAnyAction * action,
1035                   unsigned field, ExprDef * array_ndx, ExprDef * value)
1036 {
1037     ExprResult rtrn;
1038     XkbcRedirectKeyAction *act;
1039     unsigned t1, t2;
1040     unsigned long tmp;
1041
1042     if (array_ndx != NULL)
1043         return ReportActionNotArray(action->type, field);
1044
1045     act = (XkbcRedirectKeyAction *) action;
1046     switch (field)
1047     {
1048     case F_Keycode:
1049         if (!ExprResolveKeyName(value, &rtrn, NULL, NULL))
1050             return ReportMismatch(action->type, field, "key name");
1051         tmp = KeyNameToLong(rtrn.keyName.name);
1052         if (!FindNamedKey(xkb, tmp, &t1, True, CreateKeyNames(xkb), 0))
1053         {
1054             return ReportNotFound(action->type, field, "Key",
1055                                   XkbcKeyNameText(rtrn.keyName.name));
1056         }
1057         act->new_key = t1;
1058         return True;
1059     case F_ModsToClear:
1060     case F_Modifiers:
1061         t1 = 0;
1062         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
1063         {
1064             act->mods_mask |= (t2 & 0xff);
1065             if (field == F_Modifiers)
1066                 act->mods |= (t2 & 0xff);
1067             else
1068                 act->mods &= ~(t2 & 0xff);
1069
1070             t2 = (t2 >> 8) & 0xffff;
1071             act->vmods_mask |= t2;
1072             if (field == F_Modifiers)
1073                 act->vmods |= t2;
1074             else
1075                 act->vmods &= ~t2;
1076             return True;
1077         }
1078         return True;
1079     }
1080     return ReportIllegal(action->type, field);
1081 }
1082
1083 static Bool
1084 HandleDeviceBtn(XkbcDescPtr xkb,
1085                 XkbAnyAction * action,
1086                 unsigned field, ExprDef * array_ndx, ExprDef * value)
1087 {
1088     ExprResult rtrn;
1089     XkbDeviceBtnAction *act;
1090
1091     act = (XkbDeviceBtnAction *) action;
1092     if (field == F_Button)
1093     {
1094         if (array_ndx != NULL)
1095             return ReportActionNotArray(action->type, field);
1096         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1097             return ReportMismatch(action->type, field,
1098                                   "integer (range 1..255)");
1099         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1100         {
1101             ERROR("Button must specify default or be in the range 1..255\n");
1102             ACTION("Illegal button value %d ignored\n", rtrn.ival);
1103             return False;
1104         }
1105         act->button = rtrn.ival;
1106         return True;
1107     }
1108     else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
1109     {
1110         if (array_ndx != NULL)
1111             return ReportActionNotArray(action->type, field);
1112         if (!ExprResolveEnum(value, &rtrn, lockWhich))
1113             return ReportMismatch(action->type, field, "lock or unlock");
1114         act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
1115         act->flags |= rtrn.ival;
1116         return True;
1117     }
1118     else if (field == F_Count)
1119     {
1120         if (array_ndx != NULL)
1121             return ReportActionNotArray(action->type, field);
1122         if (!ExprResolveInteger
1123             (value, &rtrn, SimpleLookup, (char *) btnNames))
1124             return ReportMismatch(action->type, field, "integer");
1125         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1126         {
1127             ERROR("The count field must have a value in the range 0..255\n");
1128             ACTION("Illegal count %d ignored\n", rtrn.ival);
1129             return False;
1130         }
1131         act->count = rtrn.ival;
1132         return True;
1133     }
1134     else if (field == F_Device)
1135     {
1136         if (array_ndx != NULL)
1137             return ReportActionNotArray(action->type, field);
1138         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1139             return ReportMismatch(action->type, field,
1140                                   "integer (range 1..255)");
1141         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1142         {
1143             ERROR("Device must specify default or be in the range 1..255\n");
1144             ACTION("Illegal device value %d ignored\n", rtrn.ival);
1145             return False;
1146         }
1147         act->device = rtrn.ival;
1148         return True;
1149     }
1150     return ReportIllegal(action->type, field);
1151 }
1152
1153 static Bool
1154 HandleDeviceValuator(XkbcDescPtr xkb,
1155                      XkbAnyAction * action,
1156                      unsigned field, ExprDef * array_ndx, ExprDef * value)
1157 {
1158 #if 0
1159     ExprResult rtrn;
1160     XkbDeviceValuatorAction *act;
1161
1162     act = (XkbDeviceValuatorAction *) action;
1163     /*  XXX - Not yet implemented */
1164 #endif
1165     return False;
1166 }
1167
1168 static Bool
1169 HandlePrivate(XkbcDescPtr xkb,
1170               XkbAnyAction * action,
1171               unsigned field, ExprDef * array_ndx, ExprDef * value)
1172 {
1173     ExprResult rtrn;
1174
1175     switch (field)
1176     {
1177     case F_Type:
1178         if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1179             return ReportMismatch(PrivateAction, field, "integer");
1180         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1181         {
1182             ERROR("Private action type must be in the range 0..255\n");
1183             ACTION("Illegal type %d ignored\n", rtrn.ival);
1184             return False;
1185         }
1186         action->type = rtrn.uval;
1187         return True;
1188     case F_Data:
1189         if (array_ndx == NULL)
1190         {
1191             if (!ExprResolveString(value, &rtrn, NULL, NULL))
1192                 return ReportMismatch(action->type, field, "string");
1193             else
1194             {
1195                 int len = strlen(rtrn.str);
1196                 if ((len < 1) || (len > 7))
1197                 {
1198                     WARN("A private action has 7 data bytes\n");
1199                     ACTION("Extra %d bytes ignored\n", len - 6);
1200                     return False;
1201                 }
1202                 strncpy((char *) action->data, rtrn.str, 7);
1203             }
1204             return True;
1205         }
1206         else
1207         {
1208             unsigned ndx;
1209             if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1210             {
1211                 ERROR("Array subscript must be integer\n");
1212                 ACTION("Illegal subscript ignored\n");
1213                 return False;
1214             }
1215             ndx = rtrn.uval;
1216             if (ndx > 6)
1217             {
1218                 ERROR("The data for a private action is 7 bytes long\n");
1219                 ACTION("Attempt to use data[%d] ignored\n", ndx);
1220                 return False;
1221             }
1222             if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1223                 return ReportMismatch(action->type, field, "integer");
1224             if ((rtrn.ival < 0) || (rtrn.ival > 255))
1225             {
1226                 ERROR("All data for a private action must be 0..255\n");
1227                 ACTION("Illegal datum %d ignored\n", rtrn.ival);
1228                 return False;
1229             }
1230             action->data[ndx] = rtrn.uval;
1231             return True;
1232         }
1233     }
1234     return ReportIllegal(PrivateAction, field);
1235 }
1236
1237 typedef Bool(*actionHandler) (XkbcDescPtr /* xkb */ ,
1238                               XkbAnyAction * /* action */ ,
1239                               unsigned /* field */ ,
1240                               ExprDef * /* array_ndx */ ,
1241                               ExprDef * /* value */
1242     );
1243
1244 static actionHandler handleAction[XkbSA_NumActions + 1] = {
1245     HandleNoAction /* NoAction     */ ,
1246     HandleSetLatchMods /* SetMods      */ ,
1247     HandleSetLatchMods /* LatchMods    */ ,
1248     HandleLockMods /* LockMods     */ ,
1249     HandleSetLatchGroup /* SetGroup     */ ,
1250     HandleSetLatchGroup /* LatchGroup   */ ,
1251     HandleLockGroup /* LockGroup    */ ,
1252     HandleMovePtr /* MovePtr      */ ,
1253     HandlePtrBtn /* PtrBtn       */ ,
1254     HandlePtrBtn /* LockPtrBtn   */ ,
1255     HandleSetPtrDflt /* SetPtrDflt   */ ,
1256     HandleISOLock /* ISOLock      */ ,
1257     HandleNoAction /* Terminate    */ ,
1258     HandleSwitchScreen /* SwitchScreen */ ,
1259     HandleSetLockControls /* SetControls  */ ,
1260     HandleSetLockControls /* LockControls */ ,
1261     HandleActionMessage /* ActionMessage */ ,
1262     HandleRedirectKey /* RedirectKey  */ ,
1263     HandleDeviceBtn /* DeviceBtn    */ ,
1264     HandleDeviceBtn /* LockDeviceBtn */ ,
1265     HandleDeviceValuator /* DeviceValuatr */ ,
1266     HandlePrivate               /* Private      */
1267 };
1268
1269 /***====================================================================***/
1270
1271 static void
1272 ApplyActionFactoryDefaults(XkbcAction * action)
1273 {
1274     if (action->type == XkbSA_SetPtrDflt)
1275     {                           /* increment default button */
1276         action->dflt.affect = XkbSA_AffectDfltBtn;
1277         action->dflt.flags = 0;
1278         XkbSASetPtrDfltValue(&action->dflt, 1);
1279     }
1280     else if (action->type == XkbSA_ISOLock)
1281     {
1282         action->iso.real_mods = LockMask;
1283     }
1284     return;
1285 }
1286
1287
1288 int
1289 HandleActionDef(ExprDef * def,
1290                 XkbcDescPtr xkb,
1291                 XkbAnyAction * action, unsigned mergeMode, ActionInfo * info)
1292 {
1293     ExprDef *arg;
1294     register char *str;
1295     unsigned tmp, hndlrType;
1296
1297     if (!actionsInitialized)
1298         ActionsInit();
1299
1300     if (def->op != ExprActionDecl)
1301     {
1302         ERROR("Expected an action definition, found %s\n",
1303                exprOpText(def->op));
1304         return False;
1305     }
1306     str = XkbcAtomGetString(def->value.action.name);
1307     if (!str)
1308     {
1309         WSGO("Missing name in action definition!!\n");
1310         return False;
1311     }
1312     if (!stringToAction(str, &tmp))
1313     {
1314         ERROR("Unknown action %s\n", str);
1315         return False;
1316     }
1317     action->type = hndlrType = tmp;
1318     if (action->type != XkbSA_NoAction)
1319     {
1320         ApplyActionFactoryDefaults((XkbcAction *) action);
1321         while (info)
1322         {
1323             if ((info->action == XkbSA_NoAction)
1324                 || (info->action == hndlrType))
1325             {
1326                 if (!(*handleAction[hndlrType]) (xkb, action,
1327                                                  info->field,
1328                                                  info->array_ndx,
1329                                                  info->value))
1330                 {
1331                     return False;
1332                 }
1333             }
1334             info = info->next;
1335         }
1336     }
1337     for (arg = def->value.action.args; arg != NULL;
1338          arg = (ExprDef *) arg->common.next)
1339     {
1340         ExprDef *field, *value, *arrayRtrn;
1341         ExprResult elemRtrn, fieldRtrn;
1342         unsigned fieldNdx;
1343
1344         if (arg->op == OpAssign)
1345         {
1346             field = arg->value.binary.left;
1347             value = arg->value.binary.right;
1348         }
1349         else
1350         {
1351             if ((arg->op == OpNot) || (arg->op == OpInvert))
1352             {
1353                 field = arg->value.child;
1354                 value = &constFalse;
1355             }
1356             else
1357             {
1358                 field = arg;
1359                 value = &constTrue;
1360             }
1361         }
1362         if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
1363             return False;       /* internal error -- already reported */
1364
1365         if (elemRtrn.str != NULL)
1366         {
1367             ERROR("Cannot change defaults in an action definition\n");
1368             ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str,
1369                     fieldRtrn.str);
1370             return False;
1371         }
1372         if (!stringToField(fieldRtrn.str, &fieldNdx))
1373         {
1374             ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str));
1375             return False;
1376         }
1377         if (!(*handleAction[hndlrType])
1378             (xkb, action, fieldNdx, arrayRtrn, value))
1379         {
1380             return False;
1381         }
1382     }
1383     return True;
1384 }
1385
1386 /***====================================================================***/
1387
1388 int
1389 SetActionField(XkbcDescPtr xkb,
1390                char *elem,
1391                char *field,
1392                ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
1393 {
1394     ActionInfo *new, *old;
1395
1396     if (!actionsInitialized)
1397         ActionsInit();
1398
1399     new = uTypedAlloc(ActionInfo);
1400     if (new == NULL)
1401     {
1402         WSGO("Couldn't allocate space for action default\n");
1403         return False;
1404     }
1405     if (uStrCaseCmp(elem, "action") == 0)
1406         new->action = XkbSA_NoAction;
1407     else
1408     {
1409         if (!stringToAction(elem, &new->action))
1410             return False;
1411         if (new->action == XkbSA_NoAction)
1412         {
1413             ERROR("\"%s\" is not a valid field in a NoAction action\n",
1414                    field);
1415             return False;
1416         }
1417     }
1418     if (!stringToField(field, &new->field))
1419     {
1420         ERROR("\"%s\" is not a legal field name\n", field);
1421         return False;
1422     }
1423     new->array_ndx = array_ndx;
1424     new->value = value;
1425     new->next = NULL;
1426     old = *info_rtrn;
1427     while ((old) && (old->next))
1428         old = old->next;
1429     if (old == NULL)
1430         *info_rtrn = new;
1431     else
1432         old->next = new;
1433     return True;
1434 }
1435
1436 /***====================================================================***/
1437
1438 void
1439 ActionsInit(void)
1440 {
1441     if (!actionsInitialized)
1442     {
1443         bzero((char *) &constTrue, sizeof(constTrue));
1444         bzero((char *) &constFalse, sizeof(constFalse));
1445         constTrue.common.stmtType = StmtExpr;
1446         constTrue.common.next = NULL;
1447         constTrue.op = ExprIdent;
1448         constTrue.type = TypeBoolean;
1449         constTrue.value.str = XkbcInternAtom("true", False);
1450         constFalse.common.stmtType = StmtExpr;
1451         constFalse.common.next = NULL;
1452         constFalse.op = ExprIdent;
1453         constFalse.type = TypeBoolean;
1454         constFalse.value.str = XkbcInternAtom("false", False);
1455         actionsInitialized = 1;
1456     }
1457     return;
1458 }