00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "ruby.h"
00016 #include "env.h"
00017 #include "node.h"
00018 #include "st.h"
00019 #include "util.h"
00020
00021 static st_table *rb_global_tbl;
00022 st_table *rb_class_tbl;
00023 static ID autoload, classpath, tmp_classpath;
00024
00025 void
00026 Init_var_tables()
00027 {
00028 rb_global_tbl = st_init_numtable();
00029 rb_class_tbl = st_init_numtable();
00030 autoload = rb_intern("__autoload__");
00031 classpath = rb_intern("__classpath__");
00032 tmp_classpath = rb_intern("__tmp_classpath__");
00033 }
00034
00035 struct fc_result {
00036 ID name;
00037 VALUE klass;
00038 VALUE path;
00039 VALUE track;
00040 struct fc_result *prev;
00041 };
00042
00043 static VALUE
00044 fc_path(fc, name)
00045 struct fc_result *fc;
00046 ID name;
00047 {
00048 VALUE path, tmp;
00049
00050 path = rb_str_new2(rb_id2name(name));
00051 while (fc) {
00052 if (fc->track == rb_cObject) break;
00053 if (ROBJECT(fc->track)->iv_tbl &&
00054 st_lookup(ROBJECT(fc->track)->iv_tbl, classpath, &tmp)) {
00055 tmp = rb_str_dup(tmp);
00056 rb_str_cat2(tmp, "::");
00057 rb_str_append(tmp, path);
00058
00059 return tmp;
00060 }
00061 tmp = rb_str_new2(rb_id2name(fc->name));
00062 rb_str_cat2(tmp, "::");
00063 rb_str_append(tmp, path);
00064 path = tmp;
00065 fc = fc->prev;
00066 }
00067 return path;
00068 }
00069
00070 static int
00071 fc_i(key, value, res)
00072 ID key;
00073 VALUE value;
00074 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(value)->iv_tbl) 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_safe(RCLASS(value)->iv_tbl, 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(klass)
00117 VALUE klass;
00118 {
00119 struct fc_result arg;
00120
00121 arg.name = 0;
00122 arg.path = 0;
00123 arg.klass = klass;
00124 arg.track = rb_cObject;
00125 arg.prev = 0;
00126 if (RCLASS(rb_cObject)->iv_tbl) {
00127 st_foreach_safe(RCLASS(rb_cObject)->iv_tbl, fc_i, (st_data_t)&arg);
00128 }
00129 if (arg.path == 0) {
00130 st_foreach(rb_class_tbl, fc_i, (st_data_t)&arg);
00131 }
00132 if (arg.path) {
00133 if (!ROBJECT(klass)->iv_tbl) {
00134 ROBJECT(klass)->iv_tbl = st_init_numtable();
00135 }
00136 st_insert(ROBJECT(klass)->iv_tbl, classpath, arg.path);
00137 st_delete(RCLASS(klass)->iv_tbl, &tmp_classpath, 0);
00138 return arg.path;
00139 }
00140 return Qnil;
00141 }
00142
00143 static VALUE
00144 classname(klass)
00145 VALUE klass;
00146 {
00147 VALUE path = Qnil;
00148
00149 if (!klass) klass = rb_cObject;
00150 if (ROBJECT(klass)->iv_tbl) {
00151 if (!st_lookup(ROBJECT(klass)->iv_tbl, classpath, &path)) {
00152 ID classid = rb_intern("__classid__");
00153
00154 if (!st_lookup(ROBJECT(klass)->iv_tbl, classid, &path)) {
00155 return find_class_path(klass);
00156 }
00157 path = rb_str_new2(rb_id2name(SYM2ID(path)));
00158 st_insert(ROBJECT(klass)->iv_tbl, classpath, path);
00159 st_delete(RCLASS(klass)->iv_tbl, (st_data_t*)&classid, 0);
00160 }
00161 if (TYPE(path) != T_STRING) {
00162 rb_bug("class path is not set properly");
00163 }
00164 return path;
00165 }
00166 return find_class_path(klass);
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176 VALUE
00177 rb_mod_name(mod)
00178 VALUE mod;
00179 {
00180 VALUE path = classname(mod);
00181
00182 if (!NIL_P(path)) return rb_str_dup(path);
00183 return rb_str_new(0,0);
00184 }
00185
00186 VALUE
00187 rb_class_path(klass)
00188 VALUE klass;
00189 {
00190 VALUE path = classname(klass);
00191
00192 if (!NIL_P(path)) return path;
00193 if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,
00194 tmp_classpath, &path)) {
00195 return path;
00196 }
00197 else {
00198 char *s = "Class";
00199 size_t len;
00200
00201 if (TYPE(klass) == T_MODULE) {
00202 if (rb_obj_class(klass) == rb_cModule) {
00203 s = "Module";
00204 }
00205 else {
00206 s = rb_class2name(RBASIC(klass)->klass);
00207 }
00208 }
00209 len = 2 + strlen(s) + 3 + 2 * SIZEOF_LONG + 1;
00210 path = rb_str_new(0, len);
00211 snprintf(RSTRING(path)->ptr, len+1, "#<%s:0x%lx>", s, klass);
00212 RSTRING(path)->len = strlen(RSTRING(path)->ptr);
00213 rb_ivar_set(klass, tmp_classpath, path);
00214
00215 return path;
00216 }
00217 }
00218
00219 void
00220 rb_set_class_path(klass, under, name)
00221 VALUE klass, under;
00222 const char *name;
00223 {
00224 VALUE str;
00225
00226 if (under == rb_cObject) {
00227 str = rb_str_new2(name);
00228 }
00229 else {
00230 str = rb_str_dup(rb_class_path(under));
00231 rb_str_cat2(str, "::");
00232 rb_str_cat2(str, name);
00233 }
00234 rb_ivar_set(klass, classpath, str);
00235 }
00236
00237 VALUE
00238 rb_path2class(path)
00239 const char *path;
00240 {
00241 const char *pbeg, *p;
00242 ID id;
00243 VALUE c = rb_cObject;
00244
00245 if (path[0] == '#') {
00246 rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path);
00247 }
00248 pbeg = p = path;
00249 while (*p) {
00250 VALUE str;
00251
00252 while (*p && *p != ':') p++;
00253 str = rb_str_new(pbeg, p-pbeg);
00254 id = rb_intern(RSTRING(str)->ptr);
00255 if (p[0] == ':') {
00256 if (p[1] != ':') goto undefined_class;
00257 p += 2;
00258 pbeg = p;
00259 }
00260 if (!rb_const_defined(c, id)) {
00261 undefined_class:
00262 rb_raise(rb_eArgError, "undefined class/module %.*s", p-path, path);
00263 }
00264 c = rb_const_get_at(c, id);
00265 switch (TYPE(c)) {
00266 case T_MODULE:
00267 case T_CLASS:
00268 break;
00269 default:
00270 rb_raise(rb_eTypeError, "%s does not refer class/module", path);
00271 }
00272 }
00273
00274 return c;
00275 }
00276
00277 void
00278 rb_name_class(klass, id)
00279 VALUE klass;
00280 ID id;
00281 {
00282 rb_iv_set(klass, "__classid__", ID2SYM(id));
00283 }
00284
00285 VALUE
00286 rb_class_name(klass)
00287 VALUE klass;
00288 {
00289 return rb_class_path(rb_class_real(klass));
00290 }
00291
00292 char *
00293 rb_class2name(klass)
00294 VALUE klass;
00295 {
00296 return RSTRING(rb_class_name(klass))->ptr;
00297 }
00298
00299 char *
00300 rb_obj_classname(obj)
00301 VALUE obj;
00302 {
00303 return rb_class2name(CLASS_OF(obj));
00304 }
00305
00306 struct trace_var {
00307 int removed;
00308 void (*func)();
00309 VALUE data;
00310 struct trace_var *next;
00311 };
00312
00313 struct global_variable {
00314 int counter;
00315 void *data;
00316 VALUE (*getter)();
00317 void (*setter)();
00318 void (*marker)();
00319 int block_trace;
00320 struct trace_var *trace;
00321 };
00322
00323 struct global_entry {
00324 struct global_variable *var;
00325 ID id;
00326 };
00327
00328 static VALUE undef_getter();
00329 static void undef_setter();
00330 static void undef_marker();
00331
00332 static VALUE val_getter();
00333 static void val_setter();
00334 static void val_marker();
00335
00336 static VALUE var_getter();
00337 static void var_setter();
00338 static void var_marker();
00339
00340 struct global_entry*
00341 rb_global_entry(id)
00342 ID id;
00343 {
00344 struct global_entry *entry;
00345
00346 if (!st_lookup(rb_global_tbl, id, (st_data_t *)&entry)) {
00347 struct global_variable *var;
00348 entry = ALLOC(struct global_entry);
00349 var = ALLOC(struct global_variable);
00350 entry->id = id;
00351 entry->var = var;
00352 var->counter = 1;
00353 var->data = 0;
00354 var->getter = undef_getter;
00355 var->setter = undef_setter;
00356 var->marker = undef_marker;
00357
00358 var->block_trace = 0;
00359 var->trace = 0;
00360 st_add_direct(rb_global_tbl, id, (st_data_t)entry);
00361 }
00362 return entry;
00363 }
00364
00365 static VALUE
00366 undef_getter(id)
00367 ID id;
00368 {
00369 rb_warning("global variable `%s' not initialized", rb_id2name(id));
00370
00371 return Qnil;
00372 }
00373
00374 static void
00375 undef_setter(val, id, data, var)
00376 VALUE val;
00377 ID id;
00378 void *data;
00379 struct global_variable *var;
00380 {
00381 var->getter = val_getter;
00382 var->setter = val_setter;
00383 var->marker = val_marker;
00384
00385 var->data = (void*)val;
00386 }
00387
00388 static void
00389 undef_marker()
00390 {
00391 }
00392
00393 static VALUE
00394 val_getter(id, val)
00395 ID id;
00396 VALUE val;
00397 {
00398 return val;
00399 }
00400
00401 static void
00402 val_setter(val, id, data, var)
00403 VALUE val;
00404 ID id;
00405 void *data;
00406 struct global_variable *var;
00407 {
00408 var->data = (void*)val;
00409 }
00410
00411 static void
00412 val_marker(data)
00413 VALUE data;
00414 {
00415 if (data) rb_gc_mark_maybe(data);
00416 }
00417
00418 static VALUE
00419 var_getter(id, var)
00420 ID id;
00421 VALUE *var;
00422 {
00423 if (!var) return Qnil;
00424 return *var;
00425 }
00426
00427 static void
00428 var_setter(val, id, var)
00429 VALUE val;
00430 ID id;
00431 VALUE *var;
00432 {
00433 *var = val;
00434 }
00435
00436 static void
00437 var_marker(var)
00438 VALUE *var;
00439 {
00440 if (var) rb_gc_mark_maybe(*var);
00441 }
00442
00443 static void
00444 readonly_setter(val, id, var)
00445 VALUE val;
00446 ID id;
00447 void *var;
00448 {
00449 rb_name_error(id, "%s is a read-only variable", rb_id2name(id));
00450 }
00451
00452 static int
00453 mark_global_entry(key, entry)
00454 ID key;
00455 struct global_entry *entry;
00456 {
00457 struct trace_var *trace;
00458 struct global_variable *var = entry->var;
00459
00460 (*var->marker)(var->data);
00461 trace = var->trace;
00462 while (trace) {
00463 if (trace->data) rb_gc_mark_maybe(trace->data);
00464 trace = trace->next;
00465 }
00466 return ST_CONTINUE;
00467 }
00468
00469 void
00470 rb_gc_mark_global_tbl()
00471 {
00472 if (rb_global_tbl) {
00473 st_foreach(rb_global_tbl, mark_global_entry, 0);
00474 }
00475 }
00476
00477 static ID
00478 global_id(name)
00479 const char *name;
00480 {
00481 ID id;
00482
00483 if (name[0] == '$') id = rb_intern(name);
00484 else {
00485 char *buf = ALLOCA_N(char, strlen(name)+2);
00486 buf[0] = '$';
00487 strcpy(buf+1, name);
00488 id = rb_intern(buf);
00489 }
00490 return id;
00491 }
00492
00493 void
00494 rb_define_hooked_variable(name, var, getter, setter)
00495 const char *name;
00496 VALUE *var;
00497 VALUE (*getter)();
00498 void (*setter)();
00499 {
00500 struct global_variable *gvar;
00501 ID id = global_id(name);
00502
00503 gvar = rb_global_entry(id)->var;
00504 gvar->data = (void*)var;
00505 gvar->getter = getter?getter:var_getter;
00506 gvar->setter = setter?setter:var_setter;
00507 gvar->marker = var_marker;
00508 }
00509
00510 void
00511 rb_define_variable(name, var)
00512 const char *name;
00513 VALUE *var;
00514 {
00515 rb_define_hooked_variable(name, var, 0, 0);
00516 }
00517
00518 void
00519 rb_define_readonly_variable(name, var)
00520 const char *name;
00521 VALUE *var;
00522 {
00523 rb_define_hooked_variable(name, var, 0, readonly_setter);
00524 }
00525
00526 void
00527 rb_define_virtual_variable(name, getter, setter)
00528 const char *name;
00529 VALUE (*getter)();
00530 void (*setter)();
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(cmd, val)
00539 VALUE cmd, val;
00540 {
00541 rb_eval_cmd(cmd, rb_ary_new3(1, val), 0);
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
00567 VALUE
00568 rb_f_trace_var(argc, argv)
00569 int argc;
00570 VALUE *argv;
00571 {
00572 VALUE var, cmd;
00573 struct global_entry *entry;
00574 struct trace_var *trace;
00575
00576 rb_secure(4);
00577 if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) {
00578 cmd = rb_block_proc();
00579 }
00580 if (NIL_P(cmd)) {
00581 return rb_f_untrace_var(argc, argv);
00582 }
00583 entry = rb_global_entry(rb_to_id(var));
00584 if (OBJ_TAINTED(cmd)) {
00585 rb_raise(rb_eSecurityError, "Insecure: tainted variable trace");
00586 }
00587 trace = ALLOC(struct trace_var);
00588 trace->next = entry->var->trace;
00589 trace->func = rb_trace_eval;
00590 trace->data = cmd;
00591 trace->removed = 0;
00592 entry->var->trace = trace;
00593
00594 return Qnil;
00595 }
00596
00597 static void
00598 remove_trace(var)
00599 struct global_variable *var;
00600 {
00601 struct trace_var *trace = var->trace;
00602 struct trace_var t;
00603 struct trace_var *next;
00604
00605 t.next = trace;
00606 trace = &t;
00607 while (trace->next) {
00608 next = trace->next;
00609 if (next->removed) {
00610 trace->next = next->next;
00611 free(next);
00612 }
00613 else {
00614 trace = next;
00615 }
00616 }
00617 var->trace = t.next;
00618 }
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 VALUE
00631 rb_f_untrace_var(argc, argv)
00632 int argc;
00633 VALUE *argv;
00634 {
00635 VALUE var, cmd;
00636 ID id;
00637 struct global_entry *entry;
00638 struct trace_var *trace;
00639
00640 rb_scan_args(argc, argv, "11", &var, &cmd);
00641 id = rb_to_id(var);
00642 if (!st_lookup(rb_global_tbl, id, (st_data_t *)&entry)) {
00643 rb_name_error(id, "undefined global variable %s", rb_id2name(id));
00644 }
00645
00646 trace = entry->var->trace;
00647 if (NIL_P(cmd)) {
00648 VALUE ary = rb_ary_new();
00649
00650 while (trace) {
00651 struct trace_var *next = trace->next;
00652 rb_ary_push(ary, (VALUE)trace->data);
00653 trace->removed = 1;
00654 trace = next;
00655 }
00656
00657 if (!entry->var->block_trace) remove_trace(entry->var);
00658 return ary;
00659 }
00660 else {
00661 while (trace) {
00662 if (trace->data == cmd) {
00663 trace->removed = 1;
00664 if (!entry->var->block_trace) remove_trace(entry->var);
00665 return rb_ary_new3(1, cmd);
00666 }
00667 trace = trace->next;
00668 }
00669 }
00670 return Qnil;
00671 }
00672
00673 VALUE
00674 rb_gvar_get(entry)
00675 struct global_entry *entry;
00676 {
00677 struct global_variable *var = entry->var;
00678 return (*var->getter)(entry->id, var->data, var);
00679 }
00680
00681 struct trace_data {
00682 struct trace_var *trace;
00683 VALUE val;
00684 };
00685
00686 static VALUE
00687 trace_ev(data)
00688 struct trace_data *data;
00689 {
00690 struct trace_var *trace = data->trace;
00691
00692 while (trace) {
00693 (*trace->func)(trace->data, data->val);
00694 trace = trace->next;
00695 }
00696 return Qnil;
00697 }
00698
00699 static VALUE
00700 trace_en(var)
00701 struct global_variable *var;
00702 {
00703 var->block_trace = 0;
00704 remove_trace(var);
00705 return Qnil;
00706 }
00707
00708 VALUE
00709 rb_gvar_set(entry, val)
00710 struct global_entry *entry;
00711 VALUE val;
00712 {
00713 struct trace_data trace;
00714 struct global_variable *var = entry->var;
00715
00716 if (rb_safe_level() >= 4)
00717 rb_raise(rb_eSecurityError, "Insecure: can't change global variable value");
00718 (*var->setter)(val, entry->id, var->data, var);
00719
00720 if (var->trace && !var->block_trace) {
00721 var->block_trace = 1;
00722 trace.trace = var->trace;
00723 trace.val = val;
00724 rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
00725 }
00726 return val;
00727 }
00728
00729 VALUE
00730 rb_gv_set(name, val)
00731 const char *name;
00732 VALUE val;
00733 {
00734 struct global_entry *entry;
00735
00736 entry = rb_global_entry(global_id(name));
00737 return rb_gvar_set(entry, val);
00738 }
00739
00740 VALUE
00741 rb_gv_get(name)
00742 const char *name;
00743 {
00744 struct global_entry *entry;
00745
00746 entry = rb_global_entry(global_id(name));
00747 return rb_gvar_get(entry);
00748 }
00749
00750 VALUE
00751 rb_gvar_defined(entry)
00752 struct global_entry *entry;
00753 {
00754 if (entry->var->getter == undef_getter) return Qfalse;
00755 return Qtrue;
00756 }
00757
00758 static int
00759 gvar_i(key, entry, ary)
00760 ID key;
00761 struct global_entry *entry;
00762 VALUE ary;
00763 {
00764 rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
00765 return ST_CONTINUE;
00766 }
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777 VALUE
00778 rb_f_global_variables()
00779 {
00780 VALUE ary = rb_ary_new();
00781 char buf[4];
00782 char *s = "&`'+123456789";
00783
00784 st_foreach(rb_global_tbl, gvar_i, ary);
00785 if (!NIL_P(rb_backref_get())) {
00786 while (*s) {
00787 sprintf(buf, "$%c", *s++);
00788 rb_ary_push(ary, rb_str_new2(buf));
00789 }
00790 }
00791 return ary;
00792 }
00793
00794 void
00795 rb_alias_variable(name1, name2)
00796 ID name1;
00797 ID name2;
00798 {
00799 struct global_entry *entry1, *entry2;
00800
00801 if (rb_safe_level() >= 4)
00802 rb_raise(rb_eSecurityError, "Insecure: can't alias global variable");
00803
00804 entry2 = rb_global_entry(name2);
00805 if (!st_lookup(rb_global_tbl, name1, (st_data_t *)&entry1)) {
00806 entry1 = ALLOC(struct global_entry);
00807 entry1->id = name1;
00808 st_add_direct(rb_global_tbl, name1, (st_data_t)entry1);
00809 }
00810 else if (entry1->var != entry2->var) {
00811 struct global_variable *var = entry1->var;
00812 if (var->block_trace) {
00813 rb_raise(rb_eRuntimeError, "can't alias in tracer");
00814 }
00815 var->counter--;
00816 if (var->counter == 0) {
00817 struct trace_var *trace = var->trace;
00818 while (trace) {
00819 struct trace_var *next = trace->next;
00820 free(trace);
00821 trace = next;
00822 }
00823 free(var);
00824 }
00825 }
00826 else {
00827 return;
00828 }
00829 entry2->var->counter++;
00830 entry1->var = entry2->var;
00831 }
00832
00833 static int special_generic_ivar = 0;
00834 static st_table *generic_iv_tbl;
00835
00836 st_table*
00837 rb_generic_ivar_table(obj)
00838 VALUE obj;
00839 {
00840 st_table *tbl;
00841
00842 if (!FL_TEST(obj, FL_EXIVAR)) return 0;
00843 if (!generic_iv_tbl) return 0;
00844 if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) return 0;
00845 return tbl;
00846 }
00847
00848 static VALUE
00849 generic_ivar_get(obj, id, warn)
00850 VALUE obj;
00851 ID id;
00852 int warn;
00853 {
00854 st_table *tbl;
00855 VALUE val;
00856
00857 if (generic_iv_tbl) {
00858 if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
00859 if (st_lookup(tbl, id, &val)) {
00860 return val;
00861 }
00862 }
00863 }
00864 if (warn) {
00865 rb_warning("instance variable %s not initialized", rb_id2name(id));
00866 }
00867 return Qnil;
00868 }
00869
00870 static void
00871 generic_ivar_set(obj, id, val)
00872 VALUE obj;
00873 ID id;
00874 VALUE val;
00875 {
00876 st_table *tbl;
00877
00878 if (rb_special_const_p(obj)) {
00879 special_generic_ivar = 1;
00880 }
00881 if (!generic_iv_tbl) {
00882 generic_iv_tbl = st_init_numtable();
00883 }
00884
00885 if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
00886 FL_SET(obj, FL_EXIVAR);
00887 tbl = st_init_numtable();
00888 st_add_direct(generic_iv_tbl, obj, (st_data_t)tbl);
00889 st_add_direct(tbl, id, val);
00890 return;
00891 }
00892 st_insert(tbl, id, val);
00893 }
00894
00895 static VALUE
00896 generic_ivar_defined(obj, id)
00897 VALUE obj;
00898 ID id;
00899 {
00900 st_table *tbl;
00901 VALUE val;
00902
00903 if (!generic_iv_tbl) return Qfalse;
00904 if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) return Qfalse;
00905 if (st_lookup(tbl, id, &val)) {
00906 return Qtrue;
00907 }
00908 return Qfalse;
00909 }
00910
00911 static int
00912 generic_ivar_remove(obj, id, valp)
00913 VALUE obj;
00914 ID id;
00915 VALUE *valp;
00916 {
00917 st_table *tbl;
00918 int status;
00919
00920 if (!generic_iv_tbl) return 0;
00921 if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) return 0;
00922 status = st_delete(tbl, &id, valp);
00923 if (tbl->num_entries == 0) {
00924 st_delete(generic_iv_tbl, &obj, (st_data_t *)&tbl);
00925 st_free_table(tbl);
00926 }
00927 return status;
00928 }
00929
00930 void
00931 rb_mark_generic_ivar(obj)
00932 VALUE obj;
00933 {
00934 st_table *tbl;
00935
00936 if (!generic_iv_tbl) return;
00937 if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
00938 rb_mark_tbl(tbl);
00939 }
00940 }
00941
00942 static int
00943 givar_mark_i(key, value)
00944 ID key;
00945 VALUE value;
00946 {
00947 rb_gc_mark(value);
00948 return ST_CONTINUE;
00949 }
00950
00951 static int
00952 givar_i(obj, tbl)
00953 VALUE obj;
00954 st_table *tbl;
00955 {
00956 if (rb_special_const_p(obj)) {
00957 st_foreach(tbl, givar_mark_i, 0);
00958 }
00959 return ST_CONTINUE;
00960 }
00961
00962 void
00963 rb_mark_generic_ivar_tbl()
00964 {
00965 if (!generic_iv_tbl) return;
00966 if (special_generic_ivar == 0) return;
00967 st_foreach_safe(generic_iv_tbl, givar_i, 0);
00968 }
00969
00970 void
00971 rb_free_generic_ivar(obj)
00972 VALUE obj;
00973 {
00974 st_table *tbl;
00975
00976 if (st_delete(generic_iv_tbl, &obj, (st_data_t *)&tbl))
00977 st_free_table(tbl);
00978 }
00979
00980 void
00981 rb_copy_generic_ivar(clone, obj)
00982 VALUE clone, obj;
00983 {
00984 st_table *tbl;
00985
00986 if (!generic_iv_tbl) return;
00987 if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
00988 st_table *old;
00989
00990 if (st_lookup(generic_iv_tbl, clone, (st_data_t *)&old)) {
00991 st_free_table(old);
00992 st_insert(generic_iv_tbl, clone, (st_data_t)st_copy(tbl));
00993 }
00994 else {
00995 st_add_direct(generic_iv_tbl, clone, (st_data_t)st_copy(tbl));
00996 }
00997 }
00998 }
00999
01000 static VALUE
01001 ivar_get(obj, id, warn)
01002 VALUE obj;
01003 ID id;
01004 int warn;
01005 {
01006 VALUE val;
01007
01008 switch (TYPE(obj)) {
01009 case T_OBJECT:
01010 case T_CLASS:
01011 case T_MODULE:
01012 if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, &val))
01013 return val;
01014 break;
01015 default:
01016 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01017 return generic_ivar_get(obj, id, warn);
01018 break;
01019 }
01020 if (warn) {
01021 rb_warning("instance variable %s not initialized", rb_id2name(id));
01022 }
01023 return Qnil;
01024 }
01025
01026 VALUE
01027 rb_ivar_get(obj, id)
01028 VALUE obj;
01029 ID id;
01030 {
01031 return ivar_get(obj, id, Qtrue);
01032 }
01033
01034 VALUE
01035 rb_attr_get(obj, id)
01036 VALUE obj;
01037 ID id;
01038 {
01039 return ivar_get(obj, id, Qfalse);
01040 }
01041
01042 VALUE
01043 rb_ivar_set(obj, id, val)
01044 VALUE obj;
01045 ID id;
01046 VALUE val;
01047 {
01048 if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
01049 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
01050 if (OBJ_FROZEN(obj)) rb_error_frozen("object");
01051 switch (TYPE(obj)) {
01052 case T_OBJECT:
01053 case T_CLASS:
01054 case T_MODULE:
01055 if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable();
01056 st_insert(ROBJECT(obj)->iv_tbl, id, val);
01057 break;
01058 default:
01059 generic_ivar_set(obj, id, val);
01060 break;
01061 }
01062 return val;
01063 }
01064
01065 VALUE
01066 rb_ivar_defined(obj, id)
01067 VALUE obj;
01068 ID id;
01069 {
01070 switch (TYPE(obj)) {
01071 case T_OBJECT:
01072 case T_CLASS:
01073 case T_MODULE:
01074 if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, 0))
01075 return Qtrue;
01076 break;
01077 default:
01078 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01079 return generic_ivar_defined(obj, id);
01080 break;
01081 }
01082 return Qfalse;
01083 }
01084
01085 static int
01086 ivar_i(key, entry, ary)
01087 ID key;
01088 struct global_entry *entry;
01089 VALUE ary;
01090 {
01091 if (rb_is_instance_id(key)) {
01092 rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
01093 }
01094 return ST_CONTINUE;
01095 }
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 VALUE
01115 rb_obj_instance_variables(obj)
01116 VALUE obj;
01117 {
01118 VALUE ary;
01119
01120 ary = rb_ary_new();
01121 switch (TYPE(obj)) {
01122 case T_OBJECT:
01123 case T_CLASS:
01124 case T_MODULE:
01125 if (ROBJECT(obj)->iv_tbl) {
01126 st_foreach_safe(ROBJECT(obj)->iv_tbl, ivar_i, ary);
01127 }
01128 break;
01129 default:
01130 if (!generic_iv_tbl) break;
01131 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01132 st_table *tbl;
01133
01134 if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
01135 st_foreach_safe(tbl, ivar_i, ary);
01136 }
01137 }
01138 break;
01139 }
01140 return ary;
01141 }
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165 VALUE
01166 rb_obj_remove_instance_variable(obj, name)
01167 VALUE obj, name;
01168 {
01169 VALUE val = Qnil;
01170 ID id = rb_to_id(name);
01171
01172 if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
01173 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
01174 if (OBJ_FROZEN(obj)) rb_error_frozen("object");
01175 if (!rb_is_instance_id(id)) {
01176 rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id));
01177 }
01178
01179 switch (TYPE(obj)) {
01180 case T_OBJECT:
01181 case T_CLASS:
01182 case T_MODULE:
01183 if (ROBJECT(obj)->iv_tbl && st_delete(ROBJECT(obj)->iv_tbl, (st_data_t*)&id, &val)) {
01184 return val;
01185 }
01186 break;
01187 default:
01188 if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01189 if (generic_ivar_remove(obj, id, &val)) {
01190 return val;
01191 }
01192 }
01193 break;
01194 }
01195 rb_name_error(id, "instance variable %s not defined", rb_id2name(id));
01196 return Qnil;
01197 }
01200 static void uninitialized_constant (VALUE, ID);
01201 static void
01202 uninitialized_constant(klass, id)
01203 VALUE klass;
01204 ID id;
01205 {
01206 if (klass && klass != rb_cObject)
01207 rb_name_error(id, "uninitialized constant %s::%s",
01208 rb_class2name(klass),
01209 rb_id2name(id));
01210 else {
01211 rb_name_error(id, "uninitialized constant %s", rb_id2name(id));
01212 }
01213 }
01214
01215 static VALUE
01216 const_missing(klass, id)
01217 VALUE klass;
01218 ID id;
01219 {
01220 return rb_funcall(klass, rb_intern("const_missing"), 1, ID2SYM(id));
01221 }
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252 VALUE
01253 rb_mod_const_missing(klass, name)
01254 VALUE klass, name;
01255 {
01256 ruby_frame = ruby_frame->prev;
01257 uninitialized_constant(klass, rb_to_id(name));
01258 return Qnil;
01259 }
01260
01261 static struct st_table *
01262 check_autoload_table(av)
01263 VALUE av;
01264 {
01265 Check_Type(av, T_DATA);
01266 if (RDATA(av)->dmark != (RUBY_DATA_FUNC)rb_mark_tbl ||
01267 RDATA(av)->dfree != (RUBY_DATA_FUNC)st_free_table) {
01268 rb_raise(rb_eTypeError, "wrong autoload table: %s", RSTRING(rb_inspect(av))->ptr);
01269 }
01270 return (struct st_table *)DATA_PTR(av);
01271 }
01272
01273 void
01274 rb_autoload(mod, id, file)
01275 VALUE mod;
01276 ID id;
01277 const char *file;
01278 {
01279 VALUE av, fn;
01280 struct st_table *tbl;
01281
01282 if (!rb_is_const_id(id)) {
01283 rb_raise(rb_eNameError, "autoload must be constant name", rb_id2name(id));
01284 }
01285 if (!file || !*file) {
01286 rb_raise(rb_eArgError, "empty file name");
01287 }
01288
01289 if ((tbl = RCLASS(mod)->iv_tbl) && st_lookup(tbl, id, &av) && av != Qundef)
01290 return;
01291
01292 rb_const_set(mod, id, Qundef);
01293 tbl = RCLASS(mod)->iv_tbl;
01294 if (st_lookup(tbl, autoload, &av)) {
01295 tbl = check_autoload_table(av);
01296 }
01297 else {
01298 av = Data_Wrap_Struct(0 , rb_mark_tbl, st_free_table, 0);
01299 st_add_direct(tbl, autoload, av);
01300 DATA_PTR(av) = tbl = st_init_numtable();
01301 }
01302 fn = rb_str_new2(file);
01303 FL_UNSET(fn, FL_TAINT);
01304 OBJ_FREEZE(fn);
01305 st_insert(tbl, id, (st_data_t)rb_node_newnode(NODE_MEMO, fn, ruby_safe_level, 0));
01306 }
01307
01308 static NODE*
01309 autoload_delete(mod, id)
01310 VALUE mod;
01311 ID id;
01312 {
01313 VALUE val;
01314 st_data_t load = 0;
01315
01316 st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, 0);
01317 if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) {
01318 struct st_table *tbl = check_autoload_table(val);
01319
01320 st_delete(tbl, (st_data_t*)&id, &load);
01321
01322 if (tbl->num_entries == 0) {
01323 DATA_PTR(val) = 0;
01324 st_free_table(tbl);
01325 id = autoload;
01326 if (st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, &val)) {
01327 rb_gc_force_recycle(val);
01328 }
01329 }
01330 }
01331
01332 return (NODE *)load;
01333 }
01334
01335 VALUE
01336 rb_autoload_load(klass, id)
01337 VALUE klass;
01338 ID id;
01339 {
01340 VALUE file;
01341 NODE *load = autoload_delete(klass, id);
01342
01343 if (!load || !(file = load->nd_lit) || rb_provided(RSTRING(file)->ptr)) {
01344 return Qfalse;
01345 }
01346 return rb_require_safe(file, load->nd_nth);
01347 }
01348
01349 static VALUE
01350 autoload_file(mod, id)
01351 VALUE mod;
01352 ID id;
01353 {
01354 VALUE val, file;
01355 struct st_table *tbl;
01356 st_data_t load;
01357
01358 if (!st_lookup(RCLASS(mod)->iv_tbl, autoload, &val) ||
01359 !(tbl = check_autoload_table(val)) || !st_lookup(tbl, id, &load)) {
01360 return Qnil;
01361 }
01362 file = ((NODE *)load)->nd_lit;
01363 Check_Type(file, T_STRING);
01364 if (!RSTRING(file)->ptr || !*RSTRING(file)->ptr) {
01365 rb_raise(rb_eArgError, "empty file name");
01366 }
01367 if (!rb_provided(RSTRING(file)->ptr)) {
01368 return file;
01369 }
01370
01371
01372 st_delete(tbl, (st_data_t*)&id, 0);
01373 if (!tbl->num_entries) {
01374 DATA_PTR(val) = 0;
01375 st_free_table(tbl);
01376 id = autoload;
01377 if (st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, &val)) {
01378 rb_gc_force_recycle(val);
01379 }
01380 }
01381 return Qnil;
01382 }
01383
01384 VALUE
01385 rb_autoload_p(mod, id)
01386 VALUE mod;
01387 ID id;
01388 {
01389 struct st_table *tbl = RCLASS(mod)->iv_tbl;
01390 VALUE val;
01391
01392 if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) {
01393 return Qnil;
01394 }
01395 return autoload_file(mod, id);
01396 }
01397
01398 static VALUE
01399 rb_const_get_0(klass, id, exclude, recurse)
01400 VALUE klass;
01401 ID id;
01402 int exclude, recurse;
01403 {
01404 VALUE value, tmp;
01405 int mod_retry = 0;
01406
01407 tmp = klass;
01408 retry:
01409 while (tmp) {
01410 while (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
01411 if (value == Qundef) {
01412 if (!RTEST(rb_autoload_load(tmp, id))) break;
01413 continue;
01414 }
01415 if (exclude && tmp == rb_cObject && klass != rb_cObject) {
01416 rb_warn("toplevel constant %s referenced by %s::%s",
01417 rb_id2name(id), rb_class2name(klass), rb_id2name(id));
01418 }
01419 return value;
01420 }
01421 if (!recurse && klass != rb_cObject) break;
01422 tmp = RCLASS(tmp)->super;
01423 }
01424 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
01425 mod_retry = 1;
01426 tmp = rb_cObject;
01427 goto retry;
01428 }
01429
01430 return const_missing(klass, id);
01431 }
01432
01433 VALUE
01434 rb_const_get_from(klass, id)
01435 VALUE klass;
01436 ID id;
01437 {
01438 return rb_const_get_0(klass, id, Qtrue, Qtrue);
01439 }
01440
01441 VALUE
01442 rb_const_get(klass, id)
01443 VALUE klass;
01444 ID id;
01445 {
01446 return rb_const_get_0(klass, id, Qfalse, Qtrue);
01447 }
01448
01449 VALUE
01450 rb_const_get_at(klass, id)
01451 VALUE klass;
01452 ID id;
01453 {
01454 return rb_const_get_0(klass, id, Qtrue, Qfalse);
01455 }
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466 VALUE
01467 rb_mod_remove_const(mod, name)
01468 VALUE mod, name;
01469 {
01470 ID id = rb_to_id(name);
01471 VALUE val;
01472
01473 if (!rb_is_const_id(id)) {
01474 rb_name_error(id, "`%s' is not allowed as a constant name", rb_id2name(id));
01475 }
01476 if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4)
01477 rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
01478 if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
01479
01480 if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, (st_data_t*)&id, &val)) {
01481 if (val == Qundef) {
01482 autoload_delete(mod, id);
01483 val = Qnil;
01484 }
01485 return val;
01486 }
01487 if (rb_const_defined_at(mod, id)) {
01488 rb_name_error(id, "cannot remove %s::%s",
01489 rb_class2name(mod), rb_id2name(id));
01490 }
01491 rb_name_error(id, "constant %s::%s not defined",
01492 rb_class2name(mod), rb_id2name(id));
01493 return Qnil;
01494 }
01495
01496 static int
01497 sv_i(key, value, tbl)
01498 ID key;
01499 VALUE value;
01500 st_table *tbl;
01501 {
01502 if (rb_is_const_id(key)) {
01503 if (!st_lookup(tbl, key, 0)) {
01504 st_insert(tbl, key, key);
01505 }
01506 }
01507 return ST_CONTINUE;
01508 }
01509
01510 void*
01511 rb_mod_const_at(mod, data)
01512 VALUE mod;
01513 void *data;
01514 {
01515 st_table *tbl = data;
01516 if (!tbl) {
01517 tbl = st_init_numtable();
01518 }
01519 if (RCLASS(mod)->iv_tbl) {
01520 st_foreach_safe(RCLASS(mod)->iv_tbl, sv_i, (st_data_t)tbl);
01521 }
01522 return tbl;
01523 }
01524
01525 void*
01526 rb_mod_const_of(mod, data)
01527 VALUE mod;
01528 void *data;
01529 {
01530 VALUE tmp = mod;
01531 for (;;) {
01532 data = rb_mod_const_at(tmp, data);
01533 tmp = RCLASS(tmp)->super;
01534 if (!tmp) break;
01535 if (tmp == rb_cObject && mod != rb_cObject) break;
01536 }
01537 return data;
01538 }
01539
01540 static int
01541 list_i(key, value, ary)
01542 ID key, value;
01543 VALUE ary;
01544 {
01545 rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
01546 return ST_CONTINUE;
01547 }
01548
01549 VALUE
01550 rb_const_list(data)
01551 void *data;
01552 {
01553 st_table *tbl = data;
01554 VALUE ary;
01555
01556 if (!tbl) return rb_ary_new2(0);
01557 ary = rb_ary_new2(tbl->num_entries);
01558 st_foreach(tbl, list_i, ary);
01559 st_free_table(tbl);
01560
01561 return ary;
01562 }
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573 VALUE
01574 rb_mod_constants(mod)
01575 VALUE mod;
01576 {
01577 return rb_const_list(rb_mod_const_of(mod, 0));
01578 }
01579
01580