14#include "ruby/internal/config.h"
24#include "debug_counter.h"
28#include "internal/array.h"
29#include "internal/bits.h"
30#include "internal/compar.h"
31#include "internal/compilers.h"
32#include "internal/concurrent_set.h"
33#include "internal/encoding.h"
34#include "internal/error.h"
35#include "internal/gc.h"
36#include "internal/hash.h"
37#include "internal/numeric.h"
38#include "internal/object.h"
39#include "internal/proc.h"
40#include "internal/re.h"
41#include "internal/sanitizers.h"
42#include "internal/simd.h"
43#include "internal/string.h"
44#include "internal/transcode.h"
51#include "ruby_assert.h"
58#if defined HAVE_CRYPT_R
59# if defined HAVE_CRYPT_H
62#elif !defined HAVE_CRYPT
63# include "missing/crypt.h"
64# define HAVE_CRYPT_R 1
68#undef rb_usascii_str_new
72#undef rb_usascii_str_new_cstr
73#undef rb_utf8_str_new_cstr
74#undef rb_enc_str_new_cstr
75#undef rb_external_str_new_cstr
76#undef rb_locale_str_new_cstr
77#undef rb_str_dup_frozen
78#undef rb_str_buf_new_cstr
129#define RUBY_MAX_CHAR_LEN 16
130#define STR_PRECOMPUTED_HASH FL_USER4
131#define STR_SHARED_ROOT FL_USER5
132#define STR_BORROWED FL_USER6
133#define STR_TMPLOCK FL_USER7
134#define STR_NOFREE FL_USER18
136#define STR_SET_NOEMBED(str) do {\
137 FL_SET((str), STR_NOEMBED);\
138 FL_UNSET((str), STR_SHARED | STR_SHARED_ROOT | STR_BORROWED);\
140#define STR_SET_EMBED(str) FL_UNSET((str), STR_NOEMBED | STR_SHARED | STR_NOFREE)
142#define STR_SET_LEN(str, n) do { \
143 RSTRING(str)->len = (n); \
146#define TERM_LEN(str) (rb_str_enc_fastpath(str) ? 1 : rb_enc_mbminlen(rb_enc_from_index(ENCODING_GET(str))))
147#define TERM_FILL(ptr, termlen) do {\
148 char *const term_fill_ptr = (ptr);\
149 const int term_fill_len = (termlen);\
150 *term_fill_ptr = '\0';\
151 if (UNLIKELY(term_fill_len > 1))\
152 memset(term_fill_ptr, 0, term_fill_len);\
155#define RESIZE_CAPA(str,capacity) do {\
156 const int termlen = TERM_LEN(str);\
157 RESIZE_CAPA_TERM(str,capacity,termlen);\
159#define RESIZE_CAPA_TERM(str,capacity,termlen) do {\
160 if (STR_EMBED_P(str)) {\
161 if (str_embed_capa(str) < capacity + termlen) {\
162 char *const tmp = ALLOC_N(char, (size_t)(capacity) + (termlen));\
163 const long tlen = RSTRING_LEN(str);\
164 memcpy(tmp, RSTRING_PTR(str), str_embed_capa(str));\
165 RSTRING(str)->as.heap.ptr = tmp;\
166 RSTRING(str)->len = tlen;\
167 STR_SET_NOEMBED(str);\
168 RSTRING(str)->as.heap.aux.capa = (capacity);\
172 RUBY_ASSERT(!FL_TEST((str), STR_SHARED)); \
173 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char, \
174 (size_t)(capacity) + (termlen), STR_HEAP_SIZE(str)); \
175 RSTRING(str)->as.heap.aux.capa = (capacity);\
179#define STR_SET_SHARED(str, shared_str) do { \
180 if (!FL_TEST(str, STR_FAKESTR)) { \
181 RUBY_ASSERT(RSTRING_PTR(shared_str) <= RSTRING_PTR(str)); \
182 RUBY_ASSERT(RSTRING_PTR(str) <= RSTRING_PTR(shared_str) + RSTRING_LEN(shared_str)); \
183 RB_OBJ_WRITE((str), &RSTRING(str)->as.heap.aux.shared, (shared_str)); \
184 FL_SET((str), STR_SHARED); \
185 rb_gc_register_pinning_obj(str); \
186 FL_SET((shared_str), STR_SHARED_ROOT); \
187 if (RBASIC_CLASS((shared_str)) == 0) \
188 FL_SET_RAW((shared_str), STR_BORROWED); \
192#define STR_HEAP_PTR(str) (RSTRING(str)->as.heap.ptr)
193#define STR_HEAP_SIZE(str) ((size_t)RSTRING(str)->as.heap.aux.capa + TERM_LEN(str))
196#define STR_ENC_GET(str) get_encoding(str)
199zero_filled(
const char *s,
int n)
202 if (*s++)
return false;
207#if !defined SHARABLE_MIDDLE_SUBSTRING
208# define SHARABLE_MIDDLE_SUBSTRING 0
212SHARABLE_SUBSTRING_P(
VALUE str,
long beg,
long len)
214#if SHARABLE_MIDDLE_SUBSTRING
217 long end = beg +
len;
218 long source_len = RSTRING_LEN(str);
219 return end == source_len || zero_filled(RSTRING_PTR(str) + end, TERM_LEN(str));
224str_embed_capa(
VALUE str)
226 return rb_obj_shape_slot_size(str) - offsetof(
struct RString, as.
embed.ary);
230rb_str_reembeddable_p(
VALUE str)
232 return !
FL_TEST(str, STR_NOFREE|STR_SHARED_ROOT|STR_SHARED);
238rb_str_embedded_shared_root_p(
VALUE str)
240 return STR_EMBED_P(str) &&
FL_TEST(str, STR_SHARED_ROOT);
244rb_str_embed_size(
long capa,
long termlen)
252rb_str_size_as_embedded(
VALUE str)
255 if (STR_EMBED_P(str)) {
257 if (
FL_TEST_RAW(str, STR_PRECOMPUTED_HASH))
capa +=
sizeof(st_index_t);
259 real_size = rb_str_embed_size(
capa, TERM_LEN(str));
263 else if (rb_str_reembeddable_p(str)) {
265 if (
FL_TEST_RAW(str, STR_PRECOMPUTED_HASH))
capa +=
sizeof(st_index_t);
267 real_size = rb_str_embed_size(
capa, TERM_LEN(str));
270 real_size =
sizeof(
struct RString);
277STR_EMBEDDABLE_P(
long len,
long termlen)
279 return rb_gc_size_allocatable_p(rb_str_embed_size(
len, termlen));
286#define STR_COPY_MAX_EMBED_SIZE 256
290static VALUE str_new_frozen_buffer(
VALUE klass,
VALUE orig,
int copy_encoding);
291static VALUE str_new_static(
VALUE klass,
const char *
ptr,
long len,
int encindex);
293static void str_make_independent_expand(
VALUE str,
long len,
long expand,
const int termlen);
294static inline void str_modifiable(
VALUE str);
299str_make_independent(
VALUE str)
301 long len = RSTRING_LEN(str);
302 int termlen = TERM_LEN(str);
303 str_make_independent_expand((str),
len, 0L, termlen);
306static inline int str_dependent_p(
VALUE str);
309rb_str_make_independent(
VALUE str)
311 if (str_dependent_p(str)) {
312 str_make_independent(str);
317rb_str_make_embedded(
VALUE str)
322 int termlen = TERM_LEN(str);
323 char *buf =
RSTRING(str)->as.heap.ptr;
324 long old_capa =
RSTRING(str)->as.heap.aux.capa + termlen;
328 STR_SET_LEN(str,
len);
331 memcpy(RSTRING_PTR(str), buf,
len);
332 SIZED_FREE_N(buf, old_capa);
339rb_debug_rstring_null_ptr(
const char *func)
341 fprintf(stderr,
"%s is returning NULL!! "
342 "SIGSEGV is highly expected to follow immediately.\n"
343 "If you could reproduce, attach your debugger here, "
344 "and look at the passed string.\n",
349static VALUE sym_ascii, sym_turkic, sym_lithuanian, sym_fold;
352get_encoding(
VALUE str)
358mustnot_broken(
VALUE str)
360 if (is_broken_string(str)) {
361 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str)));
366mustnot_wchar(
VALUE str)
369 if (rb_enc_mbminlen(enc) > 1) {
370 rb_raise(rb_eArgError,
"wide char encoding: %s", rb_enc_name(enc));
374static VALUE register_fstring(
VALUE str,
bool copy,
bool force_precompute_hash);
376#if SIZEOF_LONG == SIZEOF_VOIDP
377#define PRECOMPUTED_FAKESTR_HASH 1
382BARE_STRING_P(
VALUE str)
387static inline st_index_t
388str_do_hash(
VALUE str)
390 st_index_t h =
rb_memhash((
const void *)RSTRING_PTR(str), RSTRING_LEN(str));
392 if (e && !is_ascii_string(str)) {
399str_store_precomputed_hash(
VALUE str, st_index_t hash)
405 size_t used_bytes = (RSTRING_LEN(str) + TERM_LEN(str));
406 size_t free_bytes = str_embed_capa(str) - used_bytes;
410 memcpy(
RSTRING_END(str) + TERM_LEN(str), &hash,
sizeof(hash));
412 FL_SET(str, STR_PRECOMPUTED_HASH);
425 if (
FL_TEST(str, RSTRING_FSTR))
428 bare = BARE_STRING_P(str);
430 if (STR_EMBED_P(str)) {
435 if (
FL_TEST_RAW(str, STR_SHARED_ROOT | STR_SHARED) == STR_SHARED_ROOT) {
442 rb_str_resize(str, RSTRING_LEN(str));
444 fstr = register_fstring(str,
false,
false);
447 str_replace_shared_without_enc(str, fstr);
454static VALUE fstring_table_obj;
457fstring_concurrent_set_hash(
VALUE str)
459#ifdef PRECOMPUTED_FAKESTR_HASH
463 h = (st_index_t)
RSTRING(str)->as.heap.aux.capa;
480 const char *aptr, *bptr;
487 return (alen == blen &&
489 memcmp(aptr, bptr, alen) == 0);
494 bool force_precompute_hash;
498fstring_concurrent_set_create(
VALUE str,
void *data)
508 long len = RSTRING_LEN(str);
509 long capa =
len +
sizeof(st_index_t);
510 int term_len = TERM_LEN(str);
512 if (arg->force_precompute_hash && STR_EMBEDDABLE_P(
capa, term_len)) {
514 memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str),
len);
515 STR_SET_LEN(new_str, RSTRING_LEN(str));
517 rb_enc_copy(new_str, str);
518 str_store_precomputed_hash(new_str, str_do_hash(str));
522 rb_enc_copy(new_str, str);
523#ifdef PRECOMPUTED_FAKESTR_HASH
524 if (
rb_str_capacity(new_str) >= RSTRING_LEN(str) + term_len +
sizeof(st_index_t)) {
525 str_store_precomputed_hash(new_str, (st_index_t)
RSTRING(str)->as.heap.aux.capa);
539 if (!
OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
542 if (STR_SHARED_P(str)) {
544 str_make_independent(str);
547 if (!BARE_STRING_P(str)) {
553 RBASIC(str)->flags |= RSTRING_FSTR;
569 .hash = fstring_concurrent_set_hash,
570 .cmp = fstring_concurrent_set_cmp,
571 .create = fstring_concurrent_set_create,
576Init_fstring_table(
void)
578 fstring_table_obj = rb_concurrent_set_new(&fstring_concurrent_set_funcs, 8192);
579 rb_gc_register_address(&fstring_table_obj);
583register_fstring(
VALUE str,
bool copy,
bool force_precompute_hash)
587 .force_precompute_hash = force_precompute_hash
590#if SIZEOF_VOIDP == SIZEOF_LONG
594 RSTRING(str)->as.heap.aux.capa = (long)str_do_hash(str);
598 VALUE result = rb_concurrent_set_find_or_insert(&fstring_table_obj, str, &args);
600 RUBY_ASSERT(!rb_objspace_garbage_object_p(result));
612rb_obj_is_fstring_table(
VALUE obj)
616 return obj == fstring_table_obj;
620rb_gc_free_fstring(
VALUE obj)
622 ASSERT_vm_locking_with_barrier();
628 rb_concurrent_set_delete_by_identity(fstring_table_obj, obj);
630 RB_DEBUG_COUNTER_INC(obj_str_fstr);
636rb_fstring_foreach_with_replace(
int (*callback)(
VALUE *str,
void *data),
void *data)
638 if (fstring_table_obj) {
639 rb_concurrent_set_foreach_with_replace(fstring_table_obj, callback, data);
644setup_fake_str(
struct RString *fake_str,
const char *name,
long len,
int encidx)
647 RBASIC_SET_FULL_SHAPE_ID((
VALUE)fake_str, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
660 return (
VALUE)fake_str;
669 return setup_fake_str(fake_str, name,
len, rb_enc_to_index(enc));
678rb_fstring_new(
const char *ptr,
long len)
680 struct RString fake_str = {RBASIC_INIT};
681 return register_fstring(setup_fake_str(&fake_str,
ptr,
len, ENCINDEX_US_ASCII),
false,
false);
687 struct RString fake_str = {RBASIC_INIT};
688 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
false,
false);
692rb_fstring_cstr(
const char *
ptr)
694 return rb_fstring_new(
ptr, strlen(
ptr));
698single_byte_optimizable(
VALUE str)
702 case ENCINDEX_ASCII_8BIT:
703 case ENCINDEX_US_ASCII:
725static inline const char *
726search_nonascii(
const char *p,
const char *e)
734#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
735# if SIZEOF_UINTPTR_T == 8
736# define NONASCII_MASK UINT64_C(0x8080808080808080)
737# elif SIZEOF_UINTPTR_T == 4
738# define NONASCII_MASK UINT32_C(0x80808080)
740# error "don't know what to do."
743# if SIZEOF_UINTPTR_T == 8
744# define NONASCII_MASK ((uintptr_t)0x80808080UL << 32 | (uintptr_t)0x80808080UL)
745# elif SIZEOF_UINTPTR_T == 4
746# define NONASCII_MASK 0x80808080UL
748# error "don't know what to do."
752 if (UNALIGNED_WORD_ACCESS || e - p >= SIZEOF_VOIDP) {
753#if !UNALIGNED_WORD_ACCESS
754 if ((uintptr_t)p % SIZEOF_VOIDP) {
755 int l = SIZEOF_VOIDP - (uintptr_t)p % SIZEOF_VOIDP;
760 case 7:
if (p[-7]&0x80)
return p-7;
761 case 6:
if (p[-6]&0x80)
return p-6;
762 case 5:
if (p[-5]&0x80)
return p-5;
763 case 4:
if (p[-4]&0x80)
return p-4;
765 case 3:
if (p[-3]&0x80)
return p-3;
766 case 2:
if (p[-2]&0x80)
return p-2;
767 case 1:
if (p[-1]&0x80)
return p-1;
772#if defined(HAVE_BUILTIN___BUILTIN_ASSUME_ALIGNED) &&! UNALIGNED_WORD_ACCESS
773#define aligned_ptr(value) \
774 __builtin_assume_aligned((value), sizeof(uintptr_t))
776#define aligned_ptr(value) (value)
779 t = (e - (SIZEOF_VOIDP-1));
781 for (;s < t; s +=
sizeof(uintptr_t)) {
783 memcpy(&word, s,
sizeof(word));
784 if (word & NONASCII_MASK) {
785#ifdef WORDS_BIGENDIAN
786 return (
const char *)s + (nlz_intptr(word&NONASCII_MASK)>>3);
788 return (
const char *)s + (ntz_intptr(word&NONASCII_MASK)>>3);
798 case 7:
if (e[-7]&0x80)
return e-7;
799 case 6:
if (e[-6]&0x80)
return e-6;
800 case 5:
if (e[-5]&0x80)
return e-5;
801 case 4:
if (e[-4]&0x80)
return e-4;
803 case 3:
if (e[-3]&0x80)
return e-3;
804 case 2:
if (e[-2]&0x80)
return e-2;
805 case 1:
if (e[-1]&0x80)
return e-1;
813 const char *e = p +
len;
815 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
817 p = search_nonascii(p, e);
821 if (rb_enc_asciicompat(enc)) {
822 p = search_nonascii(p, e);
825 int ret = rb_enc_precise_mbclen(p, e, enc);
829 p = search_nonascii(p, e);
835 int ret = rb_enc_precise_mbclen(p, e, enc);
851 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
854 p = search_nonascii(p, e);
858 else if (rb_enc_asciicompat(enc)) {
859 p = search_nonascii(p, e);
865 int ret = rb_enc_precise_mbclen(p, e, enc);
872 p = search_nonascii(p, e);
878 int ret = rb_enc_precise_mbclen(p, e, enc);
903 rb_enc_set_index(str1, rb_enc_get_index(str2));
911rb_enc_cr_str_copy_for_substr(
VALUE dest,
VALUE src)
916 str_enc_copy(dest, src);
917 if (RSTRING_LEN(dest) == 0) {
918 if (!rb_enc_asciicompat(STR_ENC_GET(src)))
929 if (!rb_enc_asciicompat(STR_ENC_GET(src)) ||
930 search_nonascii(RSTRING_PTR(dest),
RSTRING_END(dest)))
941rb_enc_cr_str_exact_copy(
VALUE dest,
VALUE src)
943 str_enc_copy(dest, src);
950 return coderange_scan(RSTRING_PTR(str), RSTRING_LEN(str), enc);
956 return enc_coderange_scan(str, enc);
960rbimpl_enc_str_coderange_scan(
VALUE str)
962 int cr = enc_coderange_scan(str, get_encoding(str));
967#undef rb_enc_str_coderange
974 cr = rbimpl_enc_str_coderange_scan(str);
978#define rb_enc_str_coderange rb_enc_str_coderange_inline
981rb_enc_str_asciicompat(
VALUE str)
984 return rb_str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
992 return rb_enc_str_asciicompat(str) && is_ascii_string(str);
1001str_mod_check(
VALUE s,
const char *p,
long len)
1003 if (RSTRING_PTR(s) != p || RSTRING_LEN(s) !=
len){
1009str_capacity(
VALUE str,
const int termlen)
1011 if (STR_EMBED_P(str)) {
1012 return str_embed_capa(str) - termlen;
1014 else if (
FL_ANY_RAW(str, STR_SHARED|STR_NOFREE)) {
1018 return RSTRING(str)->as.heap.aux.capa;
1025 return str_capacity(str, TERM_LEN(str));
1029must_not_null(
const char *
ptr)
1032 rb_raise(rb_eArgError,
"NULL pointer given");
1037str_alloc_embed(
VALUE klass,
size_t capa)
1039 size_t size = rb_str_embed_size(
capa, 0);
1046 str->as.embed.ary[0] = 0;
1052str_alloc_heap(
VALUE klass)
1057 str->as.heap.aux.capa = 0;
1058 str->as.heap.ptr = NULL;
1064empty_str_alloc(
VALUE klass)
1066 RUBY_DTRACE_CREATE_HOOK(STRING, 0);
1067 VALUE str = str_alloc_embed(klass, 0);
1068 memset(
RSTRING(str)->
as.embed.ary, 0, str_embed_capa(str));
1079 rb_raise(rb_eArgError,
"negative string size (or size too big)");
1083 enc = rb_ascii8bit_encoding();
1086 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1088 int termlen = rb_enc_mbminlen(enc);
1090 if (STR_EMBEDDABLE_P(
len, termlen)) {
1091 str = str_alloc_embed(klass,
len + termlen);
1097 str = str_alloc_heap(klass);
1103 rb_xmalloc_mul_add_mul(
sizeof(
char),
len,
sizeof(
char), termlen);
1106 rb_enc_raw_set(str, enc);
1109 memcpy(RSTRING_PTR(str),
ptr,
len);
1112 memset(RSTRING_PTR(str), 0,
len);
1115 STR_SET_LEN(str,
len);
1116 TERM_FILL(RSTRING_PTR(str) +
len, termlen);
1123 return str_enc_new(klass,
ptr,
len, rb_ascii8bit_encoding());
1158 __msan_unpoison_string(
ptr);
1178 if (rb_enc_mbminlen(enc) != 1) {
1179 rb_raise(rb_eArgError,
"wchar encoding given");
1181 return rb_enc_str_new(
ptr, strlen(
ptr), enc);
1185str_new_static(
VALUE klass,
const char *
ptr,
long len,
int encindex)
1190 rb_raise(rb_eArgError,
"negative string size (or size too big)");
1194 str = str_enc_new(klass,
ptr,
len, rb_enc_from_index(encindex));
1197 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1198 str = str_alloc_heap(klass);
1202 RBASIC(str)->flags |= STR_NOFREE;
1203 rb_enc_associate_index(str, encindex);
1218rb_str_new_owned(
char *
ptr,
long len,
long capa,
int encindex)
1220 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1227 rb_enc_associate_index(str, encindex);
1249static VALUE str_cat_conv_enc_opts(
VALUE newstr,
long ofs,
const char *
ptr,
long len,
1251 int ecflags,
VALUE ecopts);
1256 int encidx = rb_enc_to_index(enc);
1257 if (rb_enc_get_index(str) == encidx)
1258 return is_ascii_string(str);
1269 if (!to)
return str;
1270 if (!from) from = rb_enc_get(str);
1271 if (from == to)
return str;
1272 if ((rb_enc_asciicompat(to) && is_enc_ascii_string(str, from)) ||
1273 rb_is_ascii8bit_enc(to)) {
1274 if (STR_ENC_GET(str) != to) {
1276 rb_enc_associate(str, to);
1283 from, to, ecflags, ecopts);
1284 if (
NIL_P(newstr)) {
1292rb_str_cat_conv_enc_opts(
VALUE newstr,
long ofs,
const char *
ptr,
long len,
1297 olen = RSTRING_LEN(newstr);
1298 if (ofs < -olen || olen < ofs)
1300 if (ofs < 0) ofs += olen;
1302 STR_SET_LEN(newstr, ofs);
1306 rb_str_modify(newstr);
1307 return str_cat_conv_enc_opts(newstr, ofs,
ptr,
len, from,
1315 STR_SET_LEN(str, 0);
1316 rb_enc_associate(str, enc);
1322str_cat_conv_enc_opts(
VALUE newstr,
long ofs,
const char *
ptr,
long len,
1324 int ecflags,
VALUE ecopts)
1329 VALUE econv_wrapper;
1330 const unsigned char *start, *sp;
1331 unsigned char *dest, *dp;
1332 size_t converted_output = (size_t)ofs;
1337 RBASIC_CLEAR_CLASS(econv_wrapper);
1339 if (!ec)
return Qnil;
1342 sp = (
unsigned char*)
ptr;
1344 while ((dest = (
unsigned char*)RSTRING_PTR(newstr)),
1345 (dp = dest + converted_output),
1349 size_t converted_input = sp - start;
1350 size_t rest =
len - converted_input;
1351 converted_output = dp - dest;
1353 if (converted_input && converted_output &&
1354 rest < (LONG_MAX / converted_output)) {
1355 rest = (rest * converted_output) / converted_input;
1360 olen += rest < 2 ? 2 : rest;
1361 rb_str_resize(newstr, olen);
1368 len = dp - (
unsigned char*)RSTRING_PTR(newstr);
1370 rb_enc_associate(newstr, to);
1389 const int eidx = rb_enc_to_index(eenc);
1392 return rb_enc_str_new(
ptr,
len, eenc);
1396 if ((eidx == rb_ascii8bit_encindex()) ||
1397 (eidx == rb_usascii_encindex() && search_nonascii(
ptr,
ptr +
len))) {
1401 ienc = rb_default_internal_encoding();
1402 if (!ienc || eenc == ienc) {
1403 return rb_enc_str_new(
ptr,
len, eenc);
1407 if ((eidx == rb_ascii8bit_encindex()) ||
1408 (eidx == rb_usascii_encindex()) ||
1409 (rb_enc_asciicompat(eenc) && !search_nonascii(
ptr,
ptr +
len))) {
1410 return rb_enc_str_new(
ptr,
len, ienc);
1413 str = rb_enc_str_new(NULL, 0, ienc);
1416 if (
NIL_P(rb_str_cat_conv_enc_opts(str, 0,
ptr,
len, eenc, 0,
Qnil))) {
1417 rb_str_initialize(str,
ptr,
len, eenc);
1425 int eidx = rb_enc_to_index(eenc);
1426 if (eidx == rb_usascii_encindex() &&
1427 !is_ascii_string(str)) {
1428 rb_enc_associate_index(str, rb_ascii8bit_encindex());
1431 rb_enc_associate_index(str, eidx);
1490str_replace_shared_without_enc(
VALUE str2,
VALUE str)
1492 const int termlen = TERM_LEN(str);
1497 if (str_embed_capa(str2) >=
len + termlen) {
1498 char *ptr2 =
RSTRING(str2)->as.embed.ary;
1499 STR_SET_EMBED(str2);
1500 memcpy(ptr2, RSTRING_PTR(str),
len);
1501 TERM_FILL(ptr2+
len, termlen);
1505 if (STR_SHARED_P(str)) {
1506 root =
RSTRING(str)->as.heap.aux.shared;
1515 if (!STR_EMBED_P(str2) && !
FL_TEST_RAW(str2, STR_SHARED|STR_NOFREE)) {
1517 rb_fatal(
"about to free a possible shared root");
1519 char *ptr2 = STR_HEAP_PTR(str2);
1521 SIZED_FREE_N(ptr2, STR_HEAP_SIZE(str2));
1524 FL_SET(str2, STR_NOEMBED);
1526 STR_SET_SHARED(str2, root);
1529 STR_SET_LEN(str2,
len);
1537 str_replace_shared_without_enc(str2, str);
1538 rb_enc_cr_str_exact_copy(str2, str);
1545 return str_replace_shared(str_alloc_heap(klass), str);
1562rb_str_new_frozen_String(
VALUE orig)
1570rb_str_frozen_bare_string(
VALUE orig)
1572 if (RB_LIKELY(BARE_STRING_P(orig) &&
OBJ_FROZEN_RAW(orig)))
return orig;
1577rb_str_tmp_frozen_acquire(
VALUE orig)
1580 return str_new_frozen_buffer(0, orig, FALSE);
1584rb_str_tmp_frozen_no_embed_acquire(
VALUE orig)
1586 if (
OBJ_FROZEN_RAW(orig) && !STR_EMBED_P(orig) && !rb_str_reembeddable_p(orig))
return orig;
1587 if (STR_SHARED_P(orig) && !STR_EMBED_P(
RSTRING(orig)->
as.heap.aux.shared))
return rb_str_tmp_frozen_acquire(orig);
1589 VALUE str = str_alloc_heap(0);
1592 FL_SET(str, STR_SHARED_ROOT);
1594 size_t capa = str_capacity(orig, TERM_LEN(orig));
1600 if (STR_EMBED_P(orig) ||
FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT | RSTRING_FSTR)) {
1601 RSTRING(str)->as.heap.ptr = rb_xmalloc_mul_add_mul(
sizeof(
char),
capa,
sizeof(
char), TERM_LEN(orig));
1608 RBASIC(str)->flags |=
RBASIC(orig)->flags & STR_NOFREE;
1609 RBASIC(orig)->flags &= ~STR_NOFREE;
1610 STR_SET_SHARED(orig, str);
1621 RSTRING(str)->as.heap.aux.capa =
capa + (TERM_LEN(orig) - TERM_LEN(str));
1627rb_str_tmp_frozen_release(
VALUE orig,
VALUE tmp)
1632 if (STR_EMBED_P(tmp)) {
1635 else if (
FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_SHARED &&
1641 RUBY_ASSERT(RSTRING_LEN(orig) == RSTRING_LEN(tmp));
1645 RSTRING(orig)->as.heap.aux.capa =
RSTRING(tmp)->as.heap.aux.capa + TERM_LEN(tmp) - TERM_LEN(orig);
1646 RBASIC(orig)->flags |=
RBASIC(tmp)->flags & STR_NOFREE;
1651 STR_SET_LEN(tmp, 0);
1659 return str_new_frozen_buffer(klass, orig, TRUE);
1668heap_str_make_shared(
VALUE klass,
VALUE orig,
int termlen)
1674 VALUE str = str_alloc_heap(klass);
1675 STR_SET_LEN(str, RSTRING_LEN(orig));
1676 RSTRING(str)->as.heap.ptr = RSTRING_PTR(orig);
1677 RSTRING(str)->as.heap.aux.capa =
RSTRING(orig)->as.heap.aux.capa + TERM_LEN(orig) - termlen;
1678 RBASIC(str)->flags |=
RBASIC(orig)->flags & STR_NOFREE;
1679 RBASIC(orig)->flags &= ~STR_NOFREE;
1680 STR_SET_SHARED(orig, str);
1687str_new_frozen_buffer(
VALUE klass,
VALUE orig,
int copy_encoding)
1691 long len = RSTRING_LEN(orig);
1692 rb_encoding *enc = copy_encoding ? STR_ENC_GET(orig) : rb_ascii8bit_encoding();
1693 int termlen = copy_encoding ? TERM_LEN(orig) : 1;
1695 if (STR_EMBED_P(orig) || STR_EMBEDDABLE_P(
len, termlen)) {
1696 str = str_enc_new(klass, RSTRING_PTR(orig),
len, enc);
1702 long ofs =
RSTRING(orig)->as.heap.ptr - RSTRING_PTR(
shared);
1703 long rest = RSTRING_LEN(
shared) - ofs - RSTRING_LEN(orig);
1709 if ((ofs > 0) || (rest > 0) ||
1712 str = str_new_shared(klass,
shared);
1714 RSTRING(str)->as.heap.ptr += ofs;
1715 STR_SET_LEN(str, RSTRING_LEN(str) - (ofs + rest));
1723 else if (STR_EMBEDDABLE_P(RSTRING_LEN(orig), TERM_LEN(orig))) {
1724 str = str_alloc_embed(klass, RSTRING_LEN(orig) + TERM_LEN(orig));
1726 memcpy(RSTRING_PTR(str), RSTRING_PTR(orig), RSTRING_LEN(orig));
1727 STR_SET_LEN(str, RSTRING_LEN(orig));
1733 str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
1736 str = heap_str_make_shared(klass, orig, termlen);
1741 if (copy_encoding) rb_enc_cr_str_exact_copy(str, orig);
1753str_new_empty_String(
VALUE str)
1756 rb_enc_copy(v, str);
1760#define STR_BUF_MIN_SIZE 63
1765 if (STR_EMBEDDABLE_P(
capa, 1)) {
1773 RSTRING(str)->as.heap.ptr[0] =
'\0';
1793 return str_new(0, 0,
len);
1799 if (STR_EMBED_P(str)) {
1800 RB_DEBUG_COUNTER_INC(obj_str_embed);
1802 else if (
FL_TEST(str, STR_SHARED | STR_NOFREE)) {
1803 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared,
FL_TEST(str, STR_SHARED));
1804 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared,
FL_TEST(str, STR_NOFREE));
1807 RB_DEBUG_COUNTER_INC(obj_str_ptr);
1808 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
1813rb_str_memsize(
VALUE str)
1815 if (
FL_TEST(str, STR_NOEMBED|STR_SHARED|STR_NOFREE) == STR_NOEMBED) {
1816 return STR_HEAP_SIZE(str);
1826 return rb_convert_type_with_id(str,
T_STRING,
"String", idTo_str);
1829static inline void str_discard(
VALUE str);
1830static void str_shared_replace(
VALUE str,
VALUE str2);
1835 if (str != str2) str_shared_replace(str, str2);
1846 enc = STR_ENC_GET(str2);
1849 termlen = rb_enc_mbminlen(enc);
1851 STR_SET_LEN(str, RSTRING_LEN(str2));
1853 if (str_embed_capa(str) >= RSTRING_LEN(str2) + termlen) {
1855 memcpy(RSTRING_PTR(str), RSTRING_PTR(str2), (
size_t)RSTRING_LEN(str2) + termlen);
1856 rb_enc_associate(str, enc);
1860 if (STR_EMBED_P(str2)) {
1862 long len = RSTRING_LEN(str2);
1865 char *new_ptr =
ALLOC_N(
char,
len + termlen);
1866 memcpy(new_ptr,
RSTRING(str2)->
as.embed.ary,
len + termlen);
1867 RSTRING(str2)->as.heap.ptr = new_ptr;
1868 STR_SET_LEN(str2,
len);
1870 STR_SET_NOEMBED(str2);
1873 STR_SET_NOEMBED(str);
1875 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1877 if (
FL_TEST(str2, STR_SHARED)) {
1879 STR_SET_SHARED(str,
shared);
1882 RSTRING(str)->as.heap.aux.capa =
RSTRING(str2)->as.heap.aux.capa;
1886 STR_SET_EMBED(str2);
1887 RSTRING_PTR(str2)[0] = 0;
1888 STR_SET_LEN(str2, 0);
1889 rb_enc_associate(str, enc);
1903 return rb_obj_as_string_result(str, obj);
1919 len = RSTRING_LEN(str2);
1920 if (STR_SHARED_P(str2)) {
1923 STR_SET_NOEMBED(str);
1924 STR_SET_LEN(str,
len);
1925 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1926 STR_SET_SHARED(str,
shared);
1927 rb_enc_cr_str_exact_copy(str, str2);
1930 str_replace_shared(str, str2);
1939 size_t size = rb_str_embed_size(
capa, 0);
1955 str->as.heap.aux.capa = 0;
1956 str->as.heap.ptr = NULL;
1966 encidx = rb_enc_get_index(str);
1967 flags &= ~ENCODING_MASK;
1970 if (encidx) rb_enc_associate_index(dup, encidx);
1979 long len = RSTRING_LEN(str);
1984 STR_SET_LEN(dup, RSTRING_LEN(str));
1985 str_duplicate_setup_encoding(str, dup, flags);
1994 root =
RSTRING(str)->as.heap.aux.shared;
1997 root = str = str_new_frozen(klass, str);
2003 RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
2005 STR_SET_SHARED(dup, root);
2006 flags |= RSTRING_NOEMBED | STR_SHARED;
2008 STR_SET_LEN(dup, RSTRING_LEN(str));
2009 str_duplicate_setup_encoding(str, dup, flags);
2016 if (STR_EMBED_P(str) && rb_str_embed_size(RSTRING_LEN(str), 1) <= STR_COPY_MAX_EMBED_SIZE) {
2017 dup = str_alloc_embed(klass, RSTRING_LEN(str) + TERM_LEN(str));
2019 str_duplicate_setup_embed(klass, str, dup);
2022 dup = str_alloc_heap(klass);
2024 str_duplicate_setup_heap(klass, str, dup);
2038rb_str_dup_m(
VALUE str)
2040 if (LIKELY(BARE_STRING_P(str))) {
2051 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2058 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2062 new_str = ec_str_alloc_embed(ec, klass, RSTRING_LEN(str) + TERM_LEN(str));
2063 str_duplicate_setup_embed(klass, str, new_str);
2066 new_str = ec_str_alloc_heap(ec, klass);
2067 str_duplicate_setup_heap(klass, str, new_str);
2077rb_zjit_str_resurrect_fastpath(
VALUE str,
bool chilled,
size_t *size_out,
2079 long *len_out,
size_t *byte_size_out)
2083 if (!STR_EMBED_P(str))
return false;
2085 long len = RSTRING_LEN(str);
2086 long termlen = TERM_LEN(str);
2087 size_t size = rb_str_embed_size(
len + termlen, 0);
2088 if (!rb_gc_size_allocatable_p(size))
return false;
2096 flags &= ~FL_FREEZE;
2098 if (chilled) flags |= STR_CHILLED;
2103 *byte_size_out = (size_t)(
len + termlen);
2109rb_str_with_debug_created_info(
VALUE str,
VALUE path,
int line)
2111 VALUE debug_info = rb_ary_new_from_args(2, path,
INT2FIX(line));
2135 static ID keyword_ids[2];
2136 VALUE orig, opt, venc, vcapa;
2141 if (!keyword_ids[0]) {
2142 keyword_ids[0] = rb_id_encoding();
2143 CONST_ID(keyword_ids[1],
"capacity");
2151 if (!UNDEF_P(venc) && !
NIL_P(venc)) {
2152 enc = rb_to_encoding(venc);
2154 if (!UNDEF_P(vcapa) && !
NIL_P(vcapa)) {
2157 int termlen = enc ? rb_enc_mbminlen(enc) : 1;
2159 if (
capa < STR_BUF_MIN_SIZE) {
2160 capa = STR_BUF_MIN_SIZE;
2164 len = RSTRING_LEN(orig);
2168 if (orig == str) n = 0;
2170 str_modifiable(str);
2171 if (STR_EMBED_P(str) ||
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2173 const size_t size = (size_t)
capa + termlen;
2174 const char *
const old_ptr = RSTRING_PTR(str);
2175 const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
2176 char *new_ptr =
ALLOC_N(
char, size);
2177 if (STR_EMBED_P(str))
RUBY_ASSERT((
long)osize <= str_embed_capa(str));
2178 memcpy(new_ptr, old_ptr, osize < size ? osize : size);
2180 RSTRING(str)->as.heap.ptr = new_ptr;
2182 else if (STR_HEAP_SIZE(str) != (
size_t)
capa + termlen) {
2183 SIZED_REALLOC_N(
RSTRING(str)->
as.heap.ptr,
char,
2184 (
size_t)
capa + termlen, STR_HEAP_SIZE(str));
2186 STR_SET_LEN(str,
len);
2189 memcpy(
RSTRING(str)->
as.heap.ptr, RSTRING_PTR(orig),
len);
2190 rb_enc_cr_str_exact_copy(str, orig);
2192 FL_SET(str, STR_NOEMBED);
2199 rb_enc_associate(str, enc);
2211rb_str_s_new(
int argc,
VALUE *argv,
VALUE klass)
2217 static ID keyword_ids[2];
2227 keyword_ids[0] = rb_id_encoding();
2228 CONST_ID(keyword_ids[1],
"capacity");
2230 encoding = kwargs[0];
2231 capacity = kwargs[1];
2240 if (UNDEF_P(encoding)) {
2242 encoding = rb_obj_encoding(orig);
2246 if (!UNDEF_P(encoding)) {
2247 enc = rb_to_encoding(encoding);
2251 if (UNDEF_P(capacity)) {
2253 VALUE empty_str = str_new(klass,
"", 0);
2255 rb_enc_associate(empty_str, enc);
2259 VALUE copy = str_duplicate(klass, orig);
2260 rb_enc_associate(copy, enc);
2273 if (orig_capa >
capa) {
2278 VALUE str = str_enc_new(klass, NULL,
capa, enc);
2279 STR_SET_LEN(str, 0);
2290#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2305static inline uintptr_t
2306count_utf8_lead_bytes_with_word(
const uintptr_t *s)
2311 d = (d>>6) | (~d>>7);
2312 d &= NONASCII_MASK >> 7;
2315#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2317 return rb_popcount_intptr(d);
2321# if SIZEOF_VOIDP == 8
2330enc_strlen(
const char *p,
const char *e,
rb_encoding *enc,
int cr)
2336 long diff = (long)(e - p);
2337 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2342 if ((
int)
sizeof(uintptr_t) * 2 < e - p) {
2343 const uintptr_t *s, *t;
2344 const uintptr_t lowbits =
sizeof(uintptr_t) - 1;
2345 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2346 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
2347 while (p < (
const char *)s) {
2348 if (is_utf8_lead_byte(*p))
len++;
2352 len += count_utf8_lead_bytes_with_word(s);
2355 p = (
const char *)s;
2358 if (is_utf8_lead_byte(*p))
len++;
2364 else if (rb_enc_asciicompat(enc)) {
2368 q = search_nonascii(p, e);
2373 p += rb_enc_fast_mbclen(p, e, enc);
2379 q = search_nonascii(p, e);
2384 p += rb_enc_mbclen(p, e, enc);
2391 for (c=0; p<e; c++) {
2392 p += rb_enc_mbclen(p, e, enc);
2407rb_enc_strlen_cr(
const char *p,
const char *e,
rb_encoding *enc,
int *cr)
2415 long diff = (long)(e - p);
2416 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2418 else if (rb_enc_asciicompat(enc)) {
2421 q = search_nonascii(p, e);
2428 ret = rb_enc_precise_mbclen(p, e, enc);
2443 for (c=0; p<e; c++) {
2444 ret = rb_enc_precise_mbclen(p, e, enc);
2451 if (p + rb_enc_mbminlen(enc) <= e)
2452 p += rb_enc_mbminlen(enc);
2468 if (single_byte_optimizable(str))
return RSTRING_LEN(str);
2469 if (!enc) enc = STR_ENC_GET(str);
2470 p = RSTRING_PTR(str);
2475 long n = rb_enc_strlen_cr(p, e, enc, &cr);
2480 return enc_strlen(p, e, enc, cr);
2487 return str_strlen(str, NULL);
2501 return LONG2NUM(str_strlen(str, NULL));
2513rb_str_bytesize(
VALUE str)
2532rb_str_empty(
VALUE str)
2534 return RBOOL(RSTRING_LEN(str) == 0);
2553 const char *ptr1, *ptr2;
2559 enc = rb_enc_check_str(str1, str2);
2562 termlen = rb_enc_mbminlen(enc);
2563 if (len1 > LONG_MAX - len2) {
2564 rb_raise(rb_eArgError,
"string size too big");
2566 str3 = str_enc_new(
rb_cString, 0, len1+len2, enc);
2567 ptr3 = RSTRING_PTR(str3);
2568 memcpy(ptr3, ptr1, len1);
2569 memcpy(ptr3+len1, ptr2, len2);
2570 TERM_FILL(&ptr3[len1+len2], termlen);
2586 MAYBE_UNUSED(
char) *ptr1, *ptr2;
2589 int enc1 = rb_enc_get_index(str1);
2590 int enc2 = rb_enc_get_index(str2);
2595 else if (enc2 < 0) {
2598 else if (enc1 != enc2) {
2601 else if (len1 > LONG_MAX - len2) {
2635 rb_enc_copy(str2, str);
2640 rb_raise(rb_eArgError,
"negative argument");
2642 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2643 if (STR_EMBEDDABLE_P(
len, 1)) {
2645 memset(RSTRING_PTR(str2), 0,
len + 1);
2652 STR_SET_LEN(str2,
len);
2653 rb_enc_copy(str2, str);
2656 if (
len && LONG_MAX/
len < RSTRING_LEN(str)) {
2657 rb_raise(rb_eArgError,
"argument too big");
2660 len *= RSTRING_LEN(str);
2661 termlen = TERM_LEN(str);
2663 ptr2 = RSTRING_PTR(str2);
2665 n = RSTRING_LEN(str);
2666 memcpy(ptr2, RSTRING_PTR(str), n);
2667 while (n <=
len/2) {
2668 memcpy(ptr2 + n, ptr2, n);
2671 memcpy(ptr2 + n, ptr2,
len-n);
2673 STR_SET_LEN(str2,
len);
2674 TERM_FILL(&ptr2[
len], termlen);
2675 rb_enc_cr_str_copy_for_substr(str2, str);
2714rb_check_lockedtmp(
VALUE str)
2716 if (
FL_TEST(str, STR_TMPLOCK)) {
2723#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2725str_modifiable(
VALUE str)
2729 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2730 if (CHILLED_STRING_P(str)) {
2731 CHILLED_STRING_MUTATED(str);
2733 rb_check_lockedtmp(str);
2734 rb_check_frozen(str);
2739str_dependent_p(
VALUE str)
2741 if (STR_EMBED_P(str) || !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2751#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2753str_independent(
VALUE str)
2757 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2758 str_modifiable(str);
2759 return !str_dependent_p(str);
2765str_make_independent_expand(
VALUE str,
long len,
long expand,
const int termlen)
2775 if (!STR_EMBED_P(str) && str_embed_capa(str) >=
capa + termlen) {
2780 STR_SET_LEN(str,
len);
2785 oldptr = RSTRING_PTR(str);
2787 memcpy(
ptr, oldptr,
len);
2789 if (
FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2790 SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
2792 STR_SET_NOEMBED(str);
2793 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2794 TERM_FILL(
ptr +
len, termlen);
2796 STR_SET_LEN(str,
len);
2803 if (!str_independent(str))
2804 str_make_independent(str);
2813 int termlen = TERM_LEN(str);
2814 long len = RSTRING_LEN(str);
2817 rb_raise(rb_eArgError,
"negative expanding string size");
2819 if (expand >= LONG_MAX -
len) {
2820 rb_raise(rb_eArgError,
"string size too big");
2823 if (!str_independent(str)) {
2824 str_make_independent_expand(str,
len, expand, termlen);
2826 else if (expand > 0) {
2827 RESIZE_CAPA_TERM(str,
len + expand, termlen);
2834str_modify_keep_cr(
VALUE str)
2836 if (!str_independent(str))
2837 str_make_independent(str);
2844str_discard(
VALUE str)
2846 str_modifiable(str);
2847 if (!STR_EMBED_P(str) && !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2848 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2849 RSTRING(str)->as.heap.ptr = 0;
2850 STR_SET_LEN(str, 0);
2857 int encindex = rb_enc_get_index(str);
2859 if (RB_UNLIKELY(encindex == -1)) {
2863 if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
2868 if (!rb_enc_asciicompat(enc)) {
2890 return RSTRING_PTR(str);
2894str_null_char(
const char *s,
long len,
const int minlen,
rb_encoding *enc)
2896 const char *e = s +
len;
2898 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2899 if (zero_filled(s, minlen))
return s;
2905str_fill_term(
VALUE str,
char *s,
long len,
int termlen)
2910 if (str_dependent_p(str)) {
2911 if (!zero_filled(s +
len, termlen))
2912 str_make_independent_expand(str,
len, 0L, termlen);
2915 TERM_FILL(s +
len, termlen);
2918 return RSTRING_PTR(str);
2922rb_str_change_terminator_length(
VALUE str,
const int oldtermlen,
const int termlen)
2924 long capa = str_capacity(str, oldtermlen) + oldtermlen;
2925 long len = RSTRING_LEN(str);
2929 rb_check_lockedtmp(str);
2930 str_make_independent_expand(str,
len, 0L, termlen);
2932 else if (str_dependent_p(str)) {
2933 if (termlen > oldtermlen)
2934 str_make_independent_expand(str,
len, 0L, termlen);
2937 if (!STR_EMBED_P(str)) {
2942 if (termlen > oldtermlen) {
2943 TERM_FILL(RSTRING_PTR(str) +
len, termlen);
2951str_null_check(
VALUE str,
int *w)
2953 char *s = RSTRING_PTR(str);
2954 long len = RSTRING_LEN(str);
2957 if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
2959 minlen = rb_enc_mbminlen(enc);
2963 if (str_null_char(s,
len, minlen, enc)) {
2966 return str_fill_term(str, s,
len, minlen);
2971 if (!s || memchr(s, 0,
len)) {
2975 s = str_fill_term(str, s,
len, minlen);
2980static char *str_to_cstr(
VALUE str);
2983rb_str_null_check(
VALUE str)
2991 if (RB_LIKELY(rb_str_enc_fastpath(str))) {
2992 if (!s || memchr(s, 0,
len)) {
2993 rb_raise(rb_eArgError,
"string contains null byte");
3004rb_str_to_cstr(
VALUE str)
3007 return str_null_check(str, &w);
3014 return str_to_cstr(str);
3018str_to_cstr(
VALUE str)
3021 char *s = str_null_check(str, &w);
3024 rb_raise(rb_eArgError,
"string contains null char");
3026 rb_raise(rb_eArgError,
"string contains null byte");
3032rb_str_fill_terminator(
VALUE str,
const int newminlen)
3034 char *s = RSTRING_PTR(str);
3035 long len = RSTRING_LEN(str);
3036 return str_fill_term(str, s,
len, newminlen);
3042 str = rb_check_convert_type_with_id(str,
T_STRING,
"String", idTo_str);
3068str_nth_len(
const char *p,
const char *e,
long *nthp,
rb_encoding *enc)
3077 else if (rb_enc_asciicompat(enc)) {
3078 const char *p2, *e2;
3081 while (p < e && 0 < nth) {
3087 p2 = search_nonascii(p, e2);
3095 n = rb_enc_mbclen(p, e, enc);
3106 while (p < e && nth--) {
3107 p += rb_enc_mbclen(p, e, enc);
3118 return str_nth_len(p, e, &nth, enc);
3122str_nth(
const char *p,
const char *e,
long nth,
rb_encoding *enc,
int singlebyte)
3127 p = str_nth_len(p, e, &nth, enc);
3136str_offset(
const char *p,
const char *e,
long nth,
rb_encoding *enc,
int singlebyte)
3138 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3139 if (!pp)
return e - p;
3146 return str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
3147 STR_ENC_GET(str), single_byte_optimizable(str));
3152str_utf8_nth(
const char *p,
const char *e,
long *nthp)
3155 if ((
int)SIZEOF_VOIDP * 2 < e - p && (
int)SIZEOF_VOIDP * 2 < nth) {
3156 const uintptr_t *s, *t;
3157 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3158 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3159 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
3160 while (p < (
const char *)s) {
3161 if (is_utf8_lead_byte(*p)) nth--;
3165 nth -= count_utf8_lead_bytes_with_word(s);
3167 }
while (s < t && (
int)SIZEOF_VOIDP <= nth);
3171 if (is_utf8_lead_byte(*p)) {
3172 if (nth == 0)
break;
3182str_utf8_offset(
const char *p,
const char *e,
long nth)
3184 const char *pp = str_utf8_nth(p, e, &nth);
3193 if (single_byte_optimizable(str) || pos < 0)
3196 const char *p = RSTRING_PTR(str);
3197 return enc_strlen(p, p + pos, STR_ENC_GET(str),
ENC_CODERANGE(str));
3202str_subseq(
VALUE str,
long beg,
long len)
3210 const int termlen = TERM_LEN(str);
3211 if (!SHARABLE_SUBSTRING_P(str, beg,
len)) {
3212 str2 = rb_enc_str_new(RSTRING_PTR(str) + beg,
len, rb_str_enc_get(str));
3222 const bool root_available = STR_SHARED_P(str) ||
3224 const size_t max_embed_size = root_available ?
3225 rb_gc_size_slot_size(
sizeof(
struct RString)) : STR_COPY_MAX_EMBED_SIZE;
3226 const size_t embed_size = rb_str_embed_size(
len, termlen);
3228 if (embed_size <= max_embed_size && rb_gc_size_allocatable_p(embed_size)) {
3230 char *ptr2 =
RSTRING(str2)->as.embed.ary;
3231 memcpy(ptr2, RSTRING_PTR(str) + beg,
len);
3232 TERM_FILL(ptr2 +
len, termlen);
3234 STR_SET_LEN(str2,
len);
3243 str_replace_shared(str2, str);
3249 RSTRING(str2)->as.heap.ptr += beg;
3250 if (RSTRING_LEN(str2) >
len) {
3251 STR_SET_LEN(str2,
len);
3261 VALUE str2 = str_subseq(str, beg,
len);
3262 rb_enc_cr_str_copy_for_substr(str2, str);
3271 const long blen = RSTRING_LEN(str);
3273 const char *p, *s = RSTRING_PTR(str), *e = s + blen;
3275 if (
len < 0)
return 0;
3276 if (beg < 0 && -beg < 0)
return 0;
3280 if (single_byte_optimizable(str)) {
3281 if (beg > blen)
return 0;
3284 if (beg < 0)
return 0;
3286 if (
len > blen - beg)
3288 if (
len < 0)
return 0;
3293 if (
len > -beg)
len = -beg;
3297 while (beg-- >
len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3300 while (
len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3306 slen = str_strlen(str, enc);
3308 if (beg < 0)
return 0;
3310 if (
len == 0)
goto end;
3313 else if (beg > 0 && beg > blen) {
3317 if (beg > str_strlen(str, enc))
return 0;
3322 enc == rb_utf8_encoding()) {
3323 p = str_utf8_nth(s, e, &beg);
3324 if (beg > 0)
return 0;
3325 len = str_utf8_offset(p, e,
len);
3331 p = s + beg * char_sz;
3335 else if (
len * char_sz > e - p)
3340 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3341 if (beg > 0)
return 0;
3345 len = str_offset(p, e,
len, enc, 0);
3353static VALUE str_substr(
VALUE str,
long beg,
long len,
int empty);
3358 return str_substr(str, beg,
len, TRUE);
3368str_substr(
VALUE str,
long beg,
long len,
int empty)
3372 if (!p)
return Qnil;
3373 if (!
len && !empty)
return Qnil;
3375 beg = p - RSTRING_PTR(str);
3377 VALUE str2 = str_subseq(str, beg,
len);
3378 rb_enc_cr_str_copy_for_substr(str2, str);
3386 if (CHILLED_STRING_P(str)) {
3391 rb_str_resize(str, RSTRING_LEN(str));
3409 if (
OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3452str_uminus(
VALUE str)
3457 return rb_fstring(str);
3461#define rb_str_dup_frozen rb_str_new_frozen
3466 rb_check_frozen(str);
3467 if (
FL_TEST(str, STR_TMPLOCK)) {
3470 FL_SET(str, STR_TMPLOCK);
3477 rb_check_frozen(str);
3478 if (!
FL_TEST(str, STR_TMPLOCK)) {
3498 const int termlen = TERM_LEN(str);
3500 str_modifiable(str);
3501 if (STR_SHARED_P(str)) {
3504 if (
len > (
capa = (
long)str_capacity(str, termlen)) ||
len < 0) {
3505 rb_bug(
"probable buffer overflow: %ld for %ld",
len,
capa);
3516 else if (
len > RSTRING_LEN(str)) {
3520 const char *
const new_end = RSTRING_PTR(str) +
len;
3530 else if (
len < RSTRING_LEN(str)) {
3538 STR_SET_LEN(str,
len);
3539 TERM_FILL(&RSTRING_PTR(str)[
len], termlen);
3546 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3549 int independent = str_independent(str);
3550 long slen = RSTRING_LEN(str);
3551 const int termlen = TERM_LEN(str);
3553 if (slen >
len || (termlen != 1 && slen <
len)) {
3559 if (STR_EMBED_P(str)) {
3560 if (
len == slen)
return str;
3561 if (str_embed_capa(str) >=
len + termlen) {
3562 STR_SET_LEN(str,
len);
3566 str_make_independent_expand(str, slen,
len - slen, termlen);
3568 else if (str_embed_capa(str) >=
len + termlen) {
3570 char *
ptr = STR_HEAP_PTR(str);
3572 if (slen >
len) slen =
len;
3575 STR_SET_LEN(str,
len);
3577 SIZED_FREE_N(
ptr,
capa + termlen);
3581 else if (!independent) {
3582 if (
len == slen)
return str;
3583 str_make_independent_expand(str, slen,
len - slen, termlen);
3587 SIZED_REALLOC_N(
RSTRING(str)->
as.heap.ptr,
char,
3588 (
size_t)
len + termlen, STR_HEAP_SIZE(str));
3591 else if (
len == slen)
return str;
3592 STR_SET_LEN(str,
len);
3599str_ensure_available_capa(
VALUE str,
long len)
3601 str_modify_keep_cr(str);
3603 const int termlen = TERM_LEN(str);
3604 long olen = RSTRING_LEN(str);
3606 if (RB_UNLIKELY(olen > LONG_MAX -
len)) {
3607 rb_raise(rb_eArgError,
"string sizes too big");
3610 long total = olen +
len;
3611 long capa = str_capacity(str, termlen);
3614 if (total >= LONG_MAX / 2) {
3617 while (total >
capa) {
3620 RESIZE_CAPA_TERM(str,
capa, termlen);
3625str_buf_cat4(
VALUE str,
const char *
ptr,
long len,
bool keep_cr)
3628 str_modify_keep_cr(str);
3633 if (
len == 0)
return 0;
3635 long total, olen,
off = -1;
3637 const int termlen = TERM_LEN(str);
3640 if (
ptr >= sptr &&
ptr <= sptr + olen) {
3644 long capa = str_capacity(str, termlen);
3646 if (olen > LONG_MAX -
len) {
3647 rb_raise(rb_eArgError,
"string sizes too big");
3651 if (total >= LONG_MAX / 2) {
3654 while (total >
capa) {
3657 RESIZE_CAPA_TERM(str,
capa, termlen);
3658 sptr = RSTRING_PTR(str);
3663 memcpy(sptr + olen,
ptr,
len);
3664 STR_SET_LEN(str, total);
3665 TERM_FILL(sptr + total, termlen);
3670#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3671#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3676 if (
len == 0)
return str;
3678 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3680 return str_buf_cat(str,
ptr,
len);
3691rb_str_buf_cat_byte(
VALUE str,
unsigned char byte)
3696 if (UNLIKELY(!str_independent(str))) {
3697 str_make_independent(str);
3700 long string_length = -1;
3701 const int null_terminator_length = 1;
3706 if (UNLIKELY(string_length > LONG_MAX - 1)) {
3707 rb_raise(rb_eArgError,
"string sizes too big");
3710 long string_capacity = str_capacity(str, null_terminator_length);
3716 if (LIKELY(string_capacity >= string_length + 1)) {
3718 sptr[string_length] = byte;
3719 STR_SET_LEN(str, string_length + 1);
3720 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3724 str_buf_cat(str, (
char *)&
byte, 1);
3740 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3751rb_enc_cr_str_buf_cat(
VALUE str,
const char *
ptr,
long len,
3752 int ptr_encindex,
int ptr_cr,
int *ptr_cr_ret)
3761 if (str_encindex == ptr_encindex) {
3763 ptr_cr = coderange_scan(
ptr,
len, rb_enc_from_index(ptr_encindex));
3767 str_enc = rb_enc_from_index(str_encindex);
3768 ptr_enc = rb_enc_from_index(ptr_encindex);
3769 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3772 if (RSTRING_LEN(str) == 0) {
3775 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3781 ptr_cr = coderange_scan(
ptr,
len, ptr_enc);
3785 str_cr = rb_enc_str_coderange(str);
3790 *ptr_cr_ret = ptr_cr;
3792 if (str_encindex != ptr_encindex &&
3795 str_enc = rb_enc_from_index(str_encindex);
3796 ptr_enc = rb_enc_from_index(ptr_encindex);
3801 res_encindex = str_encindex;
3806 res_encindex = str_encindex;
3810 res_encindex = ptr_encindex;
3815 res_encindex = str_encindex;
3822 res_encindex = str_encindex;
3828 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3830 str_buf_cat(str,
ptr,
len);
3836 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3843 return rb_enc_cr_str_buf_cat(str,
ptr,
len,
3853 if (rb_enc_asciicompat(enc)) {
3854 return rb_enc_cr_str_buf_cat(str,
ptr, strlen(
ptr),
3860 unsigned int c = (
unsigned char)*
ptr;
3861 int len = rb_enc_codelen(c, enc);
3862 rb_enc_mbcput(c, buf, enc);
3863 rb_enc_cr_str_buf_cat(str, buf,
len,
3874 int str2_cr = rb_enc_str_coderange(str2);
3876 if (rb_str_enc_fastpath(str)) {
3880 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3886 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3897 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3913rb_str_concat_literals(
size_t num,
const VALUE *strary)
3917 unsigned long len = 1;
3922 for (i = 0; i < num; ++i) {
len += RSTRING_LEN(strary[i]); }
3924 str_enc_copy_direct(str, strary[0]);
3926 for (i = s; i < num; ++i) {
3927 const VALUE v = strary[i];
3931 if (encidx != ENCINDEX_US_ASCII) {
3933 rb_enc_set_index(str, encidx);
3946rb_str_concat_multi(
int argc,
VALUE *argv,
VALUE str)
3948 str_modifiable(str);
3953 else if (argc > 1) {
3956 rb_enc_copy(arg_str, str);
3957 for (i = 0; i < argc; i++) {
3992rb_str_append_as_bytes(
int argc,
VALUE *argv,
VALUE str)
3994 long needed_capacity = 0;
3998 for (
int index = 0; index < argc; index++) {
3999 VALUE obj = argv[index];
4007 needed_capacity += RSTRING_LEN(obj);
4012 "wrong argument type %"PRIsVALUE
" (expected String or Integer)",
4019 str_ensure_available_capa(str, needed_capacity);
4022 for (
int index = 0; index < argc; index++) {
4023 VALUE obj = argv[index];
4028 argv[index] = obj = rb_int_and(obj,
INT2FIX(0xff));
4029 char byte = (char)(
NUM2INT(obj) & 0xFF);
4043 rb_bug(
"append_as_bytes arguments should have been validated");
4047 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
4048 TERM_FILL(sptr, TERM_LEN(str));
4053 for (
int index = 0; index < argc; index++) {
4054 VALUE obj = argv[index];
4071 rb_bug(
"append_as_bytes arguments should have been validated");
4150 if (rb_num_to_uint(str2, &code) == 0) {
4163 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4166 rb_str_buf_cat_byte(str1, (
unsigned char)code);
4169 long pos = RSTRING_LEN(str1);
4174 switch (
len = rb_enc_codelen(code, enc)) {
4175 case ONIGERR_INVALID_CODE_POINT_VALUE:
4176 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4178 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4184 rb_enc_mbcput(code, buf, enc);
4185 if (rb_enc_precise_mbclen(buf, buf +
len + 1, enc) !=
len) {
4186 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4188 rb_str_resize(str1, pos+
len);
4189 memcpy(RSTRING_PTR(str1) + pos, buf,
len);
4202rb_ascii8bit_appendable_encoding_index(
rb_encoding *enc,
unsigned int code)
4204 int encidx = rb_enc_to_index(enc);
4206 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4211 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4212 return ENCINDEX_ASCII_8BIT;
4234rb_str_prepend_multi(
int argc,
VALUE *argv,
VALUE str)
4236 str_modifiable(str);
4241 else if (argc > 1) {
4244 rb_enc_copy(arg_str, str);
4245 for (i = 0; i < argc; i++) {
4258 st_index_t precomputed_hash;
4259 memcpy(&precomputed_hash,
RSTRING_END(str) + TERM_LEN(str),
sizeof(precomputed_hash));
4261 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4262 return precomputed_hash;
4265 return str_do_hash(str);
4272 const char *ptr1, *ptr2;
4275 return (len1 != len2 ||
4277 memcmp(ptr1, ptr2, len1) != 0);
4289rb_str_hash_m(
VALUE str)
4295#define lesser(a,b) (((a)>(b))?(b):(a))
4303 if (RSTRING_LEN(str1) == 0)
return TRUE;
4304 if (RSTRING_LEN(str2) == 0)
return TRUE;
4307 if (idx1 == idx2)
return TRUE;
4308 rc1 = rb_enc_str_coderange(str1);
4309 rc2 = rb_enc_str_coderange(str2);
4312 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4316 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4326 const char *ptr1, *ptr2;
4329 if (str1 == str2)
return 0;
4332 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4341 if (len1 > len2)
return 1;
4344 if (retval > 0)
return 1;
4378 if (str1 == str2)
return Qtrue;
4385 return rb_str_eql_internal(str1, str2);
4399 if (str1 == str2)
return Qtrue;
4401 return rb_str_eql_internal(str1, str2);
4439 return rb_invcmp(str1, str2);
4481 return str_casecmp(str1, s);
4489 const char *p1, *p1end, *p2, *p2end;
4491 enc = rb_enc_compatible(str1, str2);
4496 p1 = RSTRING_PTR(str1); p1end =
RSTRING_END(str1);
4497 p2 = RSTRING_PTR(str2); p2end =
RSTRING_END(str2);
4498 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4499 while (p1 < p1end && p2 < p2end) {
4501 unsigned int c1 =
TOLOWER(*p1 & 0xff);
4502 unsigned int c2 =
TOLOWER(*p2 & 0xff);
4504 return INT2FIX(c1 < c2 ? -1 : 1);
4511 while (p1 < p1end && p2 < p2end) {
4512 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4513 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4515 if (0 <= c1 && 0 <= c2) {
4519 return INT2FIX(c1 < c2 ? -1 : 1);
4523 l1 = rb_enc_mbclen(p1, p1end, enc);
4524 l2 = rb_enc_mbclen(p2, p2end, enc);
4525 len = l1 < l2 ? l1 : l2;
4526 r = memcmp(p1, p2,
len);
4528 return INT2FIX(r < 0 ? -1 : 1);
4530 return INT2FIX(l1 < l2 ? -1 : 1);
4536 if (p1 == p1end && p2 == p2end)
return INT2FIX(0);
4537 if (p1 == p1end)
return INT2FIX(-1);
4570 return str_casecmp_p(str1, s);
4577 VALUE folded_str1, folded_str2;
4578 VALUE fold_opt = sym_fold;
4580 enc = rb_enc_compatible(str1, str2);
4585 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4586 if (RSTRING_LEN(str1) != RSTRING_LEN(str2))
return Qfalse;
4587 const char *p1 = RSTRING_PTR(str1), *p1end =
RSTRING_END(str1);
4588 const char *p2 = RSTRING_PTR(str2);
4589 while (p1 < p1end) {
4590 if (*p1 != *p2 &&
TOLOWER((
unsigned char)*p1) !=
TOLOWER((
unsigned char)*p2)) {
4599 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4600 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4602 return rb_str_eql(folded_str1, folded_str2);
4606strseq_core(
const char *str_ptr,
const char *str_ptr_end,
long str_len,
4607 const char *sub_ptr,
long sub_len,
long offset,
rb_encoding *enc)
4609 const char *search_start = str_ptr;
4610 long pos, search_len = str_len - offset;
4614 pos =
rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4615 if (pos < 0)
return pos;
4617 if (t == search_start + pos)
break;
4618 search_len -= t - search_start;
4619 if (search_len <= 0)
return -1;
4620 offset += t - search_start;
4623 return pos + offset;
4627#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4628#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4631rb_strseq_index(
VALUE str,
VALUE sub,
long offset,
int in_byte)
4633 const char *str_ptr, *str_ptr_end, *sub_ptr;
4634 long str_len, sub_len;
4637 enc = rb_enc_check(str, sub);
4638 if (is_broken_string(sub))
return -1;
4640 str_ptr = RSTRING_PTR(str);
4642 str_len = RSTRING_LEN(str);
4643 sub_ptr = RSTRING_PTR(sub);
4644 sub_len = RSTRING_LEN(sub);
4646 if (str_len < sub_len)
return -1;
4649 long str_len_char, sub_len_char;
4650 int single_byte = single_byte_optimizable(str);
4651 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4652 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4654 offset += str_len_char;
4655 if (offset < 0)
return -1;
4657 if (str_len_char - offset < sub_len_char)
return -1;
4658 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4661 if (sub_len == 0)
return offset;
4664 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4677rb_str_index_m(
int argc,
VALUE *argv,
VALUE str)
4684 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4685 long slen = str_strlen(str, enc);
4687 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4699 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4700 enc, single_byte_optimizable(str));
4710 pos = rb_str_index(str, sub, pos);
4724str_ensure_byte_pos(
VALUE str,
long pos)
4726 if (!single_byte_optimizable(str)) {
4727 const char *s = RSTRING_PTR(str);
4729 const char *p = s + pos;
4730 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4732 "offset %ld does not land on character boundary", pos);
4805rb_str_byteindex_m(
int argc,
VALUE *argv,
VALUE str)
4811 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4813 long slen = RSTRING_LEN(str);
4814 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4825 str_ensure_byte_pos(str, pos);
4830 pos = RMATCH_BEG(match, 0);
4836 pos = rb_str_byteindex(str, sub, pos);
4837 if (pos >= 0)
return LONG2NUM(pos);
4845 const char *hit, *adjusted, *sbeg, *e, *t;
4847 long slen, searchlen;
4849 sbeg = RSTRING_PTR(str);
4850 slen = RSTRING_LEN(sub);
4851 if (slen == 0)
return s - sbeg;
4853 t = RSTRING_PTR(sub);
4855 searchlen = s - sbeg + 1;
4857 if (s + slen <= e && memcmp(s, t, slen) == 0) {
4862 hit = memrchr(sbeg, c, searchlen);
4865 if (hit != adjusted) {
4866 searchlen = adjusted - sbeg;
4869 if (hit + slen <= e && memcmp(hit, t, slen) == 0)
4871 searchlen = adjusted - sbeg;
4872 }
while (searchlen > 0);
4882 const char *sbeg, *s;
4886 enc = rb_enc_check(str, sub);
4887 if (is_broken_string(sub))
return -1;
4888 singlebyte = single_byte_optimizable(str);
4889 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc);
4890 slen = str_strlen(sub, enc);
4893 if (
len < slen)
return -1;
4895 if (
len - pos < slen) pos =
len - slen;
4896 if (
len == 0)
return pos;
4898 sbeg = RSTRING_PTR(str);
4901 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4902 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4910 s = str_nth(sbeg,
RSTRING_END(str), pos, enc, singlebyte);
4911 return str_rindex(str, sub, s, enc);
4923rb_str_rindex_m(
int argc,
VALUE *argv,
VALUE str)
4928 long pos,
len = str_strlen(str, enc);
4930 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4932 if (pos < 0 && (pos +=
len) < 0) {
4938 if (pos >
len) pos =
len;
4946 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4947 enc, single_byte_optimizable(str));
4957 pos = rb_str_rindex(str, sub, pos);
4967rb_str_byterindex(
VALUE str,
VALUE sub,
long pos)
4970 const char *sbeg, *s;
4973 enc = rb_enc_check(str, sub);
4974 if (is_broken_string(sub))
return -1;
4975 len = RSTRING_LEN(str);
4976 slen = RSTRING_LEN(sub);
4979 if (
len < slen)
return -1;
4980 if (
len - pos < slen) pos =
len - slen;
4981 if (
len == 0)
return pos;
4983 sbeg = RSTRING_PTR(str);
4986 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4993 return str_rindex(str, sub, s, enc);
5083rb_str_byterindex_m(
int argc,
VALUE *argv,
VALUE str)
5089 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
5091 long len = RSTRING_LEN(str);
5092 if (pos < 0 && (pos +=
len) < 0) {
5098 if (pos >
len) pos =
len;
5101 pos = RSTRING_LEN(str);
5104 str_ensure_byte_pos(str, pos);
5109 pos = RMATCH_BEG(match, 0);
5115 pos = rb_str_byterindex(str, sub, pos);
5116 if (pos >= 0)
return LONG2NUM(pos);
5158 switch (OBJ_BUILTIN_TYPE(y)) {
5210rb_str_match_m(
int argc,
VALUE *argv,
VALUE str)
5217 result =
rb_funcallv(get_pat(re), rb_intern(
"match"), argc, argv);
5248rb_str_match_m_p(
int argc,
VALUE *argv,
VALUE str)
5252 re = get_pat(argv[0]);
5253 return rb_reg_match_p(re, str, argc > 1 ?
NUM2LONG(argv[1]) : 0);
5262static enum neighbor_char
5268 if (rb_enc_mbminlen(enc) > 1) {
5270 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5272 return NEIGHBOR_NOT_CHAR;
5274 c = rb_enc_mbc_to_codepoint(p, p +
len, enc) + 1;
5276 if (!l)
return NEIGHBOR_NOT_CHAR;
5277 if (l !=
len)
return NEIGHBOR_WRAPPED;
5278 rb_enc_mbcput(c, p, enc);
5279 r = rb_enc_precise_mbclen(p, p +
len, enc);
5281 return NEIGHBOR_NOT_CHAR;
5283 return NEIGHBOR_FOUND;
5286 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0xff; i--)
5289 return NEIGHBOR_WRAPPED;
5290 ++((
unsigned char*)p)[i];
5291 l = rb_enc_precise_mbclen(p, p+
len, enc);
5295 return NEIGHBOR_FOUND;
5298 memset(p+l, 0xff,
len-l);
5304 for (len2 =
len-1; 0 < len2; len2--) {
5305 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5309 memset(p+len2+1, 0xff,
len-(len2+1));
5314static enum neighbor_char
5319 if (rb_enc_mbminlen(enc) > 1) {
5321 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5323 return NEIGHBOR_NOT_CHAR;
5325 c = rb_enc_mbc_to_codepoint(p, p +
len, enc);
5326 if (!c)
return NEIGHBOR_NOT_CHAR;
5329 if (!l)
return NEIGHBOR_NOT_CHAR;
5330 if (l !=
len)
return NEIGHBOR_WRAPPED;
5331 rb_enc_mbcput(c, p, enc);
5332 r = rb_enc_precise_mbclen(p, p +
len, enc);
5334 return NEIGHBOR_NOT_CHAR;
5336 return NEIGHBOR_FOUND;
5339 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0; i--)
5342 return NEIGHBOR_WRAPPED;
5343 --((
unsigned char*)p)[i];
5344 l = rb_enc_precise_mbclen(p, p+
len, enc);
5348 return NEIGHBOR_FOUND;
5351 memset(p+l, 0,
len-l);
5357 for (len2 =
len-1; 0 < len2; len2--) {
5358 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5362 memset(p+len2+1, 0,
len-(len2+1));
5376static enum neighbor_char
5377enc_succ_alnum_char(
char *p,
long len,
rb_encoding *enc,
char *carry)
5379 enum neighbor_char ret;
5383 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5387 const int max_gaps = 1;
5389 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5391 ctype = ONIGENC_CTYPE_DIGIT;
5393 ctype = ONIGENC_CTYPE_ALPHA;
5395 return NEIGHBOR_NOT_CHAR;
5398 for (
try = 0;
try <= max_gaps; ++
try) {
5399 ret = enc_succ_char(p,
len, enc);
5400 if (ret == NEIGHBOR_FOUND) {
5401 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5403 return NEIGHBOR_FOUND;
5410 ret = enc_pred_char(p,
len, enc);
5411 if (ret == NEIGHBOR_FOUND) {
5412 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5425 return NEIGHBOR_NOT_CHAR;
5428 if (ctype != ONIGENC_CTYPE_DIGIT) {
5430 return NEIGHBOR_WRAPPED;
5434 enc_succ_char(carry,
len, enc);
5435 return NEIGHBOR_WRAPPED;
5453 str =
rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5454 rb_enc_cr_str_copy_for_substr(str, orig);
5455 return str_succ(str);
5462 char *sbeg, *s, *e, *last_alnum = 0;
5463 int found_alnum = 0;
5465 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] =
"\1";
5466 long carry_pos = 0, carry_len = 1;
5467 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5469 slen = RSTRING_LEN(str);
5470 if (slen == 0)
return str;
5472 enc = STR_ENC_GET(str);
5473 sbeg = RSTRING_PTR(str);
5474 s = e = sbeg + slen;
5476 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5477 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5483 l = rb_enc_precise_mbclen(s, e, enc);
5484 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5485 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5486 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5488 case NEIGHBOR_NOT_CHAR:
5490 case NEIGHBOR_FOUND:
5492 case NEIGHBOR_WRAPPED:
5497 carry_pos = s - sbeg;
5502 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5503 enum neighbor_char neighbor;
5504 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5505 l = rb_enc_precise_mbclen(s, e, enc);
5506 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5507 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5509 neighbor = enc_succ_char(tmp, l, enc);
5511 case NEIGHBOR_FOUND:
5515 case NEIGHBOR_WRAPPED:
5518 case NEIGHBOR_NOT_CHAR:
5521 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5523 enc_succ_char(s, l, enc);
5525 if (!rb_enc_asciicompat(enc)) {
5526 MEMCPY(carry, s,
char, l);
5529 carry_pos = s - sbeg;
5533 RESIZE_CAPA(str, slen + carry_len);
5534 sbeg = RSTRING_PTR(str);
5535 s = sbeg + carry_pos;
5536 memmove(s + carry_len, s, slen - carry_pos);
5537 memmove(s, carry, carry_len);
5539 STR_SET_LEN(str, slen);
5540 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5541 rb_enc_str_coderange(str);
5556rb_str_succ_bang(
VALUE str)
5564all_digits_p(
const char *s,
long len)
5592 VALUE end, exclusive;
5596 return rb_str_upto_each(beg, end,
RTEST(exclusive), str_upto_i,
Qnil);
5602 VALUE current, after_end;
5609 enc = rb_enc_check(beg, end);
5610 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5612 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5613 char c = RSTRING_PTR(beg)[0];
5614 char e = RSTRING_PTR(end)[0];
5616 if (c > e || (excl && c == e))
return beg;
5618 VALUE str = rb_enc_str_new(&c, 1, enc);
5620 if ((*each)(str, arg))
break;
5621 if (!excl && c == e)
break;
5623 if (excl && c == e)
break;
5628 if (ascii &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
ISDIGIT(RSTRING_PTR(end)[0]) &&
5629 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5630 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5635 b = rb_str_to_inum(beg, 10, FALSE);
5636 e = rb_str_to_inum(end, 10, FALSE);
5643 if (excl && bi == ei)
break;
5644 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5649 ID op = excl ?
'<' : idLE;
5650 VALUE args[2], fmt = rb_fstring_lit(
"%.*d");
5655 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5663 if (n > 0 || (excl && n == 0))
return beg;
5671 if ((*each)(current, arg))
break;
5672 if (
NIL_P(next))
break;
5676 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5691 if (is_ascii_string(beg) &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
5692 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5693 VALUE b, args[2], fmt = rb_fstring_lit(
"%.*d");
5695 b = rb_str_to_inum(beg, 10, FALSE);
5701 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5709 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5717 if ((*each)(current, arg))
break;
5720 if (RSTRING_LEN(current) == 0)
5731 if (!
rb_equal(str, *argp))
return 0;
5745 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5746 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5747 rb_enc_asciicompat(STR_ENC_GET(val))) {
5748 const char *bp = RSTRING_PTR(beg);
5749 const char *ep = RSTRING_PTR(end);
5750 const char *vp = RSTRING_PTR(val);
5751 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5752 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5760 if (b <= v && v < e)
return Qtrue;
5761 return RBOOL(!
RTEST(exclusive) && v == e);
5768 all_digits_p(bp, RSTRING_LEN(beg)) &&
5769 all_digits_p(ep, RSTRING_LEN(end))) {
5774 rb_str_upto_each(beg, end,
RTEST(exclusive), include_range_i, (
VALUE)&val);
5776 return RBOOL(
NIL_P(val));
5799 return rb_str_subpat(str, indx,
INT2FIX(0));
5802 if (rb_str_index(str, indx, 0) != -1)
5808 long beg,
len = str_strlen(str, NULL);
5820 return str_substr(str, idx, 1, FALSE);
5837rb_str_aref_m(
int argc,
VALUE *argv,
VALUE str)
5841 return rb_str_subpat(str, argv[0], argv[1]);
5844 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5848 return rb_str_aref(str, argv[0]);
5854 char *
ptr = RSTRING_PTR(str);
5855 long olen = RSTRING_LEN(str), nlen;
5857 str_modifiable(str);
5858 if (
len > olen)
len = olen;
5860 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5862 size_t old_capa =
RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5863 int fl = (int)(
RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5866 memmove(
ptr, oldptr +
len, nlen);
5867 if (fl == STR_NOEMBED) {
5868 SIZED_FREE_N(oldptr, old_capa);
5872 if (!STR_SHARED_P(str)) {
5874 rb_enc_cr_str_exact_copy(
shared, str);
5879 STR_SET_LEN(str, nlen);
5881 if (!SHARABLE_MIDDLE_SUBSTRING) {
5882 TERM_FILL(
ptr + nlen, TERM_LEN(str));
5889rb_str_update_1(
VALUE str,
long beg,
long len,
VALUE val,
long vbeg,
long vlen)
5895 if (beg == 0 && vlen == 0) {
5900 str_modify_keep_cr(str);
5904 RESIZE_CAPA(str, slen + vlen -
len);
5905 sptr = RSTRING_PTR(str);
5909 cr = rb_enc_str_coderange(val);
5914 memmove(sptr + beg + vlen,
5916 slen - (beg +
len));
5918 if (vlen < beg &&
len < 0) {
5922 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5925 STR_SET_LEN(str, slen);
5926 TERM_FILL(&sptr[slen], TERM_LEN(str));
5933 rb_str_update_1(str, beg,
len, val, 0, RSTRING_LEN(val));
5942 int singlebyte = single_byte_optimizable(str);
5948 enc = rb_enc_check(str, val);
5949 slen = str_strlen(str, enc);
5951 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5960 if (
len > slen - beg) {
5963 p = str_nth(RSTRING_PTR(str),
RSTRING_END(str), beg, enc, singlebyte);
5968 beg = p - RSTRING_PTR(str);
5970 rb_str_update_0(str, beg,
len, val);
5971 rb_enc_associate(str, enc);
5982 long start, end,
len;
5990 int num_regs = RMATCH_NREGS(match);
5991 if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
5998 start = RMATCH_BEG(match, nth);
6002 end = RMATCH_END(match, nth);
6006 if (start +
len > RSTRING_LEN(str)) {
6010 enc = rb_enc_check_str(str, val);
6011 rb_str_update_0(str, start,
len, val);
6012 rb_enc_associate(str, enc);
6020 switch (
TYPE(indx)) {
6022 rb_str_subpat_set(str, indx,
INT2FIX(0), val);
6026 beg = rb_str_index(str, indx, 0);
6065rb_str_aset_m(
int argc,
VALUE *argv,
VALUE str)
6069 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6077 return rb_str_aset(str, argv[0], argv[1]);
6129rb_str_slice_bang(
int argc,
VALUE *argv,
VALUE str)
6137 str_modify_keep_cr(str);
6142 int num_regs = RMATCH_NREGS(match);
6145 if ((nth += num_regs) <= 0)
return Qnil;
6147 else if (nth >= num_regs)
return Qnil;
6148 beg = RMATCH_BEG(match, nth);
6149 len = RMATCH_END(match, nth) - beg;
6151 if (beg > RSTRING_LEN(str))
return Qnil;
6152 if (
len > RSTRING_LEN(str) - beg)
len = RSTRING_LEN(str) - beg;
6155 else if (argc == 2) {
6164 beg = p - RSTRING_PTR(str);
6168 beg = rb_str_index(str, indx, 0);
6169 if (beg == -1)
return Qnil;
6170 len = RSTRING_LEN(indx);
6182 beg = p - RSTRING_PTR(str);
6191 beg = p - RSTRING_PTR(str);
6195 rb_enc_cr_str_copy_for_substr(result, str);
6203 char *sptr = RSTRING_PTR(str);
6204 long slen = RSTRING_LEN(str);
6205 if (beg +
len > slen)
6209 slen - (beg +
len));
6211 STR_SET_LEN(str, slen);
6212 TERM_FILL(&sptr[slen], TERM_LEN(str));
6223 switch (OBJ_BUILTIN_TYPE(pat)) {
6242get_pat_quoted(
VALUE pat,
int check)
6246 switch (OBJ_BUILTIN_TYPE(pat)) {
6260 if (check && is_broken_string(pat)) {
6267rb_pat_search0(
VALUE pat,
VALUE str,
long pos,
int set_backref_str,
VALUE *match)
6270 pos = rb_str_byteindex(str, pat, pos);
6271 if (set_backref_str) {
6273 str = rb_str_new_frozen_String(str);
6274 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6276 *match = match_data;
6286 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6291rb_pat_search(
VALUE pat,
VALUE str,
long pos,
int set_backref_str)
6293 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6311rb_str_sub_bang(
int argc,
VALUE *argv,
VALUE str)
6326 hash = rb_check_hash_type(repl);
6333 pat = get_pat_quoted(argv[0], 1);
6335 str_modifiable(str);
6336 beg = rb_pat_search(pat, str, 0, 1);
6348 end0 = beg0 + RSTRING_LEN(pat);
6352 beg0 = RMATCH_BEG(match, 0);
6353 end0 = RMATCH_END(match, 0);
6357 if (iter || !
NIL_P(hash)) {
6358 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6364 repl = rb_hash_aref(hash,
rb_str_subseq(str, beg0, end0 - beg0));
6367 str_mod_check(str, p,
len);
6368 rb_check_frozen(str);
6371 repl = rb_reg_regsub_match(repl, str, match);
6374 enc = rb_enc_compatible(str, repl);
6377 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6381 rb_enc_inspect_name(str_enc),
6382 rb_enc_inspect_name(STR_ENC_GET(repl)));
6384 enc = STR_ENC_GET(repl);
6387 rb_enc_associate(str, enc);
6397 rlen = RSTRING_LEN(repl);
6398 len = RSTRING_LEN(str);
6400 RESIZE_CAPA(str,
len + rlen - plen);
6402 p = RSTRING_PTR(str);
6404 memmove(p + beg0 + rlen, p + beg0 + plen,
len - beg0 - plen);
6406 rp = RSTRING_PTR(repl);
6407 memmove(p + beg0, rp, rlen);
6409 STR_SET_LEN(str,
len);
6410 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
6433 rb_str_sub_bang(argc, argv, str);
6438str_gsub(
int argc,
VALUE *argv,
VALUE str,
int bang)
6441 long beg, beg0, end0;
6442 long offset, blen, slen,
len, last;
6443 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6445 int need_backref_str = -1;
6456 hash = rb_check_hash_type(repl);
6460 else if (rb_hash_default_unredefined(hash) && !
FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6469 rb_error_arity(argc, 1, 2);
6472 pat = get_pat_quoted(argv[0], 1);
6473 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6476 if (bang)
return Qnil;
6479 if (bang) str_modify_keep_cr(str);
6482 blen = RSTRING_LEN(str) + 30;
6484 sp = RSTRING_PTR(str);
6485 slen = RSTRING_LEN(str);
6487 str_enc = STR_ENC_GET(str);
6488 rb_enc_associate(dest, str_enc);
6494 end0 = beg0 + RSTRING_LEN(pat);
6498 beg0 = RMATCH_BEG(match, 0);
6499 end0 = RMATCH_END(match, 0);
6508 struct RString fake_str = {RBASIC_INIT};
6510 if (mode == FAST_MAP) {
6519 val = rb_hash_aref(hash, key);
6522 str_mod_check(str, sp, slen);
6527 else if (need_backref_str) {
6528 val = rb_reg_regsub_match(repl, str, match);
6529 if (need_backref_str < 0) {
6530 need_backref_str = val != repl;
6537 len = beg0 - offset;
6551 if (RSTRING_LEN(str) <= end0)
break;
6552 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0,
RSTRING_END(str), str_enc);
6554 offset = end0 +
len;
6556 cp = RSTRING_PTR(str) + offset;
6557 if (offset > RSTRING_LEN(str))
break;
6560 if (mode != FAST_MAP && mode != STR) {
6563 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6568 if (RSTRING_LEN(str) > offset) {
6571 rb_pat_search0(pat, str, last, 1, &match);
6573 str_shared_replace(str, dest);
6598rb_str_gsub_bang(
int argc,
VALUE *argv,
VALUE str)
6600 str_modifiable(str);
6601 return str_gsub(argc, argv, str, 1);
6651 return str_gsub(argc, argv, str, 0);
6671 str_modifiable(str);
6672 if (str == str2)
return str;
6676 return str_replace(str, str2);
6693rb_str_clear(
VALUE str)
6697 STR_SET_LEN(str, 0);
6698 RSTRING_PTR(str)[0] = 0;
6699 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6715rb_str_chr(
VALUE str)
6733 pos += RSTRING_LEN(str);
6734 if (pos < 0 || RSTRING_LEN(str) <= pos)
6737 return INT2FIX((
unsigned char)RSTRING_PTR(str)[pos]);
6757 char *
ptr, *head, *left = 0;
6763 char byte = (char)(
NUM2INT(w) & 0xFF);
6765 long len = RSTRING_LEN(str);
6766 if (pos < -
len ||
len <= pos)
6771 if (!str_independent(str))
6772 str_make_independent(str);
6773 enc = STR_ENC_GET(str);
6774 head = RSTRING_PTR(str);
6776 if (!STR_EMBED_P(str)) {
6783 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6791 width = rb_enc_precise_mbclen(left, head+
len, enc);
6793 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6809str_bit_offset_out_of_range(
long byte_len, uint64_t bit_offset)
6812 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6828str_bit_offset_from_index(
VALUE index)
6840 offset.long_value =
FIX2LONG(integer);
6841 if (offset.long_value < 0) {
6844 offset.value = (uint64_t)offset.long_value;
6845 offset.fits_long =
true;
6850 if (rb_int_negative_p(integer)) {
6853 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6854 rb_raise(rb_eArgError,
"bit index out of representable range");
6857 offset.value = (uint64_t)
NUM2ULL(integer);
6858 if (offset.value <= (uint64_t)LONG_MAX) {
6859 offset.long_value = (long)offset.value;
6860 offset.fits_long =
true;
6863 offset.long_value = 0;
6864 offset.fits_long =
false;
6874str_bit_length_from_index(
VALUE index)
6881 rb_raise(rb_eArgError,
"negative bit length");
6883 return (uint64_t)value;
6887 if (rb_int_negative_p(integer)) {
6888 rb_raise(rb_eArgError,
"negative bit length");
6890 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6891 rb_raise(rb_eArgError,
"bit length out of representable range");
6893 return (uint64_t)
NUM2ULL(integer);
6896static inline uint64_t
6897str_bit_size(
long byte_len)
6903 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT)
return UINT64_MAX;
6904 return (uint64_t)byte_len * CHAR_BIT;
6909 uint64_t end_exclusive;
6932 out->beg =
NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6934 out->end_open =
true;
6935 out->end_exclusive = 0;
6938 uint64_t end = str_bit_offset_from_index(end_v).value;
6939 out->end_open =
false;
6944 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6954str_bit_range_resolve(
const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6956 uint64_t beg = range->beg;
6957 if (beg > total_bits)
return false;
6959 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6960 if (end_exclusive < beg) end_exclusive = beg;
6963 *lenp = end_exclusive - beg;
6968str_lsb_first_from_opts(
VALUE opts)
6970 static ID keywords[1];
6978 if (vlsb_first ==
Qundef || vlsb_first ==
Qtrue) {
6981 if (vlsb_first ==
Qfalse) {
6984 rb_raise(rb_eArgError,
"lsb_first must be true or false");
6989str_lsb_first(
int argc,
VALUE *argv,
VALUE *index)
6994 return str_lsb_first_from_opts(opts);
6997static inline uint64_t
6998str_logical_to_physical_bit64(uint64_t logical,
bool lsb_first)
7000 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
7004str_logical_to_physical_bit(
long logical,
bool lsb_first)
7006 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
7011 unsigned int bit_offset;
7015str_bit_location_from_offset(uint64_t logical, bool lsb_first)
7021 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7023 location.byte_index = (long)(physical / CHAR_BIT);
7024 location.bit_offset = (
unsigned int)(physical % CHAR_BIT);
7029str_get_bit(
const char *ptr,
long bit_index)
7031 return (((
unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7037 return (((
unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7044 bool lsb_first = str_lsb_first(argc, argv, &index);
7047 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7051 if (offset.fits_long) {
7052 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.long_value, lsb_first));
7055 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7067rb_str_bit_get(
int argc,
VALUE *argv,
VALUE str)
7069 int bit = str_bit_get(argc, argv, str);
7081rb_str_bit_set_p(
int argc,
VALUE *argv,
VALUE str)
7083 int bit = str_bit_get(argc, argv, str);
7084 return bit < 0 ?
Qnil : RBOOL(bit);
7087enum str_bit_mutation {
7098static inline unsigned char
7099str_bit_region_byte_mask(
unsigned int lo,
unsigned int hi,
bool lsb_first)
7102 return (
unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7105 return (
unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7110str_apply_bit_mask(
unsigned char *
byte,
unsigned char mask,
enum str_bit_mutation mutation)
7117 *
byte &= (
unsigned char)~mask;
7127str_mutate_bit_region(
unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first,
enum str_bit_mutation mutation)
7129 uint64_t first_bit = beg;
7130 uint64_t last_bit = beg +
len - 1;
7131 long first_byte = (long)(first_bit / CHAR_BIT);
7132 long last_byte = (long)(last_bit / CHAR_BIT);
7133 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7134 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7136 if (first_byte == last_byte) {
7137 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7141 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7142 long middle_len = last_byte - first_byte - 1;
7143 if (middle_len > 0) {
7144 unsigned char *middle = ptr + first_byte + 1;
7147 memset(middle, 0xFF, middle_len);
7150 memset(middle, 0, middle_len);
7158 for (
long i = 0; i < middle_len; i++) {
7164 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7168str_mutate_single_bit(
VALUE str,
VALUE index,
bool lsb_first,
enum str_bit_mutation mutation)
7176 rb_check_frozen(str);
7178 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7183 ptr = (
unsigned char *)RSTRING_PTR(str);
7184 if (offset.fits_long) {
7185 bit_index = str_logical_to_physical_bit(offset.long_value, lsb_first);
7186 mask = (
unsigned char)(1u << (bit_index % CHAR_BIT));
7187 location.byte_index = bit_index / CHAR_BIT;
7190 location = str_bit_location_from_offset(offset.value, lsb_first);
7191 mask = (
unsigned char)(1u << location.bit_offset);
7194 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7199str_mutate_bit(
int argc,
VALUE *argv,
VALUE str,
enum str_bit_mutation mutation)
7201 VALUE target, length_v, opts;
7202 uint64_t beg = 0,
len = 0;
7205 int nargs =
rb_scan_args(argc, argv,
"11:", &target, &length_v, &opts);
7206 bool lsb_first = str_lsb_first_from_opts(opts);
7209 if (nargs == 1 && !is_range) {
7210 return str_mutate_single_bit(str, target, lsb_first, mutation);
7217 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7219 str_bit_range_to_offsets(target, &range);
7222 offset = str_bit_offset_from_index(target);
7223 len = str_bit_length_from_index(length_v);
7227 rb_check_frozen(str);
7235 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7237 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len) ||
len > total_bits - beg) {
7243 if (beg > total_bits ||
len > total_bits - beg) {
7248 if (
len == 0)
return str;
7251 str_mutate_bit_region((
unsigned char *)RSTRING_PTR(str), beg,
len, lsb_first, mutation);
7265rb_str_bit_set(
int argc,
VALUE *argv,
VALUE str)
7267 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7280rb_str_bit_clear(
int argc,
VALUE *argv,
VALUE str)
7282 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7295rb_str_bit_flip(
int argc,
VALUE *argv,
VALUE str)
7297 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7301str_count_bits(
const unsigned char *ptr,
long len)
7305 long unrolled_end =
len & ~31L;
7306 long aligned_end =
len & ~7L;
7309 for (;
off < unrolled_end;
off += 32) {
7310 uint64_t w0, w1, w2, w3;
7311 memcpy(&w0, ptr +
off, 8);
7312 memcpy(&w1, ptr +
off + 8, 8);
7313 memcpy(&w2, ptr +
off + 16, 8);
7314 memcpy(&w3, ptr +
off + 24, 8);
7315 count += rb_popcount64(w0);
7316 count += rb_popcount64(w1);
7317 count += rb_popcount64(w2);
7318 count += rb_popcount64(w3);
7322 for (;
off < aligned_end;
off += 8) {
7324 memcpy(&word, ptr +
off, 8);
7325 count += rb_popcount64(word);
7332 for (;
off <
len;
off++, shift += CHAR_BIT) {
7333 word |= (uint64_t)ptr[
off] << shift;
7335 count += rb_popcount64(word);
7342str_count_bits_region(
const unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first)
7344 uint64_t first_bit = beg;
7345 uint64_t last_bit = beg +
len - 1;
7346 long first_byte = (long)(first_bit / CHAR_BIT);
7347 long last_byte = (long)(last_bit / CHAR_BIT);
7348 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7349 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7351 if (first_byte == last_byte) {
7352 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7355 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7356 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7357 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7371rb_str_bit_count(
int argc,
VALUE *argv,
VALUE str)
7374 uint64_t beg = 0,
len = 0;
7377 int nargs =
rb_scan_args(argc, argv,
"02:", &v0, &v1, &opts);
7382 bool lsb_first = str_lsb_first_from_opts(opts);
7385 return ULL2NUM(str_count_bits((
const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7392 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7394 str_bit_range_to_offsets(v0, &range);
7396 else if (nargs == 1) {
7397 rb_raise(rb_eArgError,
"no bit length given");
7400 beg = str_bit_offset_from_index(v0).value;
7401 len = str_bit_length_from_index(v1);
7404 const unsigned char *ptr = (
const unsigned char *)RSTRING_PTR(str);
7405 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7407 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len)) {
7411 else if (beg >= total_bits) {
7416 if (
len > total_bits - beg)
len = total_bits - beg;
7418 return ULL2NUM(str_count_bits_region(ptr, beg,
len, lsb_first));
7422str_check_bitwise_length(
VALUE str,
VALUE other)
7424 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7425 rb_raise(rb_eArgError,
"operands must have the same length (%ld vs %ld)",
7426 RSTRING_LEN(str), RSTRING_LEN(other));
7431str_bitwise_result(
VALUE str)
7433 long len = RSTRING_LEN(str);
7435 rb_str_resize(result,
len);
7436 rb_enc_associate(result, rb_ascii8bit_encoding());
7441#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7443 name(unsigned char *dst, const unsigned char *src, long len) \
7446 long unrolled_end = len & ~31L; \
7447 long aligned_end = len & ~7L; \
7448 for (; off < unrolled_end; off += 32) { \
7449 uint64_t s0, s1, s2, s3; \
7450 memcpy(&s0, src + off, 8); \
7451 memcpy(&s1, src + off + 8, 8); \
7452 memcpy(&s2, src + off + 16, 8); \
7453 memcpy(&s3, src + off + 24, 8); \
7454 s0 = (expr_word(s0)); \
7455 s1 = (expr_word(s1)); \
7456 s2 = (expr_word(s2)); \
7457 s3 = (expr_word(s3)); \
7458 memcpy(dst + off, &s0, 8); \
7459 memcpy(dst + off + 8, &s1, 8); \
7460 memcpy(dst + off + 16, &s2, 8); \
7461 memcpy(dst + off + 24, &s3, 8); \
7463 for (; off < aligned_end; off += 8) { \
7465 memcpy(&word, src + off, 8); \
7466 word = (expr_word(word)); \
7467 memcpy(dst + off, &word, 8); \
7469 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7472#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7474 name(unsigned char *dst, const unsigned char *lhs, \
7475 const unsigned char *rhs, long len) \
7478 long unrolled_end = len & ~31L; \
7479 long aligned_end = len & ~7L; \
7480 for (; off < unrolled_end; off += 32) { \
7481 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7482 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7483 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7484 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7485 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7486 l0 = expr_word(l0, r0); \
7487 l1 = expr_word(l1, r1); \
7488 l2 = expr_word(l2, r2); \
7489 l3 = expr_word(l3, r3); \
7490 memcpy(dst + off, &l0, 8); \
7491 memcpy(dst + off + 8, &l1, 8); \
7492 memcpy(dst + off + 16, &l2, 8); \
7493 memcpy(dst + off + 24, &l3, 8); \
7495 for (; off < aligned_end; off += 8) { \
7496 uint64_t lhs_word, rhs_word; \
7497 memcpy(&lhs_word, lhs + off, 8); \
7498 memcpy(&rhs_word, rhs + off, 8); \
7499 lhs_word = expr_word(lhs_word, rhs_word); \
7500 memcpy(dst + off, &lhs_word, 8); \
7502 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7505#define STR_BITWISE_NOT_WORD(x) (~(x))
7506#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7507#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7508#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7509#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7510#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7511#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7512#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7514STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7515STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7516STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7517STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7527rb_str_bitwise_not(
VALUE str)
7529 long len = RSTRING_LEN(str);
7530 VALUE result = str_bitwise_result(str);
7531 str_bitwise_not((
unsigned char *)RSTRING_PTR(result),
7532 (
const unsigned char *)RSTRING_PTR(str),
len);
7544rb_str_bitwise_not_bang(
VALUE str)
7550 len = RSTRING_LEN(str);
7551 ptr = (
unsigned char *)RSTRING_PTR(str);
7552 str_bitwise_not(ptr, ptr,
len);
7556#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7558 rb_str_bitwise_##name(VALUE str, VALUE other) \
7562 StringValue(other); \
7563 str_check_bitwise_length(str, other); \
7564 len = RSTRING_LEN(str); \
7565 result = str_bitwise_result(str); \
7566 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7567 (const unsigned char *)RSTRING_PTR(str), \
7568 (const unsigned char *)RSTRING_PTR(other), len); \
7572 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7575 unsigned char *ptr; \
7576 StringValue(other); \
7577 str_check_bitwise_length(str, other); \
7578 rb_str_modify(str); \
7579 len = RSTRING_LEN(str); \
7580 ptr = (unsigned char *)RSTRING_PTR(str); \
7581 str_bitwise_##name(ptr, ptr, \
7582 (const unsigned char *)RSTRING_PTR(other), len); \
7586STR_DEFINE_BINARY_BITWISE_METHOD(and)
7587STR_DEFINE_BINARY_BITWISE_METHOD(or)
7588STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7591str_byte_substr(
VALUE str,
long beg,
long len,
int empty)
7593 long n = RSTRING_LEN(str);
7595 if (beg > n ||
len < 0)
return Qnil;
7598 if (beg < 0)
return Qnil;
7603 if (!empty)
return Qnil;
7607 VALUE str2 = str_subseq(str, beg,
len);
7609 str_enc_copy_direct(str2, str);
7611 if (RSTRING_LEN(str2) == 0) {
7612 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7646 long beg,
len = RSTRING_LEN(str);
7654 return str_byte_substr(str, beg,
len, TRUE);
7659 return str_byte_substr(str, idx, 1, FALSE);
7671rb_str_byteslice(
int argc,
VALUE *argv,
VALUE str)
7676 return str_byte_substr(str, beg,
len, TRUE);
7679 return str_byte_aref(str, argv[0]);
7683str_check_beg_len(
VALUE str,
long *beg,
long *
len)
7685 long end, slen = RSTRING_LEN(str);
7688 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7697 if (*
len > slen - *beg) {
7701 str_ensure_byte_pos(str, *beg);
7702 str_ensure_byte_pos(str, end);
7716rb_str_bytesplice(
int argc,
VALUE *argv,
VALUE str)
7718 long beg,
len, vbeg, vlen;
7723 if (!(argc == 2 || argc == 3 || argc == 5)) {
7724 rb_raise(rb_eArgError,
"wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7728 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7729 rb_builtin_class_name(argv[0]));
7736 vlen = RSTRING_LEN(val);
7741 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7742 rb_builtin_class_name(argv[2]));
7754 vlen = RSTRING_LEN(val);
7762 str_check_beg_len(str, &beg, &
len);
7763 str_check_beg_len(val, &vbeg, &vlen);
7764 str_modify_keep_cr(str);
7767 rb_enc_associate(str, rb_enc_check(str, val));
7770 rb_str_update_1(str, beg,
len, val, vbeg, vlen);
7792rb_str_reverse(
VALUE str)
7799 if (RSTRING_LEN(str) <= 1)
return str_duplicate(
rb_cString, str);
7800 enc = STR_ENC_GET(str);
7806 if (RSTRING_LEN(str) > 1) {
7807 if (single_byte_optimizable(str)) {
7814 int clen = rb_enc_fast_mbclen(s, e, enc);
7822 cr = rb_enc_asciicompat(enc) ?
7825 int clen = rb_enc_mbclen(s, e, enc);
7834 STR_SET_LEN(rev, RSTRING_LEN(str));
7835 str_enc_copy_direct(rev, str);
7857rb_str_reverse_bang(
VALUE str)
7859 if (RSTRING_LEN(str) > 1) {
7860 if (single_byte_optimizable(str)) {
7863 str_modify_keep_cr(str);
7864 s = RSTRING_PTR(str);
7873 str_shared_replace(str, rb_str_reverse(str));
7877 str_modify_keep_cr(str);
7906 i = rb_str_index(str, arg, 0);
7908 return RBOOL(i != -1);
7952 rb_raise(rb_eArgError,
"invalid radix %d", base);
7954 return rb_str_to_inum(str, base, FALSE);
7979rb_str_to_f(
VALUE str)
7996rb_str_to_s(
VALUE str)
8008 char s[RUBY_MAX_CHAR_LEN];
8009 int n = rb_enc_codelen(c, enc);
8011 rb_enc_mbcput(c, s, enc);
8016#define CHAR_ESC_LEN 13
8019rb_str_buf_cat_escaped_char(
VALUE result,
unsigned int c,
int unicode_p)
8021 char buf[CHAR_ESC_LEN + 1];
8029 snprintf(buf, CHAR_ESC_LEN,
"%c", c);
8031 else if (c < 0x10000) {
8032 snprintf(buf, CHAR_ESC_LEN,
"\\u%04X", c);
8035 snprintf(buf, CHAR_ESC_LEN,
"\\u{%X}", c);
8040 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", c);
8043 snprintf(buf, CHAR_ESC_LEN,
"\\x{%X}", c);
8046 l = (int)strlen(buf);
8052ruby_escaped_char(
int c)
8055 case '\0':
return "\\0";
8056 case '\n':
return "\\n";
8057 case '\r':
return "\\r";
8058 case '\t':
return "\\t";
8059 case '\f':
return "\\f";
8060 case '\013':
return "\\v";
8061 case '\010':
return "\\b";
8062 case '\007':
return "\\a";
8063 case '\033':
return "\\e";
8064 case '\x7f':
return "\\c?";
8070rb_str_escape(
VALUE str)
8074 const char *p = RSTRING_PTR(str);
8076 const char *prev = p;
8077 char buf[CHAR_ESC_LEN + 1];
8079 int unicode_p = rb_enc_unicode_p(enc);
8080 int asciicompat = rb_enc_asciicompat(enc);
8085 int n = rb_enc_precise_mbclen(p, pend, enc);
8087 if (p > prev) str_buf_cat(result, prev, p - prev);
8088 n = rb_enc_mbminlen(enc);
8090 n = (int)(pend - p);
8092 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8093 str_buf_cat(result, buf, strlen(buf));
8099 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8101 cc = ruby_escaped_char(c);
8103 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8104 str_buf_cat(result, cc, strlen(cc));
8107 else if (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c)) {
8110 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8111 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8115 if (p > prev) str_buf_cat(result, prev, p - prev);
8125static const bool inspect_no_escape[256] = {
8126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8128 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8129 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8130 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8131 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8132 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8133 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
8149 const char *p, *pend, *prev;
8150 char buf[CHAR_ESC_LEN + 1];
8152 rb_encoding *resenc = rb_default_internal_encoding();
8153 int unicode_p = rb_enc_unicode_p(enc);
8154 int asciicompat = rb_enc_asciicompat(enc);
8155 int cr = rb_enc_str_coderange(str);
8157 if (resenc == NULL) resenc = rb_default_external_encoding();
8158 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8159 rb_enc_associate(result, resenc);
8160 str_buf_cat2(result,
"\"");
8173 while (p < pend && inspect_no_escape[(
unsigned char)*p]) p++;
8174 if (p >= pend)
break;
8177 n = rb_enc_precise_mbclen(p, pend, enc);
8179 if (p > prev) str_buf_cat(result, prev, p - prev);
8180 n = rb_enc_mbminlen(enc);
8182 n = (int)(pend - p);
8184 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8185 str_buf_cat(result, buf, strlen(buf));
8191 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8193 if ((asciicompat || unicode_p) &&
8194 (c ==
'"'|| c ==
'\\' ||
8199 (cc ==
'$' || cc ==
'@' || cc ==
'{'))))) {
8200 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8201 str_buf_cat2(result,
"\\");
8202 if (asciicompat || enc == resenc) {
8208 case '\n': cc =
'n';
break;
8209 case '\r': cc =
'r';
break;
8210 case '\t': cc =
't';
break;
8211 case '\f': cc =
'f';
break;
8212 case '\013': cc =
'v';
break;
8213 case '\010': cc =
'b';
break;
8214 case '\007': cc =
'a';
break;
8215 case 033: cc =
'e';
break;
8216 default: cc = 0;
break;
8219 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8222 str_buf_cat(result, buf, 2);
8235 (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c))) {
8239 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8240 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8245 if (p > prev) str_buf_cat(result, prev, p - prev);
8246 str_buf_cat2(result,
"\"");
8251#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8264 int encidx = rb_enc_get_index(str);
8267 const char *p, *pend;
8270 int u8 = (encidx == rb_utf8_encindex());
8271 static const char nonascii_suffix[] =
".dup.force_encoding(\"%s\")";
8274 if (!rb_enc_asciicompat(enc)) {
8276 len += strlen(enc->name);
8279 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8282 unsigned char c = *p++;
8285 case '"':
case '\\':
8286 case '\n':
case '\r':
8287 case '\t':
case '\f':
8288 case '\013':
case '\010':
case '\007':
case '\033':
8293 clen = IS_EVSTR(p, pend) ? 2 : 1;
8301 if (u8 && c > 0x7F) {
8302 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8304 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8307 else if (cc <= 0xFFFFF)
8320 if (clen > LONG_MAX -
len) {
8327 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8328 q = RSTRING_PTR(result); qend = q +
len + 1;
8332 unsigned char c = *p++;
8334 if (c ==
'"' || c ==
'\\') {
8338 else if (c ==
'#') {
8339 if (IS_EVSTR(p, pend)) *q++ =
'\\';
8342 else if (c ==
'\n') {
8346 else if (c ==
'\r') {
8350 else if (c ==
'\t') {
8354 else if (c ==
'\f') {
8358 else if (c ==
'\013') {
8362 else if (c ==
'\010') {
8366 else if (c ==
'\007') {
8370 else if (c ==
'\033') {
8380 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8382 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8385 snprintf(q, qend-q,
"u%04X", cc);
8387 snprintf(q, qend-q,
"u{%X}", cc);
8392 snprintf(q, qend-q,
"x%02X", c);
8398 if (!rb_enc_asciicompat(enc)) {
8399 snprintf(q, qend-q, nonascii_suffix, enc->name);
8400 encidx = rb_ascii8bit_encindex();
8403 rb_enc_associate_index(result, encidx);
8409unescape_ascii(
unsigned int c)
8433undump_after_backslash(
VALUE undumped,
const char **ss,
const char *s_end,
rb_encoding **penc,
bool *utf8,
bool *binary)
8435 const char *s = *ss;
8439 unsigned char buf[6];
8457 *buf = unescape_ascii(*s);
8469 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8470 if (*penc != enc_utf8) {
8472 rb_enc_associate(undumped, enc_utf8);
8489 if (hexlen == 0 || hexlen > 6) {
8495 if (0xd800 <= c && c <= 0xdfff) {
8498 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8508 if (0xd800 <= c && c <= 0xdfff) {
8511 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8541static VALUE rb_str_is_ascii_only_p(
VALUE str);
8553str_undump(
VALUE str)
8555 const char *s = RSTRING_PTR(str);
8558 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8560 bool binary =
false;
8564 if (rb_str_is_ascii_only_p(str) ==
Qfalse) {
8567 if (!str_null_check(str, &w)) {
8570 if (RSTRING_LEN(str) < 2)
goto invalid_format;
8571 if (*s !=
'"')
goto invalid_format;
8589 static const char force_encoding_suffix[] =
".force_encoding(\"";
8590 static const char dup_suffix[] =
".dup";
8591 const char *encname;
8596 size =
sizeof(dup_suffix) - 1;
8597 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8599 size =
sizeof(force_encoding_suffix) - 1;
8600 if (s_end - s <= size)
goto invalid_format;
8601 if (memcmp(s, force_encoding_suffix, size) != 0)
goto invalid_format;
8605 rb_raise(
rb_eRuntimeError,
"dumped string contained Unicode escape but used force_encoding");
8609 s = memchr(s,
'"', s_end-s);
8611 if (!s)
goto invalid_format;
8612 if (s_end - s != 2)
goto invalid_format;
8613 if (s[0] !=
'"' || s[1] !=
')')
goto invalid_format;
8615 encidx = rb_enc_find_index2(encname, (
long)size);
8619 rb_enc_associate_index(undumped, encidx);
8629 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8640 rb_raise(
rb_eRuntimeError,
"invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8646 if (rb_enc_dummy_p(enc)) {
8653str_true_enc(
VALUE str)
8656 rb_str_check_dummy_enc(enc);
8660static OnigCaseFoldType
8661check_case_options(
int argc,
VALUE *argv, OnigCaseFoldType flags)
8666 rb_raise(rb_eArgError,
"too many options");
8667 if (argv[0]==sym_turkic) {
8668 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8670 if (argv[1]==sym_lithuanian)
8671 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8673 rb_raise(rb_eArgError,
"invalid second option");
8676 else if (argv[0]==sym_lithuanian) {
8677 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8679 if (argv[1]==sym_turkic)
8680 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8682 rb_raise(rb_eArgError,
"invalid second option");
8686 rb_raise(rb_eArgError,
"too many options");
8687 else if (argv[0]==sym_ascii)
8688 flags |= ONIGENC_CASE_ASCII_ONLY;
8689 else if (argv[0]==sym_fold) {
8690 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8691 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8693 rb_raise(rb_eArgError,
"option :fold only allowed for downcasing");
8696 rb_raise(rb_eArgError,
"invalid option");
8703 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() ||
rb_enc_mbmaxlen(enc) == 1))
8705 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8710#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8711#ifndef CASEMAP_DEBUG
8712# define CASEMAP_DEBUG 0
8720 OnigUChar space[FLEX_ARY_LEN];
8724mapping_buffer_free(
void *p)
8728 while (current_buffer) {
8729 previous_buffer = current_buffer;
8730 current_buffer = current_buffer->next;
8731 ruby_xfree_sized(previous_buffer, offsetof(
mapping_buffer, space) + previous_buffer->capa);
8737 {0, mapping_buffer_free,},
8738 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8746 const OnigUChar *source_current, *source_end;
8747 int target_length = 0;
8748 VALUE buffer_anchor;
8751 size_t buffer_count = 0;
8752 int buffer_length_or_invalid;
8754 if (RSTRING_LEN(source) == 0)
return str_duplicate(
rb_cString, source);
8756 source_current = (OnigUChar*)RSTRING_PTR(source);
8761 while (source_current < source_end) {
8763 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8764 if (CASEMAP_DEBUG) {
8765 fprintf(stderr,
"Buffer allocation, capa is %"PRIuSIZE
"\n",
capa);
8768 *pre_buffer = current_buffer;
8769 pre_buffer = ¤t_buffer->next;
8770 current_buffer->next = NULL;
8771 current_buffer->capa =
capa;
8772 buffer_length_or_invalid = enc->case_map(flags,
8773 &source_current, source_end,
8774 current_buffer->space,
8775 current_buffer->space+current_buffer->capa,
8777 if (buffer_length_or_invalid < 0) {
8778 current_buffer =
DATA_PTR(buffer_anchor);
8780 mapping_buffer_free(current_buffer);
8781 rb_raise(rb_eArgError,
"input string invalid");
8783 target_length += current_buffer->used = buffer_length_or_invalid;
8785 if (CASEMAP_DEBUG) {
8786 fprintf(stderr,
"Buffer count is %"PRIuSIZE
"\n", buffer_count);
8789 if (buffer_count==1) {
8790 target =
rb_str_new((
const char*)current_buffer->space, target_length);
8793 char *target_current;
8796 target_current = RSTRING_PTR(target);
8797 current_buffer =
DATA_PTR(buffer_anchor);
8798 while (current_buffer) {
8799 memcpy(target_current, current_buffer->space, current_buffer->used);
8800 target_current += current_buffer->used;
8801 current_buffer = current_buffer->next;
8804 current_buffer =
DATA_PTR(buffer_anchor);
8806 mapping_buffer_free(current_buffer);
8811 str_enc_copy_direct(target, source);
8820 const OnigUChar *source_current, *source_end;
8821 OnigUChar *target_current, *target_end;
8822 long old_length = RSTRING_LEN(source);
8823 int length_or_invalid;
8825 if (old_length == 0)
return Qnil;
8827 source_current = (OnigUChar*)RSTRING_PTR(source);
8829 if (source == target) {
8830 target_current = (OnigUChar*)source_current;
8831 target_end = (OnigUChar*)source_end;
8834 target_current = (OnigUChar*)RSTRING_PTR(target);
8838 length_or_invalid = onigenc_ascii_only_case_map(flags,
8839 &source_current, source_end,
8840 target_current, target_end, enc);
8841 if (length_or_invalid < 0)
8842 rb_raise(rb_eArgError,
"input string invalid");
8843 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8844 fprintf(stderr,
"problem with rb_str_ascii_casemap"
8845 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8846 rb_raise(rb_eArgError,
"internal problem with rb_str_ascii_casemap"
8847 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8850 str_enc_copy(target, source);
8856upcase_single(
VALUE str)
8858 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8859 bool modified =
false;
8862 unsigned int c = *(
unsigned char*)s;
8864 if (
'a' <= c && c <=
'z') {
8865 *s =
'A' + (c -
'a');
8886rb_str_upcase_bang(
int argc,
VALUE *argv,
VALUE str)
8889 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8891 flags = check_case_options(argc, argv, flags);
8892 str_modify_keep_cr(str);
8893 enc = str_true_enc(str);
8894 if (case_option_single_p(flags, enc, str)) {
8895 if (upcase_single(str))
8896 flags |= ONIGENC_CASE_MODIFIED;
8898 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8899 rb_str_ascii_casemap(str, str, &flags, enc);
8901 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8903 if (ONIGENC_CASE_MODIFIED&flags)
return str;
8916rb_str_upcase(
int argc,
VALUE *argv,
VALUE str)
8919 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8922 flags = check_case_options(argc, argv, flags);
8923 enc = str_true_enc(str);
8924 if (case_option_single_p(flags, enc, str)) {
8925 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8926 str_enc_copy_direct(ret, str);
8929 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8931 rb_str_ascii_casemap(str, ret, &flags, enc);
8934 ret = rb_str_casemap(str, &flags, enc);
8941downcase_single(
VALUE str)
8943 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8944 bool modified =
false;
8947 unsigned int c = *(
unsigned char*)s;
8949 if (
'A' <= c && c <=
'Z') {
8950 *s =
'a' + (c -
'A');
8972rb_str_downcase_bang(
int argc,
VALUE *argv,
VALUE str)
8975 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8977 flags = check_case_options(argc, argv, flags);
8978 str_modify_keep_cr(str);
8979 enc = str_true_enc(str);
8980 if (case_option_single_p(flags, enc, str)) {
8981 if (downcase_single(str))
8982 flags |= ONIGENC_CASE_MODIFIED;
8984 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8985 rb_str_ascii_casemap(str, str, &flags, enc);
8987 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8989 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9003rb_str_downcase(
int argc,
VALUE *argv,
VALUE str)
9006 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9009 flags = check_case_options(argc, argv, flags);
9010 enc = str_true_enc(str);
9011 if (case_option_single_p(flags, enc, str)) {
9012 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9013 str_enc_copy_direct(ret, str);
9014 downcase_single(ret);
9016 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9018 rb_str_ascii_casemap(str, ret, &flags, enc);
9021 ret = rb_str_casemap(str, &flags, enc);
9028capitalize_single(
VALUE str)
9030 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
9031 bool modified =
false;
9034 unsigned int c = (
unsigned char)*s;
9036 if (
'a' <= c && c <=
'z') {
9037 *s =
'A' + (c -
'a');
9043 unsigned int c = (
unsigned char)*s;
9045 if (
'A' <= c && c <=
'Z') {
9046 *s =
'a' + (c -
'A');
9068rb_str_capitalize_bang(
int argc,
VALUE *argv,
VALUE str)
9071 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9073 flags = check_case_options(argc, argv, flags);
9074 str_modify_keep_cr(str);
9075 enc = str_true_enc(str);
9076 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9077 if (case_option_single_p(flags, enc, str)) {
9078 if (capitalize_single(str))
9079 flags |= ONIGENC_CASE_MODIFIED;
9081 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9082 rb_str_ascii_casemap(str, str, &flags, enc);
9084 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9086 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9100rb_str_capitalize(
int argc,
VALUE *argv,
VALUE str)
9103 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9106 flags = check_case_options(argc, argv, flags);
9107 enc = str_true_enc(str);
9108 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str;
9109 if (case_option_single_p(flags, enc, str)) {
9110 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9111 str_enc_copy_direct(ret, str);
9112 capitalize_single(ret);
9114 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9116 rb_str_ascii_casemap(str, ret, &flags, enc);
9119 ret = rb_str_casemap(str, &flags, enc);
9138rb_str_swapcase_bang(
int argc,
VALUE *argv,
VALUE str)
9141 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9143 flags = check_case_options(argc, argv, flags);
9144 str_modify_keep_cr(str);
9145 enc = str_true_enc(str);
9146 if (flags&ONIGENC_CASE_ASCII_ONLY)
9147 rb_str_ascii_casemap(str, str, &flags, enc);
9149 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9151 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9165rb_str_swapcase(
int argc,
VALUE *argv,
VALUE str)
9168 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9171 flags = check_case_options(argc, argv, flags);
9172 enc = str_true_enc(str);
9173 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str_duplicate(
rb_cString, str);
9174 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9176 rb_str_ascii_casemap(str, ret, &flags, enc);
9179 ret = rb_str_casemap(str, &flags, enc);
9184typedef unsigned char *USTR;
9188 unsigned int now, max;
9189 const char *p, *pend;
9200 if (t->p == t->pend)
return -1;
9201 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'\\' && t->p + n < t->pend) {
9204 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9206 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'-' && t->p + n < t->pend) {
9208 if (t->p < t->pend) {
9209 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9212 if (t->now < 0x80 && c < 0x80) {
9213 rb_raise(rb_eArgError,
9214 "invalid range \"%c-%c\" in string transliteration",
9218 rb_raise(rb_eArgError,
"invalid range in string transliteration");
9222 else if (t->now < c) {
9231 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9232 if (t->now == t->max) {
9237 if (t->now < t->max) {
9253 const unsigned int errc = -1;
9254 unsigned int trans[256];
9256 struct tr trsrc, trrepl;
9258 unsigned int c, c0, last = 0;
9259 int modify = 0, i, l;
9260 unsigned char *s, *send;
9262 int singlebyte = single_byte_optimizable(str);
9266#define CHECK_IF_ASCII(c) \
9267 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9268 (cr = ENC_CODERANGE_VALID) : 0)
9272 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9273 if (RSTRING_LEN(repl) == 0) {
9274 return rb_str_delete_bang(1, &src, str);
9278 e1 = rb_enc_check(str, src);
9279 e2 = rb_enc_check(str, repl);
9284 enc = rb_enc_check(src, repl);
9286 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9287 if (RSTRING_LEN(src) > 1 &&
9288 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) ==
'^' &&
9289 trsrc.p + l < trsrc.pend) {
9293 trrepl.p = RSTRING_PTR(repl);
9294 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9295 trsrc.gen = trrepl.gen = 0;
9296 trsrc.now = trrepl.now = 0;
9297 trsrc.max = trrepl.max = 0;
9300 for (i=0; i<256; i++) {
9303 while ((c = trnext(&trsrc, enc)) != errc) {
9308 if (!hash) hash = rb_hash_new();
9312 while ((c = trnext(&trrepl, enc)) != errc)
9315 for (i=0; i<256; i++) {
9316 if (trans[i] != errc) {
9324 for (i=0; i<256; i++) {
9327 while ((c = trnext(&trsrc, enc)) != errc) {
9328 r = trnext(&trrepl, enc);
9329 if (r == errc) r = trrepl.now;
9332 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9335 if (!hash) hash = rb_hash_new();
9343 str_modify_keep_cr(str);
9344 s = (
unsigned char *)RSTRING_PTR(str); send = (
unsigned char *)
RSTRING_END(str);
9345 termlen = rb_enc_mbminlen(enc);
9348 long offset, max = RSTRING_LEN(str);
9349 unsigned int save = -1;
9350 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9355 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9357 SIZED_FREE_N(buf, max + termlen);
9358 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9361 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9363 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9372 if (cflag) c = last;
9375 else if (cflag) c = errc;
9381 if (c != (
unsigned int)-1) {
9387 tlen = rb_enc_codelen(c, enc);
9393 if (enc != e1) may_modify = 1;
9395 if ((offset = t - buf) + tlen > max) {
9396 size_t MAYBE_UNUSED(old) = max + termlen;
9397 max = offset + tlen + (send - s);
9398 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9401 rb_enc_mbcput(c, t, enc);
9402 if (may_modify && memcmp(s, t, tlen) != 0) {
9408 if (!STR_EMBED_P(str)) {
9409 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9411 TERM_FILL((
char *)t, termlen);
9412 RSTRING(str)->as.heap.ptr = (
char *)buf;
9413 STR_SET_LEN(str, t - buf);
9414 STR_SET_NOEMBED(str);
9415 RSTRING(str)->as.heap.aux.capa = max;
9419 c = (
unsigned char)*s;
9420 if (trans[c] != errc) {
9437 long offset, max = (long)((send - s) * 1.2);
9438 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9443 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9445 SIZED_FREE_N(buf, max + termlen);
9446 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9449 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9451 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9459 if (cflag) c = last;
9462 else if (cflag) c = errc;
9466 c = cflag ? last : errc;
9469 tlen = rb_enc_codelen(c, enc);
9474 if (enc != e1) may_modify = 1;
9476 if ((offset = t - buf) + tlen > max) {
9477 size_t MAYBE_UNUSED(old) = max + termlen;
9478 max = offset + tlen + (long)((send - s) * 1.2);
9479 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9483 rb_enc_mbcput(c, t, enc);
9484 if (may_modify && memcmp(s, t, tlen) != 0) {
9491 if (!STR_EMBED_P(str)) {
9492 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9494 TERM_FILL((
char *)t, termlen);
9495 RSTRING(str)->as.heap.ptr = (
char *)buf;
9496 STR_SET_LEN(str, t - buf);
9497 STR_SET_NOEMBED(str);
9498 RSTRING(str)->as.heap.aux.capa = max;
9504 rb_enc_associate(str, enc);
9514 size_t initial_capa;
9518tr_buffer_init(
struct tr_buffer *buffer,
size_t initial_capa)
9520 if (initial_capa < 32) {
9523 *buffer = (
struct tr_buffer){ .initial_capa = initial_capa };
9527tr_buffer_ensure_capa(
struct tr_buffer *buffer,
size_t extra_capa)
9529 size_t offset = buffer->ptr - buffer->buf;
9530 size_t required_capa = offset + extra_capa;
9531 if (UNLIKELY(buffer->capa < required_capa)) {
9532 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9534 while (new_capa < required_capa) {
9535 new_capa = (size_t)(new_capa * 1.2);
9537 SIZED_REALLOC_N(buffer->buf,
unsigned char, new_capa, buffer->capa);
9538 buffer->ptr = buffer->buf + offset;
9539 buffer->capa = new_capa;
9544tr_buffer_append(
struct tr_buffer *buffer,
const unsigned char *ptr,
size_t len)
9547 tr_buffer_ensure_capa(buffer,
len);
9548 memcpy(buffer->ptr, ptr,
len);
9556 tr_buffer_append(buffer, (
unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9562 tr_buffer_ensure_capa(buffer, 4);
9563 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9570 SIZED_FREE_N(buffer->buf, buffer->capa);
9587tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9590 struct tr_pair *pair = &args->pairs[args->index];
9598 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9599 rb_raise(rb_eArgError,
"keys must be of size 1");
9602 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9603 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9605 pair->search = search;
9606 pair->replace = replace;
9610#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9613 const unsigned char *s;
9614 const unsigned char *send;
9617 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9618 unsigned int needles_count;
9619#ifdef HAVE_SIMD_NEON
9620 uint64_t matches_bitmap;
9622#ifdef HAVE_SIMD_SSE2
9627 VALUE trans_table[256];
9633 while (search->s < search->send) {
9634 VALUE repl = search->trans_table[*search->s];
9635 if (UNLIKELY(repl)) {
9645#ifdef HAVE_SIMD_SSE2
9650 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9652 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9653 search->matches_bitmap >>= trailing_zeros;
9654 search->s += trailing_zeros;
9657 return search->trans_table[*search->s];
9663 const unsigned int needles_count = search->needles_count;
9664 if (needles_count) {
9667 if (search->matches_bitmap) {
9668 return tr_trans_pairs_next_match_sse2(search);
9671 if ((
size_t)(search->send - search->s) >=
sizeof(__m128i)) {
9673 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9674 for (i = 0; i < needles_count; i++) {
9675 masks[i] = _mm_set1_epi8(search->needles[i]);
9679 const __m128i bytes = _mm_loadu_si128((__m128i
const *)search->s);
9681 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9682 for (i = 0; i < needles_count; i++) {
9683 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9686 for (i = 1; i < needles_count; i++) {
9687 matches[0] = _mm_or_si128(matches[0], matches[i]);
9690 const int bitmap = _mm_movemask_epi8(matches[0]);
9693 search->matches_bitmap = bitmap;
9694 return tr_trans_pairs_next_match_sse2(search);
9696 search->s +=
sizeof(__m128i);
9697 }
while ((
size_t)(search->send - search->s) >=
sizeof(__m128i));
9700 return tr_trans_pairs_search_basic(search);
9703#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9706#ifdef HAVE_SIMD_NEON
9711 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9714 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9715 search->matches_bitmap >>= trailing_zeros;
9716 search->s += trailing_zeros / 4;
9719 return search->trans_table[*search->s];
9725 const unsigned int needles_count = search->needles_count;
9726 if (needles_count) {
9729 if (search->matches_bitmap) {
9730 return tr_trans_pairs_next_match_neon(search);
9733 if ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t)) {
9735 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9736 for (i = 0; i < needles_count; i++) {
9737 masks[i] = vdupq_n_u8(search->needles[i]);
9741 const uint8x16_t bytes = vld1q_u8(search->s);
9743 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9744 for (i = 0; i < needles_count; i++) {
9745 matches[i] = vceqq_u8(bytes, masks[i]);
9748 for (i = 1; i < needles_count; i++) {
9749 matches[0] = vorrq_u8(matches[0], matches[i]);
9752 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9753 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9756 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9757 return tr_trans_pairs_next_match_neon(search);
9759 search->s +=
sizeof(uint8x16_t);
9760 }
while ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t));
9763 return tr_trans_pairs_search_basic(search);
9766#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9769#ifndef tr_trans_pairs_search_impl
9770#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9778 search->matches_bitmap >>= 1;
9787 mustnot_broken(str);
9790 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0)
return Qnil;
9795 int cr = rb_enc_str_coderange(str);
9809 pairs_count = coerce_args.index;
9813 const unsigned char *sstart = (
unsigned char *)RSTRING_PTR(str);
9814 long str_len = RSTRING_LEN(str);
9815 int termlen = rb_enc_mbminlen(e1);
9818 tr_buffer_init(&buffer, str_len);
9819 bool modify =
false;
9821 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9825 .send = sstart + str_len,
9828 for (
size_t index = 0; index < pairs_count; index++) {
9829 struct tr_pair *pair = &pairs[index];
9831 char *ptr = RSTRING_PTR(pair->search);
9832 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr,
RSTRING_END(pair->search), e1);
9834 const unsigned char first_byte = (
unsigned char)*ptr;
9837 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9838 search.needles[index] = first_byte;
9839 search.needles_count++;
9843 if (rb_enc_codelen(codepoint, e1) == 1) {
9844 search.trans_table[first_byte] = pair->replace;
9847 search.trans_table[first_byte] =
Qundef;
9849 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9851 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9855 const unsigned char *checkpoint = search.s;
9857 while ((repl = tr_trans_pairs_search_impl(&search))) {
9860 if (UNLIKELY(repl ==
Qundef)) {
9861 unsigned int c = rb_enc_mbc_to_codepoint((
char *)search.s, (
char *)search.send, e1);
9862 clen = rb_enc_codelen(c, e1);
9863 repl = rb_hash_lookup2(hash,
UINT2NUM(c), 0);
9865 tr_trans_pairs_consume_match(&search);
9873 if (checkpoint < search.s) {
9874 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9876 tr_buffer_append_str(&buffer, repl);
9877 checkpoint = search.s + clen;
9878 tr_trans_pairs_consume_match(&search);
9885 if (modify && checkpoint < search.s) {
9886 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9890 const unsigned char *s = sstart;
9891 const unsigned char *send = sstart + str_len;
9893 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9895 for (
size_t index = 0; index < pairs_count; index++) {
9896 struct tr_pair *pair = &pairs[index];
9898 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search),
RSTRING_END(pair->search), e1);
9899 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9903 bool may_modify =
false;
9905 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9907 tr_buffer_free(&buffer);
9908 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9911 unsigned int c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9912 unsigned int c0 = c;
9914 long tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
9917 if (
NIL_P(replacement)) {
9918 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9920 if (enc != e1) may_modify =
true;
9923 tlen = RSTRING_LEN(replacement);
9927 if (
NIL_P(replacement)) {
9928 tr_buffer_mbcput(&buffer, c, enc);
9931 tr_buffer_append_str(&buffer, replacement);
9934 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
9950 if (!STR_EMBED_P(str)) {
9951 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9953 tr_buffer_ensure_capa(&buffer, termlen);
9954 TERM_FILL((
char *)buffer.ptr, termlen);
9955 RSTRING(str)->as.heap.ptr = (
char *)buffer.buf;
9956 STR_SET_LEN(str, buffer.ptr - buffer.buf);
9957 STR_SET_NOEMBED(str);
9958 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
9964 rb_enc_associate(str, e1);
9982rb_str_tr_bang(
int argc,
VALUE *argv,
VALUE str)
9987 VALUE pairs = argv[0];
9988 return tr_trans_pairs(str, pairs);
9991 VALUE src = argv[0], repl = argv[1];
9992 return tr_trans(str, src, repl, 0);
10056 VALUE pairs = argv[0];
10057 VALUE result = tr_trans_pairs(str, pairs);
10058 if (
NIL_P(result)) result = str;
10062 VALUE src = argv[0], repl = argv[1];
10063 tr_trans(str, src, repl, 0);
10067#define TR_TABLE_MAX (UCHAR_MAX+1)
10068#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10070tr_setup_table(
VALUE str,
char stable[TR_TABLE_SIZE],
int first,
10073 const unsigned int errc = -1;
10074 char buf[TR_TABLE_MAX];
10077 VALUE table = 0, ptable = 0;
10078 int i, l, cflag = 0;
10080 tr.p = RSTRING_PTR(str);
tr.pend =
tr.p + RSTRING_LEN(str);
10081 tr.gen =
tr.now =
tr.max = 0;
10083 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(
tr.p,
tr.pend, &l, enc) ==
'^') {
10088 for (i=0; i<TR_TABLE_MAX; i++) {
10091 stable[TR_TABLE_MAX] = cflag;
10093 else if (stable[TR_TABLE_MAX] && !cflag) {
10094 stable[TR_TABLE_MAX] = 0;
10096 for (i=0; i<TR_TABLE_MAX; i++) {
10100 while ((c = trnext(&
tr, enc)) != errc) {
10101 if (c < TR_TABLE_MAX) {
10102 buf[(
unsigned char)c] = !cflag;
10107 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10110 table = ptable ? ptable : rb_hash_new();
10114 table = rb_hash_new();
10119 if (table && (!ptable || (cflag ^ !
NIL_P(rb_hash_aref(ptable, key))))) {
10120 rb_hash_aset(table, key,
Qtrue);
10124 for (i=0; i<TR_TABLE_MAX; i++) {
10125 stable[i] = stable[i] && buf[i];
10127 if (!table && !cflag) {
10134tr_find(
unsigned int c,
const char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
10136 if (c < TR_TABLE_MAX) {
10137 return table[c] != 0;
10143 if (!
NIL_P(rb_hash_lookup(del, v)) &&
10144 (!nodel ||
NIL_P(rb_hash_lookup(nodel, v)))) {
10148 else if (nodel && !
NIL_P(rb_hash_lookup(nodel, v))) {
10151 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10166rb_str_delete_bang(
int argc,
VALUE *argv,
VALUE str)
10168 char squeez[TR_TABLE_SIZE];
10170 char *s, *send, *t;
10171 VALUE del = 0, nodel = 0;
10173 int i, ascompat, cr;
10175 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
10177 for (i=0; i<argc; i++) {
10181 enc = rb_enc_check(str, s);
10182 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10185 str_modify_keep_cr(str);
10186 ascompat = rb_enc_asciicompat(enc);
10187 s = t = RSTRING_PTR(str);
10194 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10199 if (t != s) *t = c;
10205 c = rb_enc_codepoint_len(s, send, &clen, enc);
10207 if (tr_find(c, squeez, del, nodel)) {
10211 if (t != s) rb_enc_mbcput(c, t, enc);
10218 TERM_FILL(t, TERM_LEN(str));
10219 STR_SET_LEN(str, t - RSTRING_PTR(str));
10222 if (modify)
return str;
10236rb_str_delete(
int argc,
VALUE *argv,
VALUE str)
10239 rb_str_delete_bang(argc, argv, str);
10257rb_str_squeeze_bang(
int argc,
VALUE *argv,
VALUE str)
10259 char squeez[TR_TABLE_SIZE];
10261 VALUE del = 0, nodel = 0;
10262 unsigned char *s, *send, *t;
10264 int ascompat, singlebyte = single_byte_optimizable(str);
10268 enc = STR_ENC_GET(str);
10271 for (i=0; i<argc; i++) {
10275 enc = rb_enc_check(str, s);
10276 if (singlebyte && !single_byte_optimizable(s))
10278 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10282 str_modify_keep_cr(str);
10283 s = t = (
unsigned char *)RSTRING_PTR(str);
10284 if (!s || RSTRING_LEN(str) == 0)
return Qnil;
10287 ascompat = rb_enc_asciicompat(enc);
10291 unsigned int c = *s++;
10292 if (c != save || (argc > 0 && !squeez[c])) {
10302 if (ascompat && (c = *s) < 0x80) {
10303 if (c != save || (argc > 0 && !squeez[c])) {
10309 c = rb_enc_codepoint_len((
char *)s, (
char *)send, &clen, enc);
10311 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10312 if (t != s) rb_enc_mbcput(c, t, enc);
10321 TERM_FILL((
char *)t, TERM_LEN(str));
10322 if ((
char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10323 STR_SET_LEN(str, (
char *)t - RSTRING_PTR(str));
10327 if (modify)
return str;
10341rb_str_squeeze(
int argc,
VALUE *argv,
VALUE str)
10344 rb_str_squeeze_bang(argc, argv, str);
10364 return tr_trans(str, src, repl, 1);
10392 tr_trans(str, src, repl, 1);
10405rb_str_count(
int argc,
VALUE *argv,
VALUE str)
10407 char table[TR_TABLE_SIZE];
10409 VALUE del = 0, nodel = 0, tstr;
10410 const char *s, *send;
10419 enc = rb_enc_check(str, tstr);
10422 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10423 (ptstr = RSTRING_PTR(tstr),
10424 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (
const unsigned char *)ptstr, (
const unsigned char *)ptstr+1)) &&
10425 !is_broken_string(str)) {
10427 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10429 s = RSTRING_PTR(str);
10430 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10433 if (*(
unsigned char*)s++ == c) n++;
10439 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10440 for (i=1; i<argc; i++) {
10443 enc = rb_enc_check(str, tstr);
10444 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10447 s = RSTRING_PTR(str);
10448 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10450 ascompat = rb_enc_asciicompat(enc);
10454 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10462 c = rb_enc_codepoint_len(s, send, &clen, enc);
10463 if (tr_find(c, table, del, nodel)) {
10474rb_fs_check(
VALUE val)
10478 if (
NIL_P(val))
return 0;
10483static const char isspacetable[256] = {
10484 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10485 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10486 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10487 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10489 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10490 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10491 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10492 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10493 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10494 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10495 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10496 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10502#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10505split_string(
VALUE result,
VALUE str,
long beg,
long len,
long empty_count)
10507 if (empty_count >= 0 &&
len == 0) {
10508 return empty_count + 1;
10510 if (empty_count > 0) {
10515 }
while (--empty_count > 0);
10519 rb_yield(str_new_empty_String(str));
10520 }
while (--empty_count > 0);
10530 return empty_count;
10534 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10538literal_split_pattern(
VALUE spat, split_type_t default_type)
10546 return SPLIT_TYPE_CHARS;
10548 else if (rb_enc_asciicompat(enc)) {
10549 if (
len == 1 && ptr[0] ==
' ') {
10550 return SPLIT_TYPE_AWK;
10555 if (rb_enc_ascget(ptr, ptr +
len, &l, enc) ==
' ' &&
len == l) {
10556 return SPLIT_TYPE_AWK;
10559 return default_type;
10572rb_str_split_m(
int argc,
VALUE *argv,
VALUE str)
10577 split_type_t split_type;
10578 long beg, end, i = 0, empty_count = -1;
10583 if (
rb_scan_args(argc, argv,
"02", &spat, &limit) == 2) {
10585 if (lim <= 0) limit =
Qnil;
10586 else if (lim == 1) {
10587 if (RSTRING_LEN(str) == 0)
10598 if (
NIL_P(limit) && !lim) empty_count = 0;
10600 enc = STR_ENC_GET(str);
10601 split_type = SPLIT_TYPE_REGEXP;
10602 if (!
NIL_P(spat)) {
10603 spat = get_pat_quoted(spat, 0);
10605 else if (
NIL_P(spat = rb_fs)) {
10606 split_type = SPLIT_TYPE_AWK;
10608 else if (!(spat = rb_fs_check(spat))) {
10609 rb_raise(
rb_eTypeError,
"value of $; must be String or Regexp");
10614 if (split_type != SPLIT_TYPE_AWK) {
10619 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10620 if (split_type == SPLIT_TYPE_AWK) {
10622 split_type = SPLIT_TYPE_STRING;
10627 mustnot_broken(spat);
10628 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10636#define SPLIT_STR(beg, len) ( \
10637 empty_count = split_string(result, str, beg, len, empty_count), \
10638 str_mod_check(str, str_start, str_len))
10641 const char *ptr = RSTRING_PTR(str);
10642 const char *
const str_start = ptr;
10643 const long str_len = RSTRING_LEN(str);
10644 const char *
const eptr = str_start + str_len;
10645 if (split_type == SPLIT_TYPE_AWK) {
10646 const char *bptr = ptr;
10652 if (is_ascii_string(str)) {
10653 while (ptr < eptr) {
10654 c = (
unsigned char)*ptr++;
10656 if (ascii_isspace(c)) {
10662 if (!
NIL_P(limit) && lim <= i)
break;
10665 else if (ascii_isspace(c)) {
10666 SPLIT_STR(beg, end-beg);
10669 if (!
NIL_P(limit)) ++i;
10677 while (ptr < eptr) {
10680 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10689 if (!
NIL_P(limit) && lim <= i)
break;
10693 SPLIT_STR(beg, end-beg);
10696 if (!
NIL_P(limit)) ++i;
10704 else if (split_type == SPLIT_TYPE_STRING) {
10705 const char *substr_start = ptr;
10706 const char *sptr = RSTRING_PTR(spat);
10707 long slen = RSTRING_LEN(spat);
10710 mustnot_broken(str);
10711 enc = rb_enc_check(str, spat);
10712 while (ptr < eptr &&
10713 (end =
rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10716 if (t != ptr + end) {
10720 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10721 str_mod_check(spat, sptr, slen);
10723 substr_start = ptr;
10724 if (!
NIL_P(limit) && lim <= ++i)
break;
10726 beg = ptr - str_start;
10728 else if (split_type == SPLIT_TYPE_CHARS) {
10732 mustnot_broken(str);
10733 enc = rb_enc_get(str);
10734 while (ptr < eptr &&
10735 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10736 SPLIT_STR(ptr - str_start, n);
10738 if (!
NIL_P(limit) && lim <= ++i)
break;
10740 beg = ptr - str_start;
10744 long len = RSTRING_LEN(str);
10751 (match ? (rb_match_unbusy(match),
rb_backref_set(match)) : (void)0)) {
10754 end = RMATCH_BEG(match, 0);
10755 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10760 else if (last_null == 1) {
10761 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10768 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10774 SPLIT_STR(beg, end-beg);
10775 beg = start = RMATCH_END(match, 0);
10779 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10780 if (RMATCH_BEG(match, idx) == -1)
continue;
10781 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10783 if (!
NIL_P(limit) && lim <= ++i)
break;
10785 if (match) rb_match_unbusy(match);
10787 if (RSTRING_LEN(str) > 0 && (!
NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10788 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10791 return result ? result : str;
10801 return rb_str_split_m(1, &sep, str);
10804#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10819#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10822chomp_newline(
const char *p,
const char *e,
rb_encoding *enc)
10824 const char *prev = rb_enc_prev_char(p, e, e, enc);
10827 prev = rb_enc_prev_char(p, e, e, enc);
10828 if (prev && rb_enc_ascget(prev, e, NULL, enc) ==
'\r')
10840 RSTRING_LEN(rs) != 1 ||
10841 RSTRING_PTR(rs)[0] !=
'\n')) {
10847#define rb_rs get_rs()
10854 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10860 if (!
NIL_P(opts)) {
10861 static ID keywords[1];
10862 if (!keywords[0]) {
10866 chomp = (!UNDEF_P(chomp) &&
RTEST(chomp));
10870 if (!ENUM_ELEM(ary, str)) {
10878 if (!RSTRING_LEN(str))
goto end;
10880 const char *
const ptr = subptr = RSTRING_PTR(str);
10881 const long len = RSTRING_LEN(str);
10884 rslen = RSTRING_LEN(rs);
10887 enc = rb_enc_get(str);
10889 enc = rb_enc_check(str, rs);
10894 const char *eol = NULL;
10896 while (subend < pend) {
10897 long chomp_rslen = 0;
10899 if (rb_enc_ascget(subend, pend, &n, enc) !=
'\r')
10901 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
10903 if (eol == subend)
break;
10907 chomp_rslen = -rslen;
10911 if (!subptr) subptr = subend;
10915 }
while (subend < pend);
10916 if (!subptr)
break;
10917 if (rslen == 0) chomp_rslen = 0;
10919 subend - subptr + (chomp ? chomp_rslen : rslen));
10920 if (ENUM_ELEM(ary, line)) {
10921 str_mod_check(str, ptr,
len);
10923 subptr = eol = NULL;
10928 rsptr = RSTRING_PTR(rs);
10929 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
10938 rsptr = RSTRING_PTR(rs);
10939 rslen = RSTRING_LEN(rs);
10942 while (subptr < pend) {
10943 pos =
rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
10944 if (pos < 0)
break;
10945 hit = subptr + pos;
10947 if (hit != adjusted) {
10951 subend = hit += rslen;
10954 subend = chomp_newline(subptr, subend, enc);
10961 if (ENUM_ELEM(ary, line)) {
10962 str_mod_check(str, ptr,
len);
10963 str_mod_check(rs, rsptr, rslen);
10968 if (subptr < pend) {
10971 pend = chomp_newline(subptr, pend, enc);
10973 else if (pend - subptr >= rslen &&
10974 memcmp(pend - rslen, rsptr, rslen) == 0) {
10979 ENUM_ELEM(ary, line);
11000rb_str_each_line(
int argc,
VALUE *argv,
VALUE str)
11003 return rb_str_enumerate_lines(argc, argv, str, 0);
11058rb_str_lines(
int argc,
VALUE *argv,
VALUE str)
11060 VALUE ary = WANTARRAY(
"lines", 0);
11061 return rb_str_enumerate_lines(argc, argv, str, ary);
11067 return LONG2FIX(RSTRING_LEN(str));
11075 for (i=0; i<RSTRING_LEN(str); i++) {
11076 ENUM_ELEM(ary,
INT2FIX((
unsigned char)RSTRING_PTR(str)[i]));
11094rb_str_each_byte(
VALUE str)
11097 return rb_str_enumerate_bytes(str, 0);
11109rb_str_bytes(
VALUE str)
11111 VALUE ary = WANTARRAY(
"bytes", RSTRING_LEN(str));
11112 return rb_str_enumerate_bytes(str, ary);
11130 ptr = RSTRING_PTR(str);
11131 len = RSTRING_LEN(str);
11132 enc = rb_enc_get(str);
11135 for (i = 0; i <
len; i += n) {
11136 n = rb_enc_fast_mbclen(ptr + i, ptr +
len, enc);
11141 for (i = 0; i <
len; i += n) {
11142 n = rb_enc_mbclen(ptr + i, ptr +
len, enc);
11163rb_str_each_char(
VALUE str)
11166 return rb_str_enumerate_chars(str, 0);
11178rb_str_chars(
VALUE str)
11181 return rb_str_enumerate_chars(str, ary);
11185rb_str_enumerate_codepoints(
VALUE str,
VALUE ary)
11190 const char *ptr, *end;
11192 int enc_asciicompat;
11194 if (single_byte_optimizable(str))
11195 return rb_str_enumerate_bytes(str, ary);
11198 ptr = RSTRING_PTR(str);
11200 enc = STR_ENC_GET(str);
11201 enc_asciicompat = rb_enc_asciicompat(enc);
11203 while (ptr < end) {
11208 c = (enc_asciicompat &&
ISASCII(*ptr)) ?
11209 (
unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11230rb_str_each_codepoint(
VALUE str)
11233 return rb_str_enumerate_codepoints(str, 0);
11245rb_str_codepoints(
VALUE str)
11248 return rb_str_enumerate_codepoints(str, ary);
11254 int encidx = rb_enc_to_index(enc);
11256 const OnigUChar source_ascii[] =
"\\X";
11257 const OnigUChar *source = source_ascii;
11258 size_t source_len =
sizeof(source_ascii) - 1;
11261#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11262#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11263#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11264#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11265#define CASE_UTF(e) \
11266 case ENCINDEX_UTF_##e: { \
11267 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11268 source = source_UTF_##e; \
11269 source_len = sizeof(source_UTF_##e); \
11272 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11280 regex_t *reg_grapheme_cluster;
11282 int r = onig_new(®_grapheme_cluster, source, source + source_len,
11283 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11285 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11286 onig_error_code_to_str(message, r, &einfo);
11287 rb_fatal(
"cannot compile grapheme cluster regexp: %s", (
char *)message);
11290 return reg_grapheme_cluster;
11296 int encidx = rb_enc_to_index(enc);
11297 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11299 if (encidx == rb_utf8_encindex()) {
11300 if (!reg_grapheme_cluster_utf8) {
11301 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11304 return reg_grapheme_cluster_utf8;
11313 size_t grapheme_cluster_count = 0;
11315 const char *ptr, *end;
11317 if (!rb_enc_unicode_p(enc)) {
11321 bool cached_reg_grapheme_cluster =
true;
11322 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11323 if (!reg_grapheme_cluster) {
11324 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11325 cached_reg_grapheme_cluster =
false;
11328 ptr = RSTRING_PTR(str);
11331 while (ptr < end) {
11332 OnigPosition
len = onig_match(reg_grapheme_cluster,
11333 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11334 (
const OnigUChar *)ptr, NULL, 0);
11335 if (
len <= 0)
break;
11336 grapheme_cluster_count++;
11340 if (!cached_reg_grapheme_cluster) {
11341 onig_free(reg_grapheme_cluster);
11344 return SIZET2NUM(grapheme_cluster_count);
11348rb_str_enumerate_grapheme_clusters(
VALUE str,
VALUE ary)
11352 const char *ptr0, *ptr, *end;
11354 if (!rb_enc_unicode_p(enc)) {
11355 return rb_str_enumerate_chars(str, ary);
11360 bool cached_reg_grapheme_cluster =
true;
11361 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11362 if (!reg_grapheme_cluster) {
11363 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11364 cached_reg_grapheme_cluster =
false;
11367 ptr0 = ptr = RSTRING_PTR(str);
11370 while (ptr < end) {
11371 OnigPosition
len = onig_match(reg_grapheme_cluster,
11372 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11373 (
const OnigUChar *)ptr, NULL, 0);
11374 if (
len <= 0)
break;
11379 if (!cached_reg_grapheme_cluster) {
11380 onig_free(reg_grapheme_cluster);
11400rb_str_each_grapheme_cluster(
VALUE str)
11403 return rb_str_enumerate_grapheme_clusters(str, 0);
11415rb_str_grapheme_clusters(
VALUE str)
11418 return rb_str_enumerate_grapheme_clusters(str, ary);
11422chopped_length(
VALUE str)
11425 const char *p, *p2, *beg, *end;
11427 beg = RSTRING_PTR(str);
11428 end = beg + RSTRING_LEN(str);
11429 if (beg >= end)
return 0;
11430 p = rb_enc_prev_char(beg, end, end, enc);
11432 if (p > beg && rb_enc_ascget(p, end, 0, enc) ==
'\n') {
11433 p2 = rb_enc_prev_char(beg, p, end, enc);
11434 if (p2 && rb_enc_ascget(p2, end, 0, enc) ==
'\r') p = p2;
11452rb_str_chop_bang(
VALUE str)
11454 str_modify_keep_cr(str);
11455 if (RSTRING_LEN(str) > 0) {
11457 len = chopped_length(str);
11458 STR_SET_LEN(str,
len);
11459 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11478rb_str_chop(
VALUE str)
11484smart_chomp(
VALUE str,
const char *e,
const char *p)
11487 if (rb_enc_mbminlen(enc) > 1) {
11489 if (e - p < rb_enc_mbminlen(enc))
return e - p;
11494 pp = e - rb_enc_mbminlen(enc);
11497 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11505 if (--e > p && *(e-1) ==
'\r') {
11522 const char *pp, *e, *rsptr;
11524 const char *
const p = RSTRING_PTR(str);
11525 long len = RSTRING_LEN(str);
11527 if (
len == 0)
return 0;
11530 return smart_chomp(str, e, p);
11533 enc = rb_enc_get(str);
11536 if (rb_enc_mbminlen(enc) > 1) {
11537 while (e - p >= rb_enc_mbminlen(enc)) {
11541 pp -= rb_enc_mbminlen(enc);
11544 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11551 while (e > p && *(e-1) ==
'\n') {
11553 if (e > p && *(e-1) ==
'\r')
11559 if (rslen >
len)
return len;
11561 enc = rb_enc_get(rs);
11562 newline = rsptr[rslen-1];
11563 if (rslen == rb_enc_mbminlen(enc)) {
11565 if (newline ==
'\n')
11566 return smart_chomp(str, e, p);
11570 return smart_chomp(str, e, p);
11574 enc = rb_enc_check(str, rs);
11575 if (is_broken_string(rs)) {
11579 if (p[
len-1] == newline &&
11581 memcmp(rsptr, pp, rslen) == 0)) {
11582 if (at_char_boundary(p, pp, e, enc))
11583 return len - rslen;
11595chomp_rs(
int argc,
const VALUE *argv)
11599 VALUE rs = argv[0];
11611 str_modify_keep_cr(str);
11612 STR_SET_LEN(str,
len);
11613 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11623 long olen = RSTRING_LEN(str);
11624 long len = chompped_length(str, rs);
11625 if (
len >= olen)
return Qnil;
11626 return str_shrink(str,
len);
11642rb_str_chomp_bang(
int argc,
VALUE *argv,
VALUE str)
11645 str_modifiable(str);
11646 if (RSTRING_LEN(str) == 0 && argc < 2)
return Qnil;
11647 rs = chomp_rs(argc, argv);
11649 return rb_str_chomp_string(str, rs);
11662rb_str_chomp(
int argc,
VALUE *argv,
VALUE str)
11664 VALUE rs = chomp_rs(argc, argv);
11670tr_setup_table_multi(
char table[TR_TABLE_SIZE],
VALUE *tablep,
VALUE *ctablep,
11671 VALUE str,
int num_selectors,
VALUE *selectors)
11675 for (i=0; i<num_selectors; i++) {
11676 VALUE selector = selectors[i];
11680 enc = rb_enc_check(str, selector);
11681 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11688 const char *
const start = s;
11690 if (!s || s >= e)
return 0;
11693 if (single_byte_optimizable(str)) {
11694 while (s < e && (*s ==
'\0' || ascii_isspace(*s))) s++;
11699 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11709lstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11710 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11712 const char *
const start = s;
11714 if (!s || s >= e)
return 0;
11719 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11721 if (!tr_find(cc, table, del, nodel))
break;
11740rb_str_lstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11744 long olen, loffset;
11746 str_modify_keep_cr(str);
11747 enc = STR_ENC_GET(str);
11750 char table[TR_TABLE_SIZE];
11751 VALUE del = 0, nodel = 0;
11753 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11756 str_modify_keep_cr(str);
11757 enc = STR_ENC_GET(str);
11760 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11763 loffset = lstrip_offset(str, start, start+olen, enc);
11767 long len = olen-loffset;
11768 memmove(start, start + loffset,
len);
11769 STR_SET_LEN(str,
len);
11770 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11805rb_str_lstrip(
int argc,
VALUE *argv,
VALUE str)
11812 char table[TR_TABLE_SIZE];
11813 VALUE del = 0, nodel = 0;
11815 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11820 loffset = lstrip_offset_table(str, start, start+
len, STR_ENC_GET(str), table, del, nodel);
11823 loffset = lstrip_offset(str, start, start+
len, STR_ENC_GET(str));
11825 if (loffset <= 0)
return str_duplicate(
rb_cString, str);
11834 rb_str_check_dummy_enc(enc);
11838 if (!s || s >= e)
return 0;
11842 if (single_byte_optimizable(str)) {
11844 while (s < t && ((c = *(t-1)) ==
'\0' || ascii_isspace(c))) t--;
11849 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11859rstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11860 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11862 const char *t, *tp;
11864 rb_str_check_dummy_enc(enc);
11868 if (!s || s >= e)
return 0;
11872 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11874 if (!tr_find(c, table, del, nodel))
break;
11894rb_str_rstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11898 long olen, roffset;
11900 str_modify_keep_cr(str);
11901 enc = STR_ENC_GET(str);
11904 char table[TR_TABLE_SIZE];
11905 VALUE del = 0, nodel = 0;
11907 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11910 str_modify_keep_cr(str);
11911 enc = STR_ENC_GET(str);
11914 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11917 roffset = rstrip_offset(str, start, start+olen, enc);
11920 long len = olen - roffset;
11922 STR_SET_LEN(str,
len);
11923 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11957rb_str_rstrip(
int argc,
VALUE *argv,
VALUE str)
11961 long olen, roffset;
11963 enc = STR_ENC_GET(str);
11966 char table[TR_TABLE_SIZE];
11967 VALUE del = 0, nodel = 0;
11969 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11972 enc = STR_ENC_GET(str);
11975 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11978 roffset = rstrip_offset(str, start, start+olen, enc);
11980 if (roffset <= 0)
return str_duplicate(
rb_cString, str);
11998rb_str_strip_bang(
int argc,
VALUE *argv,
VALUE str)
12001 long olen, loffset, roffset;
12004 str_modify_keep_cr(str);
12005 enc = STR_ENC_GET(str);
12009 char table[TR_TABLE_SIZE];
12010 VALUE del = 0, nodel = 0;
12012 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12015 str_modify_keep_cr(str);
12016 enc = STR_ENC_GET(str);
12019 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12020 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12023 loffset = lstrip_offset(str, start, start+olen, enc);
12024 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12027 if (loffset > 0 || roffset > 0) {
12028 long len = olen-roffset;
12031 memmove(start, start + loffset,
len);
12033 STR_SET_LEN(str,
len);
12034 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
12069rb_str_strip(
int argc,
VALUE *argv,
VALUE str)
12072 long olen, loffset, roffset;
12078 char table[TR_TABLE_SIZE];
12079 VALUE del = 0, nodel = 0;
12081 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12084 enc = STR_ENC_GET(str);
12087 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12088 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12091 loffset = lstrip_offset(str, start, start+olen, enc);
12092 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12095 if (loffset <= 0 && roffset <= 0)
return str_duplicate(
rb_cString, str);
12100scan_once(
VALUE str,
VALUE pat,
long *start,
int set_backref_str)
12103 long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12107 end = pos + RSTRING_LEN(pat);
12111 pos = RMATCH_BEG(match, 0);
12112 end = RMATCH_END(match, 0);
12120 if (RSTRING_LEN(str) > end)
12121 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12130 if (
NIL_P(match) || RMATCH_NREGS(match) == 1) {
12135 int num_regs = RMATCH_NREGS(match);
12137 for (
int i = 1; i < num_regs; i++) {
12139 if (RMATCH_BEG(match, i) >= 0) {
12140 s =
rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12168 long last = -1, prev = 0;
12169 const char *p = RSTRING_PTR(str);
12170 long len = RSTRING_LEN(str);
12172 pat = get_pat_quoted(pat, 1);
12173 mustnot_broken(str);
12177 while (!
NIL_P(result = scan_once(str, pat, &start, 0))) {
12182 if (last >= 0) rb_pat_search(pat, str, last, 1);
12187 while (!
NIL_P(result = scan_once(str, pat, &start, 1))) {
12191 str_mod_check(str, p,
len);
12193 if (last >= 0) rb_pat_search(pat, str, last, 1);
12245rb_str_hex(
VALUE str)
12247 return rb_str_to_inum(str, 16, FALSE);
12331rb_str_oct(
VALUE str)
12333 return rb_str_to_inum(str, -8, FALSE);
12336#ifndef HAVE_CRYPT_R
12341 rb_nativethread_lock_t lock;
12342} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12411# define CRYPT_END() ALLOCV_END(databuf)
12414 extern char *crypt(
const char *,
const char *);
12415# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12418 const char *s, *saltp, *res;
12420 char salt_8bit_clean[3];
12424 mustnot_wchar(str);
12425 mustnot_wchar(salt);
12427 saltp = RSTRING_PTR(salt);
12428 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12429 rb_raise(rb_eArgError,
"salt too short (need >=2 bytes)");
12433 if (!
ISASCII((
unsigned char)saltp[0]) || !
ISASCII((
unsigned char)saltp[1])) {
12434 salt_8bit_clean[0] = saltp[0] & 0x7f;
12435 salt_8bit_clean[1] = saltp[1] & 0x7f;
12436 salt_8bit_clean[2] =
'\0';
12437 saltp = salt_8bit_clean;
12442# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12443 data->initialized = 0;
12445 res = crypt_r(s, saltp, data);
12448 res = crypt(s, saltp);
12463 size_t res_size = strlen(res);
12464 tmp_buf =
ALLOCA_N(
char, res_size);
12465 memcpy(tmp_buf, res, res_size);
12501 char *ptr, *p, *pend;
12504 unsigned long sum0 = 0;
12509 ptr = p = RSTRING_PTR(str);
12510 len = RSTRING_LEN(str);
12516 str_mod_check(str, ptr,
len);
12519 sum0 += (
unsigned char)*p;
12530 if (bits < (
int)
sizeof(
long)*CHAR_BIT) {
12531 sum0 &= (((
unsigned long)1)<<bits)-1;
12551rb_str_justify(
int argc,
VALUE *argv,
VALUE str,
char jflag)
12555 long width,
len, flen = 1, fclen = 1;
12558 const char *f =
" ";
12559 long n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12561 int singlebyte = 1, cr;
12565 enc = STR_ENC_GET(str);
12569 enc = rb_enc_check(str, pad);
12570 f = RSTRING_PTR(pad);
12571 flen = RSTRING_LEN(pad);
12572 fclen = str_strlen(pad, enc);
12573 singlebyte = single_byte_optimizable(pad);
12574 if (flen == 0 || fclen == 0) {
12575 rb_raise(rb_eArgError,
"zero width padding");
12578 termlen = rb_enc_mbminlen(enc);
12579 len = str_strlen(str, enc);
12580 if (width < 0 || len >= width)
return str_duplicate(
rb_cString, str);
12582 llen = (jflag ==
'l') ? 0 : ((jflag ==
'r') ? n : n/2);
12586 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12587 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12589 size = RSTRING_LEN(str);
12590 if ((
len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
12591 (
len *= flen) >= LONG_MAX - llen2 - rlen2 ||
12592 (
len += llen2 + rlen2) >= LONG_MAX - size) {
12593 rb_raise(rb_eArgError,
"argument too big");
12597 p = RSTRING_PTR(res);
12599 memset(p, *f, llen);
12603 while (llen >= fclen) {
12609 memcpy(p, f, llen2);
12613 memcpy(p, RSTRING_PTR(str), size);
12616 memset(p, *f, rlen);
12620 while (rlen >= fclen) {
12626 memcpy(p, f, rlen2);
12630 TERM_FILL(p, termlen);
12631 STR_SET_LEN(res, p-RSTRING_PTR(res));
12652rb_str_ljust(
int argc,
VALUE *argv,
VALUE str)
12654 return rb_str_justify(argc, argv, str,
'l');
12666rb_str_rjust(
int argc,
VALUE *argv,
VALUE str)
12668 return rb_str_justify(argc, argv, str,
'r');
12681rb_str_center(
int argc,
VALUE *argv,
VALUE str)
12683 return rb_str_justify(argc, argv, str,
'c');
12699 sep = get_pat_quoted(sep, 0);
12706 pos = RMATCH_BEG(match, 0);
12710 pos = rb_str_index(str, sep, 0);
12711 if (pos < 0)
goto failed;
12714 long rpos = pos + RSTRING_LEN(sep);
12715 if (rpos > RSTRING_LEN(str))
goto failed;
12721 return rb_ary_new3(3, str_duplicate(
rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12737 sep = get_pat_quoted(sep, 0);
12739 pos = RSTRING_LEN(str);
12745 pos = RMATCH_BEG(match, 0);
12751 pos = rb_str_rindex(str, sep, pos);
12757 long rpos = pos + RSTRING_LEN(sep);
12758 if (rpos > RSTRING_LEN(str))
goto failed;
12763 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(
rb_cString, str));
12775rb_str_start_with(
int argc,
VALUE *argv,
VALUE str)
12779 for (i=0; i<argc; i++) {
12780 VALUE tmp = argv[i];
12782 if (rb_reg_start_with_p(tmp, str))
12786 const char *p, *s, *e;
12791 enc = rb_enc_check(str, tmp);
12792 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12793 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12794 p = RSTRING_PTR(str);
12797 if (!at_char_right_boundary(p, s, e, enc))
12799 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12815rb_str_end_with(
int argc,
VALUE *argv,
VALUE str)
12819 for (i=0; i<argc; i++) {
12820 VALUE tmp = argv[i];
12821 const char *p, *s, *e;
12826 enc = rb_enc_check(str, tmp);
12827 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12828 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12829 p = RSTRING_PTR(str);
12832 if (!at_char_boundary(p, s, e, enc))
12834 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12850deleted_prefix_length(
VALUE str,
VALUE prefix)
12852 const char *strptr, *prefixptr;
12853 long olen, prefixlen;
12858 if (!is_broken_string(prefix) ||
12859 !rb_enc_asciicompat(enc) ||
12860 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12861 enc = rb_enc_check(str, prefix);
12865 prefixlen = RSTRING_LEN(prefix);
12866 if (prefixlen <= 0)
return 0;
12867 olen = RSTRING_LEN(str);
12868 if (olen < prefixlen)
return 0;
12869 strptr = RSTRING_PTR(str);
12870 prefixptr = RSTRING_PTR(prefix);
12871 if (memcmp(strptr, prefixptr, prefixlen) != 0)
return 0;
12872 if (is_broken_string(prefix)) {
12873 if (!is_broken_string(str)) {
12877 const char *strend = strptr + olen;
12878 const char *after_prefix = strptr + prefixlen;
12879 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12900rb_str_delete_prefix_bang(
VALUE str,
VALUE prefix)
12903 str_modify_keep_cr(str);
12905 prefixlen = deleted_prefix_length(str, prefix);
12906 if (prefixlen <= 0)
return Qnil;
12920rb_str_delete_prefix(
VALUE str,
VALUE prefix)
12924 prefixlen = deleted_prefix_length(str, prefix);
12925 if (prefixlen <= 0)
return str_duplicate(
rb_cString, str);
12927 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
12940deleted_suffix_length(
VALUE str,
VALUE suffix)
12942 const char *strptr, *suffixptr;
12943 long olen, suffixlen;
12947 if (is_broken_string(suffix))
return 0;
12948 enc = rb_enc_check(str, suffix);
12951 suffixlen = RSTRING_LEN(suffix);
12952 if (suffixlen <= 0)
return 0;
12953 olen = RSTRING_LEN(str);
12954 if (olen < suffixlen)
return 0;
12955 strptr = RSTRING_PTR(str);
12956 suffixptr = RSTRING_PTR(suffix);
12957 const char *strend = strptr + olen;
12958 const char *before_suffix = strend - suffixlen;
12959 if (memcmp(before_suffix, suffixptr, suffixlen) != 0)
return 0;
12960 if (!at_char_boundary(strptr, before_suffix, strend, enc))
return 0;
12976rb_str_delete_suffix_bang(
VALUE str,
VALUE suffix)
12979 str_modifiable(str);
12981 suffixlen = deleted_suffix_length(str, suffix);
12982 if (suffixlen <= 0)
return Qnil;
12984 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
12996rb_str_delete_suffix(
VALUE str,
VALUE suffix)
13000 suffixlen = deleted_suffix_length(str, suffix);
13001 if (suffixlen <= 0)
return str_duplicate(
rb_cString, str);
13003 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
13010 rb_raise(
rb_eTypeError,
"value of %"PRIsVALUE
" must be String", rb_id2str(
id));
13016nil_setter_warning(
ID id)
13018 rb_warn_deprecated(
"non-nil '%"PRIsVALUE
"'", NULL, rb_id2str(
id));
13025 if (!
NIL_P(*var)) {
13026 nil_setter_warning(
id);
13033 val = rb_fs_check(val);
13036 "value of %"PRIsVALUE
" must be String or Regexp",
13040 nil_setter_warning(
id);
13057 str_modifiable(str);
13060 int idx = rb_enc_to_index(encoding);
13067 rb_enc_associate_index(str, idx);
13091 if (STR_EMBED_P(str)) {
13092 str2 = str_alloc_embed(
rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13097 str_replace_shared_without_enc(str2, str);
13099 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13122rb_str_valid_encoding_p(
VALUE str)
13124 int cr = rb_enc_str_coderange(str);
13131rb_str_is_ascii_only_p(
VALUE str)
13133 int cr = rb_enc_str_coderange(str);
13141 static const char ellipsis[] =
"...";
13142 const long ellipsislen =
sizeof(ellipsis) - 1;
13144 const long blen = RSTRING_LEN(str);
13145 const char *
const p = RSTRING_PTR(str), *e = p + blen;
13146 VALUE estr, ret = 0;
13149 if (
len * rb_enc_mbminlen(enc) >= blen ||
13153 else if (
len <= ellipsislen ||
13155 if (rb_enc_asciicompat(enc)) {
13157 rb_enc_associate(ret, enc);
13164 else if (ret =
rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13169 rb_enc_from_encoding(enc), 0,
Qnil);
13180 cr = rb_enc_str_coderange(str);
13182 rb_raise(rb_eArgError,
"replacement must be valid byte sequence '%+"PRIsVALUE
"'", str);
13188 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13207 if (enc == STR_ENC_GET(str)) {
13212 return enc_str_scrub(enc, str, repl, cr);
13220 const char *rep, *p, *e, *p1, *sp;
13226 rb_raise(rb_eArgError,
"both of block and replacement given");
13233 if (!
NIL_P(repl)) {
13234 repl = str_compat_and_valid(repl, enc);
13237 if (rb_enc_dummy_p(enc)) {
13240 encidx = rb_enc_to_index(enc);
13242#define DEFAULT_REPLACE_CHAR(str) do { \
13243 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13244 rep = replace; replen = (int)sizeof(replace); \
13247 slen = RSTRING_LEN(str);
13248 p = RSTRING_PTR(str);
13253 if (rb_enc_asciicompat(enc)) {
13259 else if (!
NIL_P(repl)) {
13260 rep = RSTRING_PTR(repl);
13261 replen = RSTRING_LEN(repl);
13264 else if (encidx == rb_utf8_encindex()) {
13265 DEFAULT_REPLACE_CHAR(
"\xEF\xBF\xBD");
13269 DEFAULT_REPLACE_CHAR(
"?");
13274 p = search_nonascii(p, e);
13279 int ret = rb_enc_precise_mbclen(p, e, enc);
13287 p = search_nonascii(p, e);
13304 if (e - p < clen) clen = e - p;
13311 for (; clen > 1; clen--) {
13312 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13323 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13324 str_mod_check(str, sp, slen);
13325 repl = str_compat_and_valid(repl, enc);
13332 p = search_nonascii(p, e);
13358 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13359 str_mod_check(str, sp, slen);
13360 repl = str_compat_and_valid(repl, enc);
13369 long mbminlen = rb_enc_mbminlen(enc);
13373 else if (!
NIL_P(repl)) {
13374 rep = RSTRING_PTR(repl);
13375 replen = RSTRING_LEN(repl);
13377 else if (encidx == ENCINDEX_UTF_16BE) {
13378 DEFAULT_REPLACE_CHAR(
"\xFF\xFD");
13380 else if (encidx == ENCINDEX_UTF_16LE) {
13381 DEFAULT_REPLACE_CHAR(
"\xFD\xFF");
13383 else if (encidx == ENCINDEX_UTF_32BE) {
13384 DEFAULT_REPLACE_CHAR(
"\x00\x00\xFF\xFD");
13386 else if (encidx == ENCINDEX_UTF_32LE) {
13387 DEFAULT_REPLACE_CHAR(
"\xFD\xFF\x00\x00");
13390 DEFAULT_REPLACE_CHAR(
"?");
13394 int ret = rb_enc_precise_mbclen(p, e, enc);
13407 if (e - p < clen) clen = e - p;
13408 if (clen <= mbminlen * 2) {
13413 for (; clen > mbminlen; clen-=mbminlen) {
13414 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13424 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13425 str_mod_check(str, sp, slen);
13426 repl = str_compat_and_valid(repl, enc);
13451 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13452 str_mod_check(str, sp, slen);
13453 repl = str_compat_and_valid(repl, enc);
13493str_scrub_bang(
int argc,
VALUE *argv,
VALUE str)
13501static ID id_normalize;
13502static ID id_normalized_p;
13503static VALUE mUnicodeNormalize;
13506unicode_normalize_common(
int argc,
VALUE *argv,
VALUE str,
ID id)
13508 static int UnicodeNormalizeRequired = 0;
13511 if (!UnicodeNormalizeRequired) {
13512 rb_require(
"unicode_normalize/normalize.rb");
13513 UnicodeNormalizeRequired = 1;
13517 return rb_funcallv(mUnicodeNormalize,
id, argc+1, argv2);
13528rb_str_unicode_normalize(
int argc,
VALUE *argv,
VALUE str)
13530 return unicode_normalize_common(argc, argv, str, id_normalize);
13544rb_str_unicode_normalize_bang(
int argc,
VALUE *argv,
VALUE str)
13546 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13573rb_str_unicode_normalized_p(
int argc,
VALUE *argv,
VALUE str)
13575 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13707#define sym_equal rb_obj_equal
13710sym_printable(
const char *s,
const char *send,
rb_encoding *enc)
13714 int c = rb_enc_precise_mbclen(s, send, enc);
13718 c = rb_enc_mbc_to_codepoint(s, send, enc);
13726rb_str_symname_p(
VALUE sym)
13731 rb_encoding *resenc = rb_default_internal_encoding();
13733 if (resenc == NULL) resenc = rb_default_external_encoding();
13734 enc = STR_ENC_GET(sym);
13735 ptr = RSTRING_PTR(sym);
13736 len = RSTRING_LEN(sym);
13737 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) ||
len != (
long)strlen(ptr) ||
13745rb_str_quote_unprintable(
VALUE str)
13753 resenc = rb_default_internal_encoding();
13754 if (resenc == NULL) resenc = rb_default_external_encoding();
13755 enc = STR_ENC_GET(str);
13756 ptr = RSTRING_PTR(str);
13757 len = RSTRING_LEN(str);
13758 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13759 !sym_printable(ptr, ptr +
len, enc)) {
13760 return rb_str_escape(str);
13766rb_id_quote_unprintable(
ID id)
13768 VALUE str = rb_id2str(
id);
13769 if (!rb_str_symname_p(str)) {
13770 return rb_str_escape(str);
13788sym_inspect(
VALUE sym)
13795 if (!rb_str_symname_p(str)) {
13797 len = RSTRING_LEN(str);
13798 rb_str_resize(str,
len + 1);
13799 dest = RSTRING_PTR(str);
13800 memmove(dest + 1, dest,
len);
13804 VALUE orig_str = str;
13806 len = RSTRING_LEN(orig_str);
13807 str = rb_enc_str_new(0,
len + 1, enc);
13810 ptr = RSTRING_PTR(orig_str);
13811 dest = RSTRING_PTR(str);
13812 memcpy(dest + 1, ptr,
len);
13830rb_sym_proc_call(
ID mid,
int argc,
const VALUE *argv,
int kw_splat,
VALUE passed_proc)
13835 rb_raise(rb_eArgError,
"no receiver given");
13938 return rb_str_match(
rb_sym2str(sym), other);
13953sym_match_m(
int argc,
VALUE *argv,
VALUE sym)
13955 return rb_str_match_m(argc, argv,
rb_sym2str(sym));
13968sym_match_m_p(
int argc,
VALUE *argv,
VALUE sym)
13970 return rb_str_match_m_p(argc, argv, sym);
13988 return rb_str_aref_m(argc, argv,
rb_sym2str(sym));
13999sym_length(
VALUE sym)
14033sym_downcase(
int argc,
VALUE *argv,
VALUE sym)
14049sym_capitalize(
int argc,
VALUE *argv,
VALUE sym)
14065sym_swapcase(
int argc,
VALUE *argv,
VALUE sym)
14079sym_start_with(
int argc,
VALUE *argv,
VALUE sym)
14081 return rb_str_start_with(argc, argv,
rb_sym2str(sym));
14094sym_end_with(
int argc,
VALUE *argv,
VALUE sym)
14096 return rb_str_end_with(argc, argv,
rb_sym2str(sym));
14108sym_encoding(
VALUE sym)
14114string_for_symbol(
VALUE name)
14119 rb_raise(
rb_eTypeError,
"%+"PRIsVALUE
" is not a symbol nor a string",
14133 name = string_for_symbol(name);
14134 return rb_intern_str(name);
14143 name = string_for_symbol(name);
14167 return rb_fstring(str);
14173 struct RString fake_str = {RBASIC_INIT};
14174 int encidx = ENCINDEX_US_ASCII;
14177 encidx = ENCINDEX_ASCII_8BIT;
14180 VALUE str = setup_fake_str(&fake_str,
ptr,
len, encidx);
14182 return register_fstring(str,
true,
false);
14194 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14195 rb_enc_autoload(enc);
14198 struct RString fake_str = {RBASIC_INIT};
14199 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
false);
14205 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14206 rb_enc_autoload(enc);
14209 struct RString fake_str = {RBASIC_INIT};
14210 VALUE str = register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
true);
14221#if USE_YJIT || USE_ZJIT
14223rb_jit_str_concat_codepoint(
VALUE str,
VALUE codepoint)
14228 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14229 rb_str_buf_cat_byte(str, (
char) code);
14239fstring_set_class_i(
VALUE *str,
void *data)
14243 return ST_CONTINUE;
14251 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14419 mUnicodeNormalize = rb_define_module(
"UnicodeNormalize");
14430 rb_gc_register_address(&
rb_fs);
14468#include "string.rbinc"
#define RUBY_ASSERT_ALWAYS(expr,...)
A variant of RUBY_ASSERT that does not interface with RUBY_DEBUG.
#define RBIMPL_ASSERT_OR_ASSUME(...)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
#define RUBY_ASSERT_BUILTIN_TYPE(obj, type)
A variant of RUBY_ASSERT that asserts when either RUBY_DEBUG or built-in type of obj is type.
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
@ RUBY_ENC_CODERANGE_7BIT
The object holds 0 to 127 inclusive and nothing else.
static enum ruby_coderange_type RB_ENC_CODERANGE_AND(enum ruby_coderange_type a, enum ruby_coderange_type b)
"Mix" two code ranges into one.
static int rb_isspace(int c)
Our own locale-insensitive version of isspace(3).
static int rb_isascii(int c)
Our own locale-insensitive version of isascii(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
static bool rb_enc_is_newline(const char *p, const char *e, rb_encoding *enc)
Queries if the passed pointer points to a newline character.
static bool rb_enc_isprint(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isprint(), except it additionally takes an encoding.
static bool rb_enc_isctype(OnigCodePoint c, OnigCtype t, rb_encoding *enc)
Queries if the passed code point is of passed character type in the passed encoding.
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
static VALUE RB_OBJ_FROZEN_RAW(VALUE obj)
This is an implementation detail of RB_OBJ_FROZEN().
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define TYPE(_)
Old name of rb_type.
#define ENCODING_SET_INLINED(obj, i)
Old name of RB_ENCODING_SET_INLINED.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define FL_UNSET_RAW
Old name of RB_FL_UNSET_RAW.
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
#define ALLOCV
Old name of RB_ALLOCV.
#define ISSPACE
Old name of rb_isspace.
#define T_STRING
Old name of RUBY_T_STRING.
#define ENC_CODERANGE_CLEAN_P(cr)
Old name of RB_ENC_CODERANGE_CLEAN_P.
#define ENC_CODERANGE_AND(a, b)
Old name of RB_ENC_CODERANGE_AND.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define SYM2ID
Old name of RB_SYM2ID.
#define ENC_CODERANGE(obj)
Old name of RB_ENC_CODERANGE.
#define CLASS_OF
Old name of rb_class_of.
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define FIXABLE
Old name of RB_FIXABLE.
#define xmalloc
Old name of ruby_xmalloc.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define ISDIGIT
Old name of rb_isdigit.
#define ENC_CODERANGE_MASK
Old name of RUBY_ENC_CODERANGE_MASK.
#define ZALLOC_N
Old name of RB_ZALLOC_N.
#define T_HASH
Old name of RUBY_T_HASH.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
#define FL_SET
Old name of RB_FL_SET.
#define rb_ary_new3
Old name of rb_ary_new_from_args.
#define ENCODING_INLINE_MAX
Old name of RUBY_ENCODING_INLINE_MAX.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define FL_ANY_RAW
Old name of RB_FL_ANY_RAW.
#define ISALPHA
Old name of rb_isalpha.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ULL2NUM
Old name of RB_ULL2NUM.
#define TOLOWER
Old name of rb_tolower.
#define Qtrue
Old name of RUBY_Qtrue.
#define ST2FIX
Old name of RB_ST2FIX.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define FIXNUM_MAX
Old name of RUBY_FIXNUM_MAX.
#define NUM2INT
Old name of RB_NUM2INT.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define scan_hex(s, l, e)
Old name of ruby_scan_hex.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2ULL
Old name of RB_NUM2ULL.
#define DBL2NUM
Old name of rb_float_new.
#define ISPRINT
Old name of rb_isprint.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define ENCODING_SHIFT
Old name of RUBY_ENCODING_SHIFT.
#define FL_TEST
Old name of RB_FL_TEST.
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define ENCODING_GET_INLINED(obj)
Old name of RB_ENCODING_GET_INLINED.
#define ENC_CODERANGE_CLEAR(obj)
Old name of RB_ENC_CODERANGE_CLEAR.
#define FL_UNSET
Old name of RB_FL_UNSET.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define ENCODING_IS_ASCII8BIT(obj)
Old name of RB_ENCODING_IS_ASCII8BIT.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define ENCODING_CODERANGE_SET(obj, encindex, cr)
Old name of RB_ENCODING_CODERANGE_SET.
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define OBJ_FROZEN_RAW
Old name of RB_OBJ_FROZEN_RAW.
#define T_REGEXP
Old name of RUBY_T_REGEXP.
#define ENCODING_MASK
Old name of RUBY_ENCODING_MASK.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
VALUE rb_eRangeError
RangeError exception.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_eIndexError
IndexError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_cObject
Object class.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_class_new_instance_pass_kw(int argc, const VALUE *argv, VALUE klass)
Identical to rb_class_new_instance(), except it passes the passed keywords if any to the #initialize ...
VALUE rb_obj_frozen_p(VALUE obj)
Same as RB_OBJ_FROZEN(), but returns Qtrue/Qfalse instead of #bool.
double rb_str_to_dbl(VALUE str, int mode)
Identical to rb_cstr_to_dbl(), except it accepts a Ruby's string instead of C's.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_cSymbol
Symbol class.
VALUE rb_cRange
Range class.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
VALUE rb_mComparable
Comparable module.
VALUE rb_cString
String class.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
static char * rb_enc_right_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the right boundary of a character.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
static int RB_ENCODING_GET_INLINED(VALUE obj)
Queries the encoding of the passed object.
static int rb_enc_code_to_mbclen(int c, rb_encoding *enc)
Identical to rb_enc_codelen(), except it returns 0 for invalid code points.
static char * rb_enc_step_back(const char *s, const char *p, const char *e, int n, rb_encoding *enc)
Scans the string backwards for n characters.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
VALUE rb_enc_str_new_static(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it takes a C string literal.
char * rb_enc_nth(const char *head, const char *tail, long nth, rb_encoding *enc)
Queries the n-th character.
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
Identical to rb_str_conv_enc(), except it additionally takes IO encoder options.
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
long rb_memsearch(const void *x, long m, const void *y, long n, rb_encoding *enc)
Looks for the passed string in the passed buffer.
long rb_enc_strlen(const char *head, const char *tail, rb_encoding *enc)
Counts the number of characters of the passed string, according to the passed encoding.
VALUE rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *enc)
Identical to rb_str_cat(), except it additionally takes an encoding.
VALUE rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc)
Identical to rb_enc_str_new(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_export_to_enc(VALUE obj, rb_encoding *enc)
Identical to rb_str_export(), except it additionally takes an encoding.
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *enc)
Identical to rb_external_str_new(), except it additionally takes an encoding.
int rb_enc_str_asciionly_p(VALUE str)
Queries if the passed string is "ASCII only".
VALUE rb_enc_interned_str_cstr(const char *ptr, rb_encoding *enc)
Identical to rb_enc_str_new_cstr(), except it returns a "f"string.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
Identical to rb_enc_symname_p(), except it additionally takes the passed string's length.
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_finished
The conversion stopped after converting everything.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
VALUE rb_funcall_with_block_kw(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE procval, int kw_splat)
Identical to rb_funcallv_with_block(), except you can specify how to handle the last element of the g...
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
This roughly resembles return enum_for(__callee__) unless block_given?.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_fs
The field separator character for inputs, or the $;.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
VALUE rb_sym_all_symbols(void)
Collects every single bits of symbols that have ever interned in the entire history of the current pr...
void rb_backref_set(VALUE md)
Updates $~.
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
int rb_reg_backref_number(VALUE match, VALUE backref)
Queries the index of the given named capture.
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
VALUE rb_reg_match(VALUE re, VALUE str)
This is the match operator.
void rb_match_busy(VALUE md)
Asserts that the given MatchData is "occupied".
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
void rb_str_free(VALUE str)
Destroys the given string for no reason.
VALUE rb_str_new_shared(VALUE str)
Identical to rb_str_new_cstr(), except it takes a Ruby's string instead of C's.
VALUE rb_str_plus(VALUE lhs, VALUE rhs)
Generates a new string, concatenating the former to the latter.
#define rb_utf8_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "UTF-8" encoding.
#define rb_hash_end(h)
Just another name of st_hash_end.
#define rb_hash_uint32(h, i)
Just another name of st_hash_uint32.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_filesystem_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "filesystem" encoding.
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
VALUE rb_str_times(VALUE str, VALUE num)
Repetition of a string.
VALUE rb_external_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "default external" encoding.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
long rb_str_offset(VALUE str, long pos)
"Inverse" of rb_str_sublen().
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
VALUE rb_str_ellipsize(VALUE str, long len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
st_index_t rb_memhash(const void *ptr, long len)
This is a universal hash function.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
void rb_str_shared_replace(VALUE dst, VALUE src)
Replaces the contents of the former with the latter.
#define rb_str_buf_cat
Just another name of rb_str_cat.
VALUE rb_str_new_static(const char *ptr, long len)
Identical to rb_str_new(), except it takes a C string literal.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
long rb_str_strlen(VALUE str)
Counts the number of characters (not bytes) that are stored inside of the given string.
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
#define rb_str_buf_new_cstr(str)
Identical to rb_str_new_cstr, except done differently.
#define rb_usascii_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "US ASCII" encoding.
VALUE rb_str_replace(VALUE dst, VALUE src)
Replaces the contents of the former object with the stringised contents of the latter.
char * rb_str_subpos(VALUE str, long beg, long *len)
Identical to rb_str_substr(), except it returns a C's string instead of Ruby's.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
VALUE rb_interned_str_cstr(const char *ptr)
Identical to rb_interned_str(), except it assumes the passed pointer is a pointer to a C's string.
VALUE rb_filesystem_str_new_cstr(const char *ptr)
Identical to rb_filesystem_str_new(), except it assumes the passed pointer is a pointer to a C string...
#define rb_external_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "default external" encoding.
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
long rb_str_sublen(VALUE str, long pos)
Byte offset to character offset conversion.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
VALUE rb_interned_str(const char *ptr, long len)
Identical to rb_str_new(), except it returns an infamous "f"string.
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
int rb_str_comparable(VALUE str1, VALUE str2)
Checks if two strings are comparable each other or not.
#define rb_strlen_lit(str)
Length of a string literal.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
void rb_str_update(VALUE dst, long beg, long len, VALUE src)
Replaces some (or all) of the contents of the given string.
VALUE rb_str_scrub(VALUE str, VALUE repl)
"Cleanses" the string.
#define rb_locale_str_new_cstr(str)
Identical to rb_external_str_new_cstr, except it generates a string of "locale" encoding instead of "...
VALUE rb_str_new_with_class(VALUE obj, const char *ptr, long len)
Identical to rb_str_new(), except it takes the class of the allocating object.
#define rb_str_dup_frozen
Just another name of rb_str_new_frozen.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
VALUE rb_utf8_str_new_static(const char *ptr, long len)
Identical to rb_str_new_static(), except it generates a string of "UTF-8" encoding instead of "binary...
#define rb_utf8_str_new(str, len)
Identical to rb_str_new, except it generates a string of "UTF-8" encoding.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
VALUE rb_locale_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "locale" encoding.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_drop_bytes(VALUE str, long len)
Shrinks the given string for the given number of bytes.
VALUE rb_str_split(VALUE str, const char *delim)
Divides the given string based on the given delimiter.
VALUE rb_usascii_str_new_static(const char *ptr, long len)
Identical to rb_str_new_static(), except it generates a string of "US ASCII" encoding instead of "bin...
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
ID rb_to_id(VALUE str)
Identical to rb_intern_str(), except it tries to convert the parameter object to an instance of rb_cS...
int capa
Designed capacity of the buffer.
int off
Offset inside of ptr.
int len
Length of the buffer.
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
long rb_reg_search(VALUE re, VALUE str, long pos, int dir)
Runs the passed regular expression over the passed string.
VALUE rb_reg_regcomp(VALUE str)
Creates a new instance of rb_cRegexp.
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt)
Formats a string.
VALUE rb_yield(VALUE val)
Yields the block.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define ALLOCA_N(type, n)
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
Defines RBIMPL_ATTR_NONSTRING.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
#define RBASIC(obj)
Convenient casting macro.
#define RHASH_SIZE(h)
Queries the size of the hash.
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
#define StringValue(v)
Ensures that the parameter object is a String.
VALUE rb_str_export_locale(VALUE obj)
Identical to rb_str_export(), except it converts into the locale encoding instead.
char * rb_string_value_cstr(volatile VALUE *ptr)
Identical to rb_string_value_ptr(), except it additionally checks for the contents for viability as a...
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
VALUE rb_string_value(volatile VALUE *ptr)
Identical to rb_str_to_str(), except it fills the passed pointer with the converted object.
#define RSTRING(obj)
Convenient casting macro.
VALUE rb_str_export(VALUE obj)
Identical to rb_str_to_str(), except it additionally converts the string into default external encodi...
char * rb_string_value_ptr(volatile VALUE *ptr)
Identical to rb_str_to_str(), except it returns the converted string's backend memory region.
VALUE rb_str_to_str(VALUE obj)
Identical to rb_check_string_type(), except it raises exceptions in case of conversion failures.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
#define errno
Ractor-aware version of errno.
#define RB_NUM2SSIZE
Converts an instance of rb_cInteger into C's ssize_t.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
VALUE flags
Per-object flags.
struct RBasic basic
Basic part, including flags and class.
union RString::@60::@61::@63 aux
Auxiliary info.
long capa
Capacity of *ptr.
long len
Length of the string, not including terminating NUL character.
struct RString::@60::@61 heap
Strings that use separated memory region for contents use this pattern.
struct RString::@60::@62 embed
Embedded contents.
VALUE shared
Parent of the string.
char * ptr
Pointer to the contents of the string.
union RString::@60 as
String's specific fields.
This is the struct that holds necessary info for a struct.
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Blocks until the current thread obtains a lock.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static enum ruby_value_type rb_type(VALUE obj)
Identical to RB_BUILTIN_TYPE(), except it can also accept special constants.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
ruby_value_type
C-level type of an object.