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