00001
00002
00003
00004
00005
00006
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;
00016 #else
00017
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;
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
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
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:
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
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
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
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;
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
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;
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]);
01163 ptr->key[i] = NULL;
01164 }
01165 }
01166 xfree(ptr);
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
01234
01235
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
01331 strncpy(ptr, inf->key[idx], len);
01332 ptr += len;
01333 } else {
01334
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
01397 strncpy(ptr, inf->key[idx], len);
01398 ptr += len;
01399 } else {
01400
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
01442 *(ptr++) = *(key + 1);
01443 } else {
01444
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
01494 strncpy(ptr, inf->key[idx], len);
01495 ptr += len;
01496 } else {
01497
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
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
01538 if (RARRAY_LEN(longkey_inf) > 125 ) {
01539 rb_raise(rb_eArgError, "too many longname-key definitions");
01540 }
01541
01542
01543 cbsubst_obj = allocate_cbsubst_info(&subst_inf);
01544
01545
01546
01547
01548
01549
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
01578
01579
01580
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
01616
01617
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
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