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