Revision: 1494 http://trac.macosforge.org/projects/ruby/changeset/1494 Author: lsansonetti@apple.com Date: 2009-04-26 19:04:56 -0700 (Sun, 26 Apr 2009) Log Message: ----------- added support for incoming/outcoming 'char *' types Modified Paths: -------------- MacRuby/branches/experimental/objc.h MacRuby/branches/experimental/roxor.cpp MacRuby/branches/experimental/spec/macruby/fixtures/method.m MacRuby/branches/experimental/spec/macruby/method_spec.rb Modified: MacRuby/branches/experimental/objc.h =================================================================== --- MacRuby/branches/experimental/objc.h 2009-04-27 01:01:38 UTC (rev 1493) +++ MacRuby/branches/experimental/objc.h 2009-04-27 02:04:56 UTC (rev 1494) @@ -108,6 +108,26 @@ } static inline const char * +SkipTypeModifiers(const char *type) +{ + while (true) { + switch (*type) { + case _C_CONST: + case 'O': /* bycopy */ + case 'n': /* in */ + case 'o': /* out */ + case 'N': /* inout */ + case 'V': /* oneway */ + type++; + break; + + default: + return type; + } + } +} + +static inline const char * SkipFirstType(const char *type) { while (1) { Modified: MacRuby/branches/experimental/roxor.cpp =================================================================== --- MacRuby/branches/experimental/roxor.cpp 2009-04-27 01:01:38 UTC (rev 1493) +++ MacRuby/branches/experimental/roxor.cpp 2009-04-27 02:04:56 UTC (rev 1494) @@ -4934,6 +4934,13 @@ } } +extern "C" +void +rb_vm_rval_to_charptr(VALUE rval, const char **ocval) +{ + *ocval = NIL_P(rval) ? NULL : StringValueCStr(rval); +} + static inline long rval_to_long(VALUE rval) { @@ -5195,6 +5202,8 @@ { const char *func_name = NULL; + type = SkipTypeModifiers(type); + switch (*type) { case _C_ID: case _C_CLASS: @@ -5257,6 +5266,10 @@ func_name = "rb_vm_rval_to_ocsel"; break; + case _C_CHARPTR: + func_name = "rb_vm_rval_to_charptr"; + break; + case _C_STRUCT_B: { rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_struct(type); @@ -5371,6 +5384,13 @@ extern "C" VALUE +rb_vm_charptr_to_rval(const char *ptr) +{ + return ptr == NULL ? Qnil : rb_str_new2(ptr); +} + +extern "C" +VALUE rb_vm_new_struct(VALUE klass, int argc, ...) { assert(argc > 0); @@ -5437,6 +5457,8 @@ { const char *func_name = NULL; + type = SkipTypeModifiers(type); + switch (*type) { case _C_VOID: return nilVal; @@ -5501,6 +5523,10 @@ func_name = "rb_vm_sel_to_rval"; break; + case _C_CHARPTR: + func_name = "rb_vm_charptr_to_rval"; + break; + case _C_STRUCT_B: { rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_struct(type); @@ -5552,6 +5578,8 @@ inline const Type * RoxorCompiler::convert_type(const char *type) { + type = SkipTypeModifiers(type); + switch (*type) { case _C_VOID: return Type::VoidTy; @@ -9316,6 +9344,7 @@ assert(typestr != NULL); // Converting Ruby-FFI types to Objective-C runtime types. + if (strcmp(typestr, "char") == 0) { return "c"; } @@ -9443,7 +9472,7 @@ Check_Type(args, T_ARRAY); const int argc = RARRAY_LEN(args); for (int i = 0; i < argc; i++) { - types.append(convert_ffi_type(ret)); + types.append(convert_ffi_type(RARRAY_AT(args, i))); } rb_vm_c_stub_t *stub = (rb_vm_c_stub_t *)vm_gen_stub(types, argc, false); Modified: MacRuby/branches/experimental/spec/macruby/fixtures/method.m =================================================================== --- MacRuby/branches/experimental/spec/macruby/fixtures/method.m 2009-04-27 01:01:38 UTC (rev 1493) +++ MacRuby/branches/experimental/spec/macruby/fixtures/method.m 2009-04-27 02:04:56 UTC (rev 1494) @@ -151,6 +151,16 @@ return 0; } +- (const char *)methodReturningCharPtr +{ + return "foo"; +} + +- (const char *)methodReturningCharPtr2 +{ + return NULL; +} + - (NSPoint)methodReturningNSPoint { return NSMakePoint(1, 2); @@ -261,6 +271,16 @@ return sel == 0; } +- (BOOL)methodAcceptingCharPtr:(const char *)s +{ + return strcmp(s, "foo") == 0; +} + +- (BOOL)methodAcceptingCharPtr2:(const char *)s +{ + return s == NULL; +} + - (BOOL)methodAcceptingFloat:(float)f { return f > 3.1414 && f < 3.1416; Modified: MacRuby/branches/experimental/spec/macruby/method_spec.rb =================================================================== --- MacRuby/branches/experimental/spec/macruby/method_spec.rb 2009-04-27 01:01:38 UTC (rev 1493) +++ MacRuby/branches/experimental/spec/macruby/method_spec.rb 2009-04-27 02:04:56 UTC (rev 1494) @@ -231,6 +231,13 @@ @o.methodReturningSEL2.should == nil end + it "returning 'char *' returns a String or nil in Ruby" do + @o.methodReturningCharPtr.class.should == String + @o.methodReturningCharPtr.should == 'foo' + @o.methodReturningCharPtr2.class.should == NilClass + @o.methodReturningCharPtr2.should == nil + end + it "returning 'NSPoint' returns an NSPoint boxed object in Ruby" do b = @o.methodReturningNSPoint b.class.should == NSPoint @@ -384,6 +391,21 @@ lambda { @o.methodAcceptingDouble(Object.new) }.should raise_error(TypeError) end + it "accepting a String-compatible object as 'char *' should receive the appropriate data" do + @o.methodAcceptingCharPtr('foo').should == 1 + + o2 = Object.new + def o2.to_str; 'foo' end + + @o.methodAcceptingCharPtr(o2).should == 1 + + lambda { @o.methodAcceptingCharPtr(123) }.should raise_error(TypeError) + lambda { @o.methodAcceptingCharPtr([]) }.should raise_error(TypeError) + lambda { @o.methodAcceptingCharPtr(Object.new) }.should raise_error(TypeError) + + @o.methodAcceptingCharPtr2(nil).should == 1 + end + it "accepting an NSPoint, NSSize, NSRange or NSRect object as 'NSPoint', 'NSSize', 'NSRange' or 'NSRect' should receive the C structure" do p = @o.methodReturningNSPoint @o.methodAcceptingNSPoint(p).should == 1