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