/* * Copyright (C) 1993-2003 Yukihiro Matsumoto * Copyright (C) 2000 Network Applied Communication Laboratory, Inc. * Copyright (C) 2000 Information-technology Promotion Agency, Japan * Copyright (C) 2010 Tim Felgentreff * * This file is part of jruby-cext. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 3 for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this work. If not, see . */ #include #include #ifdef __sun #include #endif #include "jruby.h" #include "ruby.h" #include "JLocalEnv.h" #include "Handle.h" using namespace jruby; extern "C" bool jruby_obj_frozen(VALUE obj) { return callMethod(obj, "frozen?", 0) == Qtrue; } static VALUE convert_type(VALUE val, const char* type_name, const char* method, int raise) { ID m = rb_intern(method); if (!rb_respond_to(val, m)) { if (raise) { rb_raise(rb_eTypeError, "can't convert %s into %s", NIL_P(val) ? "nil" : val == Qtrue ? "true" : val == Qfalse ? "false" : rb_obj_classname(val), type_name); } else { return Qnil; } } return rb_funcall(val, m, 0); } extern "C" VALUE rb_obj_freeze(VALUE obj) { return callMethodA(obj, "freeze", 0, NULL); } extern "C" char* rb_obj_classname(VALUE obj) { return rb_class2name(rb_class_of(obj)); } extern "C" void rb_extend_object(VALUE object, VALUE module) { callMethod(object, "extend", 1, module); } extern "C" int rb_respond_to(VALUE obj, ID id) { JLocalEnv env; jboolean ret = env->CallBooleanMethod(valueToObject(env, obj), IRubyObject_respondsTo_method, idToString(env, id)); checkExceptions(env); return ret != JNI_FALSE; } extern "C" int rb_obj_respond_to(VALUE obj, ID id, int include_private) { return RTEST(callMethod(obj, "respond_to?", 2, ID2SYM(id), include_private ? Qtrue : Qfalse)); } extern "C" VALUE rb_convert_type(VALUE val, int type, const char* type_name, const char* method) { VALUE v; if (TYPE(val) == type) { return val; } v = convert_type(val, type_name, method, Qtrue); if (TYPE(v) != type) { rb_raise(rb_eTypeError, "%s#%s should return %s", rb_obj_classname(val), method, type_name); } return v; } extern "C" VALUE rb_check_convert_type(VALUE val, int type, const char* type_name, const char* method) { if (TYPE(val) == type) { return val; } return convert_type(val, type_name, method, 0); } extern "C" VALUE rb_check_to_integer(VALUE object_handle, const char *method_name) { if(FIXNUM_P(object_handle)) { return object_handle; } VALUE result = rb_check_convert_type(object_handle, 0, "Integer", method_name); if(rb_obj_is_kind_of(result, rb_cInteger)) { return result; } return Qnil; } extern "C" VALUE rb_iv_get(VALUE obj, const char* name) { JLocalEnv env; char var_name[strlen(name) + 2]; (name[0] != '@') ? strcpy(var_name, "@")[0] : var_name[0] = '\0'; strcat(var_name, name); jobject retval = env->CallObjectMethod(valueToObject(env, obj), RubyBasicObject_getInstanceVariable_method, env->NewStringUTF(var_name)); checkExceptions(env); return objectToValue(env, retval); } extern "C" VALUE rb_iv_set(VALUE obj, const char* name, VALUE value) { JLocalEnv env; char var_name[strlen(name) + 2]; (name[0] != '@') ? strcpy(var_name, "@")[0] : var_name[0] = '\0'; strcat(var_name, name); jobject retval = env->CallObjectMethod(valueToObject(env, obj), RubyBasicObject_setInstanceVariable_method, env->NewStringUTF(var_name), valueToObject(env, value)); checkExceptions(env); return objectToValue(env, retval); } extern "C" VALUE rb_ivar_get(VALUE obj, ID ivar_name) { return rb_iv_get(obj, rb_id2name(ivar_name)); } extern "C" VALUE rb_ivar_set(VALUE obj, ID ivar_name, VALUE value) { return rb_iv_set(obj, rb_id2name(ivar_name), value); } extern "C" VALUE rb_ivar_defined(VALUE obj, ID ivar) { JLocalEnv env; const char* name = rb_id2name(ivar); char var_name[strlen(name) + 2]; (name[0] != '@') ? strcpy(var_name, "@")[0] : var_name[0] = '\0'; strcat(var_name, name); jboolean retval = env->CallBooleanMethod(valueToObject(env, obj), RubyBasicObject_hasInstanceVariable_method, env->NewStringUTF(var_name)); checkExceptions(env); return (retval == JNI_TRUE) ? Qtrue : Qfalse; } extern "C" void rb_obj_call_init(VALUE recv, int arg_count, VALUE* args) { callMethodANonConst(recv, "initialize", arg_count, args); } extern "C" VALUE rb_obj_is_kind_of(VALUE obj, VALUE module) { return callMethod(obj, "kind_of?", 1, module); } extern "C" VALUE rb_obj_is_instance_of(VALUE obj, VALUE klass) { return callMethodA(obj, "instance_of?", 1, &klass); } extern "C" VALUE rb_obj_taint(VALUE obj) { return callMethodA(obj, "taint", 0, NULL); } extern "C" VALUE rb_obj_tainted(VALUE obj) { return callMethodA(obj, "tainted?", 0, NULL); } extern "C" VALUE rb_attr_get(VALUE obj, ID id) { return callMethod(obj, "instance_variable_get", 1, ID2SYM(id)); } extern "C" VALUE rb_obj_as_string(VALUE obj) { VALUE str; if (TYPE(obj) == T_STRING) { return obj; } str = callMethodA(obj, "to_s", 0, NULL); if (TYPE(str) != T_STRING) { return rb_any_to_s(obj); } if (OBJ_TAINTED(obj)) { OBJ_TAINT(str); } return str; } extern "C" VALUE rb_to_integer(VALUE val, const char *method) { VALUE v; if (FIXNUM_P(val)) return val; if (TYPE(val) == T_BIGNUM) return val; v = convert_type(val, "Integer", method, 1); if (!rb_obj_is_kind_of(v, rb_cInteger)) { const char *cname = rb_obj_classname(val); rb_raise(rb_eTypeError, "can't convert %s to Integer (%s#%s gives %s)", cname, cname, method, rb_obj_classname(v)); } return v; } extern "C" VALUE rb_inspect(VALUE obj) { return rb_obj_as_string(callMethodA(obj, "inspect", 0, 0)); } extern "C" VALUE rb_any_to_s(VALUE obj) { char* buf; int len = 128, buflen; do { buf = (char *) alloca(buflen = len); len = snprintf(buf, buflen, "#<%s:%p>", rb_obj_classname(obj), (void *) obj); } while (len >= buflen); return rb_str_new_cstr(buf); } extern "C" void rb_check_frozen(VALUE obj) { if (OBJ_FROZEN(obj)) { rb_raise(is1_9() ? rb_eRuntimeError : rb_eTypeError, "can't modify frozen %s", rb_obj_classname(obj)); } } extern "C" VALUE rb_singleton_class(VALUE obj) { JLocalEnv env; jmethodID IRubyObject_getSingletonClass_method = getCachedMethodID(env, IRubyObject_class, "getSingletonClass", "()Lorg/jruby/RubyClass;"); jobject singleton = env->CallObjectMethod(valueToObject(env, obj), IRubyObject_getSingletonClass_method); checkExceptions(env); return objectToValue(env, singleton); } extern "C" VALUE rb_class_inherited_p(VALUE mod, VALUE arg) { if (TYPE(arg) != T_MODULE && TYPE(arg) != T_CLASS) { rb_raise(rb_eTypeError, "compared with non class/module"); } return callMethodA(mod, "<=", 1, &arg); } extern "C" VALUE rb_class_superclass(VALUE klass) { return callMethodA(klass, "superclass", 0, NULL); } extern "C" VALUE rb_obj_dup(VALUE obj) { return callMethod(obj, "dup", 0); } extern "C" VALUE rb_obj_clone(VALUE obj) { return callMethod(obj, "clone", 0); } extern "C" VALUE rb_obj_id(VALUE obj) { return callMethod(obj, "object_id", 0); } extern "C" VALUE rb_equal(VALUE obj, VALUE other) { return RTEST(callMethod(obj, "==", 1, other)) ? Qtrue : Qfalse; } extern "C" int rb_eql(VALUE obj1, VALUE obj2) { return RTEST(callMethodA(obj1, "eql?", 1, &obj2)); } extern "C" void jruby_infect(VALUE object1, VALUE object2) { if (OBJ_TAINTED(object1)) { JLocalEnv env; jmethodID mid = getCachedMethodID(env, IRubyObject_class, "infectBy", "(Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;"); env->CallObjectMethod(valueToObject(env, object2), mid, object1); checkExceptions(env); } } extern "C" VALUE rb_hash(VALUE obj) { VALUE hash = callMethod(obj, "hash", 0); return convert_type(hash, "Fixnum", "to_int", true); }