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