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