Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions include/mruby/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,6 @@ struct RStringEmbed {
#define RSTRING_CSTR(mrb,s) mrb_string_cstr(mrb, s)

MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s);
/* mrb_str_modify() with keeping ASCII flag if set */
MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s);

/**
* Finds the index of a substring in a string
Expand Down
2 changes: 1 addition & 1 deletion mrbgems/mruby-encoding/test/string.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
assert('String#valid_encoding? after an append inside a shared buffer') do
# An append to a string sharing a buffer with room to spare writes in place
# rather than detaching, and that path forgets the remembered answer on its
# own rather than through mrb_str_modify_keep_ascii(). Nothing else here
# own rather than through mrb_str_modify(). Nothing else here
# reaches it: a string built by `*` or from a literal has no spare capacity,
# so its sharers all take the detaching path instead.
#
Expand Down
59 changes: 31 additions & 28 deletions src/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,37 +1249,40 @@ mrb_locale_from_utf8(const char *utf8, int len)
* @param s The RString structure to modify.
*
* Prepares a string for modification. If the string is shared or not extensible,
* it will be unshared or converted to a normal string. This version keeps the
* string standing at 7BIT if that is where it stood.
* it will be unshared or converted to a normal string. What the bytes were read
* as stops holding here, so this is the prepare for a write that can change it.
* Raises an error if the string is frozen.
*/
MRB_API void
mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s)
mrb_str_modify(mrb_state *mrb, struct RString *s)
{
mrb_check_frozen(mrb, s);
str_unshare_buffer(mrb, s);
/* Every in-place write reaches here, including the ones that keep the string
ASCII, so this is where the walk's answer stops holding. What a string of
nothing but ASCII stands at is the caller's to keep. */
if (RSTR_CODERANGE(s) != MRB_STR_CODERANGE_7BIT) {
RSTR_CODERANGE_SET(s, MRB_STR_CODERANGE_UNKNOWN);
}
RSTR_CODERANGE_SET(s, MRB_STR_CODERANGE_UNKNOWN);
}

/*
* @param mrb The mruby state.
* @param s The RString structure to modify.
*
* Prepares a string for modification. Similar to `mrb_str_modify_keep_ascii`,
* but also takes 7BIT back, assuming the modification might introduce
* multi-byte characters.
* Raises an error if the string is frozen.
*/
MRB_API void
mrb_str_modify(mrb_state *mrb, struct RString *s)
/* mrb_str_modify() for a caller whose write leaves what the bytes read as
standing: it puts ASCII where ASCII stood, or it cuts where a character
ends. Such a write cannot turn a sound string unsound, so the answer the
string came in carrying is still the answer, and the next asker is spared
the walk that would arrive at it again.

Only a string already read as broken has to be asked again, since a write
is as likely to have mended it as to have left it broken. A string that
the write leaves holding nothing but ASCII keeps saying VALID rather than
moving to 7BIT: that is an answer worth less than the truth, not a wrong
one, and finding the truth is the walk this is here to skip.

The promise this asks of its caller cannot be checked here, which is why
it is not offered outside the library. */
static void
str_modify_keep_cr(mrb_state *mrb, struct RString *s)
{
mrb_str_modify_keep_ascii(mrb, s);
RSTR_CODERANGE_SET(s, MRB_STR_CODERANGE_UNKNOWN);
mrb_check_frozen(mrb, s);
str_unshare_buffer(mrb, s);
if (RSTR_CODERANGE(s) == MRB_STR_CODERANGE_BROKEN) {
RSTR_CODERANGE_SET(s, MRB_STR_CODERANGE_UNKNOWN);
}
}

/*
Expand Down Expand Up @@ -2016,7 +2019,7 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_int len = RSTR_LEN(s);

mrb_str_modify_keep_ascii(mrb, s);
str_modify_keep_cr(mrb, s);
char *p = RSTR_PTR(s);
char *pend = RSTR_PTR(s) + len;
if (len == 0 || p == NULL) return mrb_nil_value();
Expand Down Expand Up @@ -2069,7 +2072,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
mrb_int argc = mrb_get_args(mrb, "|S", &rs);
struct RString *s = mrb_str_ptr(str);

mrb_str_modify_keep_ascii(mrb, s);
str_modify_keep_cr(mrb, s);
mrb_int len = RSTR_LEN(s);
if (argc == 0) {
if (len == 0) return mrb_nil_value();
Expand Down Expand Up @@ -2177,7 +2180,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);

mrb_str_modify_keep_ascii(mrb, s);
str_modify_keep_cr(mrb, s);
if (RSTR_LEN(s) > 0) {
mrb_int len;
#ifdef MRB_UTF8_STRING
Expand Down Expand Up @@ -2249,7 +2252,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
mrb_bool modify = FALSE;
struct RString *s = mrb_str_ptr(str);

mrb_str_modify_keep_ascii(mrb, s);
str_modify_keep_cr(mrb, s);
p = RSTR_PTR(s);
pend = RSTR_PTR(s) + RSTR_LEN(s);
while (p < pend) {
Expand Down Expand Up @@ -3189,7 +3192,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
}

/*
* Even after str_modify_keep_ascii(), NULL termination is not ensured if
* Even after mrb_str_modify(), NULL termination is not ensured if
* RSTR_SET_LEN() is used explicitly (e.g. String#delete_suffix!).
*/
str_unshare_buffer(mrb, ps);
Expand Down Expand Up @@ -3428,7 +3431,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str)
char *p, *pend;
mrb_bool modify = FALSE;

mrb_str_modify_keep_ascii(mrb, s);
str_modify_keep_cr(mrb, s);
p = RSTRING_PTR(str);
pend = RSTRING_END(str);
while (p < pend) {
Expand Down
Loading