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