mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
2f8d3bdc21
modifying buffer is shared. * array.c (ary_make_shared): make an internal buffer of an array to be shared. * array.c (rb_ary_shift): avoid sliding an internal buffer by using shared buffer. * array.c (rb_ary_subseq): avoid copying the buffer. * parse.y (gettable): should freeze __LINE__ string. * io.c (rb_io_puts): old behavoir restored. rationale: a) if you want to call to_s for arrays, you can just call print a, "\n". b) to_s wastes memory if array (and sum of its contents) is huge. c) now any object that has to_ary is treated as an array, using rb_check_convert_type(). * hash.c (rb_hash_initialize): now accepts a block to calculate the default value. [new] * hash.c (rb_hash_aref): call "default" method to get the value corrensponding to the non existing key. * hash.c (rb_hash_default): get the default value based on the block given to 'new'. Now it takes an optinal "key" argument. "default" became the method to get the value for non existing key. Users may override "default" method to change the hash behavior. * hash.c (rb_hash_set_default): clear the flag if a block is given to 'new' * object.c (Init_Object): undef Data.allocate, left Data.new. * ext/curses/curses.c (window_scrollok): use RTEST(). * ext/curses/curses.c (window_idlok): ditto. * ext/curses/curses.c (window_keypad): ditto. * ext/curses/curses.c (window_idlok): idlok() may return void on some platforms; so don't use return value. * ext/curses/curses.c (window_scrollok): ditto for consistency. * ext/curses/curses.c: replace FIX2INT() by typechecking NUM2INT(). * parse.y (str_extend): should not process immature #$x and #@x interpolation, e.g #@#@ etc. * enum.c (enum_sort_by): sort_by does not have to be stable always. * enum.c (enum_sort_by): call qsort directly to gain performance. * util.c (ruby_qsort): ruby_qsort(qs6) is now native thread safe. * error.c (rb_sys_fail): it must be a bug if it's called when errno == 0. * regex.c (WC2MBC1ST): should not pass through > 0x80 number in UTF-8. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1896 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
801 lines
16 KiB
C
801 lines
16 KiB
C
/**********************************************************************
|
|
|
|
class.c -
|
|
|
|
$Author$
|
|
$Date$
|
|
created at: Tue Aug 10 15:05:44 JST 1993
|
|
|
|
Copyright (C) 1993-2001 Yukihiro Matsumoto
|
|
|
|
**********************************************************************/
|
|
|
|
#include "ruby.h"
|
|
#include "rubysig.h"
|
|
#include "node.h"
|
|
#include "st.h"
|
|
#include <ctype.h>
|
|
|
|
extern st_table *rb_class_tbl;
|
|
|
|
VALUE
|
|
rb_class_boot(super)
|
|
VALUE super;
|
|
{
|
|
NEWOBJ(klass, struct RClass);
|
|
OBJSETUP(klass, rb_cClass, T_CLASS);
|
|
|
|
klass->super = super;
|
|
klass->iv_tbl = 0;
|
|
klass->m_tbl = 0; /* safe GC */
|
|
klass->m_tbl = st_init_numtable();
|
|
|
|
OBJ_INFECT(klass, super);
|
|
return (VALUE)klass;
|
|
}
|
|
|
|
VALUE
|
|
rb_class_new(super)
|
|
VALUE super;
|
|
{
|
|
Check_Type(super, T_CLASS);
|
|
if (super == rb_cClass) {
|
|
rb_raise(rb_eTypeError, "can't make subclass of Class");
|
|
}
|
|
if (FL_TEST(super, FL_SINGLETON)) {
|
|
rb_raise(rb_eTypeError, "can't make subclass of virtual class");
|
|
}
|
|
return rb_class_boot(super);
|
|
}
|
|
|
|
static int
|
|
clone_method(mid, body, tbl)
|
|
ID mid;
|
|
NODE *body;
|
|
st_table *tbl;
|
|
{
|
|
st_insert(tbl, mid, NEW_METHOD(body->nd_body, body->nd_noex));
|
|
return ST_CONTINUE;
|
|
}
|
|
|
|
VALUE
|
|
rb_mod_clone(module)
|
|
VALUE module;
|
|
{
|
|
VALUE clone = rb_obj_clone(module);
|
|
|
|
RCLASS(clone)->super = RCLASS(module)->super;
|
|
if (RCLASS(module)->iv_tbl) {
|
|
ID id;
|
|
|
|
RCLASS(clone)->iv_tbl = st_copy(RCLASS(module)->iv_tbl);
|
|
id = rb_intern("__classpath__");
|
|
st_delete(RCLASS(clone)->iv_tbl, &id, 0);
|
|
id = rb_intern("__classid__");
|
|
st_delete(RCLASS(clone)->iv_tbl, &id, 0);
|
|
}
|
|
if (RCLASS(module)->m_tbl) {
|
|
RCLASS(clone)->m_tbl = st_init_numtable();
|
|
st_foreach(RCLASS(module)->m_tbl, clone_method, RCLASS(clone)->m_tbl);
|
|
}
|
|
|
|
return clone;
|
|
}
|
|
|
|
VALUE
|
|
rb_mod_dup(mod)
|
|
VALUE mod;
|
|
{
|
|
VALUE dup = rb_mod_clone(mod);
|
|
|
|
DUPSETUP(dup, mod);
|
|
if (FL_TEST(mod, FL_SINGLETON)) {
|
|
FL_SET(dup, FL_SINGLETON);
|
|
}
|
|
return dup;
|
|
}
|
|
|
|
VALUE
|
|
rb_singleton_class_new(super)
|
|
VALUE super;
|
|
{
|
|
VALUE klass = rb_class_boot(super);
|
|
|
|
FL_SET(klass, FL_SINGLETON);
|
|
return klass;
|
|
}
|
|
|
|
VALUE
|
|
rb_singleton_class_clone(klass)
|
|
VALUE klass;
|
|
{
|
|
if (!FL_TEST(klass, FL_SINGLETON))
|
|
return klass;
|
|
else {
|
|
/* copy singleton(unnamed) class */
|
|
NEWOBJ(clone, struct RClass);
|
|
CLONESETUP(clone, klass);
|
|
|
|
clone->super = RCLASS(klass)->super;
|
|
clone->iv_tbl = 0;
|
|
clone->m_tbl = 0;
|
|
if (RCLASS(klass)->iv_tbl) {
|
|
clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
|
|
}
|
|
clone->m_tbl = st_init_numtable();
|
|
st_foreach(RCLASS(klass)->m_tbl, clone_method, clone->m_tbl);
|
|
FL_SET(clone, FL_SINGLETON);
|
|
return (VALUE)clone;
|
|
}
|
|
}
|
|
|
|
void
|
|
rb_singleton_class_attached(klass, obj)
|
|
VALUE klass, obj;
|
|
{
|
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
|
if (!RCLASS(klass)->iv_tbl) {
|
|
RCLASS(klass)->iv_tbl = st_init_numtable();
|
|
}
|
|
st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj);
|
|
}
|
|
}
|
|
|
|
VALUE
|
|
rb_define_class_id(id, super)
|
|
ID id;
|
|
VALUE super;
|
|
{
|
|
VALUE klass;
|
|
|
|
if (!super) super = rb_cObject;
|
|
klass = rb_class_new(super);
|
|
rb_name_class(klass, id);
|
|
/* make metaclass */
|
|
RBASIC(klass)->klass = rb_singleton_class_new(RBASIC(super)->klass);
|
|
rb_singleton_class_attached(RBASIC(klass)->klass, klass);
|
|
rb_funcall(super, rb_intern("inherited"), 1, klass);
|
|
|
|
return klass;
|
|
}
|
|
|
|
VALUE
|
|
rb_define_class(name, super)
|
|
const char *name;
|
|
VALUE super;
|
|
{
|
|
VALUE klass;
|
|
ID id;
|
|
|
|
id = rb_intern(name);
|
|
if (rb_const_defined(rb_cObject, id)) {
|
|
klass = rb_const_get(rb_cObject, id);
|
|
rb_name_error(id, "%s is already defined", name);
|
|
}
|
|
klass = rb_define_class_id(id, super);
|
|
st_add_direct(rb_class_tbl, id, klass);
|
|
|
|
return klass;
|
|
}
|
|
|
|
VALUE
|
|
rb_define_class_under(outer, name, super)
|
|
VALUE outer;
|
|
const char *name;
|
|
VALUE super;
|
|
{
|
|
VALUE klass;
|
|
ID id;
|
|
|
|
id = rb_intern(name);
|
|
if (rb_const_defined_at(outer, id)) {
|
|
klass = rb_const_get(outer, id);
|
|
rb_name_error(id, "%s is already defined", name);
|
|
}
|
|
klass = rb_define_class_id(id, super);
|
|
rb_const_set(outer, id, klass);
|
|
rb_set_class_path(klass, outer, name);
|
|
|
|
return klass;
|
|
}
|
|
|
|
VALUE
|
|
rb_module_new()
|
|
{
|
|
NEWOBJ(mdl, struct RClass);
|
|
OBJSETUP(mdl, rb_cModule, T_MODULE);
|
|
|
|
mdl->super = 0;
|
|
mdl->iv_tbl = 0;
|
|
mdl->m_tbl = 0;
|
|
mdl->m_tbl = st_init_numtable();
|
|
|
|
return (VALUE)mdl;
|
|
}
|
|
|
|
VALUE
|
|
rb_define_module_id(id)
|
|
ID id;
|
|
{
|
|
VALUE mdl;
|
|
|
|
mdl = rb_module_new();
|
|
rb_name_class(mdl, id);
|
|
|
|
return mdl;
|
|
}
|
|
|
|
VALUE
|
|
rb_define_module(name)
|
|
const char *name;
|
|
{
|
|
VALUE module;
|
|
ID id;
|
|
|
|
id = rb_intern(name);
|
|
if (rb_const_defined(rb_cObject, id)) {
|
|
module = rb_const_get(rb_cObject, id);
|
|
if (TYPE(module) == T_MODULE)
|
|
return module;
|
|
rb_raise(rb_eTypeError, "%s is not a module", rb_class2name(CLASS_OF(module)));
|
|
}
|
|
module = rb_define_module_id(id);
|
|
st_add_direct(rb_class_tbl, id, module);
|
|
|
|
return module;
|
|
}
|
|
|
|
VALUE
|
|
rb_define_module_under(outer, name)
|
|
VALUE outer;
|
|
const char *name;
|
|
{
|
|
VALUE module;
|
|
ID id;
|
|
|
|
id = rb_intern(name);
|
|
if (rb_const_defined(outer, id)) {
|
|
module = rb_const_get(rb_cObject, id);
|
|
if (TYPE(module) == T_MODULE)
|
|
return module;
|
|
rb_raise(rb_eTypeError, "%s::%s is not a module",
|
|
rb_class2name(outer), rb_class2name(CLASS_OF(module)));
|
|
}
|
|
module = rb_define_module_id(id);
|
|
rb_const_set(outer, id, module);
|
|
rb_set_class_path(module, outer, name);
|
|
|
|
return module;
|
|
}
|
|
|
|
static VALUE
|
|
include_class_new(module, super)
|
|
VALUE module, super;
|
|
{
|
|
NEWOBJ(klass, struct RClass);
|
|
OBJSETUP(klass, rb_cClass, T_ICLASS);
|
|
|
|
if (!RCLASS(module)->iv_tbl) {
|
|
RCLASS(module)->iv_tbl = st_init_numtable();
|
|
}
|
|
klass->iv_tbl = RCLASS(module)->iv_tbl;
|
|
klass->m_tbl = RCLASS(module)->m_tbl;
|
|
klass->super = super;
|
|
if (TYPE(module) == T_ICLASS) {
|
|
RBASIC(klass)->klass = RBASIC(module)->klass;
|
|
}
|
|
else {
|
|
RBASIC(klass)->klass = module;
|
|
}
|
|
OBJ_INFECT(klass, module);
|
|
OBJ_INFECT(klass, super);
|
|
|
|
return (VALUE)klass;
|
|
}
|
|
|
|
void
|
|
rb_include_module(klass, module)
|
|
VALUE klass, module;
|
|
{
|
|
VALUE p, c;
|
|
int changed = 0;
|
|
|
|
rb_frozen_class_p(klass);
|
|
if (!OBJ_TAINTED(klass)) {
|
|
rb_secure(4);
|
|
}
|
|
|
|
if (NIL_P(module)) return;
|
|
if (klass == module) return;
|
|
|
|
switch (TYPE(module)) {
|
|
case T_MODULE:
|
|
case T_CLASS:
|
|
case T_ICLASS:
|
|
break;
|
|
default:
|
|
Check_Type(module, T_MODULE);
|
|
}
|
|
|
|
OBJ_INFECT(klass, module);
|
|
c = klass;
|
|
while (module) {
|
|
/* ignore if the module included already in superclasses */
|
|
for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) {
|
|
if (BUILTIN_TYPE(p) == T_ICLASS &&
|
|
RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) {
|
|
goto skip;
|
|
}
|
|
}
|
|
RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);
|
|
c = RCLASS(c)->super;
|
|
changed = 1;
|
|
skip:
|
|
module = RCLASS(module)->super;
|
|
}
|
|
if (changed) rb_clear_cache();
|
|
}
|
|
|
|
VALUE
|
|
rb_mod_included_modules(mod)
|
|
VALUE mod;
|
|
{
|
|
VALUE ary = rb_ary_new();
|
|
VALUE p;
|
|
|
|
for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) {
|
|
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
|
rb_ary_push(ary, RBASIC(p)->klass);
|
|
}
|
|
}
|
|
return ary;
|
|
}
|
|
|
|
VALUE
|
|
rb_mod_include_p(mod, mod2)
|
|
VALUE mod;
|
|
VALUE mod2;
|
|
{
|
|
VALUE p;
|
|
|
|
Check_Type(mod2, T_MODULE);
|
|
for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) {
|
|
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
|
if (RBASIC(p)->klass == mod2) return Qtrue;
|
|
}
|
|
}
|
|
return Qfalse;
|
|
}
|
|
|
|
VALUE
|
|
rb_mod_ancestors(mod)
|
|
VALUE mod;
|
|
{
|
|
VALUE ary = rb_ary_new();
|
|
VALUE p;
|
|
|
|
for (p = mod; p; p = RCLASS(p)->super) {
|
|
if (FL_TEST(p, FL_SINGLETON))
|
|
continue;
|
|
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
|
rb_ary_push(ary, RBASIC(p)->klass);
|
|
}
|
|
else {
|
|
rb_ary_push(ary, p);
|
|
}
|
|
}
|
|
return ary;
|
|
}
|
|
|
|
static int
|
|
ins_methods_i(key, body, ary)
|
|
ID key;
|
|
NODE *body;
|
|
VALUE ary;
|
|
{
|
|
if ((body->nd_noex&(NOEX_PRIVATE|NOEX_PROTECTED)) == 0) {
|
|
VALUE name = rb_str_new2(rb_id2name(key));
|
|
|
|
if (!rb_ary_includes(ary, name)) {
|
|
if (!body->nd_body) {
|
|
rb_ary_push(ary, Qnil);
|
|
}
|
|
rb_ary_push(ary, name);
|
|
}
|
|
}
|
|
else if (body->nd_body && nd_type(body->nd_body) == NODE_ZSUPER) {
|
|
rb_ary_push(ary, Qnil);
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
|
}
|
|
return ST_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
ins_methods_prot_i(key, body, ary)
|
|
ID key;
|
|
NODE *body;
|
|
VALUE ary;
|
|
{
|
|
if (!body->nd_body) {
|
|
rb_ary_push(ary, Qnil);
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
|
}
|
|
else if (body->nd_noex & NOEX_PROTECTED) {
|
|
VALUE name = rb_str_new2(rb_id2name(key));
|
|
|
|
if (!rb_ary_includes(ary, name)) {
|
|
rb_ary_push(ary, name);
|
|
}
|
|
}
|
|
else if (nd_type(body->nd_body) == NODE_ZSUPER) {
|
|
rb_ary_push(ary, Qnil);
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
|
}
|
|
return ST_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
ins_methods_priv_i(key, body, ary)
|
|
ID key;
|
|
NODE *body;
|
|
VALUE ary;
|
|
{
|
|
if (!body->nd_body) {
|
|
rb_ary_push(ary, Qnil);
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
|
}
|
|
else if (body->nd_noex & NOEX_PRIVATE) {
|
|
VALUE name = rb_str_new2(rb_id2name(key));
|
|
|
|
if (!rb_ary_includes(ary, name)) {
|
|
rb_ary_push(ary, name);
|
|
}
|
|
}
|
|
else if (nd_type(body->nd_body) == NODE_ZSUPER) {
|
|
rb_ary_push(ary, Qnil);
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(key)));
|
|
}
|
|
return ST_CONTINUE;
|
|
}
|
|
|
|
static VALUE
|
|
method_list(mod, option, func)
|
|
VALUE mod;
|
|
int option;
|
|
int (*func)();
|
|
{
|
|
VALUE ary;
|
|
VALUE klass;
|
|
VALUE *p, *q, *pend;
|
|
|
|
ary = rb_ary_new();
|
|
for (klass = mod; klass; klass = RCLASS(klass)->super) {
|
|
st_foreach(RCLASS(klass)->m_tbl, func, ary);
|
|
if (!option) break;
|
|
}
|
|
p = q = RARRAY(ary)->ptr; pend = p + RARRAY(ary)->len;
|
|
while (p < pend) {
|
|
if (*p == Qnil) {
|
|
p+=2;
|
|
continue;
|
|
}
|
|
*q++ = *p++;
|
|
}
|
|
RARRAY(ary)->len = q - RARRAY(ary)->ptr;
|
|
return ary;
|
|
}
|
|
|
|
VALUE
|
|
rb_class_instance_methods(argc, argv, mod)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE mod;
|
|
{
|
|
VALUE option;
|
|
|
|
rb_scan_args(argc, argv, "01", &option);
|
|
return method_list(mod, RTEST(option), ins_methods_i);
|
|
}
|
|
|
|
VALUE
|
|
rb_class_protected_instance_methods(argc, argv, mod)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE mod;
|
|
{
|
|
VALUE option;
|
|
|
|
rb_scan_args(argc, argv, "01", &option);
|
|
return method_list(mod, RTEST(option), ins_methods_prot_i);
|
|
}
|
|
|
|
VALUE
|
|
rb_class_private_instance_methods(argc, argv, mod)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE mod;
|
|
{
|
|
VALUE option;
|
|
|
|
rb_scan_args(argc, argv, "01", &option);
|
|
return method_list(mod, RTEST(option), ins_methods_priv_i);
|
|
}
|
|
|
|
VALUE
|
|
rb_obj_singleton_methods(argc, argv, obj)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE obj;
|
|
{
|
|
VALUE all;
|
|
VALUE ary;
|
|
VALUE klass;
|
|
VALUE *p, *q, *pend;
|
|
|
|
rb_scan_args(argc, argv, "01", &all);
|
|
ary = rb_ary_new();
|
|
klass = CLASS_OF(obj);
|
|
while (klass && FL_TEST(klass, FL_SINGLETON)) {
|
|
st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary);
|
|
klass = RCLASS(klass)->super;
|
|
}
|
|
if (RTEST(all)) {
|
|
while (klass && TYPE(klass) == T_ICLASS) {
|
|
st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary);
|
|
klass = RCLASS(klass)->super;
|
|
}
|
|
}
|
|
p = q = RARRAY(ary)->ptr; pend = p + RARRAY(ary)->len;
|
|
while (p < pend) {
|
|
if (*p == Qnil) {
|
|
p+=2;
|
|
continue;
|
|
}
|
|
*q++ = *p++;
|
|
}
|
|
RARRAY(ary)->len = q - RARRAY(ary)->ptr;
|
|
|
|
return ary;
|
|
}
|
|
|
|
void
|
|
rb_define_method_id(klass, name, func, argc)
|
|
VALUE klass;
|
|
ID name;
|
|
VALUE (*func)();
|
|
int argc;
|
|
{
|
|
rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC|NOEX_CFUNC);
|
|
}
|
|
|
|
void
|
|
rb_define_method(klass, name, func, argc)
|
|
VALUE klass;
|
|
const char *name;
|
|
VALUE (*func)();
|
|
int argc;
|
|
{
|
|
ID id = rb_intern(name);
|
|
|
|
rb_add_method(klass, id, NEW_CFUNC(func, argc),
|
|
((name[0] == 'i' && id == rb_intern("initialize"))?
|
|
NOEX_PRIVATE:NOEX_PUBLIC)|NOEX_CFUNC);
|
|
}
|
|
|
|
void
|
|
rb_define_protected_method(klass, name, func, argc)
|
|
VALUE klass;
|
|
const char *name;
|
|
VALUE (*func)();
|
|
int argc;
|
|
{
|
|
rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc),
|
|
NOEX_PROTECTED|NOEX_CFUNC);
|
|
}
|
|
|
|
void
|
|
rb_define_private_method(klass, name, func, argc)
|
|
VALUE klass;
|
|
const char *name;
|
|
VALUE (*func)();
|
|
int argc;
|
|
{
|
|
rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc),
|
|
NOEX_PRIVATE|NOEX_CFUNC);
|
|
}
|
|
|
|
void
|
|
rb_undef_method(klass, name)
|
|
VALUE klass;
|
|
const char *name;
|
|
{
|
|
rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF);
|
|
}
|
|
|
|
#define SPECIAL_SINGLETON(x,c) if (obj == (x)) {\
|
|
if (!FL_TEST(c, FL_SINGLETON)) {\
|
|
c = rb_singleton_class_new(c);\
|
|
rb_singleton_class_attached(c,obj);\
|
|
}\
|
|
return c;\
|
|
}
|
|
|
|
VALUE
|
|
rb_singleton_class(obj)
|
|
VALUE obj;
|
|
{
|
|
VALUE klass;
|
|
|
|
if (FIXNUM_P(obj) || SYMBOL_P(obj)) {
|
|
rb_raise(rb_eTypeError, "can't define singleton");
|
|
}
|
|
if (rb_special_const_p(obj)) {
|
|
SPECIAL_SINGLETON(Qnil, rb_cNilClass);
|
|
SPECIAL_SINGLETON(Qfalse, rb_cFalseClass);
|
|
SPECIAL_SINGLETON(Qtrue, rb_cTrueClass);
|
|
rb_bug("unknown immediate %d", obj);
|
|
}
|
|
|
|
DEFER_INTS;
|
|
if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON)) {
|
|
klass = RBASIC(obj)->klass;
|
|
}
|
|
else {
|
|
klass = rb_singleton_class_new(RBASIC(obj)->klass);
|
|
RBASIC(obj)->klass = klass;
|
|
rb_singleton_class_attached(klass, obj);
|
|
}
|
|
if (OBJ_TAINTED(obj)) {
|
|
OBJ_TAINT(klass);
|
|
}
|
|
else {
|
|
FL_UNSET(klass, FL_TAINT);
|
|
}
|
|
if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass);
|
|
ALLOW_INTS;
|
|
|
|
return klass;
|
|
}
|
|
|
|
void
|
|
rb_define_singleton_method(obj, name, func, argc)
|
|
VALUE obj;
|
|
const char *name;
|
|
VALUE (*func)();
|
|
int argc;
|
|
{
|
|
rb_define_method(rb_singleton_class(obj), name, func, argc);
|
|
}
|
|
|
|
void
|
|
rb_define_module_function(module, name, func, argc)
|
|
VALUE module;
|
|
const char *name;
|
|
VALUE (*func)();
|
|
int argc;
|
|
{
|
|
rb_define_private_method(module, name, func, argc);
|
|
rb_define_singleton_method(module, name, func, argc);
|
|
}
|
|
|
|
void
|
|
rb_define_global_function(name, func, argc)
|
|
const char *name;
|
|
VALUE (*func)();
|
|
int argc;
|
|
{
|
|
rb_define_module_function(rb_mKernel, name, func, argc);
|
|
}
|
|
|
|
void
|
|
rb_define_alias(klass, name1, name2)
|
|
VALUE klass;
|
|
const char *name1, *name2;
|
|
{
|
|
rb_alias(klass, rb_intern(name1), rb_intern(name2));
|
|
}
|
|
|
|
void
|
|
rb_define_attr(klass, name, read, write)
|
|
VALUE klass;
|
|
const char *name;
|
|
int read, write;
|
|
{
|
|
rb_attr(klass, rb_intern(name), read, write, Qfalse);
|
|
}
|
|
|
|
#ifdef HAVE_STDARG_PROTOTYPES
|
|
#include <stdarg.h>
|
|
#define va_init_list(a,b) va_start(a,b)
|
|
#else
|
|
#include <varargs.h>
|
|
#define va_init_list(a,b) va_start(a)
|
|
#endif
|
|
|
|
int
|
|
#ifdef HAVE_STDARG_PROTOTYPES
|
|
rb_scan_args(int argc, VALUE *argv, const char *fmt, ...)
|
|
#else
|
|
rb_scan_args(argc, argv, fmt, va_alist)
|
|
int argc;
|
|
VALUE *argv;
|
|
const char *fmt;
|
|
va_dcl
|
|
#endif
|
|
{
|
|
int n, i = 0;
|
|
const char *p = fmt;
|
|
VALUE *var;
|
|
va_list vargs;
|
|
|
|
va_init_list(vargs, fmt);
|
|
|
|
if (*p == '*') goto rest_arg;
|
|
|
|
if (ISDIGIT(*p)) {
|
|
n = *p - '0';
|
|
if (n > argc)
|
|
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n);
|
|
for (i=0; i<n; i++) {
|
|
var = va_arg(vargs, VALUE*);
|
|
if (var) *var = argv[i];
|
|
}
|
|
p++;
|
|
}
|
|
else {
|
|
goto error;
|
|
}
|
|
|
|
if (ISDIGIT(*p)) {
|
|
n = i + *p - '0';
|
|
for (; i<n; i++) {
|
|
var = va_arg(vargs, VALUE*);
|
|
if (argc > i) {
|
|
if (var) *var = argv[i];
|
|
}
|
|
else {
|
|
if (var) *var = Qnil;
|
|
}
|
|
}
|
|
p++;
|
|
}
|
|
|
|
if(*p == '*') {
|
|
rest_arg:
|
|
var = va_arg(vargs, VALUE*);
|
|
if (argc > i) {
|
|
if (var) *var = rb_ary_new4(argc-i, argv+i);
|
|
i = argc;
|
|
}
|
|
else {
|
|
if (var) *var = rb_ary_new();
|
|
}
|
|
p++;
|
|
}
|
|
|
|
if (*p == '&') {
|
|
var = va_arg(vargs, VALUE*);
|
|
if (rb_block_given_p()) {
|
|
*var = rb_f_lambda();
|
|
}
|
|
else {
|
|
*var = Qnil;
|
|
}
|
|
p++;
|
|
}
|
|
va_end(vargs);
|
|
|
|
if (*p != '\0') {
|
|
goto error;
|
|
}
|
|
|
|
if (argc > i) {
|
|
rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, i);
|
|
}
|
|
|
|
return argc;
|
|
|
|
error:
|
|
rb_fatal("bad scan arg format: %s", fmt);
|
|
return 0;
|
|
}
|