xref: /aosp_15_r20/external/libxkbcommon/src/xkbcomp/keycodes.c (revision 2b949d0487e80d67f1fda82db69e101e761f8064)
1*2b949d04SAndroid Build Coastguard Worker /************************************************************
2*2b949d04SAndroid Build Coastguard Worker  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3*2b949d04SAndroid Build Coastguard Worker  *
4*2b949d04SAndroid Build Coastguard Worker  * Permission to use, copy, modify, and distribute this
5*2b949d04SAndroid Build Coastguard Worker  * software and its documentation for any purpose and without
6*2b949d04SAndroid Build Coastguard Worker  * fee is hereby granted, provided that the above copyright
7*2b949d04SAndroid Build Coastguard Worker  * notice appear in all copies and that both that copyright
8*2b949d04SAndroid Build Coastguard Worker  * notice and this permission notice appear in supporting
9*2b949d04SAndroid Build Coastguard Worker  * documentation, and that the name of Silicon Graphics not be
10*2b949d04SAndroid Build Coastguard Worker  * used in advertising or publicity pertaining to distribution
11*2b949d04SAndroid Build Coastguard Worker  * of the software without specific prior written permission.
12*2b949d04SAndroid Build Coastguard Worker  * Silicon Graphics makes no representation about the suitability
13*2b949d04SAndroid Build Coastguard Worker  * of this software for any purpose. It is provided "as is"
14*2b949d04SAndroid Build Coastguard Worker  * without any express or implied warranty.
15*2b949d04SAndroid Build Coastguard Worker  *
16*2b949d04SAndroid Build Coastguard Worker  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17*2b949d04SAndroid Build Coastguard Worker  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18*2b949d04SAndroid Build Coastguard Worker  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19*2b949d04SAndroid Build Coastguard Worker  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20*2b949d04SAndroid Build Coastguard Worker  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21*2b949d04SAndroid Build Coastguard Worker  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22*2b949d04SAndroid Build Coastguard Worker  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23*2b949d04SAndroid Build Coastguard Worker  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24*2b949d04SAndroid Build Coastguard Worker  *
25*2b949d04SAndroid Build Coastguard Worker  ********************************************************/
26*2b949d04SAndroid Build Coastguard Worker 
27*2b949d04SAndroid Build Coastguard Worker #include "config.h"
28*2b949d04SAndroid Build Coastguard Worker 
29*2b949d04SAndroid Build Coastguard Worker #include "xkbcomp-priv.h"
30*2b949d04SAndroid Build Coastguard Worker #include "text.h"
31*2b949d04SAndroid Build Coastguard Worker #include "expr.h"
32*2b949d04SAndroid Build Coastguard Worker #include "include.h"
33*2b949d04SAndroid Build Coastguard Worker 
34*2b949d04SAndroid Build Coastguard Worker typedef struct {
35*2b949d04SAndroid Build Coastguard Worker     enum merge_mode merge;
36*2b949d04SAndroid Build Coastguard Worker 
37*2b949d04SAndroid Build Coastguard Worker     xkb_atom_t alias;
38*2b949d04SAndroid Build Coastguard Worker     xkb_atom_t real;
39*2b949d04SAndroid Build Coastguard Worker } AliasInfo;
40*2b949d04SAndroid Build Coastguard Worker 
41*2b949d04SAndroid Build Coastguard Worker typedef struct {
42*2b949d04SAndroid Build Coastguard Worker     enum merge_mode merge;
43*2b949d04SAndroid Build Coastguard Worker 
44*2b949d04SAndroid Build Coastguard Worker     xkb_atom_t name;
45*2b949d04SAndroid Build Coastguard Worker } LedNameInfo;
46*2b949d04SAndroid Build Coastguard Worker 
47*2b949d04SAndroid Build Coastguard Worker typedef struct {
48*2b949d04SAndroid Build Coastguard Worker     char *name;
49*2b949d04SAndroid Build Coastguard Worker     int errorCount;
50*2b949d04SAndroid Build Coastguard Worker 
51*2b949d04SAndroid Build Coastguard Worker     xkb_keycode_t min_key_code;
52*2b949d04SAndroid Build Coastguard Worker     xkb_keycode_t max_key_code;
53*2b949d04SAndroid Build Coastguard Worker     darray(xkb_atom_t) key_names;
54*2b949d04SAndroid Build Coastguard Worker     LedNameInfo led_names[XKB_MAX_LEDS];
55*2b949d04SAndroid Build Coastguard Worker     unsigned int num_led_names;
56*2b949d04SAndroid Build Coastguard Worker     darray(AliasInfo) aliases;
57*2b949d04SAndroid Build Coastguard Worker 
58*2b949d04SAndroid Build Coastguard Worker     struct xkb_context *ctx;
59*2b949d04SAndroid Build Coastguard Worker } KeyNamesInfo;
60*2b949d04SAndroid Build Coastguard Worker 
61*2b949d04SAndroid Build Coastguard Worker /***====================================================================***/
62*2b949d04SAndroid Build Coastguard Worker 
63*2b949d04SAndroid Build Coastguard Worker static void
InitAliasInfo(AliasInfo * info,enum merge_mode merge,xkb_atom_t alias,xkb_atom_t real)64*2b949d04SAndroid Build Coastguard Worker InitAliasInfo(AliasInfo *info, enum merge_mode merge,
65*2b949d04SAndroid Build Coastguard Worker               xkb_atom_t alias, xkb_atom_t real)
66*2b949d04SAndroid Build Coastguard Worker {
67*2b949d04SAndroid Build Coastguard Worker     memset(info, 0, sizeof(*info));
68*2b949d04SAndroid Build Coastguard Worker     info->merge = merge;
69*2b949d04SAndroid Build Coastguard Worker     info->alias = alias;
70*2b949d04SAndroid Build Coastguard Worker     info->real = real;
71*2b949d04SAndroid Build Coastguard Worker }
72*2b949d04SAndroid Build Coastguard Worker 
73*2b949d04SAndroid Build Coastguard Worker static LedNameInfo *
FindLedByName(KeyNamesInfo * info,xkb_atom_t name,xkb_led_index_t * idx_out)74*2b949d04SAndroid Build Coastguard Worker FindLedByName(KeyNamesInfo *info, xkb_atom_t name,
75*2b949d04SAndroid Build Coastguard Worker               xkb_led_index_t *idx_out)
76*2b949d04SAndroid Build Coastguard Worker {
77*2b949d04SAndroid Build Coastguard Worker     for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) {
78*2b949d04SAndroid Build Coastguard Worker         LedNameInfo *ledi = &info->led_names[idx];
79*2b949d04SAndroid Build Coastguard Worker         if (ledi->name == name) {
80*2b949d04SAndroid Build Coastguard Worker             *idx_out = idx;
81*2b949d04SAndroid Build Coastguard Worker             return ledi;
82*2b949d04SAndroid Build Coastguard Worker         }
83*2b949d04SAndroid Build Coastguard Worker     }
84*2b949d04SAndroid Build Coastguard Worker 
85*2b949d04SAndroid Build Coastguard Worker     return NULL;
86*2b949d04SAndroid Build Coastguard Worker }
87*2b949d04SAndroid Build Coastguard Worker 
88*2b949d04SAndroid Build Coastguard Worker static bool
AddLedName(KeyNamesInfo * info,enum merge_mode merge,bool same_file,LedNameInfo * new,xkb_led_index_t new_idx)89*2b949d04SAndroid Build Coastguard Worker AddLedName(KeyNamesInfo *info, enum merge_mode merge, bool same_file,
90*2b949d04SAndroid Build Coastguard Worker            LedNameInfo *new, xkb_led_index_t new_idx)
91*2b949d04SAndroid Build Coastguard Worker {
92*2b949d04SAndroid Build Coastguard Worker     xkb_led_index_t old_idx;
93*2b949d04SAndroid Build Coastguard Worker     LedNameInfo *old;
94*2b949d04SAndroid Build Coastguard Worker     const int verbosity = xkb_context_get_log_verbosity(info->ctx);
95*2b949d04SAndroid Build Coastguard Worker     const bool report = (same_file && verbosity > 0) || verbosity > 9;
96*2b949d04SAndroid Build Coastguard Worker     const bool replace = (merge == MERGE_REPLACE || merge == MERGE_OVERRIDE);
97*2b949d04SAndroid Build Coastguard Worker 
98*2b949d04SAndroid Build Coastguard Worker     /* LED with the same name already exists. */
99*2b949d04SAndroid Build Coastguard Worker     old = FindLedByName(info, new->name, &old_idx);
100*2b949d04SAndroid Build Coastguard Worker     if (old) {
101*2b949d04SAndroid Build Coastguard Worker         if (old_idx == new_idx) {
102*2b949d04SAndroid Build Coastguard Worker             log_warn(info->ctx,
103*2b949d04SAndroid Build Coastguard Worker                      "Multiple indicators named \"%s\"; "
104*2b949d04SAndroid Build Coastguard Worker                      "Identical definitions ignored\n",
105*2b949d04SAndroid Build Coastguard Worker                      xkb_atom_text(info->ctx, new->name));
106*2b949d04SAndroid Build Coastguard Worker             return true;
107*2b949d04SAndroid Build Coastguard Worker         }
108*2b949d04SAndroid Build Coastguard Worker 
109*2b949d04SAndroid Build Coastguard Worker         if (report) {
110*2b949d04SAndroid Build Coastguard Worker             xkb_led_index_t use = (replace ? new_idx + 1 : old_idx + 1);
111*2b949d04SAndroid Build Coastguard Worker             xkb_led_index_t ignore = (replace ? old_idx + 1 : new_idx + 1);
112*2b949d04SAndroid Build Coastguard Worker             log_warn(info->ctx,
113*2b949d04SAndroid Build Coastguard Worker                      "Multiple indicators named %s; Using %d, ignoring %d\n",
114*2b949d04SAndroid Build Coastguard Worker                      xkb_atom_text(info->ctx, new->name), use, ignore);
115*2b949d04SAndroid Build Coastguard Worker         }
116*2b949d04SAndroid Build Coastguard Worker 
117*2b949d04SAndroid Build Coastguard Worker         if (replace)
118*2b949d04SAndroid Build Coastguard Worker             *old = *new;
119*2b949d04SAndroid Build Coastguard Worker 
120*2b949d04SAndroid Build Coastguard Worker         return true;
121*2b949d04SAndroid Build Coastguard Worker     }
122*2b949d04SAndroid Build Coastguard Worker 
123*2b949d04SAndroid Build Coastguard Worker     if (new_idx >= info->num_led_names)
124*2b949d04SAndroid Build Coastguard Worker         info->num_led_names = new_idx + 1;
125*2b949d04SAndroid Build Coastguard Worker 
126*2b949d04SAndroid Build Coastguard Worker     /* LED with the same index already exists. */
127*2b949d04SAndroid Build Coastguard Worker     old = &info->led_names[new_idx];
128*2b949d04SAndroid Build Coastguard Worker     if (old->name != XKB_ATOM_NONE) {
129*2b949d04SAndroid Build Coastguard Worker         if (report) {
130*2b949d04SAndroid Build Coastguard Worker             const xkb_atom_t use = (replace ? new->name : old->name);
131*2b949d04SAndroid Build Coastguard Worker             const xkb_atom_t ignore = (replace ? old->name : new->name);
132*2b949d04SAndroid Build Coastguard Worker             log_warn(info->ctx, "Multiple names for indicator %d; "
133*2b949d04SAndroid Build Coastguard Worker                      "Using %s, ignoring %s\n", new_idx + 1,
134*2b949d04SAndroid Build Coastguard Worker                      xkb_atom_text(info->ctx, use),
135*2b949d04SAndroid Build Coastguard Worker                      xkb_atom_text(info->ctx, ignore));
136*2b949d04SAndroid Build Coastguard Worker         }
137*2b949d04SAndroid Build Coastguard Worker 
138*2b949d04SAndroid Build Coastguard Worker         if (replace)
139*2b949d04SAndroid Build Coastguard Worker             *old = *new;
140*2b949d04SAndroid Build Coastguard Worker 
141*2b949d04SAndroid Build Coastguard Worker         return true;
142*2b949d04SAndroid Build Coastguard Worker     }
143*2b949d04SAndroid Build Coastguard Worker 
144*2b949d04SAndroid Build Coastguard Worker     *old = *new;
145*2b949d04SAndroid Build Coastguard Worker     return true;
146*2b949d04SAndroid Build Coastguard Worker }
147*2b949d04SAndroid Build Coastguard Worker 
148*2b949d04SAndroid Build Coastguard Worker static void
ClearKeyNamesInfo(KeyNamesInfo * info)149*2b949d04SAndroid Build Coastguard Worker ClearKeyNamesInfo(KeyNamesInfo *info)
150*2b949d04SAndroid Build Coastguard Worker {
151*2b949d04SAndroid Build Coastguard Worker     free(info->name);
152*2b949d04SAndroid Build Coastguard Worker     darray_free(info->key_names);
153*2b949d04SAndroid Build Coastguard Worker     darray_free(info->aliases);
154*2b949d04SAndroid Build Coastguard Worker }
155*2b949d04SAndroid Build Coastguard Worker 
156*2b949d04SAndroid Build Coastguard Worker static void
InitKeyNamesInfo(KeyNamesInfo * info,struct xkb_context * ctx)157*2b949d04SAndroid Build Coastguard Worker InitKeyNamesInfo(KeyNamesInfo *info, struct xkb_context *ctx)
158*2b949d04SAndroid Build Coastguard Worker {
159*2b949d04SAndroid Build Coastguard Worker     memset(info, 0, sizeof(*info));
160*2b949d04SAndroid Build Coastguard Worker     info->ctx = ctx;
161*2b949d04SAndroid Build Coastguard Worker     info->min_key_code = XKB_KEYCODE_INVALID;
162*2b949d04SAndroid Build Coastguard Worker #if XKB_KEYCODE_INVALID < XKB_KEYCODE_MAX
163*2b949d04SAndroid Build Coastguard Worker #error "Hey, you can't be changing stuff like that."
164*2b949d04SAndroid Build Coastguard Worker #endif
165*2b949d04SAndroid Build Coastguard Worker }
166*2b949d04SAndroid Build Coastguard Worker 
167*2b949d04SAndroid Build Coastguard Worker static xkb_keycode_t
FindKeyByName(KeyNamesInfo * info,xkb_atom_t name)168*2b949d04SAndroid Build Coastguard Worker FindKeyByName(KeyNamesInfo *info, xkb_atom_t name)
169*2b949d04SAndroid Build Coastguard Worker {
170*2b949d04SAndroid Build Coastguard Worker     xkb_keycode_t i;
171*2b949d04SAndroid Build Coastguard Worker 
172*2b949d04SAndroid Build Coastguard Worker     for (i = info->min_key_code; i <= info->max_key_code; i++)
173*2b949d04SAndroid Build Coastguard Worker         if (darray_item(info->key_names, i) == name)
174*2b949d04SAndroid Build Coastguard Worker             return i;
175*2b949d04SAndroid Build Coastguard Worker 
176*2b949d04SAndroid Build Coastguard Worker     return XKB_KEYCODE_INVALID;
177*2b949d04SAndroid Build Coastguard Worker }
178*2b949d04SAndroid Build Coastguard Worker 
179*2b949d04SAndroid Build Coastguard Worker static bool
AddKeyName(KeyNamesInfo * info,xkb_keycode_t kc,xkb_atom_t name,enum merge_mode merge,bool same_file,bool report)180*2b949d04SAndroid Build Coastguard Worker AddKeyName(KeyNamesInfo *info, xkb_keycode_t kc, xkb_atom_t name,
181*2b949d04SAndroid Build Coastguard Worker            enum merge_mode merge, bool same_file, bool report)
182*2b949d04SAndroid Build Coastguard Worker {
183*2b949d04SAndroid Build Coastguard Worker     xkb_atom_t old_name;
184*2b949d04SAndroid Build Coastguard Worker     xkb_keycode_t old_kc;
185*2b949d04SAndroid Build Coastguard Worker     const int verbosity = xkb_context_get_log_verbosity(info->ctx);
186*2b949d04SAndroid Build Coastguard Worker 
187*2b949d04SAndroid Build Coastguard Worker     report = report && ((same_file && verbosity > 0) || verbosity > 7);
188*2b949d04SAndroid Build Coastguard Worker 
189*2b949d04SAndroid Build Coastguard Worker     if (kc >= darray_size(info->key_names))
190*2b949d04SAndroid Build Coastguard Worker         darray_resize0(info->key_names, kc + 1);
191*2b949d04SAndroid Build Coastguard Worker 
192*2b949d04SAndroid Build Coastguard Worker     info->min_key_code = MIN(info->min_key_code, kc);
193*2b949d04SAndroid Build Coastguard Worker     info->max_key_code = MAX(info->max_key_code, kc);
194*2b949d04SAndroid Build Coastguard Worker 
195*2b949d04SAndroid Build Coastguard Worker     /* There's already a key with this keycode. */
196*2b949d04SAndroid Build Coastguard Worker     old_name = darray_item(info->key_names, kc);
197*2b949d04SAndroid Build Coastguard Worker     if (old_name != XKB_ATOM_NONE) {
198*2b949d04SAndroid Build Coastguard Worker         const char *lname = KeyNameText(info->ctx, old_name);
199*2b949d04SAndroid Build Coastguard Worker         const char *kname = KeyNameText(info->ctx, name);
200*2b949d04SAndroid Build Coastguard Worker 
201*2b949d04SAndroid Build Coastguard Worker         if (old_name == name) {
202*2b949d04SAndroid Build Coastguard Worker             if (report)
203*2b949d04SAndroid Build Coastguard Worker                 log_warn(info->ctx,
204*2b949d04SAndroid Build Coastguard Worker                          "Multiple identical key name definitions; "
205*2b949d04SAndroid Build Coastguard Worker                          "Later occurrences of \"%s = %d\" ignored\n",
206*2b949d04SAndroid Build Coastguard Worker                          lname, kc);
207*2b949d04SAndroid Build Coastguard Worker             return true;
208*2b949d04SAndroid Build Coastguard Worker         }
209*2b949d04SAndroid Build Coastguard Worker         else if (merge == MERGE_AUGMENT) {
210*2b949d04SAndroid Build Coastguard Worker             if (report)
211*2b949d04SAndroid Build Coastguard Worker                 log_warn(info->ctx,
212*2b949d04SAndroid Build Coastguard Worker                          "Multiple names for keycode %d; "
213*2b949d04SAndroid Build Coastguard Worker                          "Using %s, ignoring %s\n", kc, lname, kname);
214*2b949d04SAndroid Build Coastguard Worker             return true;
215*2b949d04SAndroid Build Coastguard Worker         }
216*2b949d04SAndroid Build Coastguard Worker         else {
217*2b949d04SAndroid Build Coastguard Worker             if (report)
218*2b949d04SAndroid Build Coastguard Worker                 log_warn(info->ctx,
219*2b949d04SAndroid Build Coastguard Worker                          "Multiple names for keycode %d; "
220*2b949d04SAndroid Build Coastguard Worker                          "Using %s, ignoring %s\n", kc, kname, lname);
221*2b949d04SAndroid Build Coastguard Worker             darray_item(info->key_names, kc) = XKB_ATOM_NONE;
222*2b949d04SAndroid Build Coastguard Worker         }
223*2b949d04SAndroid Build Coastguard Worker     }
224*2b949d04SAndroid Build Coastguard Worker 
225*2b949d04SAndroid Build Coastguard Worker     /* There's already a key with this name. */
226*2b949d04SAndroid Build Coastguard Worker     old_kc = FindKeyByName(info, name);
227*2b949d04SAndroid Build Coastguard Worker     if (old_kc != XKB_KEYCODE_INVALID && old_kc != kc) {
228*2b949d04SAndroid Build Coastguard Worker         const char *kname = KeyNameText(info->ctx, name);
229*2b949d04SAndroid Build Coastguard Worker 
230*2b949d04SAndroid Build Coastguard Worker         if (merge == MERGE_OVERRIDE) {
231*2b949d04SAndroid Build Coastguard Worker             darray_item(info->key_names, old_kc) = XKB_ATOM_NONE;
232*2b949d04SAndroid Build Coastguard Worker             if (report)
233*2b949d04SAndroid Build Coastguard Worker                 log_warn(info->ctx,
234*2b949d04SAndroid Build Coastguard Worker                          "Key name %s assigned to multiple keys; "
235*2b949d04SAndroid Build Coastguard Worker                          "Using %d, ignoring %d\n", kname, kc, old_kc);
236*2b949d04SAndroid Build Coastguard Worker         }
237*2b949d04SAndroid Build Coastguard Worker         else {
238*2b949d04SAndroid Build Coastguard Worker             if (report)
239*2b949d04SAndroid Build Coastguard Worker                 log_vrb(info->ctx, 3,
240*2b949d04SAndroid Build Coastguard Worker                         "Key name %s assigned to multiple keys; "
241*2b949d04SAndroid Build Coastguard Worker                         "Using %d, ignoring %d\n", kname, old_kc, kc);
242*2b949d04SAndroid Build Coastguard Worker             return true;
243*2b949d04SAndroid Build Coastguard Worker         }
244*2b949d04SAndroid Build Coastguard Worker     }
245*2b949d04SAndroid Build Coastguard Worker 
246*2b949d04SAndroid Build Coastguard Worker     darray_item(info->key_names, kc) = name;
247*2b949d04SAndroid Build Coastguard Worker     return true;
248*2b949d04SAndroid Build Coastguard Worker }
249*2b949d04SAndroid Build Coastguard Worker 
250*2b949d04SAndroid Build Coastguard Worker /***====================================================================***/
251*2b949d04SAndroid Build Coastguard Worker 
252*2b949d04SAndroid Build Coastguard Worker static bool
253*2b949d04SAndroid Build Coastguard Worker HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge);
254*2b949d04SAndroid Build Coastguard Worker 
255*2b949d04SAndroid Build Coastguard Worker static void
MergeIncludedKeycodes(KeyNamesInfo * into,KeyNamesInfo * from,enum merge_mode merge)256*2b949d04SAndroid Build Coastguard Worker MergeIncludedKeycodes(KeyNamesInfo *into, KeyNamesInfo *from,
257*2b949d04SAndroid Build Coastguard Worker                       enum merge_mode merge)
258*2b949d04SAndroid Build Coastguard Worker {
259*2b949d04SAndroid Build Coastguard Worker     if (from->errorCount > 0) {
260*2b949d04SAndroid Build Coastguard Worker         into->errorCount += from->errorCount;
261*2b949d04SAndroid Build Coastguard Worker         return;
262*2b949d04SAndroid Build Coastguard Worker     }
263*2b949d04SAndroid Build Coastguard Worker 
264*2b949d04SAndroid Build Coastguard Worker     if (into->name == NULL) {
265*2b949d04SAndroid Build Coastguard Worker         into->name = from->name;
266*2b949d04SAndroid Build Coastguard Worker         from->name = NULL;
267*2b949d04SAndroid Build Coastguard Worker     }
268*2b949d04SAndroid Build Coastguard Worker 
269*2b949d04SAndroid Build Coastguard Worker     /* Merge key names. */
270*2b949d04SAndroid Build Coastguard Worker     if (darray_empty(into->key_names)) {
271*2b949d04SAndroid Build Coastguard Worker         into->key_names = from->key_names;
272*2b949d04SAndroid Build Coastguard Worker         darray_init(from->key_names);
273*2b949d04SAndroid Build Coastguard Worker         into->min_key_code = from->min_key_code;
274*2b949d04SAndroid Build Coastguard Worker         into->max_key_code = from->max_key_code;
275*2b949d04SAndroid Build Coastguard Worker     }
276*2b949d04SAndroid Build Coastguard Worker     else {
277*2b949d04SAndroid Build Coastguard Worker         if (darray_size(into->key_names) < darray_size(from->key_names))
278*2b949d04SAndroid Build Coastguard Worker             darray_resize0(into->key_names, darray_size(from->key_names));
279*2b949d04SAndroid Build Coastguard Worker 
280*2b949d04SAndroid Build Coastguard Worker         for (unsigned i = from->min_key_code; i <= from->max_key_code; i++) {
281*2b949d04SAndroid Build Coastguard Worker             xkb_atom_t name = darray_item(from->key_names, i);
282*2b949d04SAndroid Build Coastguard Worker             if (name == XKB_ATOM_NONE)
283*2b949d04SAndroid Build Coastguard Worker                 continue;
284*2b949d04SAndroid Build Coastguard Worker 
285*2b949d04SAndroid Build Coastguard Worker             if (!AddKeyName(into, i, name, merge, true, false))
286*2b949d04SAndroid Build Coastguard Worker                 into->errorCount++;
287*2b949d04SAndroid Build Coastguard Worker         }
288*2b949d04SAndroid Build Coastguard Worker     }
289*2b949d04SAndroid Build Coastguard Worker 
290*2b949d04SAndroid Build Coastguard Worker     /* Merge key aliases. */
291*2b949d04SAndroid Build Coastguard Worker     if (darray_empty(into->aliases)) {
292*2b949d04SAndroid Build Coastguard Worker         into->aliases = from->aliases;
293*2b949d04SAndroid Build Coastguard Worker         darray_init(from->aliases);
294*2b949d04SAndroid Build Coastguard Worker     }
295*2b949d04SAndroid Build Coastguard Worker     else {
296*2b949d04SAndroid Build Coastguard Worker         AliasInfo *alias;
297*2b949d04SAndroid Build Coastguard Worker 
298*2b949d04SAndroid Build Coastguard Worker         darray_foreach(alias, from->aliases) {
299*2b949d04SAndroid Build Coastguard Worker             KeyAliasDef def;
300*2b949d04SAndroid Build Coastguard Worker 
301*2b949d04SAndroid Build Coastguard Worker             def.merge = (merge == MERGE_DEFAULT ? alias->merge : merge);
302*2b949d04SAndroid Build Coastguard Worker             def.alias = alias->alias;
303*2b949d04SAndroid Build Coastguard Worker             def.real = alias->real;
304*2b949d04SAndroid Build Coastguard Worker 
305*2b949d04SAndroid Build Coastguard Worker             if (!HandleAliasDef(into, &def, def.merge))
306*2b949d04SAndroid Build Coastguard Worker                 into->errorCount++;
307*2b949d04SAndroid Build Coastguard Worker         }
308*2b949d04SAndroid Build Coastguard Worker     }
309*2b949d04SAndroid Build Coastguard Worker 
310*2b949d04SAndroid Build Coastguard Worker     /* Merge LED names. */
311*2b949d04SAndroid Build Coastguard Worker     if (into->num_led_names == 0) {
312*2b949d04SAndroid Build Coastguard Worker         memcpy(into->led_names, from->led_names,
313*2b949d04SAndroid Build Coastguard Worker                sizeof(*from->led_names) * from->num_led_names);
314*2b949d04SAndroid Build Coastguard Worker         into->num_led_names = from->num_led_names;
315*2b949d04SAndroid Build Coastguard Worker         from->num_led_names = 0;
316*2b949d04SAndroid Build Coastguard Worker     }
317*2b949d04SAndroid Build Coastguard Worker     else {
318*2b949d04SAndroid Build Coastguard Worker         for (xkb_led_index_t idx = 0; idx < from->num_led_names; idx++) {
319*2b949d04SAndroid Build Coastguard Worker             LedNameInfo *ledi = &from->led_names[idx];
320*2b949d04SAndroid Build Coastguard Worker 
321*2b949d04SAndroid Build Coastguard Worker             if (ledi->name == XKB_ATOM_NONE)
322*2b949d04SAndroid Build Coastguard Worker                 continue;
323*2b949d04SAndroid Build Coastguard Worker 
324*2b949d04SAndroid Build Coastguard Worker             ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge);
325*2b949d04SAndroid Build Coastguard Worker             if (!AddLedName(into, ledi->merge, false, ledi, idx))
326*2b949d04SAndroid Build Coastguard Worker                 into->errorCount++;
327*2b949d04SAndroid Build Coastguard Worker         }
328*2b949d04SAndroid Build Coastguard Worker     }
329*2b949d04SAndroid Build Coastguard Worker }
330*2b949d04SAndroid Build Coastguard Worker 
331*2b949d04SAndroid Build Coastguard Worker static void
332*2b949d04SAndroid Build Coastguard Worker HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge);
333*2b949d04SAndroid Build Coastguard Worker 
334*2b949d04SAndroid Build Coastguard Worker static bool
HandleIncludeKeycodes(KeyNamesInfo * info,IncludeStmt * include)335*2b949d04SAndroid Build Coastguard Worker HandleIncludeKeycodes(KeyNamesInfo *info, IncludeStmt *include)
336*2b949d04SAndroid Build Coastguard Worker {
337*2b949d04SAndroid Build Coastguard Worker     KeyNamesInfo included;
338*2b949d04SAndroid Build Coastguard Worker 
339*2b949d04SAndroid Build Coastguard Worker     InitKeyNamesInfo(&included, info->ctx);
340*2b949d04SAndroid Build Coastguard Worker     included.name = include->stmt;
341*2b949d04SAndroid Build Coastguard Worker     include->stmt = NULL;
342*2b949d04SAndroid Build Coastguard Worker 
343*2b949d04SAndroid Build Coastguard Worker     for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
344*2b949d04SAndroid Build Coastguard Worker         KeyNamesInfo next_incl;
345*2b949d04SAndroid Build Coastguard Worker         XkbFile *file;
346*2b949d04SAndroid Build Coastguard Worker 
347*2b949d04SAndroid Build Coastguard Worker         file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_KEYCODES);
348*2b949d04SAndroid Build Coastguard Worker         if (!file) {
349*2b949d04SAndroid Build Coastguard Worker             info->errorCount += 10;
350*2b949d04SAndroid Build Coastguard Worker             ClearKeyNamesInfo(&included);
351*2b949d04SAndroid Build Coastguard Worker             return false;
352*2b949d04SAndroid Build Coastguard Worker         }
353*2b949d04SAndroid Build Coastguard Worker 
354*2b949d04SAndroid Build Coastguard Worker         InitKeyNamesInfo(&next_incl, info->ctx);
355*2b949d04SAndroid Build Coastguard Worker 
356*2b949d04SAndroid Build Coastguard Worker         HandleKeycodesFile(&next_incl, file, MERGE_OVERRIDE);
357*2b949d04SAndroid Build Coastguard Worker 
358*2b949d04SAndroid Build Coastguard Worker         MergeIncludedKeycodes(&included, &next_incl, stmt->merge);
359*2b949d04SAndroid Build Coastguard Worker 
360*2b949d04SAndroid Build Coastguard Worker         ClearKeyNamesInfo(&next_incl);
361*2b949d04SAndroid Build Coastguard Worker         FreeXkbFile(file);
362*2b949d04SAndroid Build Coastguard Worker     }
363*2b949d04SAndroid Build Coastguard Worker 
364*2b949d04SAndroid Build Coastguard Worker     MergeIncludedKeycodes(info, &included, include->merge);
365*2b949d04SAndroid Build Coastguard Worker     ClearKeyNamesInfo(&included);
366*2b949d04SAndroid Build Coastguard Worker 
367*2b949d04SAndroid Build Coastguard Worker     return (info->errorCount == 0);
368*2b949d04SAndroid Build Coastguard Worker }
369*2b949d04SAndroid Build Coastguard Worker 
370*2b949d04SAndroid Build Coastguard Worker static bool
HandleKeycodeDef(KeyNamesInfo * info,KeycodeDef * stmt,enum merge_mode merge)371*2b949d04SAndroid Build Coastguard Worker HandleKeycodeDef(KeyNamesInfo *info, KeycodeDef *stmt, enum merge_mode merge)
372*2b949d04SAndroid Build Coastguard Worker {
373*2b949d04SAndroid Build Coastguard Worker     if (stmt->merge != MERGE_DEFAULT) {
374*2b949d04SAndroid Build Coastguard Worker         if (stmt->merge == MERGE_REPLACE)
375*2b949d04SAndroid Build Coastguard Worker             merge = MERGE_OVERRIDE;
376*2b949d04SAndroid Build Coastguard Worker         else
377*2b949d04SAndroid Build Coastguard Worker             merge = stmt->merge;
378*2b949d04SAndroid Build Coastguard Worker     }
379*2b949d04SAndroid Build Coastguard Worker 
380*2b949d04SAndroid Build Coastguard Worker     if (stmt->value < 0 || stmt->value > XKB_KEYCODE_MAX) {
381*2b949d04SAndroid Build Coastguard Worker         log_err(info->ctx,
382*2b949d04SAndroid Build Coastguard Worker                 "Illegal keycode %lld: must be between 0..%u; "
383*2b949d04SAndroid Build Coastguard Worker                 "Key ignored\n", (long long) stmt->value, XKB_KEYCODE_MAX);
384*2b949d04SAndroid Build Coastguard Worker         return false;
385*2b949d04SAndroid Build Coastguard Worker     }
386*2b949d04SAndroid Build Coastguard Worker 
387*2b949d04SAndroid Build Coastguard Worker     return AddKeyName(info, (xkb_keycode_t) stmt->value,
388*2b949d04SAndroid Build Coastguard Worker                       stmt->name, merge, false, true);
389*2b949d04SAndroid Build Coastguard Worker }
390*2b949d04SAndroid Build Coastguard Worker 
391*2b949d04SAndroid Build Coastguard Worker static bool
HandleAliasDef(KeyNamesInfo * info,KeyAliasDef * def,enum merge_mode merge)392*2b949d04SAndroid Build Coastguard Worker HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge)
393*2b949d04SAndroid Build Coastguard Worker {
394*2b949d04SAndroid Build Coastguard Worker     AliasInfo *old, new;
395*2b949d04SAndroid Build Coastguard Worker 
396*2b949d04SAndroid Build Coastguard Worker     darray_foreach(old, info->aliases) {
397*2b949d04SAndroid Build Coastguard Worker         if (old->alias == def->alias) {
398*2b949d04SAndroid Build Coastguard Worker             if (def->real == old->real) {
399*2b949d04SAndroid Build Coastguard Worker                 log_vrb(info->ctx, 1,
400*2b949d04SAndroid Build Coastguard Worker                         "Alias of %s for %s declared more than once; "
401*2b949d04SAndroid Build Coastguard Worker                         "First definition ignored\n",
402*2b949d04SAndroid Build Coastguard Worker                         KeyNameText(info->ctx, def->alias),
403*2b949d04SAndroid Build Coastguard Worker                         KeyNameText(info->ctx, def->real));
404*2b949d04SAndroid Build Coastguard Worker             }
405*2b949d04SAndroid Build Coastguard Worker             else {
406*2b949d04SAndroid Build Coastguard Worker                 xkb_atom_t use, ignore;
407*2b949d04SAndroid Build Coastguard Worker 
408*2b949d04SAndroid Build Coastguard Worker                 use = (merge == MERGE_AUGMENT ? old->real : def->real);
409*2b949d04SAndroid Build Coastguard Worker                 ignore = (merge == MERGE_AUGMENT ? def->real : old->real);
410*2b949d04SAndroid Build Coastguard Worker 
411*2b949d04SAndroid Build Coastguard Worker                 log_warn(info->ctx,
412*2b949d04SAndroid Build Coastguard Worker                          "Multiple definitions for alias %s; "
413*2b949d04SAndroid Build Coastguard Worker                          "Using %s, ignoring %s\n",
414*2b949d04SAndroid Build Coastguard Worker                          KeyNameText(info->ctx, old->alias),
415*2b949d04SAndroid Build Coastguard Worker                          KeyNameText(info->ctx, use),
416*2b949d04SAndroid Build Coastguard Worker                          KeyNameText(info->ctx, ignore));
417*2b949d04SAndroid Build Coastguard Worker 
418*2b949d04SAndroid Build Coastguard Worker                 old->real = use;
419*2b949d04SAndroid Build Coastguard Worker             }
420*2b949d04SAndroid Build Coastguard Worker 
421*2b949d04SAndroid Build Coastguard Worker             old->merge = merge;
422*2b949d04SAndroid Build Coastguard Worker             return true;
423*2b949d04SAndroid Build Coastguard Worker         }
424*2b949d04SAndroid Build Coastguard Worker     }
425*2b949d04SAndroid Build Coastguard Worker 
426*2b949d04SAndroid Build Coastguard Worker     InitAliasInfo(&new, merge, def->alias, def->real);
427*2b949d04SAndroid Build Coastguard Worker     darray_append(info->aliases, new);
428*2b949d04SAndroid Build Coastguard Worker     return true;
429*2b949d04SAndroid Build Coastguard Worker }
430*2b949d04SAndroid Build Coastguard Worker 
431*2b949d04SAndroid Build Coastguard Worker static bool
HandleKeyNameVar(KeyNamesInfo * info,VarDef * stmt)432*2b949d04SAndroid Build Coastguard Worker HandleKeyNameVar(KeyNamesInfo *info, VarDef *stmt)
433*2b949d04SAndroid Build Coastguard Worker {
434*2b949d04SAndroid Build Coastguard Worker     const char *elem, *field;
435*2b949d04SAndroid Build Coastguard Worker     ExprDef *arrayNdx;
436*2b949d04SAndroid Build Coastguard Worker 
437*2b949d04SAndroid Build Coastguard Worker     if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &arrayNdx))
438*2b949d04SAndroid Build Coastguard Worker         return false;
439*2b949d04SAndroid Build Coastguard Worker 
440*2b949d04SAndroid Build Coastguard Worker     if (elem) {
441*2b949d04SAndroid Build Coastguard Worker         log_err(info->ctx, "Unknown element %s encountered; "
442*2b949d04SAndroid Build Coastguard Worker                 "Default for field %s ignored\n", elem, field);
443*2b949d04SAndroid Build Coastguard Worker         return false;
444*2b949d04SAndroid Build Coastguard Worker     }
445*2b949d04SAndroid Build Coastguard Worker 
446*2b949d04SAndroid Build Coastguard Worker     if (!istreq(field, "minimum") && !istreq(field, "maximum")) {
447*2b949d04SAndroid Build Coastguard Worker         log_err(info->ctx, "Unknown field encountered; "
448*2b949d04SAndroid Build Coastguard Worker                 "Assignment to field %s ignored\n", field);
449*2b949d04SAndroid Build Coastguard Worker         return false;
450*2b949d04SAndroid Build Coastguard Worker     }
451*2b949d04SAndroid Build Coastguard Worker 
452*2b949d04SAndroid Build Coastguard Worker     /* We ignore explicit min/max statements, we always use computed. */
453*2b949d04SAndroid Build Coastguard Worker     return true;
454*2b949d04SAndroid Build Coastguard Worker }
455*2b949d04SAndroid Build Coastguard Worker 
456*2b949d04SAndroid Build Coastguard Worker static bool
HandleLedNameDef(KeyNamesInfo * info,LedNameDef * def,enum merge_mode merge)457*2b949d04SAndroid Build Coastguard Worker HandleLedNameDef(KeyNamesInfo *info, LedNameDef *def,
458*2b949d04SAndroid Build Coastguard Worker                  enum merge_mode merge)
459*2b949d04SAndroid Build Coastguard Worker {
460*2b949d04SAndroid Build Coastguard Worker     LedNameInfo ledi;
461*2b949d04SAndroid Build Coastguard Worker     xkb_atom_t name;
462*2b949d04SAndroid Build Coastguard Worker 
463*2b949d04SAndroid Build Coastguard Worker     if (def->ndx < 1 || def->ndx > XKB_MAX_LEDS) {
464*2b949d04SAndroid Build Coastguard Worker         info->errorCount++;
465*2b949d04SAndroid Build Coastguard Worker         log_err(info->ctx,
466*2b949d04SAndroid Build Coastguard Worker                 "Illegal indicator index (%d) specified; must be between 1 .. %d; "
467*2b949d04SAndroid Build Coastguard Worker                 "Ignored\n", def->ndx, XKB_MAX_LEDS);
468*2b949d04SAndroid Build Coastguard Worker         return false;
469*2b949d04SAndroid Build Coastguard Worker     }
470*2b949d04SAndroid Build Coastguard Worker 
471*2b949d04SAndroid Build Coastguard Worker     if (!ExprResolveString(info->ctx, def->name, &name)) {
472*2b949d04SAndroid Build Coastguard Worker         char buf[20];
473*2b949d04SAndroid Build Coastguard Worker         snprintf(buf, sizeof(buf), "%u", def->ndx);
474*2b949d04SAndroid Build Coastguard Worker         info->errorCount++;
475*2b949d04SAndroid Build Coastguard Worker         return ReportBadType(info->ctx, "indicator", "name", buf, "string");
476*2b949d04SAndroid Build Coastguard Worker     }
477*2b949d04SAndroid Build Coastguard Worker 
478*2b949d04SAndroid Build Coastguard Worker     ledi.merge = merge;
479*2b949d04SAndroid Build Coastguard Worker     ledi.name = name;
480*2b949d04SAndroid Build Coastguard Worker     return AddLedName(info, merge, true, &ledi, def->ndx - 1);
481*2b949d04SAndroid Build Coastguard Worker }
482*2b949d04SAndroid Build Coastguard Worker 
483*2b949d04SAndroid Build Coastguard Worker static void
HandleKeycodesFile(KeyNamesInfo * info,XkbFile * file,enum merge_mode merge)484*2b949d04SAndroid Build Coastguard Worker HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge)
485*2b949d04SAndroid Build Coastguard Worker {
486*2b949d04SAndroid Build Coastguard Worker     bool ok;
487*2b949d04SAndroid Build Coastguard Worker 
488*2b949d04SAndroid Build Coastguard Worker     free(info->name);
489*2b949d04SAndroid Build Coastguard Worker     info->name = strdup_safe(file->name);
490*2b949d04SAndroid Build Coastguard Worker 
491*2b949d04SAndroid Build Coastguard Worker     for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) {
492*2b949d04SAndroid Build Coastguard Worker         switch (stmt->type) {
493*2b949d04SAndroid Build Coastguard Worker         case STMT_INCLUDE:
494*2b949d04SAndroid Build Coastguard Worker             ok = HandleIncludeKeycodes(info, (IncludeStmt *) stmt);
495*2b949d04SAndroid Build Coastguard Worker             break;
496*2b949d04SAndroid Build Coastguard Worker         case STMT_KEYCODE:
497*2b949d04SAndroid Build Coastguard Worker             ok = HandleKeycodeDef(info, (KeycodeDef *) stmt, merge);
498*2b949d04SAndroid Build Coastguard Worker             break;
499*2b949d04SAndroid Build Coastguard Worker         case STMT_ALIAS:
500*2b949d04SAndroid Build Coastguard Worker             ok = HandleAliasDef(info, (KeyAliasDef *) stmt, merge);
501*2b949d04SAndroid Build Coastguard Worker             break;
502*2b949d04SAndroid Build Coastguard Worker         case STMT_VAR:
503*2b949d04SAndroid Build Coastguard Worker             ok = HandleKeyNameVar(info, (VarDef *) stmt);
504*2b949d04SAndroid Build Coastguard Worker             break;
505*2b949d04SAndroid Build Coastguard Worker         case STMT_LED_NAME:
506*2b949d04SAndroid Build Coastguard Worker             ok = HandleLedNameDef(info, (LedNameDef *) stmt, merge);
507*2b949d04SAndroid Build Coastguard Worker             break;
508*2b949d04SAndroid Build Coastguard Worker         default:
509*2b949d04SAndroid Build Coastguard Worker             log_err(info->ctx,
510*2b949d04SAndroid Build Coastguard Worker                     "Keycode files may define key and indicator names only; "
511*2b949d04SAndroid Build Coastguard Worker                     "Ignoring %s\n", stmt_type_to_string(stmt->type));
512*2b949d04SAndroid Build Coastguard Worker             ok = false;
513*2b949d04SAndroid Build Coastguard Worker             break;
514*2b949d04SAndroid Build Coastguard Worker         }
515*2b949d04SAndroid Build Coastguard Worker 
516*2b949d04SAndroid Build Coastguard Worker         if (!ok)
517*2b949d04SAndroid Build Coastguard Worker             info->errorCount++;
518*2b949d04SAndroid Build Coastguard Worker 
519*2b949d04SAndroid Build Coastguard Worker         if (info->errorCount > 10) {
520*2b949d04SAndroid Build Coastguard Worker             log_err(info->ctx, "Abandoning keycodes file \"%s\"\n",
521*2b949d04SAndroid Build Coastguard Worker                     file->name);
522*2b949d04SAndroid Build Coastguard Worker             break;
523*2b949d04SAndroid Build Coastguard Worker         }
524*2b949d04SAndroid Build Coastguard Worker     }
525*2b949d04SAndroid Build Coastguard Worker }
526*2b949d04SAndroid Build Coastguard Worker 
527*2b949d04SAndroid Build Coastguard Worker /***====================================================================***/
528*2b949d04SAndroid Build Coastguard Worker 
529*2b949d04SAndroid Build Coastguard Worker static bool
CopyKeyNamesToKeymap(struct xkb_keymap * keymap,KeyNamesInfo * info)530*2b949d04SAndroid Build Coastguard Worker CopyKeyNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
531*2b949d04SAndroid Build Coastguard Worker {
532*2b949d04SAndroid Build Coastguard Worker     struct xkb_key *keys;
533*2b949d04SAndroid Build Coastguard Worker     xkb_keycode_t min_key_code, max_key_code, kc;
534*2b949d04SAndroid Build Coastguard Worker 
535*2b949d04SAndroid Build Coastguard Worker     min_key_code = info->min_key_code;
536*2b949d04SAndroid Build Coastguard Worker     max_key_code = info->max_key_code;
537*2b949d04SAndroid Build Coastguard Worker     /* If the keymap has no keys, let's just use the safest pair we know. */
538*2b949d04SAndroid Build Coastguard Worker     if (min_key_code == XKB_KEYCODE_INVALID) {
539*2b949d04SAndroid Build Coastguard Worker         min_key_code = 8;
540*2b949d04SAndroid Build Coastguard Worker         max_key_code = 255;
541*2b949d04SAndroid Build Coastguard Worker     }
542*2b949d04SAndroid Build Coastguard Worker 
543*2b949d04SAndroid Build Coastguard Worker     keys = calloc(max_key_code + 1, sizeof(*keys));
544*2b949d04SAndroid Build Coastguard Worker     if (!keys)
545*2b949d04SAndroid Build Coastguard Worker         return false;
546*2b949d04SAndroid Build Coastguard Worker 
547*2b949d04SAndroid Build Coastguard Worker     for (kc = min_key_code; kc <= max_key_code; kc++)
548*2b949d04SAndroid Build Coastguard Worker         keys[kc].keycode = kc;
549*2b949d04SAndroid Build Coastguard Worker 
550*2b949d04SAndroid Build Coastguard Worker     for (kc = info->min_key_code; kc <= info->max_key_code; kc++)
551*2b949d04SAndroid Build Coastguard Worker         keys[kc].name = darray_item(info->key_names, kc);
552*2b949d04SAndroid Build Coastguard Worker 
553*2b949d04SAndroid Build Coastguard Worker     keymap->min_key_code = min_key_code;
554*2b949d04SAndroid Build Coastguard Worker     keymap->max_key_code = max_key_code;
555*2b949d04SAndroid Build Coastguard Worker     keymap->keys = keys;
556*2b949d04SAndroid Build Coastguard Worker     return true;
557*2b949d04SAndroid Build Coastguard Worker }
558*2b949d04SAndroid Build Coastguard Worker 
559*2b949d04SAndroid Build Coastguard Worker static bool
CopyKeyAliasesToKeymap(struct xkb_keymap * keymap,KeyNamesInfo * info)560*2b949d04SAndroid Build Coastguard Worker CopyKeyAliasesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
561*2b949d04SAndroid Build Coastguard Worker {
562*2b949d04SAndroid Build Coastguard Worker     AliasInfo *alias;
563*2b949d04SAndroid Build Coastguard Worker     unsigned i, num_key_aliases;
564*2b949d04SAndroid Build Coastguard Worker     struct xkb_key_alias *key_aliases;
565*2b949d04SAndroid Build Coastguard Worker 
566*2b949d04SAndroid Build Coastguard Worker     /*
567*2b949d04SAndroid Build Coastguard Worker      * Do some sanity checking on the aliases. We can't do it before
568*2b949d04SAndroid Build Coastguard Worker      * because keys and their aliases may be added out-of-order.
569*2b949d04SAndroid Build Coastguard Worker      */
570*2b949d04SAndroid Build Coastguard Worker     num_key_aliases = 0;
571*2b949d04SAndroid Build Coastguard Worker     darray_foreach(alias, info->aliases) {
572*2b949d04SAndroid Build Coastguard Worker         /* Check that ->real is a key. */
573*2b949d04SAndroid Build Coastguard Worker         if (!XkbKeyByName(keymap, alias->real, false)) {
574*2b949d04SAndroid Build Coastguard Worker             log_vrb(info->ctx, 5,
575*2b949d04SAndroid Build Coastguard Worker                     "Attempt to alias %s to non-existent key %s; Ignored\n",
576*2b949d04SAndroid Build Coastguard Worker                     KeyNameText(info->ctx, alias->alias),
577*2b949d04SAndroid Build Coastguard Worker                     KeyNameText(info->ctx, alias->real));
578*2b949d04SAndroid Build Coastguard Worker             alias->real = XKB_ATOM_NONE;
579*2b949d04SAndroid Build Coastguard Worker             continue;
580*2b949d04SAndroid Build Coastguard Worker         }
581*2b949d04SAndroid Build Coastguard Worker 
582*2b949d04SAndroid Build Coastguard Worker         /* Check that ->alias is not a key. */
583*2b949d04SAndroid Build Coastguard Worker         if (XkbKeyByName(keymap, alias->alias, false)) {
584*2b949d04SAndroid Build Coastguard Worker             log_vrb(info->ctx, 5,
585*2b949d04SAndroid Build Coastguard Worker                     "Attempt to create alias with the name of a real key; "
586*2b949d04SAndroid Build Coastguard Worker                     "Alias \"%s = %s\" ignored\n",
587*2b949d04SAndroid Build Coastguard Worker                     KeyNameText(info->ctx, alias->alias),
588*2b949d04SAndroid Build Coastguard Worker                     KeyNameText(info->ctx, alias->real));
589*2b949d04SAndroid Build Coastguard Worker             alias->real = XKB_ATOM_NONE;
590*2b949d04SAndroid Build Coastguard Worker             continue;
591*2b949d04SAndroid Build Coastguard Worker         }
592*2b949d04SAndroid Build Coastguard Worker 
593*2b949d04SAndroid Build Coastguard Worker         num_key_aliases++;
594*2b949d04SAndroid Build Coastguard Worker     }
595*2b949d04SAndroid Build Coastguard Worker 
596*2b949d04SAndroid Build Coastguard Worker     /* Copy key aliases. */
597*2b949d04SAndroid Build Coastguard Worker     key_aliases = NULL;
598*2b949d04SAndroid Build Coastguard Worker     if (num_key_aliases > 0) {
599*2b949d04SAndroid Build Coastguard Worker         key_aliases = calloc(num_key_aliases, sizeof(*key_aliases));
600*2b949d04SAndroid Build Coastguard Worker         if (!key_aliases)
601*2b949d04SAndroid Build Coastguard Worker             return false;
602*2b949d04SAndroid Build Coastguard Worker 
603*2b949d04SAndroid Build Coastguard Worker         i = 0;
604*2b949d04SAndroid Build Coastguard Worker         darray_foreach(alias, info->aliases) {
605*2b949d04SAndroid Build Coastguard Worker             if (alias->real != XKB_ATOM_NONE) {
606*2b949d04SAndroid Build Coastguard Worker                 key_aliases[i].alias = alias->alias;
607*2b949d04SAndroid Build Coastguard Worker                 key_aliases[i].real = alias->real;
608*2b949d04SAndroid Build Coastguard Worker                 i++;
609*2b949d04SAndroid Build Coastguard Worker             }
610*2b949d04SAndroid Build Coastguard Worker         }
611*2b949d04SAndroid Build Coastguard Worker     }
612*2b949d04SAndroid Build Coastguard Worker 
613*2b949d04SAndroid Build Coastguard Worker     keymap->num_key_aliases = num_key_aliases;
614*2b949d04SAndroid Build Coastguard Worker     keymap->key_aliases = key_aliases;
615*2b949d04SAndroid Build Coastguard Worker     return true;
616*2b949d04SAndroid Build Coastguard Worker }
617*2b949d04SAndroid Build Coastguard Worker 
618*2b949d04SAndroid Build Coastguard Worker static bool
CopyLedNamesToKeymap(struct xkb_keymap * keymap,KeyNamesInfo * info)619*2b949d04SAndroid Build Coastguard Worker CopyLedNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
620*2b949d04SAndroid Build Coastguard Worker {
621*2b949d04SAndroid Build Coastguard Worker     keymap->num_leds = info->num_led_names;
622*2b949d04SAndroid Build Coastguard Worker     for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) {
623*2b949d04SAndroid Build Coastguard Worker         LedNameInfo *ledi = &info->led_names[idx];
624*2b949d04SAndroid Build Coastguard Worker 
625*2b949d04SAndroid Build Coastguard Worker         if (ledi->name == XKB_ATOM_NONE)
626*2b949d04SAndroid Build Coastguard Worker             continue;
627*2b949d04SAndroid Build Coastguard Worker 
628*2b949d04SAndroid Build Coastguard Worker         keymap->leds[idx].name = ledi->name;
629*2b949d04SAndroid Build Coastguard Worker     }
630*2b949d04SAndroid Build Coastguard Worker 
631*2b949d04SAndroid Build Coastguard Worker     return true;
632*2b949d04SAndroid Build Coastguard Worker }
633*2b949d04SAndroid Build Coastguard Worker 
634*2b949d04SAndroid Build Coastguard Worker static bool
CopyKeyNamesInfoToKeymap(struct xkb_keymap * keymap,KeyNamesInfo * info)635*2b949d04SAndroid Build Coastguard Worker CopyKeyNamesInfoToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
636*2b949d04SAndroid Build Coastguard Worker {
637*2b949d04SAndroid Build Coastguard Worker     /* This function trashes keymap on error, but that's OK. */
638*2b949d04SAndroid Build Coastguard Worker     if (!CopyKeyNamesToKeymap(keymap, info) ||
639*2b949d04SAndroid Build Coastguard Worker         !CopyKeyAliasesToKeymap(keymap, info) ||
640*2b949d04SAndroid Build Coastguard Worker         !CopyLedNamesToKeymap(keymap, info))
641*2b949d04SAndroid Build Coastguard Worker         return false;
642*2b949d04SAndroid Build Coastguard Worker 
643*2b949d04SAndroid Build Coastguard Worker     keymap->keycodes_section_name = strdup_safe(info->name);
644*2b949d04SAndroid Build Coastguard Worker     XkbEscapeMapName(keymap->keycodes_section_name);
645*2b949d04SAndroid Build Coastguard Worker     return true;
646*2b949d04SAndroid Build Coastguard Worker }
647*2b949d04SAndroid Build Coastguard Worker 
648*2b949d04SAndroid Build Coastguard Worker /***====================================================================***/
649*2b949d04SAndroid Build Coastguard Worker 
650*2b949d04SAndroid Build Coastguard Worker bool
CompileKeycodes(XkbFile * file,struct xkb_keymap * keymap,enum merge_mode merge)651*2b949d04SAndroid Build Coastguard Worker CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap,
652*2b949d04SAndroid Build Coastguard Worker                 enum merge_mode merge)
653*2b949d04SAndroid Build Coastguard Worker {
654*2b949d04SAndroid Build Coastguard Worker     KeyNamesInfo info;
655*2b949d04SAndroid Build Coastguard Worker 
656*2b949d04SAndroid Build Coastguard Worker     InitKeyNamesInfo(&info, keymap->ctx);
657*2b949d04SAndroid Build Coastguard Worker 
658*2b949d04SAndroid Build Coastguard Worker     HandleKeycodesFile(&info, file, merge);
659*2b949d04SAndroid Build Coastguard Worker     if (info.errorCount != 0)
660*2b949d04SAndroid Build Coastguard Worker         goto err_info;
661*2b949d04SAndroid Build Coastguard Worker 
662*2b949d04SAndroid Build Coastguard Worker     if (!CopyKeyNamesInfoToKeymap(keymap, &info))
663*2b949d04SAndroid Build Coastguard Worker         goto err_info;
664*2b949d04SAndroid Build Coastguard Worker 
665*2b949d04SAndroid Build Coastguard Worker     ClearKeyNamesInfo(&info);
666*2b949d04SAndroid Build Coastguard Worker     return true;
667*2b949d04SAndroid Build Coastguard Worker 
668*2b949d04SAndroid Build Coastguard Worker err_info:
669*2b949d04SAndroid Build Coastguard Worker     ClearKeyNamesInfo(&info);
670*2b949d04SAndroid Build Coastguard Worker     return false;
671*2b949d04SAndroid Build Coastguard Worker }
672