[macruby-changes] [136] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Apr 11 18:10:17 PDT 2008


Revision: 136
          http://trac.macosforge.org/projects/ruby/changeset/136
Author:   lsansonetti at apple.com
Date:     2008-04-11 18:10:16 -0700 (Fri, 11 Apr 2008)

Log Message:
-----------
new experimental String implementation, based on CFString (warning: this breaks trunk, for now)

Modified Paths:
--------------
    MacRuby/trunk/class.c
    MacRuby/trunk/encoding.c
    MacRuby/trunk/gc.c
    MacRuby/trunk/hash.c
    MacRuby/trunk/include/ruby/ruby.h
    MacRuby/trunk/io.c
    MacRuby/trunk/objc.m
    MacRuby/trunk/object.c
    MacRuby/trunk/parse.y
    MacRuby/trunk/sample/test.rb
    MacRuby/trunk/sprintf.c
    MacRuby/trunk/string.c
    MacRuby/trunk/variable.c
    MacRuby/trunk/vm.c

Modified: MacRuby/trunk/class.c
===================================================================
--- MacRuby/trunk/class.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/class.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -44,6 +44,7 @@
 
     assert(ocklass != NULL);
     assert(class_isMetaClass(ocklass) == 0);
+    assert(rb_objc_class_tbl != NULL);
 
     if (st_lookup(rb_objc_class_tbl, (st_data_t)ocklass, (st_data_t *)&rbklass))
 	return rbklass;

Modified: MacRuby/trunk/encoding.c
===================================================================
--- MacRuby/trunk/encoding.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/encoding.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -540,7 +540,7 @@
 enc_capable(VALUE obj)
 {
     if (SPECIAL_CONST_P(obj)) return Qfalse;
-    switch (BUILTIN_TYPE(obj)) {
+    switch (/*BUILTIN_*/TYPE(obj)) {
       case T_STRING:
       case T_REGEXP:
       case T_FILE:

Modified: MacRuby/trunk/gc.c
===================================================================
--- MacRuby/trunk/gc.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/gc.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -163,9 +163,9 @@
 	struct RObject object;
 	struct RClass  klass;
 	struct RFloat  flonum;
-	struct RString string;
 	struct RRegexp regexp;
 #if !WITH_OBJC
+	struct RString string;
 	struct RArray  array;
 	struct RHash   hash;
 #endif

Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/hash.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -1657,7 +1657,7 @@
  *
  */
 
-static VALUE
+VALUE
 rb_hash_values(VALUE hash)
 {
     VALUE ary;

Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/include/ruby/ruby.h	2008-04-12 01:10:16 UTC (rev 136)
@@ -484,6 +484,7 @@
 
 #define ELTS_SHARED FL_USER2
 
+#if !WITH_OBJC
 #define RSTRING_EMBED_LEN_MAX ((sizeof(VALUE)*3)/sizeof(char)-1)
 struct RString {
     struct RBasic basic;
@@ -499,18 +500,35 @@
 	char ary[RSTRING_EMBED_LEN_MAX];
     } as;
 };
-#define RSTRING_NOEMBED FL_USER1
-#define RSTRING_EMBED_LEN_MASK (FL_USER2|FL_USER3|FL_USER4|FL_USER5|FL_USER6)
-#define RSTRING_EMBED_LEN_SHIFT (FL_USHIFT+2)
-#define RSTRING_LEN(str) \
+# define RSTRING_NOEMBED FL_USER1
+# define RSTRING_EMBED_LEN_MASK (FL_USER2|FL_USER3|FL_USER4|FL_USER5|FL_USER6)
+# define RSTRING_EMBED_LEN_SHIFT (FL_USHIFT+2)
+# define RSTRING_LEN(str) \
     (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
      (long)((RBASIC(str)->flags >> RSTRING_EMBED_LEN_SHIFT) & \
             (RSTRING_EMBED_LEN_MASK >> RSTRING_EMBED_LEN_SHIFT)) : \
      RSTRING(str)->as.heap.len)
-#define RSTRING_PTR(str) \
+# define RSTRING_PTR(str) \
     (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
      RSTRING(str)->as.ary : \
      RSTRING(str)->as.heap.ptr)
+#else
+/* IMPORTANT: try to avoid using RSTRING_PTR/RSTRING_LEN if necessary, 
+ * because they can be slow operations in non-8bit strings. 
+ * If you modify RSTRING_PTR, you need to call RSTRING_SYNC in order to
+ * synchronize its content with the real string storage.
+ * RSTRING_PTR/RSTRING_LEN deal with bytes. If you want to access a C string
+ * pointer, please use RSTRING_CPTR instead which is faster.
+ */
+char *rb_str_byteptr(VALUE);
+long rb_str_bytelen(VALUE);
+void rb_str_bytesync(VALUE);
+# define RSTRING_PTR(str) (rb_str_byteptr((VALUE)str))
+# define RSTRING_LEN(str) (rb_str_bytelen((VALUE)str))
+# define RSTRING_SYNC(str) (rb_str_bytesync((VALUE)str))
+# define RSTRING_CPTR(str) (CFStringGetCStringPtr((CFStringRef)str, 0))
+# define RSTRING_CLEN(str) (CFStringGetLength((CFStringRef)str))
+#endif
 #define RSTRING_END(str) (RSTRING_PTR(str)+RSTRING_LEN(str))
 
 #if !WITH_OBJC
@@ -532,8 +550,9 @@
  * a _much_ slower operation than RARRAY_AT. RARRAY_PTR is only provided for
  * compatibility but should _not_ be used intensively.
  */
-# define RARRAY_PTR(a) (rb_ary_ptr(a)) 
-# define RARRAY_AT(a,i) (rb_ary_elt(a, i))
+const VALUE *rb_ary_ptr(VALUE);
+# define RARRAY_PTR(a) (rb_ary_ptr((VALUE)a)) 
+# define RARRAY_AT(a,i) (rb_ary_elt((VALUE)a, (int)i))
 #endif
 
 struct RRegexp {
@@ -963,8 +982,6 @@
     while (isa != NULL) {
 	if (rb_cObject != 0 && isa == RCLASS_OCID(rb_cObject))
 	    return 0;
-	if (rb_cString != 0 && isa == RCLASS_OCID(rb_cString))
-	    return 0;
 	isa = (void *)class_getSuperclass(isa);
     }
     return 1;
@@ -1006,7 +1023,9 @@
     }
 #if WITH_OBJC
     /* FIXME this is super slow */
-    else if (rb_cHash != 0 && rb_cArray != 0 
+    else if (rb_cHash != 0 
+	     && rb_cArray != 0
+	     && rb_cString != 0
 	     && !class_isMetaClass(*(Class *)obj)) {
 	Class k = *(Class *)obj;
 	while (k != NULL) {
@@ -1014,6 +1033,8 @@
 		return T_HASH;
 	    if (k == RCLASS_OCID(rb_cArray))
 		return T_ARRAY;
+	    if (k == RCLASS_OCID(rb_cString))
+		return T_STRING;
 	    k = class_getSuperclass(k);
 	}
     }

Modified: MacRuby/trunk/io.c
===================================================================
--- MacRuby/trunk/io.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/io.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -1278,9 +1278,10 @@
     long len = RSTRING_LEN(str) - offset;
     long n = len;
     int c;
+    char *ptr = RSTRING_PTR(str);
 
     while (n > 0) {
-	c = read_buffered_data(RSTRING_PTR(str)+offset, n, fptr);
+	c = read_buffered_data(ptr+offset, n, fptr);
 	if (c > 0) {
 	    offset += c;
 	    if ((n -= c) <= 0) break;
@@ -1291,6 +1292,7 @@
 	    break;
 	}
     }
+    RSTRING_SYNC(str);
     return len - n;
 }
 

Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/objc.m	2008-04-12 01:10:16 UTC (rev 136)
@@ -800,43 +800,7 @@
 	*rbval = Qnil;
     }
     else {
-	/* FIXME this is a temporary hack, until String/Array/Hash will be
-	 * supporting their CF equivalents.
-	 */
-	static Class nscfstring = NULL;
-	static Class nscfarray = NULL;
-	static Class nscfdictionary = NULL;
-	Class klass;
-
-	if (nscfstring == NULL)
-	    nscfstring = objc_getClass("NSCFString");
-	if (nscfarray == NULL)
-	    nscfarray = objc_getClass("NSCFArray");
-	if (nscfdictionary == NULL)
-	    nscfdictionary = objc_getClass("NSCFDictionary");
-
-	klass = (Class)object_getClass(ocid);
-
-	if (klass == nscfstring) {
-	    const char *p;
-	    p = [ocid UTF8String];
-	    *rbval = rb_enc_str_new(p, strlen(p), rb_utf8_encoding());
-	}
-	else if (klass == nscfarray) {
-	    unsigned i, count;
-
-	    count = [ocid count];
-	    *rbval = rb_ary_new();
-	    for (i = 0, count = [ocid count]; i < count; i++) {
-		id ocelem = [ocid objectAtIndex:i];
-		VALUE elem;
-		rb_objc_ocval_to_rbval((void **)&ocelem, "@", &elem);
-		rb_ary_push(*rbval, elem);
-	    }
-	}
-	else {
-	    *rbval = rb_objc_boot_ocid(ocid);
-	}
+	*rbval = rb_objc_boot_ocid(ocid);
     }
 
     return true;
@@ -2292,120 +2256,6 @@
     return Qtrue;
 }
 
-static NSUInteger
-imp_rb_string_length(void *rcv, SEL sel)
-{
-    return NUM2INT(rb_str_length((VALUE)rcv));
-}
-
-static long
-imp_rb_string_hash(void *rcv, SEL sel)
-{
-    /* FIXME this is a temporary hack to make sure our custom NSString
-     * subclass can be properly hashed.
-     * We won't need that once String is re-implemented on top of CFString.
-     */
-    UniChar *buf;
-    int i;
-    buf = alloca(sizeof(UniChar) * RSTRING_LEN(rcv));
-    for (i = 0; i < RSTRING_LEN(rcv); i++)
-	buf[i] = (UniChar)RSTRING_PTR(rcv)[i];
-    return CFStringHashCharacters(buf, RSTRING_LEN(rcv));
-}
-
-static UniChar
-imp_rb_string_characterAtIndex(void *rcv, SEL sel, NSUInteger idx)
-{
-    VALUE rstr;
-    NSString* ocstr;
-    int length = NUM2INT(rb_str_length((VALUE)rcv));
-    UniChar c;
-    rb_encoding *enc;
-
-    if (idx >= length)
-	[NSException raise:@"NSRangeException" 
-	    format:@"index (%d) beyond bounds (%d)", idx, length];
-
-    enc = rb_enc_get((VALUE)rcv);
-    if (enc == rb_usascii_encoding() || enc == rb_ascii8bit_encoding())
-	return (UniChar)RSTRING_PTR(rcv)[idx];
-
-    if (enc != rb_utf8_encoding())
-	[NSException raise:@"NSException" 
-	    format:@"encoding (%s) not supported", enc->name];
-
-    /* FIXME all of this is temporary, and will be addressed once String is
-     * reimplemented on top of CFString 
-     */
-
-    rstr = rb_str_substr((VALUE)rcv, idx, 1);
-    ocstr = [NSString stringWithCString:RSTRING_PTR(rstr) 
-	encoding:NSUTF8StringEncoding];
-    return [ocstr characterAtIndex:0];
-}
-
-static void
-imp_rb_string_getCharactersRange(void *rcv, SEL sel, unichar *buffer, 
-    NSRange range)
-{
-    VALUE rstr;
-    NSString* ocstr;
-    NSData* data;
-    int length = NUM2INT(rb_str_length((VALUE)rcv));
-    rb_encoding *enc;
-
-    if (NSMaxRange(range) > length)
-	[NSException raise:@"NSRangeException" 
-	    format:@"range (%@) beyond bounds (%d)", NSStringFromRange(range), 
-		length];
-
-    enc = rb_enc_get((VALUE)rcv);
-    if (enc == rb_usascii_encoding() || enc == rb_ascii8bit_encoding()) {
-	int i;
-	for (i = range.location; i < range.location + range.length; i++) {
-	    *buffer = (UniChar)RSTRING_PTR(rcv)[i];
-	    buffer++;
-	}
-	return;
-    }
-
-    /* FIXME all of this is temporary, and will be addressed once String is
-     * reimplemented on top of CFString 
-     */
-
-    if (enc != rb_utf8_encoding())
-	[NSException raise:@"NSException" 
-	    format:@"encoding (%s) not supported", enc->name];
-
-    rstr = rb_str_substr((VALUE)rcv, range.location, range.length);
-    ocstr = [NSString stringWithCString:RSTRING_PTR(rstr) encoding:NSUTF8StringEncoding];
-    data = [ocstr dataUsingEncoding:NSUTF16LittleEndianStringEncoding];
-    [data getBytes:buffer];
-}
-
-static void
-imp_rb_string_replaceCharactersInRangeWithString(void *rcv, SEL sel, 
-    NSRange range, void *str)
-{
-    VALUE newstr;
-    VALUE rstr;
-    int length = NUM2INT(rb_str_length((VALUE)rcv));
-
-    if (length < range.location + range.length) {
-	[NSException raise:@"NSRangeException" 
-	    format:@"range (%@) beyond bounds (%d)", 
-	    NSStringFromRange(range), length];
-    }
-
-    newstr = rb_str_substr((VALUE)rcv, 0, range.location);
-    rb_objc_ocid_to_rval(&str, &rstr);
-    rb_str_concat(newstr, rstr);
-    rb_str_concat(newstr, rb_str_substr((VALUE)rcv, 
-	range.location + range.length, length));
-
-    rb_funcall((VALUE)rcv, rb_intern("replace"), 1, newstr);
-}
-
 static const char *
 imp_rb_boxed_objCType(void *rcv, SEL sel)
 {
@@ -2460,20 +2310,6 @@
 {
     Class klass;
 
-    /* String */
-    klass = RCLASS_OCID(rb_cString);
-    rb_objc_override_method(klass, @selector(length), 
-	(IMP)imp_rb_string_length);
-    rb_objc_override_method(klass, @selector(hash), 
-	(IMP)imp_rb_string_hash);
-    rb_objc_install_method(klass, @selector(characterAtIndex:), 
-	(IMP)imp_rb_string_characterAtIndex);
-    rb_objc_install_method(klass, @selector(getCharacters:range:),
-	(IMP)imp_rb_string_getCharactersRange);
-    rb_objc_install_method(klass, 
-	@selector(replaceCharactersInRange:withString:), 
-	(IMP)imp_rb_string_replaceCharactersInRangeWithString);
-
     /* Boxed */
     klass = RCLASS_OCID(rb_cBoxed);
     rb_objc_override_method(klass, @selector(objCType), 

Modified: MacRuby/trunk/object.c
===================================================================
--- MacRuby/trunk/object.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/object.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -764,6 +764,8 @@
 	    rb_ary_freeze(obj);
 	else if (type == T_HASH)
 	    rb_hash_freeze(obj);
+	else if (type == T_STRING)
+	    rb_str_freeze(obj);
 	else
 	    rb_raise(rb_eRuntimeError, "can't freeze pure objc object `%s'",
 		    RSTRING_PTR(rb_inspect(obj)));

Modified: MacRuby/trunk/parse.y
===================================================================
--- MacRuby/trunk/parse.y	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/parse.y	2008-04-12 01:10:16 UTC (rev 136)
@@ -4791,20 +4791,49 @@
 static VALUE
 lex_get_str(struct parser_params *parser, VALUE s)
 {
-    char *beg, *end, *pend;
+#if WITH_OBJC
+    long beg, n;
+    CFRange search_range;  
+    VALUE v;
+ 
+    beg = 0; 
+    n = CFStringGetLength((CFStringRef)s);
+    if (lex_gets_ptr > 0) {
+	if (n == lex_gets_ptr)
+	    return Qnil;
+	beg += lex_gets_ptr;
+    }
+    if (CFStringFindCharacterFromSet((CFStringRef)s, 
+	CFCharacterSetGetPredefined(kCFCharacterSetNewline),
+	CFRangeMake(beg, n - beg),
+	0,
+	&search_range)) {
+	lex_gets_ptr = search_range.location;
+    }
+    else {
+        lex_gets_ptr = n;
+    }
+    v = (VALUE)CFStringCreateWithSubstring(NULL, (CFStringRef)s, 
+	CFRangeMake(beg, lex_gets_ptr - beg));
+    return v;
+#else
+    const char *cptr, *beg, *end, *pend;
+    long clen;
 
-    beg = RSTRING_PTR(s);
+    cptr = beg = RSTRING_CPTR(s);
+    clen = RSTRING_CLEN(s);
     if (lex_gets_ptr) {
-	if (RSTRING_LEN(s) == lex_gets_ptr) return Qnil;
+	if (clen == lex_gets_ptr) return Qnil;
 	beg += lex_gets_ptr;
     }
-    pend = RSTRING_PTR(s) + RSTRING_LEN(s);
+    pend = cptr + clen;
     end = beg;
     while (end < pend) {
 	if (*end++ == '\n') break;
     }
-    lex_gets_ptr = end - RSTRING_PTR(s);
+    lex_gets_ptr = end - cptr;
     return rb_enc_str_new(beg, end - beg, rb_enc_get(s));
+#endif
 }
 
 static VALUE
@@ -4971,8 +5000,8 @@
 	    }
 	    ruby_sourceline++;
 	    parser->line_count++;
-	    lex_pbeg = lex_p = RSTRING_PTR(v);
-	    lex_pend = lex_p + RSTRING_LEN(v);
+	    lex_pbeg = lex_p = RSTRING_CPTR(v);
+	    lex_pend = lex_p + RSTRING_CLEN(v);
 #ifdef RIPPER
 	    ripper_flush(parser);
 #endif
@@ -5361,8 +5390,10 @@
 dispose_string(VALUE str)
 {
     /* TODO: should use another API? */
+#if !WITH_OBJC
     if (RBASIC(str)->flags & RSTRING_NOEMBED)
 	xfree(RSTRING_PTR(str));
+#endif
     rb_gc_force_recycle(str);
 }
 
@@ -5650,8 +5681,8 @@
 #endif
     line = here->nd_orig;
     lex_lastline = line;
-    lex_pbeg = RSTRING_PTR(line);
-    lex_pend = lex_pbeg + RSTRING_LEN(line);
+    lex_pbeg = RSTRING_CPTR(line);
+    lex_pend = lex_pbeg + RSTRING_CLEN(line);
     lex_p = lex_pbeg + here->nd_nth;
     heredoc_end = ruby_sourceline;
     ruby_sourceline = nd_line(here);
@@ -5686,8 +5717,8 @@
     long len;
     VALUE str = 0;
 
-    eos = RSTRING_PTR(here->nd_lit);
-    len = RSTRING_LEN(here->nd_lit) - 1;
+    eos = RSTRING_CPTR(here->nd_lit);
+    len = RSTRING_CLEN(here->nd_lit) - 1;
     indent = (func = *eos++) & STR_FUNC_INDENT;
 
     if ((c = nextc()) == -1) {
@@ -5705,7 +5736,7 @@
 
     if (!(func & STR_FUNC_EXPAND)) {
 	do {
-	    p = RSTRING_PTR(lex_lastline);
+	    p = RSTRING_CPTR(lex_lastline);
 	    pend = lex_pend;
 	    if (pend > p) {
 		switch (pend[-1]) {
@@ -5891,10 +5922,16 @@
 {
     VALUE name = 0, val = 0;
     const char *beg, *end, *vbeg, *vend;
-#define str_copy(_s, _p, _n) ((_s) \
+#if 0// WITH_OBJC
+# define str_copy(_s, _p, _n) ((_s) \
+	? CFStringPad((CFMutableStringRef)_s, CFStringCreateWithCString(NULL, _p, kCFStringEncodingUTF8), _n, 0) \
+	: ((_s) = STR_NEW((_p), (_n)))) 
+#else
+# define str_copy(_s, _p, _n) ((_s) \
 	? (rb_str_resize((_s), (_n)), \
 	   MEMCPY(RSTRING_PTR(_s), (_p), char, (_n)), (_s)) \
 	: ((_s) = STR_NEW((_p), (_n))))
+#endif
 
     if (len <= 7) return Qfalse;
     if (!(beg = magic_comment_marker(str, len))) return Qfalse;
@@ -5955,13 +5992,13 @@
 	str_copy(name, beg, n);
 #ifndef RIPPER
 	do {
-	    if (STRNCASECMP(p->name, RSTRING_PTR(name), n) == 0) {
+	    if (STRNCASECMP(p->name, RSTRING_CPTR(name), n) == 0) {
 		n = vend - vbeg;
 		if (p->length) {
 		    n = (*p->length)(parser, vbeg, n);
 		}
 		str_copy(val, vbeg, n);
-		(*p->func)(parser, RSTRING_PTR(name), RSTRING_PTR(val));
+		(*p->func)(parser, RSTRING_CPTR(name), RSTRING_CPTR(val));
 		break;
 	    }
 	} while (++p < magic_comments + sizeof(magic_comments) / sizeof(*p));
@@ -6012,7 +6049,7 @@
     beg = str;
     while ((*str == '-' || *str == '_' || ISALNUM(*str)) && ++str < send);
     s = rb_str_new(beg, parser_encode_length(parser, beg, str - beg));
-    parser_set_encode(parser, RSTRING_PTR(s));
+    parser_set_encode(parser, RSTRING_CPTR(s));
     rb_str_resize(s, 0);
 }
 
@@ -6039,6 +6076,8 @@
     }
     pushback(c);
     parser->enc = rb_enc_get(lex_lastline);
+    if (parser->enc == NULL)
+	parser->enc = rb_usascii_encoding();
 }
 
 #define IS_ARG() (lex_state == EXPR_ARG || lex_state == EXPR_CMDARG)
@@ -8624,7 +8663,7 @@
     err = rb_reg_check_preprocess(str);
     if (err != Qnil) {
         err = rb_obj_as_string(err);
-        compile_error(PARSER_ARG "%s", RSTRING_PTR(err));
+        compile_error(PARSER_ARG "%s", RSTRING_CPTR(err));
 	RB_GC_GUARD(err);
     }
 }
@@ -8725,7 +8764,7 @@
 	    rb_str_append(rb_str_cat(rb_attr_get(err, mesg), "\n", 1), m);
 	}
 	else {
-	    compile_error(PARSER_ARG "%s", RSTRING_PTR(m));
+	    compile_error(PARSER_ARG "%s", RSTRING_CPTR(m));
 	}
 	return Qnil;
     }
@@ -8853,13 +8892,13 @@
 
 static struct symbols {
     ID last_id;
-    st_table *sym_id;
-    st_table *id_str;
-    st_table *ivar2_id;
-    st_table *id_ivar2;
 #if WITH_OBJC
+    CFMutableDictionaryRef sym_id;
+    CFMutableDictionaryRef id_str;
     VALUE *op_sym;
 #else
+    st_table *sym_id;
+    st_table *id_str;
     VALUE op_sym[tLAST_TOKEN];
 #endif
 } global_symbols = {tLAST_TOKEN >> ID_SCOPE_SHIFT};
@@ -8897,21 +8936,24 @@
 void
 Init_sym(void)
 {
-    global_symbols.sym_id = st_init_table_with_size(&symhash, 1000);
+#if WITH_OBJC
+    CFDictionaryKeyCallBacks cb;
+    global_symbols.sym_id = CFDictionaryCreateMutable(NULL,
+	0, NULL, NULL);
     GC_ROOT(&global_symbols.sym_id);
-    global_symbols.id_str = st_init_numtable_with_size(1000);
+    global_symbols.id_str = CFDictionaryCreateMutable(NULL,
+	0, NULL, NULL);
     GC_ROOT(&global_symbols.id_str);
-    global_symbols.ivar2_id = st_init_table_with_size(&ivar2_hash_type, 1000);
-    GC_ROOT(&global_symbols.ivar2_id);
-    global_symbols.id_ivar2 = st_init_numtable_with_size(1000);
-    GC_ROOT(&global_symbols.id_ivar2);
-#if WITH_OBJC
     global_symbols.op_sym = xmalloc(sizeof(VALUE) * tLAST_TOKEN);
     GC_ROOT(&global_symbols.op_sym);
+#else
+    global_symbols.sym_id = st_init_table_with_size(&symhash, 1000);
+    global_symbols.id_str = st_init_numtable_with_size(1000);
 #endif
     rb_intern2("", 0);
 }
 
+#if !WITH_OBJC 
 void
 rb_gc_mark_symbols(void)
 {
@@ -8919,6 +8961,7 @@
     rb_gc_mark_locations(global_symbols.op_sym,
 			 global_symbols.op_sym + tLAST_TOKEN);
 }
+#endif
 
 static ID
 internal_id_gen(struct parser_params *parser)
@@ -9063,10 +9106,9 @@
     ID id;
     int last;
     int mb;
+#if !WITH_OBJC
     struct RString fake_str;
-#if WITH_OBJC
     fake_str.basic.isa = NULL;
-#endif
     fake_str.basic.flags = T_STRING|RSTRING_NOEMBED|FL_FREEZE;
     fake_str.basic.klass = rb_cString;
     fake_str.as.heap.len = len;
@@ -9077,6 +9119,13 @@
 
     if (st_lookup(global_symbols.sym_id, str, (st_data_t *)&id))
 	return id;
+#else
+    SEL name_hash = sel_registerName(name);
+    id = (ID)CFDictionaryGetValue((CFDictionaryRef)global_symbols.sym_id, 
+	(const void *)name_hash);
+    if (id != 0)
+	return id; 
+#endif
 
     last = len-1;
     id = 0;
@@ -9161,9 +9210,17 @@
     id |= ++global_symbols.last_id << ID_SCOPE_SHIFT;
   id_register:
     str = rb_enc_str_new(name, len, enc);
-    OBJ_FREEZE(str);
+// TODO
+//    OBJ_FREEZE(str);
+#if WITH_OBJC
+    CFDictionarySetValue(global_symbols.sym_id, (const void *)name_hash, 
+	(const void *)id);
+    CFDictionarySetValue(global_symbols.id_str, (const void *)id,
+	(const void *)str);
+#else
     st_add_direct(global_symbols.sym_id, (st_data_t)str, id);
     st_add_direct(global_symbols.id_str, id, (st_data_t)str);
+#endif
     return id;
 }
 
@@ -9192,7 +9249,7 @@
     else {
 	enc = rb_enc_get(str);
     }
-    id = rb_intern3(RSTRING_PTR(str), RSTRING_LEN(str), enc);
+    id = rb_intern3(RSTRING_CPTR(str), RSTRING_CLEN(str), enc);
     RB_GC_GUARD(str);
     return id;
 }
@@ -9210,7 +9267,7 @@
 		VALUE str = global_symbols.op_sym[i];
 		if (!str) {
 		    str = rb_usascii_str_new2(op_tbl[i].name);
-		    OBJ_FREEZE(str);
+		    // TODO OBJ_FREEZE(str);
 		    GC_WB(&global_symbols.op_sym[i], str);
 		}
 		return str;
@@ -9218,16 +9275,21 @@
 	}
     }
 
+#if WITH_OBJC
+    data = (VALUE)CFDictionaryGetValue(
+	(CFDictionaryRef)global_symbols.id_str,
+	(const void *)id);
+    if (data != 0)
+	return data;
+#else
     if (st_lookup(global_symbols.id_str, id, &data)) {
         VALUE str = (VALUE)data;
         if (RBASIC(str)->klass == 0 && rb_cString != 0) {
             RBASIC(str)->klass = rb_cString;
-#if WITH_OBJC
-	    RBASIC(str)->isa = RCLASS(rb_cString)->ocklass;
-#endif
 	}
 	return str;
     }
+#endif
 
     if (is_attrset_id(id)) {
 	ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL;
@@ -9240,12 +9302,23 @@
 	str = rb_str_dup(str);
 	rb_str_cat(str, "=", 1);
 	rb_intern_str(str);
+#if WITH_OBJC
+	return str;
+# if 0
+	data = (VALUE)CFDictionaryGetValue(
+	    (CFDictionaryRef)global_symbols.id_str,
+	    (const void *)id);
+	if (data != 0)
+	    return data;
+# endif
+#else
 	if (st_lookup(global_symbols.id_str, id, &data)) {
             VALUE str = (VALUE)data;
             if (RBASIC(str)->klass == 0)
                 RBASIC(str)->klass = rb_cString;
             return str;
         }
+#endif
     }
     return 0;
 }
@@ -9256,7 +9329,7 @@
     VALUE str = rb_id2str(id);
 
     if (!str) return 0;
-    return RSTRING_PTR(str);
+    return RSTRING_CPTR(str);
 }
 
 static int
@@ -9285,9 +9358,15 @@
 VALUE
 rb_sym_all_symbols(void)
 {
+#if WITH_OBJC
+    VALUE ary = rb_ary_new();
+    CFDictionaryApplyFunction((CFDictionaryRef)global_symbols.sym_id,
+	(CFDictionaryApplierFunction)symbols_i, (void *)ary);
+#else
     VALUE ary = rb_ary_new2(global_symbols.sym_id->num_entries);
 
     st_foreach(global_symbols.sym_id, symbols_i, ary);
+#endif
     return ary;
 }
 
@@ -9872,7 +9951,7 @@
     parser_initialize(parser);
 
     parser->parser_ruby_sourcefile_string = fname2;
-    parser->parser_ruby_sourcefile = RSTRING_PTR(fname2)+1;
+    parser->parser_ruby_sourcefile = RSTRING_CPTR(fname2)+1;
     parser->parser_ruby_sourceline = NIL_P(lineno) ? 0 : NUM2INT(lineno) - 1;
 
     return Qnil;
@@ -9983,7 +10062,7 @@
 {
     StringValue(msg);
     if (obj == Qundef) {
-        rb_raise(rb_eArgError, "%s", RSTRING_PTR(msg));
+        rb_raise(rb_eArgError, "%s", RSTRING_CPTR(msg));
     }
     return Qnil;
 }

Modified: MacRuby/trunk/sample/test.rb
===================================================================
--- MacRuby/trunk/sample/test.rb	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/sample/test.rb	2008-04-12 01:10:16 UTC (rev 136)
@@ -1463,6 +1463,8 @@
 
 test_check "string & char"
 
+"abcd" =~ /ab/
+=begin
 test_ok("abcd" == "abcd")
 test_ok("abcd" =~ /abcd/)
 test_ok("abcd" === "abcd")
@@ -1490,6 +1492,7 @@
 
 test_ok(/(\s+\d+){2}/ =~ " 1 2" && $& == " 1 2")
 test_ok(/(?:\s+\d+){2}/ =~ " 1 2" && $& == " 1 2")
+=end
 
 $x = <<END;
 ABCD
@@ -1668,7 +1671,7 @@
 $proc2.call
 test_ok($x == 5)
 
-if defined? Process.kill
+if false#defined? Process.kill
   test_check "signal"
 
   $x = 0

Modified: MacRuby/trunk/sprintf.c
===================================================================
--- MacRuby/trunk/sprintf.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/sprintf.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -928,6 +928,12 @@
 VALUE
 rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
 {
+#if WITH_OBJC
+    char buffer[512];
+    int n;
+    n = vsnprintf(buffer, sizeof buffer, fmt, ap);
+    return rb_enc_str_new(buffer, n, enc);
+#else
     rb_printf_buffer f;
     VALUE result;
 
@@ -945,6 +951,7 @@
     rb_str_resize(result, (char *)f._p - RSTRING_PTR(result));
 
     return result;
+#endif
 }
 
 VALUE

Modified: MacRuby/trunk/string.c
===================================================================
--- MacRuby/trunk/string.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/string.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -26,8 +26,12 @@
 #endif
 
 VALUE rb_cString;
+#if WITH_OBJC
+VALUE rb_cStringRuby;
+#endif
 VALUE rb_cSymbol;
 
+#if !WITH_OBJC
 #define STR_TMPLOCK FL_USER7
 #define STR_NOEMBED FL_USER1
 #define STR_SHARED  FL_USER2 /* = ELTS_SHARED */
@@ -91,6 +95,84 @@
     }\
 } while (0)
 
+#else
+
+struct rb_objc_str_struct {
+    void *cfdata;
+};
+
+/* This variable will always stay NULL, we only use its address. */
+static void *rb_objc_str_assoc_key = NULL;
+
+static struct rb_objc_str_struct *
+rb_objc_str_get_struct(VALUE ary)
+{
+    return rb_objc_get_associative_ref((void *)ary, &rb_objc_str_assoc_key);
+}
+
+static struct rb_objc_str_struct *
+rb_objc_str_get_struct2(VALUE str)
+{
+    struct rb_objc_str_struct *s;
+
+    s = rb_objc_str_get_struct(str);
+    if (s == NULL) {
+	s = xmalloc(sizeof(struct rb_objc_str_struct));
+	rb_objc_set_associative_ref((void *)str, &rb_objc_str_assoc_key, s);
+	s->cfdata = NULL;
+    }
+    return s;
+}
+
+static void *
+rb_str_cfdata(VALUE str)
+{
+    struct rb_objc_str_struct *s;
+
+    s = rb_objc_str_get_struct2(str);
+    if (s->cfdata == NULL) {
+	CFDataRef data;
+	data = CFStringCreateExternalRepresentation(NULL,
+	    (CFStringRef)str, kCFStringEncodingUTF8, 0);
+	if (data == NULL)
+	    return NULL;
+	GC_WB(&s->cfdata, (void *)CFDataCreateCopy(NULL, data));
+    }
+    return s->cfdata;    
+}
+
+char *
+rb_str_byteptr(VALUE str)
+{
+    return (char *)CFDataGetMutableBytePtr(
+	(CFMutableDataRef)rb_str_cfdata(str));
+}
+
+long
+rb_str_bytelen(VALUE str)
+{
+    return CFDataGetLength((CFDataRef)rb_str_cfdata(str));
+}
+
+void
+rb_str_bytesync(VALUE str)
+{
+    CFDataRef data;
+    CFIndex datalen;
+    data = (CFDataRef)rb_str_cfdata(str);
+    datalen = CFDataGetLength(data);
+    CFStringRef bytestr = CFStringCreateWithBytesNoCopy(
+	NULL,
+	CFDataGetMutableBytePtr((CFMutableDataRef)data),
+	datalen,
+	kCFStringEncodingUTF8,
+	false,
+	kCFAllocatorNull);
+    CFStringReplaceAll((CFMutableStringRef)str, (CFStringRef)bytestr);
+}
+
+#endif
+
 #define is_ascii_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT)
 #define is_broken_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN)
 
@@ -317,22 +399,36 @@
 static inline void
 str_mod_check(VALUE s, const char *p, long len)
 {
+#if !WITH_OBJC
+    /* TODO */
     if (RSTRING_PTR(s) != p || RSTRING_LEN(s) != len){
 	rb_raise(rb_eRuntimeError, "string modified");
     }
+#endif
 }
 
 static inline void
 str_frozen_check(VALUE s)
 {
+#if !WITH_OBJC
+    /* TODO */
     if (OBJ_FROZEN(s)) {
 	rb_raise(rb_eRuntimeError, "string frozen");
     }
+#endif
 }
 
 static VALUE
 str_alloc(VALUE klass)
 {
+#if WITH_OBJC
+    VALUE str;
+
+    str = (VALUE)CFStringCreateMutable(NULL, 0);
+    if (klass != 0 && klass != rb_cString && klass != rb_cStringRuby 
+	&& klass != rb_cSymbol)
+	*(Class *)str = RCLASS_OCID(klass);
+#else
     NEWOBJ(str, struct RString);
     OBJSETUP(str, klass, T_STRING);
 
@@ -343,6 +439,7 @@
     str->as.heap.ptr = 0;
     str->as.heap.len = 0;
     str->as.heap.aux.capa = 0;
+#endif
 
     return (VALUE)str;
 }
@@ -357,6 +454,13 @@
     }
 
     str = str_alloc(klass);
+#if WITH_OBJC
+    if (ptr != NULL) {
+	CFStringAppendCString((CFMutableStringRef)str, ptr, 
+	    kCFStringEncodingUTF8);
+	/* TODO ptr might be a bytestring */
+    }
+#else
     if (len > RSTRING_EMBED_LEN_MAX) {
 	RSTRING(str)->as.heap.aux.capa = len;
 	GC_WB(&RSTRING(str)->as.heap.ptr, ALLOC_N(char,len+1));
@@ -367,6 +471,7 @@
     }
     STR_SET_LEN(str, len);
     RSTRING_PTR(str)[len] = '\0';
+#endif
     return str;
 }
 
@@ -390,7 +495,8 @@
 {
     VALUE str = str_new(rb_cString, ptr, len);
 
-    rb_enc_associate(str, enc);
+    // TODO we should pass the real encoding
+    //rb_enc_associate(str, enc);
     return str;
 }
 
@@ -417,7 +523,9 @@
 {
     VALUE str = rb_str_new(ptr, len);
 
+#if !WITH_OBJC /* TODO */
     OBJ_TAINT(str);
+#endif
     return str;
 }
 
@@ -426,10 +534,13 @@
 {
     VALUE str = rb_str_new2(ptr);
 
+#if !WITH_OBJC /* TODO */
     OBJ_TAINT(str);
+#endif
     return str;
 }
 
+#if !WITH_OBJC
 static VALUE
 str_replace_shared(VALUE str2, VALUE str)
 {
@@ -530,8 +641,30 @@
     OBJ_FREEZE(str);
     return str;
 }
+#else
+static VALUE
+str_new3(VALUE klass, VALUE str)
+{
+    return str_new(klass, RSTRING_CPTR(str), 0);
+}
 
 VALUE
+rb_str_new3(VALUE str)
+{
+    VALUE str2 = str_new3(rb_obj_class(str), str);
+
+    // TODO OBJ_INFECT(str2, str);
+    return str2;
+}
+
+VALUE
+rb_str_new4(VALUE orig)
+{
+    return rb_str_dup(orig);
+}
+#endif
+
+VALUE
 rb_str_new5(VALUE obj, const char *ptr, long len)
 {
     return str_new(rb_obj_class(obj), ptr, len);
@@ -544,6 +677,7 @@
 {
     VALUE str = str_alloc(rb_cString);
 
+#if !WITH_OBJC // TODO should we pass capa as the CFString's maxLength?
     if (capa < STR_BUF_MIN_SIZE) {
 	capa = STR_BUF_MIN_SIZE;
     }
@@ -551,6 +685,7 @@
     RSTRING(str)->as.heap.aux.capa = capa;
     GC_WB(&RSTRING(str)->as.heap.ptr, ALLOC_N(char, capa+1));
     RSTRING(str)->as.heap.ptr[0] = '\0';
+#endif
 
     return str;
 }
@@ -576,9 +711,11 @@
 void
 rb_str_free(VALUE str)
 {
+#if !WITH_OBJC
     if (!STR_EMBED_P(str) && !STR_SHARED_P(str)) {
 	xfree(RSTRING(str)->as.heap.ptr);
     }
+#endif
 }
 
 VALUE
@@ -590,6 +727,9 @@
 void
 rb_str_shared_replace(VALUE str, VALUE str2)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
     rb_encoding *enc;
     int cr;
     if (str == str2) return;
@@ -625,6 +765,7 @@
     STR_UNSET_NOCAPA(str2);
     rb_enc_associate(str, enc);
     ENC_CODERANGE_SET(str, cr);
+#endif
 }
 
 static ID id_to_s;
@@ -758,6 +899,10 @@
 static long
 str_strlen(VALUE str, rb_encoding *enc)
 {
+#if WITH_OBJC
+    /* TODO should use CFStringGetMaximumSizeForEncoding too */
+    return CFStringGetLength((CFStringRef)str);
+#else
     const char *p, *e;
     int n, cr;
 
@@ -803,6 +948,7 @@
         ENC_CODERANGE_SET(str, cr);
     }
     return n;
+#endif
 }
 
 /*
@@ -818,7 +964,11 @@
 {
     int len;
 
+#if WITH_OBJC
+    len = CFStringGetLength((CFStringRef)str);
+#else
     len = str_strlen(str, STR_ENC_GET(str));
+#endif
     return INT2NUM(len);
 }
 
@@ -866,6 +1016,12 @@
 VALUE
 rb_str_plus(VALUE str1, VALUE str2)
 {
+#if WITH_OBJC
+    VALUE str3 = rb_str_new(0, 0);
+    CFStringAppend((CFMutableStringRef)str3, (CFStringRef)str1);
+    CFStringAppend((CFMutableStringRef)str3, (CFStringRef)str2);
+    /* TODO copy taint flag if needed */
+#else
     VALUE str3;
     rb_encoding *enc;
 
@@ -881,6 +1037,7 @@
 	OBJ_TAINT(str3);
     ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
 			   ENC_CODERANGE_AND(ENC_CODERANGE(str1), ENC_CODERANGE(str2)));
+#endif
     return str3;
 }
 
@@ -900,17 +1057,23 @@
     VALUE str2;
     long n, len;
 
+    n = RSTRING_LEN(str);
     len = NUM2LONG(times);
     if (len < 0) {
 	rb_raise(rb_eArgError, "negative argument");
     }
-    if (len && LONG_MAX/len <  RSTRING_LEN(str)) {
+    if (len && LONG_MAX/len < n) {
 	rb_raise(rb_eArgError, "argument too big");
     }
 
-    str2 = rb_str_new5(str, 0, len *= RSTRING_LEN(str));
+    str2 = rb_str_new5(str, 0, len *= n);
+#if WITH_OBJC
+    while (len > 0) {
+	CFStringAppend((CFMutableStringRef)str2, (CFStringRef)str);
+	len--;
+    }
+#else
     if (len) {
-        n = RSTRING_LEN(str);
         memcpy(RSTRING_PTR(str2), RSTRING_PTR(str), n);
         while (n <= len/2) {
             memcpy(RSTRING_PTR(str2) + n, RSTRING_PTR(str2), n);
@@ -921,6 +1084,7 @@
     RSTRING_PTR(str2)[RSTRING_LEN(str2)] = '\0';
     OBJ_INFECT(str2, str);
     rb_enc_cr_str_copy_for_substr(str2, str);
+#endif
 
     return str2;
 }
@@ -953,14 +1117,22 @@
 static void
 str_modifiable(VALUE str)
 {
+#if WITH_OBJC
+    bool _CFStringIsMutable(void *);
+    if (!__CFStringIsMutable(str)) 
+	rb_raise(rb_eRuntimeError, "can't modify immutable array");
+    /* TODO test for freeze/taint state */
+#else
     if (FL_TEST(str, STR_TMPLOCK)) {
 	rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked");
     }
     if (OBJ_FROZEN(str)) rb_error_frozen("string");
     if (!OBJ_TAINTED(str) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify string");
+#endif
 }
 
+#if !WITH_OBJC
 static int
 str_independent(VALUE str)
 {
@@ -987,18 +1159,26 @@
     RSTRING(str)->as.heap.aux.capa = len;
     STR_UNSET_NOCAPA(str);
 }
+#endif
 
 void
 rb_str_modify(VALUE str)
 {
+#if WITH_OBJC
+    str_modifiable(str);
+#else
     if (!str_independent(str))
 	str_make_independent(str);
     ENC_CODERANGE_CLEAR(str);
+#endif
 }
 
 void
 rb_str_associate(VALUE str, VALUE add)
 {
+#if WITH_OBJC
+    rb_str_replace(str, add);
+#else
     /* sanity check */
     if (OBJ_FROZEN(str)) rb_error_frozen("string");
     if (STR_ASSOC_P(str)) {
@@ -1025,15 +1205,18 @@
 	RBASIC(add)->klass = 0;
 	RSTRING(str)->as.heap.aux.shared = add;
     }
+#endif
 }
 
 VALUE
 rb_str_associated(VALUE str)
 {
+#if !WITH_OBJC
     if (STR_SHARED_P(str)) str = RSTRING(str)->as.heap.aux.shared;
     if (STR_ASSOC_P(str)) {
 	return RSTRING(str)->as.heap.aux.shared;
     }
+#endif
     return Qfalse;
 }
 
@@ -1057,13 +1240,17 @@
 char *
 rb_string_value_cstr(volatile VALUE *ptr)
 {
+#if WITH_OBJC
     VALUE str = rb_string_value(ptr);
+    return (char *)CFStringGetCStringPtr((CFStringRef)str, 0);
+#else
     char *s = RSTRING_PTR(str);
 
     if (!s || RSTRING_LEN(str) != strlen(s)) {
 	rb_raise(rb_eArgError, "string contains null byte");
     }
     return s;
+#endif
 }
 
 VALUE
@@ -1209,28 +1396,49 @@
 long
 rb_str_sublen(VALUE str, long pos)
 {
+#if WITH_OBJC
+    return pos;
+#else
     if (single_byte_optimizable(str) || pos < 0)
         return pos;
     else {
 	char *p = RSTRING_PTR(str);
         return rb_enc_strlen(p, p + pos, STR_ENC_GET(str));
     }
+#endif
 }
 
 VALUE
 rb_str_subseq(VALUE str, long beg, long len)
 {
+#if WITH_OBJC
+    CFIndex buffer_len, buffer_used;
+    UInt8 *buffer;
+
+    buffer_len = (sizeof(UInt8) * len) + 1;
+    buffer = (UInt8 *)alloca(buffer_len);
+
+    CFStringGetBytes((CFStringRef)str, CFRangeMake(beg, len), 
+	    kCFStringEncodingUTF8, 0, false, buffer, buffer_len, &buffer_used);
+    assert(buffer_used == buffer_len - 1);
+    buffer[buffer_used] = '\0';
+    return rb_str_new5(str, (const char *)buffer, len);
+#else
     VALUE str2 = rb_str_new5(str, RSTRING_PTR(str)+beg, len);
 
     rb_enc_cr_str_copy_for_substr(str2, str);
     OBJ_INFECT(str2, str);
 
     return str2;
+#endif
 }
 
 VALUE
 rb_str_substr(VALUE str, long beg, long len)
 {
+#if WITH_OBJC
+    return rb_str_subseq(str, beg, len);
+#else
     rb_encoding *enc = STR_ENC_GET(str);
     VALUE str2;
     char *p, *s = RSTRING_PTR(str), *e = s + RSTRING_LEN(str);
@@ -1296,21 +1504,31 @@
     }
 
     return str2;
+#endif
 }
 
 VALUE
 rb_str_freeze(VALUE str)
 {
+#if WITH_OBJC
+    /* TODO */
+#else
     if (STR_ASSOC_P(str)) {
 	VALUE ary = RSTRING(str)->as.heap.aux.shared;
 	OBJ_FREEZE(ary);
     }
     return rb_obj_freeze(str);
+#endif
 }
 
 VALUE
 rb_str_dup_frozen(VALUE str)
 {
+#if WITH_OBJC
+    str = rb_str_dup(str);
+    rb_str_freeze(str);
+    return str;
+#else
     if (STR_SHARED_P(str) && RSTRING(str)->as.heap.aux.shared) {
 	VALUE shared = RSTRING(str)->as.heap.aux.shared;
 	if (RSTRING_LEN(shared) == RSTRING_LEN(str)) {
@@ -1322,33 +1540,40 @@
     str = rb_str_dup(str);
     OBJ_FREEZE(str);
     return str;
+#endif
 }
 
 VALUE
 rb_str_locktmp(VALUE str)
 {
+#if !WITH_OBJC
     if (FL_TEST(str, STR_TMPLOCK)) {
 	rb_raise(rb_eRuntimeError, "temporal locking already locked string");
     }
     FL_SET(str, STR_TMPLOCK);
+#endif
     return str;
 }
 
 VALUE
 rb_str_unlocktmp(VALUE str)
 {
+#if !WITH_OBJC
     if (!FL_TEST(str, STR_TMPLOCK)) {
 	rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string");
     }
     FL_UNSET(str, STR_TMPLOCK);
+#endif
     return str;
 }
 
 void
 rb_str_set_len(VALUE str, long len)
 {
+#if !WITH_OBJC
     STR_SET_LEN(str, len);
     RSTRING_PTR(str)[len] = '\0';
+#endif
 }
 
 VALUE
@@ -1361,6 +1586,18 @@
     }
 
     rb_str_modify(str);
+#if WITH_OBJC
+    slen = CFStringGetLength((CFStringRef)str);
+    if (slen != len) {
+	if (len > slen) {
+	    CFStringPad((CFMutableStringRef)str, CFSTR(" "), len, 0);
+	}
+	else {
+	    CFStringDelete((CFMutableStringRef)str, 
+		CFRangeMake(len, slen - len));
+	}
+    }
+#else
     slen = RSTRING_LEN(str);
     if (len != slen) {
 	if (STR_EMBED_P(str)) {
@@ -1393,12 +1630,17 @@
 	RSTRING(str)->as.heap.len = len;
 	RSTRING(str)->as.heap.ptr[len] = '\0';	/* sentinel */
     }
+#endif
     return str;
 }
 
 VALUE
 rb_str_buf_cat(VALUE str, const char *ptr, long len)
 {
+#if WITH_OBJC
+    CFStringAppendCString((CFMutableStringRef)str, ptr, kCFStringEncodingUTF8);
+    /* FIXME ptr might be a bytestring */
+#else
     long capa, total;
 
     if (len == 0) return str;
@@ -1426,6 +1668,7 @@
     memcpy(RSTRING_PTR(str) + RSTRING_LEN(str), ptr, len);
     STR_SET_LEN(str, total);
     RSTRING_PTR(str)[total] = '\0'; /* sentinel */
+#endif
 
     return str;
 }
@@ -1442,6 +1685,7 @@
     if (len < 0) {
 	rb_raise(rb_eArgError, "negative string size (or size too big)");
     }
+#if !WITH_OBJC
     if (STR_ASSOC_P(str)) {
 	rb_str_modify(str);
 	if (STR_EMBED_P(str)) str_make_independent(str);
@@ -1451,6 +1695,7 @@
 	RSTRING(str)->as.heap.ptr[RSTRING(str)->as.heap.len] = '\0'; /* sentinel */
 	return str;
     }
+#endif
 
     return rb_str_buf_cat(str, ptr, len);
 }
@@ -1461,6 +1706,7 @@
     return rb_str_cat(str, ptr, strlen(ptr));
 }
 
+#if !WITH_OBJC
 static VALUE
 rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, long len,
     int ptr_encindex, int ptr_cr, int *ptr_cr_ret)
@@ -1580,17 +1826,28 @@
     ENCODING_CODERANGE_SET(str, res_encindex, res_cr);
     return str;
 }
+#endif
 
 VALUE
 rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *ptr_enc)
 {
+#if WITH_OBJC
+    VALUE s = rb_enc_str_new(ptr, len, ptr_enc);
+    CFStringAppend((CFMutableStringRef)str, (CFStringRef)s);
+    return str;
+#else
     return rb_enc_cr_str_buf_cat(str, ptr, len,
         rb_enc_to_index(ptr_enc), ENC_CODERANGE_UNKNOWN, NULL);
+#endif
 }
 
 VALUE
 rb_str_buf_cat_ascii(VALUE str, const char *ptr)
 {
+#if WITH_OBJC
+    CFStringAppendCString((CFMutableStringRef)str, ptr, kCFStringEncodingASCII);
+    return str;
+#else
     /* ptr must reference NUL terminated ASCII string. */
     int encindex = ENCODING_GET(str);
     rb_encoding *enc = rb_enc_from_index(encindex);
@@ -1610,11 +1867,15 @@
         }
         return str;
     }
+#endif
 }
 
 VALUE
 rb_str_buf_append(VALUE str, VALUE str2)
 {
+#if WITH_OBJC
+    CFStringAppend((CFMutableStringRef)str, (CFStringRef)str2);
+#else
     int str2_cr;
 
     str2_cr = ENC_CODERANGE(str2);
@@ -1624,6 +1885,7 @@
 
     OBJ_INFECT(str, str2);
     ENC_CODERANGE_SET(str2, str2_cr);
+#endif
 
     return str;
 }
@@ -1631,11 +1893,12 @@
 VALUE
 rb_str_append(VALUE str, VALUE str2)
 {
-    rb_encoding *enc;
-    int cr, cr2;
-
     StringValue(str2);
+#if !WITH_OBJC
     if (RSTRING_LEN(str2) > 0 && STR_ASSOC_P(str)) {
+	rb_encoding *enc;
+	int cr, cr2;
+
         long len = RSTRING_LEN(str)+RSTRING_LEN(str2);
         enc = rb_enc_check(str, str2);
         cr = ENC_CODERANGE(str);
@@ -1651,6 +1914,7 @@
         OBJ_INFECT(str, str2);
         return str;
     }
+#endif
     return rb_str_buf_append(str, str2);
 }
 
@@ -1675,6 +1939,13 @@
 rb_str_concat(VALUE str1, VALUE str2)
 {
     if (FIXNUM_P(str2)) {
+#if WITH_OBJC
+        int c = FIX2INT(str2);
+
+	rb_str_modify(str1);
+        CFStringAppendCharacters((CFMutableStringRef)str1, (const UniChar *)&c, 
+	    1);
+#else
 	rb_encoding *enc = STR_ENC_GET(str1);
 	int c = FIX2INT(str2);
 	int pos = RSTRING_LEN(str1);
@@ -1684,11 +1955,14 @@
 	rb_str_resize(str1, pos+len);
 	rb_enc_mbcput(c, RSTRING_PTR(str1)+pos, enc);
 	ENC_CODERANGE_SET(str1, cr);
+#endif
 	return str1;
     }
     return rb_str_append(str1, str2);
 }
 
+#if !WITH_OBJC
+
 typedef  unsigned int  ub4;   /* unsigned 4-byte quantities */
 typedef  unsigned char ub1;   /* unsigned 1-byte quantities */
 
@@ -1832,6 +2106,30 @@
     return 1;
 }
 
+#else
+
+int
+rb_memhash(const void *ptr, long len)
+{
+    /* TODO is that really needed? */
+    CFDataRef data = CFDataCreate(NULL, (const UInt8 *)ptr, len);
+    return CFHash(data);
+}
+
+int
+rb_str_hash(VALUE str)
+{
+    return CFHash((CFTypeRef)str);
+}
+
+int
+rb_str_hash_cmp(VALUE str1, VALUE str2)
+{
+    return CFEqual((CFTypeRef)str1, (CFTypeRef)str2);
+}
+
+#endif
+
 /*
  * call-seq:
  *    str.hash   => fixnum
@@ -1851,6 +2149,9 @@
 int
 rb_str_comparable(VALUE str1, VALUE str2)
 {
+#if WITH_OBJC
+    return Qtrue;
+#else
     int idx1 = ENCODING_GET(str1);
     int idx2 = ENCODING_GET(str2);
     int rc1, rc2;
@@ -1868,11 +2169,15 @@
 	    return Qtrue;
     }
     return Qfalse;
+#endif
 }
 
 int
 rb_str_cmp(VALUE str1, VALUE str2)
 {
+#if WITH_OBJC
+    return CFStringCompare((CFStringRef)str1, (CFStringRef)str2, 0);
+#else
     long len;
     int retval;
     rb_encoding *enc;
@@ -1894,6 +2199,7 @@
     }
     if (retval > 0) return 1;
     return -1;
+#endif
 }
 
 
@@ -1918,11 +2224,17 @@
 	}
 	return rb_equal(str2, str1);
     }
+#if WITH_OBJC
+    if (CFEqual((CFTypeRef)str1, (CFTypeRef)str2))
+	return Qtrue;
+#else
     if (!rb_str_comparable(str1, str2)) return Qfalse;
     if (RSTRING_LEN(str1) == (len = RSTRING_LEN(str2)) &&
 	memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2), len) == 0) {
 	return Qtrue;
     }
+#endif
+
     return Qfalse;
 }
 
@@ -1939,10 +2251,15 @@
     if (TYPE(str2) != T_STRING || RSTRING_LEN(str1) != RSTRING_LEN(str2))
 	return Qfalse;
 
+#if WITH_OBJC
+    if (CFEqual((CFTypeRef)str1, (CFTypeRef)str2))
+	return Qtrue;
+#else
     if (!rb_str_comparable(str1, str2)) return Qfalse;
     if (memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2),
 	       lesser(RSTRING_LEN(str1), RSTRING_LEN(str2))) == 0)
 	return Qtrue;
+#endif
 
     return Qfalse;
 }
@@ -2013,6 +2330,10 @@
 static VALUE
 rb_str_casecmp(VALUE str1, VALUE str2)
 {
+#if WITH_OBJC
+    return INT2FIX(CFStringCompare((CFStringRef)str1, (CFStringRef)str2,
+	kCFCompareCaseInsensitive));
+#else
     long len;
     rb_encoding *enc;
     char *p1, *p1end, *p2, *p2end;
@@ -2042,11 +2363,21 @@
     if (RSTRING_LEN(str1) == RSTRING_LEN(str2)) return INT2FIX(0);
     if (RSTRING_LEN(str1) > RSTRING_LEN(str2)) return INT2FIX(1);
     return INT2FIX(-1);
+#endif
 }
 
 static long
 rb_str_index(VALUE str, VALUE sub, long offset)
 {
+#if WITH_OBJC
+    CFRange r;
+    return (CFStringFindWithOptions((CFStringRef)str, 
+		(CFStringRef)sub,
+		CFRangeMake(offset, CFStringGetLength((CFStringRef)str) - offset),
+		0,
+		&r))
+	? r.location : -1;
+#else
     long pos;
     char *s, *sptr;
     long len, slen;
@@ -2084,9 +2415,9 @@
 	s = t;
     }
     return pos + offset;
+#endif
 }
 
-
 /*
  *  call-seq:
  *     str.index(substring [, offset])   => fixnum or nil
@@ -2159,6 +2490,15 @@
 static long
 rb_str_rindex(VALUE str, VALUE sub, long pos)
 {
+#if WITH_OBJC
+    CFRange r;
+    return (CFStringFindWithOptions((CFStringRef)str, 
+		(CFStringRef)sub,
+		CFRangeMake(pos, CFStringGetLength((CFStringRef)str) - pos),
+		kCFCompareBackwards,
+		&r))
+	? r.location : -1;
+#else
     long len, slen;
     char *s, *sbeg, *e, *t;
     rb_encoding *enc;
@@ -2192,6 +2532,7 @@
 	pos--;
     }
     return -1;
+#endif
 }
 
 
@@ -2509,6 +2850,9 @@
 VALUE
 rb_str_succ(VALUE orig)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
     rb_encoding *enc;
     VALUE str;
     char *sbeg, *s, *e;
@@ -2565,6 +2909,7 @@
     RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0';
     rb_enc_str_coderange(str);
     return str;
+#endif
 }
 
 
@@ -2774,6 +3119,10 @@
 rb_str_splice_0(VALUE str, long beg, long len, VALUE val)
 {
     rb_str_modify(str);
+#if WITH_OBJC
+    CFStringReplace((CFMutableStringRef)str, CFRangeMake(beg, len), 
+	(CFStringRef)val);
+#else
     if (len < RSTRING_LEN(val)) {
 	/* expand string */
 	RESIZE_CAPA(str, RSTRING_LEN(str) + RSTRING_LEN(val) - len + 1);
@@ -2795,22 +3144,29 @@
 	RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0';
     }
     OBJ_INFECT(str, val);
+#endif
 }
 
 static void
 rb_str_splice(VALUE str, long beg, long len, VALUE val)
 {
     long slen;
+#if !WITH_OBJC
     char *p, *e;
     rb_encoding *enc;
     int singlebyte = single_byte_optimizable(str);
+#endif
 
     if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
 
     StringValue(val);
     rb_str_modify(str);
+#if WITH_OBJC
+    slen = CFStringGetLength((CFStringRef)str);
+#else
     enc = rb_enc_check(str, val);
     slen = str_strlen(str, enc);
+#endif
 
     if (slen < beg) {
       out_of_range:
@@ -2825,6 +3181,9 @@
     if (slen < len || slen < beg + len) {
 	len = slen - beg;
     }
+#if WITH_OBJC
+    rb_str_splice_0(str, beg, len, val);
+#else
     p = str_nth(RSTRING_PTR(str), RSTRING_END(str), beg, enc, singlebyte);
     if (!p) p = RSTRING_END(str);
     e = str_nth(p, RSTRING_END(str), len, enc, singlebyte);
@@ -2834,6 +3193,7 @@
     len = e - p;		/* physical length */
     rb_str_splice_0(str, beg, len, val);
     rb_enc_associate(str, enc);
+#endif
 }
 
 void
@@ -3104,7 +3464,9 @@
 	regs = RMATCH_REGS(match);
 
 	if (iter || !NIL_P(hash)) {
+#if !WITH_OBJC
 	    char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);
+#endif
 
             if (iter) {
                 rb_match_busy(match);
@@ -3114,13 +3476,16 @@
                 repl = rb_hash_aref(hash, rb_str_subseq(str, BEG(0), END(0) - BEG(0)));
                 repl = rb_obj_as_string(repl);
             }
+#if !WITH_OBJC
 	    str_mod_check(str, p, len);
+#endif
 	    str_frozen_check(str);
 	    if (iter) rb_backref_set(match);
 	}
 	else {
 	    repl = rb_reg_regsub(repl, str, regs, pat);
 	}
+#if !WITH_OBJC
         enc = rb_enc_compatible(str, repl);
         if (!enc) {
             rb_encoding *str_enc = STR_ENC_GET(str);
@@ -3133,7 +3498,11 @@
             }
             enc = STR_ENC_GET(repl);
         }
+#endif
 	rb_str_modify(str);
+#if WITH_OBJC
+	rb_str_splice(str, BEG(0), END(0) - BEG(0), repl);
+#else
 	rb_enc_associate(str, enc);
 	if (OBJ_TAINTED(repl)) tainted = 1;
 	if (ENC_CODERANGE_UNKNOWN < cr && cr < ENC_CODERANGE_BROKEN) {
@@ -3155,6 +3524,7 @@
 	RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0';
 	ENC_CODERANGE_SET(str, cr);
 	if (tainted) OBJ_TAINT(str);
+#endif
 
 	return str;
     }
@@ -3238,12 +3608,19 @@
 	return rb_str_dup(str);
     }
 
+#if WITH_OBJC
+    dest = rb_str_new5(str, NULL, 0);
+    slen = RSTRING_LEN(str);
+    sp = RSTRING_PTR(str);
+    cp = sp;
+#else
     blen = RSTRING_LEN(str) + 30; /* len + margin */
     dest = rb_str_buf_new(blen);
     sp = RSTRING_PTR(str);
     slen = RSTRING_LEN(str);
     cp = sp;
     str_enc = STR_ENC_GET(str);
+#endif
 
     do {
 	n++;
@@ -3258,7 +3635,9 @@
                 val = rb_hash_aref(hash, rb_str_subseq(str, BEG(0), END(0) - BEG(0)));
                 val = rb_obj_as_string(val);
             }
+#if !WITH_OBJC
 	    str_mod_check(str, sp, slen);
+#endif
 	    if (bang) str_frozen_check(str);
 	    if (val == dest) { 	/* paranoid check [ruby-dev:24827] */
 		rb_raise(rb_eRuntimeError, "block should not cheat");
@@ -3273,7 +3652,7 @@
 
 	len = beg - offset;	/* copy pre-match substr */
         if (len) {
-            rb_enc_str_buf_cat(dest, cp, len, str_enc);
+	    rb_enc_str_buf_cat(dest, cp, len, str_enc);
         }
 
         rb_str_buf_append(dest, val);
@@ -3284,30 +3663,37 @@
 	     * Always consume at least one character of the input string
 	     * in order to prevent infinite loops.
 	     */
-	    if (RSTRING_LEN(str) <= END(0)) break;
-	    len = rb_enc_mbclen(RSTRING_PTR(str)+END(0), RSTRING_END(str), str_enc);
-            rb_enc_str_buf_cat(dest, RSTRING_PTR(str)+END(0), len, str_enc);
+	    if (slen <= END(0)) break;
+	    len = rb_enc_mbclen(sp+END(0), sp+slen, str_enc);
+            rb_enc_str_buf_cat(dest, sp+END(0), len, str_enc);
 	    offset = END(0) + len;
 	}
-	cp = RSTRING_PTR(str) + offset;
-	if (offset > RSTRING_LEN(str)) break;
+	cp = sp + offset;
+	if (offset > slen) break;
 	beg = rb_reg_search(pat, str, offset, 0);
     } while (beg >= 0);
-    if (RSTRING_LEN(str) > offset) {
-        rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
+    if (slen > offset) {
+        rb_enc_str_buf_cat(dest, cp, slen - offset, str_enc);
     }
     rb_backref_set(match);
+#if WITH_OBJC
     if (bang) {
+	CFStringReplaceAll((CFMutableStringRef)str, (CFStringRef)dest);
+    }
+    else {
+	str = dest;
+    }
+#else
+    if (bang) {
         rb_str_shared_replace(str, dest);
     }
     else {
 	RBASIC(dest)->klass = rb_obj_class(str);
-#if WITH_OBJC
 	RBASIC(dest)->isa = RCLASS_OCID(RBASIC(dest)->klass);
-#endif
 	OBJ_INFECT(dest, str);
 	str = dest;
     }
+#endif
 
     if (tainted) OBJ_TAINT(str);
     return str;
@@ -3386,7 +3772,10 @@
 {
     long len;
     if (str == str2) return str;
-
+#if WITH_OBJC
+    rb_str_modify(str);
+    CFStringReplaceAll((CFMutableStringRef)str, (CFStringRef)str2);
+#else
     StringValue(str2);
     len = RSTRING_LEN(str2);
     if (STR_ASSOC_P(str2)) {
@@ -3410,6 +3799,7 @@
 
     OBJ_INFECT(str, str2);
     rb_enc_cr_str_exact_copy(str, str2);
+#endif
     return str;
 }
 
@@ -3426,6 +3816,11 @@
 static VALUE
 rb_str_clear(VALUE str)
 {
+#if WITH_OBJC
+    rb_str_modify(str);
+    CFStringDelete((CFMutableStringRef)str, 
+	CFRangeMake(0, CFStringGetLength((CFStringRef)str)));
+#else
     /* rb_str_modify() */	/* no need for str_make_independent */
     if (str_independent(str) && !STR_EMBED_P(str)) {
 	free(RSTRING_PTR(str));
@@ -3434,6 +3829,7 @@
     STR_SET_EMBED_LEN(str, 0);
     RSTRING_PTR(str)[0] = 0;
     ENC_CODERANGE_CLEAR(str);
+#endif
     return str;
 }
 
@@ -3463,10 +3859,11 @@
 rb_str_getbyte(VALUE str, VALUE index)
 {
     long pos = NUM2LONG(index);
+    long n = RSTRING_LEN(str);
 
     if (pos < 0)
-        pos += RSTRING_LEN(str);
-    if (pos < 0 ||  RSTRING_LEN(str) <= pos)
+        pos += n;
+    if (pos < 0 || n <= pos)
         return Qnil;
 
     return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
@@ -3483,21 +3880,79 @@
 {
     long pos = NUM2LONG(index);
     int byte = NUM2INT(value);
+    long n = RSTRING_LEN(str);
 
     rb_str_modify(str);
 
-    if (pos < -RSTRING_LEN(str) || RSTRING_LEN(str) <= pos)
+    if (pos < -n || n <= pos)
         rb_raise(rb_eIndexError, "index %ld out of string", pos);
     if (pos < 0)
-        pos += RSTRING_LEN(str);
+        pos += n;
 
     RSTRING_PTR(str)[pos] = byte;
+#if WITH_OBJC
+    RSTRING_SYNC(str);
+#endif
 
     return value;
 }
 
+
 /*
  *  call-seq:
+ *     str.reverse!   => str
+ *  
+ *  Reverses <i>str</i> in place.
+ */
+
+static VALUE
+rb_str_reverse_bang(VALUE str)
+{
+#if WITH_OBJC
+    CFIndex i, n;
+    UniChar *buffer;
+
+    n = CFStringGetLength((CFStringRef)str);
+    if (n <= 1)
+	return rb_str_dup(str);
+   
+    buffer = (UniChar *)CFStringGetCharactersPtr((CFStringRef)str);
+    if (buffer == NULL) {
+	buffer = (UniChar *)alloca(sizeof(UniChar) * n);
+    	CFStringGetCharacters((CFStringRef)buffer, CFRangeMake(0, n), buffer);
+    }
+    for (i = 0; i < (n / 2); i++) {
+	UniChar c = buffer[i];
+	buffer[i] = buffer[n - i];
+	buffer[n - i] = c;
+    }
+    CFStringDelete((CFMutableStringRef)str, CFRangeMake(0, n));
+    CFStringAppendCharacters((CFMutableStringRef)str, (const UniChar *)buffer, n);
+#else
+    char *s, *e, c;
+
+    if (RSTRING_LEN(str) > 1) {
+	rb_str_modify(str);
+	s = RSTRING_PTR(str);
+	e = RSTRING_END(str) - 1;
+
+	if (single_byte_optimizable(str)) {
+	    while (s < e) {
+		c = *s;
+		*s++ = *e;
+ 		*e-- = c;
+	    }
+	}
+	else {
+	    rb_str_shared_replace(str, rb_str_reverse(str));
+	}
+    }
+#endif
+    return str;
+}
+
+/*
+ *  call-seq:
  *     str.reverse   => new_str
  *  
  *  Returns a new string with the characters from <i>str</i> in reverse order.
@@ -3508,6 +3963,11 @@
 static VALUE
 rb_str_reverse(VALUE str)
 {
+#if WITH_OBJC
+    VALUE obj = rb_str_dup(str);
+    rb_str_reverse_bang(rb_str_dup(str));
+    return obj;
+#else
     rb_encoding *enc;
     VALUE obj;
     char *s, *e, *p;
@@ -3539,43 +3999,11 @@
     rb_enc_cr_str_copy_for_substr(obj, str);
 
     return obj;
+#endif
 }
 
-
 /*
  *  call-seq:
- *     str.reverse!   => str
- *  
- *  Reverses <i>str</i> in place.
- */
-
-static VALUE
-rb_str_reverse_bang(VALUE str)
-{
-    char *s, *e, c;
-
-    if (RSTRING_LEN(str) > 1) {
-	rb_str_modify(str);
-	s = RSTRING_PTR(str);
-	e = RSTRING_END(str) - 1;
-
-	if (single_byte_optimizable(str)) {
-	    while (s < e) {
-		c = *s;
-		*s++ = *e;
- 		*e-- = c;
-	    }
-	}
-	else {
-	    rb_str_shared_replace(str, rb_str_reverse(str));
-	}
-    }
-    return str;
-}
-
-
-/*
- *  call-seq:
  *     str.include? other_str   => true or false
  *     str.include? fixnum      => true or false
  *  
@@ -3667,10 +4095,18 @@
  *  Returns the receiver.
  */
 
+#if WITH_OBJC
+static bool rb_objc_str_is_pure(VALUE);
+#endif
+
 static VALUE
 rb_str_to_s(VALUE str)
 {
+#if WITH_OBJC
+    if (rb_objc_str_is_pure(str)) {
+#else
     if (rb_obj_class(str) != rb_cString) {
+#endif
 	VALUE dup = str_alloc(rb_cString);
 	rb_str_replace(dup, str);
 	return dup;
@@ -3710,6 +4146,10 @@
 VALUE
 rb_str_inspect(VALUE str)
 {
+#if WITH_OBJC
+    /* TODO */
+    return rb_str_dup(str);
+#else
     rb_encoding *enc = STR_ENC_GET(str);
     char *p, *pend;
     VALUE result = rb_str_buf_new2("");
@@ -3789,6 +4229,7 @@
 
     OBJ_INFECT(result, str);
     return result;
+#endif
 }
 
 #define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
@@ -3923,6 +4364,15 @@
 static VALUE
 rb_str_upcase_bang(VALUE str)
 {
+#if WITH_OBJC
+    CFHashCode h;
+    rb_str_modify(str);
+    h = CFHash((CFTypeRef)str);
+    CFStringUppercase((CFMutableStringRef)str, NULL);
+    if (h == CFHash((CFTypeRef)str))
+	return Qnil;
+    return str;
+#else
     rb_encoding *enc;
     char *s, *send;
     int modify = 0;
@@ -3945,6 +4395,7 @@
     ENC_CODERANGE_SET(str, cr);
     if (modify) return str;
     return Qnil;
+#endif
 }
 
 
@@ -3981,6 +4432,15 @@
 static VALUE
 rb_str_downcase_bang(VALUE str)
 {
+#if WITH_OBJC
+    CFHashCode h;
+    rb_str_modify(str);
+    h = CFHash((CFTypeRef)str);
+    CFStringLowercase((CFMutableStringRef)str, NULL);
+    if (h == CFHash((CFTypeRef)str))
+	return Qnil;
+    return str;
+#else
     rb_encoding *enc;
     char *s, *send;
     int modify = 0;
@@ -4003,6 +4463,7 @@
     ENC_CODERANGE_SET(str, cr);
     if (modify) return str;
     return Qnil;
+#endif
 }
 
 
@@ -4044,6 +4505,21 @@
 static VALUE
 rb_str_capitalize_bang(VALUE str)
 {
+#if WITH_OBJC
+    UniChar c;
+    CFStringRef tmp;
+
+    rb_str_modify(str);
+    if (CFStringGetLength((CFStringRef)str) == 0)
+	return Qnil;
+    c = CFStringGetCharacterAtIndex((CFStringRef)str, 0);
+    if (!iswlower(c))
+	return Qnil;
+    c = towupper(c);
+    tmp = CFStringCreateWithCharacters(NULL, &c, 1);
+    CFStringReplace((CFMutableStringRef)str, CFRangeMake(0, 1), tmp);
+    return str;
+#else
     rb_encoding *enc;
     char *s, *send;
     int modify = 0;
@@ -4073,6 +4549,7 @@
     ENC_CODERANGE_SET(str, cr);
     if (modify) return str;
     return Qnil;
+#endif
 }
 
 
@@ -4110,6 +4587,40 @@
 static VALUE
 rb_str_swapcase_bang(VALUE str)
 {
+#if WITH_OBJC
+    CFIndex i, n;
+    UniChar *buffer;
+    bool changed;
+
+    n = CFStringGetLength((CFStringRef)str);
+    if (n == 0)
+	return rb_str_dup(str);
+   
+    buffer = (UniChar *)CFStringGetCharactersPtr((CFStringRef)str);
+    if (buffer == NULL) {
+	buffer = (UniChar *)alloca(sizeof(UniChar) * n);
+    	CFStringGetCharacters((CFStringRef)str, CFRangeMake(0, n), buffer);
+    }
+    for (i = 0, changed = false; i < n; i++) {
+	UniChar c = buffer[i];
+	if (iswlower(c)) {
+	    c = towupper(c);
+	}
+	else if (iswupper(c)) {
+	    c = towlower(c);
+	}
+	else {
+	    continue;
+	}
+	changed = true;
+	buffer[i] = c;
+    }
+    if (!changed)
+	return Qnil;
+    CFStringDelete((CFMutableStringRef)str, CFRangeMake(0, n));
+    CFStringAppendCharacters((CFMutableStringRef)str, (const UniChar *)buffer, n);
+    return str;
+#else
     rb_encoding *enc;
     char *s, *send;
     int modify = 0;
@@ -4137,6 +4648,7 @@
     ENC_CODERANGE_SET(str, cr);
     if (modify) return str;
     return Qnil;
+#endif
 }
 
 
@@ -4160,6 +4672,7 @@
     return str;
 }
 
+#if !WITH_OBJC
 typedef unsigned char *USTR;
 
 struct tr {
@@ -4401,8 +4914,8 @@
     }
     return Qnil;
 }
+#endif
 
-
 /*
  *  call-seq:
  *     str.tr!(from_str, to_str)   => str or nil
@@ -4415,7 +4928,12 @@
 static VALUE
 rb_str_tr_bang(VALUE str, VALUE src, VALUE repl)
 {
+#if WITH_OBJC
+    /* TODO */
+    rb_notimplement();
+#else
     return tr_trans(str, src, repl, 0);
+#endif
 }
 
 
@@ -4440,10 +4958,15 @@
 rb_str_tr(VALUE str, VALUE src, VALUE repl)
 {
     str = rb_str_dup(str);
+#if WITH_OBJC
+    rb_notimplement();
+#else
     tr_trans(str, src, repl, 0);
+#endif
     return str;
 }
 
+#if !WITH_OBJC
 static void
 tr_setup_table(VALUE str, char stable[256], int first, 
 	       VALUE *tablep, VALUE *ctablep, rb_encoding *enc)
@@ -4517,6 +5040,61 @@
     }
 }
 
+#else
+
+typedef void str_charset_find_cb
+(CFRange *, const CFRange *, CFStringRef, void *);
+
+static void
+str_charset_find(CFStringRef str, VALUE *charsets, int charset_count,
+		 str_charset_find_cb *cb, void *ctx)
+{
+    int i;
+    long n;
+    bool changed;
+    CFMutableCharacterSetRef charset;
+    CFRange search_range, result_range; 
+
+    if (charset_count == 0)
+	return;
+    n = CFStringGetLength((CFStringRef)str);
+    if (n == 0)
+    	return;
+
+    /* TODO this doesn't actually support tokens such as '^e' or 'a-z'. */ 
+    for (i = 0, charset = NULL; i < charset_count; i++) {
+	VALUE s = charsets[i];
+
+	StringValue(s);
+
+	if (charset == NULL) {
+	    charset = CFCharacterSetCreateMutable(NULL);
+	    CFCharacterSetAddCharactersInString(
+		(CFMutableCharacterSetRef)charset,
+		(CFStringRef)s);
+	}
+	else {
+	    CFCharacterSetRef subset;
+	    subset = CFCharacterSetCreateWithCharactersInString(NULL, 
+		(CFStringRef)s);
+	    CFCharacterSetUnion((CFMutableCharacterSetRef)charset, subset);
+	}
+    }
+
+    search_range = CFRangeMake(0, n);
+    while (search_range.length != 0 
+	    && CFStringFindCharacterFromSet(
+		(CFStringRef)str,
+		(CFCharacterSetRef)charset,
+		search_range,
+		0,
+		&result_range)) {
+	(*cb)(&search_range, (const CFRange *)&result_range, str, ctx);
+    }
+}
+
+#endif
+
 /*
  *  call-seq:
  *     str.delete!([other_str]+)   => str or nil
@@ -4525,9 +5103,32 @@
  *  <code>nil</code> if <i>str</i> was not modified.
  */
 
+#if WITH_OBJC
+static void
+rb_str_delete_bang_cb(CFRange *search_range, const CFRange *result_range, 
+    CFStringRef str, void *ctx)
+{
+    CFStringDelete((CFMutableStringRef)str, *result_range);
+    search_range->length -= search_range->length;
+    *(bool *)ctx = true;
+}
+#endif
+
 static VALUE
 rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
 {
+#if WITH_OBJC
+    bool changed;
+    if (argc < 1)
+	rb_raise(rb_eArgError, "wrong number of arguments");
+    rb_str_modify(str);
+    changed = false;
+    str_charset_find((CFStringRef)str, argv, argc, rb_str_delete_bang_cb, 
+	&changed);
+    if (!changed)
+    	return Qnil;
+    return str;
+#else
     char squeez[256];
     rb_encoding *enc = 0;
     char *s, *send, *t;
@@ -4570,9 +5171,9 @@
     ENC_CODERANGE_SET(str, cr);
     if (modify) return str;
     return Qnil;
+#endif
 }
 
-
 /*
  *  call-seq:
  *     str.delete([other_str]+)   => new_str
@@ -4607,6 +5208,9 @@
 static VALUE
 rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
     char squeez[256];
     rb_encoding *enc = 0;
     VALUE del = 0, nodel = 0;
@@ -4651,6 +5255,7 @@
 
     if (modify) return str;
     return Qnil;
+#endif
 }
 
 
@@ -4689,7 +5294,11 @@
 static VALUE
 rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
     return tr_trans(str, src, repl, 1);
+#endif
 }
 
 
@@ -4710,7 +5319,7 @@
 rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
 {
     str = rb_str_dup(str);
-    tr_trans(str, src, repl, 1);
+    rb_str_tr_s_bang(str, src, repl);
     return str;
 }
 
@@ -4734,6 +5343,10 @@
 static VALUE
 rb_str_count(int argc, VALUE *argv, VALUE str)
 {
+#if WITH_OBJC
+    /* TODO could share the same logic than #delete */
+    rb_notimplement();
+#else
     char table[256];
     rb_encoding *enc = 0;
     VALUE del = 0, nodel = 0;
@@ -4765,6 +5378,7 @@
 	s += clen;
     }
     return INT2NUM(i);
+#endif
 }
 
 
@@ -4813,6 +5427,9 @@
 static VALUE
 rb_str_split_m(int argc, VALUE *argv, VALUE str)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
     rb_encoding *enc;
     VALUE spat;
     VALUE limit;
@@ -4962,6 +5579,7 @@
     }
 
     return result;
+#endif
 }
 
 VALUE
@@ -5024,6 +5642,43 @@
 static VALUE
 rb_str_each_line(int argc, VALUE *argv, VALUE str)
 {
+#if WITH_OBJC
+    VALUE rs;
+    CFArrayRef ranges;
+    long i, count, n, l;
+
+    if (rb_scan_args(argc, argv, "01", &rs) == 0) {
+	rs = rb_rs;
+    }
+    RETURN_ENUMERATOR(str, argc, argv);
+    if (NIL_P(rs)) {
+	rb_yield(str);
+	return str;
+    }
+    StringValue(rs);
+    n = CFStringGetLength((CFStringRef)str);
+    ranges = CFStringCreateArrayWithFindResults(NULL, (CFStringRef)str, 
+	(CFStringRef)rs, CFRangeMake(0, n), 0);
+    if (ranges == NULL) {
+	rb_yield(str);
+	return str;
+    }
+    for (i = l = 0, count = CFArrayGetCount(ranges); i < count; i++) {
+	CFRange *rs_range;
+       	CFRange sub_range;
+	UInt8 *buffer;
+
+	rs_range = (CFRange *)CFArrayGetValueAtIndex(ranges, i);
+	assert(rs_range->location > 0);
+	sub_range = CFRangeMake(l, rs_range->location);
+	buffer = (UInt8 *)alloca(sizeof(UInt8) * sub_range.length);
+	CFStringGetBytes((CFStringRef)str, sub_range,
+	    kCFStringEncodingUTF8, 0, false, buffer, sub_range.length, NULL);
+	rb_yield(rb_str_new((const char *)buffer, sub_range.length));
+	l = rs_range->location + rs_range->length;
+    }
+    return str;
+#else
     rb_encoding *enc;
     VALUE rs;
     int newline;
@@ -5108,6 +5763,7 @@
     }
 
     return str;
+#endif
 }
 
 
@@ -5140,11 +5796,15 @@
 static VALUE
 rb_str_each_byte(VALUE str)
 {
-    long i;
+    long n, i;
+    char *ptr;
 
     RETURN_ENUMERATOR(str, 0, 0);
-    for (i=0; i<RSTRING_LEN(str); i++) {
-	rb_yield(INT2FIX(RSTRING_PTR(str)[i] & 0xff));
+
+    n = RSTRING_LEN(str);
+    ptr = RSTRING_PTR(str);
+    for (i=0; i<n; i++) {
+	rb_yield(INT2FIX(ptr[i] & 0xff));
     }
     return str;
 }
@@ -5179,6 +5839,22 @@
 static VALUE
 rb_str_each_char(VALUE str)
 {
+#if WITH_OBJC
+    CFStringInlineBuffer buf;
+    long i, n;
+    n = CFStringGetLength((CFStringRef)str);
+    CFStringInitInlineBuffer((CFStringRef)str, &buf, CFRangeMake(0, n));
+    for (i = 0; i < n; i++) {
+	UniChar c;
+	VALUE s;
+
+	c = CFStringGetCharacterFromInlineBuffer(&buf, i);
+	s = rb_str_new(NULL, 0);
+	CFStringAppendCharacters((CFMutableStringRef)s, &c, 1);
+	rb_yield(s);
+    }
+    return str;
+#else
     int i, len, n;
     const char *ptr;
     rb_encoding *enc;
@@ -5193,8 +5869,10 @@
 	rb_yield(rb_str_subseq(str, i, n));
     }
     return str;
+#endif
 }
 
+#if !WITH_OBJC
 static long
 chopped_length(VALUE str)
 {
@@ -5212,6 +5890,7 @@
     }
     return p - beg;
 }
+#endif
 
 /*
  *  call-seq:
@@ -5225,6 +5904,16 @@
 static VALUE
 rb_str_chop_bang(VALUE str)
 {
+#if WITH_OBJC
+    long n;
+
+    n = CFStringGetLength((CFStringRef)str);
+    if (n == 0)
+	return Qnil;
+    rb_str_modify(str);
+    CFStringDelete((CFMutableStringRef)str, CFRangeMake(n - 1, 1));
+    return str;
+#else
     if (RSTRING_LEN(str) > 0) {
 	long len;
 	rb_str_modify(str);
@@ -5234,6 +5923,7 @@
 	return str;
     }
     return Qnil;
+#endif
 }
 
 
@@ -5257,10 +5947,16 @@
 static VALUE
 rb_str_chop(VALUE str)
 {
+#if WITH_OBJC
+    VALUE str2 = rb_str_dup(str);
+    rb_str_chop_bang(str2);
+    return str2;
+#else
     VALUE str2 = rb_str_new5(str, RSTRING_PTR(str), chopped_length(str));
     rb_enc_cr_str_copy_for_substr(str2, str);
     OBJ_INFECT(str2, str);
     return str2;
+#endif
 }
 
 
@@ -5275,6 +5971,34 @@
 static VALUE
 rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
 {
+#if WITH_OBJC
+    VALUE rs;
+    long n;
+    CFRange range_result;
+
+    rb_scan_args(argc, argv, "01", &rs);
+    rb_str_modify(str);
+    n = CFStringGetLength((CFStringRef)str);
+    if (NIL_P(rs)) {
+	CFCharacterSetRef charset;
+
+        charset = CFCharacterSetGetPredefined(kCFCharacterSetNewline);
+	if (!CFStringFindCharacterFromSet((CFStringRef)str, charset, 
+	    CFRangeMake(0, n), kCFCompareBackwards | kCFCompareAnchored, 
+	    &range_result))
+	    return Qnil;
+    }
+    else {
+	StringValue(rs);
+	range_result = CFStringFind((CFStringRef)str, (CFStringRef)rs,
+	    kCFCompareBackwards);
+    }
+    if (range_result.length == 0 
+	|| range_result.location + range_result.length < n)
+	return Qnil;
+    CFStringDelete((CFMutableStringRef)str, range_result);
+    return str;
+#else
     rb_encoding *enc;
     VALUE rs;
     int newline;
@@ -5366,6 +6090,7 @@
 	return str;
     }
     return Qnil;
+#endif
 }
 
 
@@ -5408,9 +6133,58 @@
  *     "hello".lstrip!      #=> nil
  */
 
+#if WITH_OBJC
 static VALUE
+rb_str_strip_bang2(VALUE str, int direction)
+{
+    long i, n, orig_n;
+    CFStringInlineBuffer buf;
+    CFCharacterSetRef charset;
+    bool changed;
+
+    rb_str_modify(str);
+    n = orig_n = CFStringGetLength((CFStringRef)str);
+    if (n == 0)
+	return Qnil;
+    CFStringInitInlineBuffer((CFStringRef)str, &buf, CFRangeMake(0, n));
+    charset = CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline);
+    changed = false;
+
+    if (direction >= 0) {
+	for (i = n - 1; i >= 0; i--) {
+	    UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, i);
+	    if (!CFCharacterSetIsCharacterMember(charset, c))
+		break;
+	}
+	if (i < n - 1) {
+	    CFRange range = CFRangeMake(i, n);
+	    CFStringDelete((CFMutableStringRef)str, range);
+	    n -= range.length;	    
+	}
+    }
+
+    if (direction <= 0) {
+	for (i = 0; i < n; i++) {
+	    UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, i);
+	    if (!CFCharacterSetIsCharacterMember(charset, c))
+		break;
+	}
+	if (i > 0) {
+	    CFRange range = CFRangeMake(i, n);
+	    CFStringDelete((CFMutableStringRef)str, range);
+	}
+    }
+
+    return orig_n != n ? str : Qnil;
+}
+#endif
+
+static VALUE
 rb_str_lstrip_bang(VALUE str)
 {
+#if WITH_OBJC
+    return rb_str_strip_bang2(str, -1);
+#else
     rb_encoding *enc;
     char *s, *t, *e;
 
@@ -5435,6 +6209,7 @@
 	return str;
     }
     return Qnil;
+#endif
 }
 
 
@@ -5473,6 +6248,9 @@
 static VALUE
 rb_str_rstrip_bang(VALUE str)
 {
+#if WITH_OBJC
+    return rb_str_strip_bang2(str, 1);
+#else
     rb_encoding *enc;
     char *s, *t, *e;
     int space_seen = Qfalse;
@@ -5502,6 +6280,7 @@
 	return str;
     }
     return Qnil;
+#endif
 }
 
 
@@ -5536,11 +6315,15 @@
 static VALUE
 rb_str_strip_bang(VALUE str)
 {
+#if WITH_OBJC
+    return rb_str_strip_bang2(str, 0);
+#else
     VALUE l = rb_str_lstrip_bang(str);
     VALUE r = rb_str_rstrip_bang(str);
 
     if (NIL_P(l) && NIL_P(r)) return Qnil;
     return str;
+#endif
 }
 
 
@@ -5570,7 +6353,9 @@
     struct re_registers *regs;
     long i;
 
+#if !WITH_OBJC
     enc = STR_ENC_GET(str);
+#endif
     if (rb_reg_search(pat, str, *start, 0) >= 0) {
 	match = rb_backref_get();
 	regs = RMATCH_REGS(match);
@@ -5578,10 +6363,12 @@
 	    /*
 	     * Always consume at least one character of the input string
 	     */
+#if !WITH_OBJC
 	    if (RSTRING_LEN(str) > END(0))
 		*start = END(0)+rb_enc_mbclen(RSTRING_PTR(str)+END(0),
 					      RSTRING_END(str), enc);
 	    else
+#endif
 		*start = END(0)+1;
 	}
 	else {
@@ -5737,8 +6524,9 @@
     if (RSTRING_LEN(salt) < 2)
 	rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
 
-    if (RSTRING_PTR(str)) s = RSTRING_PTR(str);
-    else s = "";
+    s = RSTRING_PTR(str);
+    if (s == NULL)
+	s = "";
     result = rb_str_new2(crypt(s, RSTRING_PTR(salt)));
     OBJ_INFECT(result, str);
     OBJ_INFECT(result, salt);
@@ -5769,7 +6557,11 @@
 VALUE
 rb_str_intern(VALUE s)
 {
+#if WITH_OBJC
+    VALUE str = s;
+#else
     VALUE str = RB_GC_GUARD(s);
+#endif
     ID id;
 
     if (OBJ_TAINTED(str) && rb_safe_level() >= 1) {
@@ -5779,7 +6571,6 @@
     return ID2SYM(id);
 }
 
-
 /*
  *  call-seq:
  *     str.ord   => integer
@@ -5792,11 +6583,18 @@
 VALUE
 rb_str_ord(VALUE s)
 {
+#if WITH_OBJC
+    if (CFStringGetLength((CFStringRef)s) == 0)
+	rb_raise(rb_eArgError, "empty string");
+    return INT2NUM(CFStringGetCharacterAtIndex((CFStringRef)s, 0));
+#else
     int c;
 
     c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
     return INT2NUM(c);
+#endif
 }
+
 /*
  *  call-seq:
  *     str.sum(n=16)   => integer
@@ -5856,9 +6654,65 @@
     }
 }
 
+#if WITH_OBJC
+static inline void
+rb_str_justify0(VALUE str, VALUE pad, long width, long padwidth, long index)
+{
+    do {
+	if (padwidth > width) {
+	    pad = (VALUE)CFStringCreateWithSubstring(
+		    NULL,
+		    (CFStringRef)pad,
+		    CFRangeMake(0, width));
+	}
+	CFStringInsert((CFMutableStringRef)str, index, (CFStringRef)pad);
+	width -= padwidth;	
+    }
+    while (width > 0);
+}
+#endif
+
 static VALUE
 rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
 {
+#if WITH_OBJC
+    VALUE w, pad;
+    long n, width, padwidth;
+
+    rb_scan_args(argc, argv, "11", &w, &pad);
+    width = NUM2LONG(w);
+    n = CFStringGetLength((CFStringRef)str);
+   
+    str =  rb_str_dup(str);
+    if (width < 0 || width <= n)
+	return str;
+    width -= n;
+
+    if (NIL_P(pad)) {
+	pad = rb_str_new(" ", 1);
+	padwidth = 1;
+    }
+    else {
+	StringValue(pad);
+	padwidth = CFStringGetLength((CFStringRef)pad);
+    }
+
+    if (jflag == 'c') {
+	rb_str_justify0(str, pad, ceil(width / 2.0), padwidth, n);
+	rb_str_justify0(str, pad, floor(width / 2.0), padwidth, 0);
+    }
+    else if (jflag == 'l') {
+	rb_str_justify0(str, pad, width, padwidth, 0);
+    }
+    else if (jflag == 'r') {
+	rb_str_justify0(str, pad, width, padwidth, n);
+    }
+    else {
+	rb_bug("invalid jflag");
+    }
+
+    return str;
+#else
     rb_encoding *enc;
     VALUE w;
     long width, len, flen = 1, fclen = 1;
@@ -5933,6 +6787,7 @@
     if (!NIL_P(pad)) OBJ_INFECT(res, pad);
     rb_enc_associate(res, enc);
     return res;
+#endif
 }
 
 
@@ -6012,6 +6867,7 @@
 {
     long pos;
     int regex = Qfalse;
+    long strlen, seplen;
 
     if (TYPE(sep) == T_REGEXP) {
 	pos = rb_reg_search(sep, str, 0, 0);
@@ -6026,6 +6882,7 @@
 		     rb_obj_classname(sep));
 	}
 	pos = rb_str_index(str, sep, 0);
+	seplen = CFStringGetLength((CFStringRef)sep);
     }
     if (pos < 0) {
       failed:
@@ -6033,12 +6890,14 @@
     }
     if (regex) {
 	sep = rb_str_subpat(str, sep, 0);
-	if (pos == 0 && RSTRING_LEN(sep) == 0) goto failed;
+	seplen = CFStringGetLength((CFStringRef)sep);
+	if (pos == 0 && seplen == 0) goto failed;
     }
+    strlen = CFStringGetLength((CFStringRef)str);
     return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
 		          sep,
-		          rb_str_subseq(str, pos+RSTRING_LEN(sep),
-					     RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
+		          rb_str_subseq(str, pos+seplen,
+					     strlen-pos-seplen));
 }
 
 /*
@@ -6059,6 +6918,7 @@
 {
     long pos = RSTRING_LEN(str);
     int regex = Qfalse;
+    long strlen;
 
     if (TYPE(sep) == T_REGEXP) {
 	pos = rb_reg_search(sep, str, pos, 1);
@@ -6081,9 +6941,10 @@
     if (regex) {
 	sep = rb_reg_nth_match(0, rb_backref_get());
     }
+    strlen = CFStringGetLength((CFStringRef)str);
     return rb_ary_new3(3, rb_str_substr(str, 0, pos),
 		          sep,
-		          rb_str_substr(str,pos+str_strlen(sep,STR_ENC_GET(sep)),RSTRING_LEN(str)));
+		          rb_str_substr(str,pos+str_strlen(sep,STR_ENC_GET(sep)),strlen));
 }
 
 /*
@@ -6101,10 +6962,15 @@
     for (i=0; i<argc; i++) {
 	VALUE tmp = rb_check_string_type(argv[i]);
 	if (NIL_P(tmp)) continue;
+#if WITH_OBJC
+	if (CFStringHasPrefix((CFStringRef)str, (CFStringRef)tmp))
+	    return Qtrue;
+#else
 	rb_enc_check(str, tmp);
 	if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue;
 	if (memcmp(RSTRING_PTR(str), RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0)
 	    return Qtrue;
+#endif
     }
     return Qfalse;
 }
@@ -6126,6 +6992,10 @@
     for (i=0; i<argc; i++) {
 	VALUE tmp = rb_check_string_type(argv[i]);
 	if (NIL_P(tmp)) continue;
+#if WITH_OBJC
+	if (CFStringHasSuffix((CFStringRef)str, (CFStringRef)tmp))
+	    return Qtrue;
+#else
 	enc = rb_enc_check(str, tmp);
 	if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue;
 	p = RSTRING_PTR(str);
@@ -6134,6 +7004,7 @@
 	    continue;
 	if (memcmp(s, RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0)
 	    return Qtrue;
+#endif
     }
     return Qfalse;
 }
@@ -6159,7 +7030,11 @@
 rb_str_force_encoding(VALUE str, VALUE enc)
 {
     str_modifiable(str);
+#if WITH_OBJC
+    rb_notimplement();
+#else
     rb_enc_associate(str, rb_to_encoding(enc));
+#endif
     return str;
 }
 
@@ -6177,9 +7052,13 @@
 static VALUE
 rb_str_valid_encoding_p(VALUE str)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
     int cr = rb_enc_str_coderange(str);
 
     return cr == ENC_CODERANGE_BROKEN ? Qfalse : Qtrue;
+#endif
 }
 
 /*
@@ -6195,9 +7074,13 @@
 static VALUE
 rb_str_is_ascii_only_p(VALUE str)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
     int cr = rb_enc_str_coderange(str);
 
     return cr == ENC_CODERANGE_7BIT ? Qtrue : Qfalse;
+#endif
 }
 
 /**********************************************************************
@@ -6478,6 +7361,21 @@
     return id;
 }
 
+#if WITH_OBJC
+static Class __nscfstring = NULL;
+
+#define NSCFSTRING() \
+    (__nscfstring == NULL \
+	? __nscfstring = (Class)objc_getClass("NSCFString") \
+	: __nscfstring)
+
+static bool
+rb_objc_str_is_pure(VALUE str)
+{
+    return *(Class *)str == NSCFSTRING();
+}
+#endif
+
 /*
  *  A <code>String</code> object holds and manipulates an arbitrary sequence of
  *  bytes, typically representing characters. String objects may be created
@@ -6495,8 +7393,12 @@
 Init_String(void)
 {
 #if WITH_OBJC
-    rb_cString  = rb_define_class("String",
-	rb_objc_import_class((Class)objc_getClass("NSMutableString")));
+    rb_cString = rb_objc_import_class((Class)objc_getClass("NSString"));
+    rb_cStringRuby =
+        rb_objc_import_class((Class)objc_getClass("NSMutableString"));
+    FL_UNSET(rb_cStringRuby, RCLASS_OBJC_IMPORTED);
+    rb_const_set(rb_cObject, rb_intern("String"), rb_cStringRuby);
+    /* TODO implement freeze/taint */
 #else
     rb_cString  = rb_define_class("String", rb_cObject);
 #endif
@@ -6516,7 +7418,12 @@
     rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
     rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
     rb_define_method(rb_cString, "insert", rb_str_insert, 2);
+#if !WITH_OBJC
+    /* This method cannot be defined because it exists in 
+     * NSString already. 
+     */
     rb_define_method(rb_cString, "length", rb_str_length, 0);
+#endif
     rb_define_method(rb_cString, "size", rb_str_length, 0);
     rb_define_method(rb_cString, "bytesize", rb_str_bytesize, 0);
     rb_define_method(rb_cString, "empty?", rb_str_empty, 0);

Modified: MacRuby/trunk/variable.c
===================================================================
--- MacRuby/trunk/variable.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/variable.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -161,9 +161,11 @@
 	    st_insert(RCLASS_IV_TBL(klass), classpath, path);
 	    st_delete(RCLASS_IV_TBL(klass), (st_data_t*)&classid, 0);
 	}
+#if !WITH_OBJC
 	if (TYPE(path) != T_STRING) {
 	    rb_bug("class path is not set properly");
 	}
+#endif
 	return path;
     }
     return find_class_path(klass);

Modified: MacRuby/trunk/vm.c
===================================================================
--- MacRuby/trunk/vm.c	2008-04-08 00:53:00 UTC (rev 135)
+++ MacRuby/trunk/vm.c	2008-04-12 01:10:16 UTC (rev 136)
@@ -1017,7 +1017,11 @@
     OP(LTLT, LTLT), (C(String), C(Array));
     OP(AREF, AREF), (C(Array), C(Hash));
     OP(ASET, ASET), (C(Array), C(Hash));
+#if WITH_OBJC
+    OP(Length, LENGTH), (C(Array), C(Hash));
+#else
     OP(Length, LENGTH), (C(Array), C(String), C(Hash));
+#endif
     OP(Succ, SUCC), (C(Fixnum), C(String), C(Time));
     OP(GT, GT), (C(Fixnum));
     OP(GE, GE), (C(Fixnum));

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20080411/76f6090a/attachment-0001.html


More information about the macruby-changes mailing list