00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby/ruby.h"
00015 #include "ruby/st.h"
00016 #include "ruby/util.h"
00017 #include "ruby/encoding.h"
00018 #include "node.h"
00019 #include "constant.h"
00020 #include "internal.h"
00021 #include "id.h"
00022
00023 st_table *rb_global_tbl;
00024 static ID autoload, classpath, tmp_classpath, classid;
00025
00026 void
00027 Init_var_tables(void)
00028 {
00029 rb_global_tbl = st_init_numtable();
00030 CONST_ID(autoload, "__autoload__");
00031
00032 CONST_ID(classpath, "__classpath__");
00033
00034 CONST_ID(tmp_classpath, "__tmp_classpath__");
00035
00036 CONST_ID(classid, "__classid__");
00037 }
00038
00039 struct fc_result {
00040 ID name, preferred;
00041 VALUE klass;
00042 VALUE path;
00043 VALUE track;
00044 struct fc_result *prev;
00045 };
00046
00047 static VALUE
00048 fc_path(struct fc_result *fc, ID name)
00049 {
00050 VALUE path, tmp;
00051
00052 path = rb_id2str(name);
00053 while (fc) {
00054 st_data_t n;
00055 if (fc->track == rb_cObject) break;
00056 if (RCLASS_IV_TBL(fc->track) &&
00057 st_lookup(RCLASS_IV_TBL(fc->track), (st_data_t)classpath, &n)) {
00058 tmp = rb_str_dup((VALUE)n);
00059 rb_str_cat2(tmp, "::");
00060 rb_str_append(tmp, path);
00061 path = tmp;
00062 break;
00063 }
00064 tmp = rb_str_dup(rb_id2str(fc->name));
00065 rb_str_cat2(tmp, "::");
00066 rb_str_append(tmp, path);
00067 path = tmp;
00068 fc = fc->prev;
00069 }
00070 OBJ_FREEZE(path);
00071 return path;
00072 }
00073
00074 static int
00075 fc_i(st_data_t k, st_data_t v, st_data_t a)
00076 {
00077 ID key = (ID)k;
00078 rb_const_entry_t *ce = (rb_const_entry_t *)v;
00079 struct fc_result *res = (struct fc_result *)a;
00080 VALUE value = ce->value;
00081 if (!rb_is_const_id(key)) return ST_CONTINUE;
00082
00083 if (value == res->klass && (!res->preferred || key == res->preferred)) {
00084 res->path = fc_path(res, key);
00085 return ST_STOP;
00086 }
00087 if (RB_TYPE_P(value, T_MODULE) || RB_TYPE_P(value, T_CLASS)) {
00088 if (!RCLASS_CONST_TBL(value)) return ST_CONTINUE;
00089 else {
00090 struct fc_result arg;
00091 struct fc_result *list;
00092
00093 list = res;
00094 while (list) {
00095 if (list->track == value) return ST_CONTINUE;
00096 list = list->prev;
00097 }
00098
00099 arg.name = key;
00100 arg.preferred = res->preferred;
00101 arg.path = 0;
00102 arg.klass = res->klass;
00103 arg.track = value;
00104 arg.prev = res;
00105 st_foreach(RCLASS_CONST_TBL(value), fc_i, (st_data_t)&arg);
00106 if (arg.path) {
00107 res->path = arg.path;
00108 return ST_STOP;
00109 }
00110 }
00111 }
00112 return ST_CONTINUE;
00113 }
00114
00122 static VALUE
00123 find_class_path(VALUE klass, ID preferred)
00124 {
00125 struct fc_result arg;
00126
00127 arg.preferred = preferred;
00128 arg.name = 0;
00129 arg.path = 0;
00130 arg.klass = klass;
00131 arg.track = rb_cObject;
00132 arg.prev = 0;
00133 if (RCLASS_CONST_TBL(rb_cObject)) {
00134 st_foreach_safe(RCLASS_CONST_TBL(rb_cObject), fc_i, (st_data_t)&arg);
00135 }
00136 if (arg.path) {
00137 st_data_t tmp = tmp_classpath;
00138 if (!RCLASS_IV_TBL(klass)) {
00139 RCLASS_IV_TBL(klass) = st_init_numtable();
00140 }
00141 rb_st_insert_id_and_value(klass, RCLASS_IV_TBL(klass), (st_data_t)classpath, arg.path);
00142
00143 st_delete(RCLASS_IV_TBL(klass), &tmp, 0);
00144 return arg.path;
00145 }
00146 return Qnil;
00147 }
00148
00156 static VALUE
00157 classname(VALUE klass, int *permanent)
00158 {
00159 VALUE path = Qnil;
00160 st_data_t n;
00161
00162 if (!klass) klass = rb_cObject;
00163 *permanent = 1;
00164 if (RCLASS_IV_TBL(klass)) {
00165 if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classpath, &n)) {
00166 ID cid = 0;
00167 if (st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classid, &n)) {
00168 cid = SYM2ID(n);
00169 path = find_class_path(klass, cid);
00170 }
00171 if (NIL_P(path)) {
00172 path = find_class_path(klass, (ID)0);
00173 }
00174 if (NIL_P(path)) {
00175 if (!cid) {
00176 return Qnil;
00177 }
00178 if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)tmp_classpath, &n)) {
00179 path = rb_id2str(cid);
00180 return path;
00181 }
00182 *permanent = 0;
00183 path = (VALUE)n;
00184 return path;
00185 }
00186 }
00187 else {
00188 path = (VALUE)n;
00189 }
00190 if (!RB_TYPE_P(path, T_STRING)) {
00191 rb_bug("class path is not set properly");
00192 }
00193 return path;
00194 }
00195 return find_class_path(klass, (ID)0);
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205 VALUE
00206 rb_mod_name(VALUE mod)
00207 {
00208 int permanent;
00209 VALUE path = classname(mod, &permanent);
00210
00211 if (!NIL_P(path)) return rb_str_dup(path);
00212 return path;
00213 }
00214
00215 typedef VALUE (*path_cache_func)(VALUE obj, ID id, VALUE val);
00216
00217 static VALUE
00218 rb_tmp_class_path(VALUE klass, int *permanent, path_cache_func cache_path)
00219 {
00220 VALUE path = classname(klass, permanent);
00221 st_data_t n = (st_data_t)path;
00222
00223 if (!NIL_P(path)) {
00224 return path;
00225 }
00226 if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),
00227 (st_data_t)tmp_classpath, &n)) {
00228 *permanent = 0;
00229 return (VALUE)n;
00230 }
00231 else {
00232 const char *s = "Class";
00233
00234 if (RB_TYPE_P(klass, T_MODULE)) {
00235 if (rb_obj_class(klass) == rb_cModule) {
00236 s = "Module";
00237 }
00238 else {
00239 int perm;
00240 VALUE path;
00241
00242 path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, cache_path);
00243 s = RSTRING_PTR(path);
00244 }
00245 }
00246 path = rb_sprintf("#<%s:%p>", s, (void*)klass);
00247 OBJ_FREEZE(path);
00248
00249 cache_path(klass, tmp_classpath, path);
00250 *permanent = 0;
00251
00252 return path;
00253 }
00254 }
00255
00256 VALUE
00257 rb_class_path(VALUE klass)
00258 {
00259 int permanent;
00260 VALUE path = rb_tmp_class_path(klass, &permanent, rb_ivar_set);
00261 if (!NIL_P(path)) path = rb_str_dup(path);
00262 return path;
00263 }
00264
00265 static VALUE
00266 null_cache(VALUE obj, ID id, VALUE val)
00267 {
00268 return Qnil;
00269 }
00270
00271 VALUE
00272 rb_class_path_no_cache(VALUE klass)
00273 {
00274 int permanent;
00275 VALUE path = rb_tmp_class_path(klass, &permanent, null_cache);
00276 if (!NIL_P(path)) path = rb_str_dup(path);
00277 return path;
00278 }
00279
00280 VALUE
00281 rb_class_path_cached(VALUE klass)
00282 {
00283 st_table *ivtbl = RCLASS_IV_TBL(klass);
00284 st_data_t n;
00285
00286 if (!ivtbl) return Qnil;
00287 if (st_lookup(ivtbl, (st_data_t)classpath, &n)) return (VALUE)n;
00288 if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
00289 return Qnil;
00290 }
00291
00292 void
00293 rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
00294 {
00295 VALUE str;
00296 ID pathid = classpath;
00297
00298 if (under == rb_cObject) {
00299 str = rb_str_new_frozen(name);
00300 }
00301 else {
00302 int permanent;
00303 str = rb_str_dup(rb_tmp_class_path(under, &permanent, rb_ivar_set));
00304 rb_str_cat2(str, "::");
00305 rb_str_append(str, name);
00306 OBJ_FREEZE(str);
00307 if (!permanent) {
00308 pathid = tmp_classpath;
00309 rb_ivar_set(klass, classid, ID2SYM(rb_intern_str(name)));
00310 }
00311 }
00312 rb_ivar_set(klass, pathid, str);
00313 }
00314
00315 void
00316 rb_set_class_path(VALUE klass, VALUE under, const char *name)
00317 {
00318 VALUE str;
00319 ID pathid = classpath;
00320
00321 if (under == rb_cObject) {
00322 str = rb_str_new2(name);
00323 }
00324 else {
00325 int permanent;
00326 str = rb_str_dup(rb_tmp_class_path(under, &permanent, rb_ivar_set));
00327 rb_str_cat2(str, "::");
00328 rb_str_cat2(str, name);
00329 if (!permanent) {
00330 pathid = tmp_classpath;
00331 rb_ivar_set(klass, classid, ID2SYM(rb_intern(name)));
00332 }
00333 }
00334 OBJ_FREEZE(str);
00335 rb_ivar_set(klass, pathid, str);
00336 }
00337
00338 VALUE
00339 rb_path_to_class(VALUE pathname)
00340 {
00341 rb_encoding *enc = rb_enc_get(pathname);
00342 const char *pbeg, *p, *path = RSTRING_PTR(pathname);
00343 ID id;
00344 VALUE c = rb_cObject;
00345
00346 if (!rb_enc_asciicompat(enc)) {
00347 rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
00348 }
00349 pbeg = p = path;
00350 if (path[0] == '#') {
00351 rb_raise(rb_eArgError, "can't retrieve anonymous class %"PRIsVALUE,
00352 QUOTE(pathname));
00353 }
00354 while (*p) {
00355 while (*p && *p != ':') p++;
00356 id = rb_check_id_cstr(pbeg, p-pbeg, enc);
00357 if (p[0] == ':') {
00358 if (p[1] != ':') goto undefined_class;
00359 p += 2;
00360 pbeg = p;
00361 }
00362 if (!id || !rb_const_defined_at(c, id)) {
00363 undefined_class:
00364 rb_raise(rb_eArgError, "undefined class/module %.*"PRIsVALUE,
00365 (int)(p-path), pathname);
00366 }
00367 c = rb_const_get_at(c, id);
00368 if (!RB_TYPE_P(c, T_MODULE) && !RB_TYPE_P(c, T_CLASS)) {
00369 rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
00370 pathname);
00371 }
00372 }
00373 RB_GC_GUARD(pathname);
00374
00375 return c;
00376 }
00377
00378 VALUE
00379 rb_path2class(const char *path)
00380 {
00381 return rb_path_to_class(rb_str_new_cstr(path));
00382 }
00383
00384 void
00385 rb_name_class(VALUE klass, ID id)
00386 {
00387 rb_ivar_set(klass, classid, ID2SYM(id));
00388 }
00389
00390 VALUE
00391 rb_class_name(VALUE klass)
00392 {
00393 return rb_class_path(rb_class_real(klass));
00394 }
00395
00396 const char *
00397 rb_class2name(VALUE klass)
00398 {
00399 int permanent;
00400 VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, rb_ivar_set);
00401 if (NIL_P(path)) return NULL;
00402 return RSTRING_PTR(path);
00403 }
00404
00405 const char *
00406 rb_obj_classname(VALUE obj)
00407 {
00408 return rb_class2name(CLASS_OF(obj));
00409 }
00410
00411 #define global_variable rb_global_variable
00412 #define global_entry rb_global_entry
00413
00414 #define gvar_getter_t rb_gvar_getter_t
00415 #define gvar_setter_t rb_gvar_setter_t
00416 #define gvar_marker_t rb_gvar_marker_t
00417
00418 struct trace_var {
00419 int removed;
00420 void (*func)(VALUE arg, VALUE val);
00421 VALUE data;
00422 struct trace_var *next;
00423 };
00424
00425 struct global_variable {
00426 int counter;
00427 void *data;
00428 gvar_getter_t *getter;
00429 gvar_setter_t *setter;
00430 gvar_marker_t *marker;
00431 int block_trace;
00432 struct trace_var *trace;
00433 };
00434
00435 #define undef_getter rb_gvar_undef_getter
00436 #define undef_setter rb_gvar_undef_setter
00437 #define undef_marker rb_gvar_undef_marker
00438
00439 #define val_getter rb_gvar_val_getter
00440 #define val_setter rb_gvar_val_setter
00441 #define val_marker rb_gvar_val_marker
00442
00443 #define var_getter rb_gvar_var_getter
00444 #define var_setter rb_gvar_var_setter
00445 #define var_marker rb_gvar_var_marker
00446
00447 #define readonly_setter rb_gvar_readonly_setter
00448
00449 struct global_entry*
00450 rb_global_entry(ID id)
00451 {
00452 struct global_entry *entry;
00453 st_data_t data;
00454
00455 if (!st_lookup(rb_global_tbl, (st_data_t)id, &data)) {
00456 struct global_variable *var;
00457 entry = ALLOC(struct global_entry);
00458 var = ALLOC(struct global_variable);
00459 entry->id = id;
00460 entry->var = var;
00461 var->counter = 1;
00462 var->data = 0;
00463 var->getter = undef_getter;
00464 var->setter = undef_setter;
00465 var->marker = undef_marker;
00466
00467 var->block_trace = 0;
00468 var->trace = 0;
00469 st_add_direct(rb_global_tbl, id, (st_data_t)entry);
00470 }
00471 else {
00472 entry = (struct global_entry *)data;
00473 }
00474 return entry;
00475 }
00476
00477 VALUE
00478 undef_getter(ID id, void *data, struct global_variable *var)
00479 {
00480 rb_warning("global variable `%"PRIsVALUE"' not initialized", QUOTE_ID(id));
00481
00482 return Qnil;
00483 }
00484
00485 void
00486 undef_setter(VALUE val, ID id, void *data, struct global_variable *var)
00487 {
00488 var->getter = val_getter;
00489 var->setter = val_setter;
00490 var->marker = val_marker;
00491
00492 var->data = (void*)val;
00493 }
00494
00495 void
00496 undef_marker(VALUE *var)
00497 {
00498 }
00499
00500 VALUE
00501 val_getter(ID id, void *data, struct global_variable *var)
00502 {
00503 return (VALUE)data;
00504 }
00505
00506 void
00507 val_setter(VALUE val, ID id, void *data, struct global_variable *var)
00508 {
00509 var->data = (void*)val;
00510 }
00511
00512 void
00513 val_marker(VALUE *var)
00514 {
00515 VALUE data = (VALUE)var;
00516 if (data) rb_gc_mark_maybe(data);
00517 }
00518
00519 VALUE
00520 var_getter(ID id, void *data, struct global_variable *gvar)
00521 {
00522 VALUE *var = data;
00523 if (!var) return Qnil;
00524 return *var;
00525 }
00526
00527 void
00528 var_setter(VALUE val, ID id, void *data, struct global_variable *gvar)
00529 {
00530 *(VALUE *)data = val;
00531 }
00532
00533 void
00534 var_marker(VALUE *var)
00535 {
00536 if (var) rb_gc_mark_maybe(*var);
00537 }
00538
00539 void
00540 readonly_setter(VALUE val, ID id, void *data, struct global_variable *gvar)
00541 {
00542 rb_name_error(id, "%"PRIsVALUE" is a read-only variable", QUOTE_ID(id));
00543 }
00544
00545 static int
00546 mark_global_entry(st_data_t k, st_data_t v, st_data_t a)
00547 {
00548 struct global_entry *entry = (struct global_entry *)v;
00549 struct trace_var *trace;
00550 struct global_variable *var = entry->var;
00551
00552 (*var->marker)(var->data);
00553 trace = var->trace;
00554 while (trace) {
00555 if (trace->data) rb_gc_mark_maybe(trace->data);
00556 trace = trace->next;
00557 }
00558 return ST_CONTINUE;
00559 }
00560
00561 void
00562 rb_gc_mark_global_tbl(void)
00563 {
00564 if (rb_global_tbl)
00565 st_foreach_safe(rb_global_tbl, mark_global_entry, 0);
00566 }
00567
00568 static ID
00569 global_id(const char *name)
00570 {
00571 ID id;
00572
00573 if (name[0] == '$') id = rb_intern(name);
00574 else {
00575 size_t len = strlen(name);
00576 char *buf = ALLOCA_N(char, len+1);
00577 buf[0] = '$';
00578 memcpy(buf+1, name, len);
00579 id = rb_intern2(buf, len+1);
00580 }
00581 return id;
00582 }
00583
00584 void
00585 rb_define_hooked_variable(
00586 const char *name,
00587 VALUE *var,
00588 VALUE (*getter)(ANYARGS),
00589 void (*setter)(ANYARGS))
00590 {
00591 volatile VALUE tmp = var ? *var : Qnil;
00592 ID id = global_id(name);
00593 struct global_variable *gvar = rb_global_entry(id)->var;
00594
00595 gvar->data = (void*)var;
00596 gvar->getter = getter?(gvar_getter_t *)getter:var_getter;
00597 gvar->setter = setter?(gvar_setter_t *)setter:var_setter;
00598 gvar->marker = var_marker;
00599
00600 RB_GC_GUARD(tmp);
00601 }
00602
00603 void
00604 rb_define_variable(const char *name, VALUE *var)
00605 {
00606 rb_define_hooked_variable(name, var, 0, 0);
00607 }
00608
00609 void
00610 rb_define_readonly_variable(const char *name, VALUE *var)
00611 {
00612 rb_define_hooked_variable(name, var, 0, readonly_setter);
00613 }
00614
00615 void
00616 rb_define_virtual_variable(
00617 const char *name,
00618 VALUE (*getter)(ANYARGS),
00619 void (*setter)(ANYARGS))
00620 {
00621 if (!getter) getter = val_getter;
00622 if (!setter) setter = readonly_setter;
00623 rb_define_hooked_variable(name, 0, getter, setter);
00624 }
00625
00626 static void
00627 rb_trace_eval(VALUE cmd, VALUE val)
00628 {
00629 rb_eval_cmd(cmd, rb_ary_new3(1, val), 0);
00630 }
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 VALUE
00656 rb_f_trace_var(int argc, VALUE *argv)
00657 {
00658 VALUE var, cmd;
00659 struct global_entry *entry;
00660 struct trace_var *trace;
00661
00662 if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) {
00663 cmd = rb_block_proc();
00664 }
00665 if (NIL_P(cmd)) {
00666 return rb_f_untrace_var(argc, argv);
00667 }
00668 entry = rb_global_entry(rb_to_id(var));
00669 if (OBJ_TAINTED(cmd)) {
00670 rb_raise(rb_eSecurityError, "Insecure: tainted variable trace");
00671 }
00672 trace = ALLOC(struct trace_var);
00673 trace->next = entry->var->trace;
00674 trace->func = rb_trace_eval;
00675 trace->data = cmd;
00676 trace->removed = 0;
00677 entry->var->trace = trace;
00678
00679 return Qnil;
00680 }
00681
00682 static void
00683 remove_trace(struct global_variable *var)
00684 {
00685 struct trace_var *trace = var->trace;
00686 struct trace_var t;
00687 struct trace_var *next;
00688
00689 t.next = trace;
00690 trace = &t;
00691 while (trace->next) {
00692 next = trace->next;
00693 if (next->removed) {
00694 trace->next = next->next;
00695 xfree(next);
00696 }
00697 else {
00698 trace = next;
00699 }
00700 }
00701 var->trace = t.next;
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714 VALUE
00715 rb_f_untrace_var(int argc, VALUE *argv)
00716 {
00717 VALUE var, cmd;
00718 ID id;
00719 struct global_entry *entry;
00720 struct trace_var *trace;
00721 st_data_t data;
00722
00723 rb_scan_args(argc, argv, "11", &var, &cmd);
00724 id = rb_check_id(&var);
00725 if (!id) {
00726 rb_name_error_str(var, "undefined global variable %"PRIsVALUE"", QUOTE(var));
00727 }
00728 if (!st_lookup(rb_global_tbl, (st_data_t)id, &data)) {
00729 rb_name_error(id, "undefined global variable %"PRIsVALUE"", QUOTE_ID(id));
00730 }
00731
00732 trace = (entry = (struct global_entry *)data)->var->trace;
00733 if (NIL_P(cmd)) {
00734 VALUE ary = rb_ary_new();
00735
00736 while (trace) {
00737 struct trace_var *next = trace->next;
00738 rb_ary_push(ary, (VALUE)trace->data);
00739 trace->removed = 1;
00740 trace = next;
00741 }
00742
00743 if (!entry->var->block_trace) remove_trace(entry->var);
00744 return ary;
00745 }
00746 else {
00747 while (trace) {
00748 if (trace->data == cmd) {
00749 trace->removed = 1;
00750 if (!entry->var->block_trace) remove_trace(entry->var);
00751 return rb_ary_new3(1, cmd);
00752 }
00753 trace = trace->next;
00754 }
00755 }
00756 return Qnil;
00757 }
00758
00759 VALUE
00760 rb_gvar_get(struct global_entry *entry)
00761 {
00762 struct global_variable *var = entry->var;
00763 return (*var->getter)(entry->id, var->data, var);
00764 }
00765
00766 struct trace_data {
00767 struct trace_var *trace;
00768 VALUE val;
00769 };
00770
00771 static VALUE
00772 trace_ev(struct trace_data *data)
00773 {
00774 struct trace_var *trace = data->trace;
00775
00776 while (trace) {
00777 (*trace->func)(trace->data, data->val);
00778 trace = trace->next;
00779 }
00780
00781 return Qnil;
00782 }
00783
00784 static VALUE
00785 trace_en(struct global_variable *var)
00786 {
00787 var->block_trace = 0;
00788 remove_trace(var);
00789 return Qnil;
00790 }
00791
00792 VALUE
00793 rb_gvar_set(struct global_entry *entry, VALUE val)
00794 {
00795 struct trace_data trace;
00796 struct global_variable *var = entry->var;
00797
00798 (*var->setter)(val, entry->id, var->data, var);
00799
00800 if (var->trace && !var->block_trace) {
00801 var->block_trace = 1;
00802 trace.trace = var->trace;
00803 trace.val = val;
00804 rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
00805 }
00806 return val;
00807 }
00808
00809 VALUE
00810 rb_gv_set(const char *name, VALUE val)
00811 {
00812 struct global_entry *entry;
00813
00814 entry = rb_global_entry(global_id(name));
00815 return rb_gvar_set(entry, val);
00816 }
00817
00818 VALUE
00819 rb_gv_get(const char *name)
00820 {
00821 struct global_entry *entry;
00822
00823 entry = rb_global_entry(global_id(name));
00824 return rb_gvar_get(entry);
00825 }
00826
00827 VALUE
00828 rb_gvar_defined(struct global_entry *entry)
00829 {
00830 if (entry->var->getter == undef_getter) return Qfalse;
00831 return Qtrue;
00832 }
00833
00834 static int
00835 gvar_i(st_data_t k, st_data_t v, st_data_t a)
00836 {
00837 ID key = (ID)k;
00838 VALUE ary = (VALUE)a;
00839 rb_ary_push(ary, ID2SYM(key));
00840 return ST_CONTINUE;
00841 }
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852 VALUE
00853 rb_f_global_variables(void)
00854 {
00855 VALUE ary = rb_ary_new();
00856 char buf[2];
00857 int i;
00858
00859 st_foreach_safe(rb_global_tbl, gvar_i, ary);
00860 buf[0] = '$';
00861 for (i = 1; i <= 9; ++i) {
00862 buf[1] = (char)(i + '0');
00863 rb_ary_push(ary, ID2SYM(rb_intern2(buf, 2)));
00864 }
00865 return ary;
00866 }
00867
00868 void
00869 rb_alias_variable(ID name1, ID name2)
00870 {
00871 struct global_entry *entry1, *entry2;
00872 st_data_t data1;
00873
00874 entry2 = rb_global_entry(name2);
00875 if (!st_lookup(rb_global_tbl, (st_data_t)name1, &data1)) {
00876 entry1 = ALLOC(struct global_entry);
00877 entry1->id = name1;
00878 st_add_direct(rb_global_tbl, name1, (st_data_t)entry1);
00879 }
00880 else if ((entry1 = (struct global_entry *)data1)->var != entry2->var) {
00881 struct global_variable *var = entry1->var;
00882 if (var->block_trace) {
00883 rb_raise(rb_eRuntimeError, "can't alias in tracer");
00884 }
00885 var->counter--;
00886 if (var->counter == 0) {
00887 struct trace_var *trace = var->trace;
00888 while (trace) {
00889 struct trace_var *next = trace->next;
00890 xfree(trace);
00891 trace = next;
00892 }
00893 xfree(var);
00894 }
00895 }
00896 else {
00897 return;
00898 }
00899 entry2->var->counter++;
00900 entry1->var = entry2->var;
00901 }
00902
00903 static int special_generic_ivar = 0;
00904 static st_table *generic_iv_tbl;
00905
00906 st_table*
00907 rb_generic_ivar_table(VALUE obj)
00908 {
00909 st_data_t tbl;
00910
00911 if (!FL_TEST(obj, FL_EXIVAR)) return 0;
00912 if (!generic_iv_tbl) return 0;
00913 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) return 0;
00914 return (st_table *)tbl;
00915 }
00916
00917 static VALUE
00918 generic_ivar_get(VALUE obj, ID id, VALUE undef)
00919 {
00920 st_data_t tbl, val;
00921
00922 if (generic_iv_tbl) {
00923 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
00924 if (st_lookup((st_table *)tbl, (st_data_t)id, &val)) {
00925 return (VALUE)val;
00926 }
00927 }
00928 }
00929 return undef;
00930 }
00931
00932 static void
00933 generic_ivar_set(VALUE obj, ID id, VALUE val)
00934 {
00935 st_table *tbl;
00936 st_data_t data;
00937
00938 if (rb_special_const_p(obj)) {
00939 if (rb_obj_frozen_p(obj)) rb_error_frozen("object");
00940 special_generic_ivar = 1;
00941 }
00942 if (!generic_iv_tbl) {
00943 generic_iv_tbl = st_init_numtable();
00944 }
00945 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
00946 FL_SET(obj, FL_EXIVAR);
00947 tbl = st_init_numtable();
00948 st_add_direct(generic_iv_tbl, (st_data_t)obj, (st_data_t)tbl);
00949 st_add_direct(tbl, (st_data_t)id, (st_data_t)val);
00950 if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
00951 return;
00952 }
00953 st_insert((st_table *)data, (st_data_t)id, (st_data_t)val);
00954 if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, data, val);
00955 }
00956
00957 static VALUE
00958 generic_ivar_defined(VALUE obj, ID id)
00959 {
00960 st_table *tbl;
00961 st_data_t data;
00962
00963 if (!generic_iv_tbl) return Qfalse;
00964 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return Qfalse;
00965 tbl = (st_table *)data;
00966 if (st_lookup(tbl, (st_data_t)id, &data)) {
00967 return Qtrue;
00968 }
00969 return Qfalse;
00970 }
00971
00972 static int
00973 generic_ivar_remove(VALUE obj, ID id, st_data_t *valp)
00974 {
00975 st_table *tbl;
00976 st_data_t data, key = (st_data_t)id;
00977 int status;
00978
00979 if (!generic_iv_tbl) return 0;
00980 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return 0;
00981 tbl = (st_table *)data;
00982 status = st_delete(tbl, &key, valp);
00983 if (tbl->num_entries == 0) {
00984 key = (st_data_t)obj;
00985 st_delete(generic_iv_tbl, &key, &data);
00986 st_free_table((st_table *)data);
00987 }
00988 return status;
00989 }
00990
00991 void
00992 rb_mark_generic_ivar(VALUE obj)
00993 {
00994 st_data_t tbl;
00995
00996 if (!generic_iv_tbl) return;
00997 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
00998 rb_mark_tbl((st_table *)tbl);
00999 }
01000 }
01001
01002 static int
01003 givar_mark_i(st_data_t k, st_data_t v, st_data_t a)
01004 {
01005 VALUE value = (VALUE)v;
01006 rb_gc_mark(value);
01007 return ST_CONTINUE;
01008 }
01009
01010 static int
01011 givar_i(st_data_t k, st_data_t v, st_data_t a)
01012 {
01013 VALUE obj = (VALUE)k;
01014 st_table *tbl = (st_table *)v;
01015 if (rb_special_const_p(obj)) {
01016 st_foreach_safe(tbl, givar_mark_i, 0);
01017 }
01018 return ST_CONTINUE;
01019 }
01020
01021 void
01022 rb_mark_generic_ivar_tbl(void)
01023 {
01024 if (!generic_iv_tbl) return;
01025 if (special_generic_ivar == 0) return;
01026 st_foreach_safe(generic_iv_tbl, givar_i, 0);
01027 }
01028
01029 void
01030 rb_free_generic_ivar(VALUE obj)
01031 {
01032 st_data_t key = (st_data_t)obj, tbl;
01033
01034 if (!generic_iv_tbl) return;
01035 if (st_delete(generic_iv_tbl, &key, &tbl))
01036 st_free_table((st_table *)tbl);
01037 }
01038
01039 RUBY_FUNC_EXPORTED size_t
01040 rb_generic_ivar_memsize(VALUE obj)
01041 {
01042 st_data_t tbl;
01043 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl))
01044 return st_memsize((st_table *)tbl);
01045 return 0;
01046 }
01047
01048 void
01049 rb_copy_generic_ivar(VALUE clone, VALUE obj)
01050 {
01051 st_data_t data;
01052
01053 if (!generic_iv_tbl) return;
01054 if (!FL_TEST(obj, FL_EXIVAR)) {
01055 clear:
01056 if (FL_TEST(clone, FL_EXIVAR)) {
01057 rb_free_generic_ivar(clone);
01058 FL_UNSET(clone, FL_EXIVAR);
01059 }
01060 return;
01061 }
01062 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
01063 st_table *tbl = (st_table *)data;
01064
01065 if (tbl->num_entries == 0)
01066 goto clear;
01067
01068 if (st_lookup(generic_iv_tbl, (st_data_t)clone, &data)) {
01069 st_free_table((st_table *)data);
01070 st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
01071 }
01072 else {
01073 st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
01074 FL_SET(clone, FL_EXIVAR);
01075 }
01076 }
01077 }
01078
01079 static VALUE
01080 rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
01081 {
01082 VALUE val, *ptr;
01083 struct st_table *iv_index_tbl;
01084 long len;
01085 st_data_t index;
01086
01087 if (SPECIAL_CONST_P(obj)) goto generic;
01088 switch (BUILTIN_TYPE(obj)) {
01089 case T_OBJECT:
01090 len = ROBJECT_NUMIV(obj);
01091 ptr = ROBJECT_IVPTR(obj);
01092 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01093 if (!iv_index_tbl) break;
01094 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01095 if (len <= (long)index) break;
01096 val = ptr[index];
01097 if (val != Qundef)
01098 return val;
01099 break;
01100 case T_CLASS:
01101 case T_MODULE:
01102 if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, &index))
01103 return (VALUE)index;
01104 break;
01105 default:
01106 generic:
01107 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01108 return generic_ivar_get(obj, id, undef);
01109 break;
01110 }
01111 return undef;
01112 }
01113
01114 VALUE
01115 rb_ivar_get(VALUE obj, ID id)
01116 {
01117 VALUE iv = rb_ivar_lookup(obj, id, Qundef);
01118
01119 if (iv == Qundef) {
01120 rb_warning("instance variable %"PRIsVALUE" not initialized", QUOTE_ID(id));
01121 iv = Qnil;
01122 }
01123 return iv;
01124 }
01125
01126 VALUE
01127 rb_attr_get(VALUE obj, ID id)
01128 {
01129 return rb_ivar_lookup(obj, id, Qnil);
01130 }
01131
01132 VALUE
01133 rb_ivar_set(VALUE obj, ID id, VALUE val)
01134 {
01135 struct st_table *iv_index_tbl;
01136 st_data_t index;
01137 long i, len;
01138 int ivar_extended;
01139
01140 rb_check_frozen(obj);
01141 if (SPECIAL_CONST_P(obj)) goto generic;
01142 switch (BUILTIN_TYPE(obj)) {
01143 case T_OBJECT:
01144 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01145 if (!iv_index_tbl) {
01146 VALUE klass = rb_obj_class(obj);
01147 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
01148 if (!iv_index_tbl) {
01149 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
01150 }
01151 }
01152 ivar_extended = 0;
01153 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
01154 index = iv_index_tbl->num_entries;
01155 st_add_direct(iv_index_tbl, (st_data_t)id, index);
01156 ivar_extended = 1;
01157 }
01158 len = ROBJECT_NUMIV(obj);
01159 if (len <= (long)index) {
01160 VALUE *ptr = ROBJECT_IVPTR(obj);
01161 if (index < ROBJECT_EMBED_LEN_MAX) {
01162 RBASIC(obj)->flags |= ROBJECT_EMBED;
01163 ptr = ROBJECT(obj)->as.ary;
01164 for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
01165 ptr[i] = Qundef;
01166 }
01167 }
01168 else {
01169 VALUE *newptr;
01170 long newsize = (index+1) + (index+1)/4;
01171 if (!ivar_extended &&
01172 iv_index_tbl->num_entries < (st_index_t)newsize) {
01173 newsize = iv_index_tbl->num_entries;
01174 }
01175 if (RBASIC(obj)->flags & ROBJECT_EMBED) {
01176 newptr = ALLOC_N(VALUE, newsize);
01177 MEMCPY(newptr, ptr, VALUE, len);
01178 RBASIC(obj)->flags &= ~ROBJECT_EMBED;
01179 ROBJECT(obj)->as.heap.ivptr = newptr;
01180 }
01181 else {
01182 REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
01183 newptr = ROBJECT(obj)->as.heap.ivptr;
01184 }
01185 for (; len < newsize; len++)
01186 newptr[len] = Qundef;
01187 ROBJECT(obj)->as.heap.numiv = newsize;
01188 ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
01189 }
01190 }
01191 RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], val);
01192 break;
01193 case T_CLASS:
01194 case T_MODULE:
01195 if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
01196 rb_st_insert_id_and_value(obj, RCLASS_IV_TBL(obj), (st_data_t)id, val);
01197 break;
01198 default:
01199 generic:
01200 generic_ivar_set(obj, id, val);
01201 break;
01202 }
01203 return val;
01204 }
01205
01206 VALUE
01207 rb_ivar_defined(VALUE obj, ID id)
01208 {
01209 VALUE val;
01210 struct st_table *iv_index_tbl;
01211 st_data_t index;
01212 if (SPECIAL_CONST_P(obj)) goto generic;
01213 switch (BUILTIN_TYPE(obj)) {
01214 case T_OBJECT:
01215 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01216 if (!iv_index_tbl) break;
01217 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01218 if (ROBJECT_NUMIV(obj) <= (long)index) break;
01219 val = ROBJECT_IVPTR(obj)[index];
01220 if (val != Qundef)
01221 return Qtrue;
01222 break;
01223 case T_CLASS:
01224 case T_MODULE:
01225 if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, 0))
01226 return Qtrue;
01227 break;
01228 default:
01229 generic:
01230 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01231 return generic_ivar_defined(obj, id);
01232 break;
01233 }
01234 return Qfalse;
01235 }
01236
01237 struct obj_ivar_tag {
01238 VALUE obj;
01239 int (*func)(ID key, VALUE val, st_data_t arg);
01240 st_data_t arg;
01241 };
01242
01243 static int
01244 obj_ivar_i(st_data_t key, st_data_t index, st_data_t arg)
01245 {
01246 struct obj_ivar_tag *data = (struct obj_ivar_tag *)arg;
01247 if ((long)index < ROBJECT_NUMIV(data->obj)) {
01248 VALUE val = ROBJECT_IVPTR(data->obj)[(long)index];
01249 if (val != Qundef) {
01250 return (data->func)((ID)key, val, data->arg);
01251 }
01252 }
01253 return ST_CONTINUE;
01254 }
01255
01256 static void
01257 obj_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01258 {
01259 st_table *tbl;
01260 struct obj_ivar_tag data;
01261
01262 tbl = ROBJECT_IV_INDEX_TBL(obj);
01263 if (!tbl)
01264 return;
01265
01266 data.obj = obj;
01267 data.func = (int (*)(ID key, VALUE val, st_data_t arg))func;
01268 data.arg = arg;
01269
01270 st_foreach_safe(tbl, obj_ivar_i, (st_data_t)&data);
01271 }
01272
01273 void
01274 rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01275 {
01276 if (SPECIAL_CONST_P(obj)) goto generic;
01277 switch (BUILTIN_TYPE(obj)) {
01278 case T_OBJECT:
01279 obj_ivar_each(obj, func, arg);
01280 break;
01281 case T_CLASS:
01282 case T_MODULE:
01283 if (RCLASS_IV_TBL(obj)) {
01284 st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
01285 }
01286 break;
01287 default:
01288 generic:
01289 if (!generic_iv_tbl) break;
01290 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01291 st_data_t tbl;
01292
01293 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
01294 st_foreach_safe((st_table *)tbl, func, arg);
01295 }
01296 }
01297 break;
01298 }
01299 }
01300
01301 st_index_t
01302 rb_ivar_count(VALUE obj)
01303 {
01304 st_table *tbl;
01305 if (SPECIAL_CONST_P(obj)) goto generic;
01306 switch (BUILTIN_TYPE(obj)) {
01307 case T_OBJECT:
01308 if ((tbl = ROBJECT_IV_INDEX_TBL(obj)) != 0) {
01309 st_index_t i, count, num = tbl->num_entries;
01310 const VALUE *const ivptr = ROBJECT_IVPTR(obj);
01311 for (i = count = 0; i < num; ++i) {
01312 if (ivptr[i] != Qundef) {
01313 count++;
01314 }
01315 }
01316 return count;
01317 }
01318 break;
01319 case T_CLASS:
01320 case T_MODULE:
01321 if ((tbl = RCLASS_IV_TBL(obj)) != 0) {
01322 return tbl->num_entries;
01323 }
01324 break;
01325 default:
01326 generic:
01327 if (!generic_iv_tbl) break;
01328 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01329 st_data_t data;
01330
01331 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data) &&
01332 (tbl = (st_table *)data) != 0) {
01333 return tbl->num_entries;
01334 }
01335 }
01336 break;
01337 }
01338 return 0;
01339 }
01340
01341 static int
01342 ivar_i(st_data_t k, st_data_t v, st_data_t a)
01343 {
01344 ID key = (ID)k;
01345 VALUE ary = (VALUE)a;
01346
01347 if (rb_is_instance_id(key)) {
01348 rb_ary_push(ary, ID2SYM(key));
01349 }
01350 return ST_CONTINUE;
01351 }
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370 VALUE
01371 rb_obj_instance_variables(VALUE obj)
01372 {
01373 VALUE ary;
01374
01375 ary = rb_ary_new();
01376 rb_ivar_foreach(obj, ivar_i, ary);
01377 return ary;
01378 }
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402 VALUE
01403 rb_obj_remove_instance_variable(VALUE obj, VALUE name)
01404 {
01405 VALUE val = Qnil;
01406 const ID id = rb_check_id(&name);
01407 st_data_t n, v;
01408 struct st_table *iv_index_tbl;
01409 st_data_t index;
01410
01411 rb_check_frozen(obj);
01412 if (!id) {
01413 if (rb_is_instance_name(name)) {
01414 rb_name_error_str(name, "instance variable %"PRIsVALUE" not defined",
01415 name);
01416 }
01417 else {
01418 rb_name_error_str(name, "`%"PRIsVALUE"' is not allowed as an instance variable name",
01419 QUOTE(name));
01420 }
01421 }
01422 if (!rb_is_instance_id(id)) {
01423 rb_name_error(id, "`%"PRIsVALUE"' is not allowed as an instance variable name",
01424 QUOTE_ID(id));
01425 }
01426
01427 if (SPECIAL_CONST_P(obj)) goto generic;
01428 switch (BUILTIN_TYPE(obj)) {
01429 case T_OBJECT:
01430 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01431 if (!iv_index_tbl) break;
01432 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01433 if (ROBJECT_NUMIV(obj) <= (long)index) break;
01434 val = ROBJECT_IVPTR(obj)[index];
01435 if (val != Qundef) {
01436 ROBJECT_IVPTR(obj)[index] = Qundef;
01437 return val;
01438 }
01439 break;
01440 case T_CLASS:
01441 case T_MODULE:
01442 n = id;
01443 if (RCLASS_IV_TBL(obj) && st_delete(RCLASS_IV_TBL(obj), &n, &v)) {
01444 return (VALUE)v;
01445 }
01446 break;
01447 default:
01448 generic:
01449 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01450 v = val;
01451 if (generic_ivar_remove(obj, (st_data_t)id, &v)) {
01452 return (VALUE)v;
01453 }
01454 }
01455 break;
01456 }
01457 rb_name_error(id, "instance variable %"PRIsVALUE" not defined", QUOTE_ID(id));
01458
01459 UNREACHABLE;
01460 }
01461
01462 NORETURN(static void uninitialized_constant(VALUE, ID));
01463 static void
01464 uninitialized_constant(VALUE klass, ID id)
01465 {
01466 if (klass && rb_class_real(klass) != rb_cObject)
01467 rb_name_error(id, "uninitialized constant %"PRIsVALUE"::%"PRIsVALUE"",
01468 rb_class_name(klass),
01469 QUOTE_ID(id));
01470 else {
01471 rb_name_error(id, "uninitialized constant %"PRIsVALUE"", QUOTE_ID(id));
01472 }
01473 }
01474
01475 static VALUE
01476 const_missing(VALUE klass, ID id)
01477 {
01478 return rb_funcall(klass, rb_intern("const_missing"), 1, ID2SYM(id));
01479 }
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518 VALUE
01519 rb_mod_const_missing(VALUE klass, VALUE name)
01520 {
01521 rb_vm_pop_cfunc_frame();
01522 uninitialized_constant(klass, rb_to_id(name));
01523
01524 UNREACHABLE;
01525 }
01526
01527 static void
01528 autoload_mark(void *ptr)
01529 {
01530 rb_mark_tbl((st_table *)ptr);
01531 }
01532
01533 static void
01534 autoload_free(void *ptr)
01535 {
01536 st_free_table((st_table *)ptr);
01537 }
01538
01539 static size_t
01540 autoload_memsize(const void *ptr)
01541 {
01542 const st_table *tbl = ptr;
01543 return tbl ? st_memsize(tbl) : 0;
01544 }
01545
01546 static const rb_data_type_t autoload_data_type = {
01547 "autoload",
01548 {autoload_mark, autoload_free, autoload_memsize,},
01549 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01550 };
01551
01552 #define check_autoload_table(av) \
01553 (struct st_table *)rb_check_typeddata((av), &autoload_data_type)
01554
01555 static VALUE
01556 autoload_data(VALUE mod, ID id)
01557 {
01558 struct st_table *tbl;
01559 st_data_t val;
01560
01561 if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
01562 !(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, (st_data_t)id, &val)) {
01563 return 0;
01564 }
01565 return (VALUE)val;
01566 }
01567
01568 struct autoload_data_i {
01569 VALUE feature;
01570 int safe_level;
01571 VALUE thread;
01572 VALUE value;
01573 };
01574
01575 static void
01576 autoload_i_mark(void *ptr)
01577 {
01578 struct autoload_data_i *p = ptr;
01579 rb_gc_mark(p->feature);
01580 rb_gc_mark(p->thread);
01581 rb_gc_mark(p->value);
01582 }
01583
01584 static void
01585 autoload_i_free(void *ptr)
01586 {
01587 struct autoload_data_i *p = ptr;
01588 xfree(p);
01589 }
01590
01591 static size_t
01592 autoload_i_memsize(const void *ptr)
01593 {
01594 return sizeof(struct autoload_data_i);
01595 }
01596
01597 static const rb_data_type_t autoload_data_i_type = {
01598 "autoload_i",
01599 {autoload_i_mark, autoload_i_free, autoload_i_memsize,},
01600 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01601 };
01602
01603 #define check_autoload_data(av) \
01604 (struct autoload_data_i *)rb_check_typeddata((av), &autoload_data_i_type)
01605
01606 void
01607 rb_autoload(VALUE mod, ID id, const char *file)
01608 {
01609 st_data_t av;
01610 VALUE ad, fn;
01611 struct st_table *tbl;
01612 struct autoload_data_i *ele;
01613
01614 if (!rb_is_const_id(id)) {
01615 rb_raise(rb_eNameError, "autoload must be constant name: %"PRIsVALUE"",
01616 QUOTE_ID(id));
01617 }
01618 if (!file || !*file) {
01619 rb_raise(rb_eArgError, "empty file name");
01620 }
01621
01622 if ((tbl = RCLASS_CONST_TBL(mod)) && st_lookup(tbl, (st_data_t)id, &av) && ((rb_const_entry_t*)av)->value != Qundef)
01623 return;
01624
01625 rb_const_set(mod, id, Qundef);
01626 tbl = RCLASS_IV_TBL(mod);
01627 if (tbl && st_lookup(tbl, (st_data_t)autoload, &av)) {
01628 tbl = check_autoload_table((VALUE)av);
01629 }
01630 else {
01631 if (!tbl) tbl = RCLASS_IV_TBL(mod) = st_init_numtable();
01632 av = (st_data_t)TypedData_Wrap_Struct(0, &autoload_data_type, 0);
01633 st_add_direct(tbl, (st_data_t)autoload, av);
01634 RB_OBJ_WRITTEN(mod, Qnil, av);
01635 DATA_PTR(av) = tbl = st_init_numtable();
01636 }
01637 fn = rb_str_new2(file);
01638 FL_UNSET(fn, FL_TAINT);
01639 OBJ_FREEZE(fn);
01640
01641 ele = ALLOC(struct autoload_data_i);
01642 ele->feature = fn;
01643 ele->safe_level = rb_safe_level();
01644 ele->thread = Qnil;
01645 ele->value = Qundef;
01646 ad = TypedData_Wrap_Struct(0, &autoload_data_i_type, ele);
01647 st_insert(tbl, (st_data_t)id, (st_data_t)ad);
01648 }
01649
01650 static void
01651 autoload_delete(VALUE mod, ID id)
01652 {
01653 st_data_t val, load = 0, n = id;
01654 rb_const_entry_t *ce;
01655
01656 st_delete(RCLASS_CONST_TBL(mod), &n, &val);
01657 ce = (rb_const_entry_t*)val;
01658 if (ce) xfree(ce);
01659 if (st_lookup(RCLASS_IV_TBL(mod), (st_data_t)autoload, &val)) {
01660 struct st_table *tbl = check_autoload_table((VALUE)val);
01661
01662 st_delete(tbl, &n, &load);
01663
01664 if (tbl->num_entries == 0) {
01665 n = autoload;
01666 st_delete(RCLASS_IV_TBL(mod), &n, &val);
01667 }
01668 }
01669 }
01670
01671 static VALUE
01672 autoload_provided(VALUE arg)
01673 {
01674 const char **p = (const char **)arg;
01675 return rb_feature_provided(*p, p);
01676 }
01677
01678 static VALUE
01679 reset_safe(VALUE safe)
01680 {
01681 rb_set_safe_level_force((int)safe);
01682 return safe;
01683 }
01684
01685 static VALUE
01686 check_autoload_required(VALUE mod, ID id, const char **loadingpath)
01687 {
01688 VALUE file, load;
01689 struct autoload_data_i *ele;
01690 const char *loading;
01691 int safe;
01692
01693 if (!(load = autoload_data(mod, id)) || !(ele = check_autoload_data(load))) {
01694 return 0;
01695 }
01696 file = ele->feature;
01697 Check_Type(file, T_STRING);
01698 if (!RSTRING_PTR(file) || !*RSTRING_PTR(file)) {
01699 rb_raise(rb_eArgError, "empty file name");
01700 }
01701 loading = RSTRING_PTR(file);
01702 safe = rb_safe_level();
01703 rb_set_safe_level_force(0);
01704 if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
01705 return load;
01706 }
01707 if (loadingpath && loading) {
01708 *loadingpath = loading;
01709 return load;
01710 }
01711 return 0;
01712 }
01713
01714 int
01715 rb_autoloading_value(VALUE mod, ID id, VALUE* value)
01716 {
01717 VALUE load;
01718 struct autoload_data_i *ele;
01719
01720 if (!(load = autoload_data(mod, id)) || !(ele = check_autoload_data(load))) {
01721 return 0;
01722 }
01723 if (ele->thread == rb_thread_current()) {
01724 if (ele->value != Qundef) {
01725 if (value) {
01726 *value = ele->value;
01727 }
01728 return 1;
01729 }
01730 }
01731 return 0;
01732 }
01733
01734 static int
01735 autoload_defined_p(VALUE mod, ID id)
01736 {
01737 struct st_table *tbl = RCLASS_CONST_TBL(mod);
01738 st_data_t val;
01739
01740 if (!tbl || !st_lookup(tbl, (st_data_t)id, &val) || ((rb_const_entry_t*)val)->value != Qundef) {
01741 return 0;
01742 }
01743 return !rb_autoloading_value(mod, id, NULL);
01744 }
01745
01746 struct autoload_const_set_args {
01747 VALUE mod;
01748 ID id;
01749 VALUE value;
01750 };
01751
01752 static VALUE
01753 autoload_const_set(VALUE arg)
01754 {
01755 struct autoload_const_set_args* args = (struct autoload_const_set_args *)arg;
01756 autoload_delete(args->mod, args->id);
01757 rb_const_set(args->mod, args->id, args->value);
01758 return 0;
01759 }
01760
01761 static VALUE
01762 autoload_require(VALUE arg)
01763 {
01764 struct autoload_data_i *ele = (struct autoload_data_i *)arg;
01765 return rb_require_safe(ele->feature, ele->safe_level);
01766 }
01767
01768 VALUE
01769 rb_autoload_load(VALUE mod, ID id)
01770 {
01771 VALUE load, result;
01772 const char *loading = 0, *src;
01773 struct autoload_data_i *ele;
01774 int state = 0;
01775
01776 if (!autoload_defined_p(mod, id)) return Qfalse;
01777 load = check_autoload_required(mod, id, &loading);
01778 if (!load) return Qfalse;
01779 src = rb_sourcefile();
01780 if (src && loading && strcmp(src, loading) == 0) return Qfalse;
01781
01782
01783 if (!(ele = check_autoload_data(load))) {
01784 return Qfalse;
01785 }
01786 if (ele->thread == Qnil) {
01787 ele->thread = rb_thread_current();
01788 }
01789
01790 result = rb_protect(autoload_require, (VALUE)ele, &state);
01791 if (ele->thread == rb_thread_current()) {
01792 ele->thread = Qnil;
01793 }
01794 if (state) rb_jump_tag(state);
01795
01796 if (RTEST(result)) {
01797
01798 if (ele->value != Qundef) {
01799 int safe_backup;
01800 struct autoload_const_set_args args;
01801 args.mod = mod;
01802 args.id = id;
01803 args.value = ele->value;
01804 safe_backup = rb_safe_level();
01805 rb_set_safe_level_force(ele->safe_level);
01806 rb_ensure(autoload_const_set, (VALUE)&args, reset_safe, (VALUE)safe_backup);
01807 }
01808 }
01809 RB_GC_GUARD(load);
01810 return result;
01811 }
01812
01813 VALUE
01814 rb_autoload_p(VALUE mod, ID id)
01815 {
01816 VALUE load;
01817 struct autoload_data_i *ele;
01818
01819 while (!autoload_defined_p(mod, id)) {
01820 mod = RCLASS_SUPER(mod);
01821 if (!mod) return Qnil;
01822 }
01823 load = check_autoload_required(mod, id, 0);
01824 if (!load) return Qnil;
01825 return (ele = check_autoload_data(load)) ? ele->feature : Qnil;
01826 }
01827
01828 static VALUE
01829 rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
01830 {
01831 VALUE value, tmp, av;
01832 int mod_retry = 0;
01833
01834 tmp = klass;
01835 retry:
01836 while (RTEST(tmp)) {
01837 VALUE am = 0;
01838 st_data_t data;
01839 while (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &data)) {
01840 rb_const_entry_t *ce = (rb_const_entry_t *)data;
01841 if (visibility && ce->flag == CONST_PRIVATE) {
01842 rb_name_error(id, "private constant %"PRIsVALUE"::%"PRIsVALUE" referenced",
01843 rb_class_name(klass), QUOTE_ID(id));
01844 }
01845 value = ce->value;
01846 if (value == Qundef) {
01847 if (am == tmp) break;
01848 am = tmp;
01849 if (rb_autoloading_value(tmp, id, &av)) return av;
01850 rb_autoload_load(tmp, id);
01851 continue;
01852 }
01853 if (exclude && tmp == rb_cObject && klass != rb_cObject) {
01854 rb_warn("toplevel constant %"PRIsVALUE" referenced by %"PRIsVALUE"::%"PRIsVALUE"",
01855 QUOTE_ID(id), rb_class_name(klass), QUOTE_ID(id));
01856 }
01857 return value;
01858 }
01859 if (!recurse) break;
01860 tmp = RCLASS_SUPER(tmp);
01861 }
01862 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
01863 mod_retry = 1;
01864 tmp = rb_cObject;
01865 goto retry;
01866 }
01867
01868 value = const_missing(klass, id);
01869 rb_vm_inc_const_missing_count();
01870 return value;
01871 }
01872
01873 VALUE
01874 rb_const_get_from(VALUE klass, ID id)
01875 {
01876 return rb_const_get_0(klass, id, TRUE, TRUE, FALSE);
01877 }
01878
01879 VALUE
01880 rb_const_get(VALUE klass, ID id)
01881 {
01882 return rb_const_get_0(klass, id, FALSE, TRUE, FALSE);
01883 }
01884
01885 VALUE
01886 rb_const_get_at(VALUE klass, ID id)
01887 {
01888 return rb_const_get_0(klass, id, TRUE, FALSE, FALSE);
01889 }
01890
01891 VALUE
01892 rb_public_const_get_from(VALUE klass, ID id)
01893 {
01894 return rb_const_get_0(klass, id, TRUE, TRUE, TRUE);
01895 }
01896
01897 VALUE
01898 rb_public_const_get(VALUE klass, ID id)
01899 {
01900 return rb_const_get_0(klass, id, FALSE, TRUE, TRUE);
01901 }
01902
01903 VALUE
01904 rb_public_const_get_at(VALUE klass, ID id)
01905 {
01906 return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
01907 }
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919 VALUE
01920 rb_mod_remove_const(VALUE mod, VALUE name)
01921 {
01922 const ID id = rb_check_id(&name);
01923
01924 if (!id) {
01925 if (rb_is_const_name(name)) {
01926 rb_name_error_str(name, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
01927 rb_class_name(mod), name);
01928 }
01929 else {
01930 rb_name_error_str(name, "`%"PRIsVALUE"' is not allowed as a constant name",
01931 QUOTE(name));
01932 }
01933 }
01934 if (!rb_is_const_id(id)) {
01935 rb_name_error(id, "`%"PRIsVALUE"' is not allowed as a constant name",
01936 QUOTE_ID(id));
01937 }
01938 return rb_const_remove(mod, id);
01939 }
01940
01941 VALUE
01942 rb_const_remove(VALUE mod, ID id)
01943 {
01944 VALUE val;
01945 st_data_t v, n = id;
01946
01947 rb_check_frozen(mod);
01948 if (!RCLASS_CONST_TBL(mod) || !st_delete(RCLASS_CONST_TBL(mod), &n, &v)) {
01949 if (rb_const_defined_at(mod, id)) {
01950 rb_name_error(id, "cannot remove %"PRIsVALUE"::%"PRIsVALUE"",
01951 rb_class_name(mod), QUOTE_ID(id));
01952 }
01953 rb_name_error(id, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
01954 rb_class_name(mod), QUOTE_ID(id));
01955 }
01956
01957 rb_clear_constant_cache();
01958
01959 val = ((rb_const_entry_t*)v)->value;
01960 if (val == Qundef) {
01961 autoload_delete(mod, id);
01962 val = Qnil;
01963 }
01964 xfree((rb_const_entry_t*)v);
01965 return val;
01966 }
01967
01968 static int
01969 sv_i(st_data_t k, st_data_t v, st_data_t a)
01970 {
01971 ID key = (ID)k;
01972 rb_const_entry_t *ce = (rb_const_entry_t *)v;
01973 st_table *tbl = (st_table *)a;
01974
01975 if (rb_is_const_id(key)) {
01976 if (!st_lookup(tbl, (st_data_t)key, 0)) {
01977 st_insert(tbl, (st_data_t)key, (st_data_t)ce);
01978 }
01979 }
01980 return ST_CONTINUE;
01981 }
01982
01983 static int
01984 rb_local_constants_i(st_data_t const_name, st_data_t const_value, st_data_t ary)
01985 {
01986 rb_ary_push((VALUE)ary, ID2SYM((ID)const_name));
01987 return ST_CONTINUE;
01988 }
01989
01990 static VALUE
01991 rb_local_constants(VALUE mod)
01992 {
01993 st_table *tbl = RCLASS_CONST_TBL(mod);
01994 VALUE ary;
01995
01996 if (!tbl) return rb_ary_new2(0);
01997
01998 ary = rb_ary_new2(tbl->num_entries);
01999 st_foreach(tbl, rb_local_constants_i, ary);
02000 return ary;
02001 }
02002
02003 void*
02004 rb_mod_const_at(VALUE mod, void *data)
02005 {
02006 st_table *tbl = data;
02007 if (!tbl) {
02008 tbl = st_init_numtable();
02009 }
02010 if (RCLASS_CONST_TBL(mod)) {
02011 st_foreach_safe(RCLASS_CONST_TBL(mod), sv_i, (st_data_t)tbl);
02012 }
02013 return tbl;
02014 }
02015
02016 void*
02017 rb_mod_const_of(VALUE mod, void *data)
02018 {
02019 VALUE tmp = mod;
02020 for (;;) {
02021 data = rb_mod_const_at(tmp, data);
02022 tmp = RCLASS_SUPER(tmp);
02023 if (!tmp) break;
02024 if (tmp == rb_cObject && mod != rb_cObject) break;
02025 }
02026 return data;
02027 }
02028
02029 static int
02030 list_i(st_data_t key, st_data_t value, VALUE ary)
02031 {
02032 ID sym = (ID)key;
02033 rb_const_entry_t *ce = (rb_const_entry_t *)value;
02034 if (ce->flag != CONST_PRIVATE) rb_ary_push(ary, ID2SYM(sym));
02035 return ST_CONTINUE;
02036 }
02037
02038 VALUE
02039 rb_const_list(void *data)
02040 {
02041 st_table *tbl = data;
02042 VALUE ary;
02043
02044 if (!tbl) return rb_ary_new2(0);
02045 ary = rb_ary_new2(tbl->num_entries);
02046 st_foreach_safe(tbl, list_i, ary);
02047 st_free_table(tbl);
02048
02049 return ary;
02050 }
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070 VALUE
02071 rb_mod_constants(int argc, VALUE *argv, VALUE mod)
02072 {
02073 VALUE inherit;
02074
02075 if (argc == 0) {
02076 inherit = Qtrue;
02077 }
02078 else {
02079 rb_scan_args(argc, argv, "01", &inherit);
02080 }
02081
02082 if (RTEST(inherit)) {
02083 return rb_const_list(rb_mod_const_of(mod, 0));
02084 }
02085 else {
02086 return rb_local_constants(mod);
02087 }
02088 }
02089
02090 static int
02091 rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
02092 {
02093 st_data_t value;
02094 VALUE tmp;
02095 int mod_retry = 0;
02096
02097 tmp = klass;
02098 retry:
02099 while (tmp) {
02100 if (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &value)) {
02101 rb_const_entry_t *ce = (rb_const_entry_t *)value;
02102 if (visibility && ce->flag == CONST_PRIVATE) {
02103 return (int)Qfalse;
02104 }
02105 if (ce->value == Qundef && !check_autoload_required(tmp, id, 0) && !rb_autoloading_value(tmp, id, 0))
02106 return (int)Qfalse;
02107 return (int)Qtrue;
02108 }
02109 if (!recurse) break;
02110 tmp = RCLASS_SUPER(tmp);
02111 }
02112 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
02113 mod_retry = 1;
02114 tmp = rb_cObject;
02115 goto retry;
02116 }
02117 return (int)Qfalse;
02118 }
02119
02120 int
02121 rb_const_defined_from(VALUE klass, ID id)
02122 {
02123 return rb_const_defined_0(klass, id, TRUE, TRUE, FALSE);
02124 }
02125
02126 int
02127 rb_const_defined(VALUE klass, ID id)
02128 {
02129 return rb_const_defined_0(klass, id, FALSE, TRUE, FALSE);
02130 }
02131
02132 int
02133 rb_const_defined_at(VALUE klass, ID id)
02134 {
02135 return rb_const_defined_0(klass, id, TRUE, FALSE, FALSE);
02136 }
02137
02138 int
02139 rb_public_const_defined_from(VALUE klass, ID id)
02140 {
02141 return rb_const_defined_0(klass, id, TRUE, TRUE, TRUE);
02142 }
02143
02144 int
02145 rb_public_const_defined(VALUE klass, ID id)
02146 {
02147 return rb_const_defined_0(klass, id, FALSE, TRUE, TRUE);
02148 }
02149
02150 int
02151 rb_public_const_defined_at(VALUE klass, ID id)
02152 {
02153 return rb_const_defined_0(klass, id, TRUE, FALSE, TRUE);
02154 }
02155
02156 static void
02157 check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
02158 {
02159 rb_check_frozen(klass);
02160 }
02161
02162 void
02163 rb_const_set(VALUE klass, ID id, VALUE val)
02164 {
02165 rb_const_entry_t *ce;
02166 rb_const_flag_t visibility = CONST_PUBLIC;
02167
02168 if (NIL_P(klass)) {
02169 rb_raise(rb_eTypeError, "no class/module to define constant %"PRIsVALUE"",
02170 QUOTE_ID(id));
02171 }
02172
02173 check_before_mod_set(klass, id, val, "constant");
02174 if (!RCLASS_CONST_TBL(klass)) {
02175 RCLASS_CONST_TBL(klass) = st_init_numtable();
02176 }
02177 else {
02178 st_data_t value;
02179
02180 if (st_lookup(RCLASS_CONST_TBL(klass), (st_data_t)id, &value)) {
02181 rb_const_entry_t *ce = (rb_const_entry_t*)value;
02182 if (ce->value == Qundef) {
02183 VALUE load;
02184 struct autoload_data_i *ele;
02185
02186 load = autoload_data(klass, id);
02187
02188 if (load && (ele = check_autoload_data(load)) && (ele->thread == rb_thread_current())) {
02189 rb_clear_constant_cache();
02190
02191 ele->value = val;
02192 return;
02193 }
02194
02195 autoload_delete(klass, id);
02196 }
02197 else {
02198 VALUE name = QUOTE_ID(id);
02199 visibility = ce->flag;
02200 if (klass == rb_cObject)
02201 rb_warn("already initialized constant %"PRIsVALUE"", name);
02202 else
02203 rb_warn("already initialized constant %"PRIsVALUE"::%"PRIsVALUE"",
02204 rb_class_name(klass), name);
02205 if (!NIL_P(ce->file) && ce->line) {
02206 rb_compile_warn(RSTRING_PTR(ce->file), ce->line,
02207 "previous definition of %"PRIsVALUE" was here", name);
02208 }
02209 st_delete(RCLASS_CONST_TBL(klass), &id, 0);
02210 xfree(ce);
02211 }
02212 }
02213 }
02214
02215 rb_clear_constant_cache();
02216
02217
02218 ce = ALLOC(rb_const_entry_t);
02219 MEMZERO(ce, rb_const_entry_t, 1);
02220 ce->flag = visibility;
02221 ce->line = rb_sourceline();
02222 st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
02223 RB_OBJ_WRITE(klass, &ce->value, val);
02224 RB_OBJ_WRITE(klass, &ce->file, rb_sourcefilename());
02225 }
02226
02227 void
02228 rb_define_const(VALUE klass, const char *name, VALUE val)
02229 {
02230 ID id = rb_intern(name);
02231
02232 if (!rb_is_const_id(id)) {
02233 rb_warn("rb_define_const: invalid name `%s' for constant", name);
02234 }
02235 rb_const_set(klass, id, val);
02236 }
02237
02238 void
02239 rb_define_global_const(const char *name, VALUE val)
02240 {
02241 rb_define_const(rb_cObject, name, val);
02242 }
02243
02244 static void
02245 set_const_visibility(VALUE mod, int argc, VALUE *argv, rb_const_flag_t flag)
02246 {
02247 int i;
02248 st_data_t v;
02249 ID id;
02250
02251 if (argc == 0) {
02252 rb_warning("%"PRIsVALUE" with no argument is just ignored",
02253 QUOTE_ID(rb_frame_callee()));
02254 return;
02255 }
02256
02257 for (i = 0; i < argc; i++) {
02258 VALUE val = argv[i];
02259 id = rb_check_id(&val);
02260 if (!id) {
02261 if (i > 0) {
02262 rb_clear_constant_cache();
02263 }
02264
02265 rb_name_error_str(val, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
02266 rb_class_name(mod), QUOTE(val));
02267 }
02268 if (RCLASS_CONST_TBL(mod) &&
02269 st_lookup(RCLASS_CONST_TBL(mod), (st_data_t)id, &v)) {
02270 ((rb_const_entry_t*)v)->flag = flag;
02271 }
02272 else {
02273 if (i > 0) {
02274 rb_clear_constant_cache();
02275 }
02276 rb_name_error(id, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
02277 rb_class_name(mod), QUOTE_ID(id));
02278 }
02279 }
02280 rb_clear_constant_cache();
02281 }
02282
02283
02284
02285
02286
02287
02288
02289
02290 VALUE
02291 rb_mod_private_constant(int argc, VALUE *argv, VALUE obj)
02292 {
02293 set_const_visibility(obj, argc, argv, CONST_PRIVATE);
02294 return obj;
02295 }
02296
02297
02298
02299
02300
02301
02302
02303
02304 VALUE
02305 rb_mod_public_constant(int argc, VALUE *argv, VALUE obj)
02306 {
02307 set_const_visibility(obj, argc, argv, CONST_PUBLIC);
02308 return obj;
02309 }
02310
02311 static VALUE
02312 original_module(VALUE c)
02313 {
02314 if (RB_TYPE_P(c, T_ICLASS))
02315 return RBASIC(c)->klass;
02316 return c;
02317 }
02318
02319 static int
02320 cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
02321 {
02322 if (!RCLASS_IV_TBL(klass)) return 0;
02323 return st_lookup(RCLASS_IV_TBL(klass), (st_data_t)id, v);
02324 }
02325
02326 static VALUE
02327 cvar_front_klass(VALUE klass)
02328 {
02329 if (FL_TEST(klass, FL_SINGLETON)) {
02330 VALUE obj = rb_ivar_get(klass, id__attached__);
02331 if (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS)) {
02332 return obj;
02333 }
02334 }
02335 return RCLASS_SUPER(klass);
02336 }
02337
02338 #define CVAR_FOREACH_ANCESTORS(klass, v, r) \
02339 for (klass = cvar_front_klass(klass); klass; klass = RCLASS_SUPER(klass)) { \
02340 if (cvar_lookup_at(klass, id, (v))) { \
02341 r; \
02342 } \
02343 }
02344
02345 #define CVAR_LOOKUP(v,r) do {\
02346 if (cvar_lookup_at(klass, id, (v))) {r;}\
02347 CVAR_FOREACH_ANCESTORS(klass, v, r);\
02348 } while(0)
02349
02350 void
02351 rb_cvar_set(VALUE klass, ID id, VALUE val)
02352 {
02353 VALUE tmp, front = 0, target = 0;
02354
02355 tmp = klass;
02356 CVAR_LOOKUP(0, {if (!front) front = klass; target = klass;});
02357 if (target) {
02358 if (front && target != front) {
02359 st_data_t did = id;
02360
02361 if (RTEST(ruby_verbose)) {
02362 rb_warning("class variable %"PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
02363 QUOTE_ID(id), rb_class_name(original_module(front)),
02364 rb_class_name(original_module(target)));
02365 }
02366 if (BUILTIN_TYPE(front) == T_CLASS) {
02367 st_delete(RCLASS_IV_TBL(front),&did,0);
02368 }
02369 }
02370 }
02371 else {
02372 target = tmp;
02373 }
02374
02375 check_before_mod_set(target, id, val, "class variable");
02376 if (!RCLASS_IV_TBL(target)) {
02377 RCLASS_IV_TBL(target) = st_init_numtable();
02378 }
02379
02380 rb_st_insert_id_and_value(target, RCLASS_IV_TBL(target), (st_data_t)id, (st_data_t)val);
02381 }
02382
02383 VALUE
02384 rb_cvar_get(VALUE klass, ID id)
02385 {
02386 VALUE tmp, front = 0, target = 0;
02387 st_data_t value;
02388
02389 tmp = klass;
02390 CVAR_LOOKUP(&value, {if (!front) front = klass; target = klass;});
02391 if (!target) {
02392 rb_name_error(id, "uninitialized class variable %"PRIsVALUE" in %"PRIsVALUE"",
02393 QUOTE_ID(id), rb_class_name(tmp));
02394 }
02395 if (front && target != front) {
02396 st_data_t did = id;
02397
02398 if (RTEST(ruby_verbose)) {
02399 rb_warning("class variable %"PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
02400 QUOTE_ID(id), rb_class_name(original_module(front)),
02401 rb_class_name(original_module(target)));
02402 }
02403 if (BUILTIN_TYPE(front) == T_CLASS) {
02404 st_delete(RCLASS_IV_TBL(front),&did,0);
02405 }
02406 }
02407 return (VALUE)value;
02408 }
02409
02410 VALUE
02411 rb_cvar_defined(VALUE klass, ID id)
02412 {
02413 if (!klass) return Qfalse;
02414 CVAR_LOOKUP(0,return Qtrue);
02415 return Qfalse;
02416 }
02417
02418 void
02419 rb_cv_set(VALUE klass, const char *name, VALUE val)
02420 {
02421 ID id = rb_intern(name);
02422 if (!rb_is_class_id(id)) {
02423 rb_name_error(id, "wrong class variable name %s", name);
02424 }
02425 rb_cvar_set(klass, id, val);
02426 }
02427
02428 VALUE
02429 rb_cv_get(VALUE klass, const char *name)
02430 {
02431 ID id = rb_intern(name);
02432 if (!rb_is_class_id(id)) {
02433 rb_name_error(id, "wrong class variable name %s", name);
02434 }
02435 return rb_cvar_get(klass, id);
02436 }
02437
02438 void
02439 rb_define_class_variable(VALUE klass, const char *name, VALUE val)
02440 {
02441 ID id = rb_intern(name);
02442
02443 if (!rb_is_class_id(id)) {
02444 rb_name_error(id, "wrong class variable name %s", name);
02445 }
02446 rb_cvar_set(klass, id, val);
02447 }
02448
02449 static int
02450 cv_i(st_data_t k, st_data_t v, st_data_t a)
02451 {
02452 ID key = (ID)k;
02453 st_table *tbl = (st_table *)a;
02454
02455 if (rb_is_class_id(key)) {
02456 if (!st_lookup(tbl, (st_data_t)key, 0)) {
02457 st_insert(tbl, (st_data_t)key, 0);
02458 }
02459 }
02460 return ST_CONTINUE;
02461 }
02462
02463 static void*
02464 mod_cvar_at(VALUE mod, void *data)
02465 {
02466 st_table *tbl = data;
02467 if (!tbl) {
02468 tbl = st_init_numtable();
02469 }
02470 if (RCLASS_IV_TBL(mod)) {
02471 st_foreach_safe(RCLASS_IV_TBL(mod), cv_i, (st_data_t)tbl);
02472 }
02473 return tbl;
02474 }
02475
02476 static void*
02477 mod_cvar_of(VALUE mod, void *data)
02478 {
02479 VALUE tmp = mod;
02480 for (;;) {
02481 data = mod_cvar_at(tmp, data);
02482 tmp = RCLASS_SUPER(tmp);
02483 if (!tmp) break;
02484 }
02485 return data;
02486 }
02487
02488 static int
02489 cv_list_i(st_data_t key, st_data_t value, VALUE ary)
02490 {
02491 ID sym = (ID)key;
02492 rb_ary_push(ary, ID2SYM(sym));
02493 return ST_CONTINUE;
02494 }
02495
02496 static VALUE
02497 cvar_list(void *data)
02498 {
02499 st_table *tbl = data;
02500 VALUE ary;
02501
02502 if (!tbl) return rb_ary_new2(0);
02503 ary = rb_ary_new2(tbl->num_entries);
02504 st_foreach_safe(tbl, cv_list_i, ary);
02505 st_free_table(tbl);
02506
02507 return ary;
02508 }
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530 VALUE
02531 rb_mod_class_variables(int argc, VALUE *argv, VALUE mod)
02532 {
02533 VALUE inherit;
02534 st_table *tbl;
02535
02536 if (argc == 0) {
02537 inherit = Qtrue;
02538 }
02539 else {
02540 rb_scan_args(argc, argv, "01", &inherit);
02541 }
02542 if (RTEST(inherit)) {
02543 tbl = mod_cvar_of(mod, 0);
02544 }
02545 else {
02546 tbl = mod_cvar_at(mod, 0);
02547 }
02548 return cvar_list(tbl);
02549 }
02550
02551
02552
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570
02571 VALUE
02572 rb_mod_remove_cvar(VALUE mod, VALUE name)
02573 {
02574 const ID id = rb_check_id(&name);
02575 st_data_t val, n = id;
02576
02577 if (!id) {
02578 if (rb_is_class_name(name)) {
02579 rb_name_error_str(name, "class variable %"PRIsVALUE" not defined for %"PRIsVALUE"",
02580 name, rb_class_name(mod));
02581 }
02582 else {
02583 rb_name_error_str(name, "wrong class variable name %"PRIsVALUE"", QUOTE(name));
02584 }
02585 }
02586 if (!rb_is_class_id(id)) {
02587 rb_name_error(id, "wrong class variable name %"PRIsVALUE"", QUOTE_ID(id));
02588 }
02589 rb_check_frozen(mod);
02590 if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), &n, &val)) {
02591 return (VALUE)val;
02592 }
02593 if (rb_cvar_defined(mod, id)) {
02594 rb_name_error(id, "cannot remove %"PRIsVALUE" for %"PRIsVALUE"",
02595 QUOTE_ID(id), rb_class_name(mod));
02596 }
02597 rb_name_error(id, "class variable %"PRIsVALUE" not defined for %"PRIsVALUE"",
02598 QUOTE_ID(id), rb_class_name(mod));
02599
02600 UNREACHABLE;
02601 }
02602
02603 VALUE
02604 rb_iv_get(VALUE obj, const char *name)
02605 {
02606 ID id = rb_intern(name);
02607
02608 return rb_ivar_get(obj, id);
02609 }
02610
02611 VALUE
02612 rb_iv_set(VALUE obj, const char *name, VALUE val)
02613 {
02614 ID id = rb_intern(name);
02615
02616 return rb_ivar_set(obj, id, val);
02617 }
02618
02619
02620 int
02621 rb_st_insert_id_and_value(VALUE obj, st_table *tbl, ID key, VALUE value)
02622 {
02623 int result = st_insert(tbl, (st_data_t)key, (st_data_t)value);
02624 RB_OBJ_WRITTEN(obj, Qundef, value);
02625 return result;
02626 }
02627
02628 static int
02629 tbl_copy_i(st_data_t key, st_data_t value, st_data_t data)
02630 {
02631 RB_OBJ_WRITTEN((VALUE)data, Qundef, (VALUE)value);
02632 return ST_CONTINUE;
02633 }
02634
02635 st_table *
02636 rb_st_copy(VALUE obj, struct st_table *orig_tbl)
02637 {
02638 st_table *new_tbl = st_copy(orig_tbl);
02639 st_foreach(new_tbl, tbl_copy_i, (st_data_t)obj);
02640 return new_tbl;
02641 }
02642