ensure str_modify is called at the beginning of modifying methods

This commit is contained in:
Yukihiro Matsumoto
2012-06-02 04:12:23 +09:00
parent cd48737e11
commit b2d0f22dee
+110 -107
View File
@@ -38,25 +38,15 @@ static mrb_value get_pat(mrb_state *mrb, mrb_value pat, mrb_int quote);
static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2);
static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, long beg, long len);
#define RESIZE_CAPA(str,capacity) do {\
RSTRING(str)->buf = mrb_realloc(mrb, RSTRING(str)->buf, (capacity)+1);\
RSTRING_CAPA(str) = capacity;\
} while (0)
#define STR_SET_LEN(str, n) do { \
RSTRING(str)->len = (n);\
} while (0)
#define STR_DEC_LEN(str) do {\
RSTRING(str)->len--;\
#define RESIZE_CAPA(s,capacity) do {\
s->buf = mrb_realloc(mrb, s->buf, (capacity)+1);\
s->aux.capa = capacity;\
} while (0)
static void
str_modify(mrb_state *mrb, mrb_value str)
str_modify(mrb_state *mrb, struct RString *s)
{
struct RString *s = mrb_str_ptr(str);
if (MRB_STR_SHARED_P(str)) {
if (s->flags & MRB_STR_SHARED) {
char *ptr, *p;
long len;
@@ -70,7 +60,7 @@ str_modify(mrb_state *mrb, mrb_value str)
s->buf = ptr;
s->len = len;
s->aux.capa = len;
MRB_STR_UNSET_NOCAPA(str);
s->flags &= ~MRB_STR_SHARED;
}
}
@@ -78,18 +68,19 @@ mrb_value
mrb_str_resize(mrb_state *mrb, mrb_value str, int len)
{
int slen;
struct RString *s = mrb_str_ptr(str);
str_modify(mrb, str);
slen = RSTRING_LEN(str);
str_modify(mrb, s);
slen = s->len;
if (len != slen) {
if (slen < len || slen -len > 1024) {
RSTRING_PTR(str) = mrb_realloc(mrb, RSTRING_PTR(str), len+1);
s->buf = mrb_realloc(mrb, s->buf, len+1);
}
if (!MRB_STR_NOCAPA_P(str)) {
RSTRING_CAPA(str) = len;
if (!(s->flags & MRB_STR_SHARED)) {
s->aux.capa = len;
}
RSTRING(str)->len = len;
RSTRING(str)->buf[len] = '\0'; /* sentinel */
s->len = len;
s->buf[len] = '\0'; /* sentinel */
}
return str;
}
@@ -176,21 +167,21 @@ mrb_str_buf_new(mrb_state *mrb, int capa)
return mrb_obj_value(s);
}
mrb_value
str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, int len)
static void
str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, int len)
{
long capa, total, off = -1;
str_modify(mrb, str);
if (ptr >= RSTRING_PTR(str) && ptr <= RSTRING_END(str)) {
off = ptr - RSTRING_PTR(str);
str_modify(mrb, s);
if (ptr >= s->buf && ptr <= s->buf + s->len) {
off = ptr - s->buf;
}
if (len == 0) return mrb_fixnum_value(0);
capa = RSTRING_CAPA(str);
if (RSTRING_LEN(str) >= LONG_MAX - len) {
if (len == 0) return;
capa = s->aux.capa;
if (s->len >= LONG_MAX - len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string sizes too big");
}
total = RSTRING_LEN(str)+len;
total = s->len+len;
if (capa <= total) {
while (total > capa) {
if (capa + 1 >= LONG_MAX / 2) {
@@ -199,23 +190,22 @@ str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, int len)
}
capa = (capa + 1) * 2;
}
RESIZE_CAPA(str, capa);
RESIZE_CAPA(s, capa);
}
if (off != -1) {
ptr = RSTRING_PTR(str) + off;
ptr = s->buf + off;
}
memcpy(RSTRING_PTR(str) + RSTRING_LEN(str), ptr, len);
STR_SET_LEN(str, total);
RSTRING_PTR(str)[total] = '\0'; /* sentinel */
return str;
memcpy(s->buf + s->len, ptr, len);
s->len = total;
s->buf[total] = '\0'; /* sentinel */
}
mrb_value
mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, int len)
{
if (len == 0) return str;
return str_buf_cat(mrb, str, ptr, len);
str_buf_cat(mrb, mrb_str_ptr(str), ptr, len);
return str;
}
mrb_value
@@ -337,7 +327,7 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
struct RString *s1 = mrb_str_ptr(self), *s2;
int len;
str_modify(mrb, self);
str_modify(mrb, s1);
if (mrb_type(other) != MRB_TT_STRING) {
other = mrb_str_to_str(mrb, other);
}
@@ -863,19 +853,20 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str)
static mrb_value
mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str)
{
char *s, *send;
char *p, *pend;
int modify = 0;
struct RString *s = mrb_str_ptr(str);
str_modify(mrb, str);
if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return mrb_nil_value();
s = RSTRING_PTR(str); send = RSTRING_END(str);
if (ISLOWER(*s)) {
*s = toupper(*s);
str_modify(mrb, s);
if (s->len == 0 || !s->buf) return mrb_nil_value();
p = s->buf; pend = s->buf + s->len;
if (ISLOWER(*p)) {
*p = toupper(*p);
modify = 1;
}
while (++s < send) {
if (ISUPPER(*s)) {
*s = tolower(*s);
while (++p < pend) {
if (ISUPPER(*p)) {
*p = tolower(*p);
modify = 1;
}
}
@@ -920,21 +911,22 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
mrb_int newline;
char *p, *pp;
long len, rslen;
struct RString *s = mrb_str_ptr(str);
str_modify(mrb, str);
len = RSTRING_LEN(str);
str_modify(mrb, s);
len = s->len;
if (mrb_get_args(mrb, "|S", &rs) == 0) {
if (len == 0) return mrb_nil_value();
smart_chomp:
if (RSTRING_PTR(str)[len-1] == '\n') {
STR_DEC_LEN(str);
if (RSTRING_LEN(str) > 0 &&
RSTRING_PTR(str)[RSTRING_LEN(str)-1] == '\r') {
STR_DEC_LEN(str);
if (s->buf[len-1] == '\n') {
s->len--;
if (s->len > 0 &&
s->buf[s->len-1] == '\r') {
s->len--;
}
}
else if (RSTRING_PTR(str)[len-1] == '\r') {
STR_DEC_LEN(str);
else if (s->buf[len-1] == '\r') {
s->len--;
}
else {
return mrb_nil_value();
@@ -943,7 +935,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
}
if (len == 0 || mrb_nil_p(rs)) return mrb_nil_value();
p = RSTRING_PTR(str);
p = s->buf;
rslen = RSTRING_LEN(rs);
if (rslen == 0) {
while (len>0 && p[len-1] == '\n') {
@@ -951,8 +943,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (len>0 && p[len-1] == '\r')
len--;
}
if (len < RSTRING_LEN(str)) {
STR_SET_LEN(str, len);
if (len < s->len) {
s->len = len;
p[len] = '\0';
return str;
}
@@ -969,7 +961,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (p[len-1] == newline &&
(rslen <= 1 ||
memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) {
STR_SET_LEN(str, len - rslen);
s->len = len - rslen;
p[len] = '\0';
return str;
}
@@ -1017,18 +1009,20 @@ mrb_str_chomp(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
{
str_modify(mrb, str);
if (RSTRING_LEN(str) > 0) {
struct RString *s = mrb_str_ptr(str);
str_modify(mrb, s);
if (s->len > 0) {
int len;
len = RSTRING_LEN(str) - 1;
if (RSTRING_PTR(str)[len] == '\n') {
len = s->len - 1;
if (s->buf[len] == '\n') {
if (len > 0 &&
RSTRING_PTR(str)[len-1] == '\r') {
s->buf[len-1] == '\r') {
len--;
}
}
STR_SET_LEN(str, len);
RSTRING_PTR(str)[len] = '\0';
s->len = len;
s->buf[len] = '\0';
return str;
}
return mrb_nil_value();
@@ -1071,18 +1065,19 @@ mrb_str_chop(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
{
char *s, *send;
char *p, *pend;
int modify = 0;
struct RString *s = mrb_str_ptr(str);
str_modify(mrb, str);
s = RSTRING_PTR(str);
send = RSTRING_END(str);
while (s < send) {
if (ISUPPER(*s)) {
*s = tolower(*s);
str_modify(mrb, s);
p = s->buf;
pend = s->buf + s->len;
while (p < pend) {
if (ISUPPER(*p)) {
*p = tolower(*p);
modify = 1;
}
s++;
p++;
}
if (modify) return str;
@@ -1244,6 +1239,7 @@ str_gsub(mrb_state *mrb, mrb_value str, mrb_int bang)
mrb_int offset, blen, len, last;
char *sp, *cp;
if (bang) str_modify(mrb, mrb_str_ptr(self));
mrb_get_args(mrb, "*", &argv, &argc);
switch (argc) {
case 1:
@@ -1362,8 +1358,10 @@ mrb_str_gsub(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_gsub_bang(mrb_state *mrb, mrb_value self)
{
str_modify(mrb, self);
return str_gsub(mrb, self, 1);
striuct RString *s = mrb_str_ptr(self);
str_modify(mrb, s);
return str_gsub(mrb, s, 1);
}
#endif //INCLUDE_REGEXP
@@ -1535,6 +1533,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
int len = s2->len;
str_modify(mrb, s1);
s1->buf = mrb_realloc(mrb, s1->buf, len);
memcpy(s1->buf, s2->buf, len);
s1->len = s2->len;
@@ -1740,16 +1739,17 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
static mrb_value
mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
{
char *s, *e;
struct RString *s = mrb_str_ptr(str);
char *p, *e;
char c;
str_modify(mrb, str);
if (RSTRING(str)->len > 1) {
s = RSTRING(str)->buf;
e = s + RSTRING(str)->len - 1;
while (s < e) {
c = *s;
*s++ = *e;
str_modify(mrb, s);
if (s->len > 1) {
p = s->buf;
e = p + s->len - 1;
while (p < e) {
c = *p;
*p++ = *e;
*e-- = c;
}
}
@@ -2702,18 +2702,19 @@ mrb_str_to_s(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_upcase_bang(mrb_state *mrb, mrb_value str)
{
char *s, *send;
struct RString *s = mrb_str_ptr(str);
char *p, *pend;
int modify = 0;
str_modify(mrb, str);
s = RSTRING_PTR(str);
send = RSTRING_END(str);
while (s < send) {
if (ISLOWER(*s)) {
*s = toupper(*s);
str_modify(mrb, s);
p = RSTRING_PTR(str);
pend = RSTRING_END(str);
while (p < pend) {
if (ISLOWER(*p)) {
*p = toupper(*p);
modify = 1;
}
s++;
p++;
}
if (modify) return str;
@@ -2848,18 +2849,20 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
mrb_value
mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, long len)
{
if (len < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)");
}
if (0/*STR_ASSOC_P(str)*/) {
mrb_realloc(mrb, RSTRING(str)->buf, RSTRING(str)->len+len+1);
memcpy(RSTRING(str)->buf + RSTRING(str)->len, ptr, len);
RSTRING(str)->len += len;
RSTRING(str)->buf[RSTRING(str)->len] = '\0'; /* sentinel */
return str;
}
struct RString *s = mrb_str_ptr(str);
return str_buf_cat(mrb, str, ptr, len);
if (len < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)");
}
if (0/*STR_ASSOC_P(str)*/) {
mrb_realloc(mrb, s->buf, s->len+len+1);
memcpy(s->buf + s->len, ptr, len);
s->len += len;
s->buf[s->len] = '\0'; /* sentinel */
return str;
}
str_buf_cat(mrb, s, ptr, len);
return str;
}
mrb_value