XKBCvt.c revision e9628295
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    /* try to convert to Latin-1, handling ctrl */
61    if (!(((keysym >= XK_BackSpace) && (keysym <= XK_Clear)) ||
62          (keysym == XK_Return) || (keysym == XK_Escape) ||
63          (keysym == XK_KP_Space) || (keysym == XK_KP_Tab) ||
64          (keysym == XK_KP_Enter) ||
65          ((keysym >= XK_KP_Multiply) && (keysym <= XK_KP_9)) ||
66          (keysym == XK_KP_Equal) || (keysym == XK_Delete)))
67        return 0;
68
69    if (nbytes < 1) {
70        if (extra_rtrn)
71            *extra_rtrn = 1;
72        return 0;
73    }
74    /* if X keysym, convert to ascii by grabbing low 7 bits */
75    if (keysym == XK_KP_Space)
76        buffer[0] = XK_space & 0x7F;            /* patch encoding botch */
77    else
78        buffer[0] = (char) (keysym & 0x7F);
79    return 1;
80}
81
82/*ARGSUSED*/
83static int
84_XkbKSToKnownSet(XPointer priv,
85                 KeySym keysym,
86                 char *buffer,
87                 int nbytes,
88                 int *extra_rtrn)
89{
90    char tbuf[8], *buf;
91
92    if (extra_rtrn)
93        *extra_rtrn = 0;
94
95    /* convert "dead" diacriticals for dumb applications */
96    if ((keysym & 0xffffff00) == 0xfe00) {
97        switch (keysym) {
98        case XK_dead_grave:            keysym = XK_grave; break;
99        case XK_dead_acute:            keysym = XK_acute; break;
100        case XK_dead_circumflex:       keysym = XK_asciicircum; break;
101        case XK_dead_tilde:            keysym = XK_asciitilde; break;
102        case XK_dead_macron:           keysym = XK_macron; break;
103        case XK_dead_breve:            keysym = XK_breve; break;
104        case XK_dead_abovedot:         keysym = XK_abovedot; break;
105        case XK_dead_diaeresis:        keysym = XK_diaeresis; break;
106        case XK_dead_abovering:        keysym = XK_degree; break;
107        case XK_dead_doubleacute:      keysym = XK_doubleacute; break;
108        case XK_dead_caron:            keysym = XK_caron; break;
109        case XK_dead_cedilla:          keysym = XK_cedilla; break;
110        case XK_dead_ogonek:           keysym = XK_ogonek; break;
111        case XK_dead_iota:             keysym = XK_Greek_iota; break;
112#ifdef XK_KATAKANA
113        case XK_dead_voiced_sound:     keysym = XK_voicedsound; break;
114        case XK_dead_semivoiced_sound: keysym = XK_semivoicedsound; break;
115#endif
116        }
117    }
118
119    if (nbytes < 1)
120        buf = tbuf;
121    else
122        buf = buffer;
123
124    if ((keysym & 0xffffff00) == 0xff00) {
125        return _XkbHandleSpecialSym(keysym, buf, nbytes, extra_rtrn);
126    }
127    return _XimGetCharCode(priv, keysym, (unsigned char *) buf, nbytes);
128}
129
130typedef struct _XkbToKS {
131    unsigned prefix;
132    char *map;
133} XkbToKS;
134
135/*ARGSUSED*/
136static KeySym
137_XkbKnownSetToKS(XPointer priv, char *buffer, int nbytes, Status *status)
138{
139    if (nbytes != 1)
140        return NoSymbol;
141    if (((buffer[0] & 0x80) == 0) && (buffer[0] >= 32))
142        return buffer[0];
143    else if ((buffer[0] & 0x7f) >= 32) {
144        XkbToKS *map = (XkbToKS *) priv;
145
146        if (map) {
147            if (map->map)
148                return map->prefix | map->map[buffer[0] & 0x7f];
149            else
150                return map->prefix | buffer[0];
151        }
152        return buffer[0];
153    }
154    return NoSymbol;
155}
156
157static KeySym
158__XkbDefaultToUpper(KeySym sym)
159{
160    KeySym lower, upper;
161
162    XConvertCase(sym, &lower, &upper);
163    return upper;
164}
165
166#ifdef XKB_EXTEND_LOOKUP_STRING
167static int
168Strcmp(char *str1, char *str2)
169{
170    char str[256];
171    char c, *s;
172
173    /*
174     * unchecked strings from the environment can end up here, so check
175     * the length before copying.
176     */
177    if (strlen(str1) >= sizeof(str))    /* almost certain it's a mismatch */
178        return 1;
179
180    for (s = str; (c = *str1++);) {
181        if (isupper(c))
182            c = tolower(c);
183        *s++ = c;
184    }
185    *s = '\0';
186    return (strcmp(str, str2));
187}
188#endif
189
190int
191_XkbGetConverters(const char *encoding_name, XkbConverters * cvt_rtrn)
192{
193    if (!cvt_rtrn)
194        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 =
221    "c=ascii:da,de,en,es,fr,is,it,nl,no,pt,sv=iso8859-1:hu,pl,cs=iso8859-2:"
222    "eo=iso8859-3:sp=iso8859-5:ar,ara=iso8859-6:el=iso8859-7:he=iso8859-8:"
223    "tr=iso8859-9:lt,lv=iso8859-13:et,fi=iso8859-15:ru=koi8-r:uk=koi8-u:"
224    "th,th_TH,th_TH.iso8859-11=iso8859-11:th_TH.TIS620=tis620:hy=armscii-8:"
225    "vi=tcvn-5712:ka=georgian-academy:be,bg=microsoft-cp1251";
226
227char *
228_XkbGetCharset(void)
229{
230    /*
231     * PAGE USAGE TUNING: explicitly initialize to move these to data
232     * instead of bss
233     */
234    static char buf[100] = { 0 };
235    char lang[256];
236    char *start, *tmp, *end, *next, *set;
237    char *country, *charset;
238    char *locale;
239
240    tmp = getenv("_XKB_CHARSET");
241    if (tmp)
242        return tmp;
243    locale = setlocale(LC_CTYPE, NULL);
244
245    if (locale == NULL)
246        return NULL;
247
248    if (strlen(locale) >= sizeof(lang))
249        return NULL;
250
251    for (tmp = lang; *tmp = *locale++; tmp++) {
252        if (isupper(*tmp))
253            *tmp = tolower(*tmp);
254    }
255    country = strchr(lang, '_');
256    if (country) {
257        *country++ = '\0';
258        charset = strchr(country, '.');
259        if (charset)
260            *charset++ = '\0';
261        if (charset) {
262            strncpy(buf, charset, 99);
263            buf[99] = '\0';
264            return buf;
265        }
266    }
267    else {
268        charset = NULL;
269    }
270
271    if ((tmp = getenv("_XKB_LOCALE_CHARSETS")) != NULL) {
272        start = _XkbAlloc(strlen(tmp) + 1);
273        strcpy(start, tmp);
274        tmp = start;
275    }
276    else {
277        struct stat sbuf;
278        FILE *file;
279#ifndef __UNIXOS2__
280        char *cf = CHARSET_FILE;
281#else
282        char *cf = __XOS2RedirRoot(CHARSET_FILE);
283#endif
284
285#ifndef S_ISREG
286# define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
287#endif
288
289        if ((stat(cf, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
290            (file = fopen(cf, "r"))) {
291            tmp = _XkbAlloc(sbuf.st_size + 1);
292            if (tmp != NULL) {
293                sbuf.st_size = (long) fread(tmp, 1, sbuf.st_size, file);
294                tmp[sbuf.st_size] = '\0';
295            }
296            fclose(file);
297        }
298    }
299
300    if (tmp == NULL) {
301        tmp = _XkbAlloc(strlen(_XkbKnownLanguages) + 1);
302        if (!tmp)
303            return NULL;
304        strcpy(tmp, _XkbKnownLanguages);
305    }
306    start = tmp;
307    do {
308        if ((set = strchr(tmp, '=')) == NULL)
309            break;
310        *set++ = '\0';
311        if ((next = strchr(set, ':')) != NULL)
312            *next++ = '\0';
313        while (tmp && *tmp) {
314            if ((end = strchr(tmp, ',')) != NULL)
315                *end++ = '\0';
316            if (Strcmp(tmp, lang) == 0) {
317                strncpy(buf, set, 100);
318                buf[99] = '\0';
319                Xfree(start);
320                return buf;
321            }
322            tmp = end;
323        }
324        tmp = next;
325    } while (tmp && *tmp);
326    Xfree(start);
327    return NULL;
328}
329#else
330char *
331_XkbGetCharset(void)
332{
333    char *tmp;
334    XLCd lcd;
335
336    tmp = getenv("_XKB_CHARSET");
337    if (tmp)
338        return tmp;
339
340    lcd = _XlcCurrentLC();
341    if (lcd)
342        return XLC_PUBLIC(lcd, encoding_name);
343
344    return NULL;
345}
346#endif
347