XKBCvt.c revision b4ee4795
1/*
2
3Copyright 1988, 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <stdio.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35
36#include <X11/X.h>
37#include <X11/Xlib.h>
38#define NEED_EVENTS
39#include "Xlibint.h"
40#include "Xlcint.h"
41#include "XlcPubI.h"
42#include "Ximint.h"
43#include <X11/Xutil.h>
44#include <X11/Xmd.h>
45#define XK_LATIN1
46#define XK_PUBLISHING
47#include <X11/keysym.h>
48#include <X11/extensions/XKBproto.h>
49#include "XKBlibint.h"
50#include <X11/Xlocale.h>
51#include <ctype.h>
52#include <X11/Xos.h>
53
54#ifdef __sgi_not_xconsortium
55#define	XKB_EXTEND_LOOKUP_STRING
56#endif
57
58static int
59_XkbHandleSpecialSym(KeySym keysym, char *buffer, int nbytes, int *extra_rtrn)
60{
61
62    /* try to convert to Latin-1, handling ctrl */
63    if (!(((keysym >= XK_BackSpace) && (keysym <= XK_Clear)) ||
64	   (keysym == XK_Return) || (keysym == XK_Escape) ||
65	   (keysym == XK_KP_Space) || (keysym == XK_KP_Tab) ||
66	   (keysym == XK_KP_Enter) ||
67	   ((keysym >= XK_KP_Multiply) && (keysym <= XK_KP_9)) ||
68	   (keysym == XK_KP_Equal) ||
69	   (keysym == XK_Delete)))
70	return 0;
71
72    if (nbytes<1) {
73	if (extra_rtrn)
74	    *extra_rtrn= 1;
75	return 0;
76    }
77    /* if X keysym, convert to ascii by grabbing low 7 bits */
78    if (keysym == XK_KP_Space)
79	 buffer[0] = XK_space & 0x7F; /* patch encoding botch */
80    else if (keysym == XK_hyphen)
81	 buffer[0] = (char)(XK_minus & 0xFF); /* map to equiv character */
82    else buffer[0] = (char)(keysym & 0x7F);
83    return 1;
84}
85
86/*ARGSUSED*/
87static int
88_XkbKSToKnownSet (	XPointer 	priv,
89			KeySym 		keysym,
90			char *		buffer,
91			int 		nbytes,
92			int *		extra_rtrn)
93{
94    char tbuf[8],*buf;
95
96    if (extra_rtrn)
97	*extra_rtrn= 0;
98
99    /* convert "dead" diacriticals for dumb applications */
100    if ( (keysym&0xffffff00)== 0xfe00 ) {
101	switch ( keysym ) {
102	    case XK_dead_grave:		keysym = XK_grave; break;
103	    case XK_dead_acute:		keysym = XK_acute; break;
104	    case XK_dead_circumflex:	keysym = XK_asciicircum; break;
105	    case XK_dead_tilde:		keysym = XK_asciitilde; break;
106	    case XK_dead_macron:	keysym = XK_macron; break;
107	    case XK_dead_breve:		keysym = XK_breve; break;
108	    case XK_dead_abovedot:	keysym = XK_abovedot; break;
109	    case XK_dead_diaeresis:	keysym = XK_diaeresis; break;
110	    case XK_dead_abovering:	keysym = XK_degree; break;
111	    case XK_dead_doubleacute:	keysym = XK_doubleacute; break;
112	    case XK_dead_caron:		keysym = XK_caron; break;
113	    case XK_dead_cedilla:	keysym = XK_cedilla; break;
114	    case XK_dead_ogonek	:	keysym = XK_ogonek; break;
115	    case XK_dead_iota:		keysym = XK_Greek_iota; break;
116#ifdef XK_KATAKANA
117	    case XK_dead_voiced_sound:	keysym = XK_voicedsound; break;
118	    case XK_dead_semivoiced_sound:keysym = XK_semivoicedsound; break;
119#endif
120	}
121    }
122
123    if (nbytes<1)	buf= tbuf;
124    else		buf= buffer;
125
126    if ((keysym&0xffffff00)==0xff00) {
127	return _XkbHandleSpecialSym(keysym, buf, nbytes, extra_rtrn);
128    }
129    return _XimGetCharCode (priv, keysym, (unsigned char *)buf, nbytes);
130}
131
132typedef struct _XkbToKS {
133	unsigned	 prefix;
134	char		*map;
135} XkbToKS;
136
137/*ARGSUSED*/
138static KeySym
139_XkbKnownSetToKS(XPointer priv,char *buffer,int nbytes,Status *status)
140{
141    if (nbytes!=1)
142	return NoSymbol;
143    if (((buffer[0]&0x80)==0)&&(buffer[0]>=32))
144	return buffer[0];
145    else if ((buffer[0]&0x7f)>=32) {
146	XkbToKS *map= (XkbToKS *)priv;
147	if ( map ) {
148	    if ( map->map )	return map->prefix|map->map[buffer[0]&0x7f];
149	    else		return map->prefix|buffer[0];
150	}
151	return buffer[0];
152    }
153    return NoSymbol;
154}
155
156static KeySym
157__XkbDefaultToUpper(KeySym sym)
158{
159    KeySym	lower,upper;
160
161    XConvertCase(sym, &lower, &upper);
162    return upper;
163}
164
165#ifdef XKB_EXTEND_LOOKUP_STRING
166static int
167Strcmp(char *str1, char *str2)
168{
169    char str[256];
170    char c, *s;
171
172    /*
173     * unchecked strings from the environment can end up here, so check
174     * the length before copying.
175     */
176    if (strlen(str1) >= sizeof(str)) /* almost certain it's a mismatch */
177	return 1;
178
179    for (s = str; (c = *str1++); ) {
180	if (isupper(c))
181	    c = tolower(c);
182	*s++ = c;
183    }
184    *s = '\0';
185    return (strcmp(str, str2));
186}
187#endif
188
189int
190_XkbGetConverters(const char *encoding_name, XkbConverters *cvt_rtrn)
191{
192    if ( !cvt_rtrn ) return 0;
193
194    cvt_rtrn->KSToMB = _XkbKSToKnownSet;
195    cvt_rtrn->KSToMBPriv = _XimGetLocaleCode(encoding_name);
196    cvt_rtrn->MBToKS = _XkbKnownSetToKS;
197    cvt_rtrn->MBToKSPriv = NULL;
198    cvt_rtrn->KSToUpper = __XkbDefaultToUpper;
199    return 1;
200}
201
202/***====================================================================***/
203
204/*
205 * The function _XkbGetCharset seems to be missnamed as what it seems to
206 * be used for is to determine the encoding-name for the locale. ???
207 */
208
209#ifdef XKB_EXTEND_LOOKUP_STRING
210
211/*
212 * XKB_EXTEND_LOOKUP_STRING is not used by the SI. It is used by various
213 * X Consortium/X Project Team members, so we leave it in the source as
214 * an simplify integration by these companies.
215 */
216
217#define	CHARSET_FILE	"/usr/lib/X11/input/charsets"
218static char *_XkbKnownLanguages = "c=ascii:da,de,en,es,fr,is,it,nl,no,pt,sv=iso8859-1:hu,pl,cs=iso8859-2:eo=iso8859-3:sp=iso8859-5:ar,ara=iso8859-6:el=iso8859-7:he=iso8859-8:tr=iso8859-9:lt,lv=iso8859-13:et,fi=iso8859-15:ru=koi8-r:uk=koi8-u:th,th_TH,th_TH.iso8859-11=iso8859-11:th_TH.TIS620=tis620:hy=armscii-8:vi=tcvn-5712:ka=georgian-academy:be,bg=microsoft-cp1251";
219
220char	*
221_XkbGetCharset(void)
222{
223    /*
224     * PAGE USAGE TUNING: explicitly initialize to move these to data
225     * instead of bss
226     */
227    static char buf[100] = { 0 };
228    char lang[256];
229    char *start,*tmp,*end,*next,*set;
230    char *country,*charset;
231    char *locale;
232
233    tmp = getenv( "_XKB_CHARSET" );
234    if ( tmp )
235	return tmp;
236    locale = setlocale(LC_CTYPE,NULL);
237
238    if ( locale == NULL )
239	return NULL;
240
241    if (strlen(locale) >= sizeof(lang))
242	return NULL;
243
244    for (tmp = lang; *tmp = *locale++; tmp++) {
245	if (isupper(*tmp))
246	    *tmp = tolower(*tmp);
247    }
248    country = strchr( lang, '_');
249    if ( country ) {
250	*country++ = '\0';
251	charset = strchr( country, '.' );
252	if ( charset )	*charset++ = '\0';
253	if ( charset ) {
254	    strncpy(buf,charset,99);
255	    buf[99] = '\0';
256	    return buf;
257	}
258    }
259    else {
260	charset = NULL;
261    }
262
263    if ((tmp = getenv("_XKB_LOCALE_CHARSETS"))!=NULL) {
264	start = _XkbAlloc(strlen(tmp) + 1);
265	strcpy(start, tmp);
266	tmp = start;
267    } else {
268	struct stat sbuf;
269	FILE *file;
270#ifndef __UNIXOS2__
271	char *cf = CHARSET_FILE;
272#else
273        char *cf = __XOS2RedirRoot(CHARSET_FILE);
274#endif
275
276#ifndef S_ISREG
277# define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
278#endif
279
280	if ( (stat(cf,&sbuf)==0) && S_ISREG(sbuf.st_mode) &&
281	    (file = fopen(cf,"r")) ) {
282	    tmp = _XkbAlloc(sbuf.st_size+1);
283	    if (tmp!=NULL) {
284		sbuf.st_size = (long)fread(tmp,1,sbuf.st_size,file);
285		tmp[sbuf.st_size] = '\0';
286	    }
287	    fclose(file);
288	}
289    }
290
291    if ( tmp == NULL ) {
292	tmp = _XkbAlloc(strlen(_XkbKnownLanguages) + 1);
293	if (!tmp)
294	    return NULL;
295	strcpy(tmp, _XkbKnownLanguages);
296    }
297    start = tmp;
298    do {
299	if ( (set=strchr(tmp,'=')) == NULL )
300	    break;
301	*set++ = '\0';
302	if ( (next=strchr(set,':')) != NULL )
303	    *next++ = '\0';
304	while ( tmp && *tmp ) {
305	    if ( (end=strchr(tmp,',')) != NULL )
306		*end++ = '\0';
307	    if ( Strcmp( tmp, lang ) == 0 ) {
308		strncpy(buf,set,100);
309		buf[99] = '\0';
310		Xfree(start);
311		return buf;
312	    }
313	    tmp = end;
314	}
315	tmp = next;
316    } while ( tmp && *tmp );
317    Xfree(start);
318    return NULL;
319}
320#else
321char	*
322_XkbGetCharset(void)
323{
324    char *tmp;
325    XLCd lcd;
326
327    tmp = getenv( "_XKB_CHARSET" );
328    if ( tmp )
329	return tmp;
330
331    lcd = _XlcCurrentLC();
332    if ( lcd )
333	return XLC_PUBLIC(lcd,encoding_name);
334
335    return NULL;
336}
337#endif
338
339