imLcPrs.c revision b4ee4795
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 void xlocaledir( 48 char *buf, 49 int buf_len 50); 51 52extern int _Xmbstowcs( 53 wchar_t *wstr, 54 char *str, 55 int len 56); 57 58extern int _Xmbstoutf8( 59 char *ustr, 60 const char *str, 61 int len 62); 63 64/* 65 * Parsing File Format: 66 * 67 * FILE ::= { [PRODUCTION] [COMMENT] "\n"} 68 * PRODUCTION ::= LHS ":" RHS [ COMMENT ] 69 * COMMENT ::= "#" {<any character except null or newline>} 70 * LHS ::= EVENT { EVENT } 71 * EVENT ::= [MODIFIER_LIST] "<" keysym ">" 72 * MODIFIER_LIST ::= ("!" {MODIFIER} ) | "None" 73 * MODIFIER ::= ["~"] modifier_name 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, *j; 314 int l = 0; 315 316 while (*i) { 317 if (*i == '%') { 318 i++; 319 switch (*i) { 320 case '%': 321 l++; 322 break; 323 case 'H': 324 home = getenv("HOME"); 325 if (home) 326 l += strlen(home); 327 break; 328 case 'L': 329 lcCompose = _XlcFileName(im->core.lcd, COMPOSE_FILE); 330 if (lcCompose) 331 l += strlen(lcCompose); 332 break; 333 case 'S': 334 xlocaledir(dir, XLC_BUFSIZE); 335 l += strlen(dir); 336 break; 337 } 338 } else { 339 l++; 340 } 341 i++; 342 } 343 344 j = ret = Xmalloc(l+1); 345 if (ret == NULL) 346 return ret; 347 i = name; 348 while (*i) { 349 if (*i == '%') { 350 i++; 351 switch (*i) { 352 case '%': 353 *j++ = '%'; 354 break; 355 case 'H': 356 if (home) { 357 strcpy(j, home); 358 j += strlen(home); 359 } 360 break; 361 case 'L': 362 if (lcCompose) { 363 strcpy(j, lcCompose); 364 j += strlen(lcCompose); 365 Xfree(lcCompose); 366 } 367 break; 368 case 'S': 369 strcpy(j, dir); 370 j += strlen(dir); 371 break; 372 } 373 i++; 374 } else { 375 *j++ = *i++; 376 } 377 } 378 *j = '\0'; 379 return ret; 380} 381 382#ifndef MB_LEN_MAX 383#define MB_LEN_MAX 6 384#endif 385 386static int 387get_mb_string (Xim im, char *buf, KeySym ks) 388{ 389 XPointer from, to; 390 int from_len, to_len, len; 391 XPointer args[1]; 392 XlcCharSet charset; 393 char local_buf[MB_LEN_MAX]; 394 unsigned int ucs; 395 ucs = KeySymToUcs4(ks); 396 397 from = (XPointer) &ucs; 398 to = (XPointer) local_buf; 399 from_len = 1; 400 to_len = MB_LEN_MAX; 401 args[0] = (XPointer) &charset; 402 if (_XlcConvert(im->private.local.ucstoc_conv, 403 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 404 return 0; 405 } 406 407 from = (XPointer) local_buf; 408 to = (XPointer) buf; 409 from_len = MB_LEN_MAX - to_len; 410 to_len = MB_LEN_MAX + 1; 411 args[0] = (XPointer) charset; 412 if (_XlcConvert(im->private.local.cstomb_conv, 413 &from, &from_len, &to, &to_len, args, 1 ) != 0) { 414 return 0; 415 } 416 len = MB_LEN_MAX + 1 - to_len; 417 buf[len] = '\0'; 418 return len; 419} 420 421#define AllMask (ShiftMask | LockMask | ControlMask | Mod1Mask) 422#define LOCAL_WC_BUFSIZE 128 423#define LOCAL_UTF8_BUFSIZE 256 424#define SEQUENCE_MAX 10 425 426static int 427parseline( 428 FILE *fp, 429 Xim im, 430 char* tokenbuf) 431{ 432 int token; 433 DTModifier modifier_mask; 434 DTModifier modifier; 435 DTModifier tmp; 436 KeySym keysym = NoSymbol; 437 DTIndex *top = &im->private.local.top; 438 DefTreeBase *b = &im->private.local.base; 439 DTIndex t; 440 DefTree *p = NULL; 441 Bool exclam, tilde; 442 KeySym rhs_keysym = 0; 443 char *rhs_string_mb; 444 int l; 445 int lastch = 0; 446 char local_mb_buf[MB_LEN_MAX+1]; 447 wchar_t local_wc_buf[LOCAL_WC_BUFSIZE], *rhs_string_wc; 448 char local_utf8_buf[LOCAL_UTF8_BUFSIZE], *rhs_string_utf8; 449 450 struct DefBuffer { 451 DTModifier modifier_mask; 452 DTModifier modifier; 453 KeySym keysym; 454 }; 455 456 struct DefBuffer buf[SEQUENCE_MAX]; 457 int i, n; 458 459 do { 460 token = nexttoken(fp, tokenbuf, &lastch); 461 } while (token == ENDOFLINE); 462 463 if (token == ENDOFFILE) { 464 return(-1); 465 } 466 467 n = 0; 468 do { 469 if ((token == KEY) && (strcmp("include", tokenbuf) == 0)) { 470 char *filename; 471 FILE *infp; 472 token = nexttoken(fp, tokenbuf, &lastch); 473 if (token != KEY && token != STRING) 474 goto error; 475 if ((filename = TransFileName(im, tokenbuf)) == NULL) 476 goto error; 477 infp = _XFopenFile(filename, "r"); 478 Xfree(filename); 479 if (infp == NULL) 480 goto error; 481 _XimParseStringFile(infp, im); 482 fclose(infp); 483 return (0); 484 } else if ((token == KEY) && (strcmp("None", tokenbuf) == 0)) { 485 modifier = 0; 486 modifier_mask = AllMask; 487 token = nexttoken(fp, tokenbuf, &lastch); 488 } else { 489 modifier_mask = modifier = 0; 490 exclam = False; 491 if (token == EXCLAM) { 492 exclam = True; 493 token = nexttoken(fp, tokenbuf, &lastch); 494 } 495 while (token == TILDE || token == KEY) { 496 tilde = False; 497 if (token == TILDE) { 498 tilde = True; 499 token = nexttoken(fp, tokenbuf, &lastch); 500 if (token != KEY) 501 goto error; 502 } 503 tmp = modmask(tokenbuf); 504 if (!tmp) { 505 goto error; 506 } 507 modifier_mask |= tmp; 508 if (tilde) { 509 modifier &= ~tmp; 510 } else { 511 modifier |= tmp; 512 } 513 token = nexttoken(fp, tokenbuf, &lastch); 514 } 515 if (exclam) { 516 modifier_mask = AllMask; 517 } 518 } 519 520 if (token != LESS) { 521 goto error; 522 } 523 524 token = nexttoken(fp, tokenbuf, &lastch); 525 if (token != KEY) { 526 goto error; 527 } 528 529 token = nexttoken(fp, tokenbuf, &lastch); 530 if (token != GREATER) { 531 goto error; 532 } 533 534 keysym = XStringToKeysym(tokenbuf); 535 if (keysym == NoSymbol) { 536 goto error; 537 } 538 539 buf[n].keysym = keysym; 540 buf[n].modifier = modifier; 541 buf[n].modifier_mask = modifier_mask; 542 n++; 543 if( n >= SEQUENCE_MAX ) 544 goto error; 545 token = nexttoken(fp, tokenbuf, &lastch); 546 } while (token != COLON); 547 548 token = nexttoken(fp, tokenbuf, &lastch); 549 if (token == STRING) { 550 l = strlen(tokenbuf) + 1; 551 while (b->mbused + l > b->mbsize) { 552 b->mbsize = b->mbsize ? b->mbsize * 1.5 : 1024; 553 if (! (b->mb = Xrealloc (b->mb, b->mbsize)) ) 554 goto error; 555 } 556 rhs_string_mb = &b->mb[b->mbused]; 557 b->mbused += l; 558 strcpy(rhs_string_mb, tokenbuf); 559 token = nexttoken(fp, tokenbuf, &lastch); 560 if (token == KEY) { 561 rhs_keysym = XStringToKeysym(tokenbuf); 562 if (rhs_keysym == NoSymbol) { 563 goto error; 564 } 565 token = nexttoken(fp, tokenbuf, &lastch); 566 } 567 if (token != ENDOFLINE && token != ENDOFFILE) { 568 goto error; 569 } 570 } else if (token == KEY) { 571 rhs_keysym = XStringToKeysym(tokenbuf); 572 if (rhs_keysym == NoSymbol) { 573 goto error; 574 } 575 token = nexttoken(fp, tokenbuf, &lastch); 576 if (token != ENDOFLINE && token != ENDOFFILE) { 577 goto error; 578 } 579 580 l = get_mb_string(im, local_mb_buf, rhs_keysym); 581 while (b->mbused + l + 1 > b->mbsize) { 582 b->mbsize = b->mbsize ? b->mbsize * 1.5 : 1024; 583 if (! (b->mb = Xrealloc (b->mb, b->mbsize)) ) 584 goto error; 585 } 586 rhs_string_mb = &b->mb[b->mbused]; 587 b->mbused += l + 1; 588 memcpy(rhs_string_mb, local_mb_buf, l); 589 rhs_string_mb[l] = '\0'; 590 } else { 591 goto error; 592 } 593 594 l = _Xmbstowcs(local_wc_buf, rhs_string_mb, LOCAL_WC_BUFSIZE - 1); 595 if (l == LOCAL_WC_BUFSIZE - 1) { 596 local_wc_buf[l] = (wchar_t)'\0'; 597 } 598 while (b->wcused + l + 1 > b->wcsize) { 599 b->wcsize = b->wcsize ? b->wcsize * 1.5 : 512; 600 if (! (b->wc = Xrealloc (b->wc, sizeof(wchar_t) * b->wcsize)) ) 601 goto error; 602 } 603 rhs_string_wc = &b->wc[b->wcused]; 604 b->wcused += l + 1; 605 memcpy((char *)rhs_string_wc, (char *)local_wc_buf, (l + 1) * sizeof(wchar_t) ); 606 607 l = _Xmbstoutf8(local_utf8_buf, rhs_string_mb, LOCAL_UTF8_BUFSIZE - 1); 608 if (l == LOCAL_UTF8_BUFSIZE - 1) { 609 local_utf8_buf[l] = '\0'; 610 } 611 while (b->utf8used + l + 1 > b->utf8size) { 612 b->utf8size = b->utf8size ? b->utf8size * 1.5 : 1024; 613 if (! (b->utf8 = Xrealloc (b->utf8, b->utf8size)) ) 614 goto error; 615 } 616 rhs_string_utf8 = &b->utf8[b->utf8used]; 617 b->utf8used += l + 1; 618 memcpy(rhs_string_utf8, local_utf8_buf, l + 1); 619 620 for (i = 0; i < n; i++) { 621 for (t = *top; t; t = b->tree[t].next) { 622 if (buf[i].keysym == b->tree[t].keysym && 623 buf[i].modifier == b->tree[t].modifier && 624 buf[i].modifier_mask == b->tree[t].modifier_mask) { 625 break; 626 } 627 } 628 if (t) { 629 p = &b->tree[t]; 630 top = &p->succession; 631 } else { 632 while (b->treeused >= b->treesize) { 633 DefTree *old = b->tree; 634 int oldsize = b->treesize; 635 b->treesize = b->treesize ? b->treesize * 1.5 : 256; 636 if (! (b->tree = Xrealloc (b->tree, sizeof(DefTree) * b->treesize)) ) 637 goto error; 638 if (top >= (DTIndex *) old && top < (DTIndex *) &old[oldsize]) 639 top = (DTIndex *) (((char *) top) + (((char *)b->tree)-(char *)old)); 640 } 641 p = &b->tree[b->treeused]; 642 p->keysym = buf[i].keysym; 643 p->modifier = buf[i].modifier; 644 p->modifier_mask = buf[i].modifier_mask; 645 p->succession = 0; 646 p->next = *top; 647 p->mb = 0; 648 p->wc = 0; 649 p->utf8 = 0; 650 p->ks = NoSymbol; 651 *top = b->treeused; 652 top = &p->succession; 653 b->treeused++; 654 } 655 } 656 657 /* old entries no longer freed... */ 658 p->mb = rhs_string_mb - b->mb; 659 p->wc = rhs_string_wc - b->wc; 660 p->utf8 = rhs_string_utf8 - b->utf8; 661 p->ks = rhs_keysym; 662 return(n); 663error: 664 while (token != ENDOFLINE && token != ENDOFFILE) { 665 token = nexttoken(fp, tokenbuf, &lastch); 666 } 667 return(0); 668} 669 670void 671_XimParseStringFile( 672 FILE *fp, 673 Xim im) 674{ 675 char tb[8192]; 676 char* tbp; 677 struct stat st; 678 679 if (fstat (fileno (fp), &st) != -1) { 680 unsigned long size = (unsigned long) st.st_size; 681 if (size <= sizeof tb) tbp = tb; 682 else tbp = malloc (size); 683 684 if (tbp != NULL) { 685 while (parseline(fp, im, tbp) >= 0) {} 686 if (tbp != tb) free (tbp); 687 } 688 } 689} 690