|
Ruby
2.0.0p481(2014-05-08revision45883)
|
00001 /************************************************ 00002 00003 tkutil.c - 00004 00005 $Author: nagachika $ 00006 created at: Fri Nov 3 00:47:54 JST 1995 00007 00008 ************************************************/ 00009 00010 #define TKUTIL_RELEASE_DATE "2010-03-26" 00011 00012 #include "ruby.h" 00013 00014 #ifdef RUBY_VM 00015 static int rb_thread_critical; /* dummy */ 00016 #else 00017 /* On Ruby 1.8.x, use rb_thread_critical (defined at rubysig.h) */ 00018 #include "rubysig.h" 00019 #endif 00020 #ifdef HAVE_RUBY_ST_H 00021 #include "ruby/st.h" 00022 #else 00023 #include "st.h" 00024 #endif 00025 00026 #if !defined(RHASH_TBL) 00027 #define RHASH_TBL(h) (RHASH(h)->tbl) 00028 #endif 00029 #if !defined(RSTRING_PTR) 00030 #define RSTRING_PTR(s) (RSTRING(s)->ptr) 00031 #define RSTRING_LEN(s) (RSTRING(s)->len) 00032 #endif 00033 #if !defined(RARRAY_PTR) 00034 #define RARRAY_PTR(s) (RARRAY(s)->ptr) 00035 #define RARRAY_LEN(s) (RARRAY(s)->len) 00036 #endif 00037 00038 #if defined(HAVE_STRNDUP) && !defined(_GNU_SOURCE) 00039 extern char *strndup(const char* _ptr, size_t _len); 00040 #endif 00041 00042 static VALUE cMethod; 00043 00044 static VALUE cTclTkLib; 00045 00046 static VALUE cTkObject; 00047 static VALUE cTkCallbackEntry; 00048 00049 static VALUE TK_None; 00050 00051 static VALUE cCB_SUBST; 00052 static VALUE cSUBST_INFO; 00053 00054 static VALUE ENCODING_NAME_UTF8; /* for saving GC cost */ 00055 00056 static ID ID_split_tklist; 00057 static ID ID_toUTF8; 00058 static ID ID_fromUTF8; 00059 static ID ID_path; 00060 static ID ID_at_path; 00061 static ID ID_at_enc; 00062 static ID ID_to_eval; 00063 static ID ID_to_s; 00064 static ID ID_source; 00065 static ID ID_downcase; 00066 static ID ID_install_cmd; 00067 static ID ID_merge_tklist; 00068 static ID ID_encoding; 00069 static ID ID_encoding_system; 00070 static ID ID_call; 00071 00072 static ID ID_SUBST_INFO; 00073 00074 static VALUE CALLBACK_TABLE; 00075 static unsigned long CALLBACK_ID_NUM = 0; 00076 00077 /*************************************/ 00078 00079 #if defined(HAVE_RB_OBJ_INSTANCE_EXEC) && !defined(RUBY_VM) 00080 extern VALUE rb_obj_instance_exec _((int, VALUE*, VALUE)); 00081 #endif 00082 static VALUE 00083 tk_s_new(argc, argv, klass) 00084 int argc; 00085 VALUE *argv; 00086 VALUE klass; 00087 { 00088 VALUE obj = rb_class_new_instance(argc, argv, klass); 00089 00090 if (rb_block_given_p()) { 00091 #ifndef HAVE_RB_OBJ_INSTANCE_EXEC 00092 rb_obj_instance_eval(0, 0, obj); 00093 #else 00094 rb_obj_instance_exec(1, &obj, obj); 00095 #endif 00096 } 00097 return obj; 00098 } 00099 00100 /*************************************/ 00101 00102 static VALUE 00103 tkNone_to_s(self) 00104 VALUE self; 00105 { 00106 return rb_str_new2(""); 00107 } 00108 00109 static VALUE 00110 tkNone_inspect(self) 00111 VALUE self; 00112 { 00113 return rb_str_new2("None"); 00114 } 00115 00116 /*************************************/ 00117 00118 static VALUE 00119 tk_obj_untrust(self, obj) 00120 VALUE self; 00121 VALUE obj; 00122 { 00123 #ifdef HAVE_RB_OBJ_TAINT 00124 rb_obj_taint(obj); 00125 #endif 00126 #ifdef HAVE_RB_OBJ_UNTRUST 00127 rb_obj_untrust(obj); 00128 #endif 00129 00130 return obj; 00131 } 00132 00133 static VALUE 00134 tk_eval_cmd(argc, argv, self) 00135 int argc; 00136 VALUE argv[]; 00137 VALUE self; 00138 { 00139 volatile VALUE cmd, rest; 00140 00141 rb_scan_args(argc, argv, "1*", &cmd, &rest); 00142 return rb_eval_cmd(cmd, rest, 0); 00143 } 00144 00145 static VALUE 00146 tk_do_callback(argc, argv, self) 00147 int argc; 00148 VALUE *argv; 00149 VALUE self; 00150 { 00151 #if 0 00152 volatile VALUE id; 00153 volatile VALUE rest; 00154 00155 rb_scan_args(argc, argv, "1*", &id, &rest); 00156 return rb_apply(rb_hash_aref(CALLBACK_TABLE, id), ID_call, rest); 00157 #endif 00158 return rb_funcall2(rb_hash_aref(CALLBACK_TABLE, argv[0]), 00159 ID_call, argc - 1, argv + 1); 00160 } 00161 00162 static const char cmd_id_head[] = "ruby_cmd TkUtil callback "; 00163 static const char cmd_id_prefix[] = "cmd"; 00164 00165 static VALUE 00166 tk_install_cmd_core(cmd) 00167 VALUE cmd; 00168 { 00169 volatile VALUE id_num; 00170 00171 id_num = ULONG2NUM(CALLBACK_ID_NUM++); 00172 id_num = rb_funcall(id_num, ID_to_s, 0, 0); 00173 id_num = rb_str_append(rb_str_new2(cmd_id_prefix), id_num); 00174 rb_hash_aset(CALLBACK_TABLE, id_num, cmd); 00175 return rb_str_append(rb_str_new2(cmd_id_head), id_num); 00176 } 00177 00178 static VALUE 00179 tk_install_cmd(argc, argv, self) 00180 int argc; 00181 VALUE *argv; 00182 VALUE self; 00183 { 00184 volatile VALUE cmd; 00185 00186 #if 0 00187 if (rb_scan_args(argc, argv, "01", &cmd) == 0) { 00188 cmd = rb_block_proc(); 00189 } 00190 return tk_install_cmd_core(cmd); 00191 #endif 00192 if (argc == 0) { 00193 cmd = rb_block_proc(); 00194 } else { 00195 cmd = argv[0]; 00196 } 00197 return tk_install_cmd_core(cmd); 00198 } 00199 00200 static VALUE 00201 tk_uninstall_cmd(self, cmd_id) 00202 VALUE self; 00203 VALUE cmd_id; 00204 { 00205 size_t head_len = strlen(cmd_id_head); 00206 size_t prefix_len = strlen(cmd_id_prefix); 00207 00208 StringValue(cmd_id); 00209 if (strncmp(cmd_id_head, RSTRING_PTR(cmd_id), head_len) != 0) { 00210 return Qnil; 00211 } 00212 if (strncmp(cmd_id_prefix, 00213 RSTRING_PTR(cmd_id) + head_len, prefix_len) != 0) { 00214 return Qnil; 00215 } 00216 00217 return rb_hash_delete(CALLBACK_TABLE, 00218 rb_str_new2(RSTRING_PTR(cmd_id) + head_len)); 00219 } 00220 00221 static VALUE 00222 tk_toUTF8(argc, argv, self) 00223 int argc; 00224 VALUE *argv; 00225 VALUE self; 00226 { 00227 return rb_funcall2(cTclTkLib, ID_toUTF8, argc, argv); 00228 } 00229 00230 static VALUE 00231 tk_fromUTF8(argc, argv, self) 00232 int argc; 00233 VALUE *argv; 00234 VALUE self; 00235 { 00236 return rb_funcall2(cTclTkLib, ID_fromUTF8, argc, argv); 00237 } 00238 00239 static VALUE 00240 fromDefaultEnc_toUTF8(str, self) 00241 VALUE str; 00242 VALUE self; 00243 { 00244 VALUE argv[1]; 00245 00246 argv[0] = str; 00247 return tk_toUTF8(1, argv, self); 00248 } 00249 00250 #if 0 00251 static VALUE 00252 fromUTF8_toDefaultEnc(str, self) 00253 VALUE str; 00254 VALUE self; 00255 { 00256 VALUE argv[1]; 00257 00258 argv[0] = str; 00259 return tk_fromUTF8(1, argv, self); 00260 } 00261 #endif 00262 00263 static int 00264 to_strkey(key, value, hash) 00265 VALUE key; 00266 VALUE value; 00267 VALUE hash; 00268 { 00269 rb_hash_aset(hash, rb_funcall(key, ID_to_s, 0, 0), value); 00270 return ST_CHECK; 00271 } 00272 00273 static VALUE 00274 tk_symbolkey2str(self, keys) 00275 VALUE self; 00276 VALUE keys; 00277 { 00278 volatile VALUE new_keys = rb_hash_new(); 00279 00280 if (NIL_P(keys)) return new_keys; 00281 keys = rb_convert_type(keys, T_HASH, "Hash", "to_hash"); 00282 st_foreach_check(RHASH_TBL(keys), to_strkey, new_keys, Qundef); 00283 return new_keys; 00284 } 00285 00286 static VALUE get_eval_string_core _((VALUE, VALUE, VALUE)); 00287 static VALUE ary2list _((VALUE, VALUE, VALUE)); 00288 static VALUE ary2list2 _((VALUE, VALUE, VALUE)); 00289 static VALUE hash2list _((VALUE, VALUE)); 00290 static VALUE hash2list_enc _((VALUE, VALUE)); 00291 static VALUE hash2kv _((VALUE, VALUE, VALUE)); 00292 static VALUE hash2kv_enc _((VALUE, VALUE, VALUE)); 00293 00294 static VALUE 00295 ary2list(ary, enc_flag, self) 00296 VALUE ary; 00297 VALUE enc_flag; 00298 VALUE self; 00299 { 00300 long idx, idx2, size, size2; 00301 int req_chk_flag; 00302 volatile VALUE val, val2, str_val; 00303 volatile VALUE dst; 00304 volatile VALUE sys_enc, dst_enc, str_enc; 00305 00306 sys_enc = rb_funcall(cTclTkLib, ID_encoding, 0, 0); 00307 if (NIL_P(sys_enc)) { 00308 sys_enc = rb_funcall(cTclTkLib, ID_encoding_system, 0, 0); 00309 sys_enc = rb_funcall(sys_enc, ID_to_s, 0, 0); 00310 } 00311 00312 if (NIL_P(enc_flag)) { 00313 dst_enc = sys_enc; 00314 req_chk_flag = 1; 00315 } else if (TYPE(enc_flag) == T_TRUE || TYPE(enc_flag) == T_FALSE) { 00316 dst_enc = enc_flag; 00317 req_chk_flag = 0; 00318 } else { 00319 dst_enc = rb_funcall(enc_flag, ID_to_s, 0, 0); 00320 req_chk_flag = 0; 00321 } 00322 00323 /* size = RARRAY_LEN(ary); */ 00324 size = 0; 00325 for(idx = 0; idx < RARRAY_LEN(ary); idx++) { 00326 if (TYPE(RARRAY_PTR(ary)[idx]) == T_HASH) { 00327 size += 2 * RHASH_SIZE(RARRAY_PTR(ary)[idx]); 00328 } else { 00329 size++; 00330 } 00331 } 00332 00333 dst = rb_ary_new2(size); 00334 for(idx = 0; idx < RARRAY_LEN(ary); idx++) { 00335 val = RARRAY_PTR(ary)[idx]; 00336 str_val = Qnil; 00337 switch(TYPE(val)) { 00338 case T_ARRAY: 00339 str_val = ary2list(val, enc_flag, self); 00340 rb_ary_push(dst, str_val); 00341 00342 if (req_chk_flag) { 00343 str_enc = rb_ivar_get(str_val, ID_at_enc); 00344 if (!NIL_P(str_enc)) { 00345 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 00346 } else { 00347 str_enc = sys_enc; 00348 } 00349 if (!rb_str_cmp(str_enc, dst_enc)) { 00350 dst_enc = Qtrue; 00351 req_chk_flag = 0; 00352 } 00353 } 00354 00355 break; 00356 00357 case T_HASH: 00358 /* rb_ary_push(dst, hash2list(val, self)); */ 00359 if (RTEST(enc_flag)) { 00360 val = hash2kv_enc(val, Qnil, self); 00361 } else { 00362 val = hash2kv(val, Qnil, self); 00363 } 00364 size2 = RARRAY_LEN(val); 00365 for(idx2 = 0; idx2 < size2; idx2++) { 00366 val2 = RARRAY_PTR(val)[idx2]; 00367 switch(TYPE(val2)) { 00368 case T_ARRAY: 00369 str_val = ary2list(val2, enc_flag, self); 00370 rb_ary_push(dst, str_val); 00371 break; 00372 00373 case T_HASH: 00374 if (RTEST(enc_flag)) { 00375 str_val = hash2list_enc(val2, self); 00376 } else { 00377 str_val = hash2list(val2, self); 00378 } 00379 rb_ary_push(dst, str_val); 00380 break; 00381 00382 default: 00383 if (val2 != TK_None) { 00384 str_val = get_eval_string_core(val2, enc_flag, self); 00385 rb_ary_push(dst, str_val); 00386 } 00387 } 00388 00389 if (req_chk_flag) { 00390 str_enc = rb_ivar_get(str_val, ID_at_enc); 00391 if (!NIL_P(str_enc)) { 00392 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 00393 } else { 00394 str_enc = sys_enc; 00395 } 00396 if (!rb_str_cmp(str_enc, dst_enc)) { 00397 dst_enc = Qtrue; 00398 req_chk_flag = 0; 00399 } 00400 } 00401 } 00402 break; 00403 00404 default: 00405 if (val != TK_None) { 00406 str_val = get_eval_string_core(val, enc_flag, self); 00407 rb_ary_push(dst, str_val); 00408 00409 if (req_chk_flag) { 00410 str_enc = rb_ivar_get(str_val, ID_at_enc); 00411 if (!NIL_P(str_enc)) { 00412 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 00413 } else { 00414 str_enc = sys_enc; 00415 } 00416 if (!rb_str_cmp(str_enc, dst_enc)) { 00417 dst_enc = Qtrue; 00418 req_chk_flag = 0; 00419 } 00420 } 00421 } 00422 } 00423 } 00424 00425 if (RTEST(dst_enc) && !NIL_P(sys_enc)) { 00426 for(idx = 0; idx < RARRAY_LEN(dst); idx++) { 00427 str_val = RARRAY_PTR(dst)[idx]; 00428 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 00429 str_val = rb_funcall(self, ID_toUTF8, 1, str_val); 00430 } else { 00431 str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val); 00432 } 00433 RARRAY_PTR(dst)[idx] = str_val; 00434 } 00435 val = rb_apply(cTclTkLib, ID_merge_tklist, dst); 00436 if (TYPE(dst_enc) == T_STRING) { 00437 val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); 00438 rb_ivar_set(val, ID_at_enc, dst_enc); 00439 } else { 00440 rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); 00441 } 00442 return val; 00443 } else { 00444 return rb_apply(cTclTkLib, ID_merge_tklist, dst); 00445 } 00446 } 00447 00448 static VALUE 00449 ary2list2(ary, enc_flag, self) 00450 VALUE ary; 00451 VALUE enc_flag; 00452 VALUE self; 00453 { 00454 long idx, size; 00455 int req_chk_flag; 00456 volatile VALUE val, str_val; 00457 volatile VALUE dst; 00458 volatile VALUE sys_enc, dst_enc, str_enc; 00459 00460 sys_enc = rb_funcall(cTclTkLib, ID_encoding, 0, 0); 00461 if (NIL_P(sys_enc)) { 00462 sys_enc = rb_funcall(cTclTkLib, ID_encoding_system, 0, 0); 00463 sys_enc = rb_funcall(sys_enc, ID_to_s, 0, 0); 00464 } 00465 00466 if (NIL_P(enc_flag)) { 00467 dst_enc = sys_enc; 00468 req_chk_flag = 1; 00469 } else if (TYPE(enc_flag) == T_TRUE || TYPE(enc_flag) == T_FALSE) { 00470 dst_enc = enc_flag; 00471 req_chk_flag = 0; 00472 } else { 00473 dst_enc = rb_funcall(enc_flag, ID_to_s, 0, 0); 00474 req_chk_flag = 0; 00475 } 00476 00477 size = RARRAY_LEN(ary); 00478 dst = rb_ary_new2(size); 00479 for(idx = 0; idx < RARRAY_LEN(ary); idx++) { 00480 val = RARRAY_PTR(ary)[idx]; 00481 str_val = Qnil; 00482 switch(TYPE(val)) { 00483 case T_ARRAY: 00484 str_val = ary2list(val, enc_flag, self); 00485 break; 00486 00487 case T_HASH: 00488 if (RTEST(enc_flag)) { 00489 str_val = hash2list(val, self); 00490 } else { 00491 str_val = hash2list_enc(val, self); 00492 } 00493 break; 00494 00495 default: 00496 if (val != TK_None) { 00497 str_val = get_eval_string_core(val, enc_flag, self); 00498 } 00499 } 00500 00501 if (!NIL_P(str_val)) { 00502 rb_ary_push(dst, str_val); 00503 00504 if (req_chk_flag) { 00505 str_enc = rb_ivar_get(str_val, ID_at_enc); 00506 if (!NIL_P(str_enc)) { 00507 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 00508 } else { 00509 str_enc = sys_enc; 00510 } 00511 if (!rb_str_cmp(str_enc, dst_enc)) { 00512 dst_enc = Qtrue; 00513 req_chk_flag = 0; 00514 } 00515 } 00516 } 00517 } 00518 00519 if (RTEST(dst_enc) && !NIL_P(sys_enc)) { 00520 for(idx = 0; idx < RARRAY_LEN(dst); idx++) { 00521 str_val = RARRAY_PTR(dst)[idx]; 00522 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 00523 str_val = rb_funcall(self, ID_toUTF8, 1, str_val); 00524 } else { 00525 str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val); 00526 } 00527 RARRAY_PTR(dst)[idx] = str_val; 00528 } 00529 val = rb_apply(cTclTkLib, ID_merge_tklist, dst); 00530 if (TYPE(dst_enc) == T_STRING) { 00531 val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); 00532 rb_ivar_set(val, ID_at_enc, dst_enc); 00533 } else { 00534 rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); 00535 } 00536 return val; 00537 } else { 00538 return rb_apply(cTclTkLib, ID_merge_tklist, dst); 00539 } 00540 } 00541 00542 static VALUE 00543 key2keyname(key) 00544 VALUE key; 00545 { 00546 return rb_str_append(rb_str_new2("-"), rb_funcall(key, ID_to_s, 0, 0)); 00547 } 00548 00549 static VALUE 00550 assoc2kv(assoc, ary, self) 00551 VALUE assoc; 00552 VALUE ary; 00553 VALUE self; 00554 { 00555 long i, j, len; 00556 volatile VALUE pair; 00557 volatile VALUE val; 00558 volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); 00559 00560 len = RARRAY_LEN(assoc); 00561 00562 for(i = 0; i < len; i++) { 00563 pair = RARRAY_PTR(assoc)[i]; 00564 if (TYPE(pair) != T_ARRAY) { 00565 rb_ary_push(dst, key2keyname(pair)); 00566 continue; 00567 } 00568 switch(RARRAY_LEN(assoc)) { 00569 case 2: 00570 rb_ary_push(dst, RARRAY_PTR(pair)[2]); 00571 00572 case 1: 00573 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00574 00575 case 0: 00576 continue; 00577 00578 default: 00579 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00580 00581 val = rb_ary_new2(RARRAY_LEN(pair) - 1); 00582 for(j = 1; j < RARRAY_LEN(pair); j++) { 00583 rb_ary_push(val, RARRAY_PTR(pair)[j]); 00584 } 00585 00586 rb_ary_push(dst, val); 00587 } 00588 } 00589 00590 if (NIL_P(ary)) { 00591 return dst; 00592 } else { 00593 return rb_ary_plus(ary, dst); 00594 } 00595 } 00596 00597 static VALUE 00598 assoc2kv_enc(assoc, ary, self) 00599 VALUE assoc; 00600 VALUE ary; 00601 VALUE self; 00602 { 00603 long i, j, len; 00604 volatile VALUE pair; 00605 volatile VALUE val; 00606 volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); 00607 00608 len = RARRAY_LEN(assoc); 00609 00610 for(i = 0; i < len; i++) { 00611 pair = RARRAY_PTR(assoc)[i]; 00612 if (TYPE(pair) != T_ARRAY) { 00613 rb_ary_push(dst, key2keyname(pair)); 00614 continue; 00615 } 00616 switch(RARRAY_LEN(assoc)) { 00617 case 2: 00618 rb_ary_push(dst, get_eval_string_core(RARRAY_PTR(pair)[2], Qtrue, self)); 00619 00620 case 1: 00621 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00622 00623 case 0: 00624 continue; 00625 00626 default: 00627 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00628 00629 val = rb_ary_new2(RARRAY_LEN(pair) - 1); 00630 for(j = 1; j < RARRAY_LEN(pair); j++) { 00631 rb_ary_push(val, RARRAY_PTR(pair)[j]); 00632 } 00633 00634 rb_ary_push(dst, get_eval_string_core(val, Qtrue, self)); 00635 } 00636 } 00637 00638 if (NIL_P(ary)) { 00639 return dst; 00640 } else { 00641 return rb_ary_plus(ary, dst); 00642 } 00643 } 00644 00645 static int 00646 push_kv(key, val, args) 00647 VALUE key; 00648 VALUE val; 00649 VALUE args; 00650 { 00651 volatile VALUE ary; 00652 00653 ary = RARRAY_PTR(args)[0]; 00654 00655 #if 0 00656 rb_ary_push(ary, key2keyname(key)); 00657 if (val != TK_None) rb_ary_push(ary, val); 00658 #endif 00659 rb_ary_push(ary, key2keyname(key)); 00660 00661 if (val == TK_None) return ST_CHECK; 00662 00663 rb_ary_push(ary, get_eval_string_core(val, Qnil, RARRAY_PTR(args)[1])); 00664 00665 return ST_CHECK; 00666 } 00667 00668 static VALUE 00669 hash2kv(hash, ary, self) 00670 VALUE hash; 00671 VALUE ary; 00672 VALUE self; 00673 { 00674 volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash)); 00675 volatile VALUE args = rb_ary_new3(2, dst, self); 00676 00677 st_foreach_check(RHASH_TBL(hash), push_kv, args, Qundef); 00678 00679 if (NIL_P(ary)) { 00680 return dst; 00681 } else { 00682 return rb_ary_concat(ary, dst); 00683 } 00684 } 00685 00686 static int 00687 push_kv_enc(key, val, args) 00688 VALUE key; 00689 VALUE val; 00690 VALUE args; 00691 { 00692 volatile VALUE ary; 00693 00694 ary = RARRAY_PTR(args)[0]; 00695 00696 #if 0 00697 rb_ary_push(ary, key2keyname(key)); 00698 if (val != TK_None) { 00699 rb_ary_push(ary, get_eval_string_core(val, Qtrue, 00700 RARRAY_PTR(args)[1])); 00701 } 00702 #endif 00703 rb_ary_push(ary, key2keyname(key)); 00704 00705 if (val == TK_None) return ST_CHECK; 00706 00707 rb_ary_push(ary, get_eval_string_core(val, Qtrue, RARRAY_PTR(args)[1])); 00708 00709 return ST_CHECK; 00710 } 00711 00712 static VALUE 00713 hash2kv_enc(hash, ary, self) 00714 VALUE hash; 00715 VALUE ary; 00716 VALUE self; 00717 { 00718 volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash)); 00719 volatile VALUE args = rb_ary_new3(2, dst, self); 00720 00721 st_foreach_check(RHASH_TBL(hash), push_kv_enc, args, Qundef); 00722 00723 if (NIL_P(ary)) { 00724 return dst; 00725 } else { 00726 return rb_ary_concat(ary, dst); 00727 } 00728 } 00729 00730 static VALUE 00731 hash2list(hash, self) 00732 VALUE hash; 00733 VALUE self; 00734 { 00735 return ary2list2(hash2kv(hash, Qnil, self), Qfalse, self); 00736 } 00737 00738 00739 static VALUE 00740 hash2list_enc(hash, self) 00741 VALUE hash; 00742 VALUE self; 00743 { 00744 return ary2list2(hash2kv_enc(hash, Qnil, self), Qfalse, self); 00745 } 00746 00747 static VALUE 00748 tk_hash_kv(argc, argv, self) 00749 int argc; 00750 VALUE *argv; 00751 VALUE self; 00752 { 00753 volatile VALUE hash, enc_flag, ary; 00754 00755 ary = Qnil; 00756 enc_flag = Qnil; 00757 switch(argc) { 00758 case 3: 00759 ary = argv[2]; 00760 case 2: 00761 enc_flag = argv[1]; 00762 case 1: 00763 hash = argv[0]; 00764 break; 00765 case 0: 00766 rb_raise(rb_eArgError, "too few arguments"); 00767 default: /* >= 3 */ 00768 rb_raise(rb_eArgError, "too many arguments"); 00769 } 00770 00771 switch(TYPE(hash)) { 00772 case T_ARRAY: 00773 if (RTEST(enc_flag)) { 00774 return assoc2kv_enc(hash, ary, self); 00775 } else { 00776 return assoc2kv(hash, ary, self); 00777 } 00778 00779 case T_HASH: 00780 if (RTEST(enc_flag)) { 00781 return hash2kv_enc(hash, ary, self); 00782 } else { 00783 return hash2kv(hash, ary, self); 00784 } 00785 00786 case T_NIL: 00787 if (NIL_P(ary)) { 00788 return rb_ary_new(); 00789 } else { 00790 return ary; 00791 } 00792 00793 default: 00794 if (hash == TK_None) { 00795 if (NIL_P(ary)) { 00796 return rb_ary_new(); 00797 } else { 00798 return ary; 00799 } 00800 } 00801 rb_raise(rb_eArgError, "Hash is expected for 1st argument"); 00802 } 00803 00804 UNREACHABLE; 00805 } 00806 00807 static VALUE 00808 get_eval_string_core(obj, enc_flag, self) 00809 VALUE obj; 00810 VALUE enc_flag; 00811 VALUE self; 00812 { 00813 switch(TYPE(obj)) { 00814 case T_FLOAT: 00815 case T_FIXNUM: 00816 case T_BIGNUM: 00817 return rb_funcall(obj, ID_to_s, 0, 0); 00818 00819 case T_STRING: 00820 if (RTEST(enc_flag)) { 00821 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 00822 return rb_funcall(self, ID_toUTF8, 1, obj); 00823 } else { 00824 return fromDefaultEnc_toUTF8(obj, self); 00825 } 00826 } else { 00827 return obj; 00828 } 00829 00830 case T_SYMBOL: 00831 if (RTEST(enc_flag)) { 00832 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 00833 return rb_funcall(self, ID_toUTF8, 1, 00834 rb_str_new2(rb_id2name(SYM2ID(obj)))); 00835 } else { 00836 return fromDefaultEnc_toUTF8(rb_str_new2(rb_id2name(SYM2ID(obj))), self); 00837 } 00838 } else { 00839 #ifdef HAVE_RB_SYM_TO_S 00840 return rb_sym_to_s(obj); 00841 #else 00842 return rb_str_new2(rb_id2name(SYM2ID(obj))); 00843 #endif 00844 } 00845 00846 case T_HASH: 00847 if (RTEST(enc_flag)) { 00848 return hash2list_enc(obj, self); 00849 } else { 00850 return hash2list(obj, self); 00851 } 00852 00853 case T_ARRAY: 00854 return ary2list(obj, enc_flag, self); 00855 00856 case T_FALSE: 00857 return rb_str_new2("0"); 00858 00859 case T_TRUE: 00860 return rb_str_new2("1"); 00861 00862 case T_NIL: 00863 return rb_str_new2(""); 00864 00865 case T_REGEXP: 00866 return rb_funcall(obj, ID_source, 0, 0); 00867 00868 default: 00869 if (rb_obj_is_kind_of(obj, cTkObject)) { 00870 /* return rb_str_new3(rb_funcall(obj, ID_path, 0, 0)); */ 00871 return get_eval_string_core(rb_funcall(obj, ID_path, 0, 0), 00872 enc_flag, self); 00873 } 00874 00875 if (rb_obj_is_kind_of(obj, rb_cProc) 00876 || rb_obj_is_kind_of(obj, cMethod) 00877 || rb_obj_is_kind_of(obj, cTkCallbackEntry)) { 00878 if (rb_obj_respond_to(self, ID_install_cmd, Qtrue)) { 00879 return rb_funcall(self, ID_install_cmd, 1, obj); 00880 } else { 00881 return tk_install_cmd_core(obj); 00882 } 00883 } 00884 00885 if (obj == TK_None) return Qnil; 00886 00887 if (rb_obj_respond_to(obj, ID_to_eval, Qtrue)) { 00888 /* return rb_funcall(obj, ID_to_eval, 0, 0); */ 00889 return get_eval_string_core(rb_funcall(obj, ID_to_eval, 0, 0), 00890 enc_flag, self); 00891 } else if (rb_obj_respond_to(obj, ID_path, Qtrue)) { 00892 /* return rb_funcall(obj, ID_path, 0, 0); */ 00893 return get_eval_string_core(rb_funcall(obj, ID_path, 0, 0), 00894 enc_flag, self); 00895 } else if (rb_obj_respond_to(obj, ID_to_s, Qtrue)) { 00896 return rb_funcall(obj, ID_to_s, 0, 0); 00897 } 00898 } 00899 00900 rb_warning("fail to convert '%+"PRIsVALUE"' to string for Tk", obj); 00901 00902 return obj; 00903 } 00904 00905 static VALUE 00906 tk_get_eval_string(argc, argv, self) 00907 int argc; 00908 VALUE *argv; 00909 VALUE self; 00910 { 00911 volatile VALUE obj, enc_flag; 00912 00913 if (rb_scan_args(argc, argv, "11", &obj, &enc_flag) == 1) { 00914 enc_flag = Qnil; 00915 } 00916 00917 return get_eval_string_core(obj, enc_flag, self); 00918 } 00919 00920 static VALUE 00921 tk_get_eval_enc_str(self, obj) 00922 VALUE self; 00923 VALUE obj; 00924 { 00925 if (obj == TK_None) { 00926 return obj; 00927 } else { 00928 return get_eval_string_core(obj, Qtrue, self); 00929 } 00930 } 00931 00932 static VALUE 00933 tk_conv_args(argc, argv, self) 00934 int argc; 00935 VALUE *argv; /* [0]:base_array, [1]:enc_mode, [2]..[n]:args */ 00936 VALUE self; 00937 { 00938 int idx, size; 00939 volatile VALUE dst; 00940 int thr_crit_bup; 00941 VALUE old_gc; 00942 00943 if (argc < 2) { 00944 rb_raise(rb_eArgError, "too few arguments"); 00945 } 00946 00947 thr_crit_bup = rb_thread_critical; 00948 rb_thread_critical = Qtrue; 00949 old_gc = rb_gc_disable(); 00950 00951 for(size = 0, idx = 2; idx < argc; idx++) { 00952 if (TYPE(argv[idx]) == T_HASH) { 00953 size += 2 * RHASH_SIZE(argv[idx]); 00954 } else { 00955 size++; 00956 } 00957 } 00958 /* dst = rb_ary_new2(argc - 2); */ 00959 dst = rb_ary_new2(size); 00960 for(idx = 2; idx < argc; idx++) { 00961 if (TYPE(argv[idx]) == T_HASH) { 00962 if (RTEST(argv[1])) { 00963 hash2kv_enc(argv[idx], dst, self); 00964 } else { 00965 hash2kv(argv[idx], dst, self); 00966 } 00967 } else if (argv[idx] != TK_None) { 00968 rb_ary_push(dst, get_eval_string_core(argv[idx], argv[1], self)); 00969 } 00970 } 00971 00972 if (old_gc == Qfalse) rb_gc_enable(); 00973 rb_thread_critical = thr_crit_bup; 00974 00975 return rb_ary_plus(argv[0], dst); 00976 } 00977 00978 00979 /*************************************/ 00980 00981 static VALUE 00982 tcl2rb_bool(self, value) 00983 VALUE self; 00984 VALUE value; 00985 { 00986 if (TYPE(value) == T_FIXNUM) { 00987 if (NUM2INT(value) == 0) { 00988 return Qfalse; 00989 } else { 00990 return Qtrue; 00991 } 00992 } 00993 00994 if (TYPE(value) == T_TRUE || TYPE(value) == T_FALSE) { 00995 return value; 00996 } 00997 00998 rb_check_type(value, T_STRING); 00999 01000 value = rb_funcall(value, ID_downcase, 0); 01001 01002 if (RSTRING_PTR(value) == (char*)NULL) return Qnil; 01003 01004 if (RSTRING_PTR(value)[0] == '\0' 01005 || strcmp(RSTRING_PTR(value), "0") == 0 01006 || strcmp(RSTRING_PTR(value), "no") == 0 01007 || strcmp(RSTRING_PTR(value), "off") == 0 01008 || strcmp(RSTRING_PTR(value), "false") == 0) { 01009 return Qfalse; 01010 } else { 01011 return Qtrue; 01012 } 01013 } 01014 01015 #if 0 01016 static VALUE 01017 tkstr_to_dec(value) 01018 VALUE value; 01019 { 01020 return rb_cstr_to_inum(RSTRING_PTR(value), 10, 1); 01021 } 01022 #endif 01023 01024 static VALUE 01025 tkstr_to_int(value) 01026 VALUE value; 01027 { 01028 return rb_cstr_to_inum(RSTRING_PTR(value), 0, 1); 01029 } 01030 01031 static VALUE 01032 tkstr_to_float(value) 01033 VALUE value; 01034 { 01035 return rb_float_new(rb_cstr_to_dbl(RSTRING_PTR(value), 1)); 01036 } 01037 01038 static VALUE 01039 tkstr_invalid_numstr(value) 01040 VALUE value; 01041 { 01042 rb_raise(rb_eArgError, 01043 "invalid value for Number: '%s'", RSTRING_PTR(value)); 01044 return Qnil; /*dummy*/ 01045 } 01046 01047 static VALUE 01048 tkstr_rescue_float(value) 01049 VALUE value; 01050 { 01051 return rb_rescue2(tkstr_to_float, value, 01052 tkstr_invalid_numstr, value, 01053 rb_eArgError, 0); 01054 } 01055 01056 static VALUE 01057 tkstr_to_number(value) 01058 VALUE value; 01059 { 01060 rb_check_type(value, T_STRING); 01061 01062 if (RSTRING_PTR(value) == (char*)NULL) return INT2FIX(0); 01063 01064 return rb_rescue2(tkstr_to_int, value, 01065 tkstr_rescue_float, value, 01066 rb_eArgError, 0); 01067 } 01068 01069 static VALUE 01070 tcl2rb_number(self, value) 01071 VALUE self; 01072 VALUE value; 01073 { 01074 return tkstr_to_number(value); 01075 } 01076 01077 static VALUE 01078 tkstr_to_str(value) 01079 VALUE value; 01080 { 01081 char * ptr; 01082 long len; 01083 01084 ptr = RSTRING_PTR(value); 01085 len = RSTRING_LEN(value); 01086 01087 if (len > 1 && *ptr == '{' && *(ptr + len - 1) == '}') { 01088 return rb_str_new(ptr + 1, len - 2); 01089 } 01090 return value; 01091 } 01092 01093 static VALUE 01094 tcl2rb_string(self, value) 01095 VALUE self; 01096 VALUE value; 01097 { 01098 rb_check_type(value, T_STRING); 01099 01100 if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2(""); 01101 01102 return tkstr_to_str(value); 01103 } 01104 01105 static VALUE 01106 tcl2rb_num_or_str(self, value) 01107 VALUE self; 01108 VALUE value; 01109 { 01110 rb_check_type(value, T_STRING); 01111 01112 if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2(""); 01113 01114 return rb_rescue2(tkstr_to_number, value, 01115 tkstr_to_str, value, 01116 rb_eArgError, 0); 01117 } 01118 01119 static VALUE 01120 tcl2rb_num_or_nil(self, value) 01121 VALUE self; 01122 VALUE value; 01123 { 01124 rb_check_type(value, T_STRING); 01125 01126 if (RSTRING_LEN(value) == 0) return Qnil; 01127 01128 return tkstr_to_number(value); 01129 } 01130 01131 01132 /*************************************/ 01133 01134 #define CBSUBST_TBL_MAX (256) 01135 struct cbsubst_info { 01136 long full_subst_length; 01137 long keylen[CBSUBST_TBL_MAX]; 01138 char *key[CBSUBST_TBL_MAX]; 01139 char type[CBSUBST_TBL_MAX]; 01140 ID ivar[CBSUBST_TBL_MAX]; 01141 VALUE proc; 01142 VALUE aliases; 01143 }; 01144 01145 static void 01146 subst_mark(ptr) 01147 struct cbsubst_info *ptr; 01148 { 01149 rb_gc_mark(ptr->proc); 01150 rb_gc_mark(ptr->aliases); 01151 } 01152 01153 static void 01154 subst_free(ptr) 01155 struct cbsubst_info *ptr; 01156 { 01157 int i; 01158 01159 if (ptr) { 01160 for(i = 0; i < CBSUBST_TBL_MAX; i++) { 01161 if (ptr->key[i] != NULL) { 01162 free(ptr->key[i]); /* allocated by malloc */ 01163 ptr->key[i] = NULL; 01164 } 01165 } 01166 xfree(ptr); /* allocated by ALLOC */ 01167 } 01168 } 01169 01170 static VALUE 01171 allocate_cbsubst_info(struct cbsubst_info **inf_ptr) 01172 { 01173 struct cbsubst_info *inf; 01174 volatile VALUE proc, aliases; 01175 int idx; 01176 01177 inf = ALLOC(struct cbsubst_info); 01178 01179 inf->full_subst_length = 0; 01180 01181 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01182 inf->keylen[idx] = 0; 01183 inf->key[idx] = NULL; 01184 inf->type[idx] = '\0'; 01185 inf->ivar[idx] = (ID) 0; 01186 } 01187 01188 proc = rb_hash_new(); 01189 inf->proc = proc; 01190 01191 aliases = rb_hash_new(); 01192 inf->aliases = aliases; 01193 01194 if (inf_ptr != (struct cbsubst_info **)NULL) *inf_ptr = inf; 01195 01196 return Data_Wrap_Struct(cSUBST_INFO, subst_mark, subst_free, inf); 01197 } 01198 01199 static void 01200 cbsubst_init() 01201 { 01202 rb_const_set(cCB_SUBST, ID_SUBST_INFO, 01203 allocate_cbsubst_info((struct cbsubst_info **)NULL)); 01204 } 01205 01206 static VALUE 01207 cbsubst_initialize(argc, argv, self) 01208 int argc; 01209 VALUE *argv; 01210 VALUE self; 01211 { 01212 struct cbsubst_info *inf; 01213 int idx, iv_idx; 01214 01215 Data_Get_Struct(rb_const_get(rb_obj_class(self), ID_SUBST_INFO), 01216 struct cbsubst_info, inf); 01217 01218 idx = 0; 01219 for(iv_idx = 0; iv_idx < CBSUBST_TBL_MAX; iv_idx++) { 01220 if ( inf->ivar[iv_idx] == (ID) 0 ) continue; 01221 rb_ivar_set(self, inf->ivar[iv_idx], argv[idx++]); 01222 if (idx >= argc) break; 01223 } 01224 01225 return self; 01226 } 01227 01228 static VALUE 01229 cbsubst_ret_val(self, val) 01230 VALUE self; 01231 VALUE val; 01232 { 01233 /* This method may be overwritten on some sub-classes. */ 01234 /* This method is used for converting from ruby's callback-return-value */ 01235 /* to tcl's value (e.g. validation procedure of entry widget). */ 01236 return val; 01237 } 01238 01239 static int 01240 each_attr_def(key, value, klass) 01241 VALUE key, value, klass; 01242 { 01243 ID key_id, value_id; 01244 01245 if (key == Qundef) return ST_CONTINUE; 01246 01247 switch(TYPE(key)) { 01248 case T_STRING: 01249 key_id = rb_intern_str(key); 01250 break; 01251 case T_SYMBOL: 01252 key_id = SYM2ID(key); 01253 break; 01254 default: 01255 rb_raise(rb_eArgError, 01256 "includes invalid key(s). expected a String or a Symbol"); 01257 } 01258 01259 switch(TYPE(value)) { 01260 case T_STRING: 01261 value_id = rb_intern_str(value); 01262 break; 01263 case T_SYMBOL: 01264 value_id = SYM2ID(value); 01265 break; 01266 default: 01267 rb_raise(rb_eArgError, 01268 "includes invalid value(s). expected a String or a Symbol"); 01269 } 01270 01271 rb_alias(klass, key_id, value_id); 01272 01273 return ST_CONTINUE; 01274 } 01275 01276 static VALUE 01277 cbsubst_def_attr_aliases(self, tbl) 01278 VALUE self; 01279 VALUE tbl; 01280 { 01281 struct cbsubst_info *inf; 01282 01283 if (TYPE(tbl) != T_HASH) { 01284 rb_raise(rb_eArgError, "expected a Hash"); 01285 } 01286 01287 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01288 struct cbsubst_info, inf); 01289 01290 rb_hash_foreach(tbl, each_attr_def, self); 01291 01292 return rb_funcall(inf->aliases, rb_intern("update"), 1, tbl); 01293 } 01294 01295 static VALUE 01296 cbsubst_sym_to_subst(self, sym) 01297 VALUE self; 01298 VALUE sym; 01299 { 01300 struct cbsubst_info *inf; 01301 VALUE str; 01302 char *buf, *ptr; 01303 int idx; 01304 long len; 01305 ID id; 01306 volatile VALUE ret; 01307 01308 if (TYPE(sym) != T_SYMBOL) return sym; 01309 01310 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01311 struct cbsubst_info, inf); 01312 01313 if (!NIL_P(ret = rb_hash_aref(inf->aliases, sym))) { 01314 str = rb_id2str(SYM2ID(ret)); 01315 } else { 01316 str = rb_id2str(SYM2ID(sym)); 01317 } 01318 01319 id = rb_intern_str(rb_sprintf("@%"PRIsVALUE, str)); 01320 01321 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01322 if (inf->ivar[idx] == id) break; 01323 } 01324 if (idx >= CBSUBST_TBL_MAX) return sym; 01325 01326 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 01327 01328 *(ptr++) = '%'; 01329 01330 if (len = inf->keylen[idx]) { 01331 /* longname */ 01332 strncpy(ptr, inf->key[idx], len); 01333 ptr += len; 01334 } else { 01335 /* single char */ 01336 *(ptr++) = (unsigned char)idx; 01337 } 01338 01339 *(ptr++) = ' '; 01340 *(ptr++) = '\0'; 01341 01342 ret = rb_str_new2(buf); 01343 01344 xfree(buf); 01345 01346 return ret; 01347 } 01348 01349 static VALUE 01350 cbsubst_get_subst_arg(argc, argv, self) 01351 int argc; 01352 VALUE *argv; 01353 VALUE self; 01354 { 01355 struct cbsubst_info *inf; 01356 VALUE str; 01357 char *buf, *ptr; 01358 int i, idx; 01359 long len; 01360 ID id; 01361 volatile VALUE arg_sym, ret; 01362 01363 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01364 struct cbsubst_info, inf); 01365 01366 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 01367 01368 for(i = 0; i < argc; i++) { 01369 switch(TYPE(argv[i])) { 01370 case T_STRING: 01371 str = argv[i]; 01372 arg_sym = ID2SYM(rb_intern_str(argv[i])); 01373 break; 01374 case T_SYMBOL: 01375 arg_sym = argv[i]; 01376 str = rb_id2str(SYM2ID(arg_sym)); 01377 break; 01378 default: 01379 rb_raise(rb_eArgError, "arg #%d is not a String or a Symbol", i); 01380 } 01381 01382 if (!NIL_P(ret = rb_hash_aref(inf->aliases, arg_sym))) { 01383 str = rb_id2str(SYM2ID(ret)); 01384 } 01385 01386 id = rb_intern_str(rb_sprintf("@%"PRIsVALUE, str)); 01387 01388 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01389 if (inf->ivar[idx] == id) break; 01390 } 01391 if (idx >= CBSUBST_TBL_MAX) { 01392 rb_raise(rb_eArgError, "cannot find attribute :%"PRIsVALUE, str); 01393 } 01394 01395 *(ptr++) = '%'; 01396 01397 if (len = inf->keylen[idx]) { 01398 /* longname */ 01399 strncpy(ptr, inf->key[idx], len); 01400 ptr += len; 01401 } else { 01402 /* single char */ 01403 *(ptr++) = (unsigned char)idx; 01404 } 01405 01406 *(ptr++) = ' '; 01407 } 01408 01409 *ptr = '\0'; 01410 01411 ret = rb_str_new2(buf); 01412 01413 xfree(buf); 01414 01415 return ret; 01416 } 01417 01418 static VALUE 01419 cbsubst_get_subst_key(self, str) 01420 VALUE self; 01421 VALUE str; 01422 { 01423 struct cbsubst_info *inf; 01424 volatile VALUE list; 01425 volatile VALUE ret; 01426 VALUE keyval; 01427 long i, len, keylen; 01428 int idx; 01429 char *buf, *ptr, *key; 01430 01431 list = rb_funcall(cTclTkLib, ID_split_tklist, 1, str); 01432 len = RARRAY_LEN(list); 01433 01434 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01435 struct cbsubst_info, inf); 01436 01437 ptr = buf = ALLOC_N(char, inf->full_subst_length + len + 1); 01438 01439 for(i = 0; i < len; i++) { 01440 keyval = RARRAY_PTR(list)[i]; 01441 key = RSTRING_PTR(keyval); 01442 if (*key == '%') { 01443 if (*(key + 2) == '\0') { 01444 /* single char */ 01445 *(ptr++) = *(key + 1); 01446 } else { 01447 /* search longname-key */ 01448 keylen = RSTRING_LEN(keyval) - 1; 01449 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01450 if (inf->keylen[idx] != keylen) continue; 01451 if ((unsigned char)inf->key[idx][0] != (unsigned char)*(key + 1)) continue; 01452 if (strncmp(inf->key[idx], key + 1, keylen)) continue; 01453 break; 01454 } 01455 if (idx < CBSUBST_TBL_MAX) { 01456 *(ptr++) = (unsigned char)idx; 01457 } else { 01458 *(ptr++) = ' '; 01459 } 01460 } 01461 } else { 01462 *(ptr++) = ' '; 01463 } 01464 } 01465 *ptr = '\0'; 01466 01467 ret = rb_str_new2(buf); 01468 xfree(buf); 01469 return ret; 01470 } 01471 01472 static VALUE 01473 cbsubst_get_all_subst_keys(self) 01474 VALUE self; 01475 { 01476 struct cbsubst_info *inf; 01477 char *buf, *ptr; 01478 char *keys_buf, *keys_ptr; 01479 int idx; 01480 long len; 01481 volatile VALUE ret; 01482 01483 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01484 struct cbsubst_info, inf); 01485 01486 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 01487 keys_ptr = keys_buf = ALLOC_N(char, CBSUBST_TBL_MAX + 1); 01488 01489 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01490 if (inf->ivar[idx] == (ID) 0) continue; 01491 01492 *(keys_ptr++) = (unsigned char)idx; 01493 01494 *(ptr++) = '%'; 01495 01496 if (len = inf->keylen[idx]) { 01497 /* longname */ 01498 strncpy(ptr, inf->key[idx], len); 01499 ptr += len; 01500 } else { 01501 /* single char */ 01502 *(ptr++) = (unsigned char)idx; 01503 } 01504 01505 *(ptr++) = ' '; 01506 } 01507 01508 *ptr = '\0'; 01509 *keys_ptr = '\0'; 01510 01511 ret = rb_ary_new3(2, rb_str_new2(keys_buf), rb_str_new2(buf)); 01512 01513 xfree(buf); 01514 xfree(keys_buf); 01515 01516 return ret; 01517 } 01518 01519 static VALUE 01520 cbsubst_table_setup(argc, argv, self) 01521 int argc; 01522 VALUE *argv; 01523 VALUE self; 01524 { 01525 volatile VALUE cbsubst_obj; 01526 volatile VALUE key_inf; 01527 volatile VALUE longkey_inf; 01528 volatile VALUE proc_inf; 01529 VALUE inf; 01530 ID id; 01531 struct cbsubst_info *subst_inf; 01532 long idx, len; 01533 unsigned char chr; 01534 01535 /* accept (key_inf, proc_inf) or (key_inf, longkey_inf, procinf) */ 01536 if (rb_scan_args(argc, argv, "21", &key_inf, &longkey_inf, &proc_inf) == 2) { 01537 proc_inf = longkey_inf; 01538 longkey_inf = rb_ary_new(); 01539 } 01540 01541 /* check the number of longkeys */ 01542 if (RARRAY_LEN(longkey_inf) > 125 /* from 0x80 to 0xFD */) { 01543 rb_raise(rb_eArgError, "too many longname-key definitions"); 01544 } 01545 01546 /* init */ 01547 cbsubst_obj = allocate_cbsubst_info(&subst_inf); 01548 01549 /* 01550 * keys : array of [subst, type, ivar] 01551 * subst ==> char code or string 01552 * type ==> char code or string 01553 * ivar ==> symbol 01554 */ 01555 len = RARRAY_LEN(key_inf); 01556 for(idx = 0; idx < len; idx++) { 01557 inf = RARRAY_PTR(key_inf)[idx]; 01558 if (TYPE(inf) != T_ARRAY) continue; 01559 01560 if (TYPE(RARRAY_PTR(inf)[0]) == T_STRING) { 01561 chr = *(RSTRING_PTR(RARRAY_PTR(inf)[0])); 01562 } else { 01563 chr = NUM2CHR(RARRAY_PTR(inf)[0]); 01564 } 01565 if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) { 01566 subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1])); 01567 } else { 01568 subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]); 01569 } 01570 01571 subst_inf->full_subst_length += 3; 01572 01573 id = SYM2ID(RARRAY_PTR(inf)[2]); 01574 subst_inf->ivar[chr] = rb_intern_str(rb_sprintf("@%"PRIsVALUE, rb_id2str(id))); 01575 01576 rb_attr(self, id, 1, 0, Qtrue); 01577 } 01578 01579 01580 /* 01581 * longkeys : array of [name, type, ivar] 01582 * name ==> longname key string 01583 * type ==> char code or string 01584 * ivar ==> symbol 01585 */ 01586 len = RARRAY_LEN(longkey_inf); 01587 for(idx = 0; idx < len; idx++) { 01588 inf = RARRAY_PTR(longkey_inf)[idx]; 01589 if (TYPE(inf) != T_ARRAY) continue; 01590 01591 chr = (unsigned char)(0x80 + idx); 01592 subst_inf->keylen[chr] = RSTRING_LEN(RARRAY_PTR(inf)[0]); 01593 #if HAVE_STRNDUP 01594 subst_inf->key[chr] = strndup(RSTRING_PTR(RARRAY_PTR(inf)[0]), 01595 RSTRING_LEN(RARRAY_PTR(inf)[0])); 01596 #else 01597 subst_inf->key[chr] = malloc(RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1); 01598 if (subst_inf->key[chr]) { 01599 strncpy(subst_inf->key[chr], RSTRING_PTR(RARRAY_PTR(inf)[0]), 01600 RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1); 01601 subst_inf->key[chr][RSTRING_LEN(RARRAY_PTR(inf)[0])] = '\0'; 01602 } 01603 #endif 01604 if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) { 01605 subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1])); 01606 } else { 01607 subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]); 01608 } 01609 01610 subst_inf->full_subst_length += (subst_inf->keylen[chr] + 2); 01611 01612 id = SYM2ID(RARRAY_PTR(inf)[2]); 01613 subst_inf->ivar[chr] = rb_intern_str(rb_sprintf("@%"PRIsVALUE, rb_id2str(id))); 01614 01615 rb_attr(self, id, 1, 0, Qtrue); 01616 } 01617 01618 /* 01619 * procs : array of [type, proc] 01620 * type ==> char code or string 01621 * proc ==> proc/method/obj (must respond to 'call') 01622 */ 01623 len = RARRAY_LEN(proc_inf); 01624 for(idx = 0; idx < len; idx++) { 01625 inf = RARRAY_PTR(proc_inf)[idx]; 01626 if (TYPE(inf) != T_ARRAY) continue; 01627 rb_hash_aset(subst_inf->proc, 01628 ((TYPE(RARRAY_PTR(inf)[0]) == T_STRING)? 01629 INT2FIX(*(RSTRING_PTR(RARRAY_PTR(inf)[0]))) : 01630 RARRAY_PTR(inf)[0]), 01631 RARRAY_PTR(inf)[1]); 01632 } 01633 01634 rb_const_set(self, ID_SUBST_INFO, cbsubst_obj); 01635 01636 return self; 01637 } 01638 01639 static VALUE 01640 cbsubst_get_extra_args_tbl(self) 01641 VALUE self; 01642 { 01643 return rb_ary_new(); 01644 } 01645 01646 static VALUE 01647 cbsubst_scan_args(self, arg_key, val_ary) 01648 VALUE self; 01649 VALUE arg_key; 01650 VALUE val_ary; 01651 { 01652 struct cbsubst_info *inf; 01653 long idx; 01654 unsigned char *keyptr = (unsigned char*)RSTRING_PTR(arg_key); 01655 long keylen = RSTRING_LEN(arg_key); 01656 long vallen = RARRAY_LEN(val_ary); 01657 unsigned char type_chr; 01658 volatile VALUE dst = rb_ary_new2(vallen); 01659 volatile VALUE proc; 01660 int thr_crit_bup; 01661 VALUE old_gc; 01662 01663 thr_crit_bup = rb_thread_critical; 01664 rb_thread_critical = Qtrue; 01665 01666 old_gc = rb_gc_disable(); 01667 01668 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01669 struct cbsubst_info, inf); 01670 01671 for(idx = 0; idx < vallen; idx++) { 01672 if (idx >= keylen) { 01673 proc = Qnil; 01674 } else if (*(keyptr + idx) == ' ') { 01675 proc = Qnil; 01676 } else { 01677 if (type_chr = inf->type[*(keyptr + idx)]) { 01678 proc = rb_hash_aref(inf->proc, INT2FIX((int)type_chr)); 01679 } else { 01680 proc = Qnil; 01681 } 01682 } 01683 01684 if (NIL_P(proc)) { 01685 rb_ary_push(dst, RARRAY_PTR(val_ary)[idx]); 01686 } else { 01687 rb_ary_push(dst, rb_funcall(proc, ID_call, 1, 01688 RARRAY_PTR(val_ary)[idx])); 01689 } 01690 } 01691 01692 if (old_gc == Qfalse) rb_gc_enable(); 01693 rb_thread_critical = thr_crit_bup; 01694 01695 return dst; 01696 } 01697 01698 static VALUE 01699 cbsubst_inspect(self) 01700 VALUE self; 01701 { 01702 return rb_str_new2("CallbackSubst"); 01703 } 01704 01705 static VALUE 01706 substinfo_inspect(self) 01707 VALUE self; 01708 { 01709 return rb_str_new2("SubstInfo"); 01710 } 01711 01712 /*************************************/ 01713 01714 static VALUE 01715 tk_cbe_inspect(self) 01716 VALUE self; 01717 { 01718 return rb_str_new2("TkCallbackEntry"); 01719 } 01720 01721 /*************************************/ 01722 01723 static VALUE 01724 tkobj_path(self) 01725 VALUE self; 01726 { 01727 return rb_ivar_get(self, ID_at_path); 01728 } 01729 01730 01731 /*************************************/ 01732 /* release date */ 01733 const char tkutil_release_date[] = TKUTIL_RELEASE_DATE; 01734 01735 void 01736 Init_tkutil() 01737 { 01738 VALUE cTK = rb_define_class("TkKernel", rb_cObject); 01739 VALUE mTK = rb_define_module("TkUtil"); 01740 01741 /* --------------------- */ 01742 01743 rb_define_const(mTK, "RELEASE_DATE", 01744 rb_obj_freeze(rb_str_new2(tkutil_release_date))); 01745 01746 /* --------------------- */ 01747 rb_global_variable(&cMethod); 01748 cMethod = rb_const_get(rb_cObject, rb_intern("Method")); 01749 01750 ID_path = rb_intern("path"); 01751 ID_at_path = rb_intern("@path"); 01752 ID_at_enc = rb_intern("@encoding"); 01753 ID_to_eval = rb_intern("to_eval"); 01754 ID_to_s = rb_intern("to_s"); 01755 ID_source = rb_intern("source"); 01756 ID_downcase = rb_intern("downcase"); 01757 ID_install_cmd = rb_intern("install_cmd"); 01758 ID_merge_tklist = rb_intern("_merge_tklist"); 01759 ID_encoding = rb_intern("encoding"); 01760 ID_encoding_system = rb_intern("encoding_system"); 01761 ID_call = rb_intern("call"); 01762 01763 /* --------------------- */ 01764 cCB_SUBST = rb_define_class_under(mTK, "CallbackSubst", rb_cObject); 01765 rb_define_singleton_method(cCB_SUBST, "inspect", cbsubst_inspect, 0); 01766 01767 cSUBST_INFO = rb_define_class_under(cCB_SUBST, "Info", rb_cObject); 01768 rb_define_singleton_method(cSUBST_INFO, "inspect", substinfo_inspect, 0); 01769 01770 ID_SUBST_INFO = rb_intern("SUBST_INFO"); 01771 rb_define_singleton_method(cCB_SUBST, "ret_val", cbsubst_ret_val, 1); 01772 rb_define_singleton_method(cCB_SUBST, "scan_args", cbsubst_scan_args, 2); 01773 rb_define_singleton_method(cCB_SUBST, "_sym2subst", 01774 cbsubst_sym_to_subst, 1); 01775 rb_define_singleton_method(cCB_SUBST, "subst_arg", 01776 cbsubst_get_subst_arg, -1); 01777 rb_define_singleton_method(cCB_SUBST, "_get_subst_key", 01778 cbsubst_get_subst_key, 1); 01779 rb_define_singleton_method(cCB_SUBST, "_get_all_subst_keys", 01780 cbsubst_get_all_subst_keys, 0); 01781 rb_define_singleton_method(cCB_SUBST, "_setup_subst_table", 01782 cbsubst_table_setup, -1); 01783 rb_define_singleton_method(cCB_SUBST, "_get_extra_args_tbl", 01784 cbsubst_get_extra_args_tbl, 0); 01785 rb_define_singleton_method(cCB_SUBST, "_define_attribute_aliases", 01786 cbsubst_def_attr_aliases, 1); 01787 01788 rb_define_method(cCB_SUBST, "initialize", cbsubst_initialize, -1); 01789 01790 cbsubst_init(); 01791 01792 /* --------------------- */ 01793 rb_global_variable(&cTkCallbackEntry); 01794 cTkCallbackEntry = rb_define_class("TkCallbackEntry", cTK); 01795 rb_define_singleton_method(cTkCallbackEntry, "inspect", tk_cbe_inspect, 0); 01796 01797 /* --------------------- */ 01798 rb_global_variable(&cTkObject); 01799 cTkObject = rb_define_class("TkObject", cTK); 01800 rb_define_method(cTkObject, "path", tkobj_path, 0); 01801 01802 /* --------------------- */ 01803 rb_require("tcltklib"); 01804 rb_global_variable(&cTclTkLib); 01805 cTclTkLib = rb_const_get(rb_cObject, rb_intern("TclTkLib")); 01806 ID_split_tklist = rb_intern("_split_tklist"); 01807 ID_toUTF8 = rb_intern("_toUTF8"); 01808 ID_fromUTF8 = rb_intern("_fromUTF8"); 01809 01810 /* --------------------- */ 01811 rb_define_singleton_method(cTK, "new", tk_s_new, -1); 01812 01813 /* --------------------- */ 01814 rb_global_variable(&TK_None); 01815 TK_None = rb_obj_alloc(rb_cObject); 01816 rb_define_const(mTK, "None", TK_None); 01817 rb_define_singleton_method(TK_None, "to_s", tkNone_to_s, 0); 01818 rb_define_singleton_method(TK_None, "inspect", tkNone_inspect, 0); 01819 OBJ_FREEZE(TK_None); 01820 01821 /* --------------------- */ 01822 rb_global_variable(&CALLBACK_TABLE); 01823 CALLBACK_TABLE = rb_hash_new(); 01824 01825 /* --------------------- */ 01826 rb_define_singleton_method(mTK, "untrust", tk_obj_untrust, 1); 01827 01828 rb_define_singleton_method(mTK, "eval_cmd", tk_eval_cmd, -1); 01829 rb_define_singleton_method(mTK, "callback", tk_do_callback, -1); 01830 rb_define_singleton_method(mTK, "install_cmd", tk_install_cmd, -1); 01831 rb_define_singleton_method(mTK, "uninstall_cmd", tk_uninstall_cmd, 1); 01832 rb_define_singleton_method(mTK, "_symbolkey2str", tk_symbolkey2str, 1); 01833 rb_define_singleton_method(mTK, "hash_kv", tk_hash_kv, -1); 01834 rb_define_singleton_method(mTK, "_get_eval_string", 01835 tk_get_eval_string, -1); 01836 rb_define_singleton_method(mTK, "_get_eval_enc_str", 01837 tk_get_eval_enc_str, 1); 01838 rb_define_singleton_method(mTK, "_conv_args", tk_conv_args, -1); 01839 01840 rb_define_singleton_method(mTK, "bool", tcl2rb_bool, 1); 01841 rb_define_singleton_method(mTK, "number", tcl2rb_number, 1); 01842 rb_define_singleton_method(mTK, "string", tcl2rb_string, 1); 01843 rb_define_singleton_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); 01844 rb_define_singleton_method(mTK, "num_or_nil", tcl2rb_num_or_nil, 1); 01845 01846 rb_define_method(mTK, "_toUTF8", tk_toUTF8, -1); 01847 rb_define_method(mTK, "_fromUTF8", tk_fromUTF8, -1); 01848 rb_define_method(mTK, "_symbolkey2str", tk_symbolkey2str, 1); 01849 rb_define_method(mTK, "hash_kv", tk_hash_kv, -1); 01850 rb_define_method(mTK, "_get_eval_string", tk_get_eval_string, -1); 01851 rb_define_method(mTK, "_get_eval_enc_str", tk_get_eval_enc_str, 1); 01852 rb_define_method(mTK, "_conv_args", tk_conv_args, -1); 01853 01854 rb_define_method(mTK, "bool", tcl2rb_bool, 1); 01855 rb_define_method(mTK, "number", tcl2rb_number, 1); 01856 rb_define_method(mTK, "string", tcl2rb_string, 1); 01857 rb_define_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); 01858 rb_define_method(mTK, "num_or_nil", tcl2rb_num_or_nil, 1); 01859 01860 /* --------------------- */ 01861 rb_global_variable(&ENCODING_NAME_UTF8); 01862 ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); 01863 01864 /* --------------------- */ 01865 } 01866
1.7.6.1