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