Fix fileID mess
[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 "keycodes.h"
28 #include "expr.h"
29 #include "parseutils.h"
30 #include "alias.h"
31
32 const char *
33 longText(unsigned long val)
34 {
35     char buf[4];
36
37     LongToKeyName(val, buf);
38     return XkbcKeyNameText(buf);
39 }
40
41 /***====================================================================***/
42
43 void
44 LongToKeyName(unsigned long val, char *name)
45 {
46     name[0] = ((val >> 24) & 0xff);
47     name[1] = ((val >> 16) & 0xff);
48     name[2] = ((val >> 8) & 0xff);
49     name[3] = (val & 0xff);
50 }
51
52 /***====================================================================***/
53
54 typedef struct _IndicatorNameInfo
55 {
56     CommonInfo defs;
57     int ndx;
58     xkb_atom_t name;
59     bool virtual;
60 } IndicatorNameInfo;
61
62 typedef struct _KeyNamesInfo
63 {
64     char *name;     /* e.g. evdev+aliases(qwerty) */
65     int errorCount;
66     unsigned file_id;
67     enum merge_mode merge;
68     xkb_keycode_t computedMin; /* lowest keycode stored */
69     xkb_keycode_t computedMax; /* highest keycode stored */
70     xkb_keycode_t explicitMin;
71     xkb_keycode_t explicitMax;
72     darray(unsigned long) names;
73     darray(unsigned int) files;
74     IndicatorNameInfo *leds;
75     AliasInfo *aliases;
76 } KeyNamesInfo;
77
78 static void HandleKeycodesFile(XkbFile *file, struct xkb_keymap *keymap,
79                                enum merge_mode merge, KeyNamesInfo *info);
80
81 static void
82 ResizeKeyNameArrays(KeyNamesInfo *info, int newMax)
83 {
84     if (newMax < darray_size(info->names))
85         return;
86
87     darray_resize0(info->names, newMax + 1);
88     darray_resize0(info->files, newMax + 1);
89 }
90
91 static void
92 InitIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info)
93 {
94     ii->defs.defined = 0;
95     ii->defs.merge = info->merge;
96     ii->defs.file_id = info->file_id;
97     ii->defs.next = NULL;
98     ii->ndx = 0;
99     ii->name = XKB_ATOM_NONE;
100     ii->virtual = false;
101 }
102
103 static void
104 ClearIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info)
105 {
106     if (ii == info->leds)
107     {
108         ClearCommonInfo(&ii->defs);
109         info->leds = NULL;
110     }
111 }
112
113 static IndicatorNameInfo *
114 NextIndicatorName(KeyNamesInfo * info)
115 {
116     IndicatorNameInfo *ii;
117
118     ii = uTypedAlloc(IndicatorNameInfo);
119     if (ii)
120     {
121         InitIndicatorNameInfo(ii, info);
122         info->leds = AddCommonInfo(&info->leds->defs, &ii->defs);
123     }
124     return ii;
125 }
126
127 static IndicatorNameInfo *
128 FindIndicatorByIndex(KeyNamesInfo * info, int ndx)
129 {
130     IndicatorNameInfo *old;
131
132     for (old = info->leds; old != NULL;
133          old = (IndicatorNameInfo *) old->defs.next)
134     {
135         if (old->ndx == ndx)
136             return old;
137     }
138     return NULL;
139 }
140
141 static IndicatorNameInfo *
142 FindIndicatorByName(KeyNamesInfo * info, xkb_atom_t name)
143 {
144     IndicatorNameInfo *old;
145
146     for (old = info->leds; old != NULL;
147          old = (IndicatorNameInfo *) old->defs.next)
148     {
149         if (old->name == name)
150             return old;
151     }
152     return NULL;
153 }
154
155 static bool
156 AddIndicatorName(KeyNamesInfo *info, struct xkb_keymap *keymap, enum merge_mode merge,
157                  IndicatorNameInfo *new)
158 {
159     IndicatorNameInfo *old;
160     bool replace;
161
162     replace = (merge == MERGE_REPLACE) || (merge == MERGE_OVERRIDE);
163     old = FindIndicatorByName(info, new->name);
164     if (old)
165     {
166         if (((old->defs.file_id == new->defs.file_id) && (warningLevel > 0))
167             || (warningLevel > 9))
168         {
169             WARN("Multiple indicators named %s\n",
170                  xkb_atom_text(keymap->ctx, new->name));
171             if (old->ndx == new->ndx)
172             {
173                 if (old->virtual != new->virtual)
174                 {
175                     if (replace)
176                         old->virtual = new->virtual;
177                     ACTION("Using %s instead of %s\n",
178                            (old->virtual ? "virtual" : "real"),
179                            (old->virtual ? "real" : "virtual"));
180                 }
181                 else
182                 {
183                     ACTION("Identical definitions ignored\n");
184                 }
185                 return true;
186             }
187             else
188             {
189                 if (replace)
190                     ACTION("Ignoring %d, using %d\n", old->ndx, new->ndx);
191                 else
192                     ACTION("Using %d, ignoring %d\n", old->ndx, new->ndx);
193             }
194             if (replace)
195             {
196                 if (info->leds == old)
197                     info->leds = (IndicatorNameInfo *) old->defs.next;
198                 else
199                 {
200                     IndicatorNameInfo *tmp;
201                     tmp = info->leds;
202                     for (; tmp != NULL;
203                          tmp = (IndicatorNameInfo *) tmp->defs.next)
204                     {
205                         if (tmp->defs.next == (CommonInfo *) old)
206                         {
207                             tmp->defs.next = old->defs.next;
208                             break;
209                         }
210                     }
211                 }
212                 free(old);
213             }
214         }
215     }
216     old = FindIndicatorByIndex(info, new->ndx);
217     if (old)
218     {
219         if (((old->defs.file_id == new->defs.file_id) && (warningLevel > 0))
220             || (warningLevel > 9))
221         {
222             WARN("Multiple names for indicator %d\n", new->ndx);
223             if ((old->name == new->name) && (old->virtual == new->virtual))
224                 ACTION("Identical definitions ignored\n");
225             else
226             {
227                 const char *oldType, *newType;
228                 xkb_atom_t using, ignoring;
229                 if (old->virtual)
230                     oldType = "virtual indicator";
231                 else
232                     oldType = "real indicator";
233                 if (new->virtual)
234                     newType = "virtual indicator";
235                 else
236                     newType = "real indicator";
237                 if (replace)
238                 {
239                     using = new->name;
240                     ignoring = old->name;
241                 }
242                 else
243                 {
244                     using = old->name;
245                     ignoring = new->name;
246                 }
247                 ACTION("Using %s %s, ignoring %s %s\n",
248                         oldType, xkb_atom_text(keymap->ctx, using),
249                         newType, xkb_atom_text(keymap->ctx, ignoring));
250             }
251         }
252         if (replace)
253         {
254             old->name = new->name;
255             old->virtual = new->virtual;
256         }
257         return true;
258     }
259     old = new;
260     new = NextIndicatorName(info);
261     if (!new)
262     {
263         WSGO("Couldn't allocate name for indicator %d\n", old->ndx);
264         ACTION("Ignored\n");
265         return false;
266     }
267     new->name = old->name;
268     new->ndx = old->ndx;
269     new->virtual = old->virtual;
270     return true;
271 }
272
273 static void
274 ClearKeyNamesInfo(KeyNamesInfo * info)
275 {
276     free(info->name);
277     info->name = NULL;
278     info->computedMax = info->explicitMax = info->explicitMin = 0;
279     info->computedMin = XKB_KEYCODE_MAX;
280     darray_free(info->names);
281     darray_free(info->files);
282     if (info->leds)
283         ClearIndicatorNameInfo(info->leds, info);
284     if (info->aliases)
285         ClearAliases(&info->aliases);
286 }
287
288 static void
289 InitKeyNamesInfo(KeyNamesInfo * info, unsigned file_id)
290 {
291     info->name = NULL;
292     info->leds = NULL;
293     info->aliases = NULL;
294     info->file_id = file_id;
295     darray_init(info->names);
296     darray_init(info->files);
297     ClearKeyNamesInfo(info);
298     info->errorCount = 0;
299 }
300
301 static int
302 FindKeyByLong(KeyNamesInfo * info, unsigned long name)
303 {
304     uint64_t i;
305
306     for (i = info->computedMin; i <= info->computedMax; i++)
307         if (darray_item(info->names, i) == name)
308             return i;
309
310     return 0;
311 }
312
313 /**
314  * Store the name of the key as a long in the info struct under the given
315  * keycode. If the same keys is referred to twice, print a warning.
316  * Note that the key's name is stored as a long, the keycode is the index.
317  */
318 static bool
319 AddKeyName(KeyNamesInfo * info,
320            xkb_keycode_t kc, char *name, enum merge_mode merge,
321            unsigned file_id, bool reportCollisions)
322 {
323     xkb_keycode_t old;
324     unsigned long lval;
325
326     ResizeKeyNameArrays(info, kc);
327
328     if (kc < info->computedMin)
329         info->computedMin = kc;
330     if (kc > info->computedMax)
331         info->computedMax = kc;
332     lval = KeyNameToLong(name);
333
334     if (reportCollisions)
335     {
336         reportCollisions = (warningLevel > 7 ||
337                             (warningLevel > 0 &&
338                              file_id == darray_item(info->files, kc)));
339     }
340
341     if (darray_item(info->names, kc) != 0)
342     {
343         char buf[6];
344
345         LongToKeyName(darray_item(info->names, kc), buf);
346         buf[4] = '\0';
347         if (darray_item(info->names, kc) == lval && reportCollisions)
348         {
349             WARN("Multiple identical key name definitions\n");
350             ACTION("Later occurences of \"<%s> = %d\" ignored\n",
351                    buf, kc);
352             return true;
353         }
354         if (merge == MERGE_AUGMENT)
355         {
356             if (reportCollisions)
357             {
358                 WARN("Multiple names for keycode %d\n", kc);
359                 ACTION("Using <%s>, ignoring <%s>\n", buf, name);
360             }
361             return true;
362         }
363         else
364         {
365             if (reportCollisions)
366             {
367                 WARN("Multiple names for keycode %d\n", kc);
368                 ACTION("Using <%s>, ignoring <%s>\n", name, buf);
369             }
370             darray_item(info->names, kc) = 0;
371             darray_item(info->files, kc) = 0;
372         }
373     }
374     old = FindKeyByLong(info, lval);
375     if ((old != 0) && (old != kc))
376     {
377         if (merge == MERGE_OVERRIDE)
378         {
379             darray_item(info->names, old) = 0;
380             darray_item(info->files, old) = 0;
381             if (reportCollisions)
382             {
383                 WARN("Key name <%s> assigned to multiple keys\n", name);
384                 ACTION("Using %d, ignoring %d\n", kc, old);
385             }
386         }
387         else
388         {
389             if ((reportCollisions) && (warningLevel > 3))
390             {
391                 WARN("Key name <%s> assigned to multiple keys\n", name);
392                 ACTION("Using %d, ignoring %d\n", old, kc);
393             }
394             return true;
395         }
396     }
397     darray_item(info->names, kc) = lval;
398     darray_item(info->files, kc) = file_id;
399     return true;
400 }
401
402 /***====================================================================***/
403
404 static void
405 MergeIncludedKeycodes(KeyNamesInfo *into, struct xkb_keymap *keymap,
406                       KeyNamesInfo *from, enum merge_mode merge)
407 {
408     uint64_t i;
409     char buf[5];
410
411     if (from->errorCount > 0)
412     {
413         into->errorCount += from->errorCount;
414         return;
415     }
416     if (into->name == NULL)
417     {
418         into->name = from->name;
419         from->name = NULL;
420     }
421
422     ResizeKeyNameArrays(into, from->computedMax);
423
424     for (i = from->computedMin; i <= from->computedMax; i++)
425     {
426         if (darray_item(from->names, i) == 0)
427             continue;
428         LongToKeyName(darray_item(from->names, i), buf);
429         buf[4] = '\0';
430         if (!AddKeyName(into, i, buf, merge, from->file_id, false))
431             into->errorCount++;
432     }
433     if (from->leds)
434     {
435         IndicatorNameInfo *led, *next;
436         for (led = from->leds; led != NULL; led = next)
437         {
438             if (merge != MERGE_DEFAULT)
439                 led->defs.merge = merge;
440             if (!AddIndicatorName(into, keymap, led->defs.merge, led))
441                 into->errorCount++;
442             next = (IndicatorNameInfo *) led->defs.next;
443         }
444     }
445     if (!MergeAliases(&into->aliases, &from->aliases, merge))
446         into->errorCount++;
447     if (from->explicitMin != 0)
448     {
449         if ((into->explicitMin == 0)
450             || (into->explicitMin > from->explicitMin))
451             into->explicitMin = from->explicitMin;
452     }
453     if (from->explicitMax > 0)
454     {
455         if ((into->explicitMax == 0)
456             || (into->explicitMax < from->explicitMax))
457             into->explicitMax = from->explicitMax;
458     }
459 }
460
461 /**
462  * Handle the given include statement (e.g. "include "evdev+aliases(qwerty)").
463  *
464  * @param stmt The include statement from the keymap file.
465  * @param keymap Unused for all but the keymap->flags.
466  * @param info Struct to store the key info in.
467  */
468 static bool
469 HandleIncludeKeycodes(IncludeStmt *stmt, struct xkb_keymap *keymap,
470                       KeyNamesInfo *info)
471 {
472     unsigned newMerge;
473     XkbFile *rtrn;
474     KeyNamesInfo included;
475     bool haveSelf;
476
477     memset(&included, 0, sizeof(included));
478
479     haveSelf = false;
480     if ((stmt->file == NULL) && (stmt->map == NULL))
481     {
482         haveSelf = true;
483         included = *info;
484         memset(info, 0, sizeof(KeyNamesInfo));
485     }
486     else if (stmt->file && strcmp(stmt->file, "computed") == 0)
487     {
488         keymap->flags |= AutoKeyNames;
489         info->explicitMin = 0;
490         info->explicitMax = XKB_KEYCODE_MAX;
491         return (info->errorCount == 0);
492     } /* parse file, store returned info in the xkb struct */
493     else if (ProcessIncludeFile(keymap->ctx, stmt, FILE_TYPE_KEYCODES, &rtrn,
494                                 &newMerge))
495     {
496         InitKeyNamesInfo(&included, rtrn->id);
497         HandleKeycodesFile(rtrn, keymap, MERGE_OVERRIDE, &included);
498         if (stmt->stmt != NULL)
499         {
500             free(included.name);
501             included.name = stmt->stmt;
502             stmt->stmt = NULL;
503         }
504         FreeXKBFile(rtrn);
505     }
506     else
507     {
508         info->errorCount += 10; /* XXX: why 10?? */
509         return false;
510     }
511     /* Do we have more than one include statement? */
512     if ((stmt->next != NULL) && (included.errorCount < 1))
513     {
514         IncludeStmt *next;
515         unsigned op;
516         KeyNamesInfo next_incl;
517
518         for (next = stmt->next; next != NULL; next = next->next)
519         {
520             if ((next->file == NULL) && (next->map == NULL))
521             {
522                 haveSelf = true;
523                 MergeIncludedKeycodes(&included, keymap, info, next->merge);
524                 ClearKeyNamesInfo(info);
525             }
526             else if (ProcessIncludeFile(keymap->ctx, next, FILE_TYPE_KEYCODES,
527                                         &rtrn, &op))
528             {
529                 InitKeyNamesInfo(&next_incl, rtrn->id);
530                 HandleKeycodesFile(rtrn, keymap, MERGE_OVERRIDE, &next_incl);
531                 MergeIncludedKeycodes(&included, keymap, &next_incl, op);
532                 ClearKeyNamesInfo(&next_incl);
533                 FreeXKBFile(rtrn);
534             }
535             else
536             {
537                 info->errorCount += 10; /* XXX: Why 10?? */
538                 ClearKeyNamesInfo(&included);
539                 return false;
540             }
541         }
542     }
543     if (haveSelf)
544         *info = included;
545     else
546     {
547         MergeIncludedKeycodes(info, keymap, &included, newMerge);
548         ClearKeyNamesInfo(&included);
549     }
550     return (info->errorCount == 0);
551 }
552
553 /**
554  * Parse the given statement and store the output in the info struct.
555  * e.g. <ESC> = 9
556  */
557 static int
558 HandleKeycodeDef(KeycodeDef *stmt, enum merge_mode merge, KeyNamesInfo *info)
559 {
560     if ((info->explicitMin != 0 && stmt->value < info->explicitMin) ||
561         (info->explicitMax != 0 && stmt->value > info->explicitMax))
562     {
563         ERROR("Illegal keycode %lu for name <%s>\n", stmt->value, stmt->name);
564         ACTION("Must be in the range %d-%d inclusive\n",
565                 info->explicitMin,
566                 info->explicitMax ? info->explicitMax : XKB_KEYCODE_MAX);
567         return 0;
568     }
569     if (stmt->merge != MERGE_DEFAULT)
570     {
571         if (stmt->merge == MERGE_REPLACE)
572             merge = MERGE_OVERRIDE;
573         else
574             merge = stmt->merge;
575     }
576     return AddKeyName(info, stmt->value, stmt->name, merge, info->file_id,
577                       true);
578 }
579
580 #define MIN_KEYCODE_DEF         0
581 #define MAX_KEYCODE_DEF         1
582
583 /**
584  * Handle the minimum/maximum statement of the xkb file.
585  * Sets explicitMin/Max of the info struct.
586  *
587  * @return 1 on success, 0 otherwise.
588  */
589 static int
590 HandleKeyNameVar(VarDef *stmt, struct xkb_keymap *keymap, KeyNamesInfo *info)
591 {
592     ExprResult tmp, field;
593     ExprDef *arrayNdx;
594     int which;
595
596     if (ExprResolveLhs(keymap, stmt->name, &tmp, &field, &arrayNdx) == 0)
597         return 0;               /* internal error, already reported */
598
599     if (tmp.str != NULL)
600     {
601         ERROR("Unknown element %s encountered\n", tmp.str);
602         ACTION("Default for field %s ignored\n", field.str);
603         goto err_out;
604     }
605     if (strcasecmp(field.str, "minimum") == 0)
606         which = MIN_KEYCODE_DEF;
607     else if (strcasecmp(field.str, "maximum") == 0)
608         which = MAX_KEYCODE_DEF;
609     else
610     {
611         ERROR("Unknown field encountered\n");
612         ACTION("Assigment to field %s ignored\n", field.str);
613         goto err_out;
614     }
615     if (arrayNdx != NULL)
616     {
617         ERROR("The %s setting is not an array\n", field.str);
618         ACTION("Illegal array reference ignored\n");
619         goto err_out;
620     }
621
622     if (ExprResolveKeyCode(keymap->ctx, stmt->value, &tmp) == 0)
623     {
624         ACTION("Assignment to field %s ignored\n", field.str);
625         goto err_out;
626     }
627     if (tmp.uval > XKB_KEYCODE_MAX)
628     {
629         ERROR
630             ("Illegal keycode %d (must be in the range %d-%d inclusive)\n",
631              tmp.uval, 0, XKB_KEYCODE_MAX);
632         ACTION("Value of \"%s\" not changed\n", field.str);
633         goto err_out;
634     }
635     if (which == MIN_KEYCODE_DEF)
636     {
637         if ((info->explicitMax > 0) && (info->explicitMax < tmp.uval))
638         {
639             ERROR
640                 ("Minimum key code (%d) must be <= maximum key code (%d)\n",
641                  tmp.uval, info->explicitMax);
642             ACTION("Minimum key code value not changed\n");
643             goto err_out;
644         }
645         if ((info->computedMax > 0) && (info->computedMin < tmp.uval))
646         {
647             ERROR
648                 ("Minimum key code (%d) must be <= lowest defined key (%d)\n",
649                  tmp.uval, info->computedMin);
650             ACTION("Minimum key code value not changed\n");
651             goto err_out;
652         }
653         info->explicitMin = tmp.uval;
654     }
655     if (which == MAX_KEYCODE_DEF)
656     {
657         if ((info->explicitMin > 0) && (info->explicitMin > tmp.uval))
658         {
659             ERROR("Maximum code (%d) must be >= minimum key code (%d)\n",
660                    tmp.uval, info->explicitMin);
661             ACTION("Maximum code value not changed\n");
662             goto err_out;
663         }
664         if ((info->computedMax > 0) && (info->computedMax > tmp.uval))
665         {
666             ERROR
667                 ("Maximum code (%d) must be >= highest defined key (%d)\n",
668                  tmp.uval, info->computedMax);
669             ACTION("Maximum code value not changed\n");
670             goto err_out;
671         }
672         info->explicitMax = tmp.uval;
673     }
674
675     free(field.str);
676     return 1;
677
678 err_out:
679     free(field.str);
680     return 0;
681 }
682
683 static int
684 HandleIndicatorNameDef(IndicatorNameDef *def, struct xkb_keymap *keymap,
685                        enum merge_mode merge, KeyNamesInfo *info)
686 {
687     IndicatorNameInfo ii;
688     ExprResult tmp;
689
690     if ((def->ndx < 1) || (def->ndx > XkbNumIndicators))
691     {
692         info->errorCount++;
693         ERROR("Name specified for illegal indicator index %d\n", def->ndx);
694         ACTION("Ignored\n");
695         return false;
696     }
697     InitIndicatorNameInfo(&ii, info);
698     ii.ndx = def->ndx;
699     if (!ExprResolveString(keymap->ctx, def->name, &tmp))
700     {
701         char buf[20];
702         snprintf(buf, sizeof(buf), "%d", def->ndx);
703         info->errorCount++;
704         return ReportBadType("indicator", "name", buf, "string");
705     }
706     ii.name = xkb_atom_intern(keymap->ctx, tmp.str);
707     free(tmp.str);
708     ii.virtual = def->virtual;
709     if (!AddIndicatorName(info, keymap, merge, &ii))
710         return false;
711     return true;
712 }
713
714 /**
715  * Handle the xkb_keycodes section of a xkb file.
716  * All information about parsed keys is stored in the info struct.
717  *
718  * Such a section may have include statements, in which case this function is
719  * semi-recursive (it calls HandleIncludeKeycodes, which may call
720  * HandleKeycodesFile again).
721  *
722  * @param file The input file (parsed xkb_keycodes section)
723  * @param xkb Necessary to pass down, may have flags changed.
724  * @param merge Merge strategy (MERGE_OVERRIDE, etc.)
725  * @param info Struct to contain the fully parsed key information.
726  */
727 static void
728 HandleKeycodesFile(XkbFile *file, struct xkb_keymap *keymap,
729                    enum merge_mode merge, KeyNamesInfo *info)
730 {
731     ParseCommon *stmt;
732
733     free(info->name);
734     info->name = uDupString(file->name);
735     stmt = file->defs;
736     while (stmt)
737     {
738         switch (stmt->stmtType)
739         {
740         case StmtInclude:    /* e.g. include "evdev+aliases(qwerty)" */
741             if (!HandleIncludeKeycodes((IncludeStmt *) stmt, keymap, info))
742                 info->errorCount++;
743             break;
744         case StmtKeycodeDef: /* e.g. <ESC> = 9; */
745             if (!HandleKeycodeDef((KeycodeDef *) stmt, merge, info))
746                 info->errorCount++;
747             break;
748         case StmtKeyAliasDef: /* e.g. alias <MENU> = <COMP>; */
749             if (!HandleAliasDef((KeyAliasDef *) stmt, merge, info->file_id,
750                                 &info->aliases))
751                 info->errorCount++;
752             break;
753         case StmtVarDef: /* e.g. minimum, maximum */
754             if (!HandleKeyNameVar((VarDef *) stmt, keymap, info))
755                 info->errorCount++;
756             break;
757         case StmtIndicatorNameDef: /* e.g. indicator 1 = "Caps Lock"; */
758             if (!HandleIndicatorNameDef((IndicatorNameDef *) stmt, keymap,
759                                         merge, info))
760                 info->errorCount++;
761             break;
762         case StmtInterpDef:
763         case StmtVModDef:
764             ERROR("Keycode files may define key and indicator names only\n");
765             ACTION("Ignoring definition of %s\n",
766                     ((stmt->stmtType ==
767                       StmtInterpDef) ? "a symbol interpretation" :
768                      "virtual modifiers"));
769             info->errorCount++;
770             break;
771         default:
772             WSGO("Unexpected statement type %d in HandleKeycodesFile\n",
773                   stmt->stmtType);
774             break;
775         }
776         stmt = stmt->next;
777         if (info->errorCount > 10)
778         {
779 #ifdef NOISY
780             ERROR("Too many errors\n");
781 #endif
782             ACTION("Abandoning keycodes file \"%s\"\n", file->topName);
783             break;
784         }
785     }
786 }
787
788 /**
789  * Compile the xkb_keycodes section, parse it's output, return the results.
790  *
791  * @param file The parsed XKB file (may have include statements requiring
792  * further parsing)
793  * @param result The effective keycodes, as gathered from the file.
794  * @param merge Merge strategy.
795  *
796  * @return true on success, false otherwise.
797  */
798 bool
799 CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
800 {
801     KeyNamesInfo info; /* contains all the info after parsing */
802
803     InitKeyNamesInfo(&info, file->id);
804
805     HandleKeycodesFile(file, keymap, merge, &info);
806
807     /* all the keys are now stored in info */
808
809     if (info.errorCount != 0)
810         goto err_info;
811
812     if (info.explicitMin > 0) /* if "minimum" statement was present */
813         keymap->min_key_code = info.explicitMin;
814     else
815         keymap->min_key_code = info.computedMin;
816
817     if (info.explicitMax > 0) /* if "maximum" statement was present */
818         keymap->max_key_code = info.explicitMax;
819     else
820         keymap->max_key_code = info.computedMax;
821
822     if (XkbcAllocNames(keymap, XkbKeyNamesMask | XkbIndicatorNamesMask, 0)
823         == Success) {
824         uint64_t i;
825         for (i = info.computedMin; i <= info.computedMax; i++)
826             LongToKeyName(darray_item(info.names, i),
827                           darray_item(keymap->names->keys, i).name);
828         if (info.name)
829             keymap->names->keycodes = strdup(info.name);
830     } else {
831         WSGO("Cannot create struct xkb_names in CompileKeycodes\n");
832         goto err_info;
833     }
834
835     if (info.leds) {
836         IndicatorNameInfo *ii;
837         if (XkbcAllocIndicatorMaps(keymap) != Success) {
838             WSGO("Couldn't allocate IndicatorRec in CompileKeycodes\n");
839             ACTION("Physical indicators not set\n");
840         }
841
842         for (ii = info.leds; ii; ii = (IndicatorNameInfo *)ii->defs.next) {
843             free(keymap->names->indicators[ii->ndx - 1]);
844             keymap->names->indicators[ii->ndx - 1] =
845                 xkb_atom_strdup(keymap->ctx, ii->name);
846         }
847     }
848
849     ApplyAliases(keymap, &info.aliases);
850
851     ClearKeyNamesInfo(&info);
852     return true;
853
854 err_info:
855     ClearKeyNamesInfo(&info);
856     return false;
857 }