Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/tk/tkutil/tkutil.c

Go to the documentation of this file.

    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