imLcPrs.c revision 1ab64890
1/* $Xorg: imLcPrs.c,v 1.3 2000/08/17 19:45:14 cpqbld Exp $ */ 2/****************************************************************** 3 4 Copyright 1992 by Oki Technosystems Laboratory, Inc. 5 Copyright 1992 by Fuji Xerox Co., Ltd. 6 7Permission to use, copy, modify, distribute, and sell this software 8and its documentation for any purpose is hereby granted without fee, 9provided that the above copyright notice appear in all copies and 10that both that copyright notice and this permission notice appear 11in supporting documentation, and that the name of Oki Technosystems 12Laboratory and Fuji Xerox not be used in advertising or publicity 13pertaining to distribution of the software without specific, written 14prior permission. 15Oki Technosystems Laboratory and Fuji Xerox make no representations 16about the suitability of this software for any purpose. It is provided 17"as is" without express or implied warranty. 18 19OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES 20WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF 21MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS 22LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR 23CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 24OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 25OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 26OR PERFORMANCE OF THIS SOFTWARE. 27 28 Author: Yasuhiro Kawai Oki Technosystems Laboratory 29 Author: Kazunori Nishihara Fuji Xerox 30 31******************************************************************/ 32 33/* $XFree86: xc/lib/X11/imLcPrs.c,v 1.10 2003/09/06 14:06:32 pascal Exp $ */ 34 35#ifdef HAVE_CONFIG_H 36#include <config.h> 37#endif 38#include <X11/Xlib.h> 39#include <X11/Xmd.h> 40#include <X11/Xos.h> 41#include "Xlibint.h" 42#include "Xlcint.h" 43#include "Ximint.h" 44#include <sys/stat.h> 45#include <stdio.h> 46 47extern int _Xmbstowcs( 48 wchar_t *wstr, 49 char *str, 50 int len 51); 52 53extern int _Xmbstoutf8( 54 char *ustr, 55 const char *str, 56 int len 57); 58 59/* 60 * Parsing File Format: 61 * 62 * FILE ::= { [PRODUCTION] [COMMENT] "\n"} 63 * PRODUCTION ::= LHS ":" RHS [ COMMENT ] 64 * COMMENT ::= "#" {<any character except null or newline>} 65 * LHS ::= EVENT { EVENT } 66 * EVENT ::= [MODIFIER_LIST] "<" keysym ">" 67 * MODIFIER_LIST ::= ("!" {MODIFIER} ) | "None" 68 * MODIFIER ::= ["~"] modifier_name 69 * RHS ::= ( STRING | keysym | STRING keysym ) 70 * STRING ::= '"' { CHAR } '"' 71 * CHAR ::= GRAPHIC_CHAR | ESCAPED_CHAR 72 * GRAPHIC_CHAR ::= locale (codeset) dependent code 73 * ESCAPED_CHAR ::= ('\\' | '\"' | OCTAL | HEX ) 74 * OCTAL ::= '\' OCTAL_CHAR [OCTAL_CHAR [OCTAL_CHAR]] 75 * OCTAL_CHAR ::= (0|1|2|3|4|5|6|7) 76 * HEX ::= '\' (x|X) HEX_CHAR [HEX_CHAR]] 77 * HEX_CHAR ::= (0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|a|b|c|d|e|f) 78 * 79 */ 80 81static int 82nextch( 83 FILE *fp, 84 int *lastch) 85{ 86 int c; 87 88 if (*lastch != 0) { 89 c = *lastch; 90 *lastch = 0; 91 } else { 92 c = getc(fp); 93 if (c == '\\') { 94 c = getc(fp); 95 if (c == '\n') { 96 c = getc(fp); 97 } else { 98 ungetc(c, fp); 99 c = '\\'; 100 } 101 } 102 } 103 return(c); 104} 105 106static void 107putbackch( 108 int c, 109 int *lastch) 110{ 111 *lastch = c; 112} 113 114#define ENDOFFILE 0 115#define ENDOFLINE 1 116#define COLON 2 117#define LESS 3 118#define GREATER 4 119#define EXCLAM 5 120#define TILDE 6 121#define STRING 7 122#define KEY 8 123#define ERROR 9 124 125#ifndef isalnum 126#define isalnum(c) \ 127 (('0' <= (c) && (c) <= '9') || \ 128 ('A' <= (c) && (c) <= 'Z') || \ 129 ('a' <= (c) && (c) <= 'z')) 130#endif 131 132static int 133nexttoken( 134 FILE *fp, 135 char *tokenbuf, 136 int *lastch) 137{ 138 int c; 139 int token; 140 char *p; 141 int i, j; 142 143 while ((c = nextch(fp, lastch)) == ' ' || c == '\t') { 144 } 145 switch (c) { 146 case EOF: 147 token = ENDOFFILE; 148 break; 149 case '\n': 150 token = ENDOFLINE; 151 break; 152 case '<': 153 token = LESS; 154 break; 155 case '>': 156 token = GREATER; 157 break; 158 case ':': 159 token = COLON; 160 break; 161 case '!': 162 token = EXCLAM; 163 break; 164 case '~': 165 token = TILDE; 166 break; 167 case '"': 168 p = tokenbuf; 169 while ((c = nextch(fp, lastch)) != '"') { 170 if (c == '\n' || c == EOF) { 171 putbackch(c, lastch); 172 token = ERROR; 173 goto string_error; 174 } else if (c == '\\') { 175 c = nextch(fp, lastch); 176 switch (c) { 177 case '\\': 178 case '"': 179 *p++ = c; 180 break; 181 case 'n': 182 *p++ = '\n'; 183 break; 184 case 'r': 185 *p++ = '\r'; 186 break; 187 case 't': 188 *p++ = '\t'; 189 break; 190 case '0': 191 case '1': 192 case '2': 193 case '3': 194 case '4': 195 case '5': 196 case '6': 197 case '7': 198 i = c - '0'; 199 c = nextch(fp, lastch); 200 for (j = 0; j < 2 && c >= '0' && c <= '7'; j++) { 201 i <<= 3; 202 i += c - '0'; 203 c = nextch(fp, lastch); 204 } 205 putbackch(c, lastch); 206 *p++ = (char)i; 207 break; 208 case 'X': 209 case 'x': 210 i = 0; 211 for (j = 0; j < 2; j++) { 212 c = nextch(fp, lastch); 213 i <<= 4; 214 if (c >= '0' && c <= '9') { 215 i += c - '0'; 216 } else if (c >= 'A' && c <= 'F') { 217 i += c - 'A' + 10; 218 } else if (c >= 'a' && c <= 'f') { 219 i += c - 'a' + 10; 220 } else { 221 putbackch(c, lastch); 222 i >>= 4; 223 break; 224 } 225 } 226 if (j == 0) { 227 token = ERROR; 228 goto string_error; 229 } 230 *p++ = (char)i; 231 break; 232 case EOF: 233 putbackch(c, lastch); 234 token = ERROR; 235 goto string_error; 236 default: 237 *p++ = c; 238 break; 239 } 240 } else { 241 *p++ = c; 242 } 243 } 244 *p = '\0'; 245 token = STRING; 246 break; 247 case '#': 248 while ((c = nextch(fp, lastch)) != '\n' && c != EOF) { 249 } 250 if (c == '\n') { 251 token = ENDOFLINE; 252 } else { 253 token = ENDOFFILE; 254 } 255 break; 256 default: 257 if (isalnum(c) || c == '_' || c == '-') { 258 p = tokenbuf; 259 *p++ = c; 260 c = nextch(fp, lastch); 261 while (isalnum(c) || c == '_' || c == '-') { 262 *p++ = c; 263 c = nextch(fp, lastch); 264 } 265 *p = '\0'; 266 putbackch(c, lastch); 267 token = KEY; 268 } else { 269 token = ERROR; 270 } 271 break; 272 } 273string_error: 274 return(token); 275} 276 277static long 278modmask( 279 char *name) 280{ 281 struct _modtbl { 282 const char name[6]; 283 long mask; 284 }; 285 286 static const struct _modtbl tbl[] = { 287 { "Ctrl", ControlMask }, 288 { "Lock", LockMask }, 289 { "Caps", LockMask }, 290 { "Shift", ShiftMask }, 291 { "Alt", Mod1Mask }, 292 { "Meta", Mod1Mask }}; 293 294 int i, num_entries = sizeof (tbl) / sizeof (tbl[0]); 295 296 for (i = 0; i < num_entries; i++) 297 if (!strcmp (name, tbl[i].name)) 298 return tbl[i].mask; 299 300 return 0; 301} 302 303static char* 304TransFileName(Xim im, char *name) 305{ 306 char *home = NULL, *lcCompose = NULL; 307 char *i = name, *ret, *j; 308 int l = 0; 309 310 while (*i) { 311 if (*i == '%') { 312 i++; 313 switch (*i) { 314 case '%': 315 l++; 316 break; 317 case 'H': 318 home = getenv("HOME"); 319 if (home) 320 l += strlen(home); 321 break; 322 case 'L': 323 lcCompose = _XlcFileName(im->core.lcd, COMPOSE_FILE); 324 if (lcCompose) 325 l += strlen(lcCompose); 326 break; 327 } 328 } else { 329 l++; 330 } 331 i++; 332 } 333 334 j = ret = Xmalloc(l+1); 335 if (ret == NULL) 336 return ret; 337 i = name; 338 while (*i) { 339 if (*i == '%') { 340 i++; 341 switch (*i) { 342 case '%': 343 *j++ = '%'; 344 break; 345 case 'H': 346 if (home) { 347 strcpy(j, home); 348 j += strlen(home); 349 } 350 break; 351 case 'L': 352 if (lcCompose) { 353 strcpy(j, lcCompose); 354 j += strlen(lcCompose); 355 Xfree(lcCompose); 356 } 357 break; 358 } 359 i++; 360 } else { 361 *j++ = *i++; 362 } 363 } 364 *j = '\0'; 365 return ret; 366} 367 368#ifndef MB_LEN_MAX 369#define MB_LEN_MAX 6 370#endif 371 372static int 373get_mb_string (Xim im, char *buf, KeySym ks) 374{ 375 XPointer from, to; 376 int from_len, to_len, len; 377 XPointer args[1]; 378 XlcCharSet charset; 379 char local_buf[MB_LEN_MAX]; 380 unsigned int ucs; 381 ucs = KeySymToUcs4(ks); 382 383 from = (XPointer) &ucs; 384 to = (XPointer) local_buf; 385 from_len = 1; 386 to_len = MB_LEN_MAX; 387 args[0] = (XPointer) &charset; 388 if (_XlcConvert(im->private.local.ucstoc_conv, 389 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 390 return 0; 391 } 392 393 from = (XPointer) local_buf; 394 to = (XPointer) buf; 395 from_len = MB_LEN_MAX - to_len; 396 to_len = MB_LEN_MAX + 1; 397 args[0] = (XPointer) charset; 398 if (_XlcConvert(im->private.local.cstomb_conv, 399 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 400 return 0; 401 } 402 len = MB_LEN_MAX + 1 - to_len; 403 buf[len] = '\0'; 404 return len; 405} 406 407#define AllMask (ShiftMask | LockMask | ControlMask | Mod1Mask) 408#define LOCAL_WC_BUFSIZE 128 409#define LOCAL_UTF8_BUFSIZE 256 410#define SEQUENCE_MAX 10 411 412static int 413parseline( 414 FILE *fp, 415 Xim im, 416 char* tokenbuf) 417{ 418 int token; 419 DTModifier modifier_mask; 420 DTModifier modifier; 421 DTModifier tmp; 422 KeySym keysym = NoSymbol; 423 DTIndex *top = &im->private.local.top; 424 DefTreeBase *b = &im->private.local.base; 425 DTIndex t; 426 DefTree *p = NULL; 427 Bool exclam, tilde; 428 KeySym rhs_keysym = 0; 429 char *rhs_string_mb; 430 int l; 431 int lastch = 0; 432 char local_mb_buf[MB_LEN_MAX+1]; 433 wchar_t local_wc_buf[LOCAL_WC_BUFSIZE], *rhs_string_wc; 434 char local_utf8_buf[LOCAL_UTF8_BUFSIZE], *rhs_string_utf8; 435 436 struct DefBuffer { 437 DTModifier modifier_mask; 438 DTModifier modifier; 439 KeySym keysym; 440 }; 441 442 struct DefBuffer buf[SEQUENCE_MAX]; 443 int i, n; 444 445 do { 446 token = nexttoken(fp, tokenbuf, &lastch); 447 } while (token == ENDOFLINE); 448 449 if (token == ENDOFFILE) { 450 return(-1); 451 } 452 453 n = 0; 454 do { 455 if ((token == KEY) && (strcmp("include", tokenbuf) == 0)) { 456 char *filename; 457 FILE *infp; 458 token = nexttoken(fp, tokenbuf, &lastch); 459 if (token != KEY && token != STRING) 460 goto error; 461 if ((filename = TransFileName(im, tokenbuf)) == NULL) 462 goto error; 463 infp = _XFopenFile(filename, "r"); 464 Xfree(filename); 465 if (infp == NULL) 466 goto error; 467 _XimParseStringFile(infp, im); 468 fclose(infp); 469 return (0); 470 } else if ((token == KEY) && (strcmp("None", tokenbuf) == 0)) { 471 modifier = 0; 472 modifier_mask = AllMask; 473 token = nexttoken(fp, tokenbuf, &lastch); 474 } else { 475 modifier_mask = modifier = 0; 476 exclam = False; 477 if (token == EXCLAM) { 478 exclam = True; 479 token = nexttoken(fp, tokenbuf, &lastch); 480 } 481 while (token == TILDE || token == KEY) { 482 tilde = False; 483 if (token == TILDE) { 484 tilde = True; 485 token = nexttoken(fp, tokenbuf, &lastch); 486 if (token != KEY) 487 goto error; 488 } 489 tmp = modmask(tokenbuf); 490 if (!tmp) { 491 goto error; 492 } 493 modifier_mask |= tmp; 494 if (tilde) { 495 modifier &= ~tmp; 496 } else { 497 modifier |= tmp; 498 } 499 token = nexttoken(fp, tokenbuf, &lastch); 500 } 501 if (exclam) { 502 modifier_mask = AllMask; 503 } 504 } 505 506 if (token != LESS) { 507 goto error; 508 } 509 510 token = nexttoken(fp, tokenbuf, &lastch); 511 if (token != KEY) { 512 goto error; 513 } 514 515 token = nexttoken(fp, tokenbuf, &lastch); 516 if (token != GREATER) { 517 goto error; 518 } 519 520 keysym = XStringToKeysym(tokenbuf); 521 if (keysym == NoSymbol) { 522 goto error; 523 } 524 525 buf[n].keysym = keysym; 526 buf[n].modifier = modifier; 527 buf[n].modifier_mask = modifier_mask; 528 n++; 529 if( n >= SEQUENCE_MAX ) 530 goto error; 531 token = nexttoken(fp, tokenbuf, &lastch); 532 } while (token != COLON); 533 534 token = nexttoken(fp, tokenbuf, &lastch); 535 if (token == STRING) { 536 l = strlen(tokenbuf) + 1; 537 while (b->mbused + l > b->mbsize) { 538 b->mbsize = b->mbsize ? b->mbsize * 1.5 : 1024; 539 if (! (b->mb = Xrealloc (b->mb, b->mbsize)) ) 540 goto error; 541 } 542 rhs_string_mb = &b->mb[b->mbused]; 543 b->mbused += l; 544 strcpy(rhs_string_mb, tokenbuf); 545 token = nexttoken(fp, tokenbuf, &lastch); 546 if (token == KEY) { 547 rhs_keysym = XStringToKeysym(tokenbuf); 548 if (rhs_keysym == NoSymbol) { 549 goto error; 550 } 551 token = nexttoken(fp, tokenbuf, &lastch); 552 } 553 if (token != ENDOFLINE && token != ENDOFFILE) { 554 goto error; 555 } 556 } else if (token == KEY) { 557 rhs_keysym = XStringToKeysym(tokenbuf); 558 if (rhs_keysym == NoSymbol) { 559 goto error; 560 } 561 token = nexttoken(fp, tokenbuf, &lastch); 562 if (token != ENDOFLINE && token != ENDOFFILE) { 563 goto error; 564 } 565 566 l = get_mb_string(im, local_mb_buf, rhs_keysym); 567 while (b->mbused + l + 1 > b->mbsize) { 568 b->mbsize = b->mbsize ? b->mbsize * 1.5 : 1024; 569 if (! (b->mb = Xrealloc (b->mb, b->mbsize)) ) 570 goto error; 571 } 572 rhs_string_mb = &b->mb[b->mbused]; 573 b->mbused += l + 1; 574 memcpy(rhs_string_mb, local_mb_buf, l); 575 rhs_string_mb[l] = '\0'; 576 } else { 577 goto error; 578 } 579 580 l = _Xmbstowcs(local_wc_buf, rhs_string_mb, LOCAL_WC_BUFSIZE - 1); 581 if (l == LOCAL_WC_BUFSIZE - 1) { 582 local_wc_buf[l] = (wchar_t)'\0'; 583 } 584 while (b->wcused + l + 1 > b->wcsize) { 585 b->wcsize = b->wcsize ? b->wcsize * 1.5 : 512; 586 if (! (b->wc = Xrealloc (b->wc, sizeof(wchar_t) * b->wcsize)) ) 587 goto error; 588 } 589 rhs_string_wc = &b->wc[b->wcused]; 590 b->wcused += l + 1; 591 memcpy((char *)rhs_string_wc, (char *)local_wc_buf, (l + 1) * sizeof(wchar_t) ); 592 593 l = _Xmbstoutf8(local_utf8_buf, rhs_string_mb, LOCAL_UTF8_BUFSIZE - 1); 594 if (l == LOCAL_UTF8_BUFSIZE - 1) { 595 local_wc_buf[l] = '\0'; 596 } 597 while (b->utf8used + l + 1 > b->utf8size) { 598 b->utf8size = b->utf8size ? b->utf8size * 1.5 : 1024; 599 if (! (b->utf8 = Xrealloc (b->utf8, b->utf8size)) ) 600 goto error; 601 } 602 rhs_string_utf8 = &b->utf8[b->utf8used]; 603 b->utf8used += l + 1; 604 memcpy(rhs_string_utf8, local_utf8_buf, l + 1); 605 606 for (i = 0; i < n; i++) { 607 for (t = *top; t; t = b->tree[t].next) { 608 if (buf[i].keysym == b->tree[t].keysym && 609 buf[i].modifier == b->tree[t].modifier && 610 buf[i].modifier_mask == b->tree[t].modifier_mask) { 611 break; 612 } 613 } 614 if (t) { 615 p = &b->tree[t]; 616 top = &p->succession; 617 } else { 618 while (b->treeused >= b->treesize) { 619 DefTree *old = b->tree; 620 int oldsize = b->treesize; 621 b->treesize = b->treesize ? b->treesize * 1.5 : 256; 622 if (! (b->tree = Xrealloc (b->tree, sizeof(DefTree) * b->treesize)) ) 623 goto error; 624 if (top >= (DTIndex *) old && top < (DTIndex *) &old[oldsize]) 625 top = (DTIndex *) (((char *) top) + (((char *)b->tree)-(char *)old)); 626 } 627 p = &b->tree[b->treeused]; 628 p->keysym = buf[i].keysym; 629 p->modifier = buf[i].modifier; 630 p->modifier_mask = buf[i].modifier_mask; 631 p->succession = 0; 632 p->next = *top; 633 p->mb = 0; 634 p->wc = 0; 635 p->utf8 = 0; 636 p->ks = NoSymbol; 637 *top = b->treeused; 638 top = &p->succession; 639 b->treeused++; 640 } 641 } 642 643 /* old entries no longer freed... */ 644 p->mb = rhs_string_mb - b->mb; 645 p->wc = rhs_string_wc - b->wc; 646 p->utf8 = rhs_string_utf8 - b->utf8; 647 p->ks = rhs_keysym; 648 return(n); 649error: 650 while (token != ENDOFLINE && token != ENDOFFILE) { 651 token = nexttoken(fp, tokenbuf, &lastch); 652 } 653 return(0); 654} 655 656void 657_XimParseStringFile( 658 FILE *fp, 659 Xim im) 660{ 661 char tb[8192]; 662 char* tbp; 663 struct stat st; 664 665 if (fstat (fileno (fp), &st) != -1) { 666 unsigned long size = (unsigned long) st.st_size; 667 if (size <= sizeof tb) tbp = tb; 668 else tbp = malloc (size); 669 670 if (tbp != NULL) { 671 while (parseline(fp, im, tbp) >= 0) {} 672 if (tbp != tb) free (tbp); 673 } 674 } 675} 676