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