Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /************************************************ 00002 00003 tkutil.c - 00004 00005 $Author: nobu $ 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 VALUE 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 int head_len = strlen(cmd_id_head); 00206 int 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 if (key == Qundef) return ST_CONTINUE; 00270 rb_hash_aset(hash, rb_funcall(key, ID_to_s, 0, 0), value); 00271 return ST_CHECK; 00272 } 00273 00274 static VALUE 00275 tk_symbolkey2str(self, keys) 00276 VALUE self; 00277 VALUE keys; 00278 { 00279 volatile VALUE new_keys = rb_hash_new(); 00280 00281 if NIL_P(keys) return new_keys; 00282 keys = rb_convert_type(keys, T_HASH, "Hash", "to_hash"); 00283 st_foreach(RHASH_TBL(keys), to_strkey, new_keys); 00284 return new_keys; 00285 } 00286 00287 static VALUE get_eval_string_core _((VALUE, VALUE, VALUE)); 00288 static VALUE ary2list _((VALUE, VALUE, VALUE)); 00289 static VALUE ary2list2 _((VALUE, VALUE, VALUE)); 00290 static VALUE hash2list _((VALUE, VALUE)); 00291 static VALUE hash2list_enc _((VALUE, VALUE)); 00292 static VALUE hash2kv _((VALUE, VALUE, VALUE)); 00293 static VALUE hash2kv_enc _((VALUE, VALUE, VALUE)); 00294 00295 static VALUE 00296 ary2list(ary, enc_flag, self) 00297 VALUE ary; 00298 VALUE enc_flag; 00299 VALUE self; 00300 { 00301 int idx, idx2, size, size2, 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 int idx, size, req_chk_flag; 00455 volatile VALUE val, str_val; 00456 volatile VALUE dst; 00457 volatile VALUE sys_enc, dst_enc, str_enc; 00458 00459 sys_enc = rb_funcall(cTclTkLib, ID_encoding, 0, 0); 00460 if NIL_P(sys_enc) { 00461 sys_enc = rb_funcall(cTclTkLib, ID_encoding_system, 0, 0); 00462 sys_enc = rb_funcall(sys_enc, ID_to_s, 0, 0); 00463 } 00464 00465 if NIL_P(enc_flag) { 00466 dst_enc = sys_enc; 00467 req_chk_flag = 1; 00468 } else if (TYPE(enc_flag) == T_TRUE || TYPE(enc_flag) == T_FALSE) { 00469 dst_enc = enc_flag; 00470 req_chk_flag = 0; 00471 } else { 00472 dst_enc = rb_funcall(enc_flag, ID_to_s, 0, 0); 00473 req_chk_flag = 0; 00474 } 00475 00476 size = RARRAY_LEN(ary); 00477 dst = rb_ary_new2(size); 00478 for(idx = 0; idx < RARRAY_LEN(ary); idx++) { 00479 val = RARRAY_PTR(ary)[idx]; 00480 str_val = Qnil; 00481 switch(TYPE(val)) { 00482 case T_ARRAY: 00483 str_val = ary2list(val, enc_flag, self); 00484 break; 00485 00486 case T_HASH: 00487 if (RTEST(enc_flag)) { 00488 str_val = hash2list(val, self); 00489 } else { 00490 str_val = hash2list_enc(val, self); 00491 } 00492 break; 00493 00494 default: 00495 if (val != TK_None) { 00496 str_val = get_eval_string_core(val, enc_flag, self); 00497 } 00498 } 00499 00500 if (!NIL_P(str_val)) { 00501 rb_ary_push(dst, str_val); 00502 00503 if (req_chk_flag) { 00504 str_enc = rb_ivar_get(str_val, ID_at_enc); 00505 if (!NIL_P(str_enc)) { 00506 str_enc = rb_funcall(str_enc, ID_to_s, 0, 0); 00507 } else { 00508 str_enc = sys_enc; 00509 } 00510 if (!rb_str_cmp(str_enc, dst_enc)) { 00511 dst_enc = Qtrue; 00512 req_chk_flag = 0; 00513 } 00514 } 00515 } 00516 } 00517 00518 if (RTEST(dst_enc) && !NIL_P(sys_enc)) { 00519 for(idx = 0; idx < RARRAY_LEN(dst); idx++) { 00520 str_val = RARRAY_PTR(dst)[idx]; 00521 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 00522 str_val = rb_funcall(self, ID_toUTF8, 1, str_val); 00523 } else { 00524 str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val); 00525 } 00526 RARRAY_PTR(dst)[idx] = str_val; 00527 } 00528 val = rb_apply(cTclTkLib, ID_merge_tklist, dst); 00529 if (TYPE(dst_enc) == T_STRING) { 00530 val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); 00531 rb_ivar_set(val, ID_at_enc, dst_enc); 00532 } else { 00533 rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); 00534 } 00535 return val; 00536 } else { 00537 return rb_apply(cTclTkLib, ID_merge_tklist, dst); 00538 } 00539 } 00540 00541 static VALUE 00542 key2keyname(key) 00543 VALUE key; 00544 { 00545 return rb_str_append(rb_str_new2("-"), rb_funcall(key, ID_to_s, 0, 0)); 00546 } 00547 00548 static VALUE 00549 assoc2kv(assoc, ary, self) 00550 VALUE assoc; 00551 VALUE ary; 00552 VALUE self; 00553 { 00554 int i, j, len; 00555 volatile VALUE pair; 00556 volatile VALUE val; 00557 volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); 00558 00559 len = RARRAY_LEN(assoc); 00560 00561 for(i = 0; i < len; i++) { 00562 pair = RARRAY_PTR(assoc)[i]; 00563 if (TYPE(pair) != T_ARRAY) { 00564 rb_ary_push(dst, key2keyname(pair)); 00565 continue; 00566 } 00567 switch(RARRAY_LEN(assoc)) { 00568 case 2: 00569 rb_ary_push(dst, RARRAY_PTR(pair)[2]); 00570 00571 case 1: 00572 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00573 00574 case 0: 00575 continue; 00576 00577 default: 00578 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00579 00580 val = rb_ary_new2(RARRAY_LEN(pair) - 1); 00581 for(j = 1; j < RARRAY_LEN(pair); j++) { 00582 rb_ary_push(val, RARRAY_PTR(pair)[j]); 00583 } 00584 00585 rb_ary_push(dst, val); 00586 } 00587 } 00588 00589 if (NIL_P(ary)) { 00590 return dst; 00591 } else { 00592 return rb_ary_plus(ary, dst); 00593 } 00594 } 00595 00596 static VALUE 00597 assoc2kv_enc(assoc, ary, self) 00598 VALUE assoc; 00599 VALUE ary; 00600 VALUE self; 00601 { 00602 int i, j, len; 00603 volatile VALUE pair; 00604 volatile VALUE val; 00605 volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); 00606 00607 len = RARRAY_LEN(assoc); 00608 00609 for(i = 0; i < len; i++) { 00610 pair = RARRAY_PTR(assoc)[i]; 00611 if (TYPE(pair) != T_ARRAY) { 00612 rb_ary_push(dst, key2keyname(pair)); 00613 continue; 00614 } 00615 switch(RARRAY_LEN(assoc)) { 00616 case 2: 00617 rb_ary_push(dst, get_eval_string_core(RARRAY_PTR(pair)[2], Qtrue, self)); 00618 00619 case 1: 00620 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00621 00622 case 0: 00623 continue; 00624 00625 default: 00626 rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); 00627 00628 val = rb_ary_new2(RARRAY_LEN(pair) - 1); 00629 for(j = 1; j < RARRAY_LEN(pair); j++) { 00630 rb_ary_push(val, RARRAY_PTR(pair)[j]); 00631 } 00632 00633 rb_ary_push(dst, get_eval_string_core(val, Qtrue, self)); 00634 } 00635 } 00636 00637 if (NIL_P(ary)) { 00638 return dst; 00639 } else { 00640 return rb_ary_plus(ary, dst); 00641 } 00642 } 00643 00644 static int 00645 push_kv(key, val, args) 00646 VALUE key; 00647 VALUE val; 00648 VALUE args; 00649 { 00650 volatile VALUE ary; 00651 00652 ary = RARRAY_PTR(args)[0]; 00653 00654 if (key == Qundef) return ST_CONTINUE; 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(RHASH_TBL(hash), push_kv, args); 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 (key == Qundef) return ST_CONTINUE; 00697 #if 0 00698 rb_ary_push(ary, key2keyname(key)); 00699 if (val != TK_None) { 00700 rb_ary_push(ary, get_eval_string_core(val, Qtrue, 00701 RARRAY_PTR(args)[1])); 00702 } 00703 #endif 00704 rb_ary_push(ary, key2keyname(key)); 00705 00706 if (val == TK_None) return ST_CHECK; 00707 00708 rb_ary_push(ary, get_eval_string_core(val, Qtrue, RARRAY_PTR(args)[1])); 00709 00710 return ST_CHECK; 00711 } 00712 00713 static VALUE 00714 hash2kv_enc(hash, ary, self) 00715 VALUE hash; 00716 VALUE ary; 00717 VALUE self; 00718 { 00719 volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash)); 00720 volatile VALUE args = rb_ary_new3(2, dst, self); 00721 00722 st_foreach(RHASH_TBL(hash), push_kv_enc, args); 00723 00724 if (NIL_P(ary)) { 00725 return dst; 00726 } else { 00727 return rb_ary_concat(ary, dst); 00728 } 00729 } 00730 00731 static VALUE 00732 hash2list(hash, self) 00733 VALUE hash; 00734 VALUE self; 00735 { 00736 return ary2list2(hash2kv(hash, Qnil, self), Qfalse, self); 00737 } 00738 00739 00740 static VALUE 00741 hash2list_enc(hash, self) 00742 VALUE hash; 00743 VALUE self; 00744 { 00745 return ary2list2(hash2kv_enc(hash, Qnil, self), Qfalse, self); 00746 } 00747 00748 static VALUE 00749 tk_hash_kv(argc, argv, self) 00750 int argc; 00751 VALUE *argv; 00752 VALUE self; 00753 { 00754 volatile VALUE hash, enc_flag, ary; 00755 00756 ary = Qnil; 00757 enc_flag = Qnil; 00758 switch(argc) { 00759 case 3: 00760 ary = argv[2]; 00761 case 2: 00762 enc_flag = argv[1]; 00763 case 1: 00764 hash = argv[0]; 00765 break; 00766 case 0: 00767 rb_raise(rb_eArgError, "too few arguments"); 00768 default: /* >= 3 */ 00769 rb_raise(rb_eArgError, "too many arguments"); 00770 } 00771 00772 switch(TYPE(hash)) { 00773 case T_ARRAY: 00774 if (RTEST(enc_flag)) { 00775 return assoc2kv_enc(hash, ary, self); 00776 } else { 00777 return assoc2kv(hash, ary, self); 00778 } 00779 00780 case T_HASH: 00781 if (RTEST(enc_flag)) { 00782 return hash2kv_enc(hash, ary, self); 00783 } else { 00784 return hash2kv(hash, ary, self); 00785 } 00786 00787 case T_NIL: 00788 if (NIL_P(ary)) { 00789 return rb_ary_new(); 00790 } else { 00791 return ary; 00792 } 00793 00794 default: 00795 if (hash == TK_None) { 00796 if (NIL_P(ary)) { 00797 return rb_ary_new(); 00798 } else { 00799 return ary; 00800 } 00801 } 00802 rb_raise(rb_eArgError, "Hash is expected for 1st argument"); 00803 } 00804 } 00805 00806 static VALUE 00807 get_eval_string_core(obj, enc_flag, self) 00808 VALUE obj; 00809 VALUE enc_flag; 00810 VALUE self; 00811 { 00812 switch(TYPE(obj)) { 00813 case T_FLOAT: 00814 case T_FIXNUM: 00815 case T_BIGNUM: 00816 return rb_funcall(obj, ID_to_s, 0, 0); 00817 00818 case T_STRING: 00819 if (RTEST(enc_flag)) { 00820 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 00821 return rb_funcall(self, ID_toUTF8, 1, obj); 00822 } else { 00823 return fromDefaultEnc_toUTF8(obj, self); 00824 } 00825 } else { 00826 return obj; 00827 } 00828 00829 case T_SYMBOL: 00830 if (RTEST(enc_flag)) { 00831 if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { 00832 return rb_funcall(self, ID_toUTF8, 1, 00833 rb_str_new2(rb_id2name(SYM2ID(obj)))); 00834 } else { 00835 return fromDefaultEnc_toUTF8(rb_str_new2(rb_id2name(SYM2ID(obj))), self); 00836 } 00837 } else { 00838 #ifdef HAVE_RB_SYM_TO_S 00839 return rb_sym_to_s(obj); 00840 #else 00841 return rb_str_new2(rb_id2name(SYM2ID(obj))); 00842 #endif 00843 } 00844 00845 case T_HASH: 00846 if (RTEST(enc_flag)) { 00847 return hash2list_enc(obj, self); 00848 } else { 00849 return hash2list(obj, self); 00850 } 00851 00852 case T_ARRAY: 00853 return ary2list(obj, enc_flag, self); 00854 00855 case T_FALSE: 00856 return rb_str_new2("0"); 00857 00858 case T_TRUE: 00859 return rb_str_new2("1"); 00860 00861 case T_NIL: 00862 return rb_str_new2(""); 00863 00864 case T_REGEXP: 00865 return rb_funcall(obj, ID_source, 0, 0); 00866 00867 default: 00868 if (rb_obj_is_kind_of(obj, cTkObject)) { 00869 /* return rb_str_new3(rb_funcall(obj, ID_path, 0, 0)); */ 00870 return get_eval_string_core(rb_funcall(obj, ID_path, 0, 0), 00871 enc_flag, self); 00872 } 00873 00874 if (rb_obj_is_kind_of(obj, rb_cProc) 00875 || rb_obj_is_kind_of(obj, cMethod) 00876 || rb_obj_is_kind_of(obj, cTkCallbackEntry)) { 00877 if (rb_obj_respond_to(self, ID_install_cmd, Qtrue)) { 00878 return rb_funcall(self, ID_install_cmd, 1, obj); 00879 } else { 00880 return tk_install_cmd_core(obj); 00881 } 00882 } 00883 00884 if (obj == TK_None) return Qnil; 00885 00886 if (rb_obj_respond_to(obj, ID_to_eval, Qtrue)) { 00887 /* return rb_funcall(obj, ID_to_eval, 0, 0); */ 00888 return get_eval_string_core(rb_funcall(obj, ID_to_eval, 0, 0), 00889 enc_flag, self); 00890 } else if (rb_obj_respond_to(obj, ID_path, Qtrue)) { 00891 /* return rb_funcall(obj, ID_path, 0, 0); */ 00892 return get_eval_string_core(rb_funcall(obj, ID_path, 0, 0), 00893 enc_flag, self); 00894 } else if (rb_obj_respond_to(obj, ID_to_s, Qtrue)) { 00895 return rb_funcall(obj, ID_to_s, 0, 0); 00896 } 00897 } 00898 00899 rb_warning("fail to convert '%s' to string for Tk", 00900 RSTRING_PTR(rb_funcall(obj, rb_intern("inspect"), 0, 0))); 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 int 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 int full_subst_length; 01137 int 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(RSTRING_PTR(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(RSTRING_PTR(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 const char *str; 01302 char *buf, *ptr; 01303 int idx, len; 01304 ID id; 01305 volatile VALUE ret; 01306 01307 if (TYPE(sym) != T_SYMBOL) return sym; 01308 01309 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01310 struct cbsubst_info, inf); 01311 01312 if (!NIL_P(ret = rb_hash_aref(inf->aliases, sym))) { 01313 str = rb_id2name(SYM2ID(ret)); 01314 } else { 01315 str = rb_id2name(SYM2ID(sym)); 01316 } 01317 01318 id = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), str))); 01319 01320 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01321 if (inf->ivar[idx] == id) break; 01322 } 01323 if (idx >= CBSUBST_TBL_MAX) return sym; 01324 01325 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 01326 01327 *(ptr++) = '%'; 01328 01329 if (len = inf->keylen[idx]) { 01330 /* longname */ 01331 strncpy(ptr, inf->key[idx], len); 01332 ptr += len; 01333 } else { 01334 /* single char */ 01335 *(ptr++) = (unsigned char)idx; 01336 } 01337 01338 *(ptr++) = ' '; 01339 *(ptr++) = '\0'; 01340 01341 ret = rb_str_new2(buf); 01342 01343 xfree(buf); 01344 01345 return ret; 01346 } 01347 01348 static VALUE 01349 cbsubst_get_subst_arg(argc, argv, self) 01350 int argc; 01351 VALUE *argv; 01352 VALUE self; 01353 { 01354 struct cbsubst_info *inf; 01355 const char *str; 01356 char *buf, *ptr; 01357 int i, idx, len; 01358 ID id; 01359 volatile VALUE arg_sym, ret; 01360 01361 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01362 struct cbsubst_info, inf); 01363 01364 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 01365 01366 for(i = 0; i < argc; i++) { 01367 switch(TYPE(argv[i])) { 01368 case T_STRING: 01369 str = RSTRING_PTR(argv[i]); 01370 arg_sym = ID2SYM(rb_intern(str)); 01371 break; 01372 case T_SYMBOL: 01373 arg_sym = argv[i]; 01374 str = rb_id2name(SYM2ID(arg_sym)); 01375 break; 01376 default: 01377 rb_raise(rb_eArgError, "arg #%d is not a String or a Symbol", i); 01378 } 01379 01380 if (!NIL_P(ret = rb_hash_aref(inf->aliases, arg_sym))) { 01381 str = rb_id2name(SYM2ID(ret)); 01382 } 01383 01384 id = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), str))); 01385 01386 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01387 if (inf->ivar[idx] == id) break; 01388 } 01389 if (idx >= CBSUBST_TBL_MAX) { 01390 rb_raise(rb_eArgError, "cannot find attribute :%s", str); 01391 } 01392 01393 *(ptr++) = '%'; 01394 01395 if (len = inf->keylen[idx]) { 01396 /* longname */ 01397 strncpy(ptr, inf->key[idx], len); 01398 ptr += len; 01399 } else { 01400 /* single char */ 01401 *(ptr++) = (unsigned char)idx; 01402 } 01403 01404 *(ptr++) = ' '; 01405 } 01406 01407 *ptr = '\0'; 01408 01409 ret = rb_str_new2(buf); 01410 01411 xfree(buf); 01412 01413 return ret; 01414 } 01415 01416 static VALUE 01417 cbsubst_get_subst_key(self, str) 01418 VALUE self; 01419 VALUE str; 01420 { 01421 struct cbsubst_info *inf; 01422 volatile VALUE list; 01423 volatile VALUE ret; 01424 VALUE keyval; 01425 int i, len, keylen, idx; 01426 char *buf, *ptr, *key; 01427 01428 list = rb_funcall(cTclTkLib, ID_split_tklist, 1, str); 01429 len = RARRAY_LEN(list); 01430 01431 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01432 struct cbsubst_info, inf); 01433 01434 ptr = buf = ALLOC_N(char, inf->full_subst_length + len + 1); 01435 01436 for(i = 0; i < len; i++) { 01437 keyval = RARRAY_PTR(list)[i]; 01438 key = RSTRING_PTR(keyval); 01439 if (*key == '%') { 01440 if (*(key + 2) == '\0') { 01441 /* single char */ 01442 *(ptr++) = *(key + 1); 01443 } else { 01444 /* search longname-key */ 01445 keylen = RSTRING_LEN(keyval) - 1; 01446 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01447 if (inf->keylen[idx] != keylen) continue; 01448 if ((unsigned char)inf->key[idx][0] != (unsigned char)*(key + 1)) continue; 01449 if (strncmp(inf->key[idx], key + 1, keylen)) continue; 01450 break; 01451 } 01452 if (idx < CBSUBST_TBL_MAX) { 01453 *(ptr++) = (unsigned char)idx; 01454 } else { 01455 *(ptr++) = ' '; 01456 } 01457 } 01458 } else { 01459 *(ptr++) = ' '; 01460 } 01461 } 01462 *ptr = '\0'; 01463 01464 ret = rb_str_new2(buf); 01465 xfree(buf); 01466 return ret; 01467 } 01468 01469 static VALUE 01470 cbsubst_get_all_subst_keys(self) 01471 VALUE self; 01472 { 01473 struct cbsubst_info *inf; 01474 char *buf, *ptr; 01475 char *keys_buf, *keys_ptr; 01476 int idx, len; 01477 volatile VALUE ret; 01478 01479 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01480 struct cbsubst_info, inf); 01481 01482 ptr = buf = ALLOC_N(char, inf->full_subst_length + 1); 01483 keys_ptr = keys_buf = ALLOC_N(char, CBSUBST_TBL_MAX + 1); 01484 01485 for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) { 01486 if (inf->ivar[idx] == (ID) 0) continue; 01487 01488 *(keys_ptr++) = (unsigned char)idx; 01489 01490 *(ptr++) = '%'; 01491 01492 if (len = inf->keylen[idx]) { 01493 /* longname */ 01494 strncpy(ptr, inf->key[idx], len); 01495 ptr += len; 01496 } else { 01497 /* single char */ 01498 *(ptr++) = (unsigned char)idx; 01499 } 01500 01501 *(ptr++) = ' '; 01502 } 01503 01504 *ptr = '\0'; 01505 *keys_ptr = '\0'; 01506 01507 ret = rb_ary_new3(2, rb_str_new2(keys_buf), rb_str_new2(buf)); 01508 01509 xfree(buf); 01510 xfree(keys_buf); 01511 01512 return ret; 01513 } 01514 01515 static VALUE 01516 cbsubst_table_setup(argc, argv, self) 01517 int argc; 01518 VALUE *argv; 01519 VALUE self; 01520 { 01521 volatile VALUE cbsubst_obj; 01522 volatile VALUE key_inf; 01523 volatile VALUE longkey_inf; 01524 volatile VALUE proc_inf; 01525 VALUE inf; 01526 ID id; 01527 struct cbsubst_info *subst_inf; 01528 int idx, len; 01529 unsigned char chr; 01530 01531 /* accept (key_inf, proc_inf) or (key_inf, longkey_inf, procinf) */ 01532 if (rb_scan_args(argc, argv, "21", &key_inf, &longkey_inf, &proc_inf) == 2) { 01533 proc_inf = longkey_inf; 01534 longkey_inf = rb_ary_new(); 01535 } 01536 01537 /* check the number of longkeys */ 01538 if (RARRAY_LEN(longkey_inf) > 125 /* from 0x80 to 0xFD */) { 01539 rb_raise(rb_eArgError, "too many longname-key definitions"); 01540 } 01541 01542 /* init */ 01543 cbsubst_obj = allocate_cbsubst_info(&subst_inf); 01544 01545 /* 01546 * keys : array of [subst, type, ivar] 01547 * subst ==> char code or string 01548 * type ==> char code or string 01549 * ivar ==> symbol 01550 */ 01551 len = RARRAY_LEN(key_inf); 01552 for(idx = 0; idx < len; idx++) { 01553 inf = RARRAY_PTR(key_inf)[idx]; 01554 if (TYPE(inf) != T_ARRAY) continue; 01555 01556 if (TYPE(RARRAY_PTR(inf)[0]) == T_STRING) { 01557 chr = *(RSTRING_PTR(RARRAY_PTR(inf)[0])); 01558 } else { 01559 chr = NUM2CHR(RARRAY_PTR(inf)[0]); 01560 } 01561 if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) { 01562 subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1])); 01563 } else { 01564 subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]); 01565 } 01566 01567 subst_inf->full_subst_length += 3; 01568 01569 id = SYM2ID(RARRAY_PTR(inf)[2]); 01570 subst_inf->ivar[chr] = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), rb_id2name(id)))); 01571 01572 rb_attr(self, id, 1, 0, Qtrue); 01573 } 01574 01575 01576 /* 01577 * longkeys : array of [name, type, ivar] 01578 * name ==> longname key string 01579 * type ==> char code or string 01580 * ivar ==> symbol 01581 */ 01582 len = RARRAY_LEN(longkey_inf); 01583 for(idx = 0; idx < len; idx++) { 01584 inf = RARRAY_PTR(longkey_inf)[idx]; 01585 if (TYPE(inf) != T_ARRAY) continue; 01586 01587 chr = (unsigned char)(0x80 + idx); 01588 subst_inf->keylen[chr] = RSTRING_LEN(RARRAY_PTR(inf)[0]); 01589 #if HAVE_STRNDUP 01590 subst_inf->key[chr] = strndup(RSTRING_PTR(RARRAY_PTR(inf)[0]), 01591 RSTRING_LEN(RARRAY_PTR(inf)[0])); 01592 #else 01593 subst_inf->key[chr] = malloc(RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1); 01594 if (subst_inf->key[chr]) { 01595 strncpy(subst_inf->key[chr], RSTRING_PTR(RARRAY_PTR(inf)[0]), 01596 RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1); 01597 subst_inf->key[chr][RSTRING_LEN(RARRAY_PTR(inf)[0])] = '\0'; 01598 } 01599 #endif 01600 if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) { 01601 subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1])); 01602 } else { 01603 subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]); 01604 } 01605 01606 subst_inf->full_subst_length += (subst_inf->keylen[chr] + 2); 01607 01608 id = SYM2ID(RARRAY_PTR(inf)[2]); 01609 subst_inf->ivar[chr] = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), rb_id2name(id)))); 01610 01611 rb_attr(self, id, 1, 0, Qtrue); 01612 } 01613 01614 /* 01615 * procs : array of [type, proc] 01616 * type ==> char code or string 01617 * proc ==> proc/method/obj (must respond to 'call') 01618 */ 01619 len = RARRAY_LEN(proc_inf); 01620 for(idx = 0; idx < len; idx++) { 01621 inf = RARRAY_PTR(proc_inf)[idx]; 01622 if (TYPE(inf) != T_ARRAY) continue; 01623 rb_hash_aset(subst_inf->proc, 01624 ((TYPE(RARRAY_PTR(inf)[0]) == T_STRING)? 01625 INT2FIX(*(RSTRING_PTR(RARRAY_PTR(inf)[0]))) : 01626 RARRAY_PTR(inf)[0]), 01627 RARRAY_PTR(inf)[1]); 01628 } 01629 01630 rb_const_set(self, ID_SUBST_INFO, cbsubst_obj); 01631 01632 return self; 01633 } 01634 01635 static VALUE 01636 cbsubst_get_extra_args_tbl(self) 01637 VALUE self; 01638 { 01639 return rb_ary_new(); 01640 } 01641 01642 static VALUE 01643 cbsubst_scan_args(self, arg_key, val_ary) 01644 VALUE self; 01645 VALUE arg_key; 01646 VALUE val_ary; 01647 { 01648 struct cbsubst_info *inf; 01649 int idx; 01650 unsigned char *keyptr = (unsigned char*)RSTRING_PTR(arg_key); 01651 int keylen = RSTRING_LEN(arg_key); 01652 int vallen = RARRAY_LEN(val_ary); 01653 unsigned char type_chr; 01654 volatile VALUE dst = rb_ary_new2(vallen); 01655 volatile VALUE proc; 01656 int thr_crit_bup; 01657 VALUE old_gc; 01658 01659 thr_crit_bup = rb_thread_critical; 01660 rb_thread_critical = Qtrue; 01661 01662 old_gc = rb_gc_disable(); 01663 01664 Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), 01665 struct cbsubst_info, inf); 01666 01667 for(idx = 0; idx < vallen; idx++) { 01668 if (idx >= keylen) { 01669 proc = Qnil; 01670 } else if (*(keyptr + idx) == ' ') { 01671 proc = Qnil; 01672 } else { 01673 if (type_chr = inf->type[*(keyptr + idx)]) { 01674 proc = rb_hash_aref(inf->proc, INT2FIX((int)type_chr)); 01675 } else { 01676 proc = Qnil; 01677 } 01678 } 01679 01680 if (NIL_P(proc)) { 01681 rb_ary_push(dst, RARRAY_PTR(val_ary)[idx]); 01682 } else { 01683 rb_ary_push(dst, rb_funcall(proc, ID_call, 1, 01684 RARRAY_PTR(val_ary)[idx])); 01685 } 01686 } 01687 01688 if (old_gc == Qfalse) rb_gc_enable(); 01689 rb_thread_critical = thr_crit_bup; 01690 01691 return dst; 01692 } 01693 01694 static VALUE 01695 cbsubst_inspect(self) 01696 VALUE self; 01697 { 01698 return rb_str_new2("CallbackSubst"); 01699 } 01700 01701 static VALUE 01702 substinfo_inspect(self) 01703 VALUE self; 01704 { 01705 return rb_str_new2("SubstInfo"); 01706 } 01707 01708 /*************************************/ 01709 01710 static VALUE 01711 tk_cbe_inspect(self) 01712 VALUE self; 01713 { 01714 return rb_str_new2("TkCallbackEntry"); 01715 } 01716 01717 /*************************************/ 01718 01719 static VALUE 01720 tkobj_path(self) 01721 VALUE self; 01722 { 01723 return rb_ivar_get(self, ID_at_path); 01724 } 01725 01726 01727 /*************************************/ 01728 /* release date */ 01729 const char tkutil_release_date[] = TKUTIL_RELEASE_DATE; 01730 01731 void 01732 Init_tkutil() 01733 { 01734 VALUE cTK = rb_define_class("TkKernel", rb_cObject); 01735 VALUE mTK = rb_define_module("TkUtil"); 01736 01737 /* --------------------- */ 01738 01739 rb_define_const(mTK, "RELEASE_DATE", 01740 rb_obj_freeze(rb_str_new2(tkutil_release_date))); 01741 01742 /* --------------------- */ 01743 rb_global_variable(&cMethod); 01744 cMethod = rb_const_get(rb_cObject, rb_intern("Method")); 01745 01746 ID_path = rb_intern("path"); 01747 ID_at_path = rb_intern("@path"); 01748 ID_at_enc = rb_intern("@encoding"); 01749 ID_to_eval = rb_intern("to_eval"); 01750 ID_to_s = rb_intern("to_s"); 01751 ID_source = rb_intern("source"); 01752 ID_downcase = rb_intern("downcase"); 01753 ID_install_cmd = rb_intern("install_cmd"); 01754 ID_merge_tklist = rb_intern("_merge_tklist"); 01755 ID_encoding = rb_intern("encoding"); 01756 ID_encoding_system = rb_intern("encoding_system"); 01757 ID_call = rb_intern("call"); 01758 01759 /* --------------------- */ 01760 cCB_SUBST = rb_define_class_under(mTK, "CallbackSubst", rb_cObject); 01761 rb_define_singleton_method(cCB_SUBST, "inspect", cbsubst_inspect, 0); 01762 01763 cSUBST_INFO = rb_define_class_under(cCB_SUBST, "Info", rb_cObject); 01764 rb_define_singleton_method(cSUBST_INFO, "inspect", substinfo_inspect, 0); 01765 01766 ID_SUBST_INFO = rb_intern("SUBST_INFO"); 01767 rb_define_singleton_method(cCB_SUBST, "ret_val", cbsubst_ret_val, 1); 01768 rb_define_singleton_method(cCB_SUBST, "scan_args", cbsubst_scan_args, 2); 01769 rb_define_singleton_method(cCB_SUBST, "_sym2subst", 01770 cbsubst_sym_to_subst, 1); 01771 rb_define_singleton_method(cCB_SUBST, "subst_arg", 01772 cbsubst_get_subst_arg, -1); 01773 rb_define_singleton_method(cCB_SUBST, "_get_subst_key", 01774 cbsubst_get_subst_key, 1); 01775 rb_define_singleton_method(cCB_SUBST, "_get_all_subst_keys", 01776 cbsubst_get_all_subst_keys, 0); 01777 rb_define_singleton_method(cCB_SUBST, "_setup_subst_table", 01778 cbsubst_table_setup, -1); 01779 rb_define_singleton_method(cCB_SUBST, "_get_extra_args_tbl", 01780 cbsubst_get_extra_args_tbl, 0); 01781 rb_define_singleton_method(cCB_SUBST, "_define_attribute_aliases", 01782 cbsubst_def_attr_aliases, 1); 01783 01784 rb_define_method(cCB_SUBST, "initialize", cbsubst_initialize, -1); 01785 01786 cbsubst_init(); 01787 01788 /* --------------------- */ 01789 rb_global_variable(&cTkCallbackEntry); 01790 cTkCallbackEntry = rb_define_class("TkCallbackEntry", cTK); 01791 rb_define_singleton_method(cTkCallbackEntry, "inspect", tk_cbe_inspect, 0); 01792 01793 /* --------------------- */ 01794 rb_global_variable(&cTkObject); 01795 cTkObject = rb_define_class("TkObject", cTK); 01796 rb_define_method(cTkObject, "path", tkobj_path, 0); 01797 01798 /* --------------------- */ 01799 rb_require("tcltklib"); 01800 rb_global_variable(&cTclTkLib); 01801 cTclTkLib = rb_const_get(rb_cObject, rb_intern("TclTkLib")); 01802 ID_split_tklist = rb_intern("_split_tklist"); 01803 ID_toUTF8 = rb_intern("_toUTF8"); 01804 ID_fromUTF8 = rb_intern("_fromUTF8"); 01805 01806 /* --------------------- */ 01807 rb_define_singleton_method(cTK, "new", tk_s_new, -1); 01808 01809 /* --------------------- */ 01810 rb_global_variable(&TK_None); 01811 TK_None = rb_obj_alloc(rb_cObject); 01812 rb_define_const(mTK, "None", TK_None); 01813 rb_define_singleton_method(TK_None, "to_s", tkNone_to_s, 0); 01814 rb_define_singleton_method(TK_None, "inspect", tkNone_inspect, 0); 01815 OBJ_FREEZE(TK_None); 01816 01817 /* --------------------- */ 01818 rb_global_variable(&CALLBACK_TABLE); 01819 CALLBACK_TABLE = rb_hash_new(); 01820 01821 /* --------------------- */ 01822 rb_define_singleton_method(mTK, "untrust", tk_obj_untrust, 1); 01823 01824 rb_define_singleton_method(mTK, "eval_cmd", tk_eval_cmd, -1); 01825 rb_define_singleton_method(mTK, "callback", tk_do_callback, -1); 01826 rb_define_singleton_method(mTK, "install_cmd", tk_install_cmd, -1); 01827 rb_define_singleton_method(mTK, "uninstall_cmd", tk_uninstall_cmd, 1); 01828 rb_define_singleton_method(mTK, "_symbolkey2str", tk_symbolkey2str, 1); 01829 rb_define_singleton_method(mTK, "hash_kv", tk_hash_kv, -1); 01830 rb_define_singleton_method(mTK, "_get_eval_string", 01831 tk_get_eval_string, -1); 01832 rb_define_singleton_method(mTK, "_get_eval_enc_str", 01833 tk_get_eval_enc_str, 1); 01834 rb_define_singleton_method(mTK, "_conv_args", tk_conv_args, -1); 01835 01836 rb_define_singleton_method(mTK, "bool", tcl2rb_bool, 1); 01837 rb_define_singleton_method(mTK, "number", tcl2rb_number, 1); 01838 rb_define_singleton_method(mTK, "string", tcl2rb_string, 1); 01839 rb_define_singleton_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); 01840 rb_define_singleton_method(mTK, "num_or_nil", tcl2rb_num_or_nil, 1); 01841 01842 rb_define_method(mTK, "_toUTF8", tk_toUTF8, -1); 01843 rb_define_method(mTK, "_fromUTF8", tk_fromUTF8, -1); 01844 rb_define_method(mTK, "_symbolkey2str", tk_symbolkey2str, 1); 01845 rb_define_method(mTK, "hash_kv", tk_hash_kv, -1); 01846 rb_define_method(mTK, "_get_eval_string", tk_get_eval_string, -1); 01847 rb_define_method(mTK, "_get_eval_enc_str", tk_get_eval_enc_str, 1); 01848 rb_define_method(mTK, "_conv_args", tk_conv_args, -1); 01849 01850 rb_define_method(mTK, "bool", tcl2rb_bool, 1); 01851 rb_define_method(mTK, "number", tcl2rb_number, 1); 01852 rb_define_method(mTK, "string", tcl2rb_string, 1); 01853 rb_define_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); 01854 rb_define_method(mTK, "num_or_nil", tcl2rb_num_or_nil, 1); 01855 01856 /* --------------------- */ 01857 rb_global_variable(&ENCODING_NAME_UTF8); 01858 ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); 01859 01860 /* --------------------- */ 01861 } 01862