1 /*
2 
3 Copyright 1988, 1989, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from 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 
57 static int
_XkbHandleSpecialSym(KeySym keysym,char * buffer,int nbytes,int * extra_rtrn)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*/
86 static int
_XkbKSToKnownSet(XPointer priv,KeySym keysym,char * buffer,int nbytes,int * extra_rtrn)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 
133 typedef struct _XkbToKS {
134     unsigned prefix;
135     char *map;
136 } XkbToKS;
137 
138 /*ARGSUSED*/
139 static KeySym
_XkbKnownSetToKS(XPointer priv,char * buffer,int nbytes,Status * status)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 
160 static KeySym
__XkbDefaultToUpper(KeySym sym)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
170 static int
Strcmp(char * str1,char * str2)171 Strcmp(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 
193 int
_XkbGetConverters(const char * encoding_name,XkbConverters * cvt_rtrn)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"
223 static 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 
230 char *
_XkbGetCharset(void)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
333 char *
_XkbGetCharset(void)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