/**********************************************************************
string.c -
$Author$
$Date$
created at: Mon Aug 9 17:12:58 JST 1993
Copyright (C) 1993-2006 Yukihiro Matsumoto
Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
Copyright (C) 2000 Information-technology Promotion Agency, Japan
**********************************************************************/
#include "ruby/ruby.h"
#include "ruby/re.h"
#define BEG(no) regs->beg[no]
#define END(no) regs->end[no]
#include <math.h>
#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
VALUE rb_cString;
VALUE rb_cSymbol;
#define STR_TMPLOCK FL_USER7
#define STR_NOEMBED FL_USER1
#define STR_ASSOC FL_USER3
#define STR_SHARED_P(s) FL_ALL(s, STR_NOEMBED|ELTS_SHARED)
#define STR_ASSOC_P(s) FL_ALL(s, STR_NOEMBED|STR_ASSOC)
#define STR_NOCAPA (STR_NOEMBED|ELTS_SHARED|STR_ASSOC)
#define STR_NOCAPA_P(s) (FL_TEST(s,STR_NOEMBED) && FL_ANY(s,ELTS_SHARED|STR_ASSOC))
#define STR_UNSET_NOCAPA(s) do {\
if (FL_TEST(s,STR_NOEMBED)) FL_UNSET(s,(ELTS_SHARED|STR_ASSOC));\
} while (0)
#define STR_SET_NOEMBED(str) do {\
FL_SET(str, STR_NOEMBED);\
STR_SET_EMBED_LEN(str, 0);\
} while (0)
#define STR_SET_EMBED(str) FL_UNSET(str, STR_NOEMBED)
#define STR_EMBED_P(str) (!FL_TEST(str, STR_NOEMBED))
#define STR_SET_EMBED_LEN(str, n) do { \
long tmp_n = (n);\
RBASIC(str)->flags &= ~RSTRING_EMBED_LEN_MASK;\
RBASIC(str)->flags |= (tmp_n) << RSTRING_EMBED_LEN_SHIFT;\
} while (0)
#define STR_SET_LEN(str, n) do { \
if (STR_EMBED_P(str)) {\
STR_SET_EMBED_LEN(str, n);\
}\
else {\
RSTRING(str)->as.heap.len = (n);\
}\
} while (0)
#define STR_DEC_LEN(str) do {\
if (STR_EMBED_P(str)) {\
long n = RSTRING_LEN(str);\
n--;\
STR_SET_EMBED_LEN(str, n);\
}\
else {\
RSTRING(str)->as.heap.len--;\
}\
} while (0)
#define RESIZE_CAPA(str,capacity) do {\
if (STR_EMBED_P(str)) {\
if ((capacity) > RSTRING_EMBED_LEN_MAX) {\
char *tmp = ALLOC_N(char, capacity+1);\
memcpy(tmp, RSTRING_PTR(str), RSTRING_LEN(str));\
RSTRING(str)->as.heap.ptr = tmp;\
RSTRING(str)->as.heap.len = RSTRING_LEN(str);\
STR_SET_NOEMBED(str);\
RSTRING(str)->as.heap.aux.capa = (capacity);\
}\
}\
else {\
REALLOC_N(RSTRING(str)->as.heap.ptr, char, (capacity)+1);\
if (!STR_NOCAPA_P(str))\
RSTRING(str)->as.heap.aux.capa = (capacity);\
}\
} while (0)
char *
rb_str_ptr(VALUE str) {
return RSTRING_PTR(str);
}
VALUE rb_fs;
static inline void
str_mod_check(VALUE s, char *p, long len)
{
if (RSTRING_PTR(s) != p || RSTRING_LEN(s) != len){
rb_raise(rb_eRuntimeError, "string modified");
}
}
static inline void
str_frozen_check(VALUE s)
{
if (OBJ_FROZEN(s)) {
rb_raise(rb_eRuntimeError, "string frozen");
}
}
static VALUE
str_alloc(VALUE klass)
{
NEWOBJ(str, struct RString);
OBJSETUP(str, klass, T_STRING);
if (klass == rb_cSymbol) {
/* need to be registered in table */
RBASIC(str)->klass = rb_cString;
}
str->as.heap.ptr = 0;
str->as.heap.len = 0;
str->as.heap.aux.capa = 0;
return (VALUE)str;
}
static VALUE
str_new(VALUE klass, const char *ptr, long len)
{
VALUE str;
if (len < 0) {
rb_raise(rb_eArgError, "negative string size (or size too big)");
}
str = str_alloc(klass);
if (len > RSTRING_EMBED_LEN_MAX) {
RSTRING(str)->as.heap.aux.capa = len;
RSTRING(str)->as.heap.ptr = ALLOC_N(char,len+1);
STR_SET_NOEMBED(str);
}
if (ptr) {
memcpy(RSTRING_PTR(str), ptr, len);
}
STR_SET_LEN(str, len);
RSTRING_PTR(str)[len] = '\0';
return str;
}
VALUE
rb_str_new(const char *ptr, long len)
{
return str_new(rb_cString, ptr, len);
}
VALUE
rb_str_new2(const char *ptr)
{
if (!ptr) {
rb_raise(rb_eArgError, "NULL pointer given");
}
return rb_str_new(ptr, strlen(ptr));
}
VALUE
rb_tainted_str_new(const char *ptr, long len)
{
VALUE str = rb_str_new(ptr, len);
OBJ_TAINT(str);
return str;
}
VALUE
rb_tainted_str_new2(const char *ptr)
{
VALUE str = rb_str_new2(ptr);
OBJ_TAINT(str);
return str;
}
static VALUE
str_new3(VALUE klass, VALUE str)
{
VALUE str2 = str_alloc(klass);
if (RSTRING_LEN(str) <= RSTRING_EMBED_LEN_MAX) {
STR_SET_EMBED(str);
memcpy(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str)+1);
STR_SET_EMBED_LEN(str2, RSTRING_LEN(str));
}
else {
FL_SET(str2, STR_NOEMBED);
RSTRING(str2)->as.heap.len = RSTRING_LEN(str);
RSTRING(str2)->as.heap.ptr = RSTRING_PTR(str);
RSTRING(str2)->as.heap.aux.shared = str;
FL_SET(str2, ELTS_SHARED);
}
return str2;
}
VALUE
rb_str_new3(VALUE str)
{
VALUE str2 = str_new3(rb_obj_class(str), str);
OBJ_INFECT(str2, str);
return str2;
}
static VALUE
str_new4(VALUE klass, VALUE str)
{
VALUE str2;
str2 = str_alloc(klass);
STR_SET_NOEMBED(str2);
RSTRING(str2)->as.heap.len = RSTRING_LEN(str);
RSTRING(str2)->as.heap.ptr = RSTRING_PTR(str);
if (STR_SHARED_P(str)) {
FL_SET(str2, ELTS_SHARED);
RSTRING(str2)->as.heap.aux.shared = RSTRING(str)->as.heap.aux.shared;
}
else {
FL_SET(str, ELTS_SHARED);
RSTRING(str)->as.heap.aux.shared = str2;
}
OBJ_INFECT(str2, str);
return str2;
}
VALUE
rb_str_new4(VALUE orig)
{
VALUE klass, str;
if (OBJ_FROZEN(orig)) return orig;
klass = rb_obj_class(orig);
if (STR_SHARED_P(orig) && (str = RSTRING(orig)->as.heap.aux.shared)
&& klass == RBASIC(str)->klass) {
|