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