2000-05-01 13:42:38 +04:00
|
|
|
/**********************************************************************
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
variable.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
$Date$
|
|
|
|
created at: Tue Apr 19 23:55:15 JST 1994
|
|
|
|
|
2003-01-16 10:34:03 +03:00
|
|
|
Copyright (C) 1993-2003 Yukihiro Matsumoto
|
2000-05-01 13:42:38 +04:00
|
|
|
Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
2000-05-09 08:53:16 +04:00
|
|
|
Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
2000-05-01 13:42:38 +04:00
|
|
|
|
|
|
|
**********************************************************************/
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
#include "ruby.h"
|
|
|
|
#include "env.h"
|
|
|
|
#include "node.h"
|
|
|
|
#include "st.h"
|
2001-05-30 13:12:34 +04:00
|
|
|
#include "util.h"
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
static st_table *rb_global_tbl;
|
|
|
|
st_table *rb_class_tbl;
|
|
|
|
|
|
|
|
void
|
|
|
|
Init_var_tables()
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_global_tbl = st_init_numtable();
|
|
|
|
rb_class_tbl = st_init_numtable();
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct fc_result {
|
|
|
|
ID name;
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE path;
|
|
|
|
VALUE track;
|
|
|
|
struct fc_result *prev;
|
|
|
|
};
|
|
|
|
|
2001-06-06 10:42:23 +04:00
|
|
|
static VALUE
|
|
|
|
fc_path(fc, name)
|
|
|
|
struct fc_result *fc;
|
|
|
|
ID name;
|
|
|
|
{
|
|
|
|
VALUE path, tmp;
|
|
|
|
|
|
|
|
path = rb_str_new2(rb_id2name(name));
|
|
|
|
while (fc) {
|
|
|
|
if (fc->track == rb_cObject) break;
|
|
|
|
if (ROBJECT(fc->track)->iv_tbl &&
|
|
|
|
st_lookup(ROBJECT(fc->track)->iv_tbl, rb_intern("__classpath__"), &tmp)) {
|
|
|
|
tmp = rb_str_dup(tmp);
|
|
|
|
rb_str_cat2(tmp, "::");
|
|
|
|
rb_str_append(tmp, path);
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
tmp = rb_str_new2(rb_id2name(fc->name));
|
|
|
|
rb_str_cat2(tmp, "::");
|
|
|
|
rb_str_append(tmp, path);
|
|
|
|
path = tmp;
|
|
|
|
fc = fc->prev;
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static int
|
|
|
|
fc_i(key, value, res)
|
|
|
|
ID key;
|
|
|
|
VALUE value;
|
|
|
|
struct fc_result *res;
|
|
|
|
{
|
1999-12-14 09:50:43 +03:00
|
|
|
if (!rb_is_const_id(key)) return ST_CONTINUE;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
if (value == res->klass) {
|
2001-06-06 10:42:23 +04:00
|
|
|
res->path = fc_path(res, key);
|
1998-01-16 15:13:05 +03:00
|
|
|
return ST_STOP;
|
|
|
|
}
|
2001-06-06 10:42:23 +04:00
|
|
|
switch (TYPE(value)) {
|
|
|
|
case T_MODULE:
|
|
|
|
case T_CLASS:
|
1998-01-16 15:13:05 +03:00
|
|
|
if (!RCLASS(value)->iv_tbl) return ST_CONTINUE;
|
2001-06-06 10:42:23 +04:00
|
|
|
else {
|
|
|
|
struct fc_result arg;
|
|
|
|
struct fc_result *list;
|
|
|
|
|
|
|
|
list = res;
|
|
|
|
while (list) {
|
|
|
|
if (list->track == value) return ST_CONTINUE;
|
|
|
|
list = list->prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg.name = key;
|
|
|
|
arg.path = 0;
|
|
|
|
arg.klass = res->klass;
|
|
|
|
arg.track = value;
|
|
|
|
arg.prev = res;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_foreach(RCLASS(value)->iv_tbl, fc_i, (st_data_t)&arg);
|
2001-06-06 10:42:23 +04:00
|
|
|
if (arg.path) {
|
|
|
|
res->path = arg.path;
|
|
|
|
return ST_STOP;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-06-06 10:42:23 +04:00
|
|
|
break;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-06-06 10:42:23 +04:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
find_class_path(klass)
|
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
struct fc_result arg;
|
|
|
|
|
|
|
|
arg.name = 0;
|
|
|
|
arg.path = 0;
|
1999-01-20 07:59:39 +03:00
|
|
|
arg.klass = klass;
|
|
|
|
arg.track = rb_cObject;
|
1998-01-16 15:13:05 +03:00
|
|
|
arg.prev = 0;
|
1999-01-20 07:59:39 +03:00
|
|
|
if (RCLASS(rb_cObject)->iv_tbl) {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_foreach(RCLASS(rb_cObject)->iv_tbl, fc_i, (st_data_t)&arg);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-06-06 10:42:23 +04:00
|
|
|
if (arg.path == 0) {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_foreach(rb_class_tbl, fc_i, (st_data_t)&arg);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-06-06 10:42:23 +04:00
|
|
|
if (arg.path) {
|
2001-12-18 11:47:06 +03:00
|
|
|
if (!ROBJECT(klass)->iv_tbl) {
|
|
|
|
ROBJECT(klass)->iv_tbl = st_init_numtable();
|
|
|
|
}
|
1999-08-13 09:45:20 +04:00
|
|
|
st_insert(ROBJECT(klass)->iv_tbl,rb_intern("__classpath__"),arg.path);
|
1998-01-16 15:13:05 +03:00
|
|
|
return arg.path;
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
classname(klass)
|
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-08-13 09:45:20 +04:00
|
|
|
VALUE path = Qnil;
|
1999-01-20 07:59:39 +03:00
|
|
|
ID classpath = rb_intern("__classpath__");
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2002-02-04 11:09:14 +03:00
|
|
|
klass = rb_class_real(klass);
|
1999-01-20 07:59:39 +03:00
|
|
|
if (!klass) klass = rb_cObject;
|
2001-12-11 06:48:08 +03:00
|
|
|
if (ROBJECT(klass)->iv_tbl &&
|
|
|
|
!st_lookup(ROBJECT(klass)->iv_tbl, classpath, &path)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
ID classid = rb_intern("__classid__");
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
if (st_lookup(ROBJECT(klass)->iv_tbl, classid, &path)) {
|
2000-04-10 09:48:43 +04:00
|
|
|
path = rb_str_new2(rb_id2name(SYM2ID(path)));
|
1999-01-20 07:59:39 +03:00
|
|
|
st_insert(ROBJECT(klass)->iv_tbl, classpath, path);
|
|
|
|
st_delete(RCLASS(klass)->iv_tbl, &classid, 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NIL_P(path)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
path = find_class_path(klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
if (NIL_P(path)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
if (TYPE(path) != T_STRING)
|
|
|
|
rb_bug("class path is not set properly");
|
1998-01-16 15:13:05 +03:00
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_mod_name(mod)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE mod;
|
|
|
|
{
|
2002-02-04 11:09:14 +03:00
|
|
|
VALUE path = classname(mod);
|
1998-01-16 15:19:22 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (path) return rb_str_dup(path);
|
|
|
|
return rb_str_new(0,0);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_class_path(klass)
|
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-02-04 11:09:14 +03:00
|
|
|
VALUE path = classname(klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
if (path) return path;
|
|
|
|
else {
|
2002-08-28 18:59:01 +04:00
|
|
|
VALUE str;
|
1998-01-16 15:13:05 +03:00
|
|
|
char *s = "Class";
|
|
|
|
|
2001-10-03 11:19:19 +04:00
|
|
|
if (TYPE(klass) == T_MODULE) {
|
2002-08-28 18:59:01 +04:00
|
|
|
if (rb_obj_class(klass) == rb_cModule) {
|
2001-10-03 11:19:19 +04:00
|
|
|
s = "Module";
|
2002-08-28 18:59:01 +04:00
|
|
|
}
|
|
|
|
else {
|
2001-10-03 11:19:19 +04:00
|
|
|
s = rb_class2name(RBASIC(klass)->klass);
|
2002-08-28 18:59:01 +04:00
|
|
|
}
|
2001-10-03 11:19:19 +04:00
|
|
|
}
|
2002-08-28 18:59:01 +04:00
|
|
|
str = rb_str_new(0, 2 + strlen(s) + 3 + 2 * SIZEOF_LONG + 1);
|
|
|
|
sprintf(RSTRING(str)->ptr, "#<%s:0x%lx>", s, klass);
|
|
|
|
RSTRING(str)->len = strlen(RSTRING(str)->ptr);
|
|
|
|
|
|
|
|
return str;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_set_class_path(klass, under, name)
|
|
|
|
VALUE klass, under;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE str;
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (under == rb_cObject) {
|
|
|
|
str = rb_str_new2(name);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-01-20 07:59:39 +03:00
|
|
|
str = rb_str_dup(rb_class_path(under));
|
2000-04-10 09:48:43 +04:00
|
|
|
rb_str_cat2(str, "::");
|
|
|
|
rb_str_cat2(str, name);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_iv_set(klass, "__classpath__", str);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_path2class(path)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *path;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-09-05 13:42:56 +04:00
|
|
|
const char *pbeg, *p;
|
|
|
|
ID id;
|
|
|
|
VALUE c = rb_cObject;
|
1999-11-29 09:33:02 +03:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
if (path[0] == '#') {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2002-09-05 13:42:56 +04:00
|
|
|
pbeg = p = path;
|
|
|
|
while (*p) {
|
|
|
|
VALUE str;
|
|
|
|
|
|
|
|
while (*p && *p != ':') p++;
|
|
|
|
str = rb_str_new(pbeg, p-pbeg);
|
|
|
|
id = rb_intern(RSTRING(str)->ptr);
|
|
|
|
if (p[0] == ':') {
|
|
|
|
if (p[1] != ':') goto undefined_class;
|
|
|
|
p += 2;
|
|
|
|
pbeg = p;
|
|
|
|
}
|
|
|
|
if (!rb_const_defined(c, id)) {
|
|
|
|
undefined_class:
|
|
|
|
rb_raise(rb_eArgError, "undefined class/module %s", rb_id2name(id));
|
|
|
|
rb_raise(rb_eArgError, "undefined class/module %s", path);
|
|
|
|
}
|
|
|
|
c = rb_const_get_at(c, id);
|
|
|
|
switch (TYPE(c)) {
|
|
|
|
case T_MODULE:
|
|
|
|
case T_CLASS:
|
|
|
|
break;
|
|
|
|
default:
|
2002-10-23 12:20:35 +04:00
|
|
|
rb_raise(rb_eTypeError, "%s does not refer class/module", path);
|
2002-09-05 13:42:56 +04:00
|
|
|
}
|
1999-11-29 09:33:02 +03:00
|
|
|
}
|
2002-09-05 13:42:56 +04:00
|
|
|
|
1999-11-29 09:33:02 +03:00
|
|
|
return c;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_name_class(klass, id)
|
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
{
|
2000-04-10 09:48:43 +04:00
|
|
|
rb_iv_set(klass, "__classid__", ID2SYM(id));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static st_table *autoload_tbl = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
rb_autoload_id(id, filename)
|
|
|
|
ID id;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *filename;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2000-03-17 11:58:21 +03:00
|
|
|
rb_secure(4);
|
1999-12-14 09:50:43 +03:00
|
|
|
if (!rb_is_const_id(id)) {
|
2002-04-10 12:45:26 +04:00
|
|
|
rb_name_error(id, "autoload must be constant name");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!autoload_tbl) {
|
1999-01-20 07:59:39 +03:00
|
|
|
autoload_tbl = st_init_numtable();
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_insert(autoload_tbl, id, (st_data_t)strdup(filename));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_autoload(klass, filename)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *klass, *filename;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_autoload_id(rb_intern(klass), filename);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_f_autoload(obj, klass, file)
|
|
|
|
VALUE obj, klass, file;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-05-02 08:22:21 +04:00
|
|
|
rb_autoload_id(rb_to_id(klass), StringValuePtr(file));
|
1998-01-16 15:13:05 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_class2name(klass)
|
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
return RSTRING(rb_class_path(klass))->ptr;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct trace_var {
|
1998-01-16 15:19:22 +03:00
|
|
|
int removed;
|
1998-01-16 15:13:05 +03:00
|
|
|
void (*func)();
|
2001-03-19 06:20:24 +03:00
|
|
|
VALUE data;
|
1998-01-16 15:13:05 +03:00
|
|
|
struct trace_var *next;
|
|
|
|
};
|
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable {
|
|
|
|
int counter;
|
1998-01-16 15:13:05 +03:00
|
|
|
void *data;
|
|
|
|
VALUE (*getter)();
|
|
|
|
void (*setter)();
|
|
|
|
void (*marker)();
|
|
|
|
int block_trace;
|
|
|
|
struct trace_var *trace;
|
|
|
|
};
|
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_entry {
|
|
|
|
struct global_variable *var;
|
|
|
|
ID id;
|
|
|
|
};
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE undef_getter();
|
|
|
|
static void undef_setter();
|
|
|
|
static void undef_marker();
|
|
|
|
|
|
|
|
static VALUE val_getter();
|
|
|
|
static void val_setter();
|
|
|
|
static void val_marker();
|
|
|
|
|
|
|
|
static VALUE var_getter();
|
|
|
|
static void var_setter();
|
|
|
|
static void var_marker();
|
|
|
|
|
|
|
|
struct global_entry*
|
|
|
|
rb_global_entry(id)
|
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
struct global_entry *entry;
|
|
|
|
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (!st_lookup(rb_global_tbl, id, (st_data_t *)&entry)) {
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable *var;
|
1998-01-16 15:13:05 +03:00
|
|
|
entry = ALLOC(struct global_entry);
|
2001-10-22 20:20:14 +04:00
|
|
|
var = ALLOC(struct global_variable);
|
1998-01-16 15:13:05 +03:00
|
|
|
entry->id = id;
|
2001-10-22 20:20:14 +04:00
|
|
|
entry->var = var;
|
|
|
|
var->counter = 1;
|
|
|
|
var->data = 0;
|
|
|
|
var->getter = undef_getter;
|
|
|
|
var->setter = undef_setter;
|
|
|
|
var->marker = undef_marker;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
var->block_trace = 0;
|
|
|
|
var->trace = 0;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_add_direct(rb_global_tbl, id, (st_data_t)entry);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
undef_getter(id)
|
|
|
|
ID id;
|
|
|
|
{
|
2002-04-11 14:03:01 +04:00
|
|
|
rb_warning("global variable `%s' not initialized", rb_id2name(id));
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2001-10-22 20:20:14 +04:00
|
|
|
undef_setter(val, id, data, var)
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE val;
|
|
|
|
ID id;
|
|
|
|
void *data;
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable *var;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-10-22 20:20:14 +04:00
|
|
|
var->getter = val_getter;
|
|
|
|
var->setter = val_setter;
|
|
|
|
var->marker = val_marker;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
var->data = (void*)val;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
undef_marker()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
val_getter(id, val)
|
|
|
|
ID id;
|
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2001-10-22 20:20:14 +04:00
|
|
|
val_setter(val, id, data, var)
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE val;
|
|
|
|
ID id;
|
|
|
|
void *data;
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable *var;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-10-22 20:20:14 +04:00
|
|
|
var->data = (void*)val;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
val_marker(data)
|
2001-03-19 06:20:24 +03:00
|
|
|
VALUE data;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (data) rb_gc_mark_maybe(data);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
var_getter(id, var)
|
|
|
|
ID id;
|
|
|
|
VALUE *var;
|
|
|
|
{
|
2001-11-13 11:19:52 +03:00
|
|
|
if (!var) return Qnil;
|
1998-01-16 15:13:05 +03:00
|
|
|
return *var;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
var_setter(val, id, var)
|
|
|
|
VALUE val;
|
|
|
|
ID id;
|
|
|
|
VALUE *var;
|
|
|
|
{
|
|
|
|
*var = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
var_marker(var)
|
2001-03-19 06:20:24 +03:00
|
|
|
VALUE *var;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (var) rb_gc_mark_maybe(*var);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
readonly_setter(val, id, var)
|
|
|
|
VALUE val;
|
|
|
|
ID id;
|
|
|
|
void *var;
|
|
|
|
{
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "can't set variable %s", rb_id2name(id));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
mark_global_entry(key, entry)
|
|
|
|
ID key;
|
|
|
|
struct global_entry *entry;
|
|
|
|
{
|
|
|
|
struct trace_var *trace;
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable *var = entry->var;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
(*var->marker)(var->data);
|
|
|
|
trace = var->trace;
|
1998-01-16 15:13:05 +03:00
|
|
|
while (trace) {
|
1999-01-20 07:59:39 +03:00
|
|
|
if (trace->data) rb_gc_mark_maybe(trace->data);
|
1998-01-16 15:13:05 +03:00
|
|
|
trace = trace->next;
|
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_gc_mark_global_tbl()
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
st_foreach(rb_global_tbl, mark_global_entry, 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ID
|
|
|
|
global_id(name)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
ID id;
|
|
|
|
|
|
|
|
if (name[0] == '$') id = rb_intern(name);
|
|
|
|
else {
|
|
|
|
char *buf = ALLOCA_N(char, strlen(name)+2);
|
|
|
|
buf[0] = '$';
|
|
|
|
strcpy(buf+1, name);
|
|
|
|
id = rb_intern(buf);
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_hooked_variable(name, var, getter, setter)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE *var;
|
|
|
|
VALUE (*getter)();
|
|
|
|
void (*setter)();
|
|
|
|
{
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable *gvar;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id = global_id(name);
|
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
gvar = rb_global_entry(id)->var;
|
|
|
|
gvar->data = (void*)var;
|
|
|
|
gvar->getter = getter?getter:var_getter;
|
|
|
|
gvar->setter = setter?setter:var_setter;
|
|
|
|
gvar->marker = var_marker;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_variable(name, var)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE *var;
|
|
|
|
{
|
|
|
|
rb_define_hooked_variable(name, var, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_readonly_variable(name, var)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE *var;
|
|
|
|
{
|
|
|
|
rb_define_hooked_variable(name, var, 0, readonly_setter);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_virtual_variable(name, getter, setter)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE (*getter)();
|
|
|
|
void (*setter)();
|
|
|
|
{
|
|
|
|
if (!getter) getter = val_getter;
|
|
|
|
if (!setter) setter = readonly_setter;
|
|
|
|
rb_define_hooked_variable(name, 0, getter, setter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rb_trace_eval(cmd, val)
|
|
|
|
VALUE cmd, val;
|
|
|
|
{
|
2001-11-13 11:19:52 +03:00
|
|
|
rb_eval_cmd(cmd, rb_ary_new3(1, val), 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_f_trace_var(argc, argv)
|
1998-01-16 15:13:05 +03:00
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
{
|
|
|
|
VALUE var, cmd;
|
|
|
|
struct global_entry *entry;
|
|
|
|
struct trace_var *trace;
|
|
|
|
|
2001-11-13 11:19:52 +03:00
|
|
|
rb_secure(4);
|
1998-01-16 15:13:05 +03:00
|
|
|
if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) {
|
1999-01-20 07:59:39 +03:00
|
|
|
cmd = rb_f_lambda();
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
if (NIL_P(cmd)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_f_untrace_var(argc, argv);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-11-13 11:19:52 +03:00
|
|
|
entry = rb_global_entry(rb_to_id(var));
|
|
|
|
if (OBJ_TAINTED(cmd)) {
|
|
|
|
rb_raise(rb_eSecurityError, "Insecure: tainted variable trace");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
trace = ALLOC(struct trace_var);
|
2001-10-22 20:20:14 +04:00
|
|
|
trace->next = entry->var->trace;
|
1998-01-16 15:13:05 +03:00
|
|
|
trace->func = rb_trace_eval;
|
2001-03-19 06:20:24 +03:00
|
|
|
trace->data = cmd;
|
1998-01-16 15:19:22 +03:00
|
|
|
trace->removed = 0;
|
2001-10-22 20:20:14 +04:00
|
|
|
entry->var->trace = trace;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
static void
|
2001-10-22 20:20:14 +04:00
|
|
|
remove_trace(var)
|
|
|
|
struct global_variable *var;
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2001-10-22 20:20:14 +04:00
|
|
|
struct trace_var *trace = var->trace;
|
1998-01-16 15:19:22 +03:00
|
|
|
struct trace_var t;
|
|
|
|
struct trace_var *next;
|
|
|
|
|
|
|
|
t.next = trace;
|
|
|
|
trace = &t;
|
|
|
|
while (trace->next) {
|
|
|
|
next = trace->next;
|
|
|
|
if (next->removed) {
|
|
|
|
trace->next = next->next;
|
|
|
|
free(next);
|
|
|
|
}
|
2001-10-21 17:22:54 +04:00
|
|
|
else {
|
|
|
|
trace = next;
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
2001-10-22 20:20:14 +04:00
|
|
|
var->trace = t.next;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_f_untrace_var(argc, argv)
|
1998-01-16 15:13:05 +03:00
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
{
|
|
|
|
VALUE var, cmd;
|
|
|
|
ID id;
|
|
|
|
struct global_entry *entry;
|
|
|
|
struct trace_var *trace;
|
|
|
|
|
|
|
|
rb_scan_args(argc, argv, "11", &var, &cmd);
|
|
|
|
id = rb_to_id(var);
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (!st_lookup(rb_global_tbl, id, (st_data_t *)&entry)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "undefined global variable %s", rb_id2name(id));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
trace = entry->var->trace;
|
1998-01-16 15:13:05 +03:00
|
|
|
if (NIL_P(cmd)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE ary = rb_ary_new();
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
while (trace) {
|
|
|
|
struct trace_var *next = trace->next;
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_push(ary, (VALUE)trace->data);
|
1998-01-16 15:19:22 +03:00
|
|
|
trace->removed = 1;
|
1998-01-16 15:13:05 +03:00
|
|
|
trace = next;
|
|
|
|
}
|
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
if (!entry->var->block_trace) remove_trace(entry->var);
|
1998-01-16 15:13:05 +03:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
else {
|
1998-01-16 15:19:22 +03:00
|
|
|
while (trace) {
|
2001-03-19 06:20:24 +03:00
|
|
|
if (trace->data == cmd) {
|
1998-01-16 15:19:22 +03:00
|
|
|
trace->removed = 1;
|
2001-10-22 20:20:14 +04:00
|
|
|
if (!entry->var->block_trace) remove_trace(entry->var);
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_ary_new3(1, cmd);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
trace = trace->next;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
2001-10-17 09:28:02 +04:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_gvar_get(entry)
|
|
|
|
struct global_entry *entry;
|
|
|
|
{
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable *var = entry->var;
|
|
|
|
return (*var->getter)(entry->id, var->data, var);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct trace_data {
|
|
|
|
struct trace_var *trace;
|
|
|
|
VALUE val;
|
|
|
|
};
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
1998-01-16 15:13:05 +03:00
|
|
|
trace_ev(data)
|
|
|
|
struct trace_data *data;
|
|
|
|
{
|
|
|
|
struct trace_var *trace = data->trace;
|
|
|
|
|
|
|
|
while (trace) {
|
|
|
|
(*trace->func)(trace->data, data->val);
|
|
|
|
trace = trace->next;
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qnil; /* not reached */
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2001-10-22 20:20:14 +04:00
|
|
|
trace_en(var)
|
|
|
|
struct global_variable *var;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-10-22 20:20:14 +04:00
|
|
|
var->block_trace = 0;
|
|
|
|
remove_trace(var);
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qnil; /* not reached */
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_gvar_set(entry, val)
|
|
|
|
struct global_entry *entry;
|
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
struct trace_data trace;
|
2001-10-22 20:20:14 +04:00
|
|
|
struct global_variable *var = entry->var;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (rb_safe_level() >= 4)
|
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't change global variable value");
|
2001-10-22 20:20:14 +04:00
|
|
|
(*var->setter)(val, entry->id, var->data, var);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
if (var->trace && !var->block_trace) {
|
|
|
|
var->block_trace = 1;
|
|
|
|
trace.trace = var->trace;
|
1998-01-16 15:13:05 +03:00
|
|
|
trace.val = val;
|
2001-10-22 20:20:14 +04:00
|
|
|
rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-11-17 10:30:37 +03:00
|
|
|
rb_gv_set(name, val)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
struct global_entry *entry;
|
|
|
|
|
|
|
|
entry = rb_global_entry(global_id(name));
|
|
|
|
return rb_gvar_set(entry, val);
|
|
|
|
}
|
|
|
|
|
1999-11-17 10:30:37 +03:00
|
|
|
VALUE
|
|
|
|
rb_gv_get(name)
|
|
|
|
const char *name;
|
|
|
|
{
|
|
|
|
struct global_entry *entry;
|
|
|
|
|
|
|
|
entry = rb_global_entry(global_id(name));
|
|
|
|
return rb_gvar_get(entry);
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_gvar_defined(entry)
|
|
|
|
struct global_entry *entry;
|
|
|
|
{
|
2001-10-22 20:20:14 +04:00
|
|
|
if (entry->var->getter == undef_getter) return Qfalse;
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qtrue;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
static int
|
|
|
|
gvar_i(key, entry, ary)
|
|
|
|
ID key;
|
|
|
|
struct global_entry *entry;
|
|
|
|
VALUE ary;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
1998-01-16 15:19:22 +03:00
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_f_global_variables()
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE ary = rb_ary_new();
|
|
|
|
char buf[4];
|
|
|
|
char *s = "&`'+123456789";
|
1998-01-16 15:19:22 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
st_foreach(rb_global_tbl, gvar_i, ary);
|
|
|
|
if (!NIL_P(rb_backref_get())) {
|
|
|
|
while (*s) {
|
|
|
|
sprintf(buf, "$%c", *s++);
|
|
|
|
rb_ary_push(ary, rb_str_new2(buf));
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
|
|
|
rb_alias_variable(name1, name2)
|
|
|
|
ID name1;
|
|
|
|
ID name2;
|
|
|
|
{
|
|
|
|
struct global_entry *entry1, *entry2;
|
|
|
|
|
2001-05-22 12:28:11 +04:00
|
|
|
if (rb_safe_level() >= 4)
|
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't alias global variable");
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-22 20:20:14 +04:00
|
|
|
entry2 = rb_global_entry(name2);
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (!st_lookup(rb_global_tbl, name1, (st_data_t *)&entry1)) {
|
2001-10-22 20:20:14 +04:00
|
|
|
entry1 = ALLOC(struct global_entry);
|
|
|
|
entry1->id = name1;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_add_direct(rb_global_tbl, name1, (st_data_t)entry1);
|
2001-10-22 20:20:14 +04:00
|
|
|
}
|
|
|
|
else if (entry1->var != entry2->var) {
|
|
|
|
struct global_variable *var = entry1->var;
|
|
|
|
if (var->block_trace) {
|
|
|
|
rb_raise(rb_eRuntimeError, "can't alias in tracer");
|
|
|
|
}
|
|
|
|
var->counter--;
|
|
|
|
if (var->counter == 0) {
|
|
|
|
struct trace_var *trace = var->trace;
|
|
|
|
while (trace) {
|
|
|
|
struct trace_var *next = trace->next;
|
|
|
|
free(trace);
|
|
|
|
trace = next;
|
|
|
|
}
|
|
|
|
free(var);
|
|
|
|
}
|
2001-10-17 09:28:02 +04:00
|
|
|
}
|
2001-10-22 20:20:14 +04:00
|
|
|
else {
|
|
|
|
return;
|
2001-10-17 09:28:02 +04:00
|
|
|
}
|
2001-10-22 20:20:14 +04:00
|
|
|
entry2->var->counter++;
|
|
|
|
entry1->var = entry2->var;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static int special_generic_ivar = 0;
|
|
|
|
static st_table *generic_iv_tbl;
|
|
|
|
|
2000-01-05 07:41:21 +03:00
|
|
|
st_table*
|
|
|
|
rb_generic_ivar_table(obj)
|
|
|
|
VALUE obj;
|
|
|
|
{
|
|
|
|
st_table *tbl;
|
|
|
|
|
|
|
|
if (!generic_iv_tbl) return 0;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) return 0;
|
2000-01-05 07:41:21 +03:00
|
|
|
return tbl;
|
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
|
|
|
generic_ivar_get(obj, id)
|
|
|
|
VALUE obj;
|
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
st_table *tbl;
|
|
|
|
VALUE val;
|
|
|
|
|
2002-12-19 12:20:20 +03:00
|
|
|
if (generic_iv_tbl) {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
|
2002-12-19 12:20:20 +03:00
|
|
|
if (st_lookup(tbl, id, &val)) {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2002-12-19 12:20:20 +03:00
|
|
|
|
|
|
|
rb_warning("instance variable %s not initialized", rb_id2name(id));
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
generic_ivar_set(obj, id, val)
|
|
|
|
VALUE obj;
|
|
|
|
ID id;
|
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
st_table *tbl;
|
|
|
|
|
|
|
|
if (rb_special_const_p(obj)) {
|
|
|
|
special_generic_ivar = 1;
|
|
|
|
}
|
|
|
|
if (!generic_iv_tbl) {
|
|
|
|
generic_iv_tbl = st_init_numtable();
|
|
|
|
}
|
|
|
|
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
FL_SET(obj, FL_EXIVAR);
|
|
|
|
tbl = st_init_numtable();
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_add_direct(generic_iv_tbl, obj, (st_data_t)tbl);
|
1999-01-20 07:59:39 +03:00
|
|
|
st_add_direct(tbl, id, val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
st_insert(tbl, id, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
generic_ivar_defined(obj, id)
|
|
|
|
VALUE obj;
|
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
st_table *tbl;
|
|
|
|
VALUE val;
|
|
|
|
|
|
|
|
if (!generic_iv_tbl) return Qfalse;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) return Qfalse;
|
1999-01-20 07:59:39 +03:00
|
|
|
if (st_lookup(tbl, id, &val)) {
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2002-04-10 12:45:26 +04:00
|
|
|
static int
|
|
|
|
generic_ivar_remove(obj, id, valp)
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE obj;
|
|
|
|
ID id;
|
2002-04-10 12:45:26 +04:00
|
|
|
VALUE *valp;
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
st_table *tbl;
|
2002-04-10 12:45:26 +04:00
|
|
|
int status;
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2002-04-10 12:45:26 +04:00
|
|
|
if (!generic_iv_tbl) return 0;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (!st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) return 0;
|
2002-04-10 12:45:26 +04:00
|
|
|
status = st_delete(tbl, &id, valp);
|
1999-01-20 07:59:39 +03:00
|
|
|
if (tbl->num_entries == 0) {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_delete(generic_iv_tbl, &obj, (st_data_t *)&tbl);
|
1999-01-20 07:59:39 +03:00
|
|
|
st_free_table(tbl);
|
|
|
|
}
|
2002-04-10 12:45:26 +04:00
|
|
|
return status;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_mark_generic_ivar(obj)
|
|
|
|
VALUE obj;
|
|
|
|
{
|
|
|
|
st_table *tbl;
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
if (!generic_iv_tbl) return;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_mark_tbl(tbl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
static int
|
|
|
|
givar_mark_i(key, value)
|
|
|
|
ID key;
|
|
|
|
VALUE value;
|
|
|
|
{
|
|
|
|
rb_gc_mark(value);
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static int
|
|
|
|
givar_i(obj, tbl)
|
|
|
|
VALUE obj;
|
|
|
|
st_table *tbl;
|
|
|
|
{
|
|
|
|
if (rb_special_const_p(obj)) {
|
|
|
|
st_foreach(tbl, givar_mark_i, 0);
|
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_mark_generic_ivar_tbl()
|
|
|
|
{
|
|
|
|
if (!generic_iv_tbl) return;
|
1999-08-13 09:45:20 +04:00
|
|
|
if (special_generic_ivar == 0) return;
|
1999-01-20 07:59:39 +03:00
|
|
|
st_foreach(generic_iv_tbl, givar_i, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_free_generic_ivar(obj)
|
|
|
|
VALUE obj;
|
|
|
|
{
|
|
|
|
st_table *tbl;
|
|
|
|
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (st_delete(generic_iv_tbl, &obj, (st_data_t *)&tbl))
|
1999-01-20 07:59:39 +03:00
|
|
|
st_free_table(tbl);
|
|
|
|
}
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
void
|
2001-07-14 19:17:19 +04:00
|
|
|
rb_copy_generic_ivar(clone, obj)
|
1999-08-13 09:45:20 +04:00
|
|
|
VALUE clone, obj;
|
|
|
|
{
|
|
|
|
st_table *tbl;
|
|
|
|
|
|
|
|
if (!generic_iv_tbl) return;
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
|
2002-09-03 09:20:14 +04:00
|
|
|
st_table *old;
|
|
|
|
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (st_lookup(generic_iv_tbl, clone, (st_data_t *)&old)) {
|
2002-09-03 09:20:14 +04:00
|
|
|
st_free_table(old);
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_insert(generic_iv_tbl, clone, (st_data_t)st_copy(tbl));
|
2002-09-03 09:20:14 +04:00
|
|
|
}
|
|
|
|
else {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_add_direct(generic_iv_tbl, clone, (st_data_t)st_copy(tbl));
|
2002-09-03 09:20:14 +04:00
|
|
|
}
|
1999-08-13 09:45:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_ivar_get(obj, id)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE obj;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
VALUE val;
|
|
|
|
|
|
|
|
switch (TYPE(obj)) {
|
|
|
|
case T_OBJECT:
|
|
|
|
case T_CLASS:
|
|
|
|
case T_MODULE:
|
1998-01-16 15:19:22 +03:00
|
|
|
if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, &val))
|
1998-01-16 15:13:05 +03:00
|
|
|
return val;
|
1999-01-20 07:59:39 +03:00
|
|
|
break;
|
1998-01-16 15:13:05 +03:00
|
|
|
default:
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
|
|
|
|
return generic_ivar_get(obj, id);
|
1998-01-16 15:13:05 +03:00
|
|
|
break;
|
|
|
|
}
|
2002-04-11 14:03:01 +04:00
|
|
|
rb_warning("instance variable %s not initialized", rb_id2name(id));
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_ivar_set(obj, id, val)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE obj;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
VALUE val;
|
|
|
|
{
|
1999-12-14 09:50:43 +03:00
|
|
|
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
|
1999-08-13 09:45:20 +04:00
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
|
2000-02-01 06:12:21 +03:00
|
|
|
if (OBJ_FROZEN(obj)) rb_error_frozen("object");
|
1998-01-16 15:13:05 +03:00
|
|
|
switch (TYPE(obj)) {
|
|
|
|
case T_OBJECT:
|
|
|
|
case T_CLASS:
|
|
|
|
case T_MODULE:
|
1999-01-20 07:59:39 +03:00
|
|
|
if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable();
|
1998-01-16 15:19:22 +03:00
|
|
|
st_insert(ROBJECT(obj)->iv_tbl, id, val);
|
1998-01-16 15:13:05 +03:00
|
|
|
break;
|
|
|
|
default:
|
1999-01-20 07:59:39 +03:00
|
|
|
generic_ivar_set(obj, id, val);
|
1998-01-16 15:13:05 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_ivar_defined(obj, id)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE obj;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
switch (TYPE(obj)) {
|
|
|
|
case T_OBJECT:
|
|
|
|
case T_CLASS:
|
|
|
|
case T_MODULE:
|
1998-01-16 15:19:22 +03:00
|
|
|
if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, 0))
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qtrue;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
|
|
|
|
return generic_ivar_defined(obj, id);
|
1998-01-16 15:13:05 +03:00
|
|
|
break;
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qfalse;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
static int
|
1999-01-20 07:59:39 +03:00
|
|
|
ivar_i(key, entry, ary)
|
1998-01-16 15:19:22 +03:00
|
|
|
ID key;
|
1999-01-20 07:59:39 +03:00
|
|
|
struct global_entry *entry;
|
|
|
|
VALUE ary;
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
|
|
|
if (rb_is_instance_id(key)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_obj_instance_variables(obj)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE obj;
|
|
|
|
{
|
1999-12-14 09:50:43 +03:00
|
|
|
VALUE ary;
|
1998-01-16 15:19:22 +03:00
|
|
|
|
1999-12-14 09:50:43 +03:00
|
|
|
ary = rb_ary_new();
|
1998-01-16 15:19:22 +03:00
|
|
|
switch (TYPE(obj)) {
|
|
|
|
case T_OBJECT:
|
|
|
|
case T_CLASS:
|
|
|
|
case T_MODULE:
|
|
|
|
if (ROBJECT(obj)->iv_tbl) {
|
1999-01-20 07:59:39 +03:00
|
|
|
st_foreach(ROBJECT(obj)->iv_tbl, ivar_i, ary);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
1999-10-04 08:51:08 +04:00
|
|
|
break;
|
1998-01-16 15:19:22 +03:00
|
|
|
default:
|
1999-10-04 08:51:08 +04:00
|
|
|
if (!generic_iv_tbl) break;
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
|
|
|
|
st_table *tbl;
|
|
|
|
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
if (st_lookup(generic_iv_tbl, obj, (st_data_t *)&tbl)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
st_foreach(tbl, ivar_i, ary);
|
|
|
|
}
|
|
|
|
}
|
1999-10-04 08:51:08 +04:00
|
|
|
break;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
1999-10-04 08:51:08 +04:00
|
|
|
return ary;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_obj_remove_instance_variable(obj, name)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE obj, name;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE val = Qnil;
|
1998-01-16 15:19:22 +03:00
|
|
|
ID id = rb_to_id(name);
|
|
|
|
|
1999-12-14 09:50:43 +03:00
|
|
|
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
|
1999-08-13 09:45:20 +04:00
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
|
2000-02-01 06:12:21 +03:00
|
|
|
if (OBJ_FROZEN(obj)) rb_error_frozen("object");
|
1999-01-20 07:59:39 +03:00
|
|
|
if (!rb_is_instance_id(id)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "`%s' is not an instance variable", rb_id2name(id));
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (TYPE(obj)) {
|
|
|
|
case T_OBJECT:
|
|
|
|
case T_CLASS:
|
|
|
|
case T_MODULE:
|
2002-04-10 12:45:26 +04:00
|
|
|
if (ROBJECT(obj)->iv_tbl && st_delete(ROBJECT(obj)->iv_tbl, &id, &val)) {
|
|
|
|
return val;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2002-04-10 12:45:26 +04:00
|
|
|
if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
|
|
|
|
if (generic_ivar_remove(obj, id, &val)) {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
break;
|
|
|
|
}
|
2002-04-10 12:45:26 +04:00
|
|
|
rb_name_error(id, "instance variable %s not defined", rb_id2name(id));
|
|
|
|
return Qnil; /* not reached */
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2000-07-12 13:36:21 +04:00
|
|
|
static int
|
|
|
|
top_const_get(id, klassp)
|
2000-07-12 10:06:50 +04:00
|
|
|
ID id;
|
2000-07-12 13:36:21 +04:00
|
|
|
VALUE *klassp;
|
2000-07-12 10:06:50 +04:00
|
|
|
{
|
|
|
|
/* pre-defined class */
|
2000-07-12 13:36:21 +04:00
|
|
|
if (st_lookup(rb_class_tbl, id, klassp)) return Qtrue;
|
2000-07-12 10:06:50 +04:00
|
|
|
|
|
|
|
/* autoload */
|
|
|
|
if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
|
|
|
|
rb_autoload_load(id);
|
2000-07-12 13:36:21 +04:00
|
|
|
*klassp = rb_const_get(rb_cObject, id);
|
|
|
|
return Qtrue;
|
2000-07-12 10:06:50 +04:00
|
|
|
}
|
2000-07-12 13:36:21 +04:00
|
|
|
return Qfalse;
|
2000-07-12 10:06:50 +04:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_get_at(klass, id)
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
VALUE value;
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
|
1998-01-16 15:13:05 +03:00
|
|
|
return value;
|
|
|
|
}
|
2000-07-12 13:36:21 +04:00
|
|
|
if (klass == rb_cObject && top_const_get(id, &value)) {
|
|
|
|
return value;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "uninitialized constant %s::%s",
|
|
|
|
RSTRING(rb_class_path(klass))->ptr,
|
|
|
|
rb_id2name(id));
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qnil; /* not reached */
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1999-12-14 09:50:43 +03:00
|
|
|
void
|
|
|
|
rb_autoload_load(id)
|
1999-11-17 10:30:37 +03:00
|
|
|
ID id;
|
|
|
|
{
|
1999-12-14 09:50:43 +03:00
|
|
|
char *modname;
|
|
|
|
VALUE module;
|
|
|
|
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_delete(autoload_tbl, &id, (st_data_t *)&modname);
|
2000-09-22 22:15:52 +04:00
|
|
|
if (rb_provided(modname)) {
|
|
|
|
free(modname);
|
|
|
|
return;
|
|
|
|
}
|
1999-12-14 09:50:43 +03:00
|
|
|
module = rb_str_new2(modname);
|
|
|
|
free(modname);
|
2000-08-28 13:53:42 +04:00
|
|
|
FL_UNSET(module, FL_TAINT);
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_f_require(Qnil, module);
|
1999-11-17 10:30:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_get(klass, id)
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
{
|
2001-05-02 08:22:21 +04:00
|
|
|
VALUE value, tmp;
|
|
|
|
int mod_retry = 0;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
tmp = klass;
|
2001-05-02 08:22:21 +04:00
|
|
|
retry:
|
1998-01-16 15:13:05 +03:00
|
|
|
while (tmp) {
|
1998-01-16 15:19:22 +03:00
|
|
|
if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
|
1998-01-16 15:13:05 +03:00
|
|
|
return value;
|
|
|
|
}
|
2000-07-12 13:36:21 +04:00
|
|
|
if (tmp == rb_cObject && top_const_get(id, &value)) return value;
|
1998-01-16 15:19:22 +03:00
|
|
|
tmp = RCLASS(tmp)->super;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-05-02 08:22:21 +04:00
|
|
|
if (!mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
|
|
|
|
mod_retry = 1;
|
|
|
|
tmp = rb_cObject;
|
|
|
|
goto retry;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-07-12 13:36:21 +04:00
|
|
|
|
|
|
|
/* Uninitialized constant */
|
2001-05-02 08:22:21 +04:00
|
|
|
if (klass && klass != rb_cObject) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "uninitialized constant %s at %s",
|
|
|
|
rb_id2name(id),
|
|
|
|
RSTRING(rb_class_path(klass))->ptr);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2002-04-24 08:54:16 +04:00
|
|
|
else { /* global_uninitialized */
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
|
2000-07-12 13:36:21 +04:00
|
|
|
}
|
|
|
|
return Qnil; /* not reached */
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_mod_remove_const(mod, name)
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE mod, name;
|
|
|
|
{
|
|
|
|
ID id = rb_to_id(name);
|
|
|
|
VALUE val;
|
|
|
|
|
1999-12-14 09:50:43 +03:00
|
|
|
if (!rb_is_const_id(id)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "`%s' is not constant", rb_id2name(id));
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2000-02-01 06:12:21 +03:00
|
|
|
if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4)
|
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
|
|
|
|
if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
|
1999-01-20 07:59:39 +03:00
|
|
|
|
|
|
|
if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, &id, &val)) {
|
|
|
|
return val;
|
|
|
|
}
|
1999-12-14 09:50:43 +03:00
|
|
|
if (rb_const_defined_at(mod, id)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "cannot remove %s::%s",
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_class2name(mod), rb_id2name(id));
|
|
|
|
}
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "constant %s::%s not defined",
|
|
|
|
rb_class2name(mod), rb_id2name(id));
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qnil; /* not reached */
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
static int
|
2001-06-05 11:19:39 +04:00
|
|
|
sv_i(key, value, tbl)
|
|
|
|
ID key;
|
|
|
|
VALUE value;
|
|
|
|
st_table *tbl;
|
|
|
|
{
|
|
|
|
if (rb_is_const_id(key)) {
|
|
|
|
if (!st_lookup(tbl, key, 0)) {
|
|
|
|
st_insert(tbl, key, key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
autoload_i(key, name, tbl)
|
1998-01-16 15:19:22 +03:00
|
|
|
ID key;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
2001-06-05 11:19:39 +04:00
|
|
|
st_table *tbl;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-06-05 11:19:39 +04:00
|
|
|
if (!st_lookup(tbl, key, 0)) {
|
|
|
|
st_insert(tbl, key, key);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-06-05 11:19:39 +04:00
|
|
|
void*
|
|
|
|
rb_mod_const_at(mod, data)
|
|
|
|
VALUE mod;
|
|
|
|
void *data;
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2001-06-05 11:19:39 +04:00
|
|
|
st_table *tbl = data;
|
|
|
|
if (!tbl) {
|
|
|
|
tbl = st_init_numtable();
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
if (RCLASS(mod)->iv_tbl) {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_foreach(RCLASS(mod)->iv_tbl, sv_i, (st_data_t)tbl);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
if ((VALUE)mod == rb_cObject) {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_foreach(rb_class_tbl, sv_i, (st_data_t)tbl);
|
1998-01-16 15:13:05 +03:00
|
|
|
if (autoload_tbl) {
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_foreach(autoload_tbl, autoload_i, (st_data_t)tbl);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
2001-06-05 11:19:39 +04:00
|
|
|
return tbl;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2001-06-05 11:19:39 +04:00
|
|
|
void*
|
|
|
|
rb_mod_const_of(mod, data)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE mod;
|
2001-06-05 11:19:39 +04:00
|
|
|
void *data;
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
|
|
|
for (;;) {
|
2001-06-05 11:19:39 +04:00
|
|
|
data = rb_mod_const_at(mod, data);
|
1998-01-16 15:19:22 +03:00
|
|
|
mod = RCLASS(mod)->super;
|
|
|
|
if (!mod) break;
|
|
|
|
}
|
2001-06-05 11:19:39 +04:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
list_i(key, value, ary)
|
|
|
|
ID key, value;
|
|
|
|
VALUE ary;
|
|
|
|
{
|
|
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_const_list(data)
|
|
|
|
void *data;
|
|
|
|
{
|
|
|
|
st_table *tbl = data;
|
|
|
|
VALUE ary;
|
|
|
|
|
|
|
|
if (!tbl) return rb_ary_new2(0);
|
|
|
|
ary = rb_ary_new2(tbl->num_entries);
|
|
|
|
st_foreach(tbl, list_i, ary);
|
2002-03-20 14:15:19 +03:00
|
|
|
st_free_table(tbl);
|
2001-06-05 11:19:39 +04:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1999-11-17 10:30:37 +03:00
|
|
|
VALUE
|
|
|
|
rb_mod_constants(mod)
|
|
|
|
VALUE mod;
|
|
|
|
{
|
2001-06-05 11:19:39 +04:00
|
|
|
return rb_const_list(rb_mod_const_of(mod, 0));
|
1999-11-17 10:30:37 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
int
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_defined_at(klass, id)
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, 0)) {
|
|
|
|
return Qtrue;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
if (klass == rb_cObject) {
|
1999-12-14 09:50:43 +03:00
|
|
|
return rb_const_defined(klass, id);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qfalse;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_autoload_defined(id)
|
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
if (autoload_tbl && st_lookup(autoload_tbl, id, 0))
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qtrue;
|
|
|
|
return Qfalse;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_defined(klass, id)
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE tmp = klass;
|
|
|
|
|
|
|
|
while (tmp) {
|
|
|
|
if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
|
|
|
|
return Qtrue;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
tmp = RCLASS(tmp)->super;
|
|
|
|
}
|
|
|
|
if (BUILTIN_TYPE(klass) == T_MODULE) {
|
1999-12-14 09:50:43 +03:00
|
|
|
return rb_const_defined(rb_cObject, id);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
if (st_lookup(rb_class_tbl, id, 0))
|
|
|
|
return Qtrue;
|
1998-01-16 15:13:05 +03:00
|
|
|
return rb_autoload_defined(id);
|
|
|
|
}
|
|
|
|
|
2000-02-18 09:59:36 +03:00
|
|
|
static void
|
2000-12-08 10:10:38 +03:00
|
|
|
mod_av_set(klass, id, val, isconst)
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
VALUE val;
|
2000-12-08 10:10:38 +03:00
|
|
|
int isconst;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2000-12-08 10:10:38 +03:00
|
|
|
char *dest = isconst ? "constant" : "class variable";
|
|
|
|
|
1999-12-14 09:50:43 +03:00
|
|
|
if (!OBJ_TAINTED(klass) && rb_safe_level() >= 4)
|
2000-02-18 09:59:36 +03:00
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest);
|
2000-02-01 06:12:21 +03:00
|
|
|
if (OBJ_FROZEN(klass)) rb_error_frozen("class/module");
|
1999-01-20 07:59:39 +03:00
|
|
|
if (!RCLASS(klass)->iv_tbl) {
|
|
|
|
RCLASS(klass)->iv_tbl = st_init_numtable();
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-08-23 10:02:15 +04:00
|
|
|
else if (isconst) {
|
|
|
|
if (st_lookup(RCLASS(klass)->iv_tbl, id, 0) ||
|
|
|
|
(klass == rb_cObject && st_lookup(rb_class_tbl, id, 0))) {
|
|
|
|
rb_warn("already initialized %s %s", dest, rb_id2name(id));
|
|
|
|
}
|
2000-02-01 06:12:21 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
st_insert(RCLASS(klass)->iv_tbl, id, val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-12-08 10:10:38 +03:00
|
|
|
|
2000-02-18 09:59:36 +03:00
|
|
|
void
|
|
|
|
rb_const_set(klass, id, val)
|
|
|
|
VALUE klass;
|
|
|
|
ID id;
|
|
|
|
VALUE val;
|
|
|
|
{
|
2000-12-08 10:10:38 +03:00
|
|
|
mod_av_set(klass, id, val, Qtrue);
|
2000-02-18 09:59:36 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-11-17 10:30:37 +03:00
|
|
|
void
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_assign(klass, id, val)
|
1999-11-17 10:30:37 +03:00
|
|
|
VALUE klass;
|
|
|
|
ID id;
|
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
VALUE tmp = klass;
|
|
|
|
|
|
|
|
while (tmp) {
|
|
|
|
if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
|
|
|
|
st_insert(RCLASS(tmp)->iv_tbl, id, val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tmp = RCLASS(tmp)->super;
|
|
|
|
}
|
|
|
|
/* pre-defined class */
|
|
|
|
if (st_lookup(rb_class_tbl, id, 0)) {
|
2002-08-30 14:46:37 +04:00
|
|
|
st_delete(rb_class_tbl, &id, 0);
|
1999-11-17 10:30:37 +03:00
|
|
|
st_insert(RCLASS(rb_cObject)->iv_tbl, id, val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* autoload */
|
|
|
|
if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
|
|
|
|
char *modname;
|
|
|
|
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_delete(autoload_tbl, (st_data_t *)&id, (st_data_t *)&modname);
|
1999-11-17 10:30:37 +03:00
|
|
|
free(modname);
|
|
|
|
st_insert(RCLASS(rb_cObject)->iv_tbl, id, val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Uninitialized constant */
|
|
|
|
if (klass && klass != rb_cObject)
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "uninitialized constant %s::%s",
|
|
|
|
RSTRING(rb_class_path(klass))->ptr,
|
|
|
|
rb_id2name(id));
|
1999-11-17 10:30:37 +03:00
|
|
|
else {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
|
1999-11-17 10:30:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_const(klass, name, val)
|
|
|
|
VALUE klass;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
ID id = rb_intern(name);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
|
|
|
if (klass == rb_cObject) {
|
|
|
|
rb_secure(4);
|
|
|
|
}
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_set(klass, id, val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_global_const(name, val)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE val;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_const(rb_cObject, name, val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2001-11-13 11:19:52 +03:00
|
|
|
static VALUE
|
|
|
|
original_module(c)
|
|
|
|
VALUE c;
|
|
|
|
{
|
|
|
|
if (TYPE(c) == T_ICLASS)
|
|
|
|
return RBASIC(c)->klass;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2001-08-20 08:29:58 +04:00
|
|
|
static void
|
2001-11-13 11:19:52 +03:00
|
|
|
cvar_override_check(id, a)
|
2002-09-17 13:36:05 +04:00
|
|
|
ID id;
|
2001-11-13 11:19:52 +03:00
|
|
|
VALUE a;
|
2001-08-20 08:29:58 +04:00
|
|
|
{
|
2001-11-13 11:19:52 +03:00
|
|
|
VALUE base = original_module(a);
|
|
|
|
|
2001-08-20 08:29:58 +04:00
|
|
|
a = RCLASS(a)->super;
|
|
|
|
while (a) {
|
2001-10-29 08:07:26 +03:00
|
|
|
if (RCLASS(a)->iv_tbl) {
|
|
|
|
if (st_lookup(RCLASS(a)->iv_tbl,id,0)) {
|
|
|
|
rb_warning("class variable %s of %s is overridden by %s",
|
2001-11-13 11:19:52 +03:00
|
|
|
rb_id2name(id), rb_class2name(original_module(a)),
|
|
|
|
rb_class2name(base));
|
2001-10-29 08:07:26 +03:00
|
|
|
}
|
2001-08-20 08:29:58 +04:00
|
|
|
}
|
|
|
|
a = RCLASS(a)->super;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-18 09:59:36 +03:00
|
|
|
void
|
2002-02-15 09:14:26 +03:00
|
|
|
rb_cvar_set(klass, id, val, warn)
|
2000-02-18 09:59:36 +03:00
|
|
|
VALUE klass;
|
|
|
|
ID id;
|
|
|
|
VALUE val;
|
2002-02-15 09:14:26 +03:00
|
|
|
int warn;
|
2000-02-18 09:59:36 +03:00
|
|
|
{
|
|
|
|
VALUE tmp;
|
|
|
|
|
|
|
|
tmp = klass;
|
|
|
|
while (tmp) {
|
2001-12-21 12:23:28 +03:00
|
|
|
if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
|
|
|
|
if (OBJ_FROZEN(tmp)) rb_error_frozen("class/module");
|
|
|
|
if (!OBJ_TAINTED(tmp) && rb_safe_level() >= 4)
|
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't modify class variable");
|
2002-04-11 14:03:01 +04:00
|
|
|
if (warn && RTEST(ruby_verbose) && klass != tmp) {
|
2001-08-14 12:13:31 +04:00
|
|
|
rb_warning("already initialized class variable %s", rb_id2name(id));
|
|
|
|
}
|
2000-09-07 10:59:46 +04:00
|
|
|
st_insert(RCLASS(tmp)->iv_tbl,id,val);
|
2002-04-11 14:03:01 +04:00
|
|
|
if (RTEST(ruby_verbose)) {
|
2001-11-13 11:19:52 +03:00
|
|
|
cvar_override_check(id, tmp);
|
2001-08-20 08:29:58 +04:00
|
|
|
}
|
2000-09-07 10:59:46 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tmp = RCLASS(tmp)->super;
|
|
|
|
}
|
|
|
|
|
2000-12-08 10:10:38 +03:00
|
|
|
mod_av_set(klass, id, val, Qfalse);
|
2000-02-18 09:59:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2000-03-23 11:37:35 +03:00
|
|
|
rb_cvar_get(klass, id)
|
2000-02-18 09:59:36 +03:00
|
|
|
VALUE klass;
|
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
VALUE value;
|
|
|
|
VALUE tmp;
|
|
|
|
|
|
|
|
tmp = klass;
|
|
|
|
while (tmp) {
|
2001-10-29 08:07:26 +03:00
|
|
|
if (RCLASS(tmp)->iv_tbl) {
|
|
|
|
if (st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
|
2002-04-11 14:03:01 +04:00
|
|
|
if (RTEST(ruby_verbose)) {
|
2001-11-13 11:19:52 +03:00
|
|
|
cvar_override_check(id, tmp);
|
2001-10-29 08:07:26 +03:00
|
|
|
}
|
|
|
|
return value;
|
2001-08-20 08:29:58 +04:00
|
|
|
}
|
2000-02-18 09:59:36 +03:00
|
|
|
}
|
|
|
|
tmp = RCLASS(tmp)->super;
|
|
|
|
}
|
|
|
|
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id,"uninitialized class variable %s in %s",
|
|
|
|
rb_id2name(id), rb_class2name(klass));
|
2000-02-18 09:59:36 +03:00
|
|
|
return Qnil; /* not reached */
|
|
|
|
}
|
|
|
|
|
2000-12-08 10:10:38 +03:00
|
|
|
VALUE
|
2000-03-23 11:37:35 +03:00
|
|
|
rb_cvar_defined(klass, id)
|
2000-02-18 09:59:36 +03:00
|
|
|
VALUE klass;
|
|
|
|
ID id;
|
|
|
|
{
|
|
|
|
VALUE tmp;
|
|
|
|
|
|
|
|
tmp = klass;
|
|
|
|
while (tmp) {
|
|
|
|
if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
tmp = RCLASS(tmp)->super;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-03-23 11:37:35 +03:00
|
|
|
rb_cv_set(klass, name, val)
|
|
|
|
VALUE klass;
|
|
|
|
const char *name;
|
|
|
|
VALUE val;
|
|
|
|
{
|
2001-05-02 08:22:21 +04:00
|
|
|
ID id = rb_intern(name);
|
|
|
|
if (!rb_is_class_id(id)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "wrong class variable name %s", name);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2002-02-15 09:14:26 +03:00
|
|
|
rb_cvar_set(klass, id, val, Qfalse);
|
2000-03-23 11:37:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_cv_get(klass, name)
|
|
|
|
VALUE klass;
|
|
|
|
const char *name;
|
|
|
|
{
|
2001-05-02 08:22:21 +04:00
|
|
|
ID id = rb_intern(name);
|
|
|
|
if (!rb_is_class_id(id)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "wrong class variable name %s", name);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
return rb_cvar_get(klass, id);
|
2000-03-23 11:37:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_class_variable(klass, name, val)
|
2000-02-18 09:59:36 +03:00
|
|
|
VALUE klass;
|
|
|
|
const char *name;
|
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
ID id = rb_intern(name);
|
|
|
|
|
2000-03-23 11:37:35 +03:00
|
|
|
if (!rb_is_class_id(id)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "wrong class variable name %s", name);
|
2000-02-18 09:59:36 +03:00
|
|
|
}
|
2002-02-15 09:14:26 +03:00
|
|
|
rb_cvar_set(klass, id, val, Qtrue);
|
2000-02-18 09:59:36 +03:00
|
|
|
}
|
|
|
|
|
2000-09-15 10:00:30 +04:00
|
|
|
static int
|
|
|
|
cv_i(key, value, ary)
|
|
|
|
ID key;
|
|
|
|
VALUE value;
|
|
|
|
VALUE ary;
|
|
|
|
{
|
|
|
|
if (rb_is_class_id(key)) {
|
|
|
|
VALUE kval = rb_str_new2(rb_id2name(key));
|
|
|
|
if (!rb_ary_includes(ary, kval)) {
|
|
|
|
rb_ary_push(ary, kval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_mod_class_variables(obj)
|
|
|
|
VALUE obj;
|
|
|
|
{
|
|
|
|
VALUE ary = rb_ary_new();
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (RCLASS(obj)->iv_tbl) {
|
|
|
|
st_foreach(RCLASS(obj)->iv_tbl, cv_i, ary);
|
|
|
|
}
|
|
|
|
obj = RCLASS(obj)->super;
|
|
|
|
if (!obj) break;
|
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2000-12-08 10:10:38 +03:00
|
|
|
VALUE
|
|
|
|
rb_mod_remove_cvar(mod, name)
|
|
|
|
VALUE mod, name;
|
|
|
|
{
|
|
|
|
ID id = rb_to_id(name);
|
|
|
|
VALUE val;
|
|
|
|
|
|
|
|
if (!rb_is_class_id(id)) {
|
2002-01-16 12:25:59 +03:00
|
|
|
rb_name_error(id, "wrong class variable name %s", rb_id2name(id));
|
2000-12-08 10:10:38 +03:00
|
|
|
}
|
|
|
|
if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4)
|
|
|
|
rb_raise(rb_eSecurityError, "Insecure: can't remove class variable");
|
|
|
|
if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
|
|
|
|
|
|
|
|
if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, &id, &val)) {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
if (rb_cvar_defined(mod, id)) {
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "cannot remove %s for %s",
|
2000-12-08 10:10:38 +03:00
|
|
|
rb_id2name(id), rb_class2name(mod));
|
|
|
|
}
|
2001-07-02 12:46:28 +04:00
|
|
|
rb_name_error(id, "class variable %s not defined for %s",
|
|
|
|
rb_id2name(id), rb_class2name(mod));
|
2000-12-08 10:10:38 +03:00
|
|
|
return Qnil; /* not reached */
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_iv_get(obj, name)
|
|
|
|
VALUE obj;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
ID id = rb_intern(name);
|
|
|
|
|
|
|
|
return rb_ivar_get(obj, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iv_set(obj, name, val)
|
|
|
|
VALUE obj;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE val;
|
|
|
|
{
|
|
|
|
ID id = rb_intern(name);
|
|
|
|
|
|
|
|
return rb_ivar_set(obj, id, val);
|
|
|
|
}
|