1/************************************************ 2 3 tkutil.c - 4 5 $Author: nagachika $ 6 created at: Fri Nov 3 00:47:54 JST 1995 7 8************************************************/ 9 10#define TKUTIL_RELEASE_DATE "2010-03-26" 11 12#include "ruby.h" 13 14#ifdef RUBY_VM 15static int rb_thread_critical; /* dummy */ 16#else 17/* On Ruby 1.8.x, use rb_thread_critical (defined at rubysig.h) */ 18#include "rubysig.h" 19#endif 20#ifdef HAVE_RUBY_ST_H 21#include "ruby/st.h" 22#else 23#include "st.h" 24#endif 25 26#if !defined(RHASH_TBL) 27#define RHASH_TBL(h) (RHASH(h)->tbl) 28#endif 29#if !defined(RSTRING_PTR) 30#define RSTRING_PTR(s) (RSTRING(s)->ptr) 31#define RSTRING_LEN(s) (RSTRING(s)->len) 32#endif 33#if !defined(RARRAY_PTR) 34#define RARRAY_PTR(s) (RARRAY(s)->ptr) 35#define RARRAY_LEN(s) (RARRAY(s)->len) 36#endif 37 38#if defined(HAVE_STRNDUP) && !defined(_GNU_SOURCE) 39extern char *strndup(const char* _ptr, size_t _len); 40#endif 41 42static VALUE cMethod; 43 44static VALUE cTclTkLib; 45 46static VALUE cTkObject; 47static VALUE cTkCallbackEntry; 48 49static VALUE TK_None; 50 51static VALUE cCB_SUBST; 52static VALUE cSUBST_INFO; 53 54static VALUE ENCODING_NAME_UTF8; /* for saving GC cost */ 55 56static ID ID_split_tklist; 57static ID ID_toUTF8; 58static ID ID_fromUTF8; 59static ID ID_path; 60static ID ID_at_path; 61static ID ID_at_enc; 62static ID ID_to_eval; 63static ID ID_to_s; 64static ID ID_source; 65static ID ID_downcase; 66static ID ID_install_cmd; 67static ID ID_merge_tklist; 68static ID ID_encoding; 69static ID ID_encoding_system; 70static ID ID_call; 71 72static ID ID_SUBST_INFO; 73 74static VALUE CALLBACK_TABLE; 75static unsigned long CALLBACK_ID_NUM = 0; 76 77/*************************************/ 78 79#if defined(HAVE_RB_OBJ_INSTANCE_EXEC) && !defined(RUBY_VM) 80extern VALUE rb_obj_instance_exec _((int, VALUE*, VALUE)); 81#endif 82static VALUE 83tk_s_new(argc, argv, klass) 84 int argc; 85 VALUE *argv; 86 VALUE klass; 87{ 88 VALUE obj = rb_class_new_instance(argc, argv, klass); 89 90 if (rb_block_given_p()) { 91#ifndef HAVE_RB_OBJ_INSTANCE_EXEC 92 rb_obj_instance_eval(0, 0, obj); 93#else 94 rb_obj_instance_exec(1, &obj, obj); 95#endif 96 } 97 return obj; 98} 99 100/*************************************/ 101 102static VALUE 103tkNone_to_s(self) 104 VALUE self; 105{ 106 return rb_str_new2(""); 107} 108 109static VALUE 110tkNone_inspect(self) 111 VALUE self; 112{ 113 return rb_str_new2("None"); 114} 115 116/*************************************/ 117 118static VALUE 119tk_obj_untrust(self, obj) 120 VALUE self; 121 VALUE obj; 122{ 123#ifdef HAVE_RB_OBJ_TAINT 124 rb_obj_taint(obj); 125#endif 126#ifdef HAVE_RB_OBJ_UNTRUST 127 rb_obj_untrust(obj); 128#endif 129 130 return obj; 131} 132 133static VALUE 134tk_eval_cmd(argc, argv, self) 135 int argc; 136 VALUE argv[]; 137 VALUE self; 138{ 139 volatile VALUE cmd, rest; 140 141 rb_scan_args(argc, argv, "1*", &cmd, &rest); 142 return rb_eval_cmd(cmd, rest, 0); 143} 144 145static VALUE 146tk_do_callback(argc, argv, self) 147 int argc; 148 VALUE *argv; 149 VALUE self; 150{ 151#if 0 152 volatile VALUE id; 153 volatile VALUE rest; 154 155 rb_scan_args(argc, argv, "1*", &id, &rest); 156 return rb_apply(rb_hash_aref(CALLBACK_TABLE, id), ID_call, rest); 157#endif 158 return rb_funcall2(rb_hash_aref(CALLBACK_TABLE, argv[0]), 159 ID_call, argc - 1, argv + 1); 160} 161 162static const char cmd_id_head[] = "ruby_cmd TkUtil callback "; 163static const char cmd_id_prefix[] = "cmd"; 164 165static VALUE 166tk_install_cmd_core(cmd) 167 VALUE cmd; 168{ 169 volatile VALUE id_num; 170 171 id_num = ULONG2NUM(CALLBACK_ID_NUM++); 172 id_num = rb_funcall(id_num, ID_to_s, 0, 0); 173 id_num = rb_str_append(rb_str_new2(cmd_id_prefix), id_num); 174 rb_hash_aset(CALLBACK_TABLE, id_num, cmd); 175 return rb_str_append(rb_str_new2(cmd_id_head), id_num); 176} 177 178static VALUE 179tk_install_cmd(argc, argv, self) 180 int argc; 181 VALUE *argv; 182 VALUE self; 183{ 184 volatile VALUE cmd; 185 186#if 0 187 if (rb_scan_args(argc, argv, "01", &cmd) == 0) { 188 cmd = rb_block_proc(); 189 } 190 return tk_install_cmd_core(cmd); 191#endif 192 if (argc == 0) { 193 cmd = rb_block_proc(); 194 } else { 195 cmd = argv[0]; 196 } 197 return tk_install_cmd_core(cmd); 198} 199 200static VALUE 201tk_uninstall_cmd(self, cmd_id) 202 VALUE self; 203 VALUE cmd_id; 204{ 205 size_t head_len = strlen(cmd_id_head); 206 size_t prefix_len = strlen(cmd_id_prefix); 207 208 StringValue(cmd_id); 209 if (strncmp(cmd_id_head, RSTRING_PTR(cmd_id), head_len) != 0) { 210 return Qnil; 211 } 212 if (strncmp(cmd_id_prefix, 213 RSTRING_PTR(cmd_id) + head_len, prefix_len) != 0) { 214 return Qnil; 215 } 216 217 return rb_hash_delete(CALLBACK_TABLE, 218 rb_str_new2(RSTRING_PTR(cmd_id) + head_len)); 219} 220 221static VALUE 222tk_toUTF8(argc, argv, self) 223 int argc; 224 VALUE *argv; 225 VALUE self; 226{ 227 return rb_funcall2(cTclTkLib, ID_toUTF8, argc, argv); 228} 229 230static VALUE 231tk_fromUTF8(argc, argv, self) 232 int argc; 233 VALUE *argv; 234 VALUE self; 235{ 236 return rb_funcall2(cTclTkLib, ID_fromUTF8, argc, argv); 237} 238 239static VALUE 240fromDefaultEnc_toUTF8(str, self) 241 VALUE str; 242 VALUE self; 243{ 244 VALUE argv[1]; 245 246 argv[0] = str; 247 return tk_toUTF8(1, argv, self); 248} 249 250#if 0 251static VALUE 252fromUTF8_toDefaultEnc(str, self) 253 VALUE str; 254 VALUE self; 255{ 256 VALUE argv[1]; 257 258 argv[0] = str; 259 return tk_fromUTF8(1, argv, self); 260} 261#endif 262 263static int 264to_strkey(key, value, hash) 265 VALUE key; 266 VALUE value; 267 VALUE hash; 268{ 269 rb_hash_aset(hash, rb_funcall(key, ID_to_s, 0, 0), value); 270 return ST_CHECK; 271} 272 273static VALUE 274tk_symbolkey2str(self, keys) 275 VALUE self; 276 VALUE keys; 277{ 278 volatile VALUE new_keys = rb_hash_new(); 279 280 if (NIL_P(keys)) return new_keys; 281 keys = rb_convert_type(keys, T_HASH, "Hash", "to_hash"); 282 st_foreach_check(RHASH_TBL(keys), to_strkey, new_keys, Qundef); 283 return new_keys; 284} 285 286static VALUE get_eval_string_core _((VALUE, VALUE, VALUE)); 287static VALUE ary2list _((VALUE, VALUE, VALUE)); 288static VALUE ary2list2 _((VALUE, VALUE, VALUE)); 289static VALUE hash2list _((VALUE, VALUE)); 290static VALUE hash2list_enc _((VALUE, VALUE)); 291static VALUE hash2kv _((VALUE, VALUE, VALUE)); 292static VALUE hash2kv_enc _((VALUE, VALUE, VALUE)); 293 294static VALUE 295ary2list(ary, enc_flag, self) 296 VALUE ary; 297 VALUE enc_flag; 298 VALUE self; 299{ 300 long idx, idx2, size, size2; 301 int req_chk_flag; 302 volatile VALUE val, val2, str_val; 303 volatile VALUE dst; 304 volatile VALUE sys_enc, dst_enc, str_enc; 305 306 sys_enc = rb_funcall(cTclTkLib, ID_encoding, 0, 0); 307 if (NIL_P(sys_enc)) { 308 sys_enc = rb_funcall(cTclTkLib, ID_encoding_system, 0, 0); 309 sys_enc = rb_funcall(sys_enc, ID_to_s, 0, 0); 310 } 311 312 if (NIL_P(enc_flag)) { 313 dst_enc = sys_enc; 314 req_chk_flag = 1; 315 } else if (TYPE(enc_flag) == T_TRUE || TYPE(enc_flag) == T_FALSE) { 316 dst_enc = enc_flag; 317 req_chk_flag = 0; 318 } else { 319 dst_enc = rb_funcall(enc_flag, ID_to_s, 0, 0); 320 req_chk_flag = 0; 321 } 322 323 /* size = RARRAY_LEN(ary); */ 324 size = 0; 325 for(idx = 0; idx < RARRAY_LEN(ary); idx++) { 326 if (TYPE(RARRAY_PTR(ary)[idx]) == T_HASH) { 327 size += 2 * RHASH_SIZE(RARRAY_PTR(ary)[idx]); 328 } else { 329 size++; 330 } 331 } 332 333 dst = rb_ary_new2(size); 334 for(idx = 0; idx < RARRAY_LEN(ary); idx++) { 335 val = RARRAY_PTR(ary)[idx]; 336 str_val = Qnil; 337 switch(TYPE(val)) { 338 case T_ARRAY: 339 str_val = ary2list(val, enc_flag, self); 340 rb_ary_push(dst, str_val); 341 342 if (req_chk_flag) { 343 str_enc = rb_ivar_get(str_val, ID_at_enc); 344 if (!NIL_P(str_enc)) { 345 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 346 } else { 347 str_enc = sys_enc; 348 } 349 if (!rb_str_cmp(str_enc, dst_enc)) { 350 dst_enc = Qtrue; 351 req_chk_flag = 0; 352 } 353 } 354 355 break; 356 357 case T_HASH: 358 /* rb_ary_push(dst, hash2list(val, self)); */ 359 if (RTEST(enc_flag)) { 360 val = hash2kv_enc(val, Qnil, self); 361 } else { 362 val = hash2kv(val, Qnil, self); 363 } 364 size2 = RARRAY_LEN(val); 365 for(idx2 = 0; idx2 < size2; idx2++) { 366 val2 = RARRAY_PTR(val)[idx2]; 367 switch(TYPE(val2)) { 368 case T_ARRAY: 369 str_val = ary2list(val2, enc_flag, self); 370 rb_ary_push(dst, str_val); 371 break; 372 373 case T_HASH: 374 if (RTEST(enc_flag)) { 375 str_val = hash2list_enc(val2, self); 376 } else { 377 str_val = hash2list(val2, self); 378 } 379 rb_ary_push(dst, str_val); 380 break; 381 382 default: 383 if (val2 != TK_None) { 384 str_val = get_eval_string_core(val2, enc_flag, self); 385 rb_ary_push(dst, str_val); 386 } 387 } 388 389 if (req_chk_flag) { 390 str_enc = rb_ivar_get(str_val, ID_at_enc); 391 if (!NIL_P(str_enc)) { 392 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 393 } else { 394 str_enc = sys_enc; 395 } 396 if (!rb_str_cmp(str_enc, dst_enc)) { 397 dst_enc = Qtrue; 398 req_chk_flag = 0; 399 } 400 } 401 } 402 break; 403 404 default: 405 if (val != TK_None) { 406 str_val = get_eval_string_core(val, enc_flag, self); 407 rb_ary_push(dst, str_val); 408 409 if (req_chk_flag) { 410 str_enc = rb_ivar_get(str_val, ID_at_enc); 411 if (!NIL_P(str_enc)) { 412 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 413 } else { 414 str_enc = sys_enc; 415 } 416 if (!rb_str_cmp(str_enc, dst_enc)) { 417 dst_enc = Qtrue; 418 req_chk_flag = 0; 419 } 420 } 421 } 422 } 423 } 424 425 if (RTEST(dst_enc) && !NIL_P(sys_enc)) { 426 for(idx = 0; idx < RARRAY_LEN(dst); idx++) { 427 str_val = RARRAY_PTR(dst)[idx]; 428 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 429 str_val = rb_funcall(self, ID_toUTF8, 1, str_val); 430 } else { 431 str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val); 432 } 433 RARRAY_PTR(dst)[idx] = str_val; 434 } 435 val = rb_apply(cTclTkLib, ID_merge_tklist, dst); 436 if (TYPE(dst_enc) == T_STRING) { 437 val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); 438 rb_ivar_set(val, ID_at_enc, dst_enc); 439 } else { 440 rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); 441 } 442 return val; 443 } else { 444 return rb_apply(cTclTkLib, ID_merge_tklist, dst); 445 } 446} 447 448static VALUE 449ary2list2(ary, enc_flag, self) 450 VALUE ary; 451 VALUE enc_flag; 452 VALUE self; 453{ 454 long idx, size; 455 int req_chk_flag; 456 volatile VALUE val, str_val; 457 volatile VALUE dst; 458 volatile VALUE sys_enc, dst_enc, str_enc; 459 460 sys_enc = rb_funcall(cTclTkLib, ID_encoding, 0, 0); 461 if (NIL_P(sys_enc)) { 462 sys_enc = rb_funcall(cTclTkLib, ID_encoding_system, 0, 0); 463 sys_enc = rb_funcall(sys_enc, ID_to_s, 0, 0); 464 } 465 466 if (NIL_P(enc_flag)) { 467 dst_enc = sys_enc; 468 req_chk_flag = 1; 469 } else if (TYPE(enc_flag) == T_TRUE || TYPE(enc_flag) == T_FALSE) { 470 dst_enc = enc_flag; 471 req_chk_flag = 0; 472 } else { 473 dst_enc = rb_funcall(enc_flag, ID_to_s, 0, 0); 474 req_chk_flag = 0; 475 } 476 477 size = RARRAY_LEN(ary); 478 dst = rb_ary_new2(size); 479 for(idx = 0; idx < RARRAY_LEN(ary); idx++) { 480 val = RARRAY_PTR(ary)[idx]; 481 str_val = Qnil; 482 switch(TYPE(val)) { 483 case T_ARRAY: 484 str_val = ary2list(val, enc_flag, self); 485 break; 486 487 case T_HASH: 488 if (RTEST(enc_flag)) { 489 str_val = hash2list(val, self); 490 } else { 491 str_val = hash2list_enc(val, self); 492 } 493 break; 494 495 default: 496 if (val != TK_None) { 497 str_val = get_eval_string_core(val, enc_flag, self); 498 } 499 } 500 501 if (!NIL_P(str_val)) { 502 rb_ary_push(dst, str_val); 503 504 if (req_chk_flag) { 505 str_enc = rb_ivar_get(str_val, ID_at_enc); 506 if (!NIL_P(str_enc)) { 507 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 508 } else { 509 str_enc = sys_enc; 510 } 511 if (!rb_str_cmp(str_enc, dst_enc)) { 512 dst_enc = Qtrue; 513 req_chk_flag = 0; 514 } 515 } 516 } 517 } 518 519 if (RTEST(dst_enc) && !NIL_P(sys_enc)) { 520 for(idx = 0; idx < RARRAY_LEN(dst); idx++) { 521 str_val = RARRAY_PTR(dst)[idx]; 522 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 523 str_val = rb_funcall(self, ID_toUTF8, 1, str_val); 524 } else { 525 str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val); 526 } 527 RARRAY_PTR(dst)[idx] = str_val; 528 } 529 val = rb_apply(cTclTkLib, ID_merge_tklist, dst); 530 if (TYPE(dst_enc) == T_STRING) { 531 val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); 532 rb_ivar_set(val, ID_at_enc, dst_enc); 533 } else { 534 rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); 535 } 536 return val; 537 } else { 538 return rb_apply(cTclTkLib, ID_merge_tklist, dst); 539 } 540} 541 542static VALUE 543key2keyname(key) 544 VALUE key; 545{ 546 return rb_str_append(rb_str_new2("-"), rb_funcall(key, ID_to_s, 0, 0)); 547} 548 549static VALUE 550assoc2kv(assoc, ary, self) 551 VALUE assoc; 552 VALUE ary; 553 VALUE self; 554{ 555 long i, j, len; 556 volatile VALUE pair; 557 volatile VALUE val; 558 volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); 559 560 len = RARRAY_LEN(assoc); 561 562 for(i = 0; i < len; i++) { 563 pair = RARRAY_PTR(assoc)[i]; 564 if (TYPE(pair) != T_ARRAY) { 565 rb_ary_push(dst, key2keyname(pair)); 566 continue; 567 } 568 switch(RARRAY_LEN(assoc)) { 569 case 2: 570 rb_ary_push(dst, RARRAY_PTR(pair)[2]); 571 572 case 1: 573 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 574 575 case 0: 576 continue; 577 578 default: 579 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 580 581 val = rb_ary_new2(RARRAY_LEN(pair) - 1); 582 for(j = 1; j < RARRAY_LEN(pair); j++) { 583 rb_ary_push(val, RARRAY_PTR(pair)[j]); 584 } 585 586 rb_ary_push(dst, val); 587 } 588 } 589 590 if (NIL_P(ary)) { 591 return dst; 592 } else { 593 return rb_ary_plus(ary, dst); 594 } 595} 596 597static VALUE 598assoc2kv_enc(assoc, ary, self) 599 VALUE assoc; 600 VALUE ary; 601 VALUE self; 602{ 603 long i, j, len; 604 volatile VALUE pair; 605 volatile VALUE val; 606 volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); 607 608 len = RARRAY_LEN(assoc); 609 610 for(i = 0; i < len; i++) { 611 pair = RARRAY_PTR(assoc)[i]; 612 if (TYPE(pair) != T_ARRAY) { 613 rb_ary_push(dst, key2keyname(pair)); 614 continue; 615 } 616 switch(RARRAY_LEN(assoc)) { 617 case 2: 618 rb_ary_push(dst, get_eval_string_core(RARRAY_PTR(pair)[2], Qtrue, self)); 619 620 case 1: 621 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 622 623 case 0: 624 continue; 625 626 default: 627 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 628 629 val = rb_ary_new2(RARRAY_LEN(pair) - 1); 630 for(j = 1; j < RARRAY_LEN(pair); j++) { 631 rb_ary_push(val, RARRAY_PTR(pair)[j]); 632 } 633 634 rb_ary_push(dst, get_eval_string_core(val, Qtrue, self)); 635 } 636 } 637 638 if (NIL_P(ary)) { 639 return dst; 640 } else { 641 return rb_ary_plus(ary, dst); 642 } 643} 644 645static int 646push_kv(key, val, args) 647 VALUE key; 648 VALUE val; 649 VALUE args; 650{ 651 volatile VALUE ary; 652 653 ary = RARRAY_PTR(args)[0]; 654 655#if 0 656 rb_ary_push(ary, key2keyname(key)); 657 if (val != TK_None) rb_ary_push(ary, val); 658#endif 659 rb_ary_push(ary, key2keyname(key)); 660 661 if (val == TK_None) return ST_CHECK; 662 663 rb_ary_push(ary, get_eval_string_core(val, Qnil, RARRAY_PTR(args)[1])); 664 665 return ST_CHECK; 666} 667 668static VALUE 669hash2kv(hash, ary, self) 670 VALUE hash; 671 VALUE ary; 672 VALUE self; 673{ 674 volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash)); 675 volatile VALUE args = rb_ary_new3(2, dst, self); 676 677 st_foreach_check(RHASH_TBL(hash), push_kv, args, Qundef); 678 679 if (NIL_P(ary)) { 680 return dst; 681 } else { 682 return rb_ary_concat(ary, dst); 683 } 684} 685 686static int 687push_kv_enc(key, val, args) 688 VALUE key; 689 VALUE val; 690 VALUE args; 691{ 692 volatile VALUE ary; 693 694 ary = RARRAY_PTR(args)[0]; 695 696#if 0 697 rb_ary_push(ary, key2keyname(key)); 698 if (val != TK_None) { 699 rb_ary_push(ary, get_eval_string_core(val, Qtrue, 700 RARRAY_PTR(args)[1])); 701 } 702#endif 703 rb_ary_push(ary, key2keyname(key)); 704 705 if (val == TK_None) return ST_CHECK; 706 707 rb_ary_push(ary, get_eval_string_core(val, Qtrue, RARRAY_PTR(args)[1])); 708 709 return ST_CHECK; 710} 711 712static VALUE 713hash2kv_enc(hash, ary, self) 714 VALUE hash; 715 VALUE ary; 716 VALUE self; 717{ 718 volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash)); 719 volatile VALUE args = rb_ary_new3(2, dst, self); 720 721 st_foreach_check(RHASH_TBL(hash), push_kv_enc, args, Qundef); 722 723 if (NIL_P(ary)) { 724 return dst; 725 } else { 726 return rb_ary_concat(ary, dst); 727 } 728} 729 730static VALUE 731hash2list(hash, self) 732 VALUE hash; 733 VALUE self; 734{ 735 return ary2list2(hash2kv(hash, Qnil, self), Qfalse, self); 736} 737 738 739static VALUE 740hash2list_enc(hash, self) 741 VALUE hash; 742 VALUE self; 743{ 744 return ary2list2(hash2kv_enc(hash, Qnil, self), Qfalse, self); 745} 746 747static VALUE 748tk_hash_kv(argc, argv, self) 749 int argc; 750 VALUE *argv; 751 VALUE self; 752{ 753 volatile VALUE hash, enc_flag, ary; 754 755 ary = Qnil; 756 enc_flag = Qnil; 757 switch(argc) { 758 case 3: 759 ary = argv[2]; 760 case 2: 761 enc_flag = argv[1]; 762 case 1: 763 hash = argv[0]; 764 break; 765 case 0: 766 rb_raise(rb_eArgError, "too few arguments"); 767 default: /* >= 3 */ 768 rb_raise(rb_eArgError, "too many arguments"); 769 } 770 771 switch(TYPE(hash)) { 772 case T_ARRAY: 773 if (RTEST(enc_flag)) { 774 return assoc2kv_enc(hash, ary, self); 775 } else { 776 return assoc2kv(hash, ary, self); 777 } 778 779 case T_HASH: 780 if (RTEST(enc_flag)) { 781 return hash2kv_enc(hash, ary, self); 782 } else { 783 return hash2kv(hash, ary, self); 784 } 785 786 case T_NIL: 787 if (NIL_P(ary)) { 788 return rb_ary_new(); 789 } else { 790 return ary; 791 } 792 793 default: 794 if (hash == TK_None) { 795 if (NIL_P(ary)) { 796 return rb_ary_new(); 797 } else { 798 return ary; 799 } 800 } 801 rb_raise(rb_eArgError, "Hash is expected for 1st argument"); 802 } 803 804 UNREACHABLE; 805} 806 807static VALUE 808get_eval_string_core(obj, enc_flag, self) 809 VALUE obj; 810 VALUE enc_flag; 811 VALUE self; 812{ 813 switch(TYPE(obj)) { 814 case T_FLOAT: 815 case T_FIXNUM: 816 case T_BIGNUM: 817 return rb_funcall(obj, ID_to_s, 0, 0); 818 819 case T_STRING: 820 if (RTEST(enc_flag)) { 821 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 822 return rb_funcall(self, ID_toUTF8, 1, obj); 823 } else { 824 return fromDefaultEnc_toUTF8(obj, self); 825 } 826 } else { 827 return obj; 828 } 829 830 case T_SYMBOL: 831 if (RTEST(enc_flag)) { 832 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 833 return rb_funcall(self, ID_toUTF8, 1, 834 rb_str_new2(rb_id2name(SYM2ID(obj)))); 835 } else { 836 return fromDefaultEnc_toUTF8(rb_str_new2(rb_id2name(SYM2ID(obj))), self); 837 } 838 } else { 839#ifdef HAVE_RB_SYM_TO_S 840 return rb_sym_to_s(obj); 841#else 842 return rb_str_new2(rb_id2name(SYM2ID(obj))); 843#endif 844 } 845 846 case T_HASH: 847 if (RTEST(enc_flag)) { 848 return hash2list_enc(obj, self); 849 } else { 850 return hash2list(obj, self); 851 } 852 853 case T_ARRAY: 854 return ary2list(obj, enc_flag, self); 855 856 case T_FALSE: 857 return rb_str_new2("0"); 858 859 case T_TRUE: 860 return rb_str_new2("1"); 861 862 case T_NIL: 863 return rb_str_new2(""); 864 865 case T_REGEXP: 866 return rb_funcall(obj, ID_source, 0, 0); 867 868 default: 869 if (rb_obj_is_kind_of(obj, cTkObject)) { 870 /* return rb_str_new3(rb_funcall(obj, ID_path, 0, 0)); */ 871 return get_eval_string_core(rb_funcall(obj, ID_path, 0, 0), 872 enc_flag, self); 873 } 874 875 if (rb_obj_is_kind_of(obj, rb_cProc) 876 || rb_obj_is_kind_of(obj, cMethod) 877 || rb_obj_is_kind_of(obj, cTkCallbackEntry)) { 878 if (rb_obj_respond_to(self, ID_install_cmd, Qtrue)) { 879 return rb_funcall(self, ID_install_cmd, 1, obj); 880 } else { 881 return tk_install_cmd_core(obj); 882 } 883 } 884 885 if (obj == TK_None) return Qnil; 886 887 if (rb_obj_respond_to(obj, ID_to_eval, Qtrue)) { 888 /* return rb_funcall(obj, ID_to_eval, 0, 0); */ 889 return get_eval_string_core(rb_funcall(obj, ID_to_eval, 0, 0), 890 enc_flag, self); 891 } else if (rb_obj_respond_to(obj, ID_path, Qtrue)) { 892 /* return rb_funcall(obj, ID_path, 0, 0); */ 893 return get_eval_string_core(rb_funcall(obj, ID_path, 0, 0), 894 enc_flag, self); 895 } else if (rb_obj_respond_to(obj, ID_to_s, Qtrue)) { 896 return rb_funcall(obj, ID_to_s, 0, 0); 897 } 898 } 899 900 rb_warning("fail to convert '%+"PRIsVALUE"' to string for Tk", obj); 901 902 return obj; 903} 904 905static VALUE 906tk_get_eval_string(argc, argv, self) 907 int argc; 908 VALUE *argv; 909 VALUE self; 910{ 911 volatile VALUE obj, enc_flag; 912 913 if (rb_scan_args(argc, argv, "11", &obj, &enc_flag) == 1) { 914 enc_flag = Qnil; 915 } 916 917 return get_eval_string_core(obj, enc_flag, self); 918} 919 920static VALUE 921tk_get_eval_enc_str(self, obj) 922 VALUE self; 923 VALUE obj; 924{ 925 if (obj == TK_None) { 926 return obj; 927 } else { 928 return get_eval_string_core(obj, Qtrue, self); 929 } 930} 931 932static VALUE 933tk_conv_args(argc, argv, self) 934 int argc; 935 VALUE *argv; /* [0]:base_array, [1]:enc_mode, [2]..[n]:args */ 936 VALUE self; 937{ 938 int idx, size; 939 volatile VALUE dst; 940 int thr_crit_bup; 941 VALUE old_gc; 942 943 if (argc < 2) { 944 rb_raise(rb_eArgError, "too few arguments"); 945 } 946 947 thr_crit_bup = rb_thread_critical; 948 rb_thread_critical = Qtrue; 949 old_gc = rb_gc_disable(); 950 951 for(size = 0, idx = 2; idx < argc; idx++) { 952 if (TYPE(argv[idx]) == T_HASH) { 953 size += 2 * RHASH_SIZE(argv[idx]); 954 } else { 955 size++; 956 } 957 } 958 /* dst = rb_ary_new2(argc - 2); */ 959 dst = rb_ary_new2(size); 960 for(idx = 2; idx < argc; idx++) { 961 if (TYPE(argv[idx]) == T_HASH) { 962 if (RTEST(argv[1])) { 963 hash2kv_enc(argv[idx], dst, self); 964 } else { 965 hash2kv(argv[idx], dst, self); 966 } 967 } else if (argv[idx] != TK_None) { 968 rb_ary_push(dst, get_eval_string_core(argv[idx], argv[1], self)); 969 } 970 } 971 972 if (old_gc == Qfalse) rb_gc_enable(); 973 rb_thread_critical = thr_crit_bup; 974 975 return rb_ary_plus(argv[0], dst); 976} 977 978 979/*************************************/ 980 981static VALUE 982tcl2rb_bool(self, value) 983 VALUE self; 984 VALUE value; 985{ 986 if (TYPE(value) == T_FIXNUM) { 987 if (NUM2INT(value) == 0) { 988 return Qfalse; 989 } else { 990 return Qtrue; 991 } 992 } 993 994 if (TYPE(value) == T_TRUE || TYPE(value) == T_FALSE) { 995 return value; 996 } 997 998 rb_check_type(value, T_STRING); 999 1000 value = rb_funcall(value, ID_downcase, 0); 1001 1002 if (RSTRING_PTR(value) == (char*)NULL) return Qnil; 1003 1004 if (RSTRING_PTR(value)[0] == '\0' 1005 || strcmp(RSTRING_PTR(value), "0") == 0 1006 || strcmp(RSTRING_PTR(value), "no") == 0 1007 || strcmp(RSTRING_PTR(value), "off") == 0 1008 || strcmp(RSTRING_PTR(value), "false") == 0) { 1009 return Qfalse; 1010 } else { 1011 return Qtrue; 1012 } 1013} 1014 1015#if 0 1016static VALUE 1017tkstr_to_dec(value) 1018 VALUE value; 1019{ 1020 return rb_cstr_to_inum(RSTRING_PTR(value), 10, 1); 1021} 1022#endif 1023 1024static VALUE 1025tkstr_to_int(value) 1026 VALUE value; 1027{ 1028 return rb_cstr_to_inum(RSTRING_PTR(value), 0, 1); 1029} 1030 1031static VALUE 1032tkstr_to_float(value) 1033 VALUE value; 1034{ 1035 return rb_float_new(rb_cstr_to_dbl(RSTRING_PTR(value), 1)); 1036} 1037 1038static VALUE 1039tkstr_invalid_numstr(value) 1040 VALUE value; 1041{ 1042 rb_raise(rb_eArgError, 1043 "invalid value for Number: '%s'", RSTRING_PTR(value)); 1044 return Qnil; /*dummy*/ 1045} 1046 1047static VALUE 1048tkstr_rescue_float(value) 1049 VALUE value; 1050{ 1051 return rb_rescue2(tkstr_to_float, value, 1052 tkstr_invalid_numstr, value, 1053 rb_eArgError, 0); 1054} 1055 1056static VALUE 1057tkstr_to_number(value) 1058 VALUE value; 1059{ 1060 rb_check_type(value, T_STRING); 1061 1062 if (RSTRING_PTR(value) == (char*)NULL) return INT2FIX(0); 1063 1064 return rb_rescue2(tkstr_to_int, value, 1065 tkstr_rescue_float, value, 1066 rb_eArgError, 0); 1067} 1068 1069static VALUE 1070tcl2rb_number(self, value) 1071 VALUE self; 1072 VALUE value; 1073{ 1074 return tkstr_to_number(value); 1075} 1076 1077static VALUE 1078tkstr_to_str(value) 1079 VALUE value; 1080{ 1081 char * ptr; 1082 long len; 1083 1084 ptr = RSTRING_PTR(value); 1085 len = RSTRING_LEN(value); 1086 1087 if (len > 1 && *ptr == '{' && *(ptr + len - 1) == '}') { 1088 return rb_str_new(ptr + 1, len - 2); 1089 } 1090 return value; 1091} 1092 1093static VALUE 1094tcl2rb_string(self, value) 1095 VALUE self; 1096 VALUE value; 1097{ 1098 rb_check_type(value, T_STRING); 1099 1100 if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2(""); 1101 1102 return tkstr_to_str(value); 1103} 1104 1105static VALUE 1106tcl2rb_num_or_str(self, value) 1107 VALUE self; 1108 VALUE value; 1109{ 1110 rb_check_type(value, T_STRING); 1111 1112 if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2(""); 1113 1114 return rb_rescue2(tkstr_to_number, value, 1115 tkstr_to_str, value, 1116 rb_eArgError, 0); 1117} 1118 1119static VALUE 1120tcl2rb_num_or_nil(self, value) 1121 VALUE self; 1122 VALUE value; 1123{ 1124 rb_check_type(value, T_STRING); 1125 1126 if (RSTRING_LEN(value) == 0) return Qnil; 1127 1128 return tkstr_to_number(value); 1129} 1130 1131 1132/*************************************/ 1133 1134#define CBSUBST_TBL_MAX (256) 1135struct cbsubst_info { 1136 long full_subst_length; 1137 long keylen[CBSUBST_TBL_MAX]; 1138 char *key[CBSUBST_TBL_MAX]; 1139 char type[CBSUBST_TBL_MAX]; 1140 ID ivar[CBSUBST_TBL_MAX]; 1141 VALUE proc; 1142 VALUE aliases; 1143}; 1144 1145static void 1146subst_mark(ptr) 1147 struct cbsubst_info *ptr; 1148{ 1149 rb_gc_mark(ptr->proc); 1150 rb_gc_mark(ptr->aliases); 1151} 1152 1153static void 1154subst_free(ptr) 1155 struct cbsubst_info *ptr; 1156{ 1157 int i; 1158 1159 if (ptr) { 1160 for(i = 0; i < CBSUBST_TBL_MAX; i++) { 1161 if (ptr->key[i] != NULL) { 1162 free(ptr->key[i]); /* allocated by malloc */ 1163 ptr->key[i] = NULL; 1164 } 1165 } 1166 xfree(ptr); /* allocated by ALLOC */ 1167 } 1168} 1169 1170static VALUE 1171allocate_cbsubst_info(struct cbsubst_info **inf_ptr) 1172{ 1173 struct cbsubst_info *inf; 1174 volatile VALUE proc, aliases; 1175 int idx; 1176 1177 inf = ALLOC(struct cbsubst_info); 1178 1179 inf->full_subst_length = 0; 1180 1181 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 1182 inf->keylen[idx] = 0; 1183 inf->key[idx] = NULL; 1184 inf->type[idx] = '\0'; 1185 inf->ivar[idx] = (ID) 0; 1186 } 1187 1188 proc = rb_hash_new(); 1189 inf->proc = proc; 1190 1191 aliases = rb_hash_new(); 1192 inf->aliases = aliases; 1193 1194 if (inf_ptr != (struct cbsubst_info **)NULL) *inf_ptr = inf; 1195 1196 return Data_Wrap_Struct(cSUBST_INFO, subst_mark, subst_free, inf); 1197} 1198 1199static void 1200cbsubst_init() 1201{ 1202 rb_const_set(cCB_SUBST, ID_SUBST_INFO, 1203 allocate_cbsubst_info((struct cbsubst_info **)NULL)); 1204} 1205 1206static VALUE 1207cbsubst_initialize(argc, argv, self) 1208 int argc; 1209 VALUE *argv; 1210 VALUE self; 1211{ 1212 struct cbsubst_info *inf; 1213 int idx, iv_idx; 1214 1215 Data_Get_Struct(rb_const_get(rb_obj_class(self), ID_SUBST_INFO), 1216 struct cbsubst_info, inf); 1217 1218 idx = 0; 1219 for(iv_idx = 0; iv_idx < CBSUBST_TBL_MAX; iv_idx++) { 1220 if ( inf->ivar[iv_idx] == (ID) 0 ) continue; 1221 rb_ivar_set(self, inf->ivar[iv_idx], argv[idx++]); 1222 if (idx >= argc) break; 1223 } 1224 1225 return self; 1226} 1227 1228static VALUE 1229cbsubst_ret_val(self, val) 1230 VALUE self; 1231 VALUE val; 1232{ 1233 /* This method may be overwritten on some sub-classes. */ 1234 /* This method is used for converting from ruby's callback-return-value */ 1235 /* to tcl's value (e.g. validation procedure of entry widget). */ 1236 return val; 1237} 1238 1239static int 1240each_attr_def(key, value, klass) 1241 VALUE key, value, klass; 1242{ 1243 ID key_id, value_id; 1244 1245 if (key == Qundef) return ST_CONTINUE; 1246 1247 switch(TYPE(key)) { 1248 case T_STRING: 1249 key_id = rb_intern_str(key); 1250 break; 1251 case T_SYMBOL: 1252 key_id = SYM2ID(key); 1253 break; 1254 default: 1255 rb_raise(rb_eArgError, 1256 "includes invalid key(s). expected a String or a Symbol"); 1257 } 1258 1259 switch(TYPE(value)) { 1260 case T_STRING: 1261 value_id = rb_intern_str(value); 1262 break; 1263 case T_SYMBOL: 1264 value_id = SYM2ID(value); 1265 break; 1266 default: 1267 rb_raise(rb_eArgError, 1268 "includes invalid value(s). expected a String or a Symbol"); 1269 } 1270 1271 rb_alias(klass, key_id, value_id); 1272 1273 return ST_CONTINUE; 1274} 1275 1276static VALUE 1277cbsubst_def_attr_aliases(self, tbl) 1278 VALUE self; 1279 VALUE tbl; 1280{ 1281 struct cbsubst_info *inf; 1282 1283 if (TYPE(tbl) != T_HASH) { 1284 rb_raise(rb_eArgError, "expected a Hash"); 1285 } 1286 1287 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 1288 struct cbsubst_info, inf); 1289 1290 rb_hash_foreach(tbl, each_attr_def, self); 1291 1292 return rb_funcall(inf->aliases, rb_intern("update"), 1, tbl); 1293} 1294 1295static VALUE 1296cbsubst_sym_to_subst(self, sym) 1297 VALUE self; 1298 VALUE sym; 1299{ 1300 struct cbsubst_info *inf; 1301 VALUE str; 1302 char *buf, *ptr; 1303 int idx; 1304 long len; 1305 ID id; 1306 volatile VALUE ret; 1307 1308 if (TYPE(sym) != T_SYMBOL) return sym; 1309 1310 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 1311 struct cbsubst_info, inf); 1312 1313 if (!NIL_P(ret = rb_hash_aref(inf->aliases, sym))) { 1314 str = rb_id2str(SYM2ID(ret)); 1315 } else { 1316 str = rb_id2str(SYM2ID(sym)); 1317 } 1318 1319 id = rb_intern_str(rb_sprintf("@%"PRIsVALUE, str)); 1320 1321 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 1322 if (inf->ivar[idx] == id) break; 1323 } 1324 if (idx >= CBSUBST_TBL_MAX) return sym; 1325 1326 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 1327 1328 *(ptr++) = '%'; 1329 1330 if (len = inf->keylen[idx]) { 1331 /* longname */ 1332 strncpy(ptr, inf->key[idx], len); 1333 ptr += len; 1334 } else { 1335 /* single char */ 1336 *(ptr++) = (unsigned char)idx; 1337 } 1338 1339 *(ptr++) = ' '; 1340 *(ptr++) = '\0'; 1341 1342 ret = rb_str_new2(buf); 1343 1344 xfree(buf); 1345 1346 return ret; 1347} 1348 1349static VALUE 1350cbsubst_get_subst_arg(argc, argv, self) 1351 int argc; 1352 VALUE *argv; 1353 VALUE self; 1354{ 1355 struct cbsubst_info *inf; 1356 VALUE str; 1357 char *buf, *ptr; 1358 int i, idx; 1359 long len; 1360 ID id; 1361 volatile VALUE arg_sym, ret; 1362 1363 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 1364 struct cbsubst_info, inf); 1365 1366 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 1367 1368 for(i = 0; i < argc; i++) { 1369 switch(TYPE(argv[i])) { 1370 case T_STRING: 1371 str = argv[i]; 1372 arg_sym = ID2SYM(rb_intern_str(argv[i])); 1373 break; 1374 case T_SYMBOL: 1375 arg_sym = argv[i]; 1376 str = rb_id2str(SYM2ID(arg_sym)); 1377 break; 1378 default: 1379 rb_raise(rb_eArgError, "arg #%d is not a String or a Symbol", i); 1380 } 1381 1382 if (!NIL_P(ret = rb_hash_aref(inf->aliases, arg_sym))) { 1383 str = rb_id2str(SYM2ID(ret)); 1384 } 1385 1386 id = rb_intern_str(rb_sprintf("@%"PRIsVALUE, str)); 1387 1388 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 1389 if (inf->ivar[idx] == id) break; 1390 } 1391 if (idx >= CBSUBST_TBL_MAX) { 1392 rb_raise(rb_eArgError, "cannot find attribute :%"PRIsVALUE, str); 1393 } 1394 1395 *(ptr++) = '%'; 1396 1397 if (len = inf->keylen[idx]) { 1398 /* longname */ 1399 strncpy(ptr, inf->key[idx], len); 1400 ptr += len; 1401 } else { 1402 /* single char */ 1403 *(ptr++) = (unsigned char)idx; 1404 } 1405 1406 *(ptr++) = ' '; 1407 } 1408 1409 *ptr = '\0'; 1410 1411 ret = rb_str_new2(buf); 1412 1413 xfree(buf); 1414 1415 return ret; 1416} 1417 1418static VALUE 1419cbsubst_get_subst_key(self, str) 1420 VALUE self; 1421 VALUE str; 1422{ 1423 struct cbsubst_info *inf; 1424 volatile VALUE list; 1425 volatile VALUE ret; 1426 VALUE keyval; 1427 long i, len, keylen; 1428 int idx; 1429 char *buf, *ptr, *key; 1430 1431 list = rb_funcall(cTclTkLib, ID_split_tklist, 1, str); 1432 len = RARRAY_LEN(list); 1433 1434 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 1435 struct cbsubst_info, inf); 1436 1437 ptr = buf = ALLOC_N(char, inf->full_subst_length + len + 1); 1438 1439 for(i = 0; i < len; i++) { 1440 keyval = RARRAY_PTR(list)[i]; 1441 key = RSTRING_PTR(keyval); 1442 if (*key == '%') { 1443 if (*(key + 2) == '\0') { 1444 /* single char */ 1445 *(ptr++) = *(key + 1); 1446 } else { 1447 /* search longname-key */ 1448 keylen = RSTRING_LEN(keyval) - 1; 1449 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 1450 if (inf->keylen[idx] != keylen) continue; 1451 if ((unsigned char)inf->key[idx][0] != (unsigned char)*(key + 1)) continue; 1452 if (strncmp(inf->key[idx], key + 1, keylen)) continue; 1453 break; 1454 } 1455 if (idx < CBSUBST_TBL_MAX) { 1456 *(ptr++) = (unsigned char)idx; 1457 } else { 1458 *(ptr++) = ' '; 1459 } 1460 } 1461 } else { 1462 *(ptr++) = ' '; 1463 } 1464 } 1465 *ptr = '\0'; 1466 1467 ret = rb_str_new2(buf); 1468 xfree(buf); 1469 return ret; 1470} 1471 1472static VALUE 1473cbsubst_get_all_subst_keys(self) 1474 VALUE self; 1475{ 1476 struct cbsubst_info *inf; 1477 char *buf, *ptr; 1478 char *keys_buf, *keys_ptr; 1479 int idx; 1480 long len; 1481 volatile VALUE ret; 1482 1483 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 1484 struct cbsubst_info, inf); 1485 1486 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 1487 keys_ptr = keys_buf = ALLOC_N(char, CBSUBST_TBL_MAX + 1); 1488 1489 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 1490 if (inf->ivar[idx] == (ID) 0) continue; 1491 1492 *(keys_ptr++) = (unsigned char)idx; 1493 1494 *(ptr++) = '%'; 1495 1496 if (len = inf->keylen[idx]) { 1497 /* longname */ 1498 strncpy(ptr, inf->key[idx], len); 1499 ptr += len; 1500 } else { 1501 /* single char */ 1502 *(ptr++) = (unsigned char)idx; 1503 } 1504 1505 *(ptr++) = ' '; 1506 } 1507 1508 *ptr = '\0'; 1509 *keys_ptr = '\0'; 1510 1511 ret = rb_ary_new3(2, rb_str_new2(keys_buf), rb_str_new2(buf)); 1512 1513 xfree(buf); 1514 xfree(keys_buf); 1515 1516 return ret; 1517} 1518 1519static VALUE 1520cbsubst_table_setup(argc, argv, self) 1521 int argc; 1522 VALUE *argv; 1523 VALUE self; 1524{ 1525 volatile VALUE cbsubst_obj; 1526 volatile VALUE key_inf; 1527 volatile VALUE longkey_inf; 1528 volatile VALUE proc_inf; 1529 VALUE inf; 1530 ID id; 1531 struct cbsubst_info *subst_inf; 1532 long idx, len; 1533 unsigned char chr; 1534 1535 /* accept (key_inf, proc_inf) or (key_inf, longkey_inf, procinf) */ 1536 if (rb_scan_args(argc, argv, "21", &key_inf, &longkey_inf, &proc_inf) == 2) { 1537 proc_inf = longkey_inf; 1538 longkey_inf = rb_ary_new(); 1539 } 1540 1541 /* check the number of longkeys */ 1542 if (RARRAY_LEN(longkey_inf) > 125 /* from 0x80 to 0xFD */) { 1543 rb_raise(rb_eArgError, "too many longname-key definitions"); 1544 } 1545 1546 /* init */ 1547 cbsubst_obj = allocate_cbsubst_info(&subst_inf); 1548 1549 /* 1550 * keys : array of [subst, type, ivar] 1551 * subst ==> char code or string 1552 * type ==> char code or string 1553 * ivar ==> symbol 1554 */ 1555 len = RARRAY_LEN(key_inf); 1556 for(idx = 0; idx < len; idx++) { 1557 inf = RARRAY_PTR(key_inf)[idx]; 1558 if (TYPE(inf) != T_ARRAY) continue; 1559 1560 if (TYPE(RARRAY_PTR(inf)[0]) == T_STRING) { 1561 chr = *(RSTRING_PTR(RARRAY_PTR(inf)[0])); 1562 } else { 1563 chr = NUM2CHR(RARRAY_PTR(inf)[0]); 1564 } 1565 if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) { 1566 subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1])); 1567 } else { 1568 subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]); 1569 } 1570 1571 subst_inf->full_subst_length += 3; 1572 1573 id = SYM2ID(RARRAY_PTR(inf)[2]); 1574 subst_inf->ivar[chr] = rb_intern_str(rb_sprintf("@%"PRIsVALUE, rb_id2str(id))); 1575 1576 rb_attr(self, id, 1, 0, Qtrue); 1577 } 1578 1579 1580 /* 1581 * longkeys : array of [name, type, ivar] 1582 * name ==> longname key string 1583 * type ==> char code or string 1584 * ivar ==> symbol 1585 */ 1586 len = RARRAY_LEN(longkey_inf); 1587 for(idx = 0; idx < len; idx++) { 1588 inf = RARRAY_PTR(longkey_inf)[idx]; 1589 if (TYPE(inf) != T_ARRAY) continue; 1590 1591 chr = (unsigned char)(0x80 + idx); 1592 subst_inf->keylen[chr] = RSTRING_LEN(RARRAY_PTR(inf)[0]); 1593#if HAVE_STRNDUP 1594 subst_inf->key[chr] = strndup(RSTRING_PTR(RARRAY_PTR(inf)[0]), 1595 RSTRING_LEN(RARRAY_PTR(inf)[0])); 1596#else 1597 subst_inf->key[chr] = malloc(RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1); 1598 if (subst_inf->key[chr]) { 1599 strncpy(subst_inf->key[chr], RSTRING_PTR(RARRAY_PTR(inf)[0]), 1600 RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1); 1601 subst_inf->key[chr][RSTRING_LEN(RARRAY_PTR(inf)[0])] = '\0'; 1602 } 1603#endif 1604 if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) { 1605 subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1])); 1606 } else { 1607 subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]); 1608 } 1609 1610 subst_inf->full_subst_length += (subst_inf->keylen[chr] + 2); 1611 1612 id = SYM2ID(RARRAY_PTR(inf)[2]); 1613 subst_inf->ivar[chr] = rb_intern_str(rb_sprintf("@%"PRIsVALUE, rb_id2str(id))); 1614 1615 rb_attr(self, id, 1, 0, Qtrue); 1616 } 1617 1618 /* 1619 * procs : array of [type, proc] 1620 * type ==> char code or string 1621 * proc ==> proc/method/obj (must respond to 'call') 1622 */ 1623 len = RARRAY_LEN(proc_inf); 1624 for(idx = 0; idx < len; idx++) { 1625 inf = RARRAY_PTR(proc_inf)[idx]; 1626 if (TYPE(inf) != T_ARRAY) continue; 1627 rb_hash_aset(subst_inf->proc, 1628 ((TYPE(RARRAY_PTR(inf)[0]) == T_STRING)? 1629 INT2FIX(*(RSTRING_PTR(RARRAY_PTR(inf)[0]))) : 1630 RARRAY_PTR(inf)[0]), 1631 RARRAY_PTR(inf)[1]); 1632 } 1633 1634 rb_const_set(self, ID_SUBST_INFO, cbsubst_obj); 1635 1636 return self; 1637} 1638 1639static VALUE 1640cbsubst_get_extra_args_tbl(self) 1641 VALUE self; 1642{ 1643 return rb_ary_new(); 1644} 1645 1646static VALUE 1647cbsubst_scan_args(self, arg_key, val_ary) 1648 VALUE self; 1649 VALUE arg_key; 1650 VALUE val_ary; 1651{ 1652 struct cbsubst_info *inf; 1653 long idx; 1654 unsigned char *keyptr = (unsigned char*)RSTRING_PTR(arg_key); 1655 long keylen = RSTRING_LEN(arg_key); 1656 long vallen = RARRAY_LEN(val_ary); 1657 unsigned char type_chr; 1658 volatile VALUE dst = rb_ary_new2(vallen); 1659 volatile VALUE proc; 1660 int thr_crit_bup; 1661 VALUE old_gc; 1662 1663 thr_crit_bup = rb_thread_critical; 1664 rb_thread_critical = Qtrue; 1665 1666 old_gc = rb_gc_disable(); 1667 1668 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 1669 struct cbsubst_info, inf); 1670 1671 for(idx = 0; idx < vallen; idx++) { 1672 if (idx >= keylen) { 1673 proc = Qnil; 1674 } else if (*(keyptr + idx) == ' ') { 1675 proc = Qnil; 1676 } else { 1677 if (type_chr = inf->type[*(keyptr + idx)]) { 1678 proc = rb_hash_aref(inf->proc, INT2FIX((int)type_chr)); 1679 } else { 1680 proc = Qnil; 1681 } 1682 } 1683 1684 if (NIL_P(proc)) { 1685 rb_ary_push(dst, RARRAY_PTR(val_ary)[idx]); 1686 } else { 1687 rb_ary_push(dst, rb_funcall(proc, ID_call, 1, 1688 RARRAY_PTR(val_ary)[idx])); 1689 } 1690 } 1691 1692 if (old_gc == Qfalse) rb_gc_enable(); 1693 rb_thread_critical = thr_crit_bup; 1694 1695 return dst; 1696} 1697 1698static VALUE 1699cbsubst_inspect(self) 1700 VALUE self; 1701{ 1702 return rb_str_new2("CallbackSubst"); 1703} 1704 1705static VALUE 1706substinfo_inspect(self) 1707 VALUE self; 1708{ 1709 return rb_str_new2("SubstInfo"); 1710} 1711 1712/*************************************/ 1713 1714static VALUE 1715tk_cbe_inspect(self) 1716 VALUE self; 1717{ 1718 return rb_str_new2("TkCallbackEntry"); 1719} 1720 1721/*************************************/ 1722 1723static VALUE 1724tkobj_path(self) 1725 VALUE self; 1726{ 1727 return rb_ivar_get(self, ID_at_path); 1728} 1729 1730 1731/*************************************/ 1732/* release date */ 1733const char tkutil_release_date[] = TKUTIL_RELEASE_DATE; 1734 1735void 1736Init_tkutil() 1737{ 1738 VALUE cTK = rb_define_class("TkKernel", rb_cObject); 1739 VALUE mTK = rb_define_module("TkUtil"); 1740 1741 /* --------------------- */ 1742 1743 rb_define_const(mTK, "RELEASE_DATE", 1744 rb_obj_freeze(rb_str_new2(tkutil_release_date))); 1745 1746 /* --------------------- */ 1747 rb_global_variable(&cMethod); 1748 cMethod = rb_const_get(rb_cObject, rb_intern("Method")); 1749 1750 ID_path = rb_intern("path"); 1751 ID_at_path = rb_intern("@path"); 1752 ID_at_enc = rb_intern("@encoding"); 1753 ID_to_eval = rb_intern("to_eval"); 1754 ID_to_s = rb_intern("to_s"); 1755 ID_source = rb_intern("source"); 1756 ID_downcase = rb_intern("downcase"); 1757 ID_install_cmd = rb_intern("install_cmd"); 1758 ID_merge_tklist = rb_intern("_merge_tklist"); 1759 ID_encoding = rb_intern("encoding"); 1760 ID_encoding_system = rb_intern("encoding_system"); 1761 ID_call = rb_intern("call"); 1762 1763 /* --------------------- */ 1764 cCB_SUBST = rb_define_class_under(mTK, "CallbackSubst", rb_cObject); 1765 rb_define_singleton_method(cCB_SUBST, "inspect", cbsubst_inspect, 0); 1766 1767 cSUBST_INFO = rb_define_class_under(cCB_SUBST, "Info", rb_cObject); 1768 rb_define_singleton_method(cSUBST_INFO, "inspect", substinfo_inspect, 0); 1769 1770 ID_SUBST_INFO = rb_intern("SUBST_INFO"); 1771 rb_define_singleton_method(cCB_SUBST, "ret_val", cbsubst_ret_val, 1); 1772 rb_define_singleton_method(cCB_SUBST, "scan_args", cbsubst_scan_args, 2); 1773 rb_define_singleton_method(cCB_SUBST, "_sym2subst", 1774 cbsubst_sym_to_subst, 1); 1775 rb_define_singleton_method(cCB_SUBST, "subst_arg", 1776 cbsubst_get_subst_arg, -1); 1777 rb_define_singleton_method(cCB_SUBST, "_get_subst_key", 1778 cbsubst_get_subst_key, 1); 1779 rb_define_singleton_method(cCB_SUBST, "_get_all_subst_keys", 1780 cbsubst_get_all_subst_keys, 0); 1781 rb_define_singleton_method(cCB_SUBST, "_setup_subst_table", 1782 cbsubst_table_setup, -1); 1783 rb_define_singleton_method(cCB_SUBST, "_get_extra_args_tbl", 1784 cbsubst_get_extra_args_tbl, 0); 1785 rb_define_singleton_method(cCB_SUBST, "_define_attribute_aliases", 1786 cbsubst_def_attr_aliases, 1); 1787 1788 rb_define_method(cCB_SUBST, "initialize", cbsubst_initialize, -1); 1789 1790 cbsubst_init(); 1791 1792 /* --------------------- */ 1793 rb_global_variable(&cTkCallbackEntry); 1794 cTkCallbackEntry = rb_define_class("TkCallbackEntry", cTK); 1795 rb_define_singleton_method(cTkCallbackEntry, "inspect", tk_cbe_inspect, 0); 1796 1797 /* --------------------- */ 1798 rb_global_variable(&cTkObject); 1799 cTkObject = rb_define_class("TkObject", cTK); 1800 rb_define_method(cTkObject, "path", tkobj_path, 0); 1801 1802 /* --------------------- */ 1803 rb_require("tcltklib"); 1804 rb_global_variable(&cTclTkLib); 1805 cTclTkLib = rb_const_get(rb_cObject, rb_intern("TclTkLib")); 1806 ID_split_tklist = rb_intern("_split_tklist"); 1807 ID_toUTF8 = rb_intern("_toUTF8"); 1808 ID_fromUTF8 = rb_intern("_fromUTF8"); 1809 1810 /* --------------------- */ 1811 rb_define_singleton_method(cTK, "new", tk_s_new, -1); 1812 1813 /* --------------------- */ 1814 rb_global_variable(&TK_None); 1815 TK_None = rb_obj_alloc(rb_cObject); 1816 rb_define_const(mTK, "None", TK_None); 1817 rb_define_singleton_method(TK_None, "to_s", tkNone_to_s, 0); 1818 rb_define_singleton_method(TK_None, "inspect", tkNone_inspect, 0); 1819 OBJ_FREEZE(TK_None); 1820 1821 /* --------------------- */ 1822 rb_global_variable(&CALLBACK_TABLE); 1823 CALLBACK_TABLE = rb_hash_new(); 1824 1825 /* --------------------- */ 1826 rb_define_singleton_method(mTK, "untrust", tk_obj_untrust, 1); 1827 1828 rb_define_singleton_method(mTK, "eval_cmd", tk_eval_cmd, -1); 1829 rb_define_singleton_method(mTK, "callback", tk_do_callback, -1); 1830 rb_define_singleton_method(mTK, "install_cmd", tk_install_cmd, -1); 1831 rb_define_singleton_method(mTK, "uninstall_cmd", tk_uninstall_cmd, 1); 1832 rb_define_singleton_method(mTK, "_symbolkey2str", tk_symbolkey2str, 1); 1833 rb_define_singleton_method(mTK, "hash_kv", tk_hash_kv, -1); 1834 rb_define_singleton_method(mTK, "_get_eval_string", 1835 tk_get_eval_string, -1); 1836 rb_define_singleton_method(mTK, "_get_eval_enc_str", 1837 tk_get_eval_enc_str, 1); 1838 rb_define_singleton_method(mTK, "_conv_args", tk_conv_args, -1); 1839 1840 rb_define_singleton_method(mTK, "bool", tcl2rb_bool, 1); 1841 rb_define_singleton_method(mTK, "number", tcl2rb_number, 1); 1842 rb_define_singleton_method(mTK, "string", tcl2rb_string, 1); 1843 rb_define_singleton_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); 1844 rb_define_singleton_method(mTK, "num_or_nil", tcl2rb_num_or_nil, 1); 1845 1846 rb_define_method(mTK, "_toUTF8", tk_toUTF8, -1); 1847 rb_define_method(mTK, "_fromUTF8", tk_fromUTF8, -1); 1848 rb_define_method(mTK, "_symbolkey2str", tk_symbolkey2str, 1); 1849 rb_define_method(mTK, "hash_kv", tk_hash_kv, -1); 1850 rb_define_method(mTK, "_get_eval_string", tk_get_eval_string, -1); 1851 rb_define_method(mTK, "_get_eval_enc_str", tk_get_eval_enc_str, 1); 1852 rb_define_method(mTK, "_conv_args", tk_conv_args, -1); 1853 1854 rb_define_method(mTK, "bool", tcl2rb_bool, 1); 1855 rb_define_method(mTK, "number", tcl2rb_number, 1); 1856 rb_define_method(mTK, "string", tcl2rb_string, 1); 1857 rb_define_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); 1858 rb_define_method(mTK, "num_or_nil", tcl2rb_num_or_nil, 1); 1859 1860 /* --------------------- */ 1861 rb_global_variable(&ENCODING_NAME_UTF8); 1862 ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); 1863 1864 /* --------------------- */ 1865} 1866