11ab64890Smrg/*
21ab64890Smrg
31ab64890SmrgCopyright 1988, 1989, 1998  The Open Group
41ab64890Smrg
51ab64890SmrgPermission to use, copy, modify, distribute, and sell this software and its
61ab64890Smrgdocumentation for any purpose is hereby granted without fee, provided that
71ab64890Smrgthe above copyright notice appear in all copies and that both that
81ab64890Smrgcopyright notice and this permission notice appear in supporting
91ab64890Smrgdocumentation.
101ab64890Smrg
111ab64890SmrgThe above copyright notice and this permission notice shall be included
121ab64890Smrgin all copies or substantial portions of the Software.
131ab64890Smrg
141ab64890SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151ab64890SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161ab64890SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
171ab64890SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
181ab64890SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
191ab64890SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
201ab64890SmrgOTHER DEALINGS IN THE SOFTWARE.
211ab64890Smrg
221ab64890SmrgExcept as contained in this notice, the name of The Open Group shall
231ab64890Smrgnot be used in advertising or otherwise to promote the sale, use or
241ab64890Smrgother dealings in this Software without prior written authorization
251ab64890Smrgfrom The Open Group.
261ab64890Smrg
271ab64890Smrg*/
281ab64890Smrg
291ab64890Smrg#ifdef HAVE_CONFIG_H
301ab64890Smrg#include <config.h>
311ab64890Smrg#endif
321ab64890Smrg#include <stdio.h>
331ab64890Smrg#include <sys/types.h>
341ab64890Smrg#include <sys/stat.h>
351ab64890Smrg
361ab64890Smrg#include <X11/X.h>
371ab64890Smrg#include <X11/Xlib.h>
381ab64890Smrg#include "Xlibint.h"
391ab64890Smrg#include "Xlcint.h"
401ab64890Smrg#include "XlcPubI.h"
411ab64890Smrg#include "Ximint.h"
421ab64890Smrg#include <X11/Xutil.h>
431ab64890Smrg#include <X11/Xmd.h>
441ab64890Smrg#define XK_LATIN1
451ab64890Smrg#define XK_PUBLISHING
461ab64890Smrg#include <X11/keysym.h>
471ab64890Smrg#include <X11/extensions/XKBproto.h>
481ab64890Smrg#include "XKBlibint.h"
491ab64890Smrg#include <X11/Xlocale.h>
501ab64890Smrg#include <ctype.h>
511ab64890Smrg#include <X11/Xos.h>
521ab64890Smrg
5361b2299dSmrgstatic int
541ab64890Smrg_XkbHandleSpecialSym(KeySym keysym, char *buffer, int nbytes, int *extra_rtrn)
551ab64890Smrg{
561ab64890Smrg    /* try to convert to Latin-1, handling ctrl */
571ab64890Smrg    if (!(((keysym >= XK_BackSpace) && (keysym <= XK_Clear)) ||
58818534a1Smrg          (keysym == XK_Return) || (keysym == XK_Escape) ||
59818534a1Smrg          (keysym == XK_KP_Space) || (keysym == XK_KP_Tab) ||
60818534a1Smrg          (keysym == XK_KP_Enter) ||
61818534a1Smrg          ((keysym >= XK_KP_Multiply) && (keysym <= XK_KP_9)) ||
62818534a1Smrg          (keysym == XK_KP_Equal) || (keysym == XK_Delete)))
63818534a1Smrg        return 0;
64818534a1Smrg
65818534a1Smrg    if (nbytes < 1) {
66818534a1Smrg        if (extra_rtrn)
67818534a1Smrg            *extra_rtrn = 1;
68818534a1Smrg        return 0;
691ab64890Smrg    }
701ab64890Smrg    /* if X keysym, convert to ascii by grabbing low 7 bits */
711ab64890Smrg    if (keysym == XK_KP_Space)
72818534a1Smrg        buffer[0] = XK_space & 0x7F;            /* patch encoding botch */
73818534a1Smrg    else
74818534a1Smrg        buffer[0] = (char) (keysym & 0x7F);
751ab64890Smrg    return 1;
761ab64890Smrg}
771ab64890Smrg
781ab64890Smrg/*ARGSUSED*/
7961b2299dSmrgstatic int
80818534a1Smrg_XkbKSToKnownSet(XPointer priv,
81818534a1Smrg                 KeySym keysym,
82818534a1Smrg                 char *buffer,
83818534a1Smrg                 int nbytes,
84818534a1Smrg                 int *extra_rtrn)
851ab64890Smrg{
86818534a1Smrg    char tbuf[8], *buf;
871ab64890Smrg
881ab64890Smrg    if (extra_rtrn)
89818534a1Smrg        *extra_rtrn = 0;
901ab64890Smrg
911ab64890Smrg    /* convert "dead" diacriticals for dumb applications */
92818534a1Smrg    if ((keysym & 0xffffff00) == 0xfe00) {
93818534a1Smrg        switch (keysym) {
94818534a1Smrg        case XK_dead_grave:            keysym = XK_grave; break;
95818534a1Smrg        case XK_dead_acute:            keysym = XK_acute; break;
96818534a1Smrg        case XK_dead_circumflex:       keysym = XK_asciicircum; break;
97818534a1Smrg        case XK_dead_tilde:            keysym = XK_asciitilde; break;
98818534a1Smrg        case XK_dead_macron:           keysym = XK_macron; break;
99818534a1Smrg        case XK_dead_breve:            keysym = XK_breve; break;
100818534a1Smrg        case XK_dead_abovedot:         keysym = XK_abovedot; break;
101818534a1Smrg        case XK_dead_diaeresis:        keysym = XK_diaeresis; break;
102818534a1Smrg        case XK_dead_abovering:        keysym = XK_degree; break;
103818534a1Smrg        case XK_dead_doubleacute:      keysym = XK_doubleacute; break;
104818534a1Smrg        case XK_dead_caron:            keysym = XK_caron; break;
105818534a1Smrg        case XK_dead_cedilla:          keysym = XK_cedilla; break;
106818534a1Smrg        case XK_dead_ogonek:           keysym = XK_ogonek; break;
107818534a1Smrg        case XK_dead_iota:             keysym = XK_Greek_iota; break;
1081ab64890Smrg#ifdef XK_KATAKANA
109818534a1Smrg        case XK_dead_voiced_sound:     keysym = XK_voicedsound; break;
110818534a1Smrg        case XK_dead_semivoiced_sound: keysym = XK_semivoicedsound; break;
1111ab64890Smrg#endif
112818534a1Smrg        }
1131ab64890Smrg    }
1141ab64890Smrg
115818534a1Smrg    if (nbytes < 1)
116818534a1Smrg        buf = tbuf;
117818534a1Smrg    else
118818534a1Smrg        buf = buffer;
1191ab64890Smrg
120818534a1Smrg    if ((keysym & 0xffffff00) == 0xff00) {
121818534a1Smrg        return _XkbHandleSpecialSym(keysym, buf, nbytes, extra_rtrn);
1221ab64890Smrg    }
123818534a1Smrg    return _XimGetCharCode(priv, keysym, (unsigned char *) buf, nbytes);
1241ab64890Smrg}
1251ab64890Smrg
1261ab64890Smrgtypedef struct _XkbToKS {
127818534a1Smrg    unsigned prefix;
128818534a1Smrg    char *map;
1291ab64890Smrg} XkbToKS;
1301ab64890Smrg
1311ab64890Smrg/*ARGSUSED*/
1321ab64890Smrgstatic KeySym
133818534a1Smrg_XkbKnownSetToKS(XPointer priv, char *buffer, int nbytes, Status *status)
1341ab64890Smrg{
135818534a1Smrg    if (nbytes != 1)
136818534a1Smrg        return NoSymbol;
137818534a1Smrg    if (((buffer[0] & 0x80) == 0) && (buffer[0] >= 32))
138818534a1Smrg        return buffer[0];
139818534a1Smrg    else if ((buffer[0] & 0x7f) >= 32) {
140818534a1Smrg        XkbToKS *map = (XkbToKS *) priv;
141818534a1Smrg
142818534a1Smrg        if (map) {
143818534a1Smrg            if (map->map)
144818534a1Smrg                return map->prefix | map->map[buffer[0] & 0x7f];
145818534a1Smrg            else
146818534a1Smrg                return map->prefix | buffer[0];
147818534a1Smrg        }
148818534a1Smrg        return buffer[0];
1491ab64890Smrg    }
1501ab64890Smrg    return NoSymbol;
1511ab64890Smrg}
1521ab64890Smrg
1531ab64890Smrgstatic KeySym
1541ab64890Smrg__XkbDefaultToUpper(KeySym sym)
1551ab64890Smrg{
156818534a1Smrg    KeySym lower, upper;
1571ab64890Smrg
1581ab64890Smrg    XConvertCase(sym, &lower, &upper);
1591ab64890Smrg    return upper;
1601ab64890Smrg}
1611ab64890Smrg
1621ab64890Smrg#ifdef XKB_EXTEND_LOOKUP_STRING
1631ab64890Smrgstatic int
1641ab64890SmrgStrcmp(char *str1, char *str2)
1651ab64890Smrg{
1661ab64890Smrg    char str[256];
1671ab64890Smrg    char c, *s;
1681ab64890Smrg
1691ab64890Smrg    /*
1701ab64890Smrg     * unchecked strings from the environment can end up here, so check
1711ab64890Smrg     * the length before copying.
1721ab64890Smrg     */
173818534a1Smrg    if (strlen(str1) >= sizeof(str))    /* almost certain it's a mismatch */
174818534a1Smrg        return 1;
1751ab64890Smrg
176818534a1Smrg    for (s = str; (c = *str1++);) {
177818534a1Smrg        if (isupper(c))
178818534a1Smrg            c = tolower(c);
179818534a1Smrg        *s++ = c;
1801ab64890Smrg    }
1811ab64890Smrg    *s = '\0';
1821ab64890Smrg    return (strcmp(str, str2));
1831ab64890Smrg}
1841ab64890Smrg#endif
1851ab64890Smrg
18661b2299dSmrgint
187818534a1Smrg_XkbGetConverters(const char *encoding_name, XkbConverters * cvt_rtrn)
1881ab64890Smrg{
189818534a1Smrg    if (!cvt_rtrn)
190818534a1Smrg        return 0;
1911ab64890Smrg
1921ab64890Smrg    cvt_rtrn->KSToMB = _XkbKSToKnownSet;
1931ab64890Smrg    cvt_rtrn->KSToMBPriv = _XimGetLocaleCode(encoding_name);
1941ab64890Smrg    cvt_rtrn->MBToKS = _XkbKnownSetToKS;
1951ab64890Smrg    cvt_rtrn->MBToKSPriv = NULL;
1961ab64890Smrg    cvt_rtrn->KSToUpper = __XkbDefaultToUpper;
1971ab64890Smrg    return 1;
1981ab64890Smrg}
1991ab64890Smrg
2001ab64890Smrg/***====================================================================***/
2011ab64890Smrg
20261b2299dSmrg/*
2031ab64890Smrg * The function _XkbGetCharset seems to be missnamed as what it seems to
2041ab64890Smrg * be used for is to determine the encoding-name for the locale. ???
2051ab64890Smrg */
2061ab64890Smrg
2071ab64890Smrg#ifdef XKB_EXTEND_LOOKUP_STRING
2081ab64890Smrg
20961b2299dSmrg/*
2101ab64890Smrg * XKB_EXTEND_LOOKUP_STRING is not used by the SI. It is used by various
2111ab64890Smrg * X Consortium/X Project Team members, so we leave it in the source as
2121ab64890Smrg * an simplify integration by these companies.
2131ab64890Smrg */
2141ab64890Smrg
2151ab64890Smrg#define	CHARSET_FILE	"/usr/lib/X11/input/charsets"
216818534a1Smrgstatic char *_XkbKnownLanguages =
217818534a1Smrg    "c=ascii:da,de,en,es,fr,is,it,nl,no,pt,sv=iso8859-1:hu,pl,cs=iso8859-2:"
218818534a1Smrg    "eo=iso8859-3:sp=iso8859-5:ar,ara=iso8859-6:el=iso8859-7:he=iso8859-8:"
219818534a1Smrg    "tr=iso8859-9:lt,lv=iso8859-13:et,fi=iso8859-15:ru=koi8-r:uk=koi8-u:"
220818534a1Smrg    "th,th_TH,th_TH.iso8859-11=iso8859-11:th_TH.TIS620=tis620:hy=armscii-8:"
221818534a1Smrg    "vi=tcvn-5712:ka=georgian-academy:be,bg=microsoft-cp1251";
222818534a1Smrg
223818534a1Smrgchar *
2241ab64890Smrg_XkbGetCharset(void)
2251ab64890Smrg{
2261ab64890Smrg    /*
2271ab64890Smrg     * PAGE USAGE TUNING: explicitly initialize to move these to data
2281ab64890Smrg     * instead of bss
2291ab64890Smrg     */
2301ab64890Smrg    static char buf[100] = { 0 };
2311ab64890Smrg    char lang[256];
232818534a1Smrg    char *start, *tmp, *end, *next, *set;
233818534a1Smrg    char *country, *charset;
2341ab64890Smrg    char *locale;
2351ab64890Smrg
236818534a1Smrg    tmp = getenv("_XKB_CHARSET");
237818534a1Smrg    if (tmp)
238818534a1Smrg        return tmp;
239818534a1Smrg    locale = setlocale(LC_CTYPE, NULL);
2401ab64890Smrg
241818534a1Smrg    if (locale == NULL)
242818534a1Smrg        return NULL;
2431ab64890Smrg
2441ab64890Smrg    if (strlen(locale) >= sizeof(lang))
245818534a1Smrg        return NULL;
2461ab64890Smrg
2471ab64890Smrg    for (tmp = lang; *tmp = *locale++; tmp++) {
248818534a1Smrg        if (isupper(*tmp))
249818534a1Smrg            *tmp = tolower(*tmp);
2501ab64890Smrg    }
251818534a1Smrg    country = strchr(lang, '_');
252818534a1Smrg    if (country) {
253818534a1Smrg        *country++ = '\0';
254818534a1Smrg        charset = strchr(country, '.');
255818534a1Smrg        if (charset)
256818534a1Smrg            *charset++ = '\0';
257818534a1Smrg        if (charset) {
258818534a1Smrg            strncpy(buf, charset, 99);
259818534a1Smrg            buf[99] = '\0';
260818534a1Smrg            return buf;
261818534a1Smrg        }
2621ab64890Smrg    }
26361b2299dSmrg    else {
264818534a1Smrg        charset = NULL;
2651ab64890Smrg    }
2661ab64890Smrg
267818534a1Smrg    if ((tmp = getenv("_XKB_LOCALE_CHARSETS")) != NULL) {
268818534a1Smrg        start = _XkbAlloc(strlen(tmp) + 1);
269818534a1Smrg        strcpy(start, tmp);
270818534a1Smrg        tmp = start;
271818534a1Smrg    }
272818534a1Smrg    else {
273818534a1Smrg        struct stat sbuf;
274818534a1Smrg        FILE *file;
275818534a1Smrg        char *cf = CHARSET_FILE;
2761ab64890Smrg
2771ab64890Smrg#ifndef S_ISREG
2781ab64890Smrg# define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
2791ab64890Smrg#endif
28061b2299dSmrg
281818534a1Smrg        if ((stat(cf, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
282818534a1Smrg            (file = fopen(cf, "r"))) {
283818534a1Smrg            tmp = _XkbAlloc(sbuf.st_size + 1);
284818534a1Smrg            if (tmp != NULL) {
285818534a1Smrg                sbuf.st_size = (long) fread(tmp, 1, sbuf.st_size, file);
286818534a1Smrg                tmp[sbuf.st_size] = '\0';
287818534a1Smrg            }
288818534a1Smrg            fclose(file);
289818534a1Smrg        }
2901ab64890Smrg    }
2911ab64890Smrg
292818534a1Smrg    if (tmp == NULL) {
293818534a1Smrg        tmp = _XkbAlloc(strlen(_XkbKnownLanguages) + 1);
294818534a1Smrg        if (!tmp)
295818534a1Smrg            return NULL;
296818534a1Smrg        strcpy(tmp, _XkbKnownLanguages);
2971ab64890Smrg    }
2981ab64890Smrg    start = tmp;
2991ab64890Smrg    do {
300818534a1Smrg        if ((set = strchr(tmp, '=')) == NULL)
301818534a1Smrg            break;
302818534a1Smrg        *set++ = '\0';
303818534a1Smrg        if ((next = strchr(set, ':')) != NULL)
304818534a1Smrg            *next++ = '\0';
305818534a1Smrg        while (tmp && *tmp) {
306818534a1Smrg            if ((end = strchr(tmp, ',')) != NULL)
307818534a1Smrg                *end++ = '\0';
308818534a1Smrg            if (Strcmp(tmp, lang) == 0) {
309818534a1Smrg                strncpy(buf, set, 100);
310818534a1Smrg                buf[99] = '\0';
311818534a1Smrg                Xfree(start);
312818534a1Smrg                return buf;
313818534a1Smrg            }
314818534a1Smrg            tmp = end;
315818534a1Smrg        }
316818534a1Smrg        tmp = next;
317818534a1Smrg    } while (tmp && *tmp);
3181ab64890Smrg    Xfree(start);
3191ab64890Smrg    return NULL;
3201ab64890Smrg}
3211ab64890Smrg#else
322818534a1Smrgchar *
3231ab64890Smrg_XkbGetCharset(void)
3241ab64890Smrg{
3251ab64890Smrg    char *tmp;
3261ab64890Smrg    XLCd lcd;
3271ab64890Smrg
328818534a1Smrg    tmp = getenv("_XKB_CHARSET");
329818534a1Smrg    if (tmp)
330818534a1Smrg        return tmp;
3311ab64890Smrg
3321ab64890Smrg    lcd = _XlcCurrentLC();
333818534a1Smrg    if (lcd)
334818534a1Smrg        return XLC_PUBLIC(lcd, encoding_name);
3351ab64890Smrg
3361ab64890Smrg    return NULL;
3371ab64890Smrg}
3381ab64890Smrg#endif
339