xkbmisc.c revision 70728a38
1/************************************************************
2 Copyright (c) 1995 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#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#elif defined(HAVE_CONFIG_H)
30#include <config.h>
31#endif
32
33#include <stdio.h>
34#include <ctype.h>
35#include <stdlib.h>
36
37#include <X11/Xos.h>
38#include <X11/Xfuncs.h>
39
40
41#include <X11/Xlib.h>
42#include <X11/keysym.h>
43#include <X11/XKBlib.h>
44#include <X11/extensions/XKBgeom.h>
45#include "XKMformat.h"
46#include "XKBfileInt.h"
47
48
49unsigned
50_XkbKSCheckCase(KeySym ks)
51{
52    unsigned set, rtrn;
53
54    set = (ks & (~0xff)) >> 8;
55    rtrn = 0;
56    switch (set) {
57    case 0:                    /* latin 1 */
58        if (((ks >= XK_A) && (ks <= XK_Z)) ||
59            ((ks >= XK_Agrave) && (ks <= XK_THORN) && (ks != XK_multiply))) {
60            rtrn |= _XkbKSUpper;
61        }
62        if (((ks >= XK_a) && (ks <= XK_z)) ||
63            ((ks >= XK_agrave) && (ks <= XK_ydiaeresis))) {
64            rtrn |= _XkbKSLower;
65        }
66        break;
67    case 1:                    /* latin 2 */
68        if (((ks >= XK_Aogonek) && (ks <= XK_Zabovedot) && (ks != XK_breve)) ||
69            ((ks >= XK_Racute) && (ks <= XK_Tcedilla))) {
70            rtrn |= _XkbKSUpper;
71        }
72        if (((ks >= XK_aogonek) && (ks <= XK_zabovedot) && (ks != XK_caron)) ||
73            ((ks >= XK_racute) && (ks <= XK_tcedilla))) {
74            rtrn |= _XkbKSLower;
75        }
76        break;
77    case 2:                    /* latin 3 */
78        if (((ks >= XK_Hstroke) && (ks <= XK_Jcircumflex)) ||
79            ((ks >= XK_Cabovedot) && (ks <= XK_Scircumflex))) {
80            rtrn |= _XkbKSUpper;
81        }
82        if (((ks >= XK_hstroke) && (ks <= XK_jcircumflex)) ||
83            ((ks >= XK_cabovedot) && (ks <= XK_scircumflex))) {
84            rtrn |= _XkbKSLower;
85        }
86        break;
87    case 3:                    /* latin 4 */
88        if (((ks >= XK_Rcedilla) && (ks <= XK_Tslash)) ||
89            (ks == XK_ENG) || ((ks >= XK_Amacron) && (ks <= XK_Umacron))) {
90            rtrn |= _XkbKSUpper;
91        }
92        if (((ks >= XK_rcedilla) && (ks <= XK_tslash)) ||
93            (ks == XK_eng) || ((ks >= XK_amacron) && (ks <= XK_umacron))) {
94            rtrn |= _XkbKSLower;
95        }
96        break;
97    case 18:                   /* latin 8 */
98        if ((ks == XK_Babovedot) ||
99            ((ks >= XK_Dabovedot) && (ks <= XK_Wacute)) ||
100            ((ks >= XK_Ygrave) && (ks <= XK_Fabovedot)) ||
101            (ks == XK_Mabovedot) ||
102            (ks == XK_Pabovedot) ||
103            (ks == XK_Sabovedot) ||
104            (ks == XK_Wdiaeresis) ||
105            ((ks >= XK_Wcircumflex) && (ks <= XK_Ycircumflex))) {
106            rtrn |= _XkbKSUpper;
107        }
108        if ((ks == XK_babovedot) ||
109            (ks == XK_dabovedot) ||
110            (ks == XK_fabovedot) ||
111            (ks == XK_mabovedot) ||
112            ((ks >= XK_wgrave) && (ks <= XK_wacute)) ||
113            (ks == XK_ygrave) ||
114            ((ks >= XK_wdiaeresis) && (ks <= XK_ycircumflex))) {
115            rtrn |= _XkbKSLower;
116        }
117        break;
118    case 19:                   /* latin 9 */
119        if ((ks == XK_OE) || (ks == XK_Ydiaeresis)) {
120            rtrn |= _XkbKSUpper;
121        }
122        if (ks == XK_oe) {
123            rtrn |= _XkbKSLower;
124        }
125        break;
126    }
127    return rtrn;
128}
129
130/***===================================================================***/
131
132Bool
133XkbLookupGroupAndLevel(XkbDescPtr       xkb,
134                       int              key,
135                       int *            mods_inout,
136                       int *            grp_inout,
137                       int *            lvl_rtrn)
138{
139    int nG, eG;
140
141    if ((!xkb) || (!XkbKeycodeInRange(xkb, key)) || (!grp_inout))
142        return False;
143
144    nG = XkbKeyNumGroups(xkb, key);
145    eG = *grp_inout;
146
147    if (nG == 0) {
148        *grp_inout = 0;
149        if (lvl_rtrn != NULL)
150            *lvl_rtrn = 0;
151        return False;
152    }
153    else if (nG == 1) {
154        eG = 0;
155    }
156    else if (eG >= nG) {
157        unsigned gI = XkbKeyGroupInfo(xkb, key);
158
159        switch (XkbOutOfRangeGroupAction(gI)) {
160        default:
161            eG %= nG;
162            break;
163        case XkbClampIntoRange:
164            eG = nG - 1;
165            break;
166        case XkbRedirectIntoRange:
167            eG = XkbOutOfRangeGroupNumber(gI);
168            if (eG >= nG)
169                eG = 0;
170            break;
171        }
172    }
173    *grp_inout = eG;
174    if (mods_inout != NULL) {
175        XkbKeyTypePtr type;
176        int preserve;
177
178        type = XkbKeyKeyType(xkb, key, eG);
179        if (lvl_rtrn != NULL)
180            *lvl_rtrn = 0;
181        preserve = 0;
182        if (type->map) {        /* find the shift level */
183            register int i;
184            register XkbKTMapEntryPtr entry;
185
186            for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
187                if ((entry->active) &&
188                    (((*mods_inout) & type->mods.mask) == entry->mods.mask)) {
189                    if (lvl_rtrn != NULL)
190                        *lvl_rtrn = entry->level;
191                    if (type->preserve)
192                        preserve = type->preserve[i].mask;
193                    break;
194                }
195            }
196        }
197        (*mods_inout) &= ~(type->mods.mask & (~preserve));
198    }
199    return True;
200}
201
202/***===================================================================***/
203
204static Bool
205XkbWriteSectionFromName(FILE *file, const char *sectionName, const char *name)
206{
207    fprintf(file, "    xkb_%-20s { include \"%s\" };\n", sectionName, name);
208    return True;
209}
210
211#define	NEED_DESC(n) ((!n)||((n)[0]=='+')||((n)[0]=='|')||(strchr((n),'%')))
212#define	COMPLETE(n)  ((n)&&(!NEED_DESC(n)))
213
214/* ARGSUSED */
215static void
216_AddIncl(FILE *         file,
217         XkbFileInfo *  result,
218         Bool           topLevel,
219         Bool           showImplicit,
220         int            index,
221         void *         priv)
222{
223    if ((priv) && (strcmp((char *) priv, "%") != 0))
224        fprintf(file, "    include \"%s\"\n", (char *) priv);
225    return;
226}
227
228Bool
229XkbWriteXKBKeymapForNames(FILE *                file,
230                          XkbComponentNamesPtr  names,
231                          Display *             dpy,
232                          XkbDescPtr            xkb,
233                          unsigned              want,
234                          unsigned              need)
235{
236    char *name, *tmp;
237    unsigned complete;
238    XkbNamesPtr old_names;
239    int multi_section;
240    unsigned wantNames, wantConfig, wantDflts;
241    XkbFileInfo finfo;
242
243    bzero(&finfo, sizeof(XkbFileInfo));
244
245    complete = 0;
246    if ((name = names->keymap) == NULL)
247        name = "default";
248    if (COMPLETE(names->keycodes))
249        complete |= XkmKeyNamesMask;
250    if (COMPLETE(names->types))
251        complete |= XkmTypesMask;
252    if (COMPLETE(names->compat))
253        complete |= XkmCompatMapMask;
254    if (COMPLETE(names->symbols))
255        complete |= XkmSymbolsMask;
256    if (COMPLETE(names->geometry))
257        complete |= XkmGeometryMask;
258    want |= (complete | need);
259    if (want & XkmSymbolsMask)
260        want |= XkmKeyNamesMask | XkmTypesMask;
261
262    if (want == 0)
263        return False;
264
265    if (xkb != NULL) {
266        old_names = xkb->names;
267        finfo.type = 0;
268        finfo.defined = 0;
269        finfo.xkb = xkb;
270        if (!XkbDetermineFileType(&finfo, XkbXKBFile, NULL))
271            return False;
272    }
273    else
274        old_names = NULL;
275
276    wantConfig = want & (~complete);
277    if (xkb != NULL) {
278        if (wantConfig & XkmTypesMask) {
279            if ((!xkb->map) || (xkb->map->num_types < XkbNumRequiredTypes))
280                wantConfig &= ~XkmTypesMask;
281        }
282        if (wantConfig & XkmCompatMapMask) {
283            if ((!xkb->compat) || (xkb->compat->num_si < 1))
284                wantConfig &= ~XkmCompatMapMask;
285        }
286        if (wantConfig & XkmSymbolsMask) {
287            if ((!xkb->map) || (!xkb->map->key_sym_map))
288                wantConfig &= ~XkmSymbolsMask;
289        }
290        if (wantConfig & XkmIndicatorsMask) {
291            if (!xkb->indicators)
292                wantConfig &= ~XkmIndicatorsMask;
293        }
294        if (wantConfig & XkmKeyNamesMask) {
295            if ((!xkb->names) || (!xkb->names->keys))
296                wantConfig &= ~XkmKeyNamesMask;
297        }
298        if ((wantConfig & XkmGeometryMask) && (!xkb->geom))
299            wantConfig &= ~XkmGeometryMask;
300    }
301    else {
302        wantConfig = 0;
303    }
304    complete |= wantConfig;
305
306    wantDflts = 0;
307    wantNames = want & (~complete);
308    if ((xkb != NULL) && (old_names != NULL)) {
309        if (wantNames & XkmTypesMask) {
310            if (old_names->types != None) {
311                tmp = XkbAtomGetString(dpy, old_names->types);
312                names->types = tmp;
313            }
314            else {
315                wantDflts |= XkmTypesMask;
316            }
317            complete |= XkmTypesMask;
318        }
319        if (wantNames & XkmCompatMapMask) {
320            if (old_names->compat != None) {
321                tmp = XkbAtomGetString(dpy, old_names->compat);
322                names->compat = tmp;
323            }
324            else
325                wantDflts |= XkmCompatMapMask;
326            complete |= XkmCompatMapMask;
327        }
328        if (wantNames & XkmSymbolsMask) {
329            if (old_names->symbols == None)
330                return False;
331            tmp = XkbAtomGetString(dpy, old_names->symbols);
332            names->symbols = tmp;
333            complete |= XkmSymbolsMask;
334        }
335        if (wantNames & XkmKeyNamesMask) {
336            if (old_names->keycodes != None) {
337                tmp = XkbAtomGetString(dpy, old_names->keycodes);
338                names->keycodes = tmp;
339            }
340            else
341                wantDflts |= XkmKeyNamesMask;
342            complete |= XkmKeyNamesMask;
343        }
344        if (wantNames & XkmGeometryMask) {
345            if (old_names->geometry == None)
346                return False;
347            tmp = XkbAtomGetString(dpy, old_names->geometry);
348            names->geometry = tmp;
349            complete |= XkmGeometryMask;
350            wantNames &= ~XkmGeometryMask;
351        }
352    }
353    if (complete & XkmCompatMapMask)
354        complete |= XkmIndicatorsMask | XkmVirtualModsMask;
355    else if (complete & (XkmSymbolsMask | XkmTypesMask))
356        complete |= XkmVirtualModsMask;
357    if (need & (~complete))
358        return False;
359    if ((complete & XkmSymbolsMask) &&
360        ((XkmKeyNamesMask | XkmTypesMask) & (~complete)))
361        return False;
362
363    multi_section = 1;
364    if (((complete & XkmKeymapRequired) == XkmKeymapRequired) &&
365        ((complete & (~XkmKeymapLegal)) == 0)) {
366        fprintf(file, "xkb_keymap \"%s\" {\n", name);
367    }
368    else if (((complete & XkmSemanticsRequired) == XkmSemanticsRequired) &&
369             ((complete & (~XkmSemanticsLegal)) == 0)) {
370        fprintf(file, "xkb_semantics \"%s\" {\n", name);
371    }
372    else if (((complete & XkmLayoutRequired) == XkmLayoutRequired) &&
373             ((complete & (~XkmLayoutLegal)) == 0)) {
374        fprintf(file, "xkb_layout \"%s\" {\n", name);
375    }
376    else if (XkmSingleSection(complete & (~XkmVirtualModsMask))) {
377        multi_section = 0;
378    }
379    else {
380        return False;
381    }
382
383    wantNames = complete & (~(wantConfig | wantDflts));
384    name = names->keycodes;
385    if (wantConfig & XkmKeyNamesMask)
386        XkbWriteXKBKeycodes(file, &finfo, False, False, _AddIncl, name);
387    else if (wantDflts & XkmKeyNamesMask)
388        fprintf(stderr, "Default symbols not implemented yet!\n");
389    else if (wantNames & XkmKeyNamesMask)
390        XkbWriteSectionFromName(file, "keycodes", name);
391
392    name = names->types;
393    if (wantConfig & XkmTypesMask)
394        XkbWriteXKBKeyTypes(file, &finfo, False, False, _AddIncl, name);
395    else if (wantDflts & XkmTypesMask)
396        fprintf(stderr, "Default types not implemented yet!\n");
397    else if (wantNames & XkmTypesMask)
398        XkbWriteSectionFromName(file, "types", name);
399
400    name = names->compat;
401    if (wantConfig & XkmCompatMapMask)
402        XkbWriteXKBCompatMap(file, &finfo, False, False, _AddIncl, name);
403    else if (wantDflts & XkmCompatMapMask)
404        fprintf(stderr, "Default interps not implemented yet!\n");
405    else if (wantNames & XkmCompatMapMask)
406        XkbWriteSectionFromName(file, "compatibility", name);
407
408    name = names->symbols;
409    if (wantConfig & XkmSymbolsMask)
410        XkbWriteXKBSymbols(file, &finfo, False, False, _AddIncl, name);
411    else if (wantNames & XkmSymbolsMask)
412        XkbWriteSectionFromName(file, "symbols", name);
413
414    name = names->geometry;
415    if (wantConfig & XkmGeometryMask)
416        XkbWriteXKBGeometry(file, &finfo, False, False, _AddIncl, name);
417    else if (wantNames & XkmGeometryMask)
418        XkbWriteSectionFromName(file, "geometry", name);
419
420    if (multi_section)
421        fprintf(file, "};\n");
422    return True;
423}
424
425/***====================================================================***/
426
427/*ARGSUSED*/
428Status
429XkbMergeFile(XkbDescPtr xkb, XkbFileInfo finfo)
430{
431    return BadImplementation;
432}
433
434/***====================================================================***/
435
436int
437XkbFindKeycodeByName(XkbDescPtr xkb, char *name, Bool use_aliases)
438{
439    register int i;
440
441    if ((!xkb) || (!xkb->names) || (!xkb->names->keys))
442        return 0;
443    for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
444        if (strncmp(xkb->names->keys[i].name, name, XkbKeyNameLength) == 0)
445            return i;
446    }
447    if (!use_aliases)
448        return 0;
449    if (xkb->geom && xkb->geom->key_aliases) {
450        XkbKeyAliasPtr a;
451
452        a = xkb->geom->key_aliases;
453        for (i = 0; i < xkb->geom->num_key_aliases; i++, a++) {
454            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
455                return XkbFindKeycodeByName(xkb, a->real, False);
456        }
457    }
458    if (xkb->names && xkb->names->key_aliases) {
459        XkbKeyAliasPtr a;
460
461        a = xkb->names->key_aliases;
462        for (i = 0; i < xkb->names->num_key_aliases; i++, a++) {
463            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
464                return XkbFindKeycodeByName(xkb, a->real, False);
465        }
466    }
467    return 0;
468}
469
470unsigned
471XkbConvertGetByNameComponents(Bool toXkm, unsigned orig)
472{
473    unsigned rtrn;
474
475    rtrn = 0;
476    if (toXkm) {
477        if (orig & XkbGBN_TypesMask)
478            rtrn |= XkmTypesMask;
479        if (orig & XkbGBN_CompatMapMask)
480            rtrn |= XkmCompatMapMask;
481        if (orig & XkbGBN_SymbolsMask)
482            rtrn |= XkmSymbolsMask;
483        if (orig & XkbGBN_IndicatorMapMask)
484            rtrn |= XkmIndicatorsMask;
485        if (orig & XkbGBN_KeyNamesMask)
486            rtrn |= XkmKeyNamesMask;
487        if (orig & XkbGBN_GeometryMask)
488            rtrn |= XkmGeometryMask;
489    }
490    else {
491        if (orig & XkmTypesMask)
492            rtrn |= XkbGBN_TypesMask;
493        if (orig & XkmCompatMapMask)
494            rtrn |= XkbGBN_CompatMapMask;
495        if (orig & XkmSymbolsMask)
496            rtrn |= XkbGBN_SymbolsMask;
497        if (orig & XkmIndicatorsMask)
498            rtrn |= XkbGBN_IndicatorMapMask;
499        if (orig & XkmKeyNamesMask)
500            rtrn |= XkbGBN_KeyNamesMask;
501        if (orig & XkmGeometryMask)
502            rtrn |= XkbGBN_GeometryMask;
503        if (orig != 0)
504            rtrn |= XkbGBN_OtherNamesMask;
505    }
506    return rtrn;
507}
508
509unsigned
510XkbConvertXkbComponents(Bool toXkm, unsigned orig)
511{
512    unsigned rtrn;
513
514    rtrn = 0;
515    if (toXkm) {
516        if (orig & XkbClientMapMask)
517            rtrn |= XkmTypesMask | XkmSymbolsMask;
518        if (orig & XkbServerMapMask)
519            rtrn |= XkmTypesMask | XkmSymbolsMask;
520        if (orig & XkbCompatMapMask)
521            rtrn |= XkmCompatMapMask;
522        if (orig & XkbIndicatorMapMask)
523            rtrn |= XkmIndicatorsMask;
524        if (orig & XkbNamesMask)
525            rtrn |= XkmKeyNamesMask;
526        if (orig & XkbGeometryMask)
527            rtrn |= XkmGeometryMask;
528    }
529    else {
530        if (orig != 0)
531            rtrn |= XkbNamesMask;
532        if (orig & XkmTypesMask)
533            rtrn |= XkbClientMapMask;
534        if (orig & XkmCompatMapMask)
535            rtrn |= XkbCompatMapMask | XkbIndicatorMapMask;
536        if (orig & XkmSymbolsMask)
537            rtrn |= XkbClientMapMask | XkbServerMapMask;
538        if (orig & XkmIndicatorsMask)
539            rtrn |= XkbIndicatorMapMask;
540        if (orig & XkmKeyNamesMask)
541            rtrn |= XkbNamesMask | XkbIndicatorMapMask;
542        if (orig & XkmGeometryMask)
543            rtrn |= XkbGeometryMask;
544    }
545    return rtrn;
546}
547
548Bool
549XkbDetermineFileType(XkbFileInfoPtr finfo, int format, int *opts_missing)
550{
551    unsigned present;
552    XkbDescPtr xkb;
553
554    if ((!finfo) || (!finfo->xkb))
555        return False;
556    if (opts_missing)
557        *opts_missing = 0;
558    xkb = finfo->xkb;
559    present = 0;
560    if ((xkb->names) && (xkb->names->keys))
561        present |= XkmKeyNamesMask;
562    if ((xkb->map) && (xkb->map->types))
563        present |= XkmTypesMask;
564    if (xkb->compat)
565        present |= XkmCompatMapMask;
566    if ((xkb->map) && (xkb->map->num_syms > 1))
567        present |= XkmSymbolsMask;
568    if (xkb->indicators)
569        present |= XkmIndicatorsMask;
570    if (xkb->geom)
571        present |= XkmGeometryMask;
572    if (!present)
573        return False;
574    else
575        switch (present) {
576        case XkmKeyNamesMask:
577            finfo->type = XkmKeyNamesIndex;
578            finfo->defined = present;
579            return True;
580        case XkmTypesMask:
581            finfo->type = XkmTypesIndex;
582            finfo->defined = present;
583            return True;
584        case XkmCompatMapMask:
585            finfo->type = XkmCompatMapIndex;
586            finfo->defined = present;
587            return True;
588        case XkmSymbolsMask:
589            if (format != XkbXKMFile) {
590                finfo->type = XkmSymbolsIndex;
591                finfo->defined = present;
592                return True;
593            }
594            break;
595        case XkmGeometryMask:
596            finfo->type = XkmGeometryIndex;
597            finfo->defined = present;
598            return True;
599        }
600    if ((present & (~XkmSemanticsLegal)) == 0) {
601        if ((XkmSemanticsRequired & present) == XkmSemanticsRequired) {
602            if (opts_missing)
603                *opts_missing = XkmSemanticsOptional & (~present);
604            finfo->type = XkmSemanticsFile;
605            finfo->defined = present;
606            return True;
607        }
608    }
609    else if ((present & (~XkmLayoutLegal)) == 0) {
610        if ((XkmLayoutRequired & present) == XkmLayoutRequired) {
611            if (opts_missing)
612                *opts_missing = XkmLayoutOptional & (~present);
613            finfo->type = XkmLayoutFile;
614            finfo->defined = present;
615            return True;
616        }
617    }
618    else if ((present & (~XkmKeymapLegal)) == 0) {
619        if ((XkmKeymapRequired & present) == XkmKeymapRequired) {
620            if (opts_missing)
621                *opts_missing = XkmKeymapOptional & (~present);
622            finfo->type = XkmKeymapFile;
623            finfo->defined = present;
624            return True;
625        }
626    }
627    return False;
628}
629
630/* all latin-1 alphanumerics, plus parens, slash, minus, underscore and */
631/* wildcards */
632
633static unsigned char componentSpecLegal[] = {
634    0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x83,
635    0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
636    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637    0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
638};
639
640void
641XkbEnsureSafeMapName(char *name)
642{
643    if (name == NULL)
644        return;
645    while (*name != '\0') {
646        if ((componentSpecLegal[(*name) / 8] & (1 << ((*name) % 8))) == 0)
647            *name = '_';
648        name++;
649    }
650    return;
651}
652
653/***====================================================================***/
654
655#define	UNMATCHABLE(c)	(((c)=='(')||((c)==')')||((c)=='/'))
656
657Bool
658XkbNameMatchesPattern(char *name, char *ptrn)
659{
660    while (ptrn[0] != '\0') {
661        if (name[0] == '\0') {
662            if (ptrn[0] == '*') {
663                ptrn++;
664                continue;
665            }
666            return False;
667        }
668        if (ptrn[0] == '?') {
669            if (UNMATCHABLE(name[0]))
670                return False;
671        }
672        else if (ptrn[0] == '*') {
673            if ((!UNMATCHABLE(name[0])) &&
674                XkbNameMatchesPattern(name + 1, ptrn))
675                return True;
676            return XkbNameMatchesPattern(name, ptrn + 1);
677        }
678        else if (ptrn[0] != name[0])
679            return False;
680        name++;
681        ptrn++;
682    }
683    /* if we get here, the pattern is exhausted (-:just like me:-) */
684    return (name[0] == '\0');
685}
686
687#ifdef NEED_STRCASECMP
688_X_HIDDEN int
689_XkbStrCaseCmp(char *str1, char *str2)
690{
691    const u_char *us1 = (const u_char *) str1, *us2 = (const u_char *) str2;
692
693    while (tolower(*us1) == tolower(*us2)) {
694        if (*us1++ == '\0')
695            return (0);
696        us2++;
697    }
698
699    return (tolower(*us1) - tolower(*us2));
700}
701#endif
702