XKBCvt.c revision 818534a1
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) || (keysym == XK_Delete)))
68        return 0;
69
70    if (nbytes < 1) {
71        if (extra_rtrn)
72            *extra_rtrn = 1;
73        return 0;
74    }
75    /* if X keysym, convert to ascii by grabbing low 7 bits */
76    if (keysym == XK_KP_Space)
77        buffer[0] = XK_space & 0x7F;            /* patch encoding botch */
78    else if (keysym == XK_hyphen)
79        buffer[0] = (char) (XK_minus & 0xFF);   /* map to equiv character */
80    else
81        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)
123        buf = tbuf;
124    else
125        buf = buffer;
126
127    if ((keysym & 0xffffff00) == 0xff00) {
128        return _XkbHandleSpecialSym(keysym, buf, nbytes, extra_rtrn);
129    }
130    return _XimGetCharCode(priv, keysym, (unsigned char *) buf, nbytes);
131}
132
133typedef struct _XkbToKS {
134    unsigned prefix;
135    char *map;
136} XkbToKS;
137
138/*ARGSUSED*/
139static KeySym
140_XkbKnownSetToKS(XPointer priv, char *buffer, int nbytes, Status *status)
141{
142    if (nbytes != 1)
143        return NoSymbol;
144    if (((buffer[0] & 0x80) == 0) && (buffer[0] >= 32))
145        return buffer[0];
146    else if ((buffer[0] & 0x7f) >= 32) {
147        XkbToKS *map = (XkbToKS *) priv;
148
149        if (map) {
150            if (map->map)
151                return map->prefix | map->map[buffer[0] & 0x7f];
152            else
153                return map->prefix | buffer[0];
154        }
155        return buffer[0];
156    }
157    return NoSymbol;
158}
159
160static KeySym
161__XkbDefaultToUpper(KeySym sym)
162{
163    KeySym lower, upper;
164
165    XConvertCase(sym, &lower, &upper);
166    return upper;
167}
168
169#ifdef XKB_EXTEND_LOOKUP_STRING
170static int
171Strcmp(char *str1, char *str2)
172{
173    char str[256];
174    char c, *s;
175
176    /*
177     * unchecked strings from the environment can end up here, so check
178     * the length before copying.
179     */
180    if (strlen(str1) >= sizeof(str))    /* almost certain it's a mismatch */
181        return 1;
182
183    for (s = str; (c = *str1++);) {
184        if (isupper(c))
185            c = tolower(c);
186        *s++ = c;
187    }
188    *s = '\0';
189    return (strcmp(str, str2));
190}
191#endif
192
193int
194_XkbGetConverters(const char *encoding_name, XkbConverters * cvt_rtrn)
195{
196    if (!cvt_rtrn)
197        return 0;
198
199    cvt_rtrn->KSToMB = _XkbKSToKnownSet;
200    cvt_rtrn->KSToMBPriv = _XimGetLocaleCode(encoding_name);
201    cvt_rtrn->MBToKS = _XkbKnownSetToKS;
202    cvt_rtrn->MBToKSPriv = NULL;
203    cvt_rtrn->KSToUpper = __XkbDefaultToUpper;
204    return 1;
205}
206
207/***====================================================================***/
208
209/*
210 * The function _XkbGetCharset seems to be missnamed as what it seems to
211 * be used for is to determine the encoding-name for the locale. ???
212 */
213
214#ifdef XKB_EXTEND_LOOKUP_STRING
215
216/*
217 * XKB_EXTEND_LOOKUP_STRING is not used by the SI. It is used by various
218 * X Consortium/X Project Team members, so we leave it in the source as
219 * an simplify integration by these companies.
220 */
221
222#define	CHARSET_FILE	"/usr/lib/X11/input/charsets"
223static char *_XkbKnownLanguages =
224    "c=ascii:da,de,en,es,fr,is,it,nl,no,pt,sv=iso8859-1:hu,pl,cs=iso8859-2:"
225    "eo=iso8859-3:sp=iso8859-5:ar,ara=iso8859-6:el=iso8859-7:he=iso8859-8:"
226    "tr=iso8859-9:lt,lv=iso8859-13:et,fi=iso8859-15:ru=koi8-r:uk=koi8-u:"
227    "th,th_TH,th_TH.iso8859-11=iso8859-11:th_TH.TIS620=tis620:hy=armscii-8:"
228    "vi=tcvn-5712:ka=georgian-academy:be,bg=microsoft-cp1251";
229
230char *
231_XkbGetCharset(void)
232{
233    /*
234     * PAGE USAGE TUNING: explicitly initialize to move these to data
235     * instead of bss
236     */
237    static char buf[100] = { 0 };
238    char lang[256];
239    char *start, *tmp, *end, *next, *set;
240    char *country, *charset;
241    char *locale;
242
243    tmp = getenv("_XKB_CHARSET");
244    if (tmp)
245        return tmp;
246    locale = setlocale(LC_CTYPE, NULL);
247
248    if (locale == NULL)
249        return NULL;
250
251    if (strlen(locale) >= sizeof(lang))
252        return NULL;
253
254    for (tmp = lang; *tmp = *locale++; tmp++) {
255        if (isupper(*tmp))
256            *tmp = tolower(*tmp);
257    }
258    country = strchr(lang, '_');
259    if (country) {
260        *country++ = '\0';
261        charset = strchr(country, '.');
262        if (charset)
263            *charset++ = '\0';
264        if (charset) {
265            strncpy(buf, charset, 99);
266            buf[99] = '\0';
267            return buf;
268        }
269    }
270    else {
271        charset = NULL;
272    }
273
274    if ((tmp = getenv("_XKB_LOCALE_CHARSETS")) != NULL) {
275        start = _XkbAlloc(strlen(tmp) + 1);
276        strcpy(start, tmp);
277        tmp = start;
278    }
279    else {
280        struct stat sbuf;
281        FILE *file;
282#ifndef __UNIXOS2__
283        char *cf = CHARSET_FILE;
284#else
285        char *cf = __XOS2RedirRoot(CHARSET_FILE);
286#endif
287
288#ifndef S_ISREG
289# define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
290#endif
291
292        if ((stat(cf, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
293            (file = fopen(cf, "r"))) {
294            tmp = _XkbAlloc(sbuf.st_size + 1);
295            if (tmp != NULL) {
296                sbuf.st_size = (long) fread(tmp, 1, sbuf.st_size, file);
297                tmp[sbuf.st_size] = '\0';
298            }
299            fclose(file);
300        }
301    }
302
303    if (tmp == NULL) {
304        tmp = _XkbAlloc(strlen(_XkbKnownLanguages) + 1);
305        if (!tmp)
306            return NULL;
307        strcpy(tmp, _XkbKnownLanguages);
308    }
309    start = tmp;
310    do {
311        if ((set = strchr(tmp, '=')) == NULL)
312            break;
313        *set++ = '\0';
314        if ((next = strchr(set, ':')) != NULL)
315            *next++ = '\0';
316        while (tmp && *tmp) {
317            if ((end = strchr(tmp, ',')) != NULL)
318                *end++ = '\0';
319            if (Strcmp(tmp, lang) == 0) {
320                strncpy(buf, set, 100);
321                buf[99] = '\0';
322                Xfree(start);
323                return buf;
324            }
325            tmp = end;
326        }
327        tmp = next;
328    } while (tmp && *tmp);
329    Xfree(start);
330    return NULL;
331}
332#else
333char *
334_XkbGetCharset(void)
335{
336    char *tmp;
337    XLCd lcd;
338
339    tmp = getenv("_XKB_CHARSET");
340    if (tmp)
341        return tmp;
342
343    lcd = _XlcCurrentLC();
344    if (lcd)
345        return XLC_PUBLIC(lcd, encoding_name);
346
347    return NULL;
348}
349#endif
350