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