imLcPrs.c revision 57f47464
1/****************************************************************** 2 3 Copyright 1992 by Oki Technosystems Laboratory, Inc. 4 Copyright 1992 by Fuji Xerox Co., Ltd. 5 6Permission to use, copy, modify, distribute, and sell this software 7and its documentation for any purpose is hereby granted without fee, 8provided that the above copyright notice appear in all copies and 9that both that copyright notice and this permission notice appear 10in supporting documentation, and that the name of Oki Technosystems 11Laboratory and Fuji Xerox not be used in advertising or publicity 12pertaining to distribution of the software without specific, written 13prior permission. 14Oki Technosystems Laboratory and Fuji Xerox make no representations 15about the suitability of this software for any purpose. It is provided 16"as is" without express or implied warranty. 17 18OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES 19WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF 20MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS 21LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR 22CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 23OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 24OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 25OR PERFORMANCE OF THIS SOFTWARE. 26 27 Author: Yasuhiro Kawai Oki Technosystems Laboratory 28 Author: Kazunori Nishihara Fuji Xerox 29 30******************************************************************/ 31 32 33#ifdef HAVE_CONFIG_H 34#include <config.h> 35#endif 36#include <X11/Xlib.h> 37#include <X11/Xmd.h> 38#include <X11/Xos.h> 39#include "Xlibint.h" 40#include "Xlcint.h" 41#include "Ximint.h" 42#include <sys/stat.h> 43#include <stdio.h> 44 45#define XLC_BUFSIZE 256 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 dir[XLC_BUFSIZE]; 308 char *i = name, *ret, *j; 309 int l = 0; 310 311 while (*i) { 312 if (*i == '%') { 313 i++; 314 switch (*i) { 315 case '%': 316 l++; 317 break; 318 case 'H': 319 home = getenv("HOME"); 320 if (home) 321 l += strlen(home); 322 break; 323 case 'L': 324 if (lcCompose == NULL) 325 lcCompose = _XlcFileName(im->core.lcd, COMPOSE_FILE); 326 if (lcCompose) 327 l += strlen(lcCompose); 328 break; 329 case 'S': 330 xlocaledir(dir, XLC_BUFSIZE); 331 l += strlen(dir); 332 break; 333 } 334 } else { 335 l++; 336 } 337 i++; 338 } 339 340 j = ret = Xmalloc(l+1); 341 if (ret == NULL) 342 return ret; 343 i = name; 344 while (*i) { 345 if (*i == '%') { 346 i++; 347 switch (*i) { 348 case '%': 349 *j++ = '%'; 350 break; 351 case 'H': 352 if (home) { 353 strcpy(j, home); 354 j += strlen(home); 355 } 356 break; 357 case 'L': 358 if (lcCompose) { 359 strcpy(j, lcCompose); 360 j += strlen(lcCompose); 361 } 362 break; 363 case 'S': 364 strcpy(j, dir); 365 j += strlen(dir); 366 break; 367 } 368 i++; 369 } else { 370 *j++ = *i++; 371 } 372 } 373 *j = '\0'; 374 Xfree(lcCompose); 375 return ret; 376} 377 378#ifndef MB_LEN_MAX 379#define MB_LEN_MAX 6 380#endif 381 382static int 383get_mb_string (Xim im, char *buf, KeySym ks) 384{ 385 XPointer from, to; 386 int from_len, to_len, len; 387 XPointer args[1]; 388 XlcCharSet charset; 389 char local_buf[MB_LEN_MAX]; 390 unsigned int ucs; 391 ucs = KeySymToUcs4(ks); 392 393 from = (XPointer) &ucs; 394 to = (XPointer) local_buf; 395 from_len = 1; 396 to_len = MB_LEN_MAX; 397 args[0] = (XPointer) &charset; 398 if (_XlcConvert(im->private.local.ucstoc_conv, 399 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 400 return 0; 401 } 402 403 from = (XPointer) local_buf; 404 to = (XPointer) buf; 405 from_len = MB_LEN_MAX - to_len; 406 to_len = MB_LEN_MAX + 1; 407 args[0] = (XPointer) charset; 408 if (_XlcConvert(im->private.local.cstomb_conv, 409 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 410 return 0; 411 } 412 len = MB_LEN_MAX + 1 - to_len; 413 buf[len] = '\0'; 414 return len; 415} 416 417#define AllMask (ShiftMask | LockMask | ControlMask | Mod1Mask) 418#define LOCAL_WC_BUFSIZE 128 419#define LOCAL_UTF8_BUFSIZE 256 420#define SEQUENCE_MAX 10 421 422static int 423parseline( 424 FILE *fp, 425 Xim im, 426 char* tokenbuf) 427{ 428 int token; 429 DTModifier modifier_mask; 430 DTModifier modifier; 431 DTModifier tmp; 432 KeySym keysym = NoSymbol; 433 DTIndex *top = &im->private.local.top; 434 DefTreeBase *b = &im->private.local.base; 435 DTIndex t; 436 DefTree *p = NULL; 437 Bool exclam, tilde; 438 KeySym rhs_keysym = 0; 439 char *rhs_string_mb; 440 int l; 441 int lastch = 0; 442 char local_mb_buf[MB_LEN_MAX+1]; 443 wchar_t local_wc_buf[LOCAL_WC_BUFSIZE], *rhs_string_wc; 444 char local_utf8_buf[LOCAL_UTF8_BUFSIZE], *rhs_string_utf8; 445 446 struct DefBuffer { 447 DTModifier modifier_mask; 448 DTModifier modifier; 449 KeySym keysym; 450 }; 451 452 struct DefBuffer buf[SEQUENCE_MAX]; 453 int i, n; 454 455 do { 456 token = nexttoken(fp, tokenbuf, &lastch); 457 } while (token == ENDOFLINE); 458 459 if (token == ENDOFFILE) { 460 return(-1); 461 } 462 463 n = 0; 464 do { 465 if ((token == KEY) && (strcmp("include", tokenbuf) == 0)) { 466 char *filename; 467 FILE *infp; 468 token = nexttoken(fp, tokenbuf, &lastch); 469 if (token != KEY && token != STRING) 470 goto error; 471 if ((filename = TransFileName(im, tokenbuf)) == NULL) 472 goto error; 473 infp = _XFopenFile(filename, "r"); 474 Xfree(filename); 475 if (infp == NULL) 476 goto error; 477 _XimParseStringFile(infp, im); 478 fclose(infp); 479 return (0); 480 } else if ((token == KEY) && (strcmp("None", tokenbuf) == 0)) { 481 modifier = 0; 482 modifier_mask = AllMask; 483 token = nexttoken(fp, tokenbuf, &lastch); 484 } else { 485 modifier_mask = modifier = 0; 486 exclam = False; 487 if (token == EXCLAM) { 488 exclam = True; 489 token = nexttoken(fp, tokenbuf, &lastch); 490 } 491 while (token == TILDE || token == KEY) { 492 tilde = False; 493 if (token == TILDE) { 494 tilde = True; 495 token = nexttoken(fp, tokenbuf, &lastch); 496 if (token != KEY) 497 goto error; 498 } 499 tmp = modmask(tokenbuf); 500 if (!tmp) { 501 goto error; 502 } 503 modifier_mask |= tmp; 504 if (tilde) { 505 modifier &= ~tmp; 506 } else { 507 modifier |= tmp; 508 } 509 token = nexttoken(fp, tokenbuf, &lastch); 510 } 511 if (exclam) { 512 modifier_mask = AllMask; 513 } 514 } 515 516 if (token != LESS) { 517 goto error; 518 } 519 520 token = nexttoken(fp, tokenbuf, &lastch); 521 if (token != KEY) { 522 goto error; 523 } 524 525 token = nexttoken(fp, tokenbuf, &lastch); 526 if (token != GREATER) { 527 goto error; 528 } 529 530 keysym = XStringToKeysym(tokenbuf); 531 if (keysym == NoSymbol) { 532 goto error; 533 } 534 535 buf[n].keysym = keysym; 536 buf[n].modifier = modifier; 537 buf[n].modifier_mask = modifier_mask; 538 n++; 539 if( n >= SEQUENCE_MAX ) 540 goto error; 541 token = nexttoken(fp, tokenbuf, &lastch); 542 } while (token != COLON); 543 544 token = nexttoken(fp, tokenbuf, &lastch); 545 if (token == STRING) { 546 l = strlen(tokenbuf) + 1; 547 while (b->mbused + l > b->mbsize) { 548 b->mbsize = b->mbsize ? b->mbsize * 1.5 : 1024; 549 if (! (b->mb = Xrealloc (b->mb, b->mbsize)) ) 550 goto error; 551 } 552 rhs_string_mb = &b->mb[b->mbused]; 553 b->mbused += l; 554 strcpy(rhs_string_mb, tokenbuf); 555 token = nexttoken(fp, tokenbuf, &lastch); 556 if (token == KEY) { 557 rhs_keysym = XStringToKeysym(tokenbuf); 558 if (rhs_keysym == NoSymbol) { 559 goto error; 560 } 561 token = nexttoken(fp, tokenbuf, &lastch); 562 } 563 if (token != ENDOFLINE && token != ENDOFFILE) { 564 goto error; 565 } 566 } else if (token == KEY) { 567 rhs_keysym = XStringToKeysym(tokenbuf); 568 if (rhs_keysym == NoSymbol) { 569 goto error; 570 } 571 token = nexttoken(fp, tokenbuf, &lastch); 572 if (token != ENDOFLINE && token != ENDOFFILE) { 573 goto error; 574 } 575 576 l = get_mb_string(im, local_mb_buf, rhs_keysym); 577 while (b->mbused + l + 1 > b->mbsize) { 578 b->mbsize = b->mbsize ? b->mbsize * 1.5 : 1024; 579 if (! (b->mb = Xrealloc (b->mb, b->mbsize)) ) 580 goto error; 581 } 582 rhs_string_mb = &b->mb[b->mbused]; 583 b->mbused += l + 1; 584 memcpy(rhs_string_mb, local_mb_buf, l); 585 rhs_string_mb[l] = '\0'; 586 } else { 587 goto error; 588 } 589 590 l = _Xmbstowcs(local_wc_buf, rhs_string_mb, LOCAL_WC_BUFSIZE - 1); 591 if (l == LOCAL_WC_BUFSIZE - 1) { 592 local_wc_buf[l] = (wchar_t)'\0'; 593 } 594 while (b->wcused + l + 1 > b->wcsize) { 595 b->wcsize = b->wcsize ? b->wcsize * 1.5 : 512; 596 if (! (b->wc = Xrealloc (b->wc, sizeof(wchar_t) * b->wcsize)) ) 597 goto error; 598 } 599 rhs_string_wc = &b->wc[b->wcused]; 600 b->wcused += l + 1; 601 memcpy((char *)rhs_string_wc, (char *)local_wc_buf, (l + 1) * sizeof(wchar_t) ); 602 603 l = _Xmbstoutf8(local_utf8_buf, rhs_string_mb, LOCAL_UTF8_BUFSIZE - 1); 604 if (l == LOCAL_UTF8_BUFSIZE - 1) { 605 local_utf8_buf[l] = '\0'; 606 } 607 while (b->utf8used + l + 1 > b->utf8size) { 608 b->utf8size = b->utf8size ? b->utf8size * 1.5 : 1024; 609 if (! (b->utf8 = Xrealloc (b->utf8, b->utf8size)) ) 610 goto error; 611 } 612 rhs_string_utf8 = &b->utf8[b->utf8used]; 613 b->utf8used += l + 1; 614 memcpy(rhs_string_utf8, local_utf8_buf, l + 1); 615 616 for (i = 0; i < n; i++) { 617 for (t = *top; t; t = b->tree[t].next) { 618 if (buf[i].keysym == b->tree[t].keysym && 619 buf[i].modifier == b->tree[t].modifier && 620 buf[i].modifier_mask == b->tree[t].modifier_mask) { 621 break; 622 } 623 } 624 if (t) { 625 p = &b->tree[t]; 626 top = &p->succession; 627 } else { 628 while (b->treeused >= b->treesize) { 629 DefTree *old = b->tree; 630 int oldsize = b->treesize; 631 b->treesize = b->treesize ? b->treesize * 1.5 : 256; 632 if (! (b->tree = Xrealloc (b->tree, sizeof(DefTree) * b->treesize)) ) 633 goto error; 634 if (top >= (DTIndex *) old && top < (DTIndex *) &old[oldsize]) 635 top = (DTIndex *) (((char *) top) + (((char *)b->tree)-(char *)old)); 636 } 637 p = &b->tree[b->treeused]; 638 p->keysym = buf[i].keysym; 639 p->modifier = buf[i].modifier; 640 p->modifier_mask = buf[i].modifier_mask; 641 p->succession = 0; 642 p->next = *top; 643 p->mb = 0; 644 p->wc = 0; 645 p->utf8 = 0; 646 p->ks = NoSymbol; 647 *top = b->treeused; 648 top = &p->succession; 649 b->treeused++; 650 } 651 } 652 653 /* old entries no longer freed... */ 654 p->mb = rhs_string_mb - b->mb; 655 p->wc = rhs_string_wc - b->wc; 656 p->utf8 = rhs_string_utf8 - b->utf8; 657 p->ks = rhs_keysym; 658 return(n); 659error: 660 while (token != ENDOFLINE && token != ENDOFFILE) { 661 token = nexttoken(fp, tokenbuf, &lastch); 662 } 663 return(0); 664} 665 666void 667_XimParseStringFile( 668 FILE *fp, 669 Xim im) 670{ 671 char tb[8192]; 672 char* tbp; 673 struct stat st; 674 675 if (fstat (fileno (fp), &st) != -1) { 676 unsigned long size = (unsigned long) st.st_size; 677 if (size <= sizeof tb) tbp = tb; 678 else tbp = malloc (size); 679 680 if (tbp != NULL) { 681 while (parseline(fp, im, tbp) >= 0) {} 682 if (tbp != tb) free (tbp); 683 } 684 } 685} 686