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