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