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