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 "xkbpath.h"
29#include "tokens.h"
30#include "keycodes.h"
31#include "misc.h"
32#include <X11/keysym.h>
33#include "parseutils.h"
34
35#include <X11/extensions/XKBgeom.h>
36
37/***====================================================================***/
38
39/**
40 * Open the file given in the include statement and parse it's content.
41 * If the statement defines a specific map to use, this map is returned in
42 * file_rtrn. Otherwise, the default map is returned.
43 *
44 * @param stmt The include statement, specifying the file name to look for.
45 * @param file_type Type of file (XkmKeyNamesIdx, etc.)
46 * @param file_rtrn Returns the key map to be used.
47 * @param merge_rtrn Always returns stmt->merge.
48 *
49 * @return True on success or False otherwise.
50 */
51Bool
52ProcessIncludeFile(IncludeStmt * stmt,
53                   unsigned file_type,
54                   XkbFile ** file_rtrn, unsigned *merge_rtrn)
55{
56    XkbFile *rtrn, *mapToUse;
57    char oldFile[1024] = {0};
58    int oldLine = lineNum;
59
60    rtrn = XkbFindFileInCache(stmt->file, file_type, &stmt->path);
61    if (rtrn == NULL)
62    {
63        /* file not in cache, open it, parse it and store it in cache for next
64           time. */
65        FILE *file = XkbFindFileInPath(stmt->file, file_type, &stmt->path);
66        if (file == NULL)
67        {
68            ERROR("Can't find file \"%s\" for %s include\n", stmt->file,
69                   XkbDirectoryForInclude(file_type));
70            ACTION("Exiting\n");
71            return False;
72        }
73        strcpy(oldFile, scanFile);
74        oldLine = lineNum;
75        setScanState(stmt->file, 1);
76#ifdef DEBUG
77        if (debugFlags & 2)
78            INFO("About to parse include file %s\n", stmt->file);
79#endif
80        /* parse the file */
81        if ((XKBParseFile(file, &rtrn) == 0) || (rtrn == NULL))
82        {
83            setScanState(oldFile, oldLine);
84            ERROR("Error interpreting include file \"%s\"\n", stmt->file);
85            ACTION("Exiting\n");
86            fclose(file);
87            return False;
88        }
89        fclose(file);
90        XkbAddFileToCache(stmt->file, file_type, stmt->path, rtrn);
91    }
92
93    /*
94     * A single file may contain several maps. Here's how we choose the map:
95     * - If a specific map was requested, look for it exclusively.
96     * - Otherwise, if the file only contains a single map, return it.
97     * - Otherwise, if the file has maps tagged as default, return the
98     *   first one.
99     * - If all fails, return the first map in the file.
100     */
101    mapToUse = rtrn;
102    if (stmt->map != NULL)
103    {
104        while ((mapToUse) && ((!uStringEqual(mapToUse->name, stmt->map)) ||
105                              (mapToUse->type != file_type)))
106        {
107            mapToUse = (XkbFile *) mapToUse->common.next;
108        }
109        if (!mapToUse)
110        {
111            ERROR("No %s named \"%s\" in the include file \"%s\"\n",
112                   XkbConfigText(file_type, XkbMessage), stmt->map,
113                   stmt->file);
114            ACTION("Exiting\n");
115            return False;
116        }
117    }
118    else if (rtrn->common.next != NULL)
119    {
120        while ((mapToUse) && !(mapToUse->flags & XkbLC_Default))
121        {
122            mapToUse = (XkbFile *) mapToUse->common.next;
123        }
124        if (!mapToUse)
125        {
126            if (warningLevel > 5)
127            {
128                WARN("No map in include statement, but \"%s\" contains several without a default map\n",
129                      stmt->file);
130                ACTION("Using first defined map, \"%s\"\n", rtrn->name);
131            }
132            mapToUse = rtrn;
133        }
134    }
135
136    setScanState(oldFile, oldLine);
137    if (mapToUse->type != file_type)
138    {
139        ERROR("Include file wrong type (expected %s, got %s)\n",
140               XkbConfigText(file_type, XkbMessage),
141               XkbConfigText(mapToUse->type, XkbMessage));
142        ACTION("Include file \"%s\" ignored\n", stmt->file);
143        return False;
144    }
145    /* FIXME: we have to check recursive includes here (or somewhere) */
146
147    mapToUse->compiled = True;
148    *file_rtrn = mapToUse;
149    *merge_rtrn = stmt->merge;
150    return True;
151}
152
153/***====================================================================***/
154
155int
156ReportNotArray(const char *type, const char *field, const char *name)
157{
158    ERROR("The %s %s field is not an array\n", type, field);
159    ACTION("Ignoring illegal assignment in %s\n", name);
160    return False;
161}
162
163int
164ReportShouldBeArray(const char *type, const char *field, char *name)
165{
166    ERROR("Missing subscript for %s %s\n", type, field);
167    ACTION("Ignoring illegal assignment in %s\n", name);
168    return False;
169}
170
171int
172ReportBadType(const char *type, const char *field,
173              const char *name, const char *wanted)
174{
175    ERROR("The %s %s field must be a %s\n", type, field, wanted);
176    ACTION("Ignoring illegal assignment in %s\n", name);
177    return False;
178}
179
180#if 0
181int
182ReportBadIndexType(char *type, char *field, char *name, char *wanted)
183{
184    ERROR("Index for the %s %s field must be a %s\n", type, field, wanted);
185    ACTION("Ignoring assignment to illegal field in %s\n", name);
186    return False;
187}
188#endif
189
190int
191ReportBadField(const char *type, const char *field, const char *name)
192{
193    ERROR("Unknown %s field %s in %s\n", type, field, name);
194    ACTION("Ignoring assignment to unknown field in %s\n", name);
195    return False;
196}
197
198#if 0
199int
200ReportMultipleDefs(char *type, char *field, char *name)
201{
202    WARN("Multiple definitions of %s in %s \"%s\"\n", field, type, name);
203    ACTION("Using last definition\n");
204    return False;
205}
206#endif
207
208/***====================================================================***/
209
210Bool
211UseNewField(unsigned field, const CommonInfo *oldDefs,
212            const CommonInfo *newDefs, unsigned *pCollide)
213{
214    Bool useNew;
215
216    useNew = False;
217    if (oldDefs->defined & field)
218    {
219        if (newDefs->defined & field)
220        {
221            if (((oldDefs->fileID == newDefs->fileID)
222                 && (warningLevel > 0)) || (warningLevel > 9))
223            {
224                *pCollide |= field;
225            }
226            if (newDefs->merge != MergeAugment)
227                useNew = True;
228        }
229    }
230    else if (newDefs->defined & field)
231        useNew = True;
232    return useNew;
233}
234
235#if 0
236static Bool
237MergeNewField(unsigned field, const CommonInfo *oldDefs,
238            const CommonInfo *newDefs, unsigned *pCollide)
239{
240    if ((oldDefs->defined & field) && (newDefs->defined & field))
241    {
242        if (((oldDefs->fileID == newDefs->fileID) && (warningLevel > 0)) ||
243            (warningLevel > 9))
244        {
245            *pCollide |= field;
246        }
247        if (newDefs->merge == MergeAugment)
248            return True;
249    }
250    return False;
251}
252#endif
253
254XPointer
255ClearCommonInfo(CommonInfo * cmn)
256{
257    if (cmn != NULL)
258    {
259        CommonInfo *this, *next;
260        for (this = cmn; this != NULL; this = next)
261        {
262            next = this->next;
263            free(this);
264        }
265    }
266    return NULL;
267}
268
269XPointer
270AddCommonInfo(CommonInfo * old, CommonInfo * new)
271{
272    CommonInfo *first;
273
274    first = old;
275    while (old && old->next)
276    {
277        old = old->next;
278    }
279    new->next = NULL;
280    if (old)
281    {
282        old->next = new;
283        return (XPointer) first;
284    }
285    return (XPointer) new;
286}
287
288/***====================================================================***/
289
290typedef struct _KeyNameDesc
291{
292    KeySym level1;
293    KeySym level2;
294    char name[5];
295    Bool used;
296} KeyNameDesc;
297
298static KeyNameDesc dfltKeys[] = {
299    {XK_Escape, NoSymbol, "ESC\0", 0},
300    {XK_quoteleft, XK_asciitilde, "TLDE", 0},
301    {XK_1, XK_exclam, "AE01", 0},
302    {XK_2, XK_at, "AE02", 0},
303    {XK_3, XK_numbersign, "AE03", 0},
304    {XK_4, XK_dollar, "AE04", 0},
305    {XK_5, XK_percent, "AE05", 0},
306    {XK_6, XK_asciicircum, "AE06", 0},
307    {XK_7, XK_ampersand, "AE07", 0},
308    {XK_8, XK_asterisk, "AE08", 0},
309    {XK_9, XK_parenleft, "AE09", 0},
310    {XK_0, XK_parenright, "AE10", 0},
311    {XK_minus, XK_underscore, "AE11", 0},
312    {XK_equal, XK_plus, "AE12", 0},
313    {XK_BackSpace, NoSymbol, "BKSP", 0},
314    {XK_Tab, NoSymbol, "TAB\0", 0},
315    {XK_q, XK_Q, "AD01", 0},
316    {XK_w, XK_W, "AD02", 0},
317    {XK_e, XK_E, "AD03", 0},
318    {XK_r, XK_R, "AD04", 0},
319    {XK_t, XK_T, "AD05", 0},
320    {XK_y, XK_Y, "AD06", 0},
321    {XK_u, XK_U, "AD07", 0},
322    {XK_i, XK_I, "AD08", 0},
323    {XK_o, XK_O, "AD09", 0},
324    {XK_p, XK_P, "AD10", 0},
325    {XK_bracketleft, XK_braceleft, "AD11", 0},
326    {XK_bracketright, XK_braceright, "AD12", 0},
327    {XK_Return, NoSymbol, "RTRN", 0},
328    {XK_Caps_Lock, NoSymbol, "CAPS", 0},
329    {XK_a, XK_A, "AC01", 0},
330    {XK_s, XK_S, "AC02", 0},
331    {XK_d, XK_D, "AC03", 0},
332    {XK_f, XK_F, "AC04", 0},
333    {XK_g, XK_G, "AC05", 0},
334    {XK_h, XK_H, "AC06", 0},
335    {XK_j, XK_J, "AC07", 0},
336    {XK_k, XK_K, "AC08", 0},
337    {XK_l, XK_L, "AC09", 0},
338    {XK_semicolon, XK_colon, "AC10", 0},
339    {XK_quoteright, XK_quotedbl, "AC11", 0},
340    {XK_Shift_L, NoSymbol, "LFSH", 0},
341    {XK_z, XK_Z, "AB01", 0},
342    {XK_x, XK_X, "AB02", 0},
343    {XK_c, XK_C, "AB03", 0},
344    {XK_v, XK_V, "AB04", 0},
345    {XK_b, XK_B, "AB05", 0},
346    {XK_n, XK_N, "AB06", 0},
347    {XK_m, XK_M, "AB07", 0},
348    {XK_comma, XK_less, "AB08", 0},
349    {XK_period, XK_greater, "AB09", 0},
350    {XK_slash, XK_question, "AB10", 0},
351    {XK_backslash, XK_bar, "BKSL", 0},
352    {XK_Control_L, NoSymbol, "LCTL", 0},
353    {XK_space, NoSymbol, "SPCE", 0},
354    {XK_Shift_R, NoSymbol, "RTSH", 0},
355    {XK_Alt_L, NoSymbol, "LALT", 0},
356    {XK_space, NoSymbol, "SPCE", 0},
357    {XK_Control_R, NoSymbol, "RCTL", 0},
358    {XK_Alt_R, NoSymbol, "RALT", 0},
359    {XK_F1, NoSymbol, "FK01", 0},
360    {XK_F2, NoSymbol, "FK02", 0},
361    {XK_F3, NoSymbol, "FK03", 0},
362    {XK_F4, NoSymbol, "FK04", 0},
363    {XK_F5, NoSymbol, "FK05", 0},
364    {XK_F6, NoSymbol, "FK06", 0},
365    {XK_F7, NoSymbol, "FK07", 0},
366    {XK_F8, NoSymbol, "FK08", 0},
367    {XK_F9, NoSymbol, "FK09", 0},
368    {XK_F10, NoSymbol, "FK10", 0},
369    {XK_F11, NoSymbol, "FK11", 0},
370    {XK_F12, NoSymbol, "FK12", 0},
371    {XK_Print, NoSymbol, "PRSC", 0},
372    {XK_Scroll_Lock, NoSymbol, "SCLK", 0},
373    {XK_Pause, NoSymbol, "PAUS", 0},
374    {XK_Insert, NoSymbol, "INS\0", 0},
375    {XK_Home, NoSymbol, "HOME", 0},
376    {XK_Prior, NoSymbol, "PGUP", 0},
377    {XK_Delete, NoSymbol, "DELE", 0},
378    {XK_End, NoSymbol, "END", 0},
379    {XK_Next, NoSymbol, "PGDN", 0},
380    {XK_Up, NoSymbol, "UP\0\0", 0},
381    {XK_Left, NoSymbol, "LEFT", 0},
382    {XK_Down, NoSymbol, "DOWN", 0},
383    {XK_Right, NoSymbol, "RGHT", 0},
384    {XK_Num_Lock, NoSymbol, "NMLK", 0},
385    {XK_KP_Divide, NoSymbol, "KPDV", 0},
386    {XK_KP_Multiply, NoSymbol, "KPMU", 0},
387    {XK_KP_Subtract, NoSymbol, "KPSU", 0},
388    {NoSymbol, XK_KP_7, "KP7\0", 0},
389    {NoSymbol, XK_KP_8, "KP8\0", 0},
390    {NoSymbol, XK_KP_9, "KP9\0", 0},
391    {XK_KP_Add, NoSymbol, "KPAD", 0},
392    {NoSymbol, XK_KP_4, "KP4\0", 0},
393    {NoSymbol, XK_KP_5, "KP5\0", 0},
394    {NoSymbol, XK_KP_6, "KP6\0", 0},
395    {NoSymbol, XK_KP_1, "KP1\0", 0},
396    {NoSymbol, XK_KP_2, "KP2\0", 0},
397    {NoSymbol, XK_KP_3, "KP3\0", 0},
398    {XK_KP_Enter, NoSymbol, "KPEN", 0},
399    {NoSymbol, XK_KP_0, "KP0\0", 0},
400    {XK_KP_Delete, NoSymbol, "KPDL", 0},
401    {XK_less, XK_greater, "LSGT", 0},
402    {XK_KP_Separator, NoSymbol, "KPCO", 0},
403    {XK_Find, NoSymbol, "FIND", 0},
404    {NoSymbol, NoSymbol, "\0\0\0\0", 0}
405};
406
407Status
408ComputeKbdDefaults(XkbDescPtr xkb)
409{
410    int nUnknown;
411
412    if ((xkb->names == NULL) || (xkb->names->keys == NULL))
413    {
414        Status rtrn;
415        if ((rtrn = XkbAllocNames(xkb, XkbKeyNamesMask, 0, 0)) != Success)
416            return rtrn;
417    }
418    for (KeyNameDesc *name = dfltKeys; (name->name[0] != '\0'); name++)
419    {
420        name->used = False;
421    }
422    nUnknown = 0;
423    for (int i = xkb->min_key_code; i <= xkb->max_key_code; i++)
424    {
425        int tmp = XkbKeyNumSyms(xkb, i);
426        if ((xkb->names->keys[i].name[0] == '\0') && (tmp > 0))
427        {
428            KeySym *syms;
429
430            tmp = XkbKeyGroupsWidth(xkb, i);
431            syms = XkbKeySymsPtr(xkb, i);
432            for (KeyNameDesc *name = dfltKeys; (name->name[0] != '\0'); name++)
433            {
434                Bool match = True;
435                if (((name->level1 != syms[0])
436                     && (name->level1 != NoSymbol))
437                    || ((name->level2 != NoSymbol) && (tmp < 2))
438                    || ((name->level2 != syms[1])
439                        && (name->level2 != NoSymbol)))
440                {
441                    match = False;
442                }
443                if (match)
444                {
445                    if (!name->used)
446                    {
447                        memcpy(xkb->names->keys[i].name, name->name,
448                               XkbKeyNameLength);
449                        name->used = True;
450                    }
451                    else
452                    {
453                        char tmpname[XkbKeyNameLength + 1];
454
455                        if (warningLevel > 2)
456                        {
457                            WARN
458                                ("Several keys match pattern for %s\n",
459                                 XkbKeyNameText(name->name, XkbMessage));
460                            ACTION("Using <U%03d> for key %d\n",
461                                    nUnknown, i);
462                        }
463                        snprintf(tmpname, sizeof(tmpname), "U%03d",
464                                 nUnknown++);
465                        memcpy(xkb->names->keys[i].name, tmpname,
466                               XkbKeyNameLength);
467                    }
468                    break;
469                }
470            }
471            if (xkb->names->keys[i].name[0] == '\0')
472            {
473                if (warningLevel > 2)
474                {
475                    char tmpname[XkbKeyNameLength + 1];
476
477                    WARN("Key %d does not match any defaults\n", i);
478                    ACTION("Using name <U%03d>\n", nUnknown);
479                    snprintf(tmpname, sizeof(tmpname), "U%03d", nUnknown++);
480                    memcpy(xkb->names->keys[i].name, tmpname,
481                           XkbKeyNameLength);
482                }
483            }
484        }
485    }
486    return Success;
487}
488
489/**
490 * Find the key with the given name and return its keycode in kc_rtrn.
491 *
492 * @param name The 4-letter name of the key as a long.
493 * @param kc_rtrn Set to the keycode if the key was found, otherwise 0.
494 * @param use_aliases True if the key aliases should be searched too.
495 * @param create If True and the key is not found, it is added to the
496 *        xkb->names at the first free keycode.
497 * @param start_from Keycode to start searching from.
498 *
499 * @return True if found, False otherwise.
500 */
501Bool
502FindNamedKey(XkbDescPtr xkb,
503             unsigned long name,
504             unsigned int *kc_rtrn,
505             Bool use_aliases, Bool create, int start_from)
506{
507    if (start_from < xkb->min_key_code)
508    {
509        start_from = xkb->min_key_code;
510    }
511    else if (start_from > xkb->max_key_code)
512    {
513        return False;
514    }
515
516    *kc_rtrn = 0;               /* some callers rely on this */
517    if (xkb && xkb->names && xkb->names->keys)
518    {
519        for (unsigned n = start_from; n <= xkb->max_key_code; n++)
520        {
521            unsigned long tmp;
522            tmp = KeyNameToLong(xkb->names->keys[n].name);
523            if (tmp == name)
524            {
525                *kc_rtrn = n;
526                return True;
527            }
528        }
529        if (use_aliases)
530        {
531            unsigned long new_name;
532            if (FindKeyNameForAlias(xkb, name, &new_name))
533                return FindNamedKey(xkb, new_name, kc_rtrn, False, create, 0);
534        }
535    }
536    if (create)
537    {
538        if ((!xkb->names) || (!xkb->names->keys))
539        {
540            if (xkb->min_key_code < XkbMinLegalKeyCode)
541            {
542                xkb->min_key_code = XkbMinLegalKeyCode;
543                xkb->max_key_code = XkbMaxLegalKeyCode;
544            }
545            if (XkbAllocNames(xkb, XkbKeyNamesMask, 0, 0) != Success)
546            {
547                if (warningLevel > 0)
548                {
549                    WARN("Couldn't allocate key names in FindNamedKey\n");
550                    ACTION("Key \"%s\" not automatically created\n",
551                            longText(name, XkbMessage));
552                }
553                return False;
554            }
555        }
556        /* Find first unused keycode and store our key here */
557        for (unsigned n = xkb->min_key_code; n <= xkb->max_key_code; n++)
558        {
559            if (xkb->names->keys[n].name[0] == '\0')
560            {
561                char buf[XkbKeyNameLength + 1];
562                LongToKeyName(name, buf);
563                memcpy(xkb->names->keys[n].name, buf, XkbKeyNameLength);
564                *kc_rtrn = n;
565                return True;
566            }
567        }
568    }
569    return False;
570}
571
572Bool
573FindKeyNameForAlias(XkbDescPtr xkb, unsigned long lname,
574                    unsigned long *real_name)
575{
576    char name[XkbKeyNameLength + 1];
577
578    if (xkb && xkb->geom && xkb->geom->key_aliases)
579    {
580        XkbKeyAliasPtr a;
581        a = xkb->geom->key_aliases;
582        LongToKeyName(lname, name);
583        name[XkbKeyNameLength] = '\0';
584        for (int i = 0; i < xkb->geom->num_key_aliases; i++, a++)
585        {
586            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
587            {
588                *real_name = KeyNameToLong(a->real);
589                return True;
590            }
591        }
592    }
593    if (xkb && xkb->names && xkb->names->key_aliases)
594    {
595        XkbKeyAliasPtr a;
596        a = xkb->names->key_aliases;
597        LongToKeyName(lname, name);
598        name[XkbKeyNameLength] = '\0';
599        for (int i = 0; i < xkb->names->num_key_aliases; i++, a++)
600        {
601            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
602            {
603                *real_name = KeyNameToLong(a->real);
604                return True;
605            }
606        }
607    }
608    return False;
609}
610