1f46a6179Smrg/************************************************************
2f46a6179Smrg Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3f46a6179Smrg
4f46a6179Smrg Permission to use, copy, modify, and distribute this
5f46a6179Smrg software and its documentation for any purpose and without
6f46a6179Smrg fee is hereby granted, provided that the above copyright
7f46a6179Smrg notice appear in all copies and that both that copyright
8f46a6179Smrg notice and this permission notice appear in supporting
9bfe6082cSmrg documentation, and that the name of Silicon Graphics not be
10bfe6082cSmrg used in advertising or publicity pertaining to distribution
11f46a6179Smrg of the software without specific prior written permission.
12bfe6082cSmrg Silicon Graphics makes no representation about the suitability
13f46a6179Smrg of this software for any purpose. It is provided "as is"
14f46a6179Smrg without any express or implied warranty.
15bfe6082cSmrg
16bfe6082cSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17bfe6082cSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18f46a6179Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19bfe6082cSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20bfe6082cSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21bfe6082cSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22f46a6179Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23f46a6179Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
24f46a6179Smrg
25f46a6179Smrg ********************************************************/
26f46a6179Smrg
27f46a6179Smrg#include "xkbcomp.h"
28f46a6179Smrg#include "xkbpath.h"
29f46a6179Smrg#include "tokens.h"
30f46a6179Smrg#include "keycodes.h"
31f46a6179Smrg#include "misc.h"
32f46a6179Smrg#include <X11/keysym.h>
33f46a6179Smrg#include "parseutils.h"
34f46a6179Smrg
35f46a6179Smrg#include <X11/extensions/XKBgeom.h>
36f46a6179Smrg
37f46a6179Smrg/***====================================================================***/
38f46a6179Smrg
3934345a63Smrg/**
4034345a63Smrg * Open the file given in the include statement and parse it's content.
4134345a63Smrg * If the statement defines a specific map to use, this map is returned in
4234345a63Smrg * file_rtrn. Otherwise, the default map is returned.
4334345a63Smrg *
4434345a63Smrg * @param stmt The include statement, specifying the file name to look for.
4534345a63Smrg * @param file_type Type of file (XkmKeyNamesIdx, etc.)
4634345a63Smrg * @param file_rtrn Returns the key map to be used.
4734345a63Smrg * @param merge_rtrn Always returns stmt->merge.
4834345a63Smrg *
4934345a63Smrg * @return True on success or False otherwise.
5034345a63Smrg */
51f46a6179SmrgBool
5234345a63SmrgProcessIncludeFile(IncludeStmt * stmt,
5334345a63Smrg                   unsigned file_type,
5434345a63Smrg                   XkbFile ** file_rtrn, unsigned *merge_rtrn)
55f46a6179Smrg{
5634345a63Smrg    XkbFile *rtrn, *mapToUse;
5734345a63Smrg    char oldFile[1024] = {0};
5834345a63Smrg    int oldLine = lineNum;
5934345a63Smrg
6034345a63Smrg    rtrn = XkbFindFileInCache(stmt->file, file_type, &stmt->path);
6134345a63Smrg    if (rtrn == NULL)
6234345a63Smrg    {
6334345a63Smrg        /* file not in cache, open it, parse it and store it in cache for next
6434345a63Smrg           time. */
656930ead5Smrg        FILE *file = XkbFindFileInPath(stmt->file, file_type, &stmt->path);
6634345a63Smrg        if (file == NULL)
6734345a63Smrg        {
68bfe6082cSmrg            ERROR("Can't find file \"%s\" for %s include\n", stmt->file,
6934345a63Smrg                   XkbDirectoryForInclude(file_type));
7034345a63Smrg            ACTION("Exiting\n");
7134345a63Smrg            return False;
7234345a63Smrg        }
7334345a63Smrg        strcpy(oldFile, scanFile);
7434345a63Smrg        oldLine = lineNum;
7534345a63Smrg        setScanState(stmt->file, 1);
766930ead5Smrg#ifdef DEBUG
7734345a63Smrg        if (debugFlags & 2)
78bfe6082cSmrg            INFO("About to parse include file %s\n", stmt->file);
796930ead5Smrg#endif
8034345a63Smrg        /* parse the file */
8134345a63Smrg        if ((XKBParseFile(file, &rtrn) == 0) || (rtrn == NULL))
8234345a63Smrg        {
8334345a63Smrg            setScanState(oldFile, oldLine);
84bfe6082cSmrg            ERROR("Error interpreting include file \"%s\"\n", stmt->file);
8534345a63Smrg            ACTION("Exiting\n");
8634345a63Smrg            fclose(file);
8734345a63Smrg            return False;
8834345a63Smrg        }
8934345a63Smrg        fclose(file);
9034345a63Smrg        XkbAddFileToCache(stmt->file, file_type, stmt->path, rtrn);
91f46a6179Smrg    }
92f757b1e9Smrg
93f757b1e9Smrg    /*
94f757b1e9Smrg     * A single file may contain several maps. Here's how we choose the map:
95f757b1e9Smrg     * - If a specific map was requested, look for it exclusively.
96f757b1e9Smrg     * - Otherwise, if the file only contains a single map, return it.
97f757b1e9Smrg     * - Otherwise, if the file has maps tagged as default, return the
98f757b1e9Smrg     *   first one.
99f757b1e9Smrg     * - If all fails, return the first map in the file.
100f757b1e9Smrg     */
10134345a63Smrg    mapToUse = rtrn;
10234345a63Smrg    if (stmt->map != NULL)
10334345a63Smrg    {
10434345a63Smrg        while ((mapToUse) && ((!uStringEqual(mapToUse->name, stmt->map)) ||
10534345a63Smrg                              (mapToUse->type != file_type)))
10634345a63Smrg        {
10734345a63Smrg            mapToUse = (XkbFile *) mapToUse->common.next;
10834345a63Smrg        }
10934345a63Smrg        if (!mapToUse)
11034345a63Smrg        {
111bfe6082cSmrg            ERROR("No %s named \"%s\" in the include file \"%s\"\n",
11234345a63Smrg                   XkbConfigText(file_type, XkbMessage), stmt->map,
11334345a63Smrg                   stmt->file);
11434345a63Smrg            ACTION("Exiting\n");
11534345a63Smrg            return False;
11634345a63Smrg        }
117f46a6179Smrg    }
118f757b1e9Smrg    else if (rtrn->common.next != NULL)
11934345a63Smrg    {
120f757b1e9Smrg        while ((mapToUse) && !(mapToUse->flags & XkbLC_Default))
121f757b1e9Smrg        {
122f757b1e9Smrg            mapToUse = (XkbFile *) mapToUse->common.next;
123f757b1e9Smrg        }
124f757b1e9Smrg        if (!mapToUse)
125f757b1e9Smrg        {
126f757b1e9Smrg            if (warningLevel > 5)
127f757b1e9Smrg            {
128bfe6082cSmrg                WARN("No map in include statement, but \"%s\" contains several without a default map\n",
129f757b1e9Smrg                      stmt->file);
130bfe6082cSmrg                ACTION("Using first defined map, \"%s\"\n", rtrn->name);
131f757b1e9Smrg            }
132f757b1e9Smrg            mapToUse = rtrn;
133f757b1e9Smrg        }
134f46a6179Smrg    }
135f757b1e9Smrg
13634345a63Smrg    setScanState(oldFile, oldLine);
13734345a63Smrg    if (mapToUse->type != file_type)
13834345a63Smrg    {
139bfe6082cSmrg        ERROR("Include file wrong type (expected %s, got %s)\n",
14034345a63Smrg               XkbConfigText(file_type, XkbMessage),
14134345a63Smrg               XkbConfigText(mapToUse->type, XkbMessage));
142bfe6082cSmrg        ACTION("Include file \"%s\" ignored\n", stmt->file);
14334345a63Smrg        return False;
144f46a6179Smrg    }
145f46a6179Smrg    /* FIXME: we have to check recursive includes here (or somewhere) */
146f46a6179Smrg
14734345a63Smrg    mapToUse->compiled = True;
14834345a63Smrg    *file_rtrn = mapToUse;
14934345a63Smrg    *merge_rtrn = stmt->merge;
150f46a6179Smrg    return True;
151f46a6179Smrg}
152f46a6179Smrg
153f46a6179Smrg/***====================================================================***/
154f46a6179Smrg
155f46a6179Smrgint
156f46a6179SmrgReportNotArray(const char *type, const char *field, const char *name)
157f46a6179Smrg{
158bfe6082cSmrg    ERROR("The %s %s field is not an array\n", type, field);
159bfe6082cSmrg    ACTION("Ignoring illegal assignment in %s\n", name);
160f46a6179Smrg    return False;
161f46a6179Smrg}
162f46a6179Smrg
163f46a6179Smrgint
164f46a6179SmrgReportShouldBeArray(const char *type, const char *field, char *name)
165f46a6179Smrg{
166bfe6082cSmrg    ERROR("Missing subscript for %s %s\n", type, field);
167bfe6082cSmrg    ACTION("Ignoring illegal assignment in %s\n", name);
168f46a6179Smrg    return False;
169f46a6179Smrg}
170f46a6179Smrg
171f46a6179Smrgint
172f46a6179SmrgReportBadType(const char *type, const char *field,
173f46a6179Smrg              const char *name, const char *wanted)
174f46a6179Smrg{
175bfe6082cSmrg    ERROR("The %s %s field must be a %s\n", type, field, wanted);
176bfe6082cSmrg    ACTION("Ignoring illegal assignment in %s\n", name);
177f46a6179Smrg    return False;
178f46a6179Smrg}
179f46a6179Smrg
1806930ead5Smrg#if 0
181f46a6179Smrgint
18234345a63SmrgReportBadIndexType(char *type, char *field, char *name, char *wanted)
183f46a6179Smrg{
184bfe6082cSmrg    ERROR("Index for the %s %s field must be a %s\n", type, field, wanted);
185bfe6082cSmrg    ACTION("Ignoring assignment to illegal field in %s\n", name);
186f46a6179Smrg    return False;
187f46a6179Smrg}
1886930ead5Smrg#endif
189f46a6179Smrg
190f46a6179Smrgint
191f46a6179SmrgReportBadField(const char *type, const char *field, const char *name)
192f46a6179Smrg{
193bfe6082cSmrg    ERROR("Unknown %s field %s in %s\n", type, field, name);
194bfe6082cSmrg    ACTION("Ignoring assignment to unknown field in %s\n", name);
195f46a6179Smrg    return False;
196f46a6179Smrg}
197f46a6179Smrg
1986930ead5Smrg#if 0
199f46a6179Smrgint
20034345a63SmrgReportMultipleDefs(char *type, char *field, char *name)
201f46a6179Smrg{
202bfe6082cSmrg    WARN("Multiple definitions of %s in %s \"%s\"\n", field, type, name);
203f46a6179Smrg    ACTION("Using last definition\n");
204f46a6179Smrg    return False;
205f46a6179Smrg}
2066930ead5Smrg#endif
207f46a6179Smrg
208f46a6179Smrg/***====================================================================***/
209f46a6179Smrg
21034345a63SmrgBool
2116930ead5SmrgUseNewField(unsigned field, const CommonInfo *oldDefs,
2126930ead5Smrg            const CommonInfo *newDefs, unsigned *pCollide)
213f46a6179Smrg{
21434345a63Smrg    Bool useNew;
21534345a63Smrg
21634345a63Smrg    useNew = False;
21734345a63Smrg    if (oldDefs->defined & field)
21834345a63Smrg    {
21934345a63Smrg        if (newDefs->defined & field)
22034345a63Smrg        {
22134345a63Smrg            if (((oldDefs->fileID == newDefs->fileID)
22234345a63Smrg                 && (warningLevel > 0)) || (warningLevel > 9))
22334345a63Smrg            {
22434345a63Smrg                *pCollide |= field;
22534345a63Smrg            }
22634345a63Smrg            if (newDefs->merge != MergeAugment)
22734345a63Smrg                useNew = True;
22834345a63Smrg        }
229f46a6179Smrg    }
23034345a63Smrg    else if (newDefs->defined & field)
23134345a63Smrg        useNew = True;
232f46a6179Smrg    return useNew;
233f46a6179Smrg}
234f46a6179Smrg
2356930ead5Smrg#if 0
2366930ead5Smrgstatic Bool
2376930ead5SmrgMergeNewField(unsigned field, const CommonInfo *oldDefs,
2386930ead5Smrg            const CommonInfo *newDefs, unsigned *pCollide)
239f46a6179Smrg{
24034345a63Smrg    if ((oldDefs->defined & field) && (newDefs->defined & field))
24134345a63Smrg    {
24234345a63Smrg        if (((oldDefs->fileID == newDefs->fileID) && (warningLevel > 0)) ||
24334345a63Smrg            (warningLevel > 9))
24434345a63Smrg        {
24534345a63Smrg            *pCollide |= field;
24634345a63Smrg        }
24734345a63Smrg        if (newDefs->merge == MergeAugment)
24834345a63Smrg            return True;
249f46a6179Smrg    }
250f46a6179Smrg    return False;
251f46a6179Smrg}
2526930ead5Smrg#endif
253f46a6179Smrg
254f46a6179SmrgXPointer
25534345a63SmrgClearCommonInfo(CommonInfo * cmn)
256f46a6179Smrg{
25734345a63Smrg    if (cmn != NULL)
25834345a63Smrg    {
25934345a63Smrg        CommonInfo *this, *next;
26034345a63Smrg        for (this = cmn; this != NULL; this = next)
26134345a63Smrg        {
26234345a63Smrg            next = this->next;
2636930ead5Smrg            free(this);
26434345a63Smrg        }
265f46a6179Smrg    }
266f46a6179Smrg    return NULL;
267f46a6179Smrg}
268f46a6179Smrg
269f46a6179SmrgXPointer
27034345a63SmrgAddCommonInfo(CommonInfo * old, CommonInfo * new)
271f46a6179Smrg{
27234345a63Smrg    CommonInfo *first;
273f46a6179Smrg
27434345a63Smrg    first = old;
27534345a63Smrg    while (old && old->next)
27634345a63Smrg    {
27734345a63Smrg        old = old->next;
278f46a6179Smrg    }
27934345a63Smrg    new->next = NULL;
28034345a63Smrg    if (old)
28134345a63Smrg    {
28234345a63Smrg        old->next = new;
28334345a63Smrg        return (XPointer) first;
284f46a6179Smrg    }
28534345a63Smrg    return (XPointer) new;
286f46a6179Smrg}
287f46a6179Smrg
288f46a6179Smrg/***====================================================================***/
289f46a6179Smrg
29034345a63Smrgtypedef struct _KeyNameDesc
29134345a63Smrg{
29234345a63Smrg    KeySym level1;
29334345a63Smrg    KeySym level2;
29434345a63Smrg    char name[5];
29534345a63Smrg    Bool used;
296f46a6179Smrg} KeyNameDesc;
297f46a6179Smrg
29834345a63Smrgstatic KeyNameDesc dfltKeys[] = {
2996930ead5Smrg    {XK_Escape, NoSymbol, "ESC\0", 0},
3006930ead5Smrg    {XK_quoteleft, XK_asciitilde, "TLDE", 0},
3016930ead5Smrg    {XK_1, XK_exclam, "AE01", 0},
3026930ead5Smrg    {XK_2, XK_at, "AE02", 0},
3036930ead5Smrg    {XK_3, XK_numbersign, "AE03", 0},
3046930ead5Smrg    {XK_4, XK_dollar, "AE04", 0},
3056930ead5Smrg    {XK_5, XK_percent, "AE05", 0},
3066930ead5Smrg    {XK_6, XK_asciicircum, "AE06", 0},
3076930ead5Smrg    {XK_7, XK_ampersand, "AE07", 0},
3086930ead5Smrg    {XK_8, XK_asterisk, "AE08", 0},
3096930ead5Smrg    {XK_9, XK_parenleft, "AE09", 0},
3106930ead5Smrg    {XK_0, XK_parenright, "AE10", 0},
3116930ead5Smrg    {XK_minus, XK_underscore, "AE11", 0},
3126930ead5Smrg    {XK_equal, XK_plus, "AE12", 0},
3136930ead5Smrg    {XK_BackSpace, NoSymbol, "BKSP", 0},
3146930ead5Smrg    {XK_Tab, NoSymbol, "TAB\0", 0},
3156930ead5Smrg    {XK_q, XK_Q, "AD01", 0},
3166930ead5Smrg    {XK_w, XK_W, "AD02", 0},
3176930ead5Smrg    {XK_e, XK_E, "AD03", 0},
3186930ead5Smrg    {XK_r, XK_R, "AD04", 0},
3196930ead5Smrg    {XK_t, XK_T, "AD05", 0},
3206930ead5Smrg    {XK_y, XK_Y, "AD06", 0},
3216930ead5Smrg    {XK_u, XK_U, "AD07", 0},
3226930ead5Smrg    {XK_i, XK_I, "AD08", 0},
3236930ead5Smrg    {XK_o, XK_O, "AD09", 0},
3246930ead5Smrg    {XK_p, XK_P, "AD10", 0},
3256930ead5Smrg    {XK_bracketleft, XK_braceleft, "AD11", 0},
3266930ead5Smrg    {XK_bracketright, XK_braceright, "AD12", 0},
3276930ead5Smrg    {XK_Return, NoSymbol, "RTRN", 0},
3286930ead5Smrg    {XK_Caps_Lock, NoSymbol, "CAPS", 0},
3296930ead5Smrg    {XK_a, XK_A, "AC01", 0},
3306930ead5Smrg    {XK_s, XK_S, "AC02", 0},
3316930ead5Smrg    {XK_d, XK_D, "AC03", 0},
3326930ead5Smrg    {XK_f, XK_F, "AC04", 0},
3336930ead5Smrg    {XK_g, XK_G, "AC05", 0},
3346930ead5Smrg    {XK_h, XK_H, "AC06", 0},
3356930ead5Smrg    {XK_j, XK_J, "AC07", 0},
3366930ead5Smrg    {XK_k, XK_K, "AC08", 0},
3376930ead5Smrg    {XK_l, XK_L, "AC09", 0},
3386930ead5Smrg    {XK_semicolon, XK_colon, "AC10", 0},
3396930ead5Smrg    {XK_quoteright, XK_quotedbl, "AC11", 0},
3406930ead5Smrg    {XK_Shift_L, NoSymbol, "LFSH", 0},
3416930ead5Smrg    {XK_z, XK_Z, "AB01", 0},
3426930ead5Smrg    {XK_x, XK_X, "AB02", 0},
3436930ead5Smrg    {XK_c, XK_C, "AB03", 0},
3446930ead5Smrg    {XK_v, XK_V, "AB04", 0},
3456930ead5Smrg    {XK_b, XK_B, "AB05", 0},
3466930ead5Smrg    {XK_n, XK_N, "AB06", 0},
3476930ead5Smrg    {XK_m, XK_M, "AB07", 0},
3486930ead5Smrg    {XK_comma, XK_less, "AB08", 0},
3496930ead5Smrg    {XK_period, XK_greater, "AB09", 0},
3506930ead5Smrg    {XK_slash, XK_question, "AB10", 0},
3516930ead5Smrg    {XK_backslash, XK_bar, "BKSL", 0},
3526930ead5Smrg    {XK_Control_L, NoSymbol, "LCTL", 0},
3536930ead5Smrg    {XK_space, NoSymbol, "SPCE", 0},
3546930ead5Smrg    {XK_Shift_R, NoSymbol, "RTSH", 0},
3556930ead5Smrg    {XK_Alt_L, NoSymbol, "LALT", 0},
3566930ead5Smrg    {XK_space, NoSymbol, "SPCE", 0},
3576930ead5Smrg    {XK_Control_R, NoSymbol, "RCTL", 0},
3586930ead5Smrg    {XK_Alt_R, NoSymbol, "RALT", 0},
3596930ead5Smrg    {XK_F1, NoSymbol, "FK01", 0},
3606930ead5Smrg    {XK_F2, NoSymbol, "FK02", 0},
3616930ead5Smrg    {XK_F3, NoSymbol, "FK03", 0},
3626930ead5Smrg    {XK_F4, NoSymbol, "FK04", 0},
3636930ead5Smrg    {XK_F5, NoSymbol, "FK05", 0},
3646930ead5Smrg    {XK_F6, NoSymbol, "FK06", 0},
3656930ead5Smrg    {XK_F7, NoSymbol, "FK07", 0},
3666930ead5Smrg    {XK_F8, NoSymbol, "FK08", 0},
3676930ead5Smrg    {XK_F9, NoSymbol, "FK09", 0},
3686930ead5Smrg    {XK_F10, NoSymbol, "FK10", 0},
3696930ead5Smrg    {XK_F11, NoSymbol, "FK11", 0},
3706930ead5Smrg    {XK_F12, NoSymbol, "FK12", 0},
3716930ead5Smrg    {XK_Print, NoSymbol, "PRSC", 0},
3726930ead5Smrg    {XK_Scroll_Lock, NoSymbol, "SCLK", 0},
3736930ead5Smrg    {XK_Pause, NoSymbol, "PAUS", 0},
3746930ead5Smrg    {XK_Insert, NoSymbol, "INS\0", 0},
3756930ead5Smrg    {XK_Home, NoSymbol, "HOME", 0},
3766930ead5Smrg    {XK_Prior, NoSymbol, "PGUP", 0},
3776930ead5Smrg    {XK_Delete, NoSymbol, "DELE", 0},
3786930ead5Smrg    {XK_End, NoSymbol, "END", 0},
3796930ead5Smrg    {XK_Next, NoSymbol, "PGDN", 0},
3806930ead5Smrg    {XK_Up, NoSymbol, "UP\0\0", 0},
3816930ead5Smrg    {XK_Left, NoSymbol, "LEFT", 0},
3826930ead5Smrg    {XK_Down, NoSymbol, "DOWN", 0},
3836930ead5Smrg    {XK_Right, NoSymbol, "RGHT", 0},
3846930ead5Smrg    {XK_Num_Lock, NoSymbol, "NMLK", 0},
3856930ead5Smrg    {XK_KP_Divide, NoSymbol, "KPDV", 0},
3866930ead5Smrg    {XK_KP_Multiply, NoSymbol, "KPMU", 0},
3876930ead5Smrg    {XK_KP_Subtract, NoSymbol, "KPSU", 0},
3886930ead5Smrg    {NoSymbol, XK_KP_7, "KP7\0", 0},
3896930ead5Smrg    {NoSymbol, XK_KP_8, "KP8\0", 0},
3906930ead5Smrg    {NoSymbol, XK_KP_9, "KP9\0", 0},
3916930ead5Smrg    {XK_KP_Add, NoSymbol, "KPAD", 0},
3926930ead5Smrg    {NoSymbol, XK_KP_4, "KP4\0", 0},
3936930ead5Smrg    {NoSymbol, XK_KP_5, "KP5\0", 0},
3946930ead5Smrg    {NoSymbol, XK_KP_6, "KP6\0", 0},
3956930ead5Smrg    {NoSymbol, XK_KP_1, "KP1\0", 0},
3966930ead5Smrg    {NoSymbol, XK_KP_2, "KP2\0", 0},
3976930ead5Smrg    {NoSymbol, XK_KP_3, "KP3\0", 0},
3986930ead5Smrg    {XK_KP_Enter, NoSymbol, "KPEN", 0},
3996930ead5Smrg    {NoSymbol, XK_KP_0, "KP0\0", 0},
4006930ead5Smrg    {XK_KP_Delete, NoSymbol, "KPDL", 0},
4016930ead5Smrg    {XK_less, XK_greater, "LSGT", 0},
4026930ead5Smrg    {XK_KP_Separator, NoSymbol, "KPCO", 0},
4036930ead5Smrg    {XK_Find, NoSymbol, "FIND", 0},
4046930ead5Smrg    {NoSymbol, NoSymbol, "\0\0\0\0", 0}
405f46a6179Smrg};
406f46a6179Smrg
407f46a6179SmrgStatus
408f46a6179SmrgComputeKbdDefaults(XkbDescPtr xkb)
409f46a6179Smrg{
4106930ead5Smrg    int nUnknown;
41134345a63Smrg
41234345a63Smrg    if ((xkb->names == NULL) || (xkb->names->keys == NULL))
41334345a63Smrg    {
4146930ead5Smrg        Status rtrn;
41534345a63Smrg        if ((rtrn = XkbAllocNames(xkb, XkbKeyNamesMask, 0, 0)) != Success)
41634345a63Smrg            return rtrn;
417f46a6179Smrg    }
4186930ead5Smrg    for (KeyNameDesc *name = dfltKeys; (name->name[0] != '\0'); name++)
41934345a63Smrg    {
42034345a63Smrg        name->used = False;
421f46a6179Smrg    }
42234345a63Smrg    nUnknown = 0;
4236930ead5Smrg    for (int i = xkb->min_key_code; i <= xkb->max_key_code; i++)
42434345a63Smrg    {
4256930ead5Smrg        int tmp = XkbKeyNumSyms(xkb, i);
42634345a63Smrg        if ((xkb->names->keys[i].name[0] == '\0') && (tmp > 0))
42734345a63Smrg        {
4286930ead5Smrg            KeySym *syms;
4296930ead5Smrg
43034345a63Smrg            tmp = XkbKeyGroupsWidth(xkb, i);
43134345a63Smrg            syms = XkbKeySymsPtr(xkb, i);
4326930ead5Smrg            for (KeyNameDesc *name = dfltKeys; (name->name[0] != '\0'); name++)
43334345a63Smrg            {
43434345a63Smrg                Bool match = True;
43534345a63Smrg                if (((name->level1 != syms[0])
43634345a63Smrg                     && (name->level1 != NoSymbol))
43734345a63Smrg                    || ((name->level2 != NoSymbol) && (tmp < 2))
43834345a63Smrg                    || ((name->level2 != syms[1])
43934345a63Smrg                        && (name->level2 != NoSymbol)))
44034345a63Smrg                {
44134345a63Smrg                    match = False;
44234345a63Smrg                }
44334345a63Smrg                if (match)
44434345a63Smrg                {
44534345a63Smrg                    if (!name->used)
44634345a63Smrg                    {
44734345a63Smrg                        memcpy(xkb->names->keys[i].name, name->name,
44834345a63Smrg                               XkbKeyNameLength);
44934345a63Smrg                        name->used = True;
45034345a63Smrg                    }
45134345a63Smrg                    else
45234345a63Smrg                    {
4536930ead5Smrg                        char tmpname[XkbKeyNameLength + 1];
4546930ead5Smrg
45534345a63Smrg                        if (warningLevel > 2)
45634345a63Smrg                        {
457bfe6082cSmrg                            WARN
45834345a63Smrg                                ("Several keys match pattern for %s\n",
45934345a63Smrg                                 XkbKeyNameText(name->name, XkbMessage));
460bfe6082cSmrg                            ACTION("Using <U%03d> for key %d\n",
46134345a63Smrg                                    nUnknown, i);
46234345a63Smrg                        }
46334345a63Smrg                        snprintf(tmpname, sizeof(tmpname), "U%03d",
46434345a63Smrg                                 nUnknown++);
46534345a63Smrg                        memcpy(xkb->names->keys[i].name, tmpname,
46634345a63Smrg                               XkbKeyNameLength);
46734345a63Smrg                    }
46834345a63Smrg                    break;
46934345a63Smrg                }
47034345a63Smrg            }
47134345a63Smrg            if (xkb->names->keys[i].name[0] == '\0')
47234345a63Smrg            {
47334345a63Smrg                if (warningLevel > 2)
47434345a63Smrg                {
4756930ead5Smrg                    char tmpname[XkbKeyNameLength + 1];
4766930ead5Smrg
477bfe6082cSmrg                    WARN("Key %d does not match any defaults\n", i);
478bfe6082cSmrg                    ACTION("Using name <U%03d>\n", nUnknown);
47934345a63Smrg                    snprintf(tmpname, sizeof(tmpname), "U%03d", nUnknown++);
48034345a63Smrg                    memcpy(xkb->names->keys[i].name, tmpname,
48134345a63Smrg                           XkbKeyNameLength);
48234345a63Smrg                }
48334345a63Smrg            }
48434345a63Smrg        }
485f46a6179Smrg    }
486f46a6179Smrg    return Success;
487f46a6179Smrg}
488f46a6179Smrg
48934345a63Smrg/**
49034345a63Smrg * Find the key with the given name and return its keycode in kc_rtrn.
49134345a63Smrg *
49234345a63Smrg * @param name The 4-letter name of the key as a long.
49334345a63Smrg * @param kc_rtrn Set to the keycode if the key was found, otherwise 0.
49434345a63Smrg * @param use_aliases True if the key aliases should be searched too.
49534345a63Smrg * @param create If True and the key is not found, it is added to the
49634345a63Smrg *        xkb->names at the first free keycode.
49734345a63Smrg * @param start_from Keycode to start searching from.
49834345a63Smrg *
49934345a63Smrg * @return True if found, False otherwise.
50034345a63Smrg */
501f46a6179SmrgBool
50234345a63SmrgFindNamedKey(XkbDescPtr xkb,
50334345a63Smrg             unsigned long name,
50434345a63Smrg             unsigned int *kc_rtrn,
50534345a63Smrg             Bool use_aliases, Bool create, int start_from)
506f46a6179Smrg{
50734345a63Smrg    if (start_from < xkb->min_key_code)
50834345a63Smrg    {
50934345a63Smrg        start_from = xkb->min_key_code;
510f46a6179Smrg    }
51134345a63Smrg    else if (start_from > xkb->max_key_code)
51234345a63Smrg    {
51334345a63Smrg        return False;
514f46a6179Smrg    }
515f46a6179Smrg
51634345a63Smrg    *kc_rtrn = 0;               /* some callers rely on this */
51734345a63Smrg    if (xkb && xkb->names && xkb->names->keys)
51834345a63Smrg    {
5196930ead5Smrg        for (unsigned n = start_from; n <= xkb->max_key_code; n++)
52034345a63Smrg        {
52134345a63Smrg            unsigned long tmp;
52234345a63Smrg            tmp = KeyNameToLong(xkb->names->keys[n].name);
52334345a63Smrg            if (tmp == name)
52434345a63Smrg            {
52534345a63Smrg                *kc_rtrn = n;
52634345a63Smrg                return True;
52734345a63Smrg            }
52834345a63Smrg        }
52934345a63Smrg        if (use_aliases)
53034345a63Smrg        {
53134345a63Smrg            unsigned long new_name;
53234345a63Smrg            if (FindKeyNameForAlias(xkb, name, &new_name))
53334345a63Smrg                return FindNamedKey(xkb, new_name, kc_rtrn, False, create, 0);
53434345a63Smrg        }
535f46a6179Smrg    }
53634345a63Smrg    if (create)
53734345a63Smrg    {
53834345a63Smrg        if ((!xkb->names) || (!xkb->names->keys))
53934345a63Smrg        {
54034345a63Smrg            if (xkb->min_key_code < XkbMinLegalKeyCode)
54134345a63Smrg            {
54234345a63Smrg                xkb->min_key_code = XkbMinLegalKeyCode;
54334345a63Smrg                xkb->max_key_code = XkbMaxLegalKeyCode;
54434345a63Smrg            }
54534345a63Smrg            if (XkbAllocNames(xkb, XkbKeyNamesMask, 0, 0) != Success)
54634345a63Smrg            {
54734345a63Smrg                if (warningLevel > 0)
54834345a63Smrg                {
54934345a63Smrg                    WARN("Couldn't allocate key names in FindNamedKey\n");
550bfe6082cSmrg                    ACTION("Key \"%s\" not automatically created\n",
55134345a63Smrg                            longText(name, XkbMessage));
55234345a63Smrg                }
55334345a63Smrg                return False;
55434345a63Smrg            }
55534345a63Smrg        }
55634345a63Smrg        /* Find first unused keycode and store our key here */
5576930ead5Smrg        for (unsigned n = xkb->min_key_code; n <= xkb->max_key_code; n++)
55834345a63Smrg        {
55934345a63Smrg            if (xkb->names->keys[n].name[0] == '\0')
56034345a63Smrg            {
56134345a63Smrg                char buf[XkbKeyNameLength + 1];
56234345a63Smrg                LongToKeyName(name, buf);
56334345a63Smrg                memcpy(xkb->names->keys[n].name, buf, XkbKeyNameLength);
56434345a63Smrg                *kc_rtrn = n;
56534345a63Smrg                return True;
56634345a63Smrg            }
56734345a63Smrg        }
568f46a6179Smrg    }
569f46a6179Smrg    return False;
570f46a6179Smrg}
571f46a6179Smrg
572f46a6179SmrgBool
57334345a63SmrgFindKeyNameForAlias(XkbDescPtr xkb, unsigned long lname,
57434345a63Smrg                    unsigned long *real_name)
575f46a6179Smrg{
57634345a63Smrg    char name[XkbKeyNameLength + 1];
57734345a63Smrg
57834345a63Smrg    if (xkb && xkb->geom && xkb->geom->key_aliases)
57934345a63Smrg    {
58034345a63Smrg        XkbKeyAliasPtr a;
58134345a63Smrg        a = xkb->geom->key_aliases;
58234345a63Smrg        LongToKeyName(lname, name);
58334345a63Smrg        name[XkbKeyNameLength] = '\0';
5846930ead5Smrg        for (int i = 0; i < xkb->geom->num_key_aliases; i++, a++)
58534345a63Smrg        {
58634345a63Smrg            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
58734345a63Smrg            {
58834345a63Smrg                *real_name = KeyNameToLong(a->real);
58934345a63Smrg                return True;
59034345a63Smrg            }
59134345a63Smrg        }
592f46a6179Smrg    }
59334345a63Smrg    if (xkb && xkb->names && xkb->names->key_aliases)
59434345a63Smrg    {
59534345a63Smrg        XkbKeyAliasPtr a;
59634345a63Smrg        a = xkb->names->key_aliases;
59734345a63Smrg        LongToKeyName(lname, name);
59834345a63Smrg        name[XkbKeyNameLength] = '\0';
5996930ead5Smrg        for (int i = 0; i < xkb->names->num_key_aliases; i++, a++)
60034345a63Smrg        {
60134345a63Smrg            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
60234345a63Smrg            {
60334345a63Smrg                *real_name = KeyNameToLong(a->real);
60434345a63Smrg                return True;
60534345a63Smrg            }
60634345a63Smrg        }
607f46a6179Smrg    }
608f46a6179Smrg    return False;
609f46a6179Smrg}
610