xkbcomp: use new log functions
[platform/upstream/libxkbcommon.git] / src / xkbcomp / keycodes.c
1 /************************************************************
2  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of Silicon Graphics not be
10  * used in advertising or publicity pertaining to distribution
11  * of the software without specific prior written permission.
12  * Silicon Graphics makes no representation about the suitability
13  * of this software for any purpose. It is provided "as is"
14  * without any express or implied warranty.
15  *
16  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  ********************************************************/
26
27 #include "xkbcomp-priv.h"
28 #include "expr.h"
29 #include "parseutils.h"
30
31 typedef struct _AliasInfo {
32     enum merge_mode merge;
33     unsigned file_id;
34     struct list entry;
35
36     char alias[XkbKeyNameLength + 1];
37     char real[XkbKeyNameLength + 1];
38 } AliasInfo;
39
40 typedef struct _IndicatorNameInfo {
41     enum merge_mode merge;
42     unsigned file_id;
43     struct list entry;
44
45     int ndx;
46     xkb_atom_t name;
47     bool virtual;
48 } IndicatorNameInfo;
49
50 typedef struct _KeyNamesInfo {
51     char *name;     /* e.g. evdev+aliases(qwerty) */
52     int errorCount;
53     unsigned file_id;
54     enum merge_mode merge;
55     xkb_keycode_t computedMin; /* lowest keycode stored */
56     xkb_keycode_t computedMax; /* highest keycode stored */
57     xkb_keycode_t explicitMin;
58     xkb_keycode_t explicitMax;
59     darray(unsigned long) names;
60     darray(unsigned int) files;
61     struct list leds;
62     struct list aliases;
63
64     struct xkb_keymap *keymap;
65 } KeyNamesInfo;
66
67 static void
68 ResizeKeyNameArrays(KeyNamesInfo *info, int newMax)
69 {
70     if (newMax < darray_size(info->names))
71         return;
72
73     darray_resize0(info->names, newMax + 1);
74     darray_resize0(info->files, newMax + 1);
75 }
76
77 static void
78 InitAliasInfo(AliasInfo *info, enum merge_mode merge, unsigned file_id,
79               char *alias, char *real)
80 {
81     memset(info, 0, sizeof(*info));
82     info->merge = merge;
83     info->file_id = file_id;
84     strncpy(info->alias, alias, XkbKeyNameLength);
85     strncpy(info->real, real, XkbKeyNameLength);
86 }
87
88 static void
89 InitIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info)
90 {
91     ii->merge = info->merge;
92     ii->file_id = info->file_id;
93     ii->ndx = 0;
94     ii->name = XKB_ATOM_NONE;
95     ii->virtual = false;
96 }
97
98 static IndicatorNameInfo *
99 NextIndicatorName(KeyNamesInfo * info)
100 {
101     IndicatorNameInfo *ii;
102
103     ii = malloc(sizeof(*ii));
104     if (!ii)
105         return NULL;
106
107     InitIndicatorNameInfo(ii, info);
108     list_append(&ii->entry, &info->leds);
109
110     return ii;
111 }
112
113 static IndicatorNameInfo *
114 FindIndicatorByIndex(KeyNamesInfo * info, int ndx)
115 {
116     IndicatorNameInfo *old;
117
118     list_foreach(old, &info->leds, entry)
119         if (old->ndx == ndx)
120             return old;
121
122     return NULL;
123 }
124
125 static IndicatorNameInfo *
126 FindIndicatorByName(KeyNamesInfo * info, xkb_atom_t name)
127 {
128     IndicatorNameInfo *old;
129
130     list_foreach(old, &info->leds, entry)
131         if (old->name == name)
132             return old;
133
134     return NULL;
135 }
136
137 static bool
138 AddIndicatorName(KeyNamesInfo *info, enum merge_mode merge,
139                  IndicatorNameInfo *new)
140 {
141     IndicatorNameInfo *old;
142     bool replace;
143     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
144
145     replace = (merge == MERGE_REPLACE) || (merge == MERGE_OVERRIDE);
146
147     old = FindIndicatorByName(info, new->name);
148     if (old) {
149         if ((old->file_id == new->file_id && verbosity > 0) ||
150             verbosity > 9) {
151             if (old->ndx == new->ndx) {
152                 if (old->virtual != new->virtual) {
153                     if (replace)
154                         old->virtual = new->virtual;
155                     log_warn(info->keymap->ctx, "Multiple indicators named %s; "
156                              "Using %s instead of %s\n",
157                              xkb_atom_text(info->keymap->ctx, new->name),
158                              (old->virtual ? "virtual" : "real"),
159                              (old->virtual ? "real" : "virtual"));
160                 }
161                 else {
162                     log_warn(info->keymap->ctx, "Multiple indicators named %s; "
163                              "Identical definitions ignored\n",
164                              xkb_atom_text(info->keymap->ctx, new->name));
165                 }
166                 return true;
167             }
168             else {
169                 log_warn(info->keymap->ctx, "Multiple indicators named %s; "
170                          "Using %d, ignoring %d\n",
171                          xkb_atom_text(info->keymap->ctx, new->name),
172                          (replace ? old->ndx : new->ndx),
173                          (replace ? new->ndx : old->ndx));
174             }
175
176             if (replace) {
177                 list_del(&old->entry);
178                 free(old);
179             }
180         }
181     }
182
183     old = FindIndicatorByIndex(info, new->ndx);
184     if (old) {
185         if ((old->file_id == new->file_id && verbosity > 0) ||
186             verbosity > 9) {
187             if (old->name == new->name && old->virtual == new->virtual) {
188                 log_warn(info->keymap->ctx,
189                          "Multiple names for indicator %d; "
190                          "Identical definitions ignored\n", new->ndx);
191             } else {
192                 const char *oldType, *newType;
193                 xkb_atom_t using, ignoring;
194                 if (old->virtual)
195                     oldType = "virtual indicator";
196                 else
197                     oldType = "real indicator";
198                 if (new->virtual)
199                     newType = "virtual indicator";
200                 else
201                     newType = "real indicator";
202                 if (replace) {
203                     using = new->name;
204                     ignoring = old->name;
205                 }
206                 else {
207                     using = old->name;
208                     ignoring = new->name;
209                 }
210                 log_warn(info->keymap->ctx,
211                          "Multiple names for indicator %d; "
212                          "Using %s %s, ignoring %s %s\n",
213                          new->ndx,
214                          oldType, xkb_atom_text(info->keymap->ctx, using),
215                          newType, xkb_atom_text(info->keymap->ctx, ignoring));
216             }
217         }
218         if (replace) {
219             old->name = new->name;
220             old->virtual = new->virtual;
221         }
222         return true;
223     }
224     old = new;
225     new = NextIndicatorName(info);
226     if (!new) {
227         log_wsgo(info->keymap->ctx,
228                  "Couldn't allocate name for indicator %d; Ignored\n",
229                  old->ndx);
230         return false;
231     }
232     new->name = old->name;
233     new->ndx = old->ndx;
234     new->virtual = old->virtual;
235     return true;
236 }
237
238 static void
239 ClearKeyNamesInfo(KeyNamesInfo * info)
240 {
241     AliasInfo *alias, *next_alias;
242     IndicatorNameInfo *ii, *next_ii;
243
244     free(info->name);
245     info->name = NULL;
246     info->computedMax = info->explicitMax = info->explicitMin = 0;
247     info->computedMin = XKB_KEYCODE_MAX;
248     darray_free(info->names);
249     darray_free(info->files);
250     list_foreach_safe(ii, next_ii, &info->leds, entry)
251         free(ii);
252     list_foreach_safe(alias, next_alias, &info->aliases, entry)
253         free(alias);
254     list_init(&info->aliases);
255 }
256
257 static void
258 InitKeyNamesInfo(KeyNamesInfo *info, struct xkb_keymap *keymap,
259                  unsigned file_id)
260 {
261     info->name = NULL;
262     list_init(&info->leds);
263     list_init(&info->aliases);
264     info->file_id = file_id;
265     darray_init(info->names);
266     darray_init(info->files);
267     ClearKeyNamesInfo(info);
268     info->errorCount = 0;
269     info->keymap = keymap;
270 }
271
272 static int
273 FindKeyByLong(KeyNamesInfo * info, unsigned long name)
274 {
275     uint64_t i;
276
277     for (i = info->computedMin; i <= info->computedMax; i++)
278         if (darray_item(info->names, i) == name)
279             return i;
280
281     return 0;
282 }
283
284 /**
285  * Store the name of the key as a long in the info struct under the given
286  * keycode. If the same keys is referred to twice, print a warning.
287  * Note that the key's name is stored as a long, the keycode is the index.
288  */
289 static bool
290 AddKeyName(KeyNamesInfo * info,
291            xkb_keycode_t kc, char *name, enum merge_mode merge,
292            unsigned file_id, bool reportCollisions)
293 {
294     xkb_keycode_t old;
295     unsigned long lval;
296     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
297
298     ResizeKeyNameArrays(info, kc);
299
300     if (kc < info->computedMin)
301         info->computedMin = kc;
302     if (kc > info->computedMax)
303         info->computedMax = kc;
304     lval = KeyNameToLong(name);
305
306     if (reportCollisions)
307         reportCollisions = (verbosity > 7 ||
308                             (verbosity > 0 &&
309                              file_id == darray_item(info->files, kc)));
310
311     if (darray_item(info->names, kc) != 0) {
312         char buf[6];
313
314         LongToKeyName(darray_item(info->names, kc), buf);
315         buf[4] = '\0';
316         if (darray_item(info->names, kc) == lval && reportCollisions) {
317             log_warn(info->keymap->ctx,
318                      "Multiple identical key name definitions; "
319                      "Later occurences of \"<%s> = %d\" ignored\n", buf, kc);
320             return true;
321         }
322
323         if (merge == MERGE_AUGMENT) {
324             if (reportCollisions)
325                 log_warn(info->keymap->ctx,
326                          "Multiple names for keycode %d; "
327                          "Using <%s>, ignoring <%s>\n", kc, buf, name);
328             return true;
329         }
330         else {
331             if (reportCollisions)
332                 log_warn(info->keymap->ctx,
333                          "Multiple names for keycode %d; "
334                          "Using <%s>, ignoring <%s>\n", kc, name, buf);
335             darray_item(info->names, kc) = 0;
336             darray_item(info->files, kc) = 0;
337         }
338     }
339
340     old = FindKeyByLong(info, lval);
341     if ((old != 0) && (old != kc)) {
342         if (merge == MERGE_OVERRIDE) {
343             darray_item(info->names, old) = 0;
344             darray_item(info->files, old) = 0;
345             if (reportCollisions)
346                 log_warn(info->keymap->ctx,
347                          "Key name <%s> assigned to multiple keys; "
348                          "Using %d, ignoring %d\n", name, kc, old);
349         }
350         else {
351             if (reportCollisions && verbosity > 3)
352                 log_warn(info->keymap->ctx,
353                          "Key name <%s> assigned to multiple keys; "
354                          "Using %d, ignoring %d\n", name, old, kc);
355             return true;
356         }
357     }
358     darray_item(info->names, kc) = lval;
359     darray_item(info->files, kc) = file_id;
360     return true;
361 }
362
363 /***====================================================================***/
364
365 static int
366 HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge,
367                unsigned file_id);
368
369 static bool
370 MergeAliases(KeyNamesInfo *into, KeyNamesInfo *from, enum merge_mode merge)
371 {
372     AliasInfo *alias, *next;
373     KeyAliasDef def;
374
375     if (list_empty(&from->aliases))
376         return true;
377
378     if (list_empty(&into->aliases)) {
379         list_replace(&from->aliases, &into->aliases);
380         list_init(&from->aliases);
381         return true;
382     }
383
384     memset(&def, 0, sizeof(def));
385
386     list_foreach_safe(alias, next, &from->aliases, entry) {
387         def.merge = (merge == MERGE_DEFAULT) ? alias->merge : merge;
388         memcpy(def.alias, alias->alias, XkbKeyNameLength);
389         memcpy(def.real, alias->real, XkbKeyNameLength);
390
391         if (!HandleAliasDef(into, &def, def.merge, alias->file_id))
392             return false;
393     }
394
395     return true;
396 }
397
398 static void
399 MergeIncludedKeycodes(KeyNamesInfo *into, KeyNamesInfo *from,
400                       enum merge_mode merge)
401 {
402     uint64_t i;
403     char buf[5];
404     IndicatorNameInfo *led;
405
406     if (from->errorCount > 0) {
407         into->errorCount += from->errorCount;
408         return;
409     }
410     if (into->name == NULL) {
411         into->name = from->name;
412         from->name = NULL;
413     }
414
415     ResizeKeyNameArrays(into, from->computedMax);
416
417     for (i = from->computedMin; i <= from->computedMax; i++) {
418         if (darray_item(from->names, i) == 0)
419             continue;
420         LongToKeyName(darray_item(from->names, i), buf);
421         buf[4] = '\0';
422         if (!AddKeyName(into, i, buf, merge, from->file_id, false))
423             into->errorCount++;
424     }
425
426     list_foreach(led, &from->leds, entry) {
427         led->merge = (merge == MERGE_DEFAULT ? led->merge : merge);
428         if (!AddIndicatorName(into, led->merge, led))
429             into->errorCount++;
430     }
431
432     if (!MergeAliases(into, from, merge))
433         into->errorCount++;
434     if (from->explicitMin != 0) {
435         if ((into->explicitMin == 0)
436             || (into->explicitMin > from->explicitMin))
437             into->explicitMin = from->explicitMin;
438     }
439     if (from->explicitMax > 0) {
440         if ((into->explicitMax == 0)
441             || (into->explicitMax < from->explicitMax))
442             into->explicitMax = from->explicitMax;
443     }
444 }
445
446 static void
447 HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge);
448
449 /**
450  * Handle the given include statement (e.g. "include "evdev+aliases(qwerty)").
451  *
452  * @param info Struct to store the key info in.
453  * @param stmt The include statement from the keymap file.
454  */
455 static bool
456 HandleIncludeKeycodes(KeyNamesInfo *info, IncludeStmt *stmt)
457 {
458     enum merge_mode merge = MERGE_DEFAULT;
459     XkbFile *rtrn;
460     KeyNamesInfo included, next_incl;
461
462     /* XXX: What's that? */
463     if (stmt->file && strcmp(stmt->file, "computed") == 0) {
464         info->keymap->flags |= AutoKeyNames;
465         info->explicitMin = 0;
466         info->explicitMax = XKB_KEYCODE_MAX;
467         return (info->errorCount == 0);
468     }
469
470     InitKeyNamesInfo(&included, info->keymap, info->file_id);
471     if (stmt->stmt) {
472         free(included.name);
473         included.name = stmt->stmt;
474         stmt->stmt = NULL;
475     }
476
477     for (; stmt; stmt = stmt->next) {
478         if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_KEYCODES,
479                                 &rtrn, &merge)) {
480             info->errorCount += 10;
481             ClearKeyNamesInfo(&included);
482             return false;
483         }
484
485         InitKeyNamesInfo(&next_incl, info->keymap, rtrn->id);
486
487         HandleKeycodesFile(&next_incl, rtrn, MERGE_OVERRIDE);
488
489         MergeIncludedKeycodes(&included, &next_incl, merge);
490
491         ClearKeyNamesInfo(&next_incl);
492         FreeXKBFile(rtrn);
493     }
494
495     MergeIncludedKeycodes(info, &included, merge);
496     ClearKeyNamesInfo(&included);
497
498     return (info->errorCount == 0);
499 }
500
501 /**
502  * Parse the given statement and store the output in the info struct.
503  * e.g. <ESC> = 9
504  */
505 static int
506 HandleKeycodeDef(KeyNamesInfo *info, KeycodeDef *stmt, enum merge_mode merge)
507 {
508     if ((info->explicitMin != 0 && stmt->value < info->explicitMin) ||
509         (info->explicitMax != 0 && stmt->value > info->explicitMax)) {
510         log_err(info->keymap->ctx,
511                 "Illegal keycode %lu for name <%s>; "
512                 "Must be in the range %d-%d inclusive\n",
513                 stmt->value, stmt->name, info->explicitMin,
514                 info->explicitMax ? info->explicitMax : XKB_KEYCODE_MAX);
515         return 0;
516     }
517     if (stmt->merge != MERGE_DEFAULT) {
518         if (stmt->merge == MERGE_REPLACE)
519             merge = MERGE_OVERRIDE;
520         else
521             merge = stmt->merge;
522     }
523     return AddKeyName(info, stmt->value, stmt->name, merge, info->file_id,
524                       true);
525 }
526
527 static void
528 HandleAliasCollision(KeyNamesInfo *info, AliasInfo *old, AliasInfo *new)
529 {
530     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
531
532     if (strncmp(new->real, old->real, XkbKeyNameLength) == 0) {
533         if ((new->file_id == old->file_id && verbosity > 0) || verbosity > 9)
534             log_warn(info->keymap->ctx,
535                      "Alias of %s for %s declared more than once; "
536                      "First definition ignored\n",
537                      XkbcKeyNameText(new->alias), XkbcKeyNameText(new->real));
538     }
539     else {
540         char *use, *ignore;
541
542         if (new->merge == MERGE_AUGMENT) {
543             use = old->real;
544             ignore = new->real;
545         }
546         else {
547             use = new->real;
548             ignore = old->real;
549         }
550
551         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
552             log_warn(info->keymap->ctx,
553                      "Multiple definitions for alias %s; "
554                      "Using %s, ignoring %s\n",
555                      XkbcKeyNameText(old->alias), XkbcKeyNameText(use),
556                      XkbcKeyNameText(ignore));
557
558         if (use != old->real)
559             memcpy(old->real, use, XkbKeyNameLength);
560     }
561
562     old->file_id = new->file_id;
563     old->merge = new->merge;
564 }
565
566 static int
567 HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge,
568                unsigned file_id)
569 {
570     AliasInfo *alias;
571
572     list_foreach(alias, &info->aliases, entry) {
573         if (strncmp(alias->alias, def->alias, XkbKeyNameLength) == 0) {
574             AliasInfo new;
575             InitAliasInfo(&new, merge, file_id, def->alias, def->real);
576             HandleAliasCollision(info, alias, &new);
577             return true;
578         }
579     }
580
581     alias = calloc(1, sizeof(*alias));
582     if (!alias) {
583         log_wsgo(info->keymap->ctx, "Allocation failure in HandleAliasDef\n");
584         return false;
585     }
586
587     alias->file_id = file_id;
588     alias->merge = merge;
589     memcpy(alias->alias, def->alias, XkbKeyNameLength);
590     memcpy(alias->real, def->real, XkbKeyNameLength);
591     list_append(&alias->entry, &info->aliases);
592
593     return true;
594 }
595
596 #define MIN_KEYCODE_DEF 0
597 #define MAX_KEYCODE_DEF 1
598
599 /**
600  * Handle the minimum/maximum statement of the xkb file.
601  * Sets explicitMin/Max of the info struct.
602  *
603  * @return 1 on success, 0 otherwise.
604  */
605 static int
606 HandleKeyNameVar(KeyNamesInfo *info, VarDef *stmt)
607 {
608     ExprResult tmp, field;
609     ExprDef *arrayNdx;
610     int which;
611
612     if (ExprResolveLhs(info->keymap, stmt->name, &tmp, &field,
613                        &arrayNdx) == 0)
614         return 0;               /* internal error, already reported */
615
616     if (tmp.str != NULL) {
617         log_err(info->keymap->ctx,
618                 "Unknown element %s encountered; "
619                 "Default for field %s ignored\n", tmp.str, field.str);
620         goto err_out;
621     }
622
623     if (strcasecmp(field.str, "minimum") == 0)
624         which = MIN_KEYCODE_DEF;
625     else if (strcasecmp(field.str, "maximum") == 0)
626         which = MAX_KEYCODE_DEF;
627     else {
628         log_err(info->keymap->ctx,
629                 "Unknown field encountered; "
630                 "Assigment to field %s ignored\n", field.str);
631         goto err_out;
632     }
633
634     if (arrayNdx != NULL) {
635         log_err(info->keymap->ctx,
636                 "The %s setting is not an array; "
637                 "Illegal array reference ignored\n", field.str);
638         goto err_out;
639     }
640
641     if (ExprResolveKeyCode(info->keymap->ctx, stmt->value, &tmp) == 0) {
642         log_err(info->keymap->ctx,
643                 "Illegal keycode encountered; "
644                 "Assignment to field %s ignored\n", field.str);
645         goto err_out;
646     }
647
648     if (tmp.uval > XKB_KEYCODE_MAX) {
649         log_err(info->keymap->ctx,
650                 "Illegal keycode %d (must be in the range %d-%d inclusive); "
651                 "Value of \"%s\" not changed\n",
652                 tmp.uval, 0, XKB_KEYCODE_MAX, field.str);
653         goto err_out;
654     }
655
656     if (which == MIN_KEYCODE_DEF) {
657         if ((info->explicitMax > 0) && (info->explicitMax < tmp.uval)) {
658             log_err(info->keymap->ctx,
659                     "Minimum key code (%d) must be <= maximum key code (%d); "
660                     "Minimum key code value not changed\n",
661                     tmp.uval, info->explicitMax);
662             goto err_out;
663         }
664         if ((info->computedMax > 0) && (info->computedMin < tmp.uval)) {
665             log_err(info->keymap->ctx,
666                     "Minimum key code (%d) must be <= lowest defined key (%d); "
667                     "Minimum key code value not changed\n",
668                     tmp.uval, info->computedMin);
669             goto err_out;
670         }
671         info->explicitMin = tmp.uval;
672     }
673
674     if (which == MAX_KEYCODE_DEF) {
675         if ((info->explicitMin > 0) && (info->explicitMin > tmp.uval)) {
676             log_err(info->keymap->ctx,
677                     "Maximum code (%d) must be >= minimum key code (%d); "
678                     "Maximum code value not changed\n",
679                     tmp.uval, info->explicitMin);
680             goto err_out;
681         }
682         if ((info->computedMax > 0) && (info->computedMax > tmp.uval)) {
683             log_err(info->keymap->ctx,
684                     "Maximum code (%d) must be >= highest defined key (%d); "
685                     "Maximum code value not changed\n",
686                     tmp.uval, info->computedMax);
687             goto err_out;
688         }
689         info->explicitMax = tmp.uval;
690     }
691
692     free(field.str);
693     return 1;
694
695 err_out:
696     free(field.str);
697     return 0;
698 }
699
700 static int
701 HandleIndicatorNameDef(KeyNamesInfo *info, IndicatorNameDef *def,
702                        enum merge_mode merge)
703 {
704     IndicatorNameInfo ii;
705     ExprResult tmp;
706
707     if ((def->ndx < 1) || (def->ndx > XkbNumIndicators)) {
708         info->errorCount++;
709         log_err(info->keymap->ctx,
710                 "Name specified for illegal indicator index %d\n; Ignored\n",
711                 def->ndx);
712         return false;
713     }
714     InitIndicatorNameInfo(&ii, info);
715     ii.ndx = def->ndx;
716     if (!ExprResolveString(info->keymap->ctx, def->name, &tmp)) {
717         char buf[20];
718         snprintf(buf, sizeof(buf), "%d", def->ndx);
719         info->errorCount++;
720         return ReportBadType(info->keymap, "indicator", "name", buf,
721                              "string");
722     }
723     ii.name = xkb_atom_intern(info->keymap->ctx, tmp.str);
724     free(tmp.str);
725     ii.virtual = def->virtual;
726     if (!AddIndicatorName(info, merge, &ii))
727         return false;
728     return true;
729 }
730
731 /**
732  * Handle the xkb_keycodes section of a xkb file.
733  * All information about parsed keys is stored in the info struct.
734  *
735  * Such a section may have include statements, in which case this function is
736  * semi-recursive (it calls HandleIncludeKeycodes, which may call
737  * HandleKeycodesFile again).
738  *
739  * @param info Struct to contain the fully parsed key information.
740  * @param file The input file (parsed xkb_keycodes section)
741  * @param merge Merge strategy (MERGE_OVERRIDE, etc.)
742  */
743 static void
744 HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge)
745 {
746     ParseCommon *stmt;
747
748     free(info->name);
749     info->name = uDupString(file->name);
750     stmt = file->defs;
751     while (stmt)
752     {
753         switch (stmt->stmtType) {
754         case StmtInclude:    /* e.g. include "evdev+aliases(qwerty)" */
755             if (!HandleIncludeKeycodes(info, (IncludeStmt *) stmt))
756                 info->errorCount++;
757             break;
758         case StmtKeycodeDef: /* e.g. <ESC> = 9; */
759             if (!HandleKeycodeDef(info, (KeycodeDef *) stmt, merge))
760                 info->errorCount++;
761             break;
762         case StmtKeyAliasDef: /* e.g. alias <MENU> = <COMP>; */
763             if (!HandleAliasDef(info, (KeyAliasDef *) stmt, merge,
764                                 info->file_id))
765                 info->errorCount++;
766             break;
767         case StmtVarDef: /* e.g. minimum, maximum */
768             if (!HandleKeyNameVar(info, (VarDef *) stmt))
769                 info->errorCount++;
770             break;
771         case StmtIndicatorNameDef: /* e.g. indicator 1 = "Caps Lock"; */
772             if (!HandleIndicatorNameDef(info, (IndicatorNameDef *) stmt,
773                                         merge))
774                 info->errorCount++;
775             break;
776         case StmtInterpDef:
777         case StmtVModDef:
778             log_err(info->keymap->ctx,
779                     "Keycode files may define key and indicator names only; "
780                     "Ignoring definition of %s\n",
781                     (stmt->stmtType == StmtInterpDef ?
782                      "a symbol interpretation" : "virtual modifiers"));
783             info->errorCount++;
784             break;
785         default:
786             log_wsgo(info->keymap->ctx,
787                      "Unexpected statement type %d in HandleKeycodesFile\n",
788                      stmt->stmtType);
789             break;
790         }
791         stmt = stmt->next;
792         if (info->errorCount > 10) {
793             log_err(info->keymap->ctx, "Abandoning keycodes file \"%s\"\n",
794                     file->topName);
795             break;
796         }
797     }
798 }
799
800 static int
801 ApplyAliases(KeyNamesInfo *info)
802 {
803     int i;
804     struct xkb_key *key;
805     struct xkb_key_alias *old, *a;
806     AliasInfo *alias, *next;
807     int nNew = 0, nOld;
808     struct xkb_keymap *keymap = info->keymap;
809
810     nOld = darray_size(keymap->key_aliases);
811     old = &darray_item(keymap->key_aliases, 0);
812
813     list_foreach(alias, &info->aliases, entry) {
814         unsigned long lname;
815
816         lname = KeyNameToLong(alias->real);
817         key = FindNamedKey(keymap, lname, false, CreateKeyNames(keymap), 0);
818         if (!key) {
819             log_lvl(info->keymap->ctx, 5,
820                     "Attempt to alias %s to non-existent key %s; "
821                     "Ignored\n",
822                     XkbcKeyNameText(alias->alias),
823                     XkbcKeyNameText(alias->real));
824             alias->alias[0] = '\0';
825             continue;
826         }
827
828         lname = KeyNameToLong(alias->alias);
829         key = FindNamedKey(keymap, lname, false, false, 0);
830         if (key) {
831             log_lvl(info->keymap->ctx, 5,
832                     "Attempt to create alias with the name of a real key; "
833                     "Alias \"%s = %s\" ignored\n",
834                     XkbcKeyNameText(alias->alias),
835                     XkbcKeyNameText(alias->real));
836             alias->alias[0] = '\0';
837             continue;
838         }
839
840         nNew++;
841
842         if (!old)
843             continue;
844
845         for (i = 0, a = old; i < nOld; i++, a++) {
846             AliasInfo old_alias;
847
848             if (strncmp(a->alias, alias->alias, XkbKeyNameLength) != 0)
849                 continue;
850
851             InitAliasInfo(&old_alias, MERGE_AUGMENT, 0, a->alias, a->real);
852             HandleAliasCollision(info, &old_alias, alias);
853             memcpy(old_alias.real, a->real, XkbKeyNameLength);
854             alias->alias[0] = '\0';
855             nNew--;
856             break;
857         }
858     }
859
860     if (nNew == 0)
861         goto out;
862
863     darray_resize0(keymap->key_aliases, nOld + nNew);
864
865     a = &darray_item(keymap->key_aliases, nOld);
866     list_foreach(alias, &info->aliases, entry) {
867         if (alias->alias[0] != '\0') {
868             strncpy(a->alias, alias->alias, XkbKeyNameLength);
869             strncpy(a->real, alias->real, XkbKeyNameLength);
870             a++;
871         }
872     }
873
874 out:
875     list_foreach_safe(alias, next, &info->aliases, entry)
876         free(alias);
877     list_init(&info->aliases);
878     return true;
879 }
880
881 /**
882  * Compile the xkb_keycodes section, parse it's output, return the results.
883  *
884  * @param file The parsed XKB file (may have include statements requiring
885  * further parsing)
886  * @param result The effective keycodes, as gathered from the file.
887  * @param merge Merge strategy.
888  *
889  * @return true on success, false otherwise.
890  */
891 bool
892 CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap,
893                 enum merge_mode merge)
894 {
895     xkb_keycode_t kc;
896     KeyNamesInfo info; /* contains all the info after parsing */
897     IndicatorNameInfo *ii;
898
899     InitKeyNamesInfo(&info, keymap, file->id);
900
901     HandleKeycodesFile(&info, file, merge);
902
903     /* all the keys are now stored in info */
904
905     if (info.errorCount != 0)
906         goto err_info;
907
908     if (info.explicitMin > 0) /* if "minimum" statement was present */
909         keymap->min_key_code = info.explicitMin;
910     else
911         keymap->min_key_code = info.computedMin;
912
913     if (info.explicitMax > 0) /* if "maximum" statement was present */
914         keymap->max_key_code = info.explicitMax;
915     else
916         keymap->max_key_code = info.computedMax;
917
918     darray_resize0(keymap->keys, keymap->max_key_code + 1);
919     for (kc = info.computedMin; kc <= info.computedMax; kc++)
920         LongToKeyName(darray_item(info.names, kc),
921                       XkbKey(keymap, kc)->name);
922
923     if (info.name)
924         keymap->keycodes_section_name = strdup(info.name);
925
926     list_foreach(ii, &info.leds, entry) {
927         free(keymap->indicator_names[ii->ndx - 1]);
928         keymap->indicator_names[ii->ndx - 1] =
929             xkb_atom_strdup(keymap->ctx, ii->name);
930     }
931
932     ApplyAliases(&info);
933
934     ClearKeyNamesInfo(&info);
935     return true;
936
937 err_info:
938     ClearKeyNamesInfo(&info);
939     return false;
940 }