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#endif
30
31#include <stdio.h>
32#include <ctype.h>
33#include <stdlib.h>
34
35#include <X11/Xos.h>
36#include <X11/Xfuncs.h>
37#include <X11/extensions/XKMformat.h>
38
39#include <X11/X.h>
40#include <X11/keysym.h>
41#include <X11/Xproto.h>
42#include "misc.h"
43#include "inputstr.h"
44#include "dix.h"
45#include "xkbstr.h"
46#define XKBSRV_NEED_FILE_FUNCS	1
47#include <xkbsrv.h>
48#include "xkbgeom.h"
49#include "xkb.h"
50
51unsigned
52_XkbKSCheckCase(KeySym ks)
53{
54unsigned	set,rtrn;
55
56    set= (ks & (~0xff)) >> 8;
57    rtrn= 0;
58    switch (set) {
59	case 0:		/* latin 1 */
60	    if (((ks>=XK_A)&&(ks<=XK_Z))||
61		((ks>=XK_Agrave)&&(ks<=XK_THORN)&&(ks!=XK_multiply))) {
62		rtrn|= _XkbKSUpper;
63	    }
64	    if (((ks>=XK_a)&&(ks<=XK_z))||
65		((ks>=XK_agrave)&&(ks<=XK_ydiaeresis))) {
66		rtrn|= _XkbKSLower;
67	    }
68	    break;
69	case 1:		/* latin 2 */
70	    if (((ks>=XK_Aogonek)&&(ks<=XK_Zabovedot)&&(ks!=XK_breve))||
71		((ks>=XK_Racute)&&(ks<=XK_Tcedilla))) {
72		rtrn|= _XkbKSUpper;
73	    }
74	    if (((ks>=XK_aogonek)&&(ks<=XK_zabovedot)&&(ks!=XK_caron))||
75		((ks>=XK_racute)&&(ks<=XK_tcedilla))) {
76		rtrn|= _XkbKSLower;
77	    }
78	    break;
79	case 2:		/* latin 3 */
80	    if (((ks>=XK_Hstroke)&&(ks<=XK_Jcircumflex))||
81		((ks>=XK_Cabovedot)&&(ks<=XK_Scircumflex))) {
82		rtrn|= _XkbKSUpper;
83	    }
84	    if (((ks>=XK_hstroke)&&(ks<=XK_jcircumflex))||
85		((ks>=XK_cabovedot)&&(ks<=XK_scircumflex))) {
86		rtrn|= _XkbKSLower;
87	    }
88	    break;
89	case 3:		/* latin 4 */
90	    if (((ks>=XK_Rcedilla)&&(ks<=XK_Tslash))||
91	        (ks==XK_ENG)||
92		((ks>=XK_Amacron)&&(ks<=XK_Umacron))) {
93		rtrn|= _XkbKSUpper;
94	    }
95	    if (((ks>=XK_rcedilla)&&(ks<=XK_tslash))||
96	        (ks==XK_eng)||
97		((ks>=XK_amacron)&&(ks<=XK_umacron))) {
98		rtrn|= _XkbKSLower;
99	    }
100	    break;
101	case 18:		/* latin 8 */
102	    if ((ks==XK_Babovedot)||
103                ((ks>=XK_Dabovedot)&&(ks<=XK_Wacute))||
104		((ks>=XK_Ygrave)&&(ks<=XK_Fabovedot))||
105	        (ks==XK_Mabovedot)||
106	        (ks==XK_Pabovedot)||
107	        (ks==XK_Sabovedot)||
108	        (ks==XK_Wdiaeresis)||
109		((ks>=XK_Wcircumflex)&&(ks<=XK_Ycircumflex))) {
110		rtrn|= _XkbKSUpper;
111	    }
112	    if ((ks==XK_babovedot)||
113	        (ks==XK_dabovedot)||
114	        (ks==XK_fabovedot)||
115	        (ks==XK_mabovedot)||
116                ((ks>=XK_wgrave)&&(ks<=XK_wacute))||
117	        (ks==XK_ygrave)||
118		((ks>=XK_wdiaeresis)&&(ks<=XK_ycircumflex))) {
119		rtrn|= _XkbKSLower;
120	    }
121	    break;
122	case 19:		/* latin 9 */
123	    if ((ks==XK_OE)||(ks==XK_Ydiaeresis)) {
124		rtrn|= _XkbKSUpper;
125	    }
126	    if (ks==XK_oe) {
127		rtrn|= _XkbKSLower;
128	    }
129	    break;
130    }
131    return rtrn;
132}
133
134/***===================================================================***/
135
136static Bool
137XkbWriteSectionFromName(FILE *file,char *sectionName,char *name)
138{
139    fprintf(file,"    xkb_%-20s { include \"%s\" };\n",sectionName,name);
140    return TRUE;
141}
142
143#define	NEED_DESC(n) ((!n)||((n)[0]=='+')||((n)[0]=='|')||(strchr((n),'%')))
144#define	COMPLETE(n)  ((n)&&(!NEED_DESC(n)))
145
146/* ARGSUSED */
147static void
148_AddIncl(	FILE *		file,
149		XkbDescPtr 	xkb,
150		Bool 		topLevel,
151		Bool 		showImplicit,
152		int 		index,
153		void *		priv)
154{
155    if ((priv)&&(strcmp((char *)priv,"%")!=0))
156	fprintf(file,"    include \"%s\"\n",(char *)priv);
157    return;
158}
159
160Bool
161XkbWriteXKBKeymapForNames(	FILE *			file,
162				XkbComponentNamesPtr	names,
163				XkbDescPtr		xkb,
164				unsigned		want,
165				unsigned		need)
166{
167const char *	tmp;
168unsigned	complete;
169XkbNamesPtr	old_names;
170int		multi_section;
171unsigned	wantNames,wantConfig,wantDflts;
172
173    complete= 0;
174    if (COMPLETE(names->keycodes))	complete|= XkmKeyNamesMask;
175    if (COMPLETE(names->types))		complete|= XkmTypesMask;
176    if (COMPLETE(names->compat))	complete|= XkmCompatMapMask;
177    if (COMPLETE(names->symbols))	complete|= XkmSymbolsMask;
178    if (COMPLETE(names->geometry))	complete|= XkmGeometryMask;
179    want|= (complete|need);
180    if (want&XkmSymbolsMask)
181	want|= XkmKeyNamesMask|XkmTypesMask;
182
183    if (want==0)
184	return FALSE;
185
186    if (xkb) {
187        old_names = xkb->names;
188
189        xkb->defined = 0;
190        /* Wow would it ever be neat if we didn't need this noise. */
191        if (xkb->names && xkb->names->keys)
192            xkb->defined |= XkmKeyNamesMask;
193        if (xkb->map && xkb->map->types)
194            xkb->defined |= XkmTypesMask;
195        if (xkb->compat)
196            xkb->defined |= XkmCompatMapMask;
197        if (xkb->map && xkb->map->num_syms)
198            xkb->defined |= XkmSymbolsMask;
199        if (xkb->indicators)
200            xkb->defined |= XkmIndicatorsMask;
201        if (xkb->geom)
202            xkb->defined |= XkmGeometryMask;
203    }
204    else {
205        old_names= NULL;
206    }
207
208    wantConfig= want&(~complete);
209    if (xkb!=NULL) {
210	if (wantConfig&XkmTypesMask) {
211	    if ((!xkb->map) || (xkb->map->num_types<XkbNumRequiredTypes))
212		wantConfig&= ~XkmTypesMask;
213	}
214	if (wantConfig&XkmCompatMapMask) {
215	    if ((!xkb->compat) || (xkb->compat->num_si<1))
216		wantConfig&= ~XkmCompatMapMask;
217	}
218	if (wantConfig&XkmSymbolsMask) {
219	    if ((!xkb->map) || (!xkb->map->key_sym_map))
220		wantConfig&= ~XkmSymbolsMask;
221	}
222	if (wantConfig&XkmIndicatorsMask) {
223	    if (!xkb->indicators)
224		wantConfig&= ~XkmIndicatorsMask;
225	}
226	if (wantConfig&XkmKeyNamesMask) {
227	    if ((!xkb->names)||(!xkb->names->keys))
228		wantConfig&= ~XkmKeyNamesMask;
229	}
230	if ((wantConfig&XkmGeometryMask)&&(!xkb->geom))
231	    wantConfig&= ~XkmGeometryMask;
232    }
233    else {
234	wantConfig= 0;
235    }
236    complete|= wantConfig;
237
238    wantDflts= 0;
239    wantNames= want&(~complete);
240    if ((xkb!=NULL) && (old_names!=NULL)) {
241	if (wantNames&XkmTypesMask) {
242	    if (old_names->types!=None) {
243		tmp= NameForAtom(old_names->types);
244		names->types= _XkbDupString(tmp);
245	    }
246	    else {
247		wantDflts|= XkmTypesMask;
248	    }
249	    complete|= XkmTypesMask;
250	}
251	if (wantNames&XkmCompatMapMask) {
252	    if (old_names->compat!=None) {
253		tmp= NameForAtom(old_names->compat);
254		names->compat= _XkbDupString(tmp);
255	    }
256	    else wantDflts|= XkmCompatMapMask;
257	    complete|= XkmCompatMapMask;
258	}
259	if (wantNames&XkmSymbolsMask) {
260	    if (old_names->symbols==None)
261		return FALSE;
262	    tmp= NameForAtom(old_names->symbols);
263	    names->symbols= _XkbDupString(tmp);
264	    complete|= XkmSymbolsMask;
265	}
266	if (wantNames&XkmKeyNamesMask) {
267	   if (old_names->keycodes!=None) {
268		tmp= NameForAtom(old_names->keycodes);
269		names->keycodes= _XkbDupString(tmp);
270	    }
271	    else wantDflts|= XkmKeyNamesMask;
272	    complete|= XkmKeyNamesMask;
273	}
274	if (wantNames&XkmGeometryMask) {
275	    if (old_names->geometry==None)
276		return FALSE;
277	    tmp= NameForAtom(old_names->geometry);
278	    names->geometry= _XkbDupString(tmp);
279	    complete|= XkmGeometryMask;
280	    wantNames&= ~XkmGeometryMask;
281	}
282    }
283    if (complete&XkmCompatMapMask)
284	complete|= XkmIndicatorsMask|XkmVirtualModsMask;
285    else if (complete&(XkmSymbolsMask|XkmTypesMask))
286	complete|= XkmVirtualModsMask;
287    if (need & (~complete))
288	return FALSE;
289    if ((complete&XkmSymbolsMask)&&((XkmKeyNamesMask|XkmTypesMask)&(~complete)))
290	return FALSE;
291
292    multi_section= 1;
293    if (((complete&XkmKeymapRequired)==XkmKeymapRequired)&&
294	((complete&(~XkmKeymapLegal))==0)) {
295	fprintf(file,"xkb_keymap \"default\" {\n");
296    }
297    else if (((complete&XkmSemanticsRequired)==XkmSemanticsRequired)&&
298	((complete&(~XkmSemanticsLegal))==0)) {
299	fprintf(file,"xkb_semantics \"default\" {\n");
300    }
301    else if (((complete&XkmLayoutRequired)==XkmLayoutRequired)&&
302	((complete&(~XkmLayoutLegal))==0)) {
303	fprintf(file,"xkb_layout \"default\" {\n");
304    }
305    else if (XkmSingleSection(complete&(~XkmVirtualModsMask))) {
306	multi_section= 0;
307    }
308    else {
309	return FALSE;
310    }
311
312    wantNames= complete&(~(wantConfig|wantDflts));
313    if (wantConfig&XkmKeyNamesMask)
314	XkbWriteXKBKeycodes(file,xkb,FALSE,FALSE,_AddIncl,names->keycodes);
315    else if (wantDflts&XkmKeyNamesMask)
316	fprintf(stderr,"Default symbols not implemented yet!\n");
317    else if (wantNames&XkmKeyNamesMask)
318	XkbWriteSectionFromName(file,"keycodes",names->keycodes);
319
320    if (wantConfig&XkmTypesMask)
321	XkbWriteXKBKeyTypes(file,xkb,FALSE,FALSE,_AddIncl,names->types);
322    else if (wantDflts&XkmTypesMask)
323	fprintf(stderr,"Default types not implemented yet!\n");
324    else if (wantNames&XkmTypesMask)
325	XkbWriteSectionFromName(file,"types",names->types);
326
327    if (wantConfig&XkmCompatMapMask)
328	XkbWriteXKBCompatMap(file,xkb,FALSE,FALSE,_AddIncl,names->compat);
329    else if (wantDflts&XkmCompatMapMask)
330	fprintf(stderr,"Default interps not implemented yet!\n");
331    else if (wantNames&XkmCompatMapMask)
332	XkbWriteSectionFromName(file,"compatibility",names->compat);
333
334    if (wantConfig&XkmSymbolsMask)
335	XkbWriteXKBSymbols(file,xkb,FALSE,FALSE,_AddIncl,names->symbols);
336    else if (wantNames&XkmSymbolsMask)
337	XkbWriteSectionFromName(file,"symbols",names->symbols);
338
339    if (wantConfig&XkmGeometryMask)
340	XkbWriteXKBGeometry(file,xkb,FALSE,FALSE,_AddIncl,names->geometry);
341    else if (wantNames&XkmGeometryMask)
342	XkbWriteSectionFromName(file,"geometry",names->geometry);
343
344    if (multi_section)
345	fprintf(file,"};\n");
346    return TRUE;
347}
348
349/***====================================================================***/
350
351int
352XkbFindKeycodeByName(XkbDescPtr xkb,char *name,Bool use_aliases)
353{
354register int	i;
355
356    if ((!xkb)||(!xkb->names)||(!xkb->names->keys))
357	return 0;
358    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
359	if (strncmp(xkb->names->keys[i].name,name,XkbKeyNameLength)==0)
360	    return i;
361    }
362    if (!use_aliases)
363	return 0;
364    if (xkb->geom && xkb->geom->key_aliases) {
365	XkbKeyAliasPtr	a;
366	a= xkb->geom->key_aliases;
367	for (i=0;i<xkb->geom->num_key_aliases;i++,a++) {
368	    if (strncmp(name,a->alias,XkbKeyNameLength)==0)
369		return XkbFindKeycodeByName(xkb,a->real,FALSE);
370	}
371    }
372    if (xkb->names && xkb->names->key_aliases) {
373	XkbKeyAliasPtr	a;
374	a= xkb->names->key_aliases;
375	for (i=0;i<xkb->names->num_key_aliases;i++,a++) {
376	    if (strncmp(name,a->alias,XkbKeyNameLength)==0)
377		return XkbFindKeycodeByName(xkb,a->real,FALSE);
378	}
379    }
380    return 0;
381}
382
383
384unsigned
385XkbConvertGetByNameComponents(Bool toXkm,unsigned orig)
386{
387unsigned	rtrn;
388
389    rtrn= 0;
390    if (toXkm) {
391	if (orig&XkbGBN_TypesMask)		rtrn|= XkmTypesMask;
392	if (orig&XkbGBN_CompatMapMask)		rtrn|= XkmCompatMapMask;
393	if (orig&XkbGBN_SymbolsMask)		rtrn|= XkmSymbolsMask;
394	if (orig&XkbGBN_IndicatorMapMask)	rtrn|= XkmIndicatorsMask;
395	if (orig&XkbGBN_KeyNamesMask)		rtrn|= XkmKeyNamesMask;
396	if (orig&XkbGBN_GeometryMask)		rtrn|= XkmGeometryMask;
397    }
398    else {
399	if (orig&XkmTypesMask)			rtrn|= XkbGBN_TypesMask;
400	if (orig&XkmCompatMapMask)		rtrn|= XkbGBN_CompatMapMask;
401	if (orig&XkmSymbolsMask)		rtrn|= XkbGBN_SymbolsMask;
402	if (orig&XkmIndicatorsMask)		rtrn|= XkbGBN_IndicatorMapMask;
403	if (orig&XkmKeyNamesMask)		rtrn|= XkbGBN_KeyNamesMask;
404	if (orig&XkmGeometryMask)		rtrn|= XkbGBN_GeometryMask;
405	if (orig!=0)				rtrn|= XkbGBN_OtherNamesMask;
406    }
407    return rtrn;
408}
409
410/***====================================================================***/
411
412#define	UNMATCHABLE(c)	(((c)=='(')||((c)==')')||((c)=='/'))
413
414Bool
415XkbNameMatchesPattern(char *name,char *ptrn)
416{
417    while (ptrn[0]!='\0') {
418	if (name[0]=='\0') {
419	    if (ptrn[0]=='*') {
420		ptrn++;
421		continue;
422	    }
423	    return FALSE;
424	}
425	if (ptrn[0]=='?') {
426	    if (UNMATCHABLE(name[0]))
427		return FALSE;
428	}
429	else if (ptrn[0]=='*') {
430	    if ((!UNMATCHABLE(name[0]))&&XkbNameMatchesPattern(name+1,ptrn))
431		return TRUE;
432	    return XkbNameMatchesPattern(name,ptrn+1);
433	}
434	else if (ptrn[0]!=name[0])
435	    return FALSE;
436	name++;
437	ptrn++;
438    }
439    /* if we get here, the pattern is exhausted (-:just like me:-) */
440    return name[0]=='\0';
441}
442