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