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