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