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