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
00020 void rb_vm_change_state(void);
00021 void rb_vm_inc_const_missing_count(void);
00022
00023 st_table *rb_global_tbl;
00024 st_table *rb_class_tbl;
00025 static ID autoload, classpath, tmp_classpath, classid;
00026
00027 void
00028 Init_var_tables(void)
00029 {
00030 rb_global_tbl = st_init_numtable();
00031 rb_class_tbl = st_init_numtable();
00032 CONST_ID(autoload, "__autoload__");
00033 CONST_ID(classpath, "__classpath__");
00034 CONST_ID(tmp_classpath, "__tmp_classpath__");
00035 CONST_ID(classid, "__classid__");
00036 }
00037
00038 struct fc_result {
00039 ID name;
00040 VALUE klass;
00041 VALUE path;
00042 VALUE track;
00043 struct fc_result *prev;
00044 };
00045
00046 static VALUE
00047 fc_path(struct fc_result *fc, ID name)
00048 {
00049 VALUE path, tmp;
00050
00051 path = rb_str_dup(rb_id2str(name));
00052 while (fc) {
00053 st_data_t n;
00054 if (fc->track == rb_cObject) break;
00055 if (RCLASS_IV_TBL(fc->track) &&
00056 st_lookup(RCLASS_IV_TBL(fc->track), (st_data_t)classpath, &n)) {
00057 tmp = rb_str_dup((VALUE)n);
00058 rb_str_cat2(tmp, "::");
00059 rb_str_append(tmp, path);
00060 path = tmp;
00061 break;
00062 }
00063 tmp = rb_str_dup(rb_id2str(fc->name));
00064 rb_str_cat2(tmp, "::");
00065 rb_str_append(tmp, path);
00066 path = tmp;
00067 fc = fc->prev;
00068 }
00069 OBJ_FREEZE(path);
00070 return path;
00071 }
00072
00073 static int
00074 fc_i(ID key, VALUE value, struct fc_result *res)
00075 {
00076 if (!rb_is_const_id(key)) return ST_CONTINUE;
00077
00078 if (value == res->klass) {
00079 res->path = fc_path(res, key);
00080 return ST_STOP;
00081 }
00082 switch (TYPE(value)) {
00083 case T_MODULE:
00084 case T_CLASS:
00085 if (!RCLASS_IV_TBL(value)) return ST_CONTINUE;
00086 else {
00087 struct fc_result arg;
00088 struct fc_result *list;
00089
00090 list = res;
00091 while (list) {
00092 if (list->track == value) return ST_CONTINUE;
00093 list = list->prev;
00094 }
00095
00096 arg.name = key;
00097 arg.path = 0;
00098 arg.klass = res->klass;
00099 arg.track = value;
00100 arg.prev = res;
00101 st_foreach(RCLASS_IV_TBL(value), fc_i, (st_data_t)&arg);
00102 if (arg.path) {
00103 res->path = arg.path;
00104 return ST_STOP;
00105 }
00106 }
00107 break;
00108
00109 default:
00110 break;
00111 }
00112 return ST_CONTINUE;
00113 }
00114
00115 static VALUE
00116 find_class_path(VALUE klass)
00117 {
00118 struct fc_result arg;
00119
00120 arg.name = 0;
00121 arg.path = 0;
00122 arg.klass = klass;
00123 arg.track = rb_cObject;
00124 arg.prev = 0;
00125 if (RCLASS_IV_TBL(rb_cObject)) {
00126 st_foreach_safe(RCLASS_IV_TBL(rb_cObject), fc_i, (st_data_t)&arg);
00127 }
00128 if (arg.path == 0) {
00129 st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg);
00130 }
00131 if (arg.path) {
00132 st_data_t tmp = tmp_classpath;
00133 if (!RCLASS_IV_TBL(klass)) {
00134 RCLASS_IV_TBL(klass) = st_init_numtable();
00135 }
00136 st_insert(RCLASS_IV_TBL(klass), (st_data_t)classpath, arg.path);
00137 st_delete(RCLASS_IV_TBL(klass), &tmp, 0);
00138 return arg.path;
00139 }
00140 return Qnil;
00141 }
00142
00143 static VALUE
00144 classname(VALUE klass)
00145 {
00146 VALUE path = Qnil;
00147 st_data_t n;
00148
00149 if (!klass) klass = rb_cObject;
00150 if (RCLASS_IV_TBL(klass)) {
00151 if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classpath, &n)) {
00152 if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classid, &n)) {
00153 return find_class_path(klass);
00154 }
00155 path = rb_str_dup(rb_id2str(SYM2ID((VALUE)n)));
00156 OBJ_FREEZE(path);
00157 st_insert(RCLASS_IV_TBL(klass), (st_data_t)classpath, (st_data_t)path);
00158 n = classid;
00159 st_delete(RCLASS_IV_TBL(klass), &n, 0);
00160 }
00161 else {
00162 path = (VALUE)n;
00163 }
00164 if (TYPE(path) != T_STRING) {
00165 rb_bug("class path is not set properly");
00166 }
00167 return path;
00168 }
00169 return find_class_path(klass);
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179 VALUE
00180 rb_mod_name(VALUE mod)
00181 {
00182 VALUE path = classname(mod);
00183
00184 if (!NIL_P(path)) return rb_str_dup(path);
00185 return path;
00186 }
00187
00188 VALUE
00189 rb_class_path(VALUE klass)
00190 {
00191 VALUE path = classname(klass);
00192 st_data_t n = (st_data_t)path;
00193
00194 if (!NIL_P(path)) return path;
00195 if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),
00196 (st_data_t)tmp_classpath, &n)) {
00197 return (VALUE)n;
00198 }
00199 else {
00200 const char *s = "Class";
00201
00202 if (TYPE(klass) == T_MODULE) {
00203 if (rb_obj_class(klass) == rb_cModule) {
00204 s = "Module";
00205 }
00206 else {
00207 s = rb_class2name(RBASIC(klass)->klass);
00208 }
00209 }
00210 path = rb_sprintf("#<%s:%p>", s, (void*)klass);
00211 OBJ_FREEZE(path);
00212 rb_ivar_set(klass, tmp_classpath, path);
00213
00214 return path;
00215 }
00216 }
00217
00218 void
00219 rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
00220 {
00221 VALUE str;
00222
00223 if (under == rb_cObject) {
00224 str = rb_str_new_frozen(name);
00225 }
00226 else {
00227 str = rb_str_dup(rb_class_path(under));
00228 rb_str_cat2(str, "::");
00229 rb_str_append(str, name);
00230 OBJ_FREEZE(str);
00231 }
00232 rb_ivar_set(klass, classpath, str);
00233 }
00234
00235 void
00236 rb_set_class_path(VALUE klass, VALUE under, const char *name)
00237 {
00238 VALUE str;
00239
00240 if (under == rb_cObject) {
00241 str = rb_str_new2(name);
00242 }
00243 else {
00244 str = rb_str_dup(rb_class_path(under));
00245 rb_str_cat2(str, "::");
00246 rb_str_cat2(str, name);
00247 }
00248 OBJ_FREEZE(str);
00249 rb_ivar_set(klass, classpath, str);
00250 }
00251
00252 VALUE
00253 rb_path_to_class(VALUE pathname)
00254 {
00255 rb_encoding *enc = rb_enc_get(pathname);
00256 const char *pbeg, *p, *path = RSTRING_PTR(pathname);
00257 ID id;
00258 VALUE c = rb_cObject;
00259
00260 if (!rb_enc_asciicompat(enc)) {
00261 rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
00262 }
00263 pbeg = p = path;
00264 if (path[0] == '#') {
00265 rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path);
00266 }
00267 while (*p) {
00268 while (*p && *p != ':') p++;
00269 id = rb_intern3(pbeg, p-pbeg, enc);
00270 if (p[0] == ':') {
00271 if (p[1] != ':') goto undefined_class;
00272 p += 2;
00273 pbeg = p;
00274 }
00275 if (!rb_const_defined(c, id)) {
00276 undefined_class:
00277 rb_raise(rb_eArgError, "undefined class/module %.*s", (int)(p-path), path);
00278 }
00279 c = rb_const_get_at(c, id);
00280 switch (TYPE(c)) {
00281 case T_MODULE:
00282 case T_CLASS:
00283 break;
00284 default:
00285 rb_raise(rb_eTypeError, "%s does not refer to class/module", path);
00286 }
00287 }
00288
00289 return c;
00290 }
00291
00292 VALUE
00293 rb_path2class(const char *path)
00294 {
00295 return rb_path_to_class(rb_str_new_cstr(path));
00296 }
00297
00298 void
00299 rb_name_class(VALUE klass, ID id)
00300 {
00301 rb_ivar_set(klass, classid, ID2SYM(id));
00302 }
00303
00304 VALUE
00305 rb_class_name(VALUE klass)
00306 {
00307 return rb_class_path(rb_class_real(klass));
00308 }
00309
00310 const char *
00311 rb_class2name(VALUE klass)
00312 {
00313 return RSTRING_PTR(rb_class_name(klass));
00314 }
00315
00316 const char *
00317 rb_obj_classname(VALUE obj)
00318 {
00319 return rb_class2name(CLASS_OF(obj));
00320 }
00321
00322 #define global_variable rb_global_variable
00323 #define global_entry rb_global_entry
00324
00325 #define gvar_getter_t rb_gvar_getter_t
00326 #define gvar_setter_t rb_gvar_setter_t
00327 #define gvar_marker_t rb_gvar_marker_t
00328
00329 struct trace_var {
00330 int removed;
00331 void (*func)(VALUE arg, VALUE val);
00332 VALUE data;
00333 struct trace_var *next;
00334 };
00335
00336 struct global_variable {
00337 int counter;
00338 void *data;
00339 gvar_getter_t *getter;
00340 gvar_setter_t *setter;
00341 gvar_marker_t *marker;
00342 int block_trace;
00343 struct trace_var *trace;
00344 };
00345
00346 #define undef_getter rb_gvar_undef_getter
00347 #define undef_setter rb_gvar_undef_setter
00348 #define undef_marker rb_gvar_undef_marker
00349
00350 #define val_getter rb_gvar_val_getter
00351 #define val_setter rb_gvar_val_setter
00352 #define val_marker rb_gvar_val_marker
00353
00354 #define var_getter rb_gvar_var_getter
00355 #define var_setter rb_gvar_var_setter
00356 #define var_marker rb_gvar_var_marker
00357
00358 #define readonly_setter rb_gvar_readonly_setter
00359
00360 struct global_entry*
00361 rb_global_entry(ID id)
00362 {
00363 struct global_entry *entry;
00364 st_data_t data;
00365
00366 if (!st_lookup(rb_global_tbl, (st_data_t)id, &data)) {
00367 struct global_variable *var;
00368 entry = ALLOC(struct global_entry);
00369 var = ALLOC(struct global_variable);
00370 entry->id = id;
00371 entry->var = var;
00372 var->counter = 1;
00373 var->data = 0;
00374 var->getter = undef_getter;
00375 var->setter = undef_setter;
00376 var->marker = undef_marker;
00377
00378 var->block_trace = 0;
00379 var->trace = 0;
00380 st_add_direct(rb_global_tbl, id, (st_data_t)entry);
00381 }
00382 else {
00383 entry = (struct global_entry *)data;
00384 }
00385 return entry;
00386 }
00387
00388 VALUE
00389 undef_getter(ID id, void *data, struct global_variable *var)
00390 {
00391 rb_warning("global variable `%s' not initialized", rb_id2name(id));
00392
00393 return Qnil;
00394 }
00395
00396 void
00397 undef_setter(VALUE val, ID id, void *data, struct global_variable *var)
00398 {
00399 var->getter = val_getter;
00400 var->setter = val_setter;
00401 var->marker = val_marker;
00402
00403 var->data = (void*)val;
00404 }
00405
00406 void
00407 undef_marker(VALUE *var)
00408 {
00409 }
00410
00411 VALUE
00412 val_getter(ID id, void *data, struct global_variable *var)
00413 {
00414 return (VALUE)data;
00415 }
00416
00417 void
00418 val_setter(VALUE val, ID id, void *data, struct global_variable *var)
00419 {
00420 var->data = (void*)val;
00421 }
00422
00423 void
00424 val_marker(VALUE *var)
00425 {
00426 VALUE data = (VALUE)var;
00427 if (data) rb_gc_mark_maybe(data);
00428 }
00429
00430 VALUE
00431 var_getter(ID id, void *data, struct global_variable *gvar)
00432 {
00433 VALUE *var = data;
00434 if (!var) return Qnil;
00435 return *var;
00436 }
00437
00438 void
00439 var_setter(VALUE val, ID id, void *data, struct global_variable *gvar)
00440 {
00441 *(VALUE *)data = val;
00442 }
00443
00444 void
00445 var_marker(VALUE *var)
00446 {
00447 if (var) rb_gc_mark_maybe(*var);
00448 }
00449
00450 void
00451 readonly_setter(VALUE val, ID id, void *data, struct global_variable *gvar)
00452 {
00453 rb_name_error(id, "%s is a read-only variable", rb_id2name(id));
00454 }
00455
00456 static int
00457 mark_global_entry(ID key, struct global_entry *entry)
00458 {
00459 struct trace_var *trace;
00460 struct global_variable *var = entry->var;
00461
00462 (*var->marker)(var->data);
00463 trace = var->trace;
00464 while (trace) {
00465 if (trace->data) rb_gc_mark_maybe(trace->data);
00466 trace = trace->next;
00467 }
00468 return ST_CONTINUE;
00469 }
00470
00471 void
00472 rb_gc_mark_global_tbl(void)
00473 {
00474 if (rb_global_tbl)
00475 st_foreach_safe(rb_global_tbl, mark_global_entry, 0);
00476 }
00477
00478 static ID
00479 global_id(const char *name)
00480 {
00481 ID id;
00482
00483 if (name[0] == '$') id = rb_intern(name);
00484 else {
00485 size_t len = strlen(name);
00486 char *buf = ALLOCA_N(char, len+1);
00487 buf[0] = '$';
00488 memcpy(buf+1, name, len);
00489 id = rb_intern2(buf, len+1);
00490 }
00491 return id;
00492 }
00493
00494 void
00495 rb_define_hooked_variable(
00496 const char *name,
00497 VALUE *var,
00498 VALUE (*getter)(ANYARGS),
00499 void (*setter)(ANYARGS))
00500 {
00501 volatile VALUE tmp = var ? *var : Qnil;
00502 ID id = global_id(name);
00503 struct global_variable *gvar = rb_global_entry(id)->var;
00504
00505 gvar->data = (void*)var;
00506 gvar->getter = getter?(gvar_getter_t *)getter:var_getter;
00507 gvar->setter = setter?(gvar_setter_t *)setter:var_setter;
00508 gvar->marker = var_marker;
00509
00510 RB_GC_GUARD(tmp);
00511 }
00512
00513 void
00514 rb_define_variable(const char *name, VALUE *var)
00515 {
00516 rb_define_hooked_variable(name, var, 0, 0);
00517 }
00518
00519 void
00520 rb_define_readonly_variable(const char *name, VALUE *var)
00521 {
00522 rb_define_hooked_variable(name, var, 0, readonly_setter);
00523 }
00524
00525 void
00526 rb_define_virtual_variable(
00527 const char *name,
00528 VALUE (*getter)(ANYARGS),
00529 void (*setter)(ANYARGS))
00530 {
00531 if (!getter) getter = val_getter;
00532 if (!setter) setter = readonly_setter;
00533 rb_define_hooked_variable(name, 0, getter, setter);
00534 }
00535
00536 static void
00537 rb_trace_eval(VALUE cmd, VALUE val)
00538 {
00539 rb_eval_cmd(cmd, rb_ary_new3(1, val), 0);
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 VALUE
00566 rb_f_trace_var(int argc, VALUE *argv)
00567 {
00568 VALUE var, cmd;
00569 struct global_entry *entry;
00570 struct trace_var *trace;
00571
00572 rb_secure(4);
00573 if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) {
00574 cmd = rb_block_proc();
00575 }
00576 if (NIL_P(cmd)) {
00577 return rb_f_untrace_var(argc, argv);
00578 }
00579 entry = rb_global_entry(rb_to_id(var));
00580 if (OBJ_TAINTED(cmd)) {
00581 rb_raise(rb_eSecurityError, "Insecure: tainted variable trace");
00582 }
00583 trace = ALLOC(struct trace_var);
00584 trace->next = entry->var->trace;
00585 trace->func = rb_trace_eval;
00586 trace->data = cmd;
00587 trace->removed = 0;
00588 entry->var->trace = trace;
00589
00590 return Qnil;
00591 }
00592
00593 static void
00594 remove_trace(struct global_variable *var)
00595 {
00596 struct trace_var *trace = var->trace;
00597 struct trace_var t;
00598 struct trace_var *next;
00599
00600 t.next = trace;
00601 trace = &t;
00602 while (trace->next) {
00603 next = trace->next;
00604 if (next->removed) {
00605 trace->next = next->next;
00606 xfree(next);
00607 }
00608 else {
00609 trace = next;
00610 }
00611 }
00612 var->trace = t.next;
00613 }
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 VALUE
00626 rb_f_untrace_var(int argc, VALUE *argv)
00627 {
00628 VALUE var, cmd;
00629 ID id;
00630 struct global_entry *entry;
00631 struct trace_var *trace;
00632 st_data_t data;
00633
00634 rb_secure(4);
00635 rb_scan_args(argc, argv, "11", &var, &cmd);
00636 id = rb_to_id(var);
00637 if (!st_lookup(rb_global_tbl, (st_data_t)id, &data)) {
00638 rb_name_error(id, "undefined global variable %s", rb_id2name(id));
00639 }
00640
00641 trace = (entry = (struct global_entry *)data)->var->trace;
00642 if (NIL_P(cmd)) {
00643 VALUE ary = rb_ary_new();
00644
00645 while (trace) {
00646 struct trace_var *next = trace->next;
00647 rb_ary_push(ary, (VALUE)trace->data);
00648 trace->removed = 1;
00649 trace = next;
00650 }
00651
00652 if (!entry->var->block_trace) remove_trace(entry->var);
00653 return ary;
00654 }
00655 else {
00656 while (trace) {
00657 if (trace->data == cmd) {
00658 trace->removed = 1;
00659 if (!entry->var->block_trace) remove_trace(entry->var);
00660 return rb_ary_new3(1, cmd);
00661 }
00662 trace = trace->next;
00663 }
00664 }
00665 return Qnil;
00666 }
00667
00668 VALUE
00669 rb_gvar_get(struct global_entry *entry)
00670 {
00671 struct global_variable *var = entry->var;
00672 return (*var->getter)(entry->id, var->data, var);
00673 }
00674
00675 struct trace_data {
00676 struct trace_var *trace;
00677 VALUE val;
00678 };
00679
00680 static VALUE
00681 trace_ev(struct trace_data *data)
00682 {
00683 struct trace_var *trace = data->trace;
00684
00685 while (trace) {
00686 (*trace->func)(trace->data, data->val);
00687 trace = trace->next;
00688 }
00689 return Qnil;
00690 }
00691
00692 static VALUE
00693 trace_en(struct global_variable *var)
00694 {
00695 var->block_trace = 0;
00696 remove_trace(var);
00697 return Qnil;
00698 }
00699
00700 VALUE
00701 rb_gvar_set(struct global_entry *entry, VALUE val)
00702 {
00703 struct trace_data trace;
00704 struct global_variable *var = entry->var;
00705
00706 if (rb_safe_level() >= 4)
00707 rb_raise(rb_eSecurityError, "Insecure: can't change global variable value");
00708 (*var->setter)(val, entry->id, var->data, var);
00709
00710 if (var->trace && !var->block_trace) {
00711 var->block_trace = 1;
00712 trace.trace = var->trace;
00713 trace.val = val;
00714 rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
00715 }
00716 return val;
00717 }
00718
00719 VALUE
00720 rb_gv_set(const char *name, VALUE val)
00721 {
00722 struct global_entry *entry;
00723
00724 entry = rb_global_entry(global_id(name));
00725 return rb_gvar_set(entry, val);
00726 }
00727
00728 VALUE
00729 rb_gv_get(const char *name)
00730 {
00731 struct global_entry *entry;
00732
00733 entry = rb_global_entry(global_id(name));
00734 return rb_gvar_get(entry);
00735 }
00736
00737 VALUE
00738 rb_gvar_defined(struct global_entry *entry)
00739 {
00740 if (entry->var->getter == undef_getter) return Qfalse;
00741 return Qtrue;
00742 }
00743
00744 static int
00745 gvar_i(ID key, struct global_entry *entry, VALUE ary)
00746 {
00747 rb_ary_push(ary, ID2SYM(key));
00748 return ST_CONTINUE;
00749 }
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760 VALUE
00761 rb_f_global_variables(void)
00762 {
00763 VALUE ary = rb_ary_new();
00764 char buf[2];
00765 int i;
00766
00767 st_foreach_safe(rb_global_tbl, gvar_i, ary);
00768 buf[0] = '$';
00769 for (i = 1; i <= 9; ++i) {
00770 buf[1] = (char)(i + '0');
00771 rb_ary_push(ary, ID2SYM(rb_intern2(buf, 2)));
00772 }
00773 return ary;
00774 }
00775
00776 void
00777 rb_alias_variable(ID name1, ID name2)
00778 {
00779 struct global_entry *entry1, *entry2;
00780 st_data_t data1;
00781
00782 if (rb_safe_level() >= 4)
00783 rb_raise(rb_eSecurityError, "Insecure: can't alias global variable");
00784
00785 entry2 = rb_global_entry(name2);
00786 if (!st_lookup(rb_global_tbl, (st_data_t)name1, &data1)) {
00787 entry1 = ALLOC(struct global_entry);
00788 entry1->id = name1;
00789 st_add_direct(rb_global_tbl, name1, (st_data_t)entry1);
00790 }
00791 else if ((entry1 = (struct global_entry *)data1)->var != entry2->var) {
00792 struct global_variable *var = entry1->var;
00793 if (var->block_trace) {
00794 rb_raise(rb_eRuntimeError, "can't alias in tracer");
00795 }
00796 var->counter--;
00797 if (var->counter == 0) {
00798 struct trace_var *trace = var->trace;
00799 while (trace) {
00800 struct trace_var *next = trace->next;
00801 xfree(trace);
00802 trace = next;
00803 }
00804 xfree(var);
00805 }
00806 }
00807 else {
00808 return;
00809 }
00810 entry2->var->counter++;
00811 entry1->var = entry2->var;
00812 }
00813
00814 static int special_generic_ivar = 0;
00815 static st_table *generic_iv_tbl;
00816
00817 st_table*
00818 rb_generic_ivar_table(VALUE obj)
00819 {
00820 st_data_t tbl;
00821
00822 if (!FL_TEST(obj, FL_EXIVAR)) return 0;
00823 if (!generic_iv_tbl) return 0;
00824 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) return 0;
00825 return (st_table *)tbl;
00826 }
00827
00828 static VALUE
00829 generic_ivar_get(VALUE obj, ID id, int warn)
00830 {
00831 st_data_t tbl, val;
00832
00833 if (generic_iv_tbl) {
00834 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
00835 if (st_lookup((st_table *)tbl, (st_data_t)id, &val)) {
00836 return (VALUE)val;
00837 }
00838 }
00839 }
00840 if (warn) {
00841 rb_warning("instance variable %s not initialized", rb_id2name(id));
00842 }
00843 return Qnil;
00844 }
00845
00846 static void
00847 generic_ivar_set(VALUE obj, ID id, VALUE val)
00848 {
00849 st_table *tbl;
00850 st_data_t data;
00851
00852 if (rb_special_const_p(obj)) {
00853 if (rb_obj_frozen_p(obj)) rb_error_frozen("object");
00854 special_generic_ivar = 1;
00855 }
00856 if (!generic_iv_tbl) {
00857 generic_iv_tbl = st_init_numtable();
00858 }
00859 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
00860 FL_SET(obj, FL_EXIVAR);
00861 tbl = st_init_numtable();
00862 st_add_direct(generic_iv_tbl, (st_data_t)obj, (st_data_t)tbl);
00863 st_add_direct(tbl, (st_data_t)id, (st_data_t)val);
00864 return;
00865 }
00866 st_insert((st_table *)data, (st_data_t)id, (st_data_t)val);
00867 }
00868
00869 static VALUE
00870 generic_ivar_defined(VALUE obj, ID id)
00871 {
00872 st_table *tbl;
00873 st_data_t data;
00874
00875 if (!generic_iv_tbl) return Qfalse;
00876 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return Qfalse;
00877 tbl = (st_table *)data;
00878 if (st_lookup(tbl, (st_data_t)id, &data)) {
00879 return Qtrue;
00880 }
00881 return Qfalse;
00882 }
00883
00884 static int
00885 generic_ivar_remove(VALUE obj, ID id, st_data_t *valp)
00886 {
00887 st_table *tbl;
00888 st_data_t data;
00889 int status;
00890
00891 if (!generic_iv_tbl) return 0;
00892 if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return 0;
00893 tbl = (st_table *)data;
00894 status = st_delete(tbl, &id, valp);
00895 if (tbl->num_entries == 0) {
00896 st_delete(generic_iv_tbl, &obj, &data);
00897 st_free_table((st_table *)data);
00898 }
00899 return status;
00900 }
00901
00902 void
00903 rb_mark_generic_ivar(VALUE obj)
00904 {
00905 st_data_t tbl;
00906
00907 if (!generic_iv_tbl) return;
00908 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
00909 rb_mark_tbl((st_table *)tbl);
00910 }
00911 }
00912
00913 static int
00914 givar_mark_i(ID key, VALUE value)
00915 {
00916 rb_gc_mark(value);
00917 return ST_CONTINUE;
00918 }
00919
00920 static int
00921 givar_i(VALUE obj, st_table *tbl)
00922 {
00923 if (rb_special_const_p(obj)) {
00924 st_foreach_safe(tbl, givar_mark_i, 0);
00925 }
00926 return ST_CONTINUE;
00927 }
00928
00929 void
00930 rb_mark_generic_ivar_tbl(void)
00931 {
00932 if (!generic_iv_tbl) return;
00933 if (special_generic_ivar == 0) return;
00934 st_foreach_safe(generic_iv_tbl, givar_i, 0);
00935 }
00936
00937 void
00938 rb_free_generic_ivar(VALUE obj)
00939 {
00940 st_data_t key = (st_data_t)obj, tbl;
00941
00942 if (!generic_iv_tbl) return;
00943 if (st_delete(generic_iv_tbl, &key, &tbl))
00944 st_free_table((st_table *)tbl);
00945 }
00946
00947 size_t
00948 rb_generic_ivar_memsize(VALUE obj)
00949 {
00950 st_data_t tbl;
00951 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl))
00952 return st_memsize((st_table *)tbl);
00953 return 0;
00954 }
00955
00956 void
00957 rb_copy_generic_ivar(VALUE clone, VALUE obj)
00958 {
00959 st_data_t data;
00960
00961 if (!generic_iv_tbl) return;
00962 if (!FL_TEST(obj, FL_EXIVAR)) {
00963 clear:
00964 if (FL_TEST(clone, FL_EXIVAR)) {
00965 rb_free_generic_ivar(clone);
00966 FL_UNSET(clone, FL_EXIVAR);
00967 }
00968 return;
00969 }
00970 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
00971 st_table *tbl = (st_table *)data;
00972
00973 if (tbl->num_entries == 0)
00974 goto clear;
00975
00976 if (st_lookup(generic_iv_tbl, (st_data_t)clone, &data)) {
00977 st_free_table((st_table *)data);
00978 st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
00979 }
00980 else {
00981 st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
00982 FL_SET(clone, FL_EXIVAR);
00983 }
00984 }
00985 }
00986
00987 static VALUE
00988 ivar_get(VALUE obj, ID id, int warn)
00989 {
00990 VALUE val, *ptr;
00991 struct st_table *iv_index_tbl;
00992 long len;
00993 st_data_t index;
00994
00995 switch (TYPE(obj)) {
00996 case T_OBJECT:
00997 len = ROBJECT_NUMIV(obj);
00998 ptr = ROBJECT_IVPTR(obj);
00999 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01000 if (!iv_index_tbl) break;
01001 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01002 if (len <= (long)index) break;
01003 val = ptr[index];
01004 if (val != Qundef)
01005 return val;
01006 break;
01007 case T_CLASS:
01008 case T_MODULE:
01009 if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, &val))
01010 return val;
01011 break;
01012 default:
01013 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01014 return generic_ivar_get(obj, id, warn);
01015 break;
01016 }
01017 if (warn) {
01018 rb_warning("instance variable %s not initialized", rb_id2name(id));
01019 }
01020 return Qnil;
01021 }
01022
01023 VALUE
01024 rb_ivar_get(VALUE obj, ID id)
01025 {
01026 return ivar_get(obj, id, TRUE);
01027 }
01028
01029 VALUE
01030 rb_attr_get(VALUE obj, ID id)
01031 {
01032 return ivar_get(obj, id, FALSE);
01033 }
01034
01035 VALUE
01036 rb_ivar_set(VALUE obj, ID id, VALUE val)
01037 {
01038 struct st_table *iv_index_tbl;
01039 st_data_t index;
01040 long i, len;
01041 int ivar_extended;
01042
01043 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
01044 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
01045 if (OBJ_FROZEN(obj)) rb_error_frozen("object");
01046 switch (TYPE(obj)) {
01047 case T_OBJECT:
01048 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01049 if (!iv_index_tbl) {
01050 VALUE klass = rb_obj_class(obj);
01051 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
01052 if (!iv_index_tbl) {
01053 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
01054 }
01055 }
01056 ivar_extended = 0;
01057 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
01058 index = iv_index_tbl->num_entries;
01059 st_add_direct(iv_index_tbl, (st_data_t)id, index);
01060 ivar_extended = 1;
01061 }
01062 len = ROBJECT_NUMIV(obj);
01063 if (len <= (long)index) {
01064 VALUE *ptr = ROBJECT_IVPTR(obj);
01065 if (index < ROBJECT_EMBED_LEN_MAX) {
01066 RBASIC(obj)->flags |= ROBJECT_EMBED;
01067 ptr = ROBJECT(obj)->as.ary;
01068 for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
01069 ptr[i] = Qundef;
01070 }
01071 }
01072 else {
01073 VALUE *newptr;
01074 long newsize = (index+1) + (index+1)/4;
01075 if (!ivar_extended &&
01076 iv_index_tbl->num_entries < (st_index_t)newsize) {
01077 newsize = iv_index_tbl->num_entries;
01078 }
01079 if (RBASIC(obj)->flags & ROBJECT_EMBED) {
01080 newptr = ALLOC_N(VALUE, newsize);
01081 MEMCPY(newptr, ptr, VALUE, len);
01082 RBASIC(obj)->flags &= ~ROBJECT_EMBED;
01083 ROBJECT(obj)->as.heap.ivptr = newptr;
01084 }
01085 else {
01086 REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
01087 newptr = ROBJECT(obj)->as.heap.ivptr;
01088 }
01089 for (; len < newsize; len++)
01090 newptr[len] = Qundef;
01091 ROBJECT(obj)->as.heap.numiv = newsize;
01092 ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
01093 }
01094 }
01095 ROBJECT_IVPTR(obj)[index] = val;
01096 break;
01097 case T_CLASS:
01098 case T_MODULE:
01099 if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
01100 st_insert(RCLASS_IV_TBL(obj), (st_data_t)id, val);
01101 break;
01102 default:
01103 generic_ivar_set(obj, id, val);
01104 break;
01105 }
01106 return val;
01107 }
01108
01109 VALUE
01110 rb_ivar_defined(VALUE obj, ID id)
01111 {
01112 VALUE val;
01113 struct st_table *iv_index_tbl;
01114 st_data_t index;
01115 switch (TYPE(obj)) {
01116 case T_OBJECT:
01117 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01118 if (!iv_index_tbl) break;
01119 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01120 if (ROBJECT_NUMIV(obj) <= (long)index) break;
01121 val = ROBJECT_IVPTR(obj)[index];
01122 if (val != Qundef)
01123 return Qtrue;
01124 break;
01125 case T_CLASS:
01126 case T_MODULE:
01127 if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, 0))
01128 return Qtrue;
01129 break;
01130 default:
01131 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01132 return generic_ivar_defined(obj, id);
01133 break;
01134 }
01135 return Qfalse;
01136 }
01137
01138 struct obj_ivar_tag {
01139 VALUE obj;
01140 int (*func)(ID key, VALUE val, st_data_t arg);
01141 st_data_t arg;
01142 };
01143
01144 static int
01145 obj_ivar_i(st_data_t key, st_data_t index, st_data_t arg)
01146 {
01147 struct obj_ivar_tag *data = (struct obj_ivar_tag *)arg;
01148 if ((long)index < ROBJECT_NUMIV(data->obj)) {
01149 VALUE val = ROBJECT_IVPTR(data->obj)[(long)index];
01150 if (val != Qundef) {
01151 return (data->func)((ID)key, val, data->arg);
01152 }
01153 }
01154 return ST_CONTINUE;
01155 }
01156
01157 static void
01158 obj_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01159 {
01160 st_table *tbl;
01161 struct obj_ivar_tag data;
01162
01163 tbl = ROBJECT_IV_INDEX_TBL(obj);
01164 if (!tbl)
01165 return;
01166
01167 data.obj = obj;
01168 data.func = (int (*)(ID key, VALUE val, st_data_t arg))func;
01169 data.arg = arg;
01170
01171 st_foreach_safe(tbl, obj_ivar_i, (st_data_t)&data);
01172 }
01173
01174 void
01175 rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01176 {
01177 switch (TYPE(obj)) {
01178 case T_OBJECT:
01179 obj_ivar_each(obj, func, arg);
01180 break;
01181 case T_CLASS:
01182 case T_MODULE:
01183 if (RCLASS_IV_TBL(obj)) {
01184 st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
01185 }
01186 break;
01187 default:
01188 if (!generic_iv_tbl) break;
01189 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01190 st_data_t tbl;
01191
01192 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
01193 st_foreach_safe((st_table *)tbl, func, arg);
01194 }
01195 }
01196 break;
01197 }
01198 }
01199
01200 st_index_t
01201 rb_ivar_count(VALUE obj)
01202 {
01203 st_table *tbl;
01204 switch (TYPE(obj)) {
01205 case T_OBJECT:
01206 if ((tbl = ROBJECT_IV_INDEX_TBL(obj)) != 0) {
01207 st_index_t i, num = tbl->num_entries, count = 0;
01208 const VALUE *const ivptr = ROBJECT_IVPTR(obj);
01209 for (i = count = 0; i < num; ++i) {
01210 if (ivptr[i] != Qundef) {
01211 count++;
01212 }
01213 }
01214 return count;
01215 }
01216 break;
01217 case T_CLASS:
01218 case T_MODULE:
01219 if ((tbl = RCLASS_IV_TBL(obj)) != 0) {
01220 return tbl->num_entries;
01221 }
01222 break;
01223 default:
01224 if (!generic_iv_tbl) break;
01225 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01226 st_data_t data;
01227
01228 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data) &&
01229 (tbl = (st_table *)data) != 0) {
01230 return tbl->num_entries;
01231 }
01232 }
01233 break;
01234 }
01235 return 0;
01236 }
01237
01238 static int
01239 ivar_i(ID key, VALUE val, VALUE ary)
01240 {
01241 if (rb_is_instance_id(key)) {
01242 rb_ary_push(ary, ID2SYM(key));
01243 }
01244 return ST_CONTINUE;
01245 }
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264 VALUE
01265 rb_obj_instance_variables(VALUE obj)
01266 {
01267 VALUE ary;
01268
01269 ary = rb_ary_new();
01270 rb_ivar_foreach(obj, ivar_i, ary);
01271 return ary;
01272 }
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296 VALUE
01297 rb_obj_remove_instance_variable(VALUE obj, VALUE name)
01298 {
01299 VALUE val = Qnil;
01300 const ID id = rb_to_id(name);
01301 st_data_t n, v;
01302 struct st_table *iv_index_tbl;
01303 st_data_t index;
01304
01305 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
01306 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
01307 if (OBJ_FROZEN(obj)) rb_error_frozen("object");
01308 if (!rb_is_instance_id(id)) {
01309 rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id));
01310 }
01311
01312 switch (TYPE(obj)) {
01313 case T_OBJECT:
01314 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01315 if (!iv_index_tbl) break;
01316 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01317 if (ROBJECT_NUMIV(obj) <= (long)index) break;
01318 val = ROBJECT_IVPTR(obj)[index];
01319 if (val != Qundef) {
01320 ROBJECT_IVPTR(obj)[index] = Qundef;
01321 return val;
01322 }
01323 break;
01324 case T_CLASS:
01325 case T_MODULE:
01326 n = id;
01327 if (RCLASS_IV_TBL(obj) && st_delete(RCLASS_IV_TBL(obj), &n, &v)) {
01328 return (VALUE)v;
01329 }
01330 break;
01331 default:
01332 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01333 v = val;
01334 if (generic_ivar_remove(obj, (st_data_t)id, &v)) {
01335 return (VALUE)v;
01336 }
01337 }
01338 break;
01339 }
01340 rb_name_error(id, "instance variable %s not defined", rb_id2name(id));
01341 return Qnil;
01342 }
01343
01344 NORETURN(static void uninitialized_constant(VALUE, ID));
01345 static void
01346 uninitialized_constant(VALUE klass, ID id)
01347 {
01348 if (klass && klass != rb_cObject)
01349 rb_name_error(id, "uninitialized constant %s::%s",
01350 rb_class2name(klass),
01351 rb_id2name(id));
01352 else {
01353 rb_name_error(id, "uninitialized constant %s", rb_id2name(id));
01354 }
01355 }
01356
01357 static VALUE
01358 const_missing(VALUE klass, ID id)
01359 {
01360 return rb_funcall(klass, rb_intern("const_missing"), 1, ID2SYM(id));
01361 }
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392 VALUE
01393 rb_mod_const_missing(VALUE klass, VALUE name)
01394 {
01395 rb_frame_pop();
01396 uninitialized_constant(klass, rb_to_id(name));
01397 return Qnil;
01398 }
01399
01400 static void
01401 autoload_mark(void *ptr)
01402 {
01403 rb_mark_tbl((st_table *)ptr);
01404 }
01405
01406 static void
01407 autoload_free(void *ptr)
01408 {
01409 st_free_table((st_table *)ptr);
01410 }
01411
01412 static size_t
01413 autoload_memsize(const void *ptr)
01414 {
01415 const st_table *tbl = ptr;
01416 return st_memsize(tbl);
01417 }
01418
01419 static const rb_data_type_t autoload_data_type = {
01420 "autoload",
01421 autoload_mark, autoload_free, autoload_memsize,
01422 };
01423
01424 #define check_autoload_table(av) \
01425 (struct st_table *)rb_check_typeddata(av, &autoload_data_type)
01426
01427 void
01428 rb_autoload(VALUE mod, ID id, const char *file)
01429 {
01430 st_data_t av;
01431 VALUE fn;
01432 struct st_table *tbl;
01433
01434 if (!rb_is_const_id(id)) {
01435 rb_raise(rb_eNameError, "autoload must be constant name: %s", rb_id2name(id));
01436 }
01437 if (!file || !*file) {
01438 rb_raise(rb_eArgError, "empty file name");
01439 }
01440
01441 if ((tbl = RCLASS_IV_TBL(mod)) && st_lookup(tbl, (st_data_t)id, &av) && (VALUE)av != Qundef)
01442 return;
01443
01444 rb_const_set(mod, id, Qundef);
01445 tbl = RCLASS_IV_TBL(mod);
01446 if (st_lookup(tbl, (st_data_t)autoload, &av)) {
01447 tbl = check_autoload_table((VALUE)av);
01448 }
01449 else {
01450 av = (st_data_t)TypedData_Wrap_Struct(0, &autoload_data_type, 0);
01451 st_add_direct(tbl, (st_data_t)autoload, av);
01452 DATA_PTR(av) = tbl = st_init_numtable();
01453 }
01454 fn = rb_str_new2(file);
01455 FL_UNSET(fn, FL_TAINT);
01456 OBJ_FREEZE(fn);
01457 st_insert(tbl, (st_data_t)id, (st_data_t)rb_node_newnode(NODE_MEMO, fn, rb_safe_level(), 0));
01458 }
01459
01460 static NODE*
01461 autoload_delete(VALUE mod, ID id)
01462 {
01463 st_data_t val, load = 0, n = id;
01464
01465 st_delete(RCLASS_IV_TBL(mod), &n, 0);
01466 if (st_lookup(RCLASS_IV_TBL(mod), (st_data_t)autoload, &val)) {
01467 struct st_table *tbl = check_autoload_table((VALUE)val);
01468
01469 st_delete(tbl, &n, &load);
01470
01471 if (tbl->num_entries == 0) {
01472 n = autoload;
01473 st_delete(RCLASS_IV_TBL(mod), &n, &val);
01474 }
01475 }
01476
01477 return (NODE *)load;
01478 }
01479
01480 static VALUE
01481 autoload_provided(VALUE arg)
01482 {
01483 const char **p = (const char **)arg;
01484 return rb_feature_provided(*p, p);
01485 }
01486
01487 static VALUE
01488 reset_safe(VALUE safe)
01489 {
01490 rb_set_safe_level_force((int)safe);
01491 return safe;
01492 }
01493
01494 static NODE *
01495 autoload_node(VALUE mod, ID id, const char **loadingpath)
01496 {
01497 VALUE file;
01498 struct st_table *tbl;
01499 st_data_t val;
01500 NODE *load;
01501 const char *loading;
01502 int safe;
01503
01504 if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
01505 !(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, (st_data_t)id, &val)) {
01506 return 0;
01507 }
01508 load = (NODE *)val;
01509 file = load->nd_lit;
01510 Check_Type(file, T_STRING);
01511 if (!RSTRING_PTR(file) || !*RSTRING_PTR(file)) {
01512 rb_raise(rb_eArgError, "empty file name");
01513 }
01514 loading = RSTRING_PTR(file);
01515 safe = rb_safe_level();
01516 rb_set_safe_level_force(0);
01517 if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
01518 return load;
01519 }
01520 if (loadingpath && loading) {
01521 *loadingpath = loading;
01522 return load;
01523 }
01524 return 0;
01525 }
01526
01527 static int
01528 autoload_node_id(VALUE mod, ID id)
01529 {
01530 struct st_table *tbl = RCLASS_IV_TBL(mod);
01531 st_data_t val;
01532
01533 if (!tbl || !st_lookup(tbl, (st_data_t)id, &val) || (VALUE)val != Qundef) {
01534 return 0;
01535 }
01536 return 1;
01537 }
01538
01539 VALUE
01540 rb_autoload_load(VALUE mod, ID id)
01541 {
01542 VALUE file;
01543 NODE *load;
01544 const char *loading = 0, *src;
01545
01546 if (!autoload_node_id(mod, id)) return Qfalse;
01547 load = autoload_node(mod, id, &loading);
01548 if (!load) return Qfalse;
01549 src = rb_sourcefile();
01550 if (src && loading && strcmp(src, loading) == 0) return Qfalse;
01551 file = load->nd_lit;
01552 return rb_require_safe(file, (int)load->nd_nth);
01553 }
01554
01555 VALUE
01556 rb_autoload_p(VALUE mod, ID id)
01557 {
01558 VALUE file;
01559 NODE *load;
01560 const char *loading = 0;
01561
01562 if (!autoload_node_id(mod, id)) return Qnil;
01563 load = autoload_node(mod, id, &loading);
01564 if (!load) return Qnil;
01565 return load && (file = load->nd_lit) ? file : Qnil;
01566 }
01567
01568 static VALUE
01569 rb_const_get_0(VALUE klass, ID id, int exclude, int recurse)
01570 {
01571 VALUE value, tmp;
01572 int mod_retry = 0;
01573
01574 tmp = klass;
01575 retry:
01576 while (RTEST(tmp)) {
01577 VALUE am = 0;
01578 while (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp), (st_data_t)id, &value)) {
01579 if (value == Qundef) {
01580 if (am == tmp) break;
01581 am = tmp;
01582 rb_autoload_load(tmp, id);
01583 continue;
01584 }
01585 if (exclude && tmp == rb_cObject && klass != rb_cObject) {
01586 rb_warn("toplevel constant %s referenced by %s::%s",
01587 rb_id2name(id), rb_class2name(klass), rb_id2name(id));
01588 }
01589 return value;
01590 }
01591 if (!recurse && klass != rb_cObject) break;
01592 tmp = RCLASS_SUPER(tmp);
01593 }
01594 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
01595 mod_retry = 1;
01596 tmp = rb_cObject;
01597 goto retry;
01598 }
01599
01600 value = const_missing(klass, id);
01601 rb_vm_inc_const_missing_count();
01602 return value;
01603 }
01604
01605 VALUE
01606 rb_const_get_from(VALUE klass, ID id)
01607 {
01608 return rb_const_get_0(klass, id, TRUE, TRUE);
01609 }
01610
01611 VALUE
01612 rb_const_get(VALUE klass, ID id)
01613 {
01614 return rb_const_get_0(klass, id, FALSE, TRUE);
01615 }
01616
01617 VALUE
01618 rb_const_get_at(VALUE klass, ID id)
01619 {
01620 return rb_const_get_0(klass, id, TRUE, FALSE);
01621 }
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632 VALUE
01633 rb_mod_remove_const(VALUE mod, VALUE name)
01634 {
01635 const ID id = rb_to_id(name);
01636
01637 if (!rb_is_const_id(id)) {
01638 rb_name_error(id, "`%s' is not allowed as a constant name", rb_id2name(id));
01639 }
01640 return rb_const_remove(mod, id);
01641 }
01642
01643 VALUE
01644 rb_const_remove(VALUE mod, ID id)
01645 {
01646 VALUE val;
01647 st_data_t v, n = id;
01648
01649 if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4)
01650 rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
01651 if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
01652
01653 if (!RCLASS_IV_TBL(mod) || !st_delete(RCLASS_IV_TBL(mod), &n, &v)) {
01654 if (rb_const_defined_at(mod, id)) {
01655 rb_name_error(id, "cannot remove %s::%s",
01656 rb_class2name(mod), rb_id2name(id));
01657 }
01658 rb_name_error(id, "constant %s::%s not defined",
01659 rb_class2name(mod), rb_id2name(id));
01660 }
01661
01662 rb_vm_change_state();
01663
01664 val = (VALUE)v;
01665 if (val == Qundef) {
01666 autoload_delete(mod, id);
01667 val = Qnil;
01668 }
01669 return val;
01670 }
01671
01672 static int
01673 sv_i(ID key, VALUE value, st_table *tbl)
01674 {
01675 if (rb_is_const_id(key)) {
01676 if (!st_lookup(tbl, (st_data_t)key, 0)) {
01677 st_insert(tbl, (st_data_t)key, (st_data_t)key);
01678 }
01679 }
01680 return ST_CONTINUE;
01681 }
01682
01683 void*
01684 rb_mod_const_at(VALUE mod, void *data)
01685 {
01686 st_table *tbl = data;
01687 if (!tbl) {
01688 tbl = st_init_numtable();
01689 }
01690 if (RCLASS_IV_TBL(mod)) {
01691 st_foreach_safe(RCLASS_IV_TBL(mod), sv_i, (st_data_t)tbl);
01692 }
01693 return tbl;
01694 }
01695
01696 void*
01697 rb_mod_const_of(VALUE mod, void *data)
01698 {
01699 VALUE tmp = mod;
01700 for (;;) {
01701 data = rb_mod_const_at(tmp, data);
01702 tmp = RCLASS_SUPER(tmp);
01703 if (!tmp) break;
01704 if (tmp == rb_cObject && mod != rb_cObject) break;
01705 }
01706 return data;
01707 }
01708
01709 static int
01710 list_i(ID key, ID value, VALUE ary)
01711 {
01712 rb_ary_push(ary, ID2SYM(key));
01713 return ST_CONTINUE;
01714 }
01715
01716 VALUE
01717 rb_const_list(void *data)
01718 {
01719 st_table *tbl = data;
01720 VALUE ary;
01721
01722 if (!tbl) return rb_ary_new2(0);
01723 ary = rb_ary_new2(tbl->num_entries);
01724 st_foreach_safe(tbl, list_i, ary);
01725 st_free_table(tbl);
01726
01727 return ary;
01728 }
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745 VALUE
01746 rb_mod_constants(int argc, VALUE *argv, VALUE mod)
01747 {
01748 VALUE inherit;
01749 st_table *tbl;
01750
01751 if (argc == 0) {
01752 inherit = Qtrue;
01753 }
01754 else {
01755 rb_scan_args(argc, argv, "01", &inherit);
01756 }
01757 if (RTEST(inherit)) {
01758 tbl = rb_mod_const_of(mod, 0);
01759 }
01760 else {
01761 tbl = rb_mod_const_at(mod, 0);
01762 }
01763 return rb_const_list(tbl);
01764 }
01765
01766 static int
01767 rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse)
01768 {
01769 st_data_t value;
01770 VALUE tmp;
01771 int mod_retry = 0;
01772
01773 tmp = klass;
01774 retry:
01775 while (tmp) {
01776 if (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp), (st_data_t)id, &value)) {
01777 if ((VALUE)value == Qundef && !autoload_node((VALUE)klass, id, 0))
01778 return (int)Qfalse;
01779 return (int)Qtrue;
01780 }
01781 if (!recurse && klass != rb_cObject) break;
01782 tmp = RCLASS_SUPER(tmp);
01783 }
01784 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
01785 mod_retry = 1;
01786 tmp = rb_cObject;
01787 goto retry;
01788 }
01789 return (int)Qfalse;
01790 }
01791
01792 int
01793 rb_const_defined_from(VALUE klass, ID id)
01794 {
01795 return rb_const_defined_0(klass, id, TRUE, TRUE);
01796 }
01797
01798 int
01799 rb_const_defined(VALUE klass, ID id)
01800 {
01801 return rb_const_defined_0(klass, id, FALSE, TRUE);
01802 }
01803
01804 int
01805 rb_const_defined_at(VALUE klass, ID id)
01806 {
01807 return rb_const_defined_0(klass, id, TRUE, FALSE);
01808 }
01809
01810 static void
01811 mod_av_set(VALUE klass, ID id, VALUE val, int isconst)
01812 {
01813 const char *dest = isconst ? "constant" : "class variable";
01814
01815 if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4)
01816 rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest);
01817 if (OBJ_FROZEN(klass)) {
01818 if (BUILTIN_TYPE(klass) == T_MODULE) {
01819 rb_error_frozen("module");
01820 }
01821 else {
01822 rb_error_frozen("class");
01823 }
01824 }
01825 if (!RCLASS_IV_TBL(klass)) {
01826 RCLASS_IV_TBL(klass) = st_init_numtable();
01827 }
01828 else if (isconst) {
01829 st_data_t value;
01830
01831 if (st_lookup(RCLASS_IV_TBL(klass), (st_data_t)id, &value)) {
01832 if ((VALUE)value == Qundef)
01833 autoload_delete(klass, id);
01834 else
01835 rb_warn("already initialized %s %s", dest, rb_id2name(id));
01836 }
01837 }
01838
01839 if (isconst){
01840 rb_vm_change_state();
01841 }
01842 st_insert(RCLASS_IV_TBL(klass), (st_data_t)id, (st_data_t)val);
01843 }
01844
01845 void
01846 rb_const_set(VALUE klass, ID id, VALUE val)
01847 {
01848 if (NIL_P(klass)) {
01849 rb_raise(rb_eTypeError, "no class/module to define constant %s",
01850 rb_id2name(id));
01851 }
01852 mod_av_set(klass, id, val, TRUE);
01853 }
01854
01855 void
01856 rb_define_const(VALUE klass, const char *name, VALUE val)
01857 {
01858 ID id = rb_intern(name);
01859
01860 if (!rb_is_const_id(id)) {
01861 rb_warn("rb_define_const: invalid name `%s' for constant", name);
01862 }
01863 if (klass == rb_cObject) {
01864 rb_secure(4);
01865 }
01866 rb_const_set(klass, id, val);
01867 }
01868
01869 void
01870 rb_define_global_const(const char *name, VALUE val)
01871 {
01872 rb_define_const(rb_cObject, name, val);
01873 }
01874
01875 static VALUE
01876 original_module(VALUE c)
01877 {
01878 if (TYPE(c) == T_ICLASS)
01879 return RBASIC(c)->klass;
01880 return c;
01881 }
01882
01883 #define CVAR_LOOKUP(v,r) do {\
01884 if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),(st_data_t)id,(v))) {\
01885 r;\
01886 }\
01887 if (FL_TEST(klass, FL_SINGLETON) ) {\
01888 VALUE obj = rb_iv_get(klass, "__attached__");\
01889 switch (TYPE(obj)) {\
01890 case T_MODULE:\
01891 case T_CLASS:\
01892 klass = obj;\
01893 break;\
01894 default:\
01895 klass = RCLASS_SUPER(klass);\
01896 break;\
01897 }\
01898 }\
01899 else {\
01900 klass = RCLASS_SUPER(klass);\
01901 }\
01902 while (klass) {\
01903 if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),(st_data_t)id,(v))) {\
01904 r;\
01905 }\
01906 klass = RCLASS_SUPER(klass);\
01907 }\
01908 } while(0)
01909
01910 void
01911 rb_cvar_set(VALUE klass, ID id, VALUE val)
01912 {
01913 VALUE tmp, front = 0, target = 0;
01914
01915 tmp = klass;
01916 CVAR_LOOKUP(0, {if (!front) front = klass; target = klass;});
01917 if (target) {
01918 if (front && target != front) {
01919 st_data_t did = id;
01920
01921 if (RTEST(ruby_verbose)) {
01922 rb_warning("class variable %s of %s is overtaken by %s",
01923 rb_id2name(id), rb_class2name(original_module(front)),
01924 rb_class2name(original_module(target)));
01925 }
01926 if (BUILTIN_TYPE(front) == T_CLASS) {
01927 st_delete(RCLASS_IV_TBL(front),&did,0);
01928 }
01929 }
01930 }
01931 else {
01932 target = tmp;
01933 }
01934 mod_av_set(target, id, val, FALSE);
01935 }
01936
01937 VALUE
01938 rb_cvar_get(VALUE klass, ID id)
01939 {
01940 VALUE value, tmp, front = 0, target = 0;
01941
01942 tmp = klass;
01943 CVAR_LOOKUP(&value, {if (!front) front = klass; target = klass;});
01944 if (!target) {
01945 rb_name_error(id,"uninitialized class variable %s in %s",
01946 rb_id2name(id), rb_class2name(tmp));
01947 }
01948 if (front && target != front) {
01949 st_data_t did = id;
01950
01951 if (RTEST(ruby_verbose)) {
01952 rb_warning("class variable %s of %s is overtaken by %s",
01953 rb_id2name(id), rb_class2name(original_module(front)),
01954 rb_class2name(original_module(target)));
01955 }
01956 if (BUILTIN_TYPE(front) == T_CLASS) {
01957 st_delete(RCLASS_IV_TBL(front),&did,0);
01958 }
01959 }
01960 return value;
01961 }
01962
01963 VALUE
01964 rb_cvar_defined(VALUE klass, ID id)
01965 {
01966 if (!klass) return Qfalse;
01967 CVAR_LOOKUP(0,return Qtrue);
01968 return Qfalse;
01969 }
01970
01971 void
01972 rb_cv_set(VALUE klass, const char *name, VALUE val)
01973 {
01974 ID id = rb_intern(name);
01975 if (!rb_is_class_id(id)) {
01976 rb_name_error(id, "wrong class variable name %s", name);
01977 }
01978 rb_cvar_set(klass, id, val);
01979 }
01980
01981 VALUE
01982 rb_cv_get(VALUE klass, const char *name)
01983 {
01984 ID id = rb_intern(name);
01985 if (!rb_is_class_id(id)) {
01986 rb_name_error(id, "wrong class variable name %s", name);
01987 }
01988 return rb_cvar_get(klass, id);
01989 }
01990
01991 void
01992 rb_define_class_variable(VALUE klass, const char *name, VALUE val)
01993 {
01994 ID id = rb_intern(name);
01995
01996 if (!rb_is_class_id(id)) {
01997 rb_name_error(id, "wrong class variable name %s", name);
01998 }
01999 rb_cvar_set(klass, id, val);
02000 }
02001
02002 static int
02003 cv_i(ID key, VALUE value, VALUE ary)
02004 {
02005 if (rb_is_class_id(key)) {
02006 VALUE kval = ID2SYM(key);
02007 if (!rb_ary_includes(ary, kval)) {
02008 rb_ary_push(ary, kval);
02009 }
02010 }
02011 return ST_CONTINUE;
02012 }
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030 VALUE
02031 rb_mod_class_variables(VALUE obj)
02032 {
02033 VALUE ary = rb_ary_new();
02034
02035 if (RCLASS_IV_TBL(obj)) {
02036 st_foreach_safe(RCLASS_IV_TBL(obj), cv_i, ary);
02037 }
02038 return ary;
02039 }
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061 VALUE
02062 rb_mod_remove_cvar(VALUE mod, VALUE name)
02063 {
02064 const ID id = rb_to_id(name);
02065 st_data_t val, n = id;
02066
02067 if (!rb_is_class_id(id)) {
02068 rb_name_error(id, "wrong class variable name %s", rb_id2name(id));
02069 }
02070 if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4)
02071 rb_raise(rb_eSecurityError, "Insecure: can't remove class variable");
02072 if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
02073
02074 if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), &n, &val)) {
02075 return (VALUE)val;
02076 }
02077 if (rb_cvar_defined(mod, id)) {
02078 rb_name_error(id, "cannot remove %s for %s",
02079 rb_id2name(id), rb_class2name(mod));
02080 }
02081 rb_name_error(id, "class variable %s not defined for %s",
02082 rb_id2name(id), rb_class2name(mod));
02083 return Qnil;
02084 }
02085
02086 VALUE
02087 rb_iv_get(VALUE obj, const char *name)
02088 {
02089 ID id = rb_intern(name);
02090
02091 return rb_ivar_get(obj, id);
02092 }
02093
02094 VALUE
02095 rb_iv_set(VALUE obj, const char *name, VALUE val)
02096 {
02097 ID id = rb_intern(name);
02098
02099 return rb_ivar_set(obj, id, val);
02100 }
02101