summaryrefslogtreecommitdiffhomepage
path: root/src/string.c
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2021-08-31 13:00:15 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2021-09-01 07:00:55 +0900
commit3622f2c4b51d4b1f9eb0a2470ea7cd2ee24fe3a5 (patch)
tree257435cdb71a3431e77df7620a04a77007d3cda1 /src/string.c
parent2c41739b66e34ee20f614e4793dfb1dba4fd7274 (diff)
downloadmruby-3622f2c4b51d4b1f9eb0a2470ea7cd2ee24fe3a5.tar.gz
mruby-3622f2c4b51d4b1f9eb0a2470ea7cd2ee24fe3a5.zip
string.c: implement `__sub_replace()` in C.
To reduce number of string allocation.
Diffstat (limited to 'src/string.c')
-rw-r--r--src/string.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/string.c b/src/string.c
index b9cc2485f..21be97db6 100644
--- a/src/string.c
+++ b/src/string.c
@@ -2847,6 +2847,51 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str)
}
}
+static mrb_value
+sub_replace(mrb_state *mrb, mrb_value self)
+{
+ char *p, *match;
+ mrb_int plen, mlen;
+ mrb_int found, offset;
+ mrb_value result;
+
+ mrb_get_args(mrb, "ssi", &p, &plen, &match, &mlen, &found);
+ result = mrb_str_new(mrb, 0, 0);
+ for (mrb_int i=0; i<plen; i++) {
+ if (p[i] != '\\' || i+1==plen) {
+ mrb_str_cat(mrb, result, p+i, 1);
+ continue;
+ }
+ i++;
+ switch (p[i]) {
+ case '\\':
+ mrb_str_cat(mrb, result, "\\", 1);
+ break;
+ case '`':
+ mrb_str_cat(mrb, result, RSTRING_PTR(self), found);
+ break;
+ case '&': case '0':
+ mrb_str_cat(mrb, result, match, mlen);
+ break;
+ case '\'':
+ offset = found + mlen;
+ if (RSTRING_LEN(self) > offset) {
+ mrb_str_cat(mrb, result, RSTRING_PTR(self)+offset, RSTRING_LEN(self)-offset);
+ }
+ break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ /* ignore sub-group match (no Regexp supported) */
+ break;
+ default:
+ mrb_str_cat(mrb, result, &p[i-1], 2);
+ break;
+ }
+ }
+ return result;
+}
+
/* ---------------------------*/
void
mrb_init_string(mrb_state *mrb)
@@ -2908,4 +2953,6 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2));
mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1));
+
+ mrb_define_method(mrb, s, "__sub_replace", sub_replace, MRB_ARGS_REQ(3)); /* internal */
}