Remove field reference lookup support
[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))
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, 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))
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(value, &rtrn, ctrlNames))
912             return ReportMismatch(action->type, field, "controls mask");
913         act->ctrls = rtrn.uval;
914         return True;
915     }
916     return ReportIllegal(action->type, field);
917 }
918
919 static LookupEntry evNames[] = {
920     {"press", XkbSA_MessageOnPress},
921     {"keypress", XkbSA_MessageOnPress},
922     {"release", XkbSA_MessageOnRelease},
923     {"keyrelease", XkbSA_MessageOnRelease},
924     {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease},
925     {"none", 0},
926     {NULL, 0}
927 };
928
929 static Bool
930 HandleActionMessage(struct xkb_desc * xkb,
931                     struct xkb_any_action * action,
932                     unsigned field, ExprDef * array_ndx, ExprDef * value)
933 {
934     ExprResult rtrn;
935     struct xkb_message_action *act;
936
937     act = (struct xkb_message_action *) action;
938     switch (field)
939     {
940     case F_Report:
941         if (array_ndx != NULL)
942             return ReportActionNotArray(action->type, field);
943         if (!ExprResolveMask(value, &rtrn, evNames))
944             return ReportMismatch(action->type, field, "key event mask");
945         act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
946         act->flags =
947             rtrn.uval & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
948         return True;
949     case F_GenKeyEvent:
950         if (array_ndx != NULL)
951             return ReportActionNotArray(action->type, field);
952         if (!ExprResolveBoolean(value, &rtrn))
953             return ReportMismatch(action->type, field, "boolean");
954         if (rtrn.uval)
955             act->flags |= XkbSA_MessageGenKeyEvent;
956         else
957             act->flags &= ~XkbSA_MessageGenKeyEvent;
958         return True;
959     case F_Data:
960         if (array_ndx == NULL)
961         {
962             if (!ExprResolveString(value, &rtrn))
963                 return ReportMismatch(action->type, field, "string");
964             else
965             {
966                 int len = strlen(rtrn.str);
967                 if ((len < 1) || (len > 6))
968                 {
969                     WARN("An action message can hold only 6 bytes\n");
970                     ACTION("Extra %d bytes ignored\n", len - 6);
971                 }
972                 strncpy((char *) act->message, rtrn.str, 6);
973             }
974             return True;
975         }
976         else
977         {
978             unsigned ndx;
979             if (!ExprResolveInteger(array_ndx, &rtrn))
980             {
981                 ERROR("Array subscript must be integer\n");
982                 ACTION("Illegal subscript ignored\n");
983                 return False;
984             }
985             ndx = rtrn.uval;
986             if (ndx > 5)
987             {
988                 ERROR("An action message is at most 6 bytes long\n");
989                 ACTION("Attempt to use data[%d] ignored\n", ndx);
990                 return False;
991             }
992             if (!ExprResolveInteger(value, &rtrn))
993                 return ReportMismatch(action->type, field, "integer");
994             if ((rtrn.ival < 0) || (rtrn.ival > 255))
995             {
996                 ERROR("Message data must be in the range 0..255\n");
997                 ACTION("Illegal datum %d ignored\n", rtrn.ival);
998                 return False;
999             }
1000             act->message[ndx] = rtrn.uval;
1001         }
1002         return True;
1003     }
1004     return ReportIllegal(action->type, field);
1005 }
1006
1007 static Bool
1008 HandleRedirectKey(struct xkb_desc * xkb,
1009                   struct xkb_any_action * action,
1010                   unsigned field, ExprDef * array_ndx, ExprDef * value)
1011 {
1012     ExprResult rtrn;
1013     struct xkb_redirect_key_action *act;
1014     unsigned t1, t2;
1015     xkb_keycode_t kc;
1016     unsigned long tmp;
1017
1018     if (array_ndx != NULL)
1019         return ReportActionNotArray(action->type, field);
1020
1021     act = (struct xkb_redirect_key_action *) action;
1022     switch (field)
1023     {
1024     case F_Keycode:
1025         if (!ExprResolveKeyName(value, &rtrn))
1026             return ReportMismatch(action->type, field, "key name");
1027         tmp = KeyNameToLong(rtrn.keyName.name);
1028         if (!FindNamedKey(xkb, tmp, &kc, True, CreateKeyNames(xkb), 0))
1029         {
1030             return ReportNotFound(action->type, field, "Key",
1031                                   XkbcKeyNameText(rtrn.keyName.name));
1032         }
1033         act->new_key = kc;
1034         return True;
1035     case F_ModsToClear:
1036     case F_Modifiers:
1037         t1 = 0;
1038         if (CheckModifierField(xkb, action->type, value, &t1, &t2))
1039         {
1040             act->mods_mask |= (t2 & 0xff);
1041             if (field == F_Modifiers)
1042                 act->mods |= (t2 & 0xff);
1043             else
1044                 act->mods &= ~(t2 & 0xff);
1045
1046             t2 = (t2 >> 8) & 0xffff;
1047             act->vmods_mask |= t2;
1048             if (field == F_Modifiers)
1049                 act->vmods |= t2;
1050             else
1051                 act->vmods &= ~t2;
1052             return True;
1053         }
1054         return True;
1055     }
1056     return ReportIllegal(action->type, field);
1057 }
1058
1059 static Bool
1060 HandleDeviceBtn(struct xkb_desc * xkb,
1061                 struct xkb_any_action * action,
1062                 unsigned field, ExprDef * array_ndx, ExprDef * value)
1063 {
1064     ExprResult rtrn;
1065     struct xkb_device_button_action *act;
1066
1067     act = (struct xkb_device_button_action *) action;
1068     if (field == F_Button)
1069     {
1070         if (array_ndx != NULL)
1071             return ReportActionNotArray(action->type, field);
1072         if (!ExprResolveInteger(value, &rtrn))
1073             return ReportMismatch(action->type, field,
1074                                   "integer (range 1..255)");
1075         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1076         {
1077             ERROR("Button must specify default or be in the range 1..255\n");
1078             ACTION("Illegal button value %d ignored\n", rtrn.ival);
1079             return False;
1080         }
1081         act->button = rtrn.ival;
1082         return True;
1083     }
1084     else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
1085     {
1086         if (array_ndx != NULL)
1087             return ReportActionNotArray(action->type, field);
1088         if (!ExprResolveEnum(value, &rtrn, lockWhich))
1089             return ReportMismatch(action->type, field, "lock or unlock");
1090         act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
1091         act->flags |= rtrn.ival;
1092         return True;
1093     }
1094     else if (field == F_Count)
1095     {
1096         if (array_ndx != NULL)
1097             return ReportActionNotArray(action->type, field);
1098         if (!ExprResolveButton(value, &rtrn))
1099             return ReportMismatch(action->type, field, "integer");
1100         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1101         {
1102             ERROR("The count field must have a value in the range 0..255\n");
1103             ACTION("Illegal count %d ignored\n", rtrn.ival);
1104             return False;
1105         }
1106         act->count = rtrn.ival;
1107         return True;
1108     }
1109     else if (field == F_Device)
1110     {
1111         if (array_ndx != NULL)
1112             return ReportActionNotArray(action->type, field);
1113         if (!ExprResolveInteger(value, &rtrn))
1114             return ReportMismatch(action->type, field,
1115                                   "integer (range 1..255)");
1116         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1117         {
1118             ERROR("Device must specify default or be in the range 1..255\n");
1119             ACTION("Illegal device value %d ignored\n", rtrn.ival);
1120             return False;
1121         }
1122         act->device = rtrn.ival;
1123         return True;
1124     }
1125     return ReportIllegal(action->type, field);
1126 }
1127
1128 static Bool
1129 HandleDeviceValuator(struct xkb_desc * xkb,
1130                      struct xkb_any_action * action,
1131                      unsigned field, ExprDef * array_ndx, ExprDef * value)
1132 {
1133 #if 0
1134     ExprResult rtrn;
1135     struct xkb_device_valuator_action *act;
1136
1137     act = (struct xkb_device_valuator_action *) action;
1138     /*  XXX - Not yet implemented */
1139 #endif
1140     return False;
1141 }
1142
1143 static Bool
1144 HandlePrivate(struct xkb_desc * xkb,
1145               struct xkb_any_action * action,
1146               unsigned field, ExprDef * array_ndx, ExprDef * value)
1147 {
1148     ExprResult rtrn;
1149
1150     switch (field)
1151     {
1152     case F_Type:
1153         if (!ExprResolveInteger(value, &rtrn))
1154             return ReportMismatch(PrivateAction, field, "integer");
1155         if ((rtrn.ival < 0) || (rtrn.ival > 255))
1156         {
1157             ERROR("Private action type must be in the range 0..255\n");
1158             ACTION("Illegal type %d ignored\n", rtrn.ival);
1159             return False;
1160         }
1161         action->type = rtrn.uval;
1162         return True;
1163     case F_Data:
1164         if (array_ndx == NULL)
1165         {
1166             if (!ExprResolveString(value, &rtrn))
1167                 return ReportMismatch(action->type, field, "string");
1168             else
1169             {
1170                 int len = strlen(rtrn.str);
1171                 if ((len < 1) || (len > 7))
1172                 {
1173                     WARN("A private action has 7 data bytes\n");
1174                     ACTION("Extra %d bytes ignored\n", len - 6);
1175                     return False;
1176                 }
1177                 strncpy((char *) action->data, rtrn.str, sizeof action->data);
1178             }
1179             free(rtrn.str);
1180             return True;
1181         }
1182         else
1183         {
1184             unsigned ndx;
1185             if (!ExprResolveInteger(array_ndx, &rtrn))
1186             {
1187                 ERROR("Array subscript must be integer\n");
1188                 ACTION("Illegal subscript ignored\n");
1189                 return False;
1190             }
1191             ndx = rtrn.uval;
1192             if (ndx >= sizeof action->data)
1193             {
1194                 ERROR("The data for a private action is 18 bytes long\n");
1195                 ACTION("Attempt to use data[%d] ignored\n", ndx);
1196                 return False;
1197             }
1198             if (!ExprResolveInteger(value, &rtrn))
1199                 return ReportMismatch(action->type, field, "integer");
1200             if ((rtrn.ival < 0) || (rtrn.ival > 255))
1201             {
1202                 ERROR("All data for a private action must be 0..255\n");
1203                 ACTION("Illegal datum %d ignored\n", rtrn.ival);
1204                 return False;
1205             }
1206             action->data[ndx] = rtrn.uval;
1207             return True;
1208         }
1209     }
1210     return ReportIllegal(PrivateAction, field);
1211 }
1212
1213 typedef Bool(*actionHandler) (struct xkb_desc * /* xkb */ ,
1214                               struct xkb_any_action * /* action */ ,
1215                               unsigned /* field */ ,
1216                               ExprDef * /* array_ndx */ ,
1217                               ExprDef * /* value */
1218     );
1219
1220 static actionHandler handleAction[XkbSA_NumActions + 1] = {
1221     HandleNoAction /* NoAction     */ ,
1222     HandleSetLatchMods /* SetMods      */ ,
1223     HandleSetLatchMods /* LatchMods    */ ,
1224     HandleLockMods /* LockMods     */ ,
1225     HandleSetLatchGroup /* SetGroup     */ ,
1226     HandleSetLatchGroup /* LatchGroup   */ ,
1227     HandleLockGroup /* LockGroup    */ ,
1228     HandleMovePtr /* MovePtr      */ ,
1229     HandlePtrBtn /* PtrBtn       */ ,
1230     HandlePtrBtn /* LockPtrBtn   */ ,
1231     HandleSetPtrDflt /* SetPtrDflt   */ ,
1232     HandleISOLock /* ISOLock      */ ,
1233     HandleNoAction /* Terminate    */ ,
1234     HandleSwitchScreen /* SwitchScreen */ ,
1235     HandleSetLockControls /* SetControls  */ ,
1236     HandleSetLockControls /* LockControls */ ,
1237     HandleActionMessage /* ActionMessage */ ,
1238     HandleRedirectKey /* RedirectKey  */ ,
1239     HandleDeviceBtn /* DeviceBtn    */ ,
1240     HandleDeviceBtn /* LockDeviceBtn */ ,
1241     HandleDeviceValuator /* DeviceValuatr */ ,
1242     HandlePrivate               /* Private      */
1243 };
1244
1245 /***====================================================================***/
1246
1247 static void
1248 ApplyActionFactoryDefaults(union xkb_action * action)
1249 {
1250     if (action->type == XkbSA_SetPtrDflt)
1251     {                           /* increment default button */
1252         action->dflt.affect = XkbSA_AffectDfltBtn;
1253         action->dflt.flags = 0;
1254         action->dflt.value = 1;
1255     }
1256     else if (action->type == XkbSA_ISOLock)
1257     {
1258         action->iso.real_mods = LockMask;
1259     }
1260     return;
1261 }
1262
1263 static void
1264 ActionsInit(void);
1265
1266 int
1267 HandleActionDef(ExprDef * def,
1268                 struct xkb_desc * xkb,
1269                 struct xkb_any_action * action, unsigned mergeMode, ActionInfo * info)
1270 {
1271     ExprDef *arg;
1272     const char *str;
1273     unsigned tmp, hndlrType;
1274
1275     if (!actionsInitialized)
1276         ActionsInit();
1277
1278     if (def->op != ExprActionDecl)
1279     {
1280         ERROR("Expected an action definition, found %s\n",
1281                exprOpText(def->op));
1282         return False;
1283     }
1284     str = XkbcAtomText(def->value.action.name);
1285     if (!str)
1286     {
1287         WSGO("Missing name in action definition!!\n");
1288         return False;
1289     }
1290     if (!stringToAction(str, &tmp))
1291     {
1292         ERROR("Unknown action %s\n", str);
1293         return False;
1294     }
1295     action->type = hndlrType = tmp;
1296     if (action->type != XkbSA_NoAction)
1297     {
1298         ApplyActionFactoryDefaults((union xkb_action *) action);
1299         while (info)
1300         {
1301             if ((info->action == XkbSA_NoAction)
1302                 || (info->action == hndlrType))
1303             {
1304                 if (!(*handleAction[hndlrType]) (xkb, action,
1305                                                  info->field,
1306                                                  info->array_ndx,
1307                                                  info->value))
1308                 {
1309                     return False;
1310                 }
1311             }
1312             info = info->next;
1313         }
1314     }
1315     for (arg = def->value.action.args; arg != NULL;
1316          arg = (ExprDef *) arg->common.next)
1317     {
1318         ExprDef *field, *value, *arrayRtrn;
1319         ExprResult elemRtrn, fieldRtrn;
1320         unsigned fieldNdx;
1321
1322         if (arg->op == OpAssign)
1323         {
1324             field = arg->value.binary.left;
1325             value = arg->value.binary.right;
1326         }
1327         else
1328         {
1329             if ((arg->op == OpNot) || (arg->op == OpInvert))
1330             {
1331                 field = arg->value.child;
1332                 value = &constFalse;
1333             }
1334             else
1335             {
1336                 field = arg;
1337                 value = &constTrue;
1338             }
1339         }
1340         if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
1341             return False;       /* internal error -- already reported */
1342
1343         if (elemRtrn.str != NULL)
1344         {
1345             ERROR("Cannot change defaults in an action definition\n");
1346             ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str,
1347                     fieldRtrn.str);
1348             free(elemRtrn.str);
1349             free(fieldRtrn.str);
1350             return False;
1351         }
1352         if (!stringToField(fieldRtrn.str, &fieldNdx))
1353         {
1354             ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str));
1355             free(elemRtrn.str);
1356             free(fieldRtrn.str);
1357             return False;
1358         }
1359         free(elemRtrn.str);
1360         free(fieldRtrn.str);
1361         if (!(*handleAction[hndlrType])
1362             (xkb, action, fieldNdx, arrayRtrn, value))
1363         {
1364             return False;
1365         }
1366     }
1367     return True;
1368 }
1369
1370 /***====================================================================***/
1371
1372 int
1373 SetActionField(struct xkb_desc * xkb,
1374                char *elem,
1375                char *field,
1376                ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
1377 {
1378     ActionInfo *new, *old;
1379
1380     if (!actionsInitialized)
1381         ActionsInit();
1382
1383     new = uTypedAlloc(ActionInfo);
1384     if (new == NULL)
1385     {
1386         WSGO("Couldn't allocate space for action default\n");
1387         return False;
1388     }
1389     if (uStrCaseCmp(elem, "action") == 0)
1390         new->action = XkbSA_NoAction;
1391     else
1392     {
1393         if (!stringToAction(elem, &new->action))
1394         {
1395             free(new);
1396             return False;
1397         }
1398         if (new->action == XkbSA_NoAction)
1399         {
1400             ERROR("\"%s\" is not a valid field in a NoAction action\n",
1401                    field);
1402             free(new);
1403             return False;
1404         }
1405     }
1406     if (!stringToField(field, &new->field))
1407     {
1408         ERROR("\"%s\" is not a legal field name\n", field);
1409         free(new);
1410         return False;
1411     }
1412     new->array_ndx = array_ndx;
1413     new->value = value;
1414     new->next = NULL;
1415     old = *info_rtrn;
1416     while ((old) && (old->next))
1417         old = old->next;
1418     if (old == NULL)
1419         *info_rtrn = new;
1420     else
1421         old->next = new;
1422     return True;
1423 }
1424
1425 /***====================================================================***/
1426
1427 static void
1428 ActionsInit(void)
1429 {
1430     if (!actionsInitialized)
1431     {
1432         bzero((char *) &constTrue, sizeof(constTrue));
1433         bzero((char *) &constFalse, sizeof(constFalse));
1434         constTrue.common.stmtType = StmtExpr;
1435         constTrue.common.next = NULL;
1436         constTrue.op = ExprIdent;
1437         constTrue.type = TypeBoolean;
1438         constTrue.value.str = xkb_intern_atom("true");
1439         constFalse.common.stmtType = StmtExpr;
1440         constFalse.common.next = NULL;
1441         constFalse.op = ExprIdent;
1442         constFalse.type = TypeBoolean;
1443         constFalse.value.str = xkb_intern_atom("false");
1444         actionsInitialized = 1;
1445     }
1446     return;
1447 }