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