XKBCvt.c revision e9fcaa8a
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#include "Xlibint.h"
39#include "Xlcint.h"
40#include "XlcPubI.h"
41#include "Ximint.h"
42#include <X11/Xutil.h>
43#include <X11/Xmd.h>
44#define XK_LATIN1
45#define XK_PUBLISHING
46#include <X11/keysym.h>
47#include <X11/extensions/XKBproto.h>
48#include "XKBlibint.h"
49#include <X11/Xlocale.h>
50#include <ctype.h>
51#include <X11/Xos.h>
52
53#ifdef __sgi_not_xconsortium
54#define	XKB_EXTEND_LOOKUP_STRING
55#endif
56
57static int
58_XkbHandleSpecialSym(KeySym keysym, char *buffer, int nbytes, int *extra_rtrn)
59{
60
61    /* try to convert to Latin-1, handling ctrl */
62    if (!(((keysym >= XK_BackSpace) && (keysym <= XK_Clear)) ||
63	   (keysym == XK_Return) || (keysym == XK_Escape) ||
64	   (keysym == XK_KP_Space) || (keysym == XK_KP_Tab) ||
65	   (keysym == XK_KP_Enter) ||
66	   ((keysym >= XK_KP_Multiply) && (keysym <= XK_KP_9)) ||
67	   (keysym == XK_KP_Equal) ||
68	   (keysym == XK_Delete)))
69	return 0;
70
71    if (nbytes<1) {
72	if (extra_rtrn)
73	    *extra_rtrn= 1;
74	return 0;
75    }
76    /* if X keysym, convert to ascii by grabbing low 7 bits */
77    if (keysym == XK_KP_Space)
78	 buffer[0] = XK_space & 0x7F; /* patch encoding botch */
79    else if (keysym == XK_hyphen)
80	 buffer[0] = (char)(XK_minus & 0xFF); /* map to equiv character */
81    else buffer[0] = (char)(keysym & 0x7F);
82    return 1;
83}
84
85/*ARGSUSED*/
86static int
87_XkbKSToKnownSet (	XPointer 	priv,
88			KeySym 		keysym,
89			char *		buffer,
90			int 		nbytes,
91			int *		extra_rtrn)
92{
93    char tbuf[8],*buf;
94
95    if (extra_rtrn)
96	*extra_rtrn= 0;
97
98    /* convert "dead" diacriticals for dumb applications */
99    if ( (keysym&0xffffff00)== 0xfe00 ) {
100	switch ( keysym ) {
101	    case XK_dead_grave:		keysym = XK_grave; break;
102	    case XK_dead_acute:		keysym = XK_acute; break;
103	    case XK_dead_circumflex:	keysym = XK_asciicircum; break;
104	    case XK_dead_tilde:		keysym = XK_asciitilde; break;
105	    case XK_dead_macron:	keysym = XK_macron; break;
106	    case XK_dead_breve:		keysym = XK_breve; break;
107	    case XK_dead_abovedot:	keysym = XK_abovedot; break;
108	    case XK_dead_diaeresis:	keysym = XK_diaeresis; break;
109	    case XK_dead_abovering:	keysym = XK_degree; break;
110	    case XK_dead_doubleacute:	keysym = XK_doubleacute; break;
111	    case XK_dead_caron:		keysym = XK_caron; break;
112	    case XK_dead_cedilla:	keysym = XK_cedilla; break;
113	    case XK_dead_ogonek	:	keysym = XK_ogonek; break;
114	    case XK_dead_iota:		keysym = XK_Greek_iota; break;
115#ifdef XK_KATAKANA
116	    case XK_dead_voiced_sound:	keysym = XK_voicedsound; break;
117	    case XK_dead_semivoiced_sound:keysym = XK_semivoicedsound; break;
118#endif
119	}
120    }
121
122    if (nbytes<1)	buf= tbuf;
123    else		buf= buffer;
124
125    if ((keysym&0xffffff00)==0xff00) {
126	return _XkbHandleSpecialSym(keysym, buf, nbytes, extra_rtrn);
127    }
128    return _XimGetCharCode (priv, keysym, (unsigned char *)buf, nbytes);
129}
130
131typedef struct _XkbToKS {
132	unsigned	 prefix;
133	char		*map;
134} XkbToKS;
135
136/*ARGSUSED*/
137static KeySym
138_XkbKnownSetToKS(XPointer priv,char *buffer,int nbytes,Status *status)
139{
140    if (nbytes!=1)
141	return NoSymbol;
142    if (((buffer[0]&0x80)==0)&&(buffer[0]>=32))
143	return buffer[0];
144    else if ((buffer[0]&0x7f)>=32) {
145	XkbToKS *map= (XkbToKS *)priv;
146	if ( map ) {
147	    if ( map->map )	return map->prefix|map->map[buffer[0]&0x7f];
148	    else		return map->prefix|buffer[0];
149	}
150	return buffer[0];
151    }
152    return NoSymbol;
153}
154
155static KeySym
156__XkbDefaultToUpper(KeySym sym)
157{
158    KeySym	lower,upper;
159
160    XConvertCase(sym, &lower, &upper);
161    return upper;
162}
163
164#ifdef XKB_EXTEND_LOOKUP_STRING
165static int
166Strcmp(char *str1, char *str2)
167{
168    char str[256];
169    char c, *s;
170
171    /*
172     * unchecked strings from the environment can end up here, so check
173     * the length before copying.
174     */
175    if (strlen(str1) >= sizeof(str)) /* almost certain it's a mismatch */
176	return 1;
177
178    for (s = str; (c = *str1++); ) {
179	if (isupper(c))
180	    c = tolower(c);
181	*s++ = c;
182    }
183    *s = '\0';
184    return (strcmp(str, str2));
185}
186#endif
187
188int
189_XkbGetConverters(const char *encoding_name, XkbConverters *cvt_rtrn)
190{
191    if ( !cvt_rtrn ) return 0;
192
193    cvt_rtrn->KSToMB = _XkbKSToKnownSet;
194    cvt_rtrn->KSToMBPriv = _XimGetLocaleCode(encoding_name);
195    cvt_rtrn->MBToKS = _XkbKnownSetToKS;
196    cvt_rtrn->MBToKSPriv = NULL;
197    cvt_rtrn->KSToUpper = __XkbDefaultToUpper;
198    return 1;
199}
200
201/***====================================================================***/
202
203/*
204 * The function _XkbGetCharset seems to be missnamed as what it seems to
205 * be used for is to determine the encoding-name for the locale. ???
206 */
207
208#ifdef XKB_EXTEND_LOOKUP_STRING
209
210/*
211 * XKB_EXTEND_LOOKUP_STRING is not used by the SI. It is used by various
212 * X Consortium/X Project Team members, so we leave it in the source as
213 * an simplify integration by these companies.
214 */
215
216#define	CHARSET_FILE	"/usr/lib/X11/input/charsets"
217static 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";
218
219char	*
220_XkbGetCharset(void)
221{
222    /*
223     * PAGE USAGE TUNING: explicitly initialize to move these to data
224     * instead of bss
225     */
226    static char buf[100] = { 0 };
227    char lang[256];
228    char *start,*tmp,*end,*next,*set;
229    char *country,*charset;
230    char *locale;
231
232    tmp = getenv( "_XKB_CHARSET" );
233    if ( tmp )
234	return tmp;
235    locale = setlocale(LC_CTYPE,NULL);
236
237    if ( locale == NULL )
238	return NULL;
239
240    if (strlen(locale) >= sizeof(lang))
241	return NULL;
242
243    for (tmp = lang; *tmp = *locale++; tmp++) {
244	if (isupper(*tmp))
245	    *tmp = tolower(*tmp);
246    }
247    country = strchr( lang, '_');
248    if ( country ) {
249	*country++ = '\0';
250	charset = strchr( country, '.' );
251	if ( charset )	*charset++ = '\0';
252	if ( charset ) {
253	    strncpy(buf,charset,99);
254	    buf[99] = '\0';
255	    return buf;
256	}
257    }
258    else {
259	charset = NULL;
260    }
261
262    if ((tmp = getenv("_XKB_LOCALE_CHARSETS"))!=NULL) {
263	start = _XkbAlloc(strlen(tmp) + 1);
264	strcpy(start, tmp);
265	tmp = start;
266    } else {
267	struct stat sbuf;
268	FILE *file;
269#ifndef __UNIXOS2__
270	char *cf = CHARSET_FILE;
271#else
272        char *cf = __XOS2RedirRoot(CHARSET_FILE);
273#endif
274
275#ifndef S_ISREG
276# define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
277#endif
278
279	if ( (stat(cf,&sbuf)==0) && S_ISREG(sbuf.st_mode) &&
280	    (file = fopen(cf,"r")) ) {
281	    tmp = _XkbAlloc(sbuf.st_size+1);
282	    if (tmp!=NULL) {
283		sbuf.st_size = (long)fread(tmp,1,sbuf.st_size,file);
284		tmp[sbuf.st_size] = '\0';
285	    }
286	    fclose(file);
287	}
288    }
289
290    if ( tmp == NULL ) {
291	tmp = _XkbAlloc(strlen(_XkbKnownLanguages) + 1);
292	if (!tmp)
293	    return NULL;
294	strcpy(tmp, _XkbKnownLanguages);
295    }
296    start = tmp;
297    do {
298	if ( (set=strchr(tmp,'=')) == NULL )
299	    break;
300	*set++ = '\0';
301	if ( (next=strchr(set,':')) != NULL )
302	    *next++ = '\0';
303	while ( tmp && *tmp ) {
304	    if ( (end=strchr(tmp,',')) != NULL )
305		*end++ = '\0';
306	    if ( Strcmp( tmp, lang ) == 0 ) {
307		strncpy(buf,set,100);
308		buf[99] = '\0';
309		Xfree(start);
310		return buf;
311	    }
312	    tmp = end;
313	}
314	tmp = next;
315    } while ( tmp && *tmp );
316    Xfree(start);
317    return NULL;
318}
319#else
320char	*
321_XkbGetCharset(void)
322{
323    char *tmp;
324    XLCd lcd;
325
326    tmp = getenv( "_XKB_CHARSET" );
327    if ( tmp )
328	return tmp;
329
330    lcd = _XlcCurrentLC();
331    if ( lcd )
332	return XLC_PUBLIC(lcd,encoding_name);
333
334    return NULL;
335}
336#endif
337
338