imLcPrs.c revision 2d67cb4f
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#include <limits.h> 45#include "pathmax.h" 46 47#define XLC_BUFSIZE 256 48 49extern int _Xmbstowcs( 50 wchar_t *wstr, 51 char *str, 52 int len 53); 54 55extern int _Xmbstoutf8( 56 char *ustr, 57 const char *str, 58 int len 59); 60 61static void parsestringfile(FILE *fp, Xim im, int depth); 62 63/* 64 * Parsing File Format: 65 * 66 * FILE ::= { [PRODUCTION] [COMMENT] "\n"} 67 * PRODUCTION ::= LHS ":" RHS [ COMMENT ] 68 * COMMENT ::= "#" {<any character except null or newline>} 69 * LHS ::= EVENT { EVENT } 70 * EVENT ::= [MODIFIER_LIST] "<" keysym ">" 71 * MODIFIER_LIST ::= (["!"] {MODIFIER} ) | "None" 72 * MODIFIER ::= ["~"] MODIFIER_NAME 73 * MODIFIER_NAME ::= ("Ctrl"|"Lock"|"Caps"|"Shift"|"Alt"|"Meta") 74 * RHS ::= ( STRING | keysym | STRING keysym ) 75 * STRING ::= '"' { CHAR } '"' 76 * CHAR ::= GRAPHIC_CHAR | ESCAPED_CHAR 77 * GRAPHIC_CHAR ::= locale (codeset) dependent code 78 * ESCAPED_CHAR ::= ('\\' | '\"' | OCTAL | HEX ) 79 * OCTAL ::= '\' OCTAL_CHAR [OCTAL_CHAR [OCTAL_CHAR]] 80 * OCTAL_CHAR ::= (0|1|2|3|4|5|6|7) 81 * HEX ::= '\' (x|X) HEX_CHAR [HEX_CHAR]] 82 * HEX_CHAR ::= (0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|a|b|c|d|e|f) 83 * 84 */ 85 86static int 87nextch( 88 FILE *fp, 89 int *lastch) 90{ 91 int c; 92 93 if (*lastch != 0) { 94 c = *lastch; 95 *lastch = 0; 96 } else { 97 c = getc(fp); 98 if (c == '\\') { 99 c = getc(fp); 100 if (c == '\n') { 101 c = getc(fp); 102 } else { 103 ungetc(c, fp); 104 c = '\\'; 105 } 106 } 107 } 108 return(c); 109} 110 111static void 112putbackch( 113 int c, 114 int *lastch) 115{ 116 *lastch = c; 117} 118 119#define ENDOFFILE 0 120#define ENDOFLINE 1 121#define COLON 2 122#define LESS 3 123#define GREATER 4 124#define EXCLAM 5 125#define TILDE 6 126#define STRING 7 127#define KEY 8 128#define ERROR 9 129 130#ifndef isalnum 131#define isalnum(c) \ 132 (('0' <= (c) && (c) <= '9') || \ 133 ('A' <= (c) && (c) <= 'Z') || \ 134 ('a' <= (c) && (c) <= 'z')) 135#endif 136 137static int 138nexttoken( 139 FILE *fp, 140 char *tokenbuf, 141 int *lastch) 142{ 143 int c; 144 int token; 145 char *p; 146 int i, j; 147 148 while ((c = nextch(fp, lastch)) == ' ' || c == '\t') { 149 } 150 switch (c) { 151 case EOF: 152 token = ENDOFFILE; 153 break; 154 case '\n': 155 token = ENDOFLINE; 156 break; 157 case '<': 158 token = LESS; 159 break; 160 case '>': 161 token = GREATER; 162 break; 163 case ':': 164 token = COLON; 165 break; 166 case '!': 167 token = EXCLAM; 168 break; 169 case '~': 170 token = TILDE; 171 break; 172 case '"': 173 p = tokenbuf; 174 while ((c = nextch(fp, lastch)) != '"') { 175 if (c == '\n' || c == EOF) { 176 putbackch(c, lastch); 177 token = ERROR; 178 goto string_error; 179 } else if (c == '\\') { 180 c = nextch(fp, lastch); 181 switch (c) { 182 case '\\': 183 case '"': 184 *p++ = c; 185 break; 186 case 'n': 187 *p++ = '\n'; 188 break; 189 case 'r': 190 *p++ = '\r'; 191 break; 192 case 't': 193 *p++ = '\t'; 194 break; 195 case '0': 196 case '1': 197 case '2': 198 case '3': 199 case '4': 200 case '5': 201 case '6': 202 case '7': 203 i = c - '0'; 204 c = nextch(fp, lastch); 205 for (j = 0; j < 2 && c >= '0' && c <= '7'; j++) { 206 i <<= 3; 207 i += c - '0'; 208 c = nextch(fp, lastch); 209 } 210 putbackch(c, lastch); 211 *p++ = (char)i; 212 break; 213 case 'X': 214 case 'x': 215 i = 0; 216 for (j = 0; j < 2; j++) { 217 c = nextch(fp, lastch); 218 i <<= 4; 219 if (c >= '0' && c <= '9') { 220 i += c - '0'; 221 } else if (c >= 'A' && c <= 'F') { 222 i += c - 'A' + 10; 223 } else if (c >= 'a' && c <= 'f') { 224 i += c - 'a' + 10; 225 } else { 226 putbackch(c, lastch); 227 i >>= 4; 228 break; 229 } 230 } 231 if (j == 0) { 232 token = ERROR; 233 goto string_error; 234 } 235 *p++ = (char)i; 236 break; 237 case EOF: 238 putbackch(c, lastch); 239 token = ERROR; 240 goto string_error; 241 default: 242 *p++ = c; 243 break; 244 } 245 } else { 246 *p++ = c; 247 } 248 } 249 *p = '\0'; 250 token = STRING; 251 break; 252 case '#': 253 while ((c = nextch(fp, lastch)) != '\n' && c != EOF) { 254 } 255 if (c == '\n') { 256 token = ENDOFLINE; 257 } else { 258 token = ENDOFFILE; 259 } 260 break; 261 default: 262 if (isalnum(c) || c == '_' || c == '-') { 263 p = tokenbuf; 264 *p++ = c; 265 c = nextch(fp, lastch); 266 while (isalnum(c) || c == '_' || c == '-') { 267 *p++ = c; 268 c = nextch(fp, lastch); 269 } 270 *p = '\0'; 271 putbackch(c, lastch); 272 token = KEY; 273 } else { 274 token = ERROR; 275 } 276 break; 277 } 278string_error: 279 return(token); 280} 281 282static long 283modmask( 284 char *name) 285{ 286 struct _modtbl { 287 const char name[6]; 288 long mask; 289 }; 290 291 static const struct _modtbl tbl[] = { 292 { "Ctrl", ControlMask }, 293 { "Lock", LockMask }, 294 { "Caps", LockMask }, 295 { "Shift", ShiftMask }, 296 { "Alt", Mod1Mask }, 297 { "Meta", Mod1Mask }}; 298 299 int i, num_entries = sizeof (tbl) / sizeof (tbl[0]); 300 301 for (i = 0; i < num_entries; i++) 302 if (!strcmp (name, tbl[i].name)) 303 return tbl[i].mask; 304 305 return 0; 306} 307 308static char* 309TransFileName(Xim im, char *name) 310{ 311 char *home = NULL, *lcCompose = NULL; 312 char dir[XLC_BUFSIZE] = ""; 313 char *i = name, *ret = NULL, *j; 314 size_t l = 0; 315 316 while (*i) { 317 if (*i == '%') { 318 i++; 319 switch (*i) { 320 case '%': 321 l++; 322 break; 323 case 'H': 324 if (home == NULL) 325 home = getenv("HOME"); 326 if (home) { 327 size_t Hsize = strlen(home); 328 if (Hsize > PATH_MAX) 329 /* your home directory length is ridiculous */ 330 goto end; 331 l += Hsize; 332 } 333 break; 334 case 'L': 335 if (lcCompose == NULL) 336 lcCompose = _XlcFileName(im->core.lcd, COMPOSE_FILE); 337 if (lcCompose) { 338 size_t Lsize = strlen(lcCompose); 339 if (Lsize > PATH_MAX) 340 /* your compose pathname length is ridiculous */ 341 goto end; 342 l += Lsize; 343 } 344 break; 345 case 'S': 346 if (dir[0] == '\0') 347 xlocaledir(dir, XLC_BUFSIZE); 348 if (dir[0]) { 349 size_t Ssize = strlen(dir); 350 if (Ssize > PATH_MAX) 351 /* your locale directory path length is ridiculous */ 352 goto end; 353 l += Ssize; 354 } 355 break; 356 } 357 } else { 358 l++; 359 } 360 i++; 361 if (l > PATH_MAX) 362 /* your expanded path length is ridiculous */ 363 goto end; 364 } 365 366 j = ret = Xmalloc(l+1); 367 if (ret == NULL) 368 goto end; 369 i = name; 370 while (*i) { 371 if (*i == '%') { 372 i++; 373 switch (*i) { 374 case '%': 375 *j++ = '%'; 376 break; 377 case 'H': 378 if (home) { 379 strcpy(j, home); 380 j += strlen(home); 381 } 382 break; 383 case 'L': 384 if (lcCompose) { 385 strcpy(j, lcCompose); 386 j += strlen(lcCompose); 387 } 388 break; 389 case 'S': 390 strcpy(j, dir); 391 j += strlen(dir); 392 break; 393 } 394 i++; 395 } else { 396 *j++ = *i++; 397 } 398 } 399 *j = '\0'; 400end: 401 Xfree(lcCompose); 402 return ret; 403} 404 405#ifndef MB_LEN_MAX 406#define MB_LEN_MAX 6 407#endif 408 409static int 410get_mb_string (Xim im, char *buf, KeySym ks) 411{ 412 XPointer from, to; 413 int from_len, to_len, len; 414 XPointer args[1]; 415 XlcCharSet charset; 416 char local_buf[MB_LEN_MAX]; 417 unsigned int ucs; 418 ucs = KeySymToUcs4(ks); 419 420 from = (XPointer) &ucs; 421 to = (XPointer) local_buf; 422 from_len = 1; 423 to_len = MB_LEN_MAX; 424 args[0] = (XPointer) &charset; 425 if (_XlcConvert(im->private.local.ucstoc_conv, 426 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 427 return 0; 428 } 429 430 from = (XPointer) local_buf; 431 to = (XPointer) buf; 432 from_len = MB_LEN_MAX - to_len; 433 to_len = MB_LEN_MAX + 1; 434 args[0] = (XPointer) charset; 435 if (_XlcConvert(im->private.local.cstomb_conv, 436 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 437 return 0; 438 } 439 len = MB_LEN_MAX + 1 - to_len; 440 buf[len] = '\0'; 441 return len; 442} 443 444#define AllMask (ShiftMask | LockMask | ControlMask | Mod1Mask) 445#define LOCAL_WC_BUFSIZE 128 446#define LOCAL_UTF8_BUFSIZE 256 447#define SEQUENCE_MAX 10 448 449static int 450parseline( 451 FILE *fp, 452 Xim im, 453 char* tokenbuf, 454 int depth) 455{ 456 int token; 457 DTModifier modifier_mask; 458 DTModifier modifier; 459 DTModifier tmp; 460 KeySym keysym = NoSymbol; 461 DTIndex *top = &im->private.local.top; 462 DefTreeBase *b = &im->private.local.base; 463 DTIndex t; 464 DefTree *p = NULL; 465 Bool exclam, tilde; 466 KeySym rhs_keysym = 0; 467 char *rhs_string_mb; 468 int l; 469 int lastch = 0; 470 char local_mb_buf[MB_LEN_MAX+1]; 471 wchar_t local_wc_buf[LOCAL_WC_BUFSIZE], *rhs_string_wc; 472 char local_utf8_buf[LOCAL_UTF8_BUFSIZE], *rhs_string_utf8; 473 474 struct DefBuffer { 475 DTModifier modifier_mask; 476 DTModifier modifier; 477 KeySym keysym; 478 }; 479 480 struct DefBuffer buf[SEQUENCE_MAX]; 481 int i, n; 482 483 do { 484 token = nexttoken(fp, tokenbuf, &lastch); 485 } while (token == ENDOFLINE); 486 487 if (token == ENDOFFILE) { 488 return(-1); 489 } 490 491 n = 0; 492 do { 493 if ((token == KEY) && (strcmp("include", tokenbuf) == 0)) { 494 char *filename; 495 FILE *infp; 496 token = nexttoken(fp, tokenbuf, &lastch); 497 if (token != KEY && token != STRING) 498 goto error; 499 if (++depth > 100) 500 goto error; 501 if ((filename = TransFileName(im, tokenbuf)) == NULL) 502 goto error; 503 infp = _XFopenFile(filename, "r"); 504 Xfree(filename); 505 if (infp == NULL) 506 goto error; 507 parsestringfile(infp, im, depth); 508 fclose(infp); 509 return (0); 510 } else if ((token == KEY) && (strcmp("None", tokenbuf) == 0)) { 511 modifier = 0; 512 modifier_mask = AllMask; 513 token = nexttoken(fp, tokenbuf, &lastch); 514 } else { 515 modifier_mask = modifier = 0; 516 exclam = False; 517 if (token == EXCLAM) { 518 exclam = True; 519 token = nexttoken(fp, tokenbuf, &lastch); 520 } 521 while (token == TILDE || token == KEY) { 522 tilde = False; 523 if (token == TILDE) { 524 tilde = True; 525 token = nexttoken(fp, tokenbuf, &lastch); 526 if (token != KEY) 527 goto error; 528 } 529 tmp = modmask(tokenbuf); 530 if (!tmp) { 531 goto error; 532 } 533 modifier_mask |= tmp; 534 if (tilde) { 535 modifier &= ~tmp; 536 } else { 537 modifier |= tmp; 538 } 539 token = nexttoken(fp, tokenbuf, &lastch); 540 } 541 if (exclam) { 542 modifier_mask = AllMask; 543 } 544 } 545 546 if (token != LESS) { 547 goto error; 548 } 549 550 token = nexttoken(fp, tokenbuf, &lastch); 551 if (token != KEY) { 552 goto error; 553 } 554 555 token = nexttoken(fp, tokenbuf, &lastch); 556 if (token != GREATER) { 557 goto error; 558 } 559 560 keysym = XStringToKeysym(tokenbuf); 561 if (keysym == NoSymbol) { 562 goto error; 563 } 564 565 buf[n].keysym = keysym; 566 buf[n].modifier = modifier; 567 buf[n].modifier_mask = modifier_mask; 568 n++; 569 if( n >= SEQUENCE_MAX ) 570 goto error; 571 token = nexttoken(fp, tokenbuf, &lastch); 572 } while (token != COLON); 573 574 token = nexttoken(fp, tokenbuf, &lastch); 575 if (token == STRING) { 576 l = strlen(tokenbuf) + 1; 577 while (b->mbused + l > b->mbsize) { 578 DTCharIndex newsize = b->mbsize ? b->mbsize * 1.5 : 1024; 579 char *newmb = Xrealloc (b->mb, newsize); 580 if (newmb == NULL) 581 goto error; 582 b->mb = newmb; 583 b->mbsize = newsize; 584 } 585 rhs_string_mb = &b->mb[b->mbused]; 586 b->mbused += l; 587 strcpy(rhs_string_mb, tokenbuf); 588 token = nexttoken(fp, tokenbuf, &lastch); 589 if (token == KEY) { 590 rhs_keysym = XStringToKeysym(tokenbuf); 591 if (rhs_keysym == NoSymbol) { 592 goto error; 593 } 594 token = nexttoken(fp, tokenbuf, &lastch); 595 } 596 if (token != ENDOFLINE && token != ENDOFFILE) { 597 goto error; 598 } 599 } else if (token == KEY) { 600 rhs_keysym = XStringToKeysym(tokenbuf); 601 if (rhs_keysym == NoSymbol) { 602 goto error; 603 } 604 token = nexttoken(fp, tokenbuf, &lastch); 605 if (token != ENDOFLINE && token != ENDOFFILE) { 606 goto error; 607 } 608 609 l = get_mb_string(im, local_mb_buf, rhs_keysym); 610 while (b->mbused + l + 1 > b->mbsize) { 611 DTCharIndex newsize = b->mbsize ? b->mbsize * 1.5 : 1024; 612 char *newmb = Xrealloc (b->mb, newsize); 613 if (newmb == NULL) 614 goto error; 615 b->mb = newmb; 616 b->mbsize = newsize; 617 } 618 rhs_string_mb = &b->mb[b->mbused]; 619 b->mbused += l + 1; 620 memcpy(rhs_string_mb, local_mb_buf, l); 621 rhs_string_mb[l] = '\0'; 622 } else { 623 goto error; 624 } 625 626 l = _Xmbstowcs(local_wc_buf, rhs_string_mb, LOCAL_WC_BUFSIZE - 1); 627 if (l == LOCAL_WC_BUFSIZE - 1) { 628 local_wc_buf[l] = (wchar_t)'\0'; 629 } 630 while (b->wcused + l + 1 > b->wcsize) { 631 DTCharIndex newsize = b->wcsize ? b->wcsize * 1.5 : 512; 632 wchar_t *newwc = Xrealloc (b->wc, sizeof(wchar_t) * newsize); 633 if (newwc == NULL) 634 goto error; 635 b->wc = newwc; 636 b->wcsize = newsize; 637 } 638 rhs_string_wc = &b->wc[b->wcused]; 639 b->wcused += l + 1; 640 memcpy((char *)rhs_string_wc, (char *)local_wc_buf, (l + 1) * sizeof(wchar_t) ); 641 642 l = _Xmbstoutf8(local_utf8_buf, rhs_string_mb, LOCAL_UTF8_BUFSIZE - 1); 643 if (l == LOCAL_UTF8_BUFSIZE - 1) { 644 local_utf8_buf[l] = '\0'; 645 } 646 while (b->utf8used + l + 1 > b->utf8size) { 647 DTCharIndex newsize = b->utf8size ? b->utf8size * 1.5 : 1024; 648 char *newutf8 = Xrealloc (b->utf8, newsize); 649 if (newutf8 == NULL) 650 goto error; 651 b->utf8 = newutf8; 652 b->utf8size = newsize; 653 } 654 rhs_string_utf8 = &b->utf8[b->utf8used]; 655 b->utf8used += l + 1; 656 memcpy(rhs_string_utf8, local_utf8_buf, l + 1); 657 658 for (i = 0; i < n; i++) { 659 for (t = *top; t; t = b->tree[t].next) { 660 if (buf[i].keysym == b->tree[t].keysym && 661 buf[i].modifier == b->tree[t].modifier && 662 buf[i].modifier_mask == b->tree[t].modifier_mask) { 663 break; 664 } 665 } 666 if (t) { 667 p = &b->tree[t]; 668 top = &p->succession; 669 } else { 670 while (b->treeused >= b->treesize) { 671 DefTree *old = b->tree; 672 int oldsize = b->treesize; 673 int newsize = b->treesize ? b->treesize * 1.5 : 256; 674 DefTree *new = Xrealloc (b->tree, sizeof(DefTree) * newsize); 675 if (new == NULL) 676 goto error; 677 b->tree = new; 678 b->treesize = newsize; 679 if (top >= (DTIndex *) old && top < (DTIndex *) &old[oldsize]) 680 top = (DTIndex *) (((char *) top) + (((char *)b->tree)-(char *)old)); 681 } 682 p = &b->tree[b->treeused]; 683 p->keysym = buf[i].keysym; 684 p->modifier = buf[i].modifier; 685 p->modifier_mask = buf[i].modifier_mask; 686 p->succession = 0; 687 p->next = *top; 688 p->mb = 0; 689 p->wc = 0; 690 p->utf8 = 0; 691 p->ks = NoSymbol; 692 *top = b->treeused; 693 top = &p->succession; 694 b->treeused++; 695 } 696 } 697 698 /* old entries no longer freed... */ 699 p->mb = rhs_string_mb - b->mb; 700 p->wc = rhs_string_wc - b->wc; 701 p->utf8 = rhs_string_utf8 - b->utf8; 702 p->ks = rhs_keysym; 703 return(n); 704error: 705 while (token != ENDOFLINE && token != ENDOFFILE) { 706 token = nexttoken(fp, tokenbuf, &lastch); 707 } 708 return(0); 709} 710 711void 712_XimParseStringFile( 713 FILE *fp, 714 Xim im) 715{ 716 parsestringfile(fp, im, 0); 717} 718 719static void 720parsestringfile( 721 FILE *fp, 722 Xim im, 723 int depth) 724{ 725 char tb[8192]; 726 char* tbp; 727 struct stat st; 728 729 if (fstat (fileno (fp), &st) != -1) { 730 unsigned long size = (unsigned long) st.st_size; 731 if (st.st_size >= INT_MAX) 732 return; 733 if (size <= sizeof tb) tbp = tb; 734 else tbp = malloc (size); 735 736 if (tbp != NULL) { 737 while (parseline(fp, im, tbp, depth) >= 0) {} 738 if (tbp != tb) free (tbp); 739 } 740 } 741} 742