symbols: remove useless identical groups optimization
[platform/upstream/libxkbcommon.git] / src / xkbcomp / symbols.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 /*
28  * Copyright © 2012 Intel Corporation
29  * Copyright © 2012 Ran Benita <ran234@gmail.com>
30  *
31  * Permission is hereby granted, free of charge, to any person obtaining a
32  * copy of this software and associated documentation files (the "Software"),
33  * to deal in the Software without restriction, including without limitation
34  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35  * and/or sell copies of the Software, and to permit persons to whom the
36  * Software is furnished to do so, subject to the following conditions:
37  *
38  * The above copyright notice and this permission notice (including the next
39  * paragraph) shall be included in all copies or substantial portions of the
40  * Software.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
45  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48  * DEALINGS IN THE SOFTWARE.
49  *
50  * Author: Daniel Stone <daniel@fooishbar.org>
51  *         Ran Benita <ran234@gmail.com>
52  */
53
54 #include "xkbcomp-priv.h"
55 #include "text.h"
56 #include "expr.h"
57 #include "action.h"
58 #include "vmod.h"
59 #include "keycodes.h"
60 #include "include.h"
61 #include "keysym.h"
62
63 enum key_repeat {
64     KEY_REPEAT_UNDEFINED = 0,
65     KEY_REPEAT_YES = 1,
66     KEY_REPEAT_NO = 2,
67 };
68
69 enum group_field {
70     GROUP_FIELD_SYMS = (1 << 0),
71     GROUP_FIELD_ACTS = (1 << 1),
72     GROUP_FIELD_TYPE = (1 << 2),
73 };
74
75 enum key_field {
76     KEY_FIELD_REPEAT    = (1 << 0),
77     KEY_FIELD_TYPE_DFLT = (1 << 1),
78     KEY_FIELD_GROUPINFO = (1 << 2),
79     KEY_FIELD_VMODMAP   = (1 << 3),
80 };
81
82 typedef struct {
83     unsigned int num_syms;
84     unsigned int sym_index;
85     union xkb_action act;
86 } LevelInfo;
87
88 typedef darray(xkb_keysym_t) darray_xkb_keysym_t;
89
90 typedef struct {
91     enum group_field defined;
92     darray_xkb_keysym_t syms;
93     darray(LevelInfo) levels;
94     xkb_atom_t type;
95 } GroupInfo;
96
97 typedef struct _KeyInfo {
98     enum key_field defined;
99     unsigned file_id;
100     enum merge_mode merge;
101
102     unsigned long name; /* the 4 chars of the key name, as long */
103
104     GroupInfo groups[XKB_NUM_GROUPS];
105
106     enum key_repeat repeat;
107     xkb_mod_mask_t vmodmap;
108     xkb_atom_t dfltType;
109
110     enum xkb_range_exceed_type out_of_range_group_action;
111     xkb_layout_index_t out_of_range_group_number;
112 } KeyInfo;
113
114 static void
115 InitGroupInfo(GroupInfo *groupi)
116 {
117     memset(groupi, 0, sizeof(*groupi));
118 }
119
120 static void
121 ClearGroupInfo(GroupInfo *groupi)
122 {
123     darray_free(groupi->syms);
124     darray_free(groupi->levels);
125 }
126
127 static void
128 InitKeyInfo(KeyInfo *keyi, unsigned file_id)
129 {
130     static const char dflt_key_name[XKB_KEY_NAME_LENGTH] = "*";
131
132     memset(keyi, 0, sizeof(*keyi));
133     keyi->file_id = file_id;
134     keyi->merge = MERGE_OVERRIDE;
135     keyi->name = KeyNameToLong(dflt_key_name);
136     keyi->out_of_range_group_action = RANGE_WRAP;
137 }
138
139 static void
140 ClearKeyInfo(KeyInfo *keyi)
141 {
142     xkb_layout_index_t i;
143     for (i = 0; i < XKB_NUM_GROUPS; i++)
144         ClearGroupInfo(&keyi->groups[i]);
145 }
146
147 /***====================================================================***/
148
149 typedef struct _ModMapEntry {
150     enum merge_mode merge;
151     bool haveSymbol;
152     int modifier;
153     union {
154         unsigned long keyName;
155         xkb_keysym_t keySym;
156     } u;
157 } ModMapEntry;
158
159 typedef struct _SymbolsInfo {
160     char *name;         /* e.g. pc+us+inet(evdev) */
161     int errorCount;
162     unsigned file_id;
163     enum merge_mode merge;
164     xkb_layout_index_t explicit_group;
165     darray(KeyInfo) keys;
166     KeyInfo dflt;
167     VModInfo vmods;
168     ActionsInfo *actions;
169     xkb_atom_t groupNames[XKB_NUM_GROUPS];
170     darray(ModMapEntry) modMaps;
171
172     struct xkb_keymap *keymap;
173 } SymbolsInfo;
174
175 static void
176 InitSymbolsInfo(SymbolsInfo *info, struct xkb_keymap *keymap,
177                 unsigned file_id, ActionsInfo *actions)
178 {
179     memset(info, 0, sizeof(*info));
180     info->keymap = keymap;
181     info->file_id = file_id;
182     info->merge = MERGE_OVERRIDE;
183     InitKeyInfo(&info->dflt, file_id);
184     InitVModInfo(&info->vmods, keymap);
185     info->actions = actions;
186 }
187
188 static void
189 ClearSymbolsInfo(SymbolsInfo * info)
190 {
191     KeyInfo *keyi;
192     free(info->name);
193     darray_foreach(keyi, info->keys)
194         ClearKeyInfo(keyi);
195     darray_free(info->keys);
196     darray_free(info->modMaps);
197 }
198
199 static bool
200 MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
201             bool report, xkb_layout_index_t group, unsigned long key_name)
202 {
203     xkb_level_index_t i, numLevels;
204     enum { INTO = (1 << 0), FROM = (1 << 1) } using;
205
206     /* First find the type of the merged group. */
207     if (into->type != from->type) {
208         if (from->type == XKB_ATOM_NONE) {
209         }
210         else if (into->type == XKB_ATOM_NONE) {
211             into->type = from->type;
212         }
213         else {
214             xkb_atom_t use = (clobber ? from->type : into->type);
215             xkb_atom_t ignore = (clobber ? into->type : from->type);
216
217             if (report)
218                 log_warn(info->keymap->ctx,
219                          "Multiple definitions for group %d type of key %s; "
220                          "Using %s, ignoring %s\n",
221                          group + 1, LongKeyNameText(key_name),
222                          xkb_atom_text(info->keymap->ctx, use),
223                          xkb_atom_text(info->keymap->ctx, ignore));
224
225             into->type = use;
226         }
227     }
228     into->defined |= (from->defined & GROUP_FIELD_TYPE);
229
230     /* Now look at the levels. */
231
232     if (darray_empty(from->levels)) {
233         InitGroupInfo(from);
234         return true;
235     }
236
237     if (darray_empty(into->levels)) {
238         from->type = into->type;
239         *into = *from;
240         InitGroupInfo(from);
241         return true;
242     }
243
244     /* First we merge the actions and ensure @into has all the levels. */
245     numLevels = MAX(darray_size(into->levels), darray_size(from->levels));
246     for (i = 0; i < numLevels; i++) {
247         union xkb_action *intoAct, *fromAct;
248
249         if (i >= darray_size(from->levels))
250             continue;
251
252         if (i >= darray_size(into->levels)) {
253             darray_append(into->levels, darray_item(from->levels, i));
254             darray_item(into->levels, i).num_syms = 0;
255             darray_item(into->levels, i).sym_index = 0;
256             continue;
257         }
258
259         intoAct = &darray_item(into->levels, i).act;
260         fromAct = &darray_item(from->levels, i).act;
261
262         if (fromAct->type == ACTION_TYPE_NONE) {
263         }
264         else if (intoAct->type == ACTION_TYPE_NONE) {
265             *intoAct = *fromAct;
266         }
267         else {
268             union xkb_action *use = (clobber ? fromAct : intoAct);
269             union xkb_action *ignore = (clobber ? intoAct : fromAct);
270
271             if (report)
272                 log_warn(info->keymap->ctx,
273                          "Multiple actions for level %d/group %u on key %s; "
274                          "Using %s, ignoring %s\n",
275                          i + 1, group + 1, LongKeyNameText(key_name),
276                          ActionTypeText(use->type),
277                          ActionTypeText(ignore->type));
278
279             *intoAct = *use;
280         }
281     }
282     into->defined |= (from->defined & GROUP_FIELD_ACTS);
283
284     /* Then merge the keysyms. */
285
286     /*
287      * We want to avoid copying and allocating if not necessary. So
288      * here we do a pre-scan of the levels to check if we'll only use
289      * @into's or @from's keysyms, and if so we'll just assign them.
290      * However if one level uses @into's and another uses @from's, we
291      * will need to construct a new syms array.
292      */
293     using = 0;
294     for (i = 0; i < numLevels; i++) {
295         unsigned int intoSize, fromSize;
296
297         intoSize = darray_item(into->levels, i).num_syms;
298         if (i < darray_size(from->levels))
299             fromSize = darray_item(from->levels, i).num_syms;
300         else
301             fromSize = 0;
302
303         if (intoSize == 0 && fromSize == 0)
304             using |= 0;
305         else if (intoSize == 0)
306             using |= FROM;
307         else if (fromSize == 0)
308             using |= INTO;
309         else
310             using |= (clobber ? FROM : INTO);
311     }
312
313     if (using == 0 || using == INTO) {
314     }
315     else if (using == FROM) {
316         darray_free(into->syms);
317         into->syms = from->syms;
318         darray_init(from->syms);
319         for (i = 0; i < darray_size(from->levels); i++) {
320             darray_item(into->levels, i).num_syms =
321                 darray_item(from->levels, i).num_syms;
322             darray_item(into->levels, i).sym_index =
323                 darray_item(from->levels, i).sym_index;
324         }
325     }
326     else {
327         darray_xkb_keysym_t syms = darray_new();
328
329         for (i = 0; i < numLevels; i++) {
330             unsigned int intoSize, fromSize;
331
332             intoSize = darray_item(into->levels, i).num_syms;
333             if (i < darray_size(from->levels))
334                 fromSize = darray_item(from->levels, i).num_syms;
335             else
336                 fromSize = 0;
337
338             /* Empty level. */
339             if (intoSize == 0 && fromSize == 0)
340                 continue;
341
342             if (intoSize != 0 && fromSize != 0 && report)
343                 log_info(info->keymap->ctx,
344                          "Multiple symbols for group %u, level %d on key %s; "
345                          "Using %s, ignoring %s\n",
346                          group + 1, i + 1, LongKeyNameText(key_name),
347                          (clobber ? "from" : "to"),
348                          (clobber ? "to" : "from"));
349
350             if (intoSize == 0 || (fromSize != 0 && clobber)) {
351                 unsigned sym_index = darray_item(from->levels, i).sym_index;
352                 darray_item(into->levels, i).sym_index = darray_size(syms);
353                 darray_item(into->levels, i).num_syms = fromSize;
354                 darray_append_items(syms, &darray_item(from->syms, sym_index),
355                                     fromSize);
356             }
357             else
358             {
359                 unsigned sym_index = darray_item(into->levels, i).sym_index;
360                 darray_item(into->levels, i).sym_index = darray_size(syms);
361                 darray_item(into->levels, i).num_syms = intoSize;
362                 darray_append_items(syms, &darray_item(into->syms, sym_index),
363                                     intoSize);
364             }
365         }
366         darray_free(into->syms);
367         into->syms = syms;
368     }
369     into->defined |= (from->defined & GROUP_FIELD_SYMS);
370
371     return true;
372 }
373
374 static bool
375 UseNewKeyField(enum key_field field, enum key_field old, enum key_field new,
376                bool clobber, bool report, enum key_field *collide)
377 {
378     if (!(old & field))
379         return (new & field);
380
381     if (new & field) {
382         if (report)
383             *collide |= field;
384
385         if (clobber)
386             return true;
387     }
388
389     return false;
390 }
391
392
393 static bool
394 MergeKeys(SymbolsInfo *info, KeyInfo *into, KeyInfo *from)
395 {
396     xkb_layout_index_t i;
397     enum key_field collide = 0;
398     bool clobber, report;
399     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
400
401     if (from->merge == MERGE_REPLACE) {
402         ClearKeyInfo(into);
403         *into = *from;
404         InitKeyInfo(from, info->file_id);
405         return true;
406     }
407
408     clobber = (from->merge != MERGE_AUGMENT);
409     report = (verbosity > 9 ||
410               (into->file_id == from->file_id && verbosity > 0));
411
412     for (i = 0; i < XKB_NUM_GROUPS; i++)
413         MergeGroups(info, &into->groups[i], &from->groups[i], clobber,
414                     report, i, into->name);
415
416     if (UseNewKeyField(KEY_FIELD_VMODMAP, into->defined, from->defined,
417                        clobber, report, &collide)) {
418         into->vmodmap = from->vmodmap;
419         into->defined |= KEY_FIELD_VMODMAP;
420     }
421     if (UseNewKeyField(KEY_FIELD_REPEAT, into->defined, from->defined,
422                        clobber, report, &collide)) {
423         into->repeat = from->repeat;
424         into->defined |= KEY_FIELD_REPEAT;
425     }
426     if (UseNewKeyField(KEY_FIELD_TYPE_DFLT, into->defined, from->defined,
427                        clobber, report, &collide)) {
428         into->dfltType = from->dfltType;
429         into->defined |= KEY_FIELD_TYPE_DFLT;
430     }
431     if (UseNewKeyField(KEY_FIELD_GROUPINFO, into->defined, from->defined,
432                        clobber, report, &collide)) {
433         into->out_of_range_group_action = from->out_of_range_group_action;
434         into->out_of_range_group_number = from->out_of_range_group_number;
435         into->defined |= KEY_FIELD_GROUPINFO;
436     }
437
438     if (collide)
439         log_warn(info->keymap->ctx,
440                  "Symbol map for key %s redefined; "
441                  "Using %s definition for conflicting fields\n",
442                  LongKeyNameText(into->name),
443                  (clobber ? "first" : "last"));
444
445     ClearKeyInfo(from);
446     InitKeyInfo(from, info->file_id);
447     return true;
448 }
449
450 static bool
451 AddKeySymbols(SymbolsInfo *info, KeyInfo *keyi)
452 {
453     unsigned long real_name;
454     KeyInfo *iter;
455
456     /*
457      * Don't keep aliases in the keys array; this guarantees that
458      * searching for keys to merge with by straight comparison (see the
459      * following loop) is enough, and we won't get multiple KeyInfo's
460      * for the same key because of aliases.
461      */
462     if (FindKeyNameForAlias(info->keymap, keyi->name, &real_name))
463         keyi->name = real_name;
464
465     darray_foreach(iter, info->keys)
466         if (iter->name == keyi->name)
467             return MergeKeys(info, iter, keyi);
468
469     darray_append(info->keys, *keyi);
470     InitKeyInfo(keyi, info->file_id);
471     return true;
472 }
473
474 static bool
475 AddModMapEntry(SymbolsInfo * info, ModMapEntry * new)
476 {
477     ModMapEntry *mm;
478     bool clobber;
479
480     clobber = (new->merge != MERGE_AUGMENT);
481     darray_foreach(mm, info->modMaps) {
482         if (new->haveSymbol && mm->haveSymbol
483             && (new->u.keySym == mm->u.keySym)) {
484             unsigned use, ignore;
485             if (mm->modifier != new->modifier) {
486                 if (clobber) {
487                     use = new->modifier;
488                     ignore = mm->modifier;
489                 }
490                 else {
491                     use = mm->modifier;
492                     ignore = new->modifier;
493                 }
494                 log_err(info->keymap->ctx,
495                         "%s added to symbol map for multiple modifiers; "
496                         "Using %s, ignoring %s.\n",
497                         KeysymText(new->u.keySym), ModIndexText(use),
498                         ModIndexText(ignore));
499                 mm->modifier = use;
500             }
501             return true;
502         }
503         if ((!new->haveSymbol) && (!mm->haveSymbol) &&
504             (new->u.keyName == mm->u.keyName)) {
505             unsigned use, ignore;
506             if (mm->modifier != new->modifier) {
507                 if (clobber) {
508                     use = new->modifier;
509                     ignore = mm->modifier;
510                 }
511                 else {
512                     use = mm->modifier;
513                     ignore = new->modifier;
514                 }
515                 log_err(info->keymap->ctx,
516                         "Key %s added to map for multiple modifiers; "
517                         "Using %s, ignoring %s.\n",
518                         LongKeyNameText(new->u.keyName), ModIndexText(use),
519                         ModIndexText(ignore));
520                 mm->modifier = use;
521             }
522             return true;
523         }
524     }
525
526     darray_append(info->modMaps, *new);
527     return true;
528 }
529
530 /***====================================================================***/
531
532 static void
533 MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
534                      enum merge_mode merge)
535 {
536     unsigned int i;
537     KeyInfo *keyi;
538     ModMapEntry *mm;
539
540     if (from->errorCount > 0) {
541         into->errorCount += from->errorCount;
542         return;
543     }
544     if (into->name == NULL) {
545         into->name = from->name;
546         from->name = NULL;
547     }
548     for (i = 0; i < XKB_NUM_GROUPS; i++) {
549         if (from->groupNames[i] != XKB_ATOM_NONE) {
550             if ((merge != MERGE_AUGMENT) ||
551                 (into->groupNames[i] == XKB_ATOM_NONE))
552                 into->groupNames[i] = from->groupNames[i];
553         }
554     }
555
556     darray_foreach(keyi, from->keys) {
557         merge = (merge == MERGE_DEFAULT ? keyi->merge : merge);
558         if (!AddKeySymbols(into, keyi))
559             into->errorCount++;
560     }
561
562     darray_foreach(mm, from->modMaps) {
563         mm->merge = (merge == MERGE_DEFAULT ? mm->merge : merge);
564         if (!AddModMapEntry(into, mm))
565             into->errorCount++;
566     }
567 }
568
569 static void
570 HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge);
571
572 static bool
573 HandleIncludeSymbols(SymbolsInfo *info, IncludeStmt *stmt)
574 {
575     enum merge_mode merge = MERGE_DEFAULT;
576     XkbFile *rtrn;
577     SymbolsInfo included, next_incl;
578
579     InitSymbolsInfo(&included, info->keymap, info->file_id, info->actions);
580     if (stmt->stmt) {
581         free(included.name);
582         included.name = stmt->stmt;
583         stmt->stmt = NULL;
584     }
585
586     for (; stmt; stmt = stmt->next_incl) {
587         if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_SYMBOLS,
588                                 &rtrn, &merge)) {
589             info->errorCount += 10;
590             ClearSymbolsInfo(&included);
591             return false;
592         }
593
594         InitSymbolsInfo(&next_incl, info->keymap, rtrn->id, info->actions);
595         next_incl.merge = next_incl.dflt.merge = MERGE_OVERRIDE;
596         if (stmt->modifier) {
597             next_incl.explicit_group = atoi(stmt->modifier) - 1;
598             if (next_incl.explicit_group >= XKB_NUM_GROUPS) {
599                 log_err(info->keymap->ctx,
600                         "Cannot set explicit group to %d - must be between 1..%d; "
601                         "Ignoring group number\n",
602                         next_incl.explicit_group + 1, XKB_NUM_GROUPS);
603                 next_incl.explicit_group = info->explicit_group;
604             }
605         }
606         else {
607             next_incl.explicit_group = info->explicit_group;
608         }
609
610         HandleSymbolsFile(&next_incl, rtrn, MERGE_OVERRIDE);
611
612         MergeIncludedSymbols(&included, &next_incl, merge);
613
614         ClearSymbolsInfo(&next_incl);
615         FreeXkbFile(rtrn);
616     }
617
618     MergeIncludedSymbols(info, &included, merge);
619     ClearSymbolsInfo(&included);
620
621     return (info->errorCount == 0);
622 }
623
624 #define SYMBOLS 1
625 #define ACTIONS 2
626
627 static bool
628 GetGroupIndex(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
629               unsigned what, xkb_layout_index_t *ndx_rtrn)
630 {
631     const char *name = (what == SYMBOLS ? "symbols" : "actions");
632
633     if (arrayNdx == NULL) {
634         xkb_layout_index_t i;
635         enum group_field field = (what == SYMBOLS ?
636                                   GROUP_FIELD_SYMS : GROUP_FIELD_ACTS);
637
638         for (i = 0; i < XKB_NUM_GROUPS; i++) {
639             if (!(keyi->groups[i].defined & field)) {
640                 *ndx_rtrn = i;
641                 return true;
642             }
643         }
644
645         log_err(info->keymap->ctx,
646                 "Too many groups of %s for key %s (max %u); "
647                 "Ignoring %s defined for extra groups\n",
648                 name, LongKeyNameText(keyi->name), XKB_NUM_GROUPS + 1, name);
649         return false;
650     }
651
652     if (!ExprResolveGroup(info->keymap->ctx, arrayNdx, ndx_rtrn)) {
653         log_err(info->keymap->ctx,
654                 "Illegal group index for %s of key %s\n"
655                 "Definition with non-integer array index ignored\n",
656                 name, LongKeyNameText(keyi->name));
657         return false;
658     }
659
660     (*ndx_rtrn)--;
661     return true;
662 }
663
664 bool
665 LookupKeysym(const char *str, xkb_keysym_t *sym_rtrn)
666 {
667     xkb_keysym_t sym;
668
669     if (!str || istreq(str, "any") || istreq(str, "nosymbol")) {
670         *sym_rtrn = XKB_KEY_NoSymbol;
671         return 1;
672     }
673
674     if (istreq(str, "none") || istreq(str, "voidsymbol")) {
675         *sym_rtrn = XKB_KEY_VoidSymbol;
676         return 1;
677     }
678
679     sym = xkb_keysym_from_name(str);
680     if (sym != XKB_KEY_NoSymbol) {
681         *sym_rtrn = sym;
682         return 1;
683     }
684
685     return 0;
686 }
687
688 static bool
689 AddSymbolsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
690                 ExprDef *value)
691 {
692     xkb_layout_index_t ndx;
693     GroupInfo *groupi;
694     unsigned int nSyms;
695     xkb_level_index_t nLevels;
696     xkb_level_index_t i;
697     int j;
698
699     if (!GetGroupIndex(info, keyi, arrayNdx, SYMBOLS, &ndx))
700         return false;
701
702     groupi = &keyi->groups[ndx];
703
704     if (value == NULL) {
705         groupi->defined |= GROUP_FIELD_SYMS;
706         return true;
707     }
708
709     if (value->op != EXPR_KEYSYM_LIST) {
710         log_err(info->keymap->ctx,
711                 "Expected a list of symbols, found %s; "
712                 "Ignoring symbols for group %u of %s\n",
713                 expr_op_type_to_string(value->op), ndx + 1,
714                 LongKeyNameText(keyi->name));
715         return false;
716     }
717
718     if (groupi->defined & GROUP_FIELD_SYMS) {
719         log_err(info->keymap->ctx,
720                 "Symbols for key %s, group %u already defined; "
721                 "Ignoring duplicate definition\n",
722                 LongKeyNameText(keyi->name), ndx + 1);
723         return false;
724     }
725
726     nSyms = darray_size(value->value.list.syms);
727     nLevels = darray_size(value->value.list.symsMapIndex);
728
729     if (darray_size(groupi->syms) < nSyms)
730         darray_resize0(groupi->syms, nSyms);
731
732     if (darray_size(groupi->levels) < nLevels)
733         darray_resize0(groupi->levels, nLevels);
734
735     groupi->defined |= GROUP_FIELD_SYMS;
736
737     for (i = 0; i < nLevels; i++) {
738         LevelInfo *leveli = &darray_item(groupi->levels, i);
739
740         leveli->sym_index = darray_item(value->value.list.symsMapIndex, i);
741         leveli->num_syms = darray_item(value->value.list.symsNumEntries, i);
742
743         for (j = 0; j < leveli->num_syms; j++) {
744             if (!LookupKeysym(darray_item(value->value.list.syms,
745                                           leveli->sym_index + j),
746                               &darray_item(groupi->syms,
747                                            leveli->sym_index + j))) {
748                 log_warn(info->keymap->ctx,
749                          "Could not resolve keysym %s for key %s, group %u (%s), level %u\n",
750                          darray_item(value->value.list.syms, i),
751                          LongKeyNameText(keyi->name),
752                          ndx + 1,
753                          xkb_atom_text(info->keymap->ctx,
754                                        info->groupNames[ndx]),
755                          nSyms);
756                 leveli->sym_index = 0;
757                 leveli->num_syms = 0;
758                 break;
759             }
760
761             if (leveli->num_syms == 1 &&
762                 darray_item(groupi->syms,
763                             leveli->sym_index + j) == XKB_KEY_NoSymbol) {
764                 leveli->sym_index = 0;
765                 leveli->num_syms = 0;
766             }
767         }
768     }
769
770     for (j = darray_size(groupi->levels) - 1;
771          j >= 0 && darray_item(groupi->levels, j).num_syms == 0; j--)
772         (void) darray_pop(groupi->levels);
773
774     return true;
775 }
776
777 static bool
778 AddActionsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
779                 ExprDef *value)
780 {
781     unsigned int i;
782     xkb_layout_index_t ndx;
783     GroupInfo *groupi;
784     unsigned int nActs;
785     ExprDef *act;
786     union xkb_action *toAct;
787
788     if (!GetGroupIndex(info, keyi, arrayNdx, ACTIONS, &ndx))
789         return false;
790
791     groupi = &keyi->groups[ndx];
792
793     if (value == NULL) {
794         groupi->defined |= GROUP_FIELD_ACTS;
795         return true;
796     }
797
798     if (value->op != EXPR_ACTION_LIST) {
799         log_wsgo(info->keymap->ctx,
800                  "Bad expression type (%d) for action list value; "
801                  "Ignoring actions for group %u of %s\n",
802                  value->op, ndx, LongKeyNameText(keyi->name));
803         return false;
804     }
805
806     if (groupi->defined & GROUP_FIELD_ACTS) {
807         log_wsgo(info->keymap->ctx,
808                  "Actions for key %s, group %u already defined\n",
809                  LongKeyNameText(keyi->name), ndx);
810         return false;
811     }
812
813     nActs = 0;
814     for (act = value->value.child; act; act = (ExprDef *) act->common.next)
815         nActs++;
816
817     if (darray_size(groupi->levels) < nActs)
818         darray_resize0(groupi->levels, nActs);
819
820     groupi->defined |= GROUP_FIELD_ACTS;
821
822     act = value->value.child;
823     for (i = 0; i < nActs; i++) {
824         toAct = &darray_item(groupi->levels, i).act;
825
826         if (!HandleActionDef(act, info->keymap, toAct, info->actions))
827             log_err(info->keymap->ctx,
828                     "Illegal action definition for %s; "
829                     "Action for group %u/level %u ignored\n",
830                     LongKeyNameText(keyi->name), ndx + 1, i + 1);
831
832         act = (ExprDef *) act->common.next;
833     }
834
835     return true;
836 }
837
838 static const LookupEntry repeatEntries[] = {
839     { "true", KEY_REPEAT_YES },
840     { "yes", KEY_REPEAT_YES },
841     { "on", KEY_REPEAT_YES },
842     { "false", KEY_REPEAT_NO },
843     { "no", KEY_REPEAT_NO },
844     { "off", KEY_REPEAT_NO },
845     { "default", KEY_REPEAT_UNDEFINED },
846     { NULL, 0 }
847 };
848
849 static bool
850 SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
851                 ExprDef *arrayNdx, ExprDef *value)
852 {
853     bool ok = true;
854     struct xkb_context *ctx = info->keymap->ctx;
855
856     if (istreq(field, "type")) {
857         xkb_layout_index_t ndx;
858         xkb_atom_t val;
859
860         if (!ExprResolveString(ctx, value, &val))
861             log_vrb(ctx, 1,
862                     "The type field of a key symbol map must be a string; "
863                     "Ignoring illegal type definition\n");
864
865         if (arrayNdx == NULL) {
866             keyi->dfltType = val;
867             keyi->defined |= KEY_FIELD_TYPE_DFLT;
868         }
869         else if (!ExprResolveGroup(ctx, arrayNdx, &ndx)) {
870             log_err(ctx,
871                     "Illegal group index for type of key %s; "
872                     "Definition with non-integer array index ignored\n",
873                     LongKeyNameText(keyi->name));
874             return false;
875         }
876         else {
877             ndx--;
878             keyi->groups[ndx].type = val;
879             keyi->groups[ndx].defined |= GROUP_FIELD_TYPE;
880         }
881     }
882     else if (istreq(field, "symbols"))
883         return AddSymbolsToKey(info, keyi, arrayNdx, value);
884     else if (istreq(field, "actions"))
885         return AddActionsToKey(info, keyi, arrayNdx, value);
886     else if (istreq(field, "vmods") ||
887              istreq(field, "virtualmods") ||
888              istreq(field, "virtualmodifiers")) {
889         xkb_mod_mask_t mask;
890
891         ok = ExprResolveVModMask(info->keymap, value, &mask);
892         if (ok) {
893             keyi->vmodmap = (mask >> XKB_NUM_CORE_MODS) & 0xffff;
894             keyi->defined |= KEY_FIELD_VMODMAP;
895         }
896         else {
897             log_err(info->keymap->ctx,
898                     "Expected a virtual modifier mask, found %s; "
899                     "Ignoring virtual modifiers definition for key %s\n",
900                     expr_op_type_to_string(value->op),
901                     LongKeyNameText(keyi->name));
902         }
903     }
904     else if (istreq(field, "locking") ||
905              istreq(field, "lock") ||
906              istreq(field, "locks")) {
907         log_err(info->keymap->ctx,
908                 "Key behaviors not supported; "
909                 "Ignoring locking specification for key %s\n",
910                 LongKeyNameText(keyi->name));
911     }
912     else if (istreq(field, "radiogroup") ||
913              istreq(field, "permanentradiogroup") ||
914              istreq(field, "allownone")) {
915         log_err(info->keymap->ctx,
916                 "Radio groups not supported; "
917                 "Ignoring radio group specification for key %s\n",
918                 LongKeyNameText(keyi->name));
919     }
920     else if (istreq_prefix("overlay", field) ||
921              istreq_prefix("permanentoverlay", field)) {
922         log_err(info->keymap->ctx,
923                 "Overlays not supported; "
924                 "Ignoring overlay specification for key %s\n",
925                 LongKeyNameText(keyi->name));
926     }
927     else if (istreq(field, "repeating") ||
928              istreq(field, "repeats") ||
929              istreq(field, "repeat")) {
930         unsigned int val;
931
932         ok = ExprResolveEnum(ctx, value, &val, repeatEntries);
933         if (!ok) {
934             log_err(info->keymap->ctx,
935                     "Illegal repeat setting for %s; "
936                     "Non-boolean repeat setting ignored\n",
937                     LongKeyNameText(keyi->name));
938             return false;
939         }
940         keyi->repeat = val;
941         keyi->defined |= KEY_FIELD_REPEAT;
942     }
943     else if (istreq(field, "groupswrap") ||
944              istreq(field, "wrapgroups")) {
945         bool set;
946
947         if (!ExprResolveBoolean(ctx, value, &set)) {
948             log_err(info->keymap->ctx,
949                     "Illegal groupsWrap setting for %s; "
950                     "Non-boolean value ignored\n",
951                     LongKeyNameText(keyi->name));
952             return false;
953         }
954
955         if (set)
956             keyi->out_of_range_group_action = RANGE_WRAP;
957         else
958             keyi->out_of_range_group_action = RANGE_SATURATE;
959
960         keyi->defined |= KEY_FIELD_GROUPINFO;
961     }
962     else if (istreq(field, "groupsclamp") ||
963              istreq(field, "clampgroups")) {
964         bool set;
965
966         if (!ExprResolveBoolean(ctx, value, &set)) {
967             log_err(info->keymap->ctx,
968                     "Illegal groupsClamp setting for %s; "
969                     "Non-boolean value ignored\n",
970                     LongKeyNameText(keyi->name));
971             return false;
972         }
973
974         if (set)
975             keyi->out_of_range_group_action = RANGE_SATURATE;
976         else
977             keyi->out_of_range_group_action = RANGE_WRAP;
978
979         keyi->defined |= KEY_FIELD_GROUPINFO;
980     }
981     else if (istreq(field, "groupsredirect") ||
982              istreq(field, "redirectgroups")) {
983         xkb_layout_index_t grp;
984
985         if (!ExprResolveGroup(ctx, value, &grp)) {
986             log_err(info->keymap->ctx,
987                     "Illegal group index for redirect of key %s; "
988                     "Definition with non-integer group ignored\n",
989                     LongKeyNameText(keyi->name));
990             return false;
991         }
992
993         keyi->out_of_range_group_action = RANGE_REDIRECT;
994         keyi->out_of_range_group_number = grp - 1;
995         keyi->defined |= KEY_FIELD_GROUPINFO;
996     }
997     else {
998         log_err(info->keymap->ctx,
999                 "Unknown field %s in a symbol interpretation; "
1000                 "Definition ignored\n",
1001                 field);
1002         ok = false;
1003     }
1004
1005     return ok;
1006 }
1007
1008 static int
1009 SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value)
1010 {
1011     xkb_layout_index_t grp;
1012     xkb_atom_t name;
1013
1014     if (!arrayNdx) {
1015         log_vrb(info->keymap->ctx, 1,
1016                 "You must specify an index when specifying a group name; "
1017                 "Group name definition without array subscript ignored\n");
1018         return false;
1019     }
1020
1021     if (!ExprResolveGroup(info->keymap->ctx, arrayNdx, &grp)) {
1022         log_err(info->keymap->ctx,
1023                 "Illegal index in group name definition; "
1024                 "Definition with non-integer array index ignored\n");
1025         return false;
1026     }
1027
1028     if (!ExprResolveString(info->keymap->ctx, value, &name)) {
1029         log_err(info->keymap->ctx,
1030                 "Group name must be a string; "
1031                 "Illegal name for group %d ignored\n", grp);
1032         return false;
1033     }
1034
1035     info->groupNames[grp - 1 + info->explicit_group] = name;
1036     return true;
1037 }
1038
1039 static int
1040 HandleSymbolsVar(SymbolsInfo *info, VarDef *stmt)
1041 {
1042     const char *elem, *field;
1043     ExprDef *arrayNdx;
1044     bool ret;
1045
1046     if (ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field,
1047                        &arrayNdx) == 0)
1048         return 0;               /* internal error, already reported */
1049     if (elem && istreq(elem, "key")) {
1050         ret = SetSymbolsField(info, &info->dflt, field, arrayNdx,
1051                               stmt->value);
1052     }
1053     else if (!elem && (istreq(field, "name") ||
1054                        istreq(field, "groupname"))) {
1055         ret = SetGroupName(info, arrayNdx, stmt->value);
1056     }
1057     else if (!elem && (istreq(field, "groupswrap") ||
1058                        istreq(field, "wrapgroups"))) {
1059         log_err(info->keymap->ctx,
1060                 "Global \"groupswrap\" not supported; Ignored\n");
1061         ret = true;
1062     }
1063     else if (!elem && (istreq(field, "groupsclamp") ||
1064                        istreq(field, "clampgroups"))) {
1065         log_err(info->keymap->ctx,
1066                 "Global \"groupsclamp\" not supported; Ignored\n");
1067         ret = true;
1068     }
1069     else if (!elem && (istreq(field, "groupsredirect") ||
1070                        istreq(field, "redirectgroups"))) {
1071         log_err(info->keymap->ctx,
1072                 "Global \"groupsredirect\" not supported; Ignored\n");
1073         ret = true;
1074     }
1075     else if (!elem && istreq(field, "allownone")) {
1076         log_err(info->keymap->ctx,
1077                 "Radio groups not supported; "
1078                 "Ignoring \"allownone\" specification\n");
1079         ret = true;
1080     }
1081     else {
1082         ret = SetActionField(info->keymap, elem, field, arrayNdx, stmt->value,
1083                              info->actions);
1084     }
1085
1086     return ret;
1087 }
1088
1089 static bool
1090 HandleSymbolsBody(SymbolsInfo *info, VarDef *def, KeyInfo *keyi)
1091 {
1092     bool ok = true;
1093     const char *elem, *field;
1094     ExprDef *arrayNdx;
1095
1096     for (; def; def = (VarDef *) def->common.next) {
1097         if (def->name && def->name->op == EXPR_FIELD_REF) {
1098             ok = HandleSymbolsVar(info, def);
1099             continue;
1100         }
1101
1102         if (!def->name) {
1103             if (!def->value || def->value->op == EXPR_KEYSYM_LIST)
1104                 field = "symbols";
1105             else
1106                 field = "actions";
1107             arrayNdx = NULL;
1108         }
1109         else {
1110             ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
1111                                 &arrayNdx);
1112         }
1113
1114         if (ok)
1115             ok = SetSymbolsField(info, keyi, field, arrayNdx, def->value);
1116     }
1117
1118     return ok;
1119 }
1120
1121 static bool
1122 SetExplicitGroup(SymbolsInfo *info, KeyInfo *keyi)
1123 {
1124     xkb_layout_index_t i;
1125
1126     if (info->explicit_group == 0)
1127         return true;
1128
1129     for (i = 1; i < XKB_NUM_GROUPS; i++) {
1130         if (keyi->groups[i].defined) {
1131             log_warn(info->keymap->ctx,
1132                      "For the map %s an explicit group specified, "
1133                      "but key %s has more than one group defined; "
1134                      "All groups except first one will be ignored\n",
1135                      info->name, LongKeyNameText(keyi->name));
1136             break;
1137         }
1138     }
1139     if (i < XKB_NUM_GROUPS)
1140         for (i = 1; i < XKB_NUM_GROUPS; i++)
1141             ClearGroupInfo(&keyi->groups[i]);
1142
1143     keyi->groups[info->explicit_group] = keyi->groups[0];
1144     InitGroupInfo(&keyi->groups[0]);
1145     return true;
1146 }
1147
1148 static int
1149 HandleSymbolsDef(SymbolsInfo *info, SymbolsDef *stmt)
1150 {
1151     KeyInfo keyi;
1152     xkb_layout_index_t i;
1153
1154     keyi = info->dflt;
1155     for (i = 0; i < XKB_NUM_GROUPS; i++) {
1156         darray_copy(keyi.groups[i].syms, info->dflt.groups[i].syms);
1157         darray_copy(keyi.groups[i].levels, info->dflt.groups[i].levels);
1158     }
1159     keyi.merge = stmt->merge;
1160     keyi.name = KeyNameToLong(stmt->keyName);
1161
1162     if (!HandleSymbolsBody(info, (VarDef *) stmt->symbols, &keyi)) {
1163         info->errorCount++;
1164         return false;
1165     }
1166
1167     if (!SetExplicitGroup(info, &keyi)) {
1168         info->errorCount++;
1169         return false;
1170     }
1171
1172     if (!AddKeySymbols(info, &keyi)) {
1173         info->errorCount++;
1174         return false;
1175     }
1176
1177     return true;
1178 }
1179
1180 static bool
1181 HandleModMapDef(SymbolsInfo *info, ModMapDef *def)
1182 {
1183     ExprDef *key;
1184     ModMapEntry tmp;
1185     xkb_mod_index_t ndx;
1186     bool ok;
1187     struct xkb_context *ctx = info->keymap->ctx;
1188
1189     if (!LookupModIndex(ctx, NULL, def->modifier, EXPR_TYPE_INT, &ndx)) {
1190         log_err(info->keymap->ctx,
1191                 "Illegal modifier map definition; "
1192                 "Ignoring map for non-modifier \"%s\"\n",
1193                 xkb_atom_text(ctx, def->modifier));
1194         return false;
1195     }
1196
1197     ok = true;
1198     tmp.modifier = ndx;
1199
1200     for (key = def->keys; key != NULL; key = (ExprDef *) key->common.next) {
1201         xkb_keysym_t sym;
1202
1203         if (key->op == EXPR_VALUE && key->value_type == EXPR_TYPE_KEYNAME) {
1204             tmp.haveSymbol = false;
1205             tmp.u.keyName = KeyNameToLong(key->value.keyName);
1206         }
1207         else if (ExprResolveKeySym(ctx, key, &sym)) {
1208             tmp.haveSymbol = true;
1209             tmp.u.keySym = sym;
1210         }
1211         else {
1212             log_err(info->keymap->ctx,
1213                     "Modmap entries may contain only key names or keysyms; "
1214                     "Illegal definition for %s modifier ignored\n",
1215                     ModIndexText(tmp.modifier));
1216             continue;
1217         }
1218
1219         ok = AddModMapEntry(info, &tmp) && ok;
1220     }
1221     return ok;
1222 }
1223
1224 static void
1225 HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge)
1226 {
1227     bool ok;
1228     ParseCommon *stmt;
1229
1230     free(info->name);
1231     info->name = strdup_safe(file->name);
1232
1233     stmt = file->defs;
1234     for (stmt = file->defs; stmt; stmt = stmt->next) {
1235         switch (stmt->type) {
1236         case STMT_INCLUDE:
1237             ok = HandleIncludeSymbols(info, (IncludeStmt *) stmt);
1238             break;
1239         case STMT_SYMBOLS:
1240             ok = HandleSymbolsDef(info, (SymbolsDef *) stmt);
1241             break;
1242         case STMT_VAR:
1243             ok = HandleSymbolsVar(info, (VarDef *) stmt);
1244             break;
1245         case STMT_VMOD:
1246             ok = HandleVModDef((VModDef *) stmt, info->keymap, merge,
1247                                &info->vmods);
1248             break;
1249         case STMT_MODMAP:
1250             ok = HandleModMapDef(info, (ModMapDef *) stmt);
1251             break;
1252         default:
1253             log_err(info->keymap->ctx,
1254                     "Interpretation files may not include other types; "
1255                     "Ignoring %s\n", stmt_type_to_string(stmt->type));
1256             ok = false;
1257             break;
1258         }
1259
1260         if (!ok)
1261             info->errorCount++;
1262
1263         if (info->errorCount > 10) {
1264             log_err(info->keymap->ctx, "Abandoning symbols file \"%s\"\n",
1265                     file->topName);
1266             break;
1267         }
1268     }
1269 }
1270
1271 /**
1272  * Given a keysym @sym, return a key which generates it, or NULL.
1273  * This is used for example in a modifier map definition, such as:
1274  *      modifier_map Lock           { Caps_Lock };
1275  * where we want to add the Lock modifier to the modmap of the key
1276  * which matches the keysym Caps_Lock.
1277  * Since there can be many keys which generates the keysym, the key
1278  * is chosen first by lowest group in which the keysym appears, than
1279  * by lowest level and than by lowest key code.
1280  */
1281 static struct xkb_key *
1282 FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym)
1283 {
1284     struct xkb_key *key, *ret = NULL;
1285     xkb_layout_index_t group, min_group = UINT32_MAX;
1286     xkb_level_index_t level, min_level = UINT16_MAX;
1287
1288     xkb_foreach_key(key, keymap) {
1289         for (group = 0; group < key->num_groups; group++) {
1290             for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1291                  level++) {
1292                 if (XkbKeyNumSyms(key, group, level) != 1 ||
1293                     (XkbKeySymEntry(key, group, level))[0] != sym)
1294                     continue;
1295
1296                 /*
1297                  * If the keysym was found in a group or level > 0, we must
1298                  * keep looking since we might find a key in which the keysym
1299                  * is in a lower group or level.
1300                  */
1301                 if (group < min_group ||
1302                     (group == min_group && level < min_level)) {
1303                     ret = key;
1304                     if (group == 0 && level == 0) {
1305                         return ret;
1306                     }
1307                     else {
1308                         min_group = group;
1309                         min_level = level;
1310                     }
1311                 }
1312             }
1313         }
1314     }
1315
1316     return ret;
1317 }
1318
1319 static bool
1320 FindNamedType(struct xkb_keymap *keymap, xkb_atom_t name, unsigned *type_rtrn)
1321 {
1322     unsigned int i;
1323
1324     for (i = 0; i < keymap->num_types; i++) {
1325         if (keymap->types[i].name == name) {
1326             *type_rtrn = i;
1327             return true;
1328         }
1329     }
1330
1331     return false;
1332 }
1333
1334 /**
1335  * Assign a type to the given sym and return the Atom for the type assigned.
1336  *
1337  * Simple recipe:
1338  * - ONE_LEVEL for width 0/1
1339  * - ALPHABETIC for 2 shift levels, with lower/upercase
1340  * - KEYPAD for keypad keys.
1341  * - TWO_LEVEL for other 2 shift level keys.
1342  * and the same for four level keys.
1343  *
1344  * @param width Number of sysms in syms.
1345  * @param syms The keysyms for the given key (must be size width).
1346  * @param typeNameRtrn Set to the Atom of the type name.
1347  *
1348  * @returns true if a type could be found, false otherwise.
1349  *
1350  * FIXME: I need to take the KeyInfo so I can look at symsMapIndex and
1351  *        all that fun stuff rather than just assuming there's always one
1352  *        symbol per level.
1353  */
1354 static bool
1355 FindAutomaticType(struct xkb_context *ctx, xkb_level_index_t width,
1356                   const xkb_keysym_t *syms, xkb_atom_t *typeNameRtrn,
1357                   bool *autoType)
1358 {
1359     *autoType = false;
1360     if ((width == 1) || (width == 0)) {
1361         *typeNameRtrn = xkb_atom_intern(ctx, "ONE_LEVEL");
1362         *autoType = true;
1363     }
1364     else if (width == 2) {
1365         if (syms && xkb_keysym_is_lower(syms[0]) &&
1366             xkb_keysym_is_upper(syms[1])) {
1367             *typeNameRtrn = xkb_atom_intern(ctx, "ALPHABETIC");
1368         }
1369         else if (syms && (xkb_keysym_is_keypad(syms[0]) ||
1370                           xkb_keysym_is_keypad(syms[1]))) {
1371             *typeNameRtrn = xkb_atom_intern(ctx, "KEYPAD");
1372             *autoType = true;
1373         }
1374         else {
1375             *typeNameRtrn = xkb_atom_intern(ctx, "TWO_LEVEL");
1376             *autoType = true;
1377         }
1378     }
1379     else if (width <= 4) {
1380         if (syms && xkb_keysym_is_lower(syms[0]) &&
1381             xkb_keysym_is_upper(syms[1]))
1382             if (xkb_keysym_is_lower(syms[2]) && xkb_keysym_is_upper(syms[3]))
1383                 *typeNameRtrn =
1384                     xkb_atom_intern(ctx, "FOUR_LEVEL_ALPHABETIC");
1385             else
1386                 *typeNameRtrn = xkb_atom_intern(ctx,
1387                                                 "FOUR_LEVEL_SEMIALPHABETIC");
1388
1389         else if (syms && (xkb_keysym_is_keypad(syms[0]) ||
1390                           xkb_keysym_is_keypad(syms[1])))
1391             *typeNameRtrn = xkb_atom_intern(ctx, "FOUR_LEVEL_KEYPAD");
1392         else
1393             *typeNameRtrn = xkb_atom_intern(ctx, "FOUR_LEVEL");
1394         /* XXX: why not set autoType here? */
1395     }
1396     return width <= 4;
1397 }
1398
1399 /**
1400  * Ensure the given KeyInfo is in a coherent state, i.e. no gaps between the
1401  * groups.
1402  */
1403 static void
1404 PrepareKeyDef(KeyInfo *keyi)
1405 {
1406     xkb_layout_index_t i, lastGroup;
1407     const GroupInfo *group0;
1408
1409     /* get highest group number */
1410     lastGroup = 0;
1411     for (i = 1; i < XKB_NUM_GROUPS; i++)
1412         if (keyi->groups[i].defined)
1413             lastGroup = i;
1414
1415     if (lastGroup == 0)
1416         return;
1417
1418     group0 = &keyi->groups[0];
1419
1420     /* If there are empty groups between non-empty ones fill them with data */
1421     /* from the first group. */
1422     /* We can make a wrong assumption here. But leaving gaps is worse. */
1423     for (i = 1; i < lastGroup; i++) {
1424         GroupInfo *groupi = &keyi->groups[i];
1425
1426         if (groupi->defined)
1427             continue;
1428
1429         groupi->type = group0->type;
1430         darray_copy(groupi->syms, group0->syms);
1431         darray_copy(groupi->levels, group0->levels);
1432         groupi->defined = group0->defined;
1433     }
1434 }
1435
1436 static bool
1437 CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi)
1438 {
1439     struct xkb_keymap *keymap = info->keymap;
1440     struct xkb_key *key;
1441     xkb_layout_index_t i;
1442     bool haveActions;
1443     unsigned int sizeSyms;
1444     unsigned int symIndex;
1445
1446     /*
1447      * The name is guaranteed to be real and not an alias (see
1448      * AddKeySymbols), so 'false' is safe here.
1449      */
1450     key = FindNamedKey(keymap, keyi->name, false);
1451     if (!key) {
1452         log_vrb(info->keymap->ctx, 5,
1453                 "Key %s not found in keycodes; Symbols ignored\n",
1454                 LongKeyNameText(keyi->name));
1455         return false;
1456     }
1457
1458     /*
1459      * Find the range of groups we need. (There shouldn't be any gaps,
1460      * see PrepareKeyDef).
1461      */
1462     key->num_groups = 0;
1463     for (i = 0; i < XKB_NUM_GROUPS; i++)
1464         if (keyi->groups[i].defined)
1465             key->num_groups = i + 1;
1466
1467     /* See if we need to allocate an actions array. */
1468     haveActions = false;
1469     for (i = 0; i < key->num_groups; i++) {
1470         LevelInfo *leveli;
1471         darray_foreach(leveli, keyi->groups[i].levels) {
1472             if (leveli->act.type != ACTION_TYPE_NONE) {
1473                 haveActions = true;
1474                 goto out_of_loops;
1475             }
1476         }
1477     }
1478 out_of_loops:
1479
1480     /*
1481      * Find and assign the groups' types in the keymap. Also find the
1482      * key width according to the largest type.
1483      */
1484     key->width = 0;
1485     for (i = 0; i < key->num_groups; i++) {
1486         struct xkb_key_type *type;
1487         GroupInfo *groupi = &keyi->groups[i];
1488         bool autoType = false;
1489
1490         /* Find the type of the group, if it is missing. */
1491         if (groupi->type == XKB_ATOM_NONE) {
1492             if (keyi->dfltType != XKB_ATOM_NONE)
1493                 groupi->type = keyi->dfltType;
1494             else if (FindAutomaticType(keymap->ctx,
1495                                        darray_size(groupi->levels),
1496                                        darray_mem(groupi->syms, 0),
1497                                        &groupi->type, &autoType)) { }
1498             else
1499                 log_vrb(info->keymap->ctx, 5,
1500                         "No automatic type for %d levels; "
1501                         "Using %s for the %s key\n",
1502                         (int) darray_size(groupi->levels),
1503                         xkb_atom_text(keymap->ctx, groupi->type),
1504                         LongKeyNameText(keyi->name));
1505         }
1506
1507         /* Find the type in the keymap, if it was defined in xkb_types. */
1508         if (FindNamedType(keymap, groupi->type, &key->kt_index[i])) {
1509             if (!autoType || darray_size(groupi->levels) > 2)
1510                 key->explicit_groups |= (1 << i);
1511         }
1512         else {
1513             log_vrb(info->keymap->ctx, 3,
1514                     "Type \"%s\" is not defined; "
1515                     "Using default type for the %s key\n",
1516                     xkb_atom_text(keymap->ctx, groupi->type),
1517                     LongKeyNameText(keyi->name));
1518             /*
1519              * Index 0 is guaranteed to contain something, usually
1520              * ONE_LEVEL or at least some default one-level type.
1521              */
1522             key->kt_index[i] = 0;
1523         }
1524
1525         /* If the type specifies fewer levels than the key has, shrink the key. */
1526         type = &keymap->types[key->kt_index[i]];
1527         if (type->num_levels < darray_size(groupi->levels)) {
1528             log_vrb(info->keymap->ctx, 1,
1529                     "Type \"%s\" has %d levels, but %s has %d levels; "
1530                     "Ignoring extra symbols\n",
1531                     xkb_atom_text(keymap->ctx, type->name),
1532                     type->num_levels,
1533                     LongKeyNameText(keyi->name),
1534                     (int) darray_size(groupi->levels));
1535             darray_resize(groupi->levels, type->num_levels);
1536         }
1537
1538         /*
1539          * Why type->num_levels and not darray_size(groupi->levels)?
1540          * Because the type may have more levels, and each group must
1541          * have at least as many levels as its type. Because the
1542          * key->syms array is indexed by (group * width + level), we
1543          * must take the largest one.
1544          * Maybe we can change it to save some space.
1545          */
1546         key->width = MAX(key->width, type->num_levels);
1547     }
1548
1549     /* Find the size of the syms array. */
1550     sizeSyms = 0;
1551     for (i = 0; i < key->num_groups; i++)
1552         sizeSyms += darray_size(keyi->groups[i].syms);
1553
1554     /* Initialize the xkb_key, now that we know the sizes. */
1555     key->syms = calloc(sizeSyms, sizeof(*key->syms));
1556     key->sym_index = calloc(key->num_groups * key->width,
1557                             sizeof(*key->sym_index));
1558     key->num_syms = calloc(key->num_groups * key->width,
1559                            sizeof(*key->num_syms));
1560     key->out_of_range_group_number = keyi->out_of_range_group_number;
1561     key->out_of_range_group_action = keyi->out_of_range_group_action;
1562     if (haveActions) {
1563         key->actions = calloc(key->num_groups * key->width,
1564                               sizeof(*key->actions));
1565         key->explicit |= EXPLICIT_INTERP;
1566     }
1567     if (keyi->defined & KEY_FIELD_VMODMAP) {
1568         key->vmodmap = keyi->vmodmap;
1569         key->explicit |= EXPLICIT_VMODMAP;
1570     }
1571
1572     if (keyi->repeat != KEY_REPEAT_UNDEFINED) {
1573         key->repeats = (keyi->repeat == KEY_REPEAT_YES);
1574         key->explicit |= EXPLICIT_REPEAT;
1575     }
1576
1577     /* Copy keysyms and actions. */
1578     symIndex = 0;
1579     for (i = 0; i < key->num_groups; i++) {
1580         GroupInfo *groupi = &keyi->groups[i];
1581         xkb_level_index_t j;
1582
1583         /* We rely on calloc having zeroized the arrays up to key->width. */
1584         for (j = 0; j < darray_size(groupi->levels); j++) {
1585             LevelInfo *leveli = &darray_item(groupi->levels, j);
1586
1587             if (leveli->act.type != ACTION_TYPE_NONE)
1588                 key->actions[i * key->width + j] = leveli->act;
1589
1590             if (leveli->num_syms <= 0)
1591                 continue;
1592
1593             memcpy(&key->syms[symIndex],
1594                    &darray_item(groupi->syms, leveli->sym_index),
1595                    leveli->num_syms * sizeof(*key->syms));
1596             key->sym_index[i * key->width + j] = symIndex;
1597             key->num_syms[i * key->width + j] = leveli->num_syms;
1598             symIndex += key->num_syms[i * key->width + j];
1599         }
1600     }
1601
1602     return true;
1603 }
1604
1605 static bool
1606 CopyModMapDef(SymbolsInfo *info, ModMapEntry *entry)
1607 {
1608     struct xkb_key *key;
1609     struct xkb_keymap *keymap = info->keymap;
1610
1611     if (!entry->haveSymbol) {
1612         key = FindNamedKey(keymap, entry->u.keyName, true);
1613         if (!key) {
1614             log_vrb(info->keymap->ctx, 5,
1615                     "Key %s not found in keycodes; "
1616                     "Modifier map entry for %s not updated\n",
1617                     LongKeyNameText(entry->u.keyName),
1618                     ModIndexText(entry->modifier));
1619             return false;
1620         }
1621     }
1622     else {
1623         key = FindKeyForSymbol(keymap, entry->u.keySym);
1624         if (!key) {
1625             log_vrb(info->keymap->ctx, 5,
1626                     "Key \"%s\" not found in symbol map; "
1627                     "Modifier map entry for %s not updated\n",
1628                     KeysymText(entry->u.keySym),
1629                     ModIndexText(entry->modifier));
1630             return false;
1631         }
1632     }
1633
1634     key->modmap |= (1 << entry->modifier);
1635     return true;
1636 }
1637
1638 static bool
1639 CopySymbolsToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info)
1640 {
1641     KeyInfo *keyi;
1642     ModMapEntry *mm;
1643     xkb_layout_index_t i;
1644     struct xkb_key *key;
1645
1646     keymap->symbols_section_name = strdup_safe(info->name);
1647
1648     for (i = 0; i < XKB_NUM_GROUPS; i++)
1649         if (info->groupNames[i] != XKB_ATOM_NONE)
1650             keymap->group_names[i] = info->groupNames[i];
1651
1652     darray_foreach(keyi, info->keys) {
1653         PrepareKeyDef(keyi);
1654         if (!CopySymbolsDef(info, keyi))
1655             info->errorCount++;
1656     }
1657
1658     if (xkb_get_log_verbosity(keymap->ctx) > 3) {
1659         xkb_foreach_key(key, keymap) {
1660             if (key->name[0] == '\0')
1661                 continue;
1662
1663             if (key->num_groups < 1)
1664                 log_info(keymap->ctx,
1665                          "No symbols defined for %s\n",
1666                          KeyNameText(key->name));
1667         }
1668     }
1669
1670     darray_foreach(mm, info->modMaps)
1671         if (!CopyModMapDef(info, mm))
1672             info->errorCount++;
1673
1674     /* XXX: If we don't ignore errorCount, things break. */
1675     return true;
1676 }
1677
1678 bool
1679 CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
1680                enum merge_mode merge)
1681 {
1682     SymbolsInfo info;
1683     ActionsInfo *actions;
1684
1685     actions = NewActionsInfo();
1686     if (!actions)
1687         return false;
1688
1689     InitSymbolsInfo(&info, keymap, file->id, actions);
1690     info.dflt.merge = merge;
1691
1692     HandleSymbolsFile(&info, file, merge);
1693
1694     if (darray_empty(info.keys))
1695         goto err_info;
1696
1697     if (info.errorCount != 0)
1698         goto err_info;
1699
1700     if (!CopySymbolsToKeymap(keymap, &info))
1701         goto err_info;
1702
1703     ClearSymbolsInfo(&info);
1704     FreeActionsInfo(actions);
1705     return true;
1706
1707 err_info:
1708     FreeActionsInfo(actions);
1709     ClearSymbolsInfo(&info);
1710     return false;
1711 }