00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby/ruby.h"
00015 #include "ruby/st.h"
00016 #include "ruby/util.h"
00017 #include "ruby/encoding.h"
00018 #include "node.h"
00019 #include "constant.h"
00020 #include "internal.h"
00021
00022 st_table *rb_global_tbl;
00023 st_table *rb_class_tbl;
00024 static ID autoload, classpath, tmp_classpath, classid;
00025
00026 void
00027 Init_var_tables(void)
00028 {
00029 rb_global_tbl = st_init_numtable();
00030 rb_class_tbl = st_init_numtable();
00031 CONST_ID(autoload, "__autoload__");
00032 CONST_ID(classpath, "__classpath__");
00033 CONST_ID(tmp_classpath, "__tmp_classpath__");
00034 CONST_ID(classid, "__classid__");
00035 }
00036
00037 struct fc_result {
00038 ID name;
00039 VALUE klass;
00040 VALUE path;
00041 VALUE track;
00042 struct fc_result *prev;
00043 };
00044
00045 static VALUE
00046 fc_path(struct fc_result *fc, ID name)
00047 {
00048 VALUE path, tmp;
00049
00050 path = rb_str_dup(rb_id2str(name));
00051 while (fc) {
00052 st_data_t n;
00053 if (fc->track == rb_cObject) break;
00054 if (RCLASS_IV_TBL(fc->track) &&
00055 st_lookup(RCLASS_IV_TBL(fc->track), (st_data_t)classpath, &n)) {
00056 tmp = rb_str_dup((VALUE)n);
00057 rb_str_cat2(tmp, "::");
00058 rb_str_append(tmp, path);
00059 path = tmp;
00060 break;
00061 }
00062 tmp = rb_str_dup(rb_id2str(fc->name));
00063 rb_str_cat2(tmp, "::");
00064 rb_str_append(tmp, path);
00065 path = tmp;
00066 fc = fc->prev;
00067 }
00068 OBJ_FREEZE(path);
00069 return path;
00070 }
00071
00072 static int
00073 fc_i(ID key, rb_const_entry_t *ce, struct fc_result *res)
00074 {
00075 VALUE value = ce->value;
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_CONST_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_CONST_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_CONST_TBL(rb_cObject)) {
00126 st_foreach_safe(RCLASS_CONST_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, key = (st_data_t)id;
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, &key, valp);
00896 if (tbl->num_entries == 0) {
00897 key = (st_data_t)obj;
00898 st_delete(generic_iv_tbl, &key, &data);
00899 st_free_table((st_table *)data);
00900 }
00901 return status;
00902 }
00903
00904 void
00905 rb_mark_generic_ivar(VALUE obj)
00906 {
00907 st_data_t tbl;
00908
00909 if (!generic_iv_tbl) return;
00910 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
00911 rb_mark_tbl((st_table *)tbl);
00912 }
00913 }
00914
00915 static int
00916 givar_mark_i(ID key, VALUE value)
00917 {
00918 rb_gc_mark(value);
00919 return ST_CONTINUE;
00920 }
00921
00922 static int
00923 givar_i(VALUE obj, st_table *tbl)
00924 {
00925 if (rb_special_const_p(obj)) {
00926 st_foreach_safe(tbl, givar_mark_i, 0);
00927 }
00928 return ST_CONTINUE;
00929 }
00930
00931 void
00932 rb_mark_generic_ivar_tbl(void)
00933 {
00934 if (!generic_iv_tbl) return;
00935 if (special_generic_ivar == 0) return;
00936 st_foreach_safe(generic_iv_tbl, givar_i, 0);
00937 }
00938
00939 void
00940 rb_free_generic_ivar(VALUE obj)
00941 {
00942 st_data_t key = (st_data_t)obj, tbl;
00943
00944 if (!generic_iv_tbl) return;
00945 if (st_delete(generic_iv_tbl, &key, &tbl))
00946 st_free_table((st_table *)tbl);
00947 }
00948
00949 RUBY_FUNC_EXPORTED size_t
00950 rb_generic_ivar_memsize(VALUE obj)
00951 {
00952 st_data_t tbl;
00953 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl))
00954 return st_memsize((st_table *)tbl);
00955 return 0;
00956 }
00957
00958 void
00959 rb_copy_generic_ivar(VALUE clone, VALUE obj)
00960 {
00961 st_data_t data;
00962
00963 if (!generic_iv_tbl) return;
00964 if (!FL_TEST(obj, FL_EXIVAR)) {
00965 clear:
00966 if (FL_TEST(clone, FL_EXIVAR)) {
00967 rb_free_generic_ivar(clone);
00968 FL_UNSET(clone, FL_EXIVAR);
00969 }
00970 return;
00971 }
00972 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
00973 st_table *tbl = (st_table *)data;
00974
00975 if (tbl->num_entries == 0)
00976 goto clear;
00977
00978 if (st_lookup(generic_iv_tbl, (st_data_t)clone, &data)) {
00979 st_free_table((st_table *)data);
00980 st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
00981 }
00982 else {
00983 st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
00984 FL_SET(clone, FL_EXIVAR);
00985 }
00986 }
00987 }
00988
00989 static VALUE
00990 ivar_get(VALUE obj, ID id, int warn)
00991 {
00992 VALUE val, *ptr;
00993 struct st_table *iv_index_tbl;
00994 long len;
00995 st_data_t index;
00996
00997 switch (TYPE(obj)) {
00998 case T_OBJECT:
00999 len = ROBJECT_NUMIV(obj);
01000 ptr = ROBJECT_IVPTR(obj);
01001 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01002 if (!iv_index_tbl) break;
01003 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01004 if (len <= (long)index) break;
01005 val = ptr[index];
01006 if (val != Qundef)
01007 return val;
01008 break;
01009 case T_CLASS:
01010 case T_MODULE:
01011 if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, &index))
01012 return (VALUE)index;
01013 break;
01014 default:
01015 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01016 return generic_ivar_get(obj, id, warn);
01017 break;
01018 }
01019 if (warn) {
01020 rb_warning("instance variable %s not initialized", rb_id2name(id));
01021 }
01022 return Qnil;
01023 }
01024
01025 VALUE
01026 rb_ivar_get(VALUE obj, ID id)
01027 {
01028 return ivar_get(obj, id, TRUE);
01029 }
01030
01031 VALUE
01032 rb_attr_get(VALUE obj, ID id)
01033 {
01034 return ivar_get(obj, id, FALSE);
01035 }
01036
01037 VALUE
01038 rb_ivar_set(VALUE obj, ID id, VALUE val)
01039 {
01040 struct st_table *iv_index_tbl;
01041 st_data_t index;
01042 long i, len;
01043 int ivar_extended;
01044
01045 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
01046 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
01047 rb_check_frozen(obj);
01048 switch (TYPE(obj)) {
01049 case T_OBJECT:
01050 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01051 if (!iv_index_tbl) {
01052 VALUE klass = rb_obj_class(obj);
01053 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
01054 if (!iv_index_tbl) {
01055 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
01056 }
01057 }
01058 ivar_extended = 0;
01059 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
01060 index = iv_index_tbl->num_entries;
01061 st_add_direct(iv_index_tbl, (st_data_t)id, index);
01062 ivar_extended = 1;
01063 }
01064 len = ROBJECT_NUMIV(obj);
01065 if (len <= (long)index) {
01066 VALUE *ptr = ROBJECT_IVPTR(obj);
01067 if (index < ROBJECT_EMBED_LEN_MAX) {
01068 RBASIC(obj)->flags |= ROBJECT_EMBED;
01069 ptr = ROBJECT(obj)->as.ary;
01070 for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
01071 ptr[i] = Qundef;
01072 }
01073 }
01074 else {
01075 VALUE *newptr;
01076 long newsize = (index+1) + (index+1)/4;
01077 if (!ivar_extended &&
01078 iv_index_tbl->num_entries < (st_index_t)newsize) {
01079 newsize = iv_index_tbl->num_entries;
01080 }
01081 if (RBASIC(obj)->flags & ROBJECT_EMBED) {
01082 newptr = ALLOC_N(VALUE, newsize);
01083 MEMCPY(newptr, ptr, VALUE, len);
01084 RBASIC(obj)->flags &= ~ROBJECT_EMBED;
01085 ROBJECT(obj)->as.heap.ivptr = newptr;
01086 }
01087 else {
01088 REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
01089 newptr = ROBJECT(obj)->as.heap.ivptr;
01090 }
01091 for (; len < newsize; len++)
01092 newptr[len] = Qundef;
01093 ROBJECT(obj)->as.heap.numiv = newsize;
01094 ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
01095 }
01096 }
01097 ROBJECT_IVPTR(obj)[index] = val;
01098 break;
01099 case T_CLASS:
01100 case T_MODULE:
01101 if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
01102 st_insert(RCLASS_IV_TBL(obj), (st_data_t)id, val);
01103 break;
01104 default:
01105 generic_ivar_set(obj, id, val);
01106 break;
01107 }
01108 return val;
01109 }
01110
01111 VALUE
01112 rb_ivar_defined(VALUE obj, ID id)
01113 {
01114 VALUE val;
01115 struct st_table *iv_index_tbl;
01116 st_data_t index;
01117 switch (TYPE(obj)) {
01118 case T_OBJECT:
01119 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01120 if (!iv_index_tbl) break;
01121 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01122 if (ROBJECT_NUMIV(obj) <= (long)index) break;
01123 val = ROBJECT_IVPTR(obj)[index];
01124 if (val != Qundef)
01125 return Qtrue;
01126 break;
01127 case T_CLASS:
01128 case T_MODULE:
01129 if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, 0))
01130 return Qtrue;
01131 break;
01132 default:
01133 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01134 return generic_ivar_defined(obj, id);
01135 break;
01136 }
01137 return Qfalse;
01138 }
01139
01140 struct obj_ivar_tag {
01141 VALUE obj;
01142 int (*func)(ID key, VALUE val, st_data_t arg);
01143 st_data_t arg;
01144 };
01145
01146 static int
01147 obj_ivar_i(st_data_t key, st_data_t index, st_data_t arg)
01148 {
01149 struct obj_ivar_tag *data = (struct obj_ivar_tag *)arg;
01150 if ((long)index < ROBJECT_NUMIV(data->obj)) {
01151 VALUE val = ROBJECT_IVPTR(data->obj)[(long)index];
01152 if (val != Qundef) {
01153 return (data->func)((ID)key, val, data->arg);
01154 }
01155 }
01156 return ST_CONTINUE;
01157 }
01158
01159 static void
01160 obj_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01161 {
01162 st_table *tbl;
01163 struct obj_ivar_tag data;
01164
01165 tbl = ROBJECT_IV_INDEX_TBL(obj);
01166 if (!tbl)
01167 return;
01168
01169 data.obj = obj;
01170 data.func = (int (*)(ID key, VALUE val, st_data_t arg))func;
01171 data.arg = arg;
01172
01173 st_foreach_safe(tbl, obj_ivar_i, (st_data_t)&data);
01174 }
01175
01176 void
01177 rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01178 {
01179 switch (TYPE(obj)) {
01180 case T_OBJECT:
01181 obj_ivar_each(obj, func, arg);
01182 break;
01183 case T_CLASS:
01184 case T_MODULE:
01185 if (RCLASS_IV_TBL(obj)) {
01186 st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
01187 }
01188 break;
01189 default:
01190 if (!generic_iv_tbl) break;
01191 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01192 st_data_t tbl;
01193
01194 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
01195 st_foreach_safe((st_table *)tbl, func, arg);
01196 }
01197 }
01198 break;
01199 }
01200 }
01201
01202 st_index_t
01203 rb_ivar_count(VALUE obj)
01204 {
01205 st_table *tbl;
01206 switch (TYPE(obj)) {
01207 case T_OBJECT:
01208 if ((tbl = ROBJECT_IV_INDEX_TBL(obj)) != 0) {
01209 st_index_t i, count, num = tbl->num_entries;
01210 const VALUE *const ivptr = ROBJECT_IVPTR(obj);
01211 for (i = count = 0; i < num; ++i) {
01212 if (ivptr[i] != Qundef) {
01213 count++;
01214 }
01215 }
01216 return count;
01217 }
01218 break;
01219 case T_CLASS:
01220 case T_MODULE:
01221 if ((tbl = RCLASS_IV_TBL(obj)) != 0) {
01222 return tbl->num_entries;
01223 }
01224 break;
01225 default:
01226 if (!generic_iv_tbl) break;
01227 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01228 st_data_t data;
01229
01230 if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data) &&
01231 (tbl = (st_table *)data) != 0) {
01232 return tbl->num_entries;
01233 }
01234 }
01235 break;
01236 }
01237 return 0;
01238 }
01239
01240 static int
01241 ivar_i(ID key, VALUE val, VALUE ary)
01242 {
01243 if (rb_is_instance_id(key)) {
01244 rb_ary_push(ary, ID2SYM(key));
01245 }
01246 return ST_CONTINUE;
01247 }
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266 VALUE
01267 rb_obj_instance_variables(VALUE obj)
01268 {
01269 VALUE ary;
01270
01271 ary = rb_ary_new();
01272 rb_ivar_foreach(obj, ivar_i, ary);
01273 return ary;
01274 }
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298 VALUE
01299 rb_obj_remove_instance_variable(VALUE obj, VALUE name)
01300 {
01301 VALUE val = Qnil;
01302 const ID id = rb_to_id(name);
01303 st_data_t n, v;
01304 struct st_table *iv_index_tbl;
01305 st_data_t index;
01306
01307 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
01308 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
01309 rb_check_frozen(obj);
01310 if (!rb_is_instance_id(id)) {
01311 rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id));
01312 }
01313
01314 switch (TYPE(obj)) {
01315 case T_OBJECT:
01316 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01317 if (!iv_index_tbl) break;
01318 if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01319 if (ROBJECT_NUMIV(obj) <= (long)index) break;
01320 val = ROBJECT_IVPTR(obj)[index];
01321 if (val != Qundef) {
01322 ROBJECT_IVPTR(obj)[index] = Qundef;
01323 return val;
01324 }
01325 break;
01326 case T_CLASS:
01327 case T_MODULE:
01328 n = id;
01329 if (RCLASS_IV_TBL(obj) && st_delete(RCLASS_IV_TBL(obj), &n, &v)) {
01330 return (VALUE)v;
01331 }
01332 break;
01333 default:
01334 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01335 v = val;
01336 if (generic_ivar_remove(obj, (st_data_t)id, &v)) {
01337 return (VALUE)v;
01338 }
01339 }
01340 break;
01341 }
01342 rb_name_error(id, "instance variable %s not defined", rb_id2name(id));
01343 return Qnil;
01344 }
01345
01346 NORETURN(static void uninitialized_constant(VALUE, ID));
01347 static void
01348 uninitialized_constant(VALUE klass, ID id)
01349 {
01350 if (klass && rb_class_real(klass) != rb_cObject)
01351 rb_name_error(id, "uninitialized constant %s::%s",
01352 rb_class2name(klass),
01353 rb_id2name(id));
01354 else {
01355 rb_name_error(id, "uninitialized constant %s", rb_id2name(id));
01356 }
01357 }
01358
01359 static VALUE
01360 const_missing(VALUE klass, ID id)
01361 {
01362 return rb_funcall(klass, rb_intern("const_missing"), 1, ID2SYM(id));
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
01394
01395
01396
01397
01398
01399
01400
01401
01402 VALUE
01403 rb_mod_const_missing(VALUE klass, VALUE name)
01404 {
01405 rb_frame_pop();
01406 uninitialized_constant(klass, rb_to_id(name));
01407 return Qnil;
01408 }
01409
01410 static void
01411 autoload_mark(void *ptr)
01412 {
01413 rb_mark_tbl((st_table *)ptr);
01414 }
01415
01416 static void
01417 autoload_free(void *ptr)
01418 {
01419 st_free_table((st_table *)ptr);
01420 }
01421
01422 static size_t
01423 autoload_memsize(const void *ptr)
01424 {
01425 const st_table *tbl = ptr;
01426 return st_memsize(tbl);
01427 }
01428
01429 static const rb_data_type_t autoload_data_type = {
01430 "autoload",
01431 {autoload_mark, autoload_free, autoload_memsize,},
01432 };
01433
01434 #define check_autoload_table(av) \
01435 (struct st_table *)rb_check_typeddata((av), &autoload_data_type)
01436
01437 void
01438 rb_autoload(VALUE mod, ID id, const char *file)
01439 {
01440 st_data_t av;
01441 VALUE fn;
01442 struct st_table *tbl;
01443
01444 if (!rb_is_const_id(id)) {
01445 rb_raise(rb_eNameError, "autoload must be constant name: %s", rb_id2name(id));
01446 }
01447 if (!file || !*file) {
01448 rb_raise(rb_eArgError, "empty file name");
01449 }
01450
01451 if ((tbl = RCLASS_CONST_TBL(mod)) && st_lookup(tbl, (st_data_t)id, &av) && ((rb_const_entry_t*)av)->value != Qundef)
01452 return;
01453
01454 rb_const_set(mod, id, Qundef);
01455 tbl = RCLASS_IV_TBL(mod);
01456 if (tbl && st_lookup(tbl, (st_data_t)autoload, &av)) {
01457 tbl = check_autoload_table((VALUE)av);
01458 }
01459 else {
01460 if (!tbl) tbl = RCLASS_IV_TBL(mod) = st_init_numtable();
01461 av = (st_data_t)TypedData_Wrap_Struct(0, &autoload_data_type, 0);
01462 st_add_direct(tbl, (st_data_t)autoload, av);
01463 DATA_PTR(av) = tbl = st_init_numtable();
01464 }
01465 fn = rb_str_new2(file);
01466 FL_UNSET(fn, FL_TAINT);
01467 OBJ_FREEZE(fn);
01468 st_insert(tbl, (st_data_t)id, (st_data_t)rb_node_newnode(NODE_MEMO, fn, rb_safe_level(), 0));
01469 }
01470
01471 static NODE*
01472 autoload_delete(VALUE mod, ID id)
01473 {
01474 st_data_t val, load = 0, n = id;
01475 rb_const_entry_t *ce;
01476
01477 st_delete(RCLASS_CONST_TBL(mod), &n, &val);
01478 ce = (rb_const_entry_t*)val;
01479 if (ce) xfree(ce);
01480 if (st_lookup(RCLASS_IV_TBL(mod), (st_data_t)autoload, &val)) {
01481 struct st_table *tbl = check_autoload_table((VALUE)val);
01482
01483 st_delete(tbl, &n, &load);
01484
01485 if (tbl->num_entries == 0) {
01486 n = autoload;
01487 st_delete(RCLASS_IV_TBL(mod), &n, &val);
01488 }
01489 }
01490
01491 return (NODE *)load;
01492 }
01493
01494 static VALUE
01495 autoload_provided(VALUE arg)
01496 {
01497 const char **p = (const char **)arg;
01498 return rb_feature_provided(*p, p);
01499 }
01500
01501 static VALUE
01502 reset_safe(VALUE safe)
01503 {
01504 rb_set_safe_level_force((int)safe);
01505 return safe;
01506 }
01507
01508 static NODE *
01509 autoload_node(VALUE mod, ID id, const char **loadingpath)
01510 {
01511 VALUE file;
01512 struct st_table *tbl;
01513 st_data_t val;
01514 NODE *load;
01515 const char *loading;
01516 int safe;
01517
01518 if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
01519 !(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, (st_data_t)id, &val)) {
01520 return 0;
01521 }
01522 load = (NODE *)val;
01523 file = load->nd_lit;
01524 Check_Type(file, T_STRING);
01525 if (!RSTRING_PTR(file) || !*RSTRING_PTR(file)) {
01526 rb_raise(rb_eArgError, "empty file name");
01527 }
01528 loading = RSTRING_PTR(file);
01529 safe = rb_safe_level();
01530 rb_set_safe_level_force(0);
01531 if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
01532 return load;
01533 }
01534 if (loadingpath && loading) {
01535 *loadingpath = loading;
01536 return load;
01537 }
01538 return 0;
01539 }
01540
01541 static int
01542 autoload_node_id(VALUE mod, ID id)
01543 {
01544 struct st_table *tbl = RCLASS_CONST_TBL(mod);
01545 st_data_t val;
01546
01547 if (!tbl || !st_lookup(tbl, (st_data_t)id, &val) || ((rb_const_entry_t*)val)->value != Qundef) {
01548 return 0;
01549 }
01550 return 1;
01551 }
01552
01553 VALUE
01554 rb_autoload_load(VALUE mod, ID id)
01555 {
01556 VALUE file;
01557 NODE *load;
01558 const char *loading = 0, *src;
01559
01560 if (!autoload_node_id(mod, id)) return Qfalse;
01561 load = autoload_node(mod, id, &loading);
01562 if (!load) return Qfalse;
01563 src = rb_sourcefile();
01564 if (src && loading && strcmp(src, loading) == 0) return Qfalse;
01565 file = load->nd_lit;
01566 return rb_require_safe(file, (int)load->nd_nth);
01567 }
01568
01569 VALUE
01570 rb_autoload_p(VALUE mod, ID id)
01571 {
01572 VALUE file;
01573 NODE *load;
01574 const char *loading = 0;
01575
01576 while (!autoload_node_id(mod, id)) {
01577 mod = RCLASS_SUPER(mod);
01578 if (!mod) return Qnil;
01579 }
01580 load = autoload_node(mod, id, &loading);
01581 if (!load) return Qnil;
01582 return load && (file = load->nd_lit) ? file : Qnil;
01583 }
01584
01585 static VALUE
01586 rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
01587 {
01588 VALUE value, tmp;
01589 int mod_retry = 0;
01590
01591 tmp = klass;
01592 retry:
01593 while (RTEST(tmp)) {
01594 VALUE am = 0;
01595 st_data_t data;
01596 while (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &data)) {
01597 rb_const_entry_t *ce = (rb_const_entry_t *)data;
01598 if (visibility && ce->flag == CONST_PRIVATE) {
01599 rb_name_error(id, "private constant %s::%s referenced", rb_class2name(klass), rb_id2name(id));
01600 }
01601 value = ce->value;
01602 if (value == Qundef) {
01603 if (am == tmp) break;
01604 am = tmp;
01605 rb_autoload_load(tmp, id);
01606 continue;
01607 }
01608 if (exclude && tmp == rb_cObject && klass != rb_cObject) {
01609 rb_warn("toplevel constant %s referenced by %s::%s",
01610 rb_id2name(id), rb_class2name(klass), rb_id2name(id));
01611 }
01612 return value;
01613 }
01614 if (!recurse) break;
01615 tmp = RCLASS_SUPER(tmp);
01616 }
01617 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
01618 mod_retry = 1;
01619 tmp = rb_cObject;
01620 goto retry;
01621 }
01622
01623 value = const_missing(klass, id);
01624 rb_vm_inc_const_missing_count();
01625 return value;
01626 }
01627
01628 VALUE
01629 rb_const_get_from(VALUE klass, ID id)
01630 {
01631 return rb_const_get_0(klass, id, TRUE, TRUE, FALSE);
01632 }
01633
01634 VALUE
01635 rb_const_get(VALUE klass, ID id)
01636 {
01637 return rb_const_get_0(klass, id, FALSE, TRUE, FALSE);
01638 }
01639
01640 VALUE
01641 rb_const_get_at(VALUE klass, ID id)
01642 {
01643 return rb_const_get_0(klass, id, TRUE, FALSE, FALSE);
01644 }
01645
01646 VALUE
01647 rb_public_const_get_from(VALUE klass, ID id)
01648 {
01649 return rb_const_get_0(klass, id, TRUE, TRUE, TRUE);
01650 }
01651
01652 VALUE
01653 rb_public_const_get(VALUE klass, ID id)
01654 {
01655 return rb_const_get_0(klass, id, FALSE, TRUE, TRUE);
01656 }
01657
01658 VALUE
01659 rb_public_const_get_at(VALUE klass, ID id)
01660 {
01661 return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
01662 }
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674 VALUE
01675 rb_mod_remove_const(VALUE mod, VALUE name)
01676 {
01677 const ID id = rb_to_id(name);
01678
01679 if (!rb_is_const_id(id)) {
01680 rb_name_error(id, "`%s' is not allowed as a constant name", rb_id2name(id));
01681 }
01682 return rb_const_remove(mod, id);
01683 }
01684
01685 VALUE
01686 rb_const_remove(VALUE mod, ID id)
01687 {
01688 VALUE val;
01689 st_data_t v, n = id;
01690
01691 if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4)
01692 rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
01693 rb_check_frozen(mod);
01694 if (!RCLASS_CONST_TBL(mod) || !st_delete(RCLASS_CONST_TBL(mod), &n, &v)) {
01695 if (rb_const_defined_at(mod, id)) {
01696 rb_name_error(id, "cannot remove %s::%s",
01697 rb_class2name(mod), rb_id2name(id));
01698 }
01699 rb_name_error(id, "constant %s::%s not defined",
01700 rb_class2name(mod), rb_id2name(id));
01701 }
01702
01703 rb_vm_change_state();
01704
01705 val = ((rb_const_entry_t*)v)->value;
01706 if (val == Qundef) {
01707 autoload_delete(mod, id);
01708 val = Qnil;
01709 }
01710 xfree((rb_const_entry_t*)v);
01711 return val;
01712 }
01713
01714 static int
01715 sv_i(ID key, rb_const_entry_t *ce, st_table *tbl)
01716 {
01717 if (rb_is_const_id(key)) {
01718 if (!st_lookup(tbl, (st_data_t)key, 0)) {
01719 st_insert(tbl, (st_data_t)key, (st_data_t)ce);
01720 }
01721 }
01722 return ST_CONTINUE;
01723 }
01724
01725 void*
01726 rb_mod_const_at(VALUE mod, void *data)
01727 {
01728 st_table *tbl = data;
01729 if (!tbl) {
01730 tbl = st_init_numtable();
01731 }
01732 if (RCLASS_CONST_TBL(mod)) {
01733 st_foreach_safe(RCLASS_CONST_TBL(mod), sv_i, (st_data_t)tbl);
01734 }
01735 return tbl;
01736 }
01737
01738 void*
01739 rb_mod_const_of(VALUE mod, void *data)
01740 {
01741 VALUE tmp = mod;
01742 for (;;) {
01743 data = rb_mod_const_at(tmp, data);
01744 tmp = RCLASS_SUPER(tmp);
01745 if (!tmp) break;
01746 if (tmp == rb_cObject && mod != rb_cObject) break;
01747 }
01748 return data;
01749 }
01750
01751 static int
01752 list_i(st_data_t key, st_data_t value, VALUE ary)
01753 {
01754 ID sym = (ID)key;
01755 rb_const_entry_t *ce = (rb_const_entry_t *)value;
01756 if (ce->flag != CONST_PRIVATE) rb_ary_push(ary, ID2SYM(sym));
01757 return ST_CONTINUE;
01758 }
01759
01760 VALUE
01761 rb_const_list(void *data)
01762 {
01763 st_table *tbl = data;
01764 VALUE ary;
01765
01766 if (!tbl) return rb_ary_new2(0);
01767 ary = rb_ary_new2(tbl->num_entries);
01768 st_foreach_safe(tbl, list_i, ary);
01769 st_free_table(tbl);
01770
01771 return ary;
01772 }
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789 VALUE
01790 rb_mod_constants(int argc, VALUE *argv, VALUE mod)
01791 {
01792 VALUE inherit;
01793 st_table *tbl;
01794
01795 if (argc == 0) {
01796 inherit = Qtrue;
01797 }
01798 else {
01799 rb_scan_args(argc, argv, "01", &inherit);
01800 }
01801 if (RTEST(inherit)) {
01802 tbl = rb_mod_const_of(mod, 0);
01803 }
01804 else {
01805 tbl = rb_mod_const_at(mod, 0);
01806 }
01807 return rb_const_list(tbl);
01808 }
01809
01810 static int
01811 rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
01812 {
01813 st_data_t value;
01814 VALUE tmp;
01815 int mod_retry = 0;
01816
01817 tmp = klass;
01818 retry:
01819 while (tmp) {
01820 if (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &value)) {
01821 rb_const_entry_t *ce = (rb_const_entry_t *)value;
01822 if (visibility && ce->flag == CONST_PRIVATE) {
01823 return (int)Qfalse;
01824 }
01825 if (ce->value == Qundef && !autoload_node(tmp, id, 0))
01826 return (int)Qfalse;
01827 return (int)Qtrue;
01828 }
01829 if (!recurse) break;
01830 tmp = RCLASS_SUPER(tmp);
01831 }
01832 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
01833 mod_retry = 1;
01834 tmp = rb_cObject;
01835 goto retry;
01836 }
01837 return (int)Qfalse;
01838 }
01839
01840 int
01841 rb_const_defined_from(VALUE klass, ID id)
01842 {
01843 return rb_const_defined_0(klass, id, TRUE, TRUE, FALSE);
01844 }
01845
01846 int
01847 rb_const_defined(VALUE klass, ID id)
01848 {
01849 return rb_const_defined_0(klass, id, FALSE, TRUE, FALSE);
01850 }
01851
01852 int
01853 rb_const_defined_at(VALUE klass, ID id)
01854 {
01855 return rb_const_defined_0(klass, id, TRUE, FALSE, FALSE);
01856 }
01857
01858 int
01859 rb_public_const_defined_from(VALUE klass, ID id)
01860 {
01861 return rb_const_defined_0(klass, id, TRUE, TRUE, TRUE);
01862 }
01863
01864 int
01865 rb_public_const_defined(VALUE klass, ID id)
01866 {
01867 return rb_const_defined_0(klass, id, FALSE, TRUE, TRUE);
01868 }
01869
01870 int
01871 rb_public_const_defined_at(VALUE klass, ID id)
01872 {
01873 return rb_const_defined_0(klass, id, TRUE, FALSE, TRUE);
01874 }
01875
01876 void
01877 check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
01878 {
01879 if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4)
01880 rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest);
01881 rb_check_frozen(klass);
01882 }
01883
01884 void
01885 rb_const_set(VALUE klass, ID id, VALUE val)
01886 {
01887 rb_const_entry_t *ce;
01888 VALUE visibility = CONST_PUBLIC;
01889
01890 if (NIL_P(klass)) {
01891 rb_raise(rb_eTypeError, "no class/module to define constant %s",
01892 rb_id2name(id));
01893 }
01894
01895 check_before_mod_set(klass, id, val, "constant");
01896 if (!RCLASS_CONST_TBL(klass)) {
01897 RCLASS_CONST_TBL(klass) = st_init_numtable();
01898 }
01899 else {
01900 st_data_t value;
01901
01902 if (st_lookup(RCLASS_CONST_TBL(klass), (st_data_t)id, &value)) {
01903 rb_const_entry_t *ce = (rb_const_entry_t*)value;
01904 if (ce->value == Qundef)
01905 autoload_delete(klass, id);
01906 else {
01907 visibility = ce->flag;
01908 rb_warn("already initialized constant %s", rb_id2name(id));
01909 }
01910 }
01911 }
01912
01913 rb_vm_change_state();
01914
01915 ce = ALLOC(rb_const_entry_t);
01916 ce->flag = (rb_const_flag_t)visibility;
01917 ce->value = val;
01918
01919 st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
01920 }
01921
01922 void
01923 rb_define_const(VALUE klass, const char *name, VALUE val)
01924 {
01925 ID id = rb_intern(name);
01926
01927 if (!rb_is_const_id(id)) {
01928 rb_warn("rb_define_const: invalid name `%s' for constant", name);
01929 }
01930 if (klass == rb_cObject) {
01931 rb_secure(4);
01932 }
01933 rb_const_set(klass, id, val);
01934 }
01935
01936 void
01937 rb_define_global_const(const char *name, VALUE val)
01938 {
01939 rb_define_const(rb_cObject, name, val);
01940 }
01941
01942 static void
01943 set_const_visibility(VALUE mod, int argc, VALUE *argv, rb_const_flag_t flag)
01944 {
01945 int i;
01946 st_data_t v;
01947 ID id;
01948
01949 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(mod)) {
01950 rb_raise(rb_eSecurityError,
01951 "Insecure: can't change constant visibility");
01952 }
01953
01954 if (argc == 0) {
01955 rb_warning("%s with no argument is just ignored", rb_id2name(rb_frame_callee()));
01956 }
01957
01958 for (i = 0; i < argc; i++) {
01959 VALUE val = argv[i];
01960 id = rb_to_id(val);
01961 if (RCLASS_CONST_TBL(mod) &&
01962 st_lookup(RCLASS_CONST_TBL(mod), (st_data_t)id, &v)) {
01963 ((rb_const_entry_t*)v)->flag = flag;
01964 }
01965 else {
01966 if ( i > 0 )
01967 rb_clear_cache_by_class(mod);
01968 rb_name_error(id, "constant %s::%s not defined", rb_class2name(mod), rb_id2name(id));
01969 }
01970 }
01971 rb_clear_cache_by_class(mod);
01972 }
01973
01974
01975
01976
01977
01978
01979
01980
01981 VALUE
01982 rb_mod_private_constant(int argc, VALUE *argv, VALUE obj)
01983 {
01984 set_const_visibility(obj, argc, argv, CONST_PRIVATE);
01985 return obj;
01986 }
01987
01988
01989
01990
01991
01992
01993
01994
01995 VALUE
01996 rb_mod_public_constant(int argc, VALUE *argv, VALUE obj)
01997 {
01998 set_const_visibility(obj, argc, argv, CONST_PUBLIC);
01999 return obj;
02000 }
02001
02002 static VALUE
02003 original_module(VALUE c)
02004 {
02005 if (TYPE(c) == T_ICLASS)
02006 return RBASIC(c)->klass;
02007 return c;
02008 }
02009
02010 #define CVAR_LOOKUP(v,r) do {\
02011 if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),(st_data_t)id,(v))) {\
02012 r;\
02013 }\
02014 if (FL_TEST(klass, FL_SINGLETON) ) {\
02015 VALUE obj = rb_iv_get(klass, "__attached__");\
02016 switch (TYPE(obj)) {\
02017 case T_MODULE:\
02018 case T_CLASS:\
02019 klass = obj;\
02020 break;\
02021 default:\
02022 klass = RCLASS_SUPER(klass);\
02023 break;\
02024 }\
02025 }\
02026 else {\
02027 klass = RCLASS_SUPER(klass);\
02028 }\
02029 while (klass) {\
02030 if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),(st_data_t)id,(v))) {\
02031 r;\
02032 }\
02033 klass = RCLASS_SUPER(klass);\
02034 }\
02035 } while(0)
02036
02037 void
02038 rb_cvar_set(VALUE klass, ID id, VALUE val)
02039 {
02040 VALUE tmp, front = 0, target = 0;
02041
02042 tmp = klass;
02043 CVAR_LOOKUP(0, {if (!front) front = klass; target = klass;});
02044 if (target) {
02045 if (front && target != front) {
02046 st_data_t did = id;
02047
02048 if (RTEST(ruby_verbose)) {
02049 rb_warning("class variable %s of %s is overtaken by %s",
02050 rb_id2name(id), rb_class2name(original_module(front)),
02051 rb_class2name(original_module(target)));
02052 }
02053 if (BUILTIN_TYPE(front) == T_CLASS) {
02054 st_delete(RCLASS_IV_TBL(front),&did,0);
02055 }
02056 }
02057 }
02058 else {
02059 target = tmp;
02060 }
02061
02062 check_before_mod_set(target, id, val, "class variable");
02063 if (!RCLASS_IV_TBL(target)) {
02064 RCLASS_IV_TBL(target) = st_init_numtable();
02065 }
02066
02067 st_insert(RCLASS_IV_TBL(target), (st_data_t)id, (st_data_t)val);
02068 }
02069
02070 VALUE
02071 rb_cvar_get(VALUE klass, ID id)
02072 {
02073 VALUE tmp, front = 0, target = 0;
02074 st_data_t value;
02075
02076 tmp = klass;
02077 CVAR_LOOKUP(&value, {if (!front) front = klass; target = klass;});
02078 if (!target) {
02079 rb_name_error(id,"uninitialized class variable %s in %s",
02080 rb_id2name(id), rb_class2name(tmp));
02081 }
02082 if (front && target != front) {
02083 st_data_t did = id;
02084
02085 if (RTEST(ruby_verbose)) {
02086 rb_warning("class variable %s of %s is overtaken by %s",
02087 rb_id2name(id), rb_class2name(original_module(front)),
02088 rb_class2name(original_module(target)));
02089 }
02090 if (BUILTIN_TYPE(front) == T_CLASS) {
02091 st_delete(RCLASS_IV_TBL(front),&did,0);
02092 }
02093 }
02094 return (VALUE)value;
02095 }
02096
02097 VALUE
02098 rb_cvar_defined(VALUE klass, ID id)
02099 {
02100 if (!klass) return Qfalse;
02101 CVAR_LOOKUP(0,return Qtrue);
02102 return Qfalse;
02103 }
02104
02105 void
02106 rb_cv_set(VALUE klass, const char *name, VALUE val)
02107 {
02108 ID id = rb_intern(name);
02109 if (!rb_is_class_id(id)) {
02110 rb_name_error(id, "wrong class variable name %s", name);
02111 }
02112 rb_cvar_set(klass, id, val);
02113 }
02114
02115 VALUE
02116 rb_cv_get(VALUE klass, const char *name)
02117 {
02118 ID id = rb_intern(name);
02119 if (!rb_is_class_id(id)) {
02120 rb_name_error(id, "wrong class variable name %s", name);
02121 }
02122 return rb_cvar_get(klass, id);
02123 }
02124
02125 void
02126 rb_define_class_variable(VALUE klass, const char *name, VALUE val)
02127 {
02128 ID id = rb_intern(name);
02129
02130 if (!rb_is_class_id(id)) {
02131 rb_name_error(id, "wrong class variable name %s", name);
02132 }
02133 rb_cvar_set(klass, id, val);
02134 }
02135
02136 static int
02137 cv_i(ID key, VALUE value, VALUE ary)
02138 {
02139 if (rb_is_class_id(key)) {
02140 VALUE kval = ID2SYM(key);
02141 if (!rb_ary_includes(ary, kval)) {
02142 rb_ary_push(ary, kval);
02143 }
02144 }
02145 return ST_CONTINUE;
02146 }
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164 VALUE
02165 rb_mod_class_variables(VALUE obj)
02166 {
02167 VALUE ary = rb_ary_new();
02168
02169 if (RCLASS_IV_TBL(obj)) {
02170 st_foreach_safe(RCLASS_IV_TBL(obj), cv_i, ary);
02171 }
02172 return ary;
02173 }
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188
02189
02190
02191
02192
02193
02194
02195 VALUE
02196 rb_mod_remove_cvar(VALUE mod, VALUE name)
02197 {
02198 const ID id = rb_to_id(name);
02199 st_data_t val, n = id;
02200
02201 if (!rb_is_class_id(id)) {
02202 rb_name_error(id, "wrong class variable name %s", rb_id2name(id));
02203 }
02204 if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4)
02205 rb_raise(rb_eSecurityError, "Insecure: can't remove class variable");
02206 rb_check_frozen(mod);
02207 if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), &n, &val)) {
02208 return (VALUE)val;
02209 }
02210 if (rb_cvar_defined(mod, id)) {
02211 rb_name_error(id, "cannot remove %s for %s",
02212 rb_id2name(id), rb_class2name(mod));
02213 }
02214 rb_name_error(id, "class variable %s not defined for %s",
02215 rb_id2name(id), rb_class2name(mod));
02216 return Qnil;
02217 }
02218
02219 VALUE
02220 rb_iv_get(VALUE obj, const char *name)
02221 {
02222 ID id = rb_intern(name);
02223
02224 return rb_ivar_get(obj, id);
02225 }
02226
02227 VALUE
02228 rb_iv_set(VALUE obj, const char *name, VALUE val)
02229 {
02230 ID id = rb_intern(name);
02231
02232 return rb_ivar_set(obj, id, val);
02233 }
02234