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